Commit | Line | Data |
---|---|---|
dcaafa88 FF |
1 | diff -u -r ../glib-2.54.2/glib/gtimezone.c ./glib/gtimezone.c |
2 | --- ../glib-2.54.2/glib/gtimezone.c 2017-07-14 01:03:39.000000000 +0200 | |
507b3347 | 3 | +++ ./glib/gtimezone.c 2018-01-07 23:20:34.447775267 +0100 |
4601842b | 4 | @@ -43,6 +43,10 @@ |
8aef3a59 FF |
5 | #include <windows.h> |
6 | #endif | |
7 | ||
8 | +#ifdef __ANDROID__ | |
8aef3a59 FF |
9 | +#include <sys/system_properties.h> |
10 | +#endif | |
11 | + | |
12 | /** | |
13 | * SECTION:timezone | |
14 | * @title: GTimeZone | |
507b3347 | 15 | @@ -392,7 +396,131 @@ |
dcaafa88 FF |
16 | gtz->transitions = NULL; |
17 | } | |
18 | ||
19 | -#ifdef G_OS_UNIX | |
8aef3a59 | 20 | +#ifdef __ANDROID__ |
ada1b36f | 21 | +/* Android uses a 'persist.sys.timezone' system property for the |
6acf9d4a FF |
22 | + * current timezone instead of a /etc/localtime file: |
23 | + * https://android.googlesource.com/platform/ndk/+/android-2.2_r1/docs/system/libc/OVERVIEW.TXT#67 | |
24 | + * | |
25 | + * There are no files under /usr/share/zoneinfo - instead a single | |
26 | + * /system/usr/share/zoneinfo/tzdata file is used which contains all | |
27 | + * files compiled together with the following tool: | |
28 | + * https://android.googlesource.com/platform/system/timezone/+/master/zone_compactor/main/java/ZoneCompactor.java | |
29 | + */ | |
30 | +static GBytes * | |
dcaafa88 FF |
31 | +zone_info_android (const gchar *identifier) |
32 | +{ | |
69fd9a5c | 33 | + char sys_timezone[PROP_VALUE_MAX]; |
4601842b FF |
34 | + GMappedFile *file; |
35 | + gchar *tzdata; | |
36 | + gsize tzdata_length; | |
37 | + const gsize index_entry_size = 52; | |
38 | + gint32 header_index_offset, header_data_offset; | |
39 | + gint32 entry_count, current_index; | |
40 | + char* entry_name; | |
41 | + gint32 entry_offset, entry_length; | |
507b3347 FF |
42 | + guint32 entry_name_start, entry_name_end; |
43 | + guint32 zoneinfo_start, zoneinfo_end; | |
4601842b | 44 | + GBytes *zoneinfo; |
507b3347 | 45 | + GError *error = NULL; |
dcaafa88 FF |
46 | + |
47 | + if (identifier == NULL) | |
48 | + { | |
022cbc0f | 49 | + if (__system_property_get ("persist.sys.timezone", sys_timezone) < 1) |
6acf9d4a FF |
50 | + { |
51 | + g_warning ("__system_property_get(\"persist.sys.timezone\") failed"); | |
52 | + return NULL; | |
53 | + } | |
dcaafa88 | 54 | + identifier = sys_timezone; |
8aef3a59 | 55 | + } |
dcaafa88 | 56 | + |
507b3347 | 57 | + file = g_mapped_file_new ("/system/usr/share/zoneinfo/tzdata", FALSE, &error); |
4601842b FF |
58 | + if (file == NULL) |
59 | + { | |
507b3347 FF |
60 | + g_warning ("Failed mapping tzdata file: %s", error->message); |
61 | + g_error_free (error); | |
4601842b FF |
62 | + return NULL; |
63 | + } | |
8aef3a59 | 64 | + |
4601842b FF |
65 | + tzdata = g_mapped_file_get_contents (file); |
66 | + tzdata_length = g_mapped_file_get_length (file); | |
67 | + if (tzdata == NULL || tzdata_length < 24) | |
dcaafa88 | 68 | + { |
4601842b | 69 | + g_warning ("Too small tzdata file"); |
dcaafa88 FF |
70 | + goto error; |
71 | + } | |
72 | + | |
4601842b FF |
73 | + header_index_offset = gint32_from_be (*((gint32_be*) (tzdata + 12))); |
74 | + header_data_offset = gint32_from_be (*((gint32_be*) (tzdata + 16))); | |
dcaafa88 | 75 | + |
507b3347 FF |
76 | + if (header_index_offset < 0 || header_data_offset < 0 || header_data_offset < index_entry_size) |
77 | + { | |
78 | + g_warning ("Invalid tzdata content"); | |
79 | + goto error; | |
80 | + } | |
81 | + | |
4601842b FF |
82 | + entry_count = (header_data_offset - header_index_offset) / index_entry_size; |
83 | + if (entry_count < 1) | |
dcaafa88 | 84 | + { |
507b3347 | 85 | + g_warning ("No index entry found"); |
4601842b FF |
86 | + goto error; |
87 | + } | |
dcaafa88 | 88 | + |
4601842b FF |
89 | + current_index = 0; |
90 | + while (current_index < entry_count) | |
91 | + { | |
507b3347 FF |
92 | + if (!g_uint_checked_mul(&entry_name_start, current_index, index_entry_size) || |
93 | + !g_uint_checked_add(&entry_name_start, entry_name_start, header_index_offset) || | |
94 | + !g_uint_checked_add(&entry_name_end, entry_name_start, 40)) | |
95 | + { | |
96 | + g_warning ("Overflow when computing entry name offset"); | |
97 | + goto error; | |
98 | + } | |
99 | + | |
100 | + entry_name = tzdata + entry_name_start; | |
101 | + | |
4601842b FF |
102 | + /* The name should be null terminated within the 40 chars. */ |
103 | + if (memchr (entry_name, 0, 40) == NULL) | |
dcaafa88 | 104 | + { |
507b3347 | 105 | + g_warning ("Invalid index entry"); |
4601842b FF |
106 | + goto error; |
107 | + } | |
dcaafa88 | 108 | + |
4601842b FF |
109 | + if (strcmp (entry_name, identifier) == 0) |
110 | + { | |
111 | + entry_offset = gint32_from_be (*(gint32_be*) (entry_name + 40)); | |
112 | + entry_length = gint32_from_be (*(gint32_be*) (entry_name + 44)); | |
507b3347 | 113 | + if (entry_length == 0 || entry_length > 65536) |
dcaafa88 | 114 | + { |
507b3347 FF |
115 | + /* Use a reasonable but arbitrary max length of an entry. */ |
116 | + g_warning ("Invalid zoneinfo entry length"); | |
dcaafa88 FF |
117 | + goto error; |
118 | + } | |
507b3347 FF |
119 | + |
120 | + if (!g_uint_checked_add(&zoneinfo_start, header_data_offset, entry_offset) || | |
121 | + !g_uint_checked_add(&zoneinfo_end, zoneinfo_start, entry_length) || | |
122 | + zoneinfo_end > tzdata_length) | |
ada1b36f | 123 | + { |
507b3347 | 124 | + g_warning ("Too large zoneinfo entry length"); |
ada1b36f FF |
125 | + goto error; |
126 | + } | |
127 | + | |
507b3347 | 128 | + zoneinfo = g_bytes_new_with_free_func (tzdata + zoneinfo_start, |
4601842b FF |
129 | + entry_length, |
130 | + (GDestroyNotify)g_mapped_file_unref, | |
131 | + g_mapped_file_ref (file)); | |
132 | + g_mapped_file_unref (file); | |
133 | + return zoneinfo; | |
8aef3a59 | 134 | + } |
4601842b | 135 | + current_index++; |
8aef3a59 | 136 | + } |
dcaafa88 | 137 | + |
8aef3a59 | 138 | +error: |
4601842b | 139 | + g_mapped_file_unref (file); |
8aef3a59 | 140 | + return NULL; |
dcaafa88 FF |
141 | +} |
142 | + | |
143 | +#elif defined(G_OS_UNIX) | |
144 | + | |
145 | static GBytes* | |
146 | zone_info_unix (const gchar *identifier) | |
147 | { | |
507b3347 | 148 | @@ -436,6 +564,10 @@ |
8aef3a59 | 149 | return zoneinfo; |
8aef3a59 FF |
150 | } |
151 | ||
dcaafa88 FF |
152 | +#endif |
153 | + | |
154 | +#ifdef G_OS_UNIX | |
155 | + | |
8aef3a59 | 156 | static void |
dcaafa88 FF |
157 | init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo) |
158 | { | |
507b3347 | 159 | @@ -1387,7 +1519,11 @@ |
dcaafa88 FF |
160 | if (tz->t_info == NULL) |
161 | { | |
162 | #ifdef G_OS_UNIX | |
163 | +# ifdef __ANDROID__ | |
164 | + GBytes *zoneinfo = zone_info_android (identifier); | |
165 | +# else | |
166 | GBytes *zoneinfo = zone_info_unix (identifier); | |
167 | +# endif | |
168 | if (!zoneinfo) | |
169 | zone_for_constant_offset (tz, "UTC"); | |
170 | else |