Commit | Line | Data |
---|---|---|
69fd9a5c FF |
1 | Patch submitted at https://bugzilla.gnome.org/show_bug.cgi?id=771304 |
2 | ||
dcaafa88 FF |
3 | diff -u -r ../glib-2.54.2/glib/gtimezone.c ./glib/gtimezone.c |
4 | --- ../glib-2.54.2/glib/gtimezone.c 2017-07-14 01:03:39.000000000 +0200 | |
5 | +++ ./glib/gtimezone.c 2017-12-09 02:03:46.797229494 +0100 | |
c780e809 | 6 | @@ -43,6 +43,13 @@ |
8aef3a59 FF |
7 | #include <windows.h> |
8 | #endif | |
9 | ||
10 | +#ifdef __ANDROID__ | |
c780e809 | 11 | +#include <arpa/inet.h> |
8aef3a59 FF |
12 | +#include <fcntl.h> |
13 | +#include <sys/system_properties.h> | |
c780e809 | 14 | +#include <unistd.h> |
8aef3a59 FF |
15 | +#endif |
16 | + | |
17 | /** | |
18 | * SECTION:timezone | |
19 | * @title: GTimeZone | |
dcaafa88 FF |
20 | @@ -392,7 +399,105 @@ |
21 | gtz->transitions = NULL; | |
22 | } | |
23 | ||
24 | -#ifdef G_OS_UNIX | |
8aef3a59 | 25 | +#ifdef __ANDROID__ |
dcaafa88 FF |
26 | +/* Android does not have /etc/localtime but uses a system property for the |
27 | + the current timezone. There are no files under /usr/share/zoneinfo, | |
28 | + instead a single /system/usr/share/zoneinfo/tzdata which are all zoneinfo | |
29 | + files compiled together with the following tool: | |
30 | + https://android.googlesource.com/platform/external/icu/+/master/tools/ZoneCompactor.java */ | |
31 | +static GBytes* | |
32 | +zone_info_android (const gchar *identifier) | |
33 | +{ | |
34 | + struct tzdata_header | |
35 | + { | |
36 | + char version[12]; | |
37 | + uint32_t index_offset; | |
38 | + uint32_t data_offset; | |
39 | + uint32_t zonetab_offset; | |
8aef3a59 FF |
40 | + } __attribute__((packed)) header; |
41 | + | |
dcaafa88 FF |
42 | + struct tzdata_index_entry |
43 | + { | |
44 | + char name[40]; | |
45 | + uint32_t offset; | |
46 | + uint32_t length; | |
47 | + uint32_t unused; | |
8aef3a59 FF |
48 | + } __attribute__((packed)) entry; |
49 | + | |
69fd9a5c | 50 | + char sys_timezone[PROP_VALUE_MAX]; |
dcaafa88 FF |
51 | + |
52 | + if (identifier == NULL) | |
53 | + { | |
54 | + if (__system_property_get("persist.sys.timezone", sys_timezone) < 1) | |
55 | + { | |
56 | + g_warning("__system_property_get(\"persist.sys.timezone\") failed\n"); | |
57 | + return NULL; | |
58 | + } | |
59 | + identifier = sys_timezone; | |
8aef3a59 | 60 | + } |
dcaafa88 FF |
61 | + |
62 | + int tzdata_fd = open("/system/usr/share/zoneinfo/tzdata", O_RDONLY); | |
63 | + if (tzdata_fd < 0) | |
64 | + { | |
65 | + g_warning("Failed opening tzdata"); | |
66 | + return NULL; | |
8aef3a59 | 67 | + } |
8aef3a59 | 68 | + |
dcaafa88 FF |
69 | + if (read(tzdata_fd, &header, sizeof(header)) < (ssize_t) sizeof(header)) |
70 | + { | |
71 | + g_warning("Failed reading tzdata header"); | |
72 | + goto error; | |
73 | + } | |
74 | + | |
75 | + header.index_offset = htonl(header.index_offset); | |
76 | + header.data_offset = htonl(header.data_offset); | |
77 | + | |
78 | + uint32_t current_offset = header.index_offset; | |
79 | + while (current_offset < header.data_offset) | |
80 | + { | |
81 | + if (read(tzdata_fd, &entry, sizeof(entry)) < (ssize_t) sizeof(entry)) | |
82 | + { | |
8aef3a59 FF |
83 | + g_warning("Failed reading tzdata index entry"); |
84 | + goto error; | |
85 | + } | |
dcaafa88 FF |
86 | + |
87 | + if (strcmp(entry.name, identifier) == 0) | |
88 | + { | |
89 | + entry.offset = htonl(entry.offset); | |
90 | + entry.length = htonl(entry.length); | |
91 | + if (entry.length == 0) | |
92 | + { | |
93 | + g_warning("Invalid tzdata entry with length zero"); | |
94 | + goto error; | |
95 | + } | |
96 | + | |
97 | + if (lseek(tzdata_fd, header.data_offset + entry.offset, SEEK_SET) == -1) | |
98 | + { | |
99 | + g_warning("Failed seeking to tzdata entry"); | |
100 | + goto error; | |
101 | + } | |
102 | + | |
103 | + guint8* data = g_malloc(entry.length); | |
104 | + if (read(tzdata_fd, data, entry.length) < entry.length) | |
105 | + { | |
106 | + g_warning("Failed reading tzdata entry"); | |
107 | + g_free(data); | |
108 | + goto error; | |
109 | + } | |
110 | + | |
111 | + close(tzdata_fd); | |
112 | + return g_bytes_new_take(data, entry.length); | |
8aef3a59 | 113 | + } |
8aef3a59 | 114 | + } |
dcaafa88 | 115 | + |
8aef3a59 | 116 | +error: |
dcaafa88 FF |
117 | + close(tzdata_fd); |
118 | + | |
8aef3a59 | 119 | + return NULL; |
dcaafa88 FF |
120 | +} |
121 | + | |
122 | +#elif defined(G_OS_UNIX) | |
123 | + | |
124 | static GBytes* | |
125 | zone_info_unix (const gchar *identifier) | |
126 | { | |
127 | @@ -436,6 +541,10 @@ | |
8aef3a59 | 128 | return zoneinfo; |
8aef3a59 FF |
129 | } |
130 | ||
dcaafa88 FF |
131 | +#endif |
132 | + | |
133 | +#ifdef G_OS_UNIX | |
134 | + | |
8aef3a59 | 135 | static void |
dcaafa88 FF |
136 | init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo) |
137 | { | |
138 | @@ -1387,7 +1496,11 @@ | |
139 | if (tz->t_info == NULL) | |
140 | { | |
141 | #ifdef G_OS_UNIX | |
142 | +# ifdef __ANDROID__ | |
143 | + GBytes *zoneinfo = zone_info_android (identifier); | |
144 | +# else | |
145 | GBytes *zoneinfo = zone_info_unix (identifier); | |
146 | +# endif | |
147 | if (!zoneinfo) | |
148 | zone_for_constant_offset (tz, "UTC"); | |
149 | else |