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 | |
4601842b FF |
3 | +++ ./glib/gtimezone.c 2017-12-21 23:47:57.704190589 +0100 |
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 | |
4601842b | 15 | @@ -392,7 +396,109 @@ |
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; | |
42 | + GBytes *zoneinfo; | |
dcaafa88 FF |
43 | + |
44 | + if (identifier == NULL) | |
45 | + { | |
022cbc0f | 46 | + if (__system_property_get ("persist.sys.timezone", sys_timezone) < 1) |
6acf9d4a FF |
47 | + { |
48 | + g_warning ("__system_property_get(\"persist.sys.timezone\") failed"); | |
49 | + return NULL; | |
50 | + } | |
dcaafa88 | 51 | + identifier = sys_timezone; |
8aef3a59 | 52 | + } |
dcaafa88 | 53 | + |
4601842b FF |
54 | + file = g_mapped_file_new ("/system/usr/share/zoneinfo/tzdata", FALSE, NULL); |
55 | + if (file == NULL) | |
56 | + { | |
57 | + g_warning ("Failed mapping tzdata file"); | |
58 | + return NULL; | |
59 | + } | |
8aef3a59 | 60 | + |
4601842b FF |
61 | + tzdata = g_mapped_file_get_contents (file); |
62 | + tzdata_length = g_mapped_file_get_length (file); | |
63 | + if (tzdata == NULL || tzdata_length < 24) | |
dcaafa88 | 64 | + { |
4601842b | 65 | + g_warning ("Too small tzdata file"); |
dcaafa88 FF |
66 | + goto error; |
67 | + } | |
68 | + | |
4601842b FF |
69 | + header_index_offset = gint32_from_be (*((gint32_be*) (tzdata + 12))); |
70 | + header_data_offset = gint32_from_be (*((gint32_be*) (tzdata + 16))); | |
dcaafa88 | 71 | + |
4601842b FF |
72 | + entry_count = (header_data_offset - header_index_offset) / index_entry_size; |
73 | + if (entry_count < 1) | |
dcaafa88 | 74 | + { |
4601842b FF |
75 | + g_warning("No index entry found"); |
76 | + goto error; | |
77 | + } | |
dcaafa88 | 78 | + |
4601842b FF |
79 | + current_index = 0; |
80 | + while (current_index < entry_count) | |
81 | + { | |
82 | + entry_name = tzdata + header_index_offset + current_index * index_entry_size; | |
83 | + /* The name should be null terminated within the 40 chars. */ | |
84 | + if (memchr (entry_name, 0, 40) == NULL) | |
dcaafa88 | 85 | + { |
4601842b FF |
86 | + g_warning("Invalid index entry"); |
87 | + goto error; | |
88 | + } | |
dcaafa88 | 89 | + |
4601842b FF |
90 | + if (strcmp (entry_name, identifier) == 0) |
91 | + { | |
92 | + entry_offset = gint32_from_be (*(gint32_be*) (entry_name + 40)); | |
93 | + entry_length = gint32_from_be (*(gint32_be*) (entry_name + 44)); | |
94 | + if (entry_length == 0) | |
dcaafa88 | 95 | + { |
4601842b | 96 | + g_warning ("Invalid tzdata entry with length zero"); |
dcaafa88 FF |
97 | + goto error; |
98 | + } | |
4601842b | 99 | + else if (entry_length > 65536 || header_data_offset + entry_offset + entry_length > tzdata_length) |
ada1b36f | 100 | + { |
4601842b | 101 | + /* Use a reasonable but arbitrary max length of an entry. */ |
ada1b36f FF |
102 | + g_warning ("Too large tzdata entry length"); |
103 | + goto error; | |
104 | + } | |
105 | + | |
4601842b FF |
106 | + zoneinfo = g_bytes_new_with_free_func (tzdata + header_data_offset + entry_offset, |
107 | + entry_length, | |
108 | + (GDestroyNotify)g_mapped_file_unref, | |
109 | + g_mapped_file_ref (file)); | |
110 | + g_mapped_file_unref (file); | |
111 | + return zoneinfo; | |
8aef3a59 | 112 | + } |
4601842b | 113 | + current_index++; |
8aef3a59 | 114 | + } |
dcaafa88 | 115 | + |
8aef3a59 | 116 | +error: |
4601842b | 117 | + g_mapped_file_unref (file); |
8aef3a59 | 118 | + return NULL; |
dcaafa88 FF |
119 | +} |
120 | + | |
121 | +#elif defined(G_OS_UNIX) | |
122 | + | |
123 | static GBytes* | |
124 | zone_info_unix (const gchar *identifier) | |
125 | { | |
4601842b | 126 | @@ -436,6 +542,10 @@ |
8aef3a59 | 127 | return zoneinfo; |
8aef3a59 FF |
128 | } |
129 | ||
dcaafa88 FF |
130 | +#endif |
131 | + | |
132 | +#ifdef G_OS_UNIX | |
133 | + | |
8aef3a59 | 134 | static void |
dcaafa88 FF |
135 | init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo) |
136 | { | |
4601842b | 137 | @@ -1387,7 +1497,11 @@ |
dcaafa88 FF |
138 | if (tz->t_info == NULL) |
139 | { | |
140 | #ifdef G_OS_UNIX | |
141 | +# ifdef __ANDROID__ | |
142 | + GBytes *zoneinfo = zone_info_android (identifier); | |
143 | +# else | |
144 | GBytes *zoneinfo = zone_info_unix (identifier); | |
145 | +# endif | |
146 | if (!zoneinfo) | |
147 | zone_for_constant_offset (tz, "UTC"); | |
148 | else |