FreeRDP
Loading...
Searching...
No Matches
tzextract.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Net;
5using System.Text;
6using System.Xml;
7using System.Xml.Linq;
8using System.Xml.Schema;
9
10internal class Program
11{
12 private static string app = AppDomain.CurrentDomain.FriendlyName;
13 private static TextWriter stderr = Console.Error;
14 private static TextWriter stdout = Console.Out;
15
16 private static void usage()
17 {
18 stderr.WriteLine("Usage:");
19 stderr.WriteLine(app + " <path to output files>");
20 Environment.Exit(1);
21 }
22
23 private static bool writeZoneMapC(string path)
24 {
25 string fname = "TimeZoneNameMap";
26 string fpath = Path.Combine(path, fname + "_static.h");
27
28 using (StreamWriter fs = new StreamWriter(fpath))
29 {
30 fs.WriteLine("/* Automatically generated by " + app + " */");
31 fs.WriteLine("");
32 fs.WriteLine("#include \"" + fname + ".h\"");
33 fs.WriteLine("");
34 fs.WriteLine("static const " + fname + "Entry " + fname + "[] ={");
35
36 bool first = true;
37 foreach (System.TimeZoneInfo tz in System.TimeZoneInfo.GetSystemTimeZones())
38 {
39 string iana;
40 System.TimeZoneInfo.TryConvertWindowsIdToIanaId(tz.Id, out iana);
41
42 StringBuilder sb = new StringBuilder();
43 if (!first)
44 sb.Append(",");
45 first = false;
46 sb.Append("{ \"");
47 sb.Append(tz.Id);
48 sb.Append("\", \"");
49 sb.Append(tz.StandardName);
50 sb.Append("\", \"");
51 sb.Append(tz.DisplayName);
52 sb.Append("\", \"");
53 sb.Append(tz.DaylightName);
54 sb.Append("\", \"");
55 sb.Append(iana);
56 sb.Append("\" }");
57 fs.WriteLine(sb.ToString());
58 }
59
60 fs.WriteLine("};");
61 fs.WriteLine("");
62 fs.WriteLine("static const size_t " + fname + "Size = ARRAYSIZE(" + fname + ");");
63 }
64 return true;
65 }
66
67 private static bool writeZoneMapJSON(string path)
68 {
69 string fname = "TimeZoneNameMap";
70 string fpath = Path.Combine(path, fname + ".json");
71
72 using (StreamWriter fs = new StreamWriter(fpath))
73 {
74 fs.WriteLine("{");
75 fs.WriteLine("\"TimeZoneNameMap\": [");
76
77 bool first = true;
78 foreach (System.TimeZoneInfo tz in System.TimeZoneInfo.GetSystemTimeZones())
79 {
80 string iana;
81 System.TimeZoneInfo.TryConvertWindowsIdToIanaId(tz.Id, out iana);
82
83 StringBuilder sb = new StringBuilder();
84 if (!first)
85 sb.Append(",");
86 first = false;
87 sb.Append("{ ");
88 sb.Append("\"Id\": \"");
89 sb.Append(tz.Id);
90 sb.Append("\", \"StandardName\": \"");
91 sb.Append(tz.StandardName);
92 sb.Append("\", \"DisplayName\": \"");
93 sb.Append(tz.DisplayName);
94 sb.Append("\", \"DaylightName\": \"");
95 sb.Append(tz.DaylightName);
96 sb.Append("\", \"Iana\": \"");
97 sb.Append(iana);
98 sb.Append("\" }");
99 fs.WriteLine(sb.ToString());
100 }
101
102 fs.WriteLine("]");
103 fs.WriteLine("}");
104 }
105 return true;
106 }
107
108 private static bool writeZoneMap(string path)
109 {
110 if (!writeZoneMapC(path))
111 return false;
112 if (!writeZoneMapJSON(path))
113 return false;
114 return true;
115 }
116
117 private static void onValidation(object sender, ValidationEventArgs e)
118 {
119 switch (e.Severity)
120 {
121 case XmlSeverityType.Warning:
122 case XmlSeverityType.Error:
123 stderr.WriteLine(e.ToString());
124 break;
125 default:
126 break;
127 }
128 }
129 private static bool updateWindowsIanaMap(string path)
130 {
131 string url =
132 "https://raw.githubusercontent.com/unicode-org/cldr/main/common/supplemental/windowsZones.xml";
133 string fname = "WindowsZones";
134 string fpath = Path.Combine(path, fname + ".c");
135
136 XmlDocument doc = new XmlDocument();
137 doc.Load(url);
138
139 stdout.WriteLine("Downloaded and parsed XML from '" + url + "'");
140
141 ValidationEventHandler handler = new ValidationEventHandler(onValidation);
142 // doc.Validate(handler);
143
144 XmlNodeList versions = doc.SelectNodes("//supplementalData/version");
145 XmlNodeList zones = doc.SelectNodes("//supplementalData/windowsZones/mapTimezones");
146 XmlNodeList mzones =
147 doc.SelectNodes("//supplementalData/windowsZones/mapTimezones/mapZone");
148
149 using (StreamWriter fs = new StreamWriter(fpath))
150 {
151 fs.WriteLine("/* Automatically generated by " + app);
152 fs.WriteLine(" *");
153 fs.WriteLine(" * url " + url);
154
155 foreach (XmlNode version in versions)
156 {
157 XmlNode nr = version.Attributes.GetNamedItem("number");
158 fs.WriteLine(" * version: " + nr.InnerText);
159 }
160
161 foreach (XmlNode node in zones)
162 {
163 XmlNode over = node.Attributes.GetNamedItem("otherVersion");
164 XmlNode tver = node.Attributes.GetNamedItem("typeVersion");
165 fs.WriteLine(" * mapTimezones: otherVersion: " + over.InnerText +
166 ", typeVersion: " + tver.InnerText);
167 }
168
169 fs.WriteLine(" */");
170 fs.WriteLine("");
171 fs.WriteLine("#include \"" + fname + ".h\"");
172 fs.WriteLine("");
173 fs.WriteLine("const WINDOWS_TZID_ENTRY " + fname + "[] = {");
174
175 foreach (XmlNode mzone in mzones)
176 {
177 XmlAttributeCollection attrs = mzone.Attributes;
178 XmlNode wzid = attrs.GetNamedItem("other");
179 XmlNode territory = attrs.GetNamedItem("territory");
180 XmlNode iana = attrs.GetNamedItem("type");
181 fs.WriteLine("\t{ \"" + iana.InnerText + "\", \"" + wzid.InnerText + "\" }, // " +
182 territory.InnerText);
183 }
184
185 fs.WriteLine("};");
186 fs.WriteLine("");
187 fs.WriteLine("const size_t " + fname + "NrElements = ARRAYSIZE(" + fname + ");");
188 }
189 stdout.WriteLine("Finished update");
190 return true;
191 }
192
193 private static bool writeIanaAliasesC(string path, string url, XmlNodeList versions,
194 List<string[]> aliases)
195 {
196 string fname = "TimeZoneIanaAliases";
197 string fpath = Path.Combine(path, fname + "_static.h");
198
199 using (StreamWriter fs = new StreamWriter(fpath))
200 {
201 fs.WriteLine("/* Automatically generated by " + app);
202 fs.WriteLine(" *");
203 fs.WriteLine(" * url " + url);
204
205 foreach (XmlNode version in versions)
206 {
207 XmlNode nr = version.Attributes.GetNamedItem("number");
208 fs.WriteLine(" * version: " + nr.InnerText);
209 }
210
211 fs.WriteLine(" */");
212 fs.WriteLine("");
213 fs.WriteLine("#include \"" + fname + ".h\"");
214 fs.WriteLine("");
215 fs.WriteLine("static const TimeZoneIanaAliasEntry " + fname + "[] = {");
216
217 foreach (string[] alias in aliases)
218 fs.WriteLine("\t{ \"" + alias[0] + "\", \"" + alias[1] + "\" },");
219
220 fs.WriteLine("};");
221 fs.WriteLine("");
222 fs.WriteLine("static const size_t " + fname + "Size = ARRAYSIZE(" + fname + ");");
223 }
224 return true;
225 }
226
227 private static bool writeIanaAliasesJSON(string path, List<string[]> aliases)
228 {
229 string fname = "TimeZoneIanaAliases";
230 string fpath = Path.Combine(path, fname + ".json");
231
232 using (StreamWriter fs = new StreamWriter(fpath))
233 {
234 fs.WriteLine("{");
235 fs.WriteLine("\"" + fname + "\": [");
236
237 bool first = true;
238 foreach (string[] alias in aliases)
239 {
240 StringBuilder sb = new StringBuilder();
241 if (!first)
242 sb.Append(",");
243 first = false;
244 sb.Append("{ \"Current\": \"");
245 sb.Append(alias[0]);
246 sb.Append("\", \"Legacy\": \"");
247 sb.Append(alias[1]);
248 sb.Append("\" }");
249 fs.WriteLine(sb.ToString());
250 }
251
252 fs.WriteLine("]");
253 fs.WriteLine("}");
254 }
255 return true;
256 }
257
258 private static bool updateIanaAliases(string path)
259 {
260 string url =
261 "https://raw.githubusercontent.com/unicode-org/cldr/main/common/bcp47/timezone.xml";
262
263 XmlDocument doc = new XmlDocument();
264 doc.Load(url);
265
266 stdout.WriteLine("Downloaded and parsed XML from '" + url + "'");
267
268 XmlNodeList versions = doc.SelectNodes("//ldmlBCP47/version");
269 XmlNodeList types = doc.SelectNodes("//ldmlBCP47/keyword/key[@name='tz']/type[@iana]");
270
271 List<string[]> aliases = new List<string[]>();
272 foreach (XmlNode type in types)
273 {
274 XmlAttributeCollection attrs = type.Attributes;
275 string iana = attrs.GetNamedItem("iana").InnerText;
276
277 /* the first alias is CLDR's name, which is what windowsZones.xml uses */
278 string legacy = attrs.GetNamedItem("alias").InnerText.Split(' ')[0];
279 if (legacy != iana)
280 aliases.Add(new string[] { iana, legacy });
281 }
282
283 if (!writeIanaAliasesC(path, url, versions, aliases))
284 return false;
285 if (!writeIanaAliasesJSON(path, aliases))
286 return false;
287
288 stdout.WriteLine("Finished update");
289 return true;
290 }
291
292 private static void Main(string[] args)
293 {
294 try
295 {
296 if (args.Length == 0)
297 {
298 stderr.WriteLine("Missing arguments!");
299 usage();
300 }
301
302 DirectoryInfo info = new DirectoryInfo(args[0]);
303 if (!info.Exists)
304 {
305 stderr.WriteLine("Path '" + info.FullName + "' does not exist");
306 usage();
307 }
308
309 if (!writeZoneMap(info.FullName))
310 return;
311
312 updateWindowsIanaMap(info.FullName);
313 updateIanaAliases(info.FullName);
314 }
315 catch (Exception e)
316 {
317 stderr.WriteLine(e.ToString());
318 Environment.Exit(-23);
319 }
320 }
321}