Implement setting of Windows-specific XML information
[wimlib] / tools / generate_language_id_map.c
1 /*
2  * generate_language_id_map.c
3  *
4  * Generate a memory-efficient map from Windows language IDs to names.  This
5  * program runs on Windows and uses LCIDToLocaleName() to enumerate all
6  * languages recognized by Windows.
7  *
8  * ----------------------------------------------------------------------------
9  *
10  * Copyright (C) 2016 Eric Biggers
11  *
12  * This file is free software; you can redistribute it and/or modify it under
13  * the terms of the GNU Lesser General Public License as published by the Free
14  * Software Foundation; either version 3 of the License, or (at your option) any
15  * later version.
16  *
17  * This file is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this file; if not, see http://www.gnu.org/licenses/.
24  */
25
26 #define WINVER 0x6000   /* Needed for LCIDToLocaleName() declaration  */
27
28 #include <inttypes.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <windows.h>
32
33 static struct {
34         uint16_t id;
35         char name[LOCALE_NAME_MAX_LENGTH];
36 } map[65536];
37
38 int main(void)
39 {
40         uint32_t num_languages = 0;
41         uint32_t name_start_offset = 0;
42         uint32_t num_chars;
43         bool need_new_line = true;
44
45         for (uint32_t lcid = 0; lcid < 65536; lcid++) {
46                 wchar_t locale_name[LOCALE_NAME_MAX_LENGTH];
47
48                 if (LCIDToLocaleName(lcid, locale_name, LOCALE_NAME_MAX_LENGTH, 0)) {
49                         size_t len = wcslen(locale_name);
50                         for (size_t j = 0; j <= len; j++) {
51                                 if (locale_name[j] > 127) {
52                                         fprintf(stderr,
53                                                 "ERROR: locale name \"%ls\" "
54                                                 "includes non-ASCII characters",
55                                                 locale_name);
56                                         return 1;
57                                 }
58                                 map[num_languages].name[j] = locale_name[j];
59                         }
60                         map[num_languages++].id = lcid;
61                 } else if (GetLastError() != ERROR_INVALID_PARAMETER) {
62                         fprintf(stderr,
63                                 "ERROR: LCIDToLocaleName(%"PRIx32"): %u\n",
64                                 lcid, (unsigned)GetLastError());
65                         return 1;
66                 }
67         }
68
69         printf("static const struct {\n");
70         printf("\tu16 id;\n");
71         printf("\tu16 name_start_offset;\n");
72         printf("} language_id_map[%"PRIu32"] = {", num_languages);
73         for (uint32_t i = 0; i < num_languages; i++) {
74                 if (need_new_line)
75                         printf("\n\t");
76                 printf("{0x%04x, %4"PRIu32"},", map[i].id, name_start_offset);
77                 need_new_line = (i % 4 == 3);
78                 if (!need_new_line)
79                         putchar(' ');
80                 name_start_offset += strlen(map[i].name) + 1;
81                 if (name_start_offset > 65536) {
82                         fprintf(stderr, "ERROR: total length of "
83                                 "language names is too long!");
84                         return 1;
85                 }
86         }
87         printf("\n};\n");
88         printf("\n");
89
90         printf("static const char language_names[%"PRIu32"] =\n",
91                name_start_offset);
92         printf("\t\"");
93         num_chars = 8;
94         for (uint32_t i = 0; i < num_languages; i++) {
95                 size_t len = strlen(map[i].name);
96                 need_new_line = (num_chars + len + 3 > 80);
97                 if (need_new_line) {
98                         printf("\"\n");
99                         printf("\t\"");
100                         num_chars = 9;
101                 }
102                 printf("%s\\0", map[i].name);
103                 num_chars += len + 2;
104         }
105         printf("\";\n");
106         return 0;
107 }