winepulse: Move AudioClient's GetService into mmdevapi.
[wine.git] / tools / winedump / nls.c
blobb52518604c840582fd1d9103f29503c792bb1e0a
1 /*
2 * Dump a NLS file
4 * Copyright 2020 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
28 #include "winedump.h"
29 #include "winnls.h"
30 #include "winternl.h"
32 static const void *read_data( unsigned int *pos, unsigned int size )
34 const void *ret = PRD( *pos, size );
35 *pos += size;
36 return ret;
39 static unsigned short mapchar( const unsigned short *table, unsigned int len, unsigned short ch )
41 unsigned int off = table[ch >> 8] + ((ch >> 4) & 0x0f);
42 if (off >= len) return 0;
43 off = table[off] + (ch & 0x0f);
44 if (off >= len) return 0;
45 return ch + table[off];
48 static unsigned int mapchar_high( const unsigned short *table, unsigned int len, unsigned int ch )
50 unsigned short ch1 = 0xd800 | ((ch - 0x10000) >> 10);
51 unsigned short ch2 = 0xdc00 | (ch & 0x3ff);
52 unsigned int off = table[256 + (ch1 - 0xd800)] + ((ch2 >> 5) & 0x1f);
53 if (off >= len) return 0;
54 off = table[off] + 2 * (ch2 & 0x1f);
55 if (off >= len) return 0;
56 return ch + *(UINT *)&table[off];
59 static void dump_offset_table( const unsigned short *table, unsigned int len )
61 int i, j, empty, ch;
63 for (i = empty = 0; i < 0x10000; i += 16)
65 for (j = 0; j < 16; j++) if (mapchar( table, len, i + j ) != i + j) break;
66 if (i && j == 16)
68 empty++;
69 continue;
71 if (empty) printf( "\n[...]" );
72 empty = 0;
73 printf( "\n%04x:", i );
74 for (j = 0; j < 16; j++)
76 ch = mapchar( table, len, i + j );
77 if (ch == i + j) printf( " ...." );
78 else printf( " %04x", ch );
81 if (table[0] >= 0x500)
83 for (i = 0x10000; i < 0x110000; i += 16)
85 for (j = 0; j < 16; j++) if (mapchar_high( table, len, i + j ) != i + j) break;
86 if (j == 16)
88 empty++;
89 continue;
91 if (empty) printf( "\n[...]" );
92 empty = 0;
93 printf( "\n%06x:", i );
94 for (j = 0; j < 16; j++)
96 ch = mapchar_high( table, len, i + j );
97 if (ch == i + j) printf( " ......" );
98 else printf( " %06x", ch );
102 if (empty) printf( "\n[...]" );
105 struct ctype
107 WORD c1, c2, c3;
110 static const char *get_ctype( const struct ctype *ctype )
112 static char buffer[100];
113 static const char *c1[] = { "up ", "lo ", "dg ", "sp ", "pt ", "cl ", "bl ", "xd ", "al " , "df "};
114 static const char *c2[] = { " ", "L ", "R ", "EN", "ES", "ET",
115 "AN", "CS", "B ", "S ", "WS", "ON" };
116 static const char *c3[] = { "ns ", "di ", "vo ", "sy ", "ka ", "hi ", "hw ", "fw ",
117 "id ", "ks ", "lx ", "hi ", "lo ", " ", " ", "al " };
118 int i;
119 strcpy( buffer, "| " );
120 for (i = 0; i < ARRAY_SIZE(c1); i++)
121 strcat( buffer, (ctype->c1 & (1 << i)) ? c1[i] : "__ " );
122 strcat( buffer, "| " );
123 strcat( buffer, ctype->c2 < ARRAY_SIZE(c2) ? c2[ctype->c2] : "??" );
124 strcat( buffer, " | " );
125 for (i = 0; i < ARRAY_SIZE(c3); i++)
126 strcat( buffer, (ctype->c3 & (1 << i)) ? c3[i] : "__ " );
127 strcat( buffer, "|" );
128 return buffer;
131 static void dump_ctype_table( const USHORT *ptr )
133 const struct ctype *ctypes = (const struct ctype *)(ptr + 2);
134 const BYTE *types = (const BYTE *)ptr + ptr[1] + 2;
135 int i, len = (ptr[1] - 2) / sizeof(*ctypes);
137 printf( " CTYPE1 CTYPE2 CTYPE3\n" );
138 for (i = 0; i < 0x10000; i++)
140 const BYTE *b = types + ((const WORD *)types)[i >> 8];
141 b = types + ((const WORD *)b)[(i >> 4) & 0x0f] + (i & 0x0f);
142 if (*b < len) printf( "%04x %s\n", i, get_ctype( ctypes + *b ));
143 else printf( "%04x ??? %02x\n", i, *b );
145 printf( "\n" );
148 static void dump_geo_table( const void *ptr )
150 const struct data
152 WCHAR signature[4]; /* L"geo" */
153 UINT total_size;
154 UINT ids_offset;
155 UINT nb_ids;
156 UINT locales_offset;
157 UINT nb_locales;
158 } *data = ptr;
160 const struct id
162 UINT id;
163 WCHAR latitude[12];
164 WCHAR longitude[12];
165 GEOCLASS class;
166 UINT parent;
167 WCHAR iso2[4];
168 WCHAR iso3[4];
169 USHORT uncode;
170 USHORT dialcode;
171 /* new versions only */
172 WCHAR currcode[4];
173 WCHAR currsymbol[8];
174 } *id;
176 const union locale
178 struct /* old version */
180 UINT lcid;
181 UINT id;
182 UINT lcid2;
183 } old;
184 struct /* new version */
186 WCHAR name[4];
187 UINT idx;
188 } new;
189 } *locale;
190 int i;
192 id = (const struct id *)((const BYTE *)data + data->ids_offset);
193 printf( "GEOIDs: (count %u)\n\n", data->nb_ids );
194 for (i = 0; i < data->nb_ids; i++)
196 if (!id[i].id) continue;
197 printf( "%u %5s %5s %s parent=%u lat=%s long=%s uncode=%u dialcode=%u currency=%s %s\n", id[i].id,
198 get_unicode_str( id[i].iso2, -1 ), get_unicode_str( id[i].iso3, -1 ),
199 id[i].class == GEOCLASS_NATION ? "nation" : id[i].class == GEOCLASS_REGION ? "region" : "???",
200 id[i].parent, get_unicode_str( id[i].latitude, -1 ), get_unicode_str( id[i].longitude, -1 ),
201 id[i].uncode, id[i].dialcode, get_unicode_str( id[i].currcode, -1 ),
202 get_unicode_str( id[i].currsymbol, -1 ));
205 locale = (const union locale *)((const BYTE *)data + data->locales_offset);
206 printf( "\nIndex: (count %u)\n\n", data->nb_locales );
207 for (i = 0; i < data->nb_locales; i++)
209 printf( "%-5s -> %u %s\n", get_unicode_str( locale[i].new.name, -1 ),
210 id[locale[i].new.idx].id, get_unicode_str( id[locale[i].new.idx].iso3, -1 ) );
214 static void dump_casemap(void)
216 unsigned int pos = 0, upper_len, lower_len;
217 const unsigned short *header, *upper, *lower;
219 if (!(header = read_data( &pos, 2 * sizeof(*header) ))) return;
220 upper_len = header[1];
221 if (!(upper = read_data( &pos, upper_len * sizeof(*upper) )))
223 printf( "Invalid len %04x\n", header[1] );
224 return;
226 lower_len = dump_total_len / sizeof(*lower) - 2 - upper_len;
227 if (!(lower = read_data( &pos, lower_len * sizeof(*lower) ))) return;
229 printf( "Magic: %04x\n", header[0] );
230 printf( "Upper-case table:\n" );
231 dump_offset_table( upper, upper_len );
232 printf( "\n\nLower-case table:\n" );
233 dump_offset_table( lower, lower_len );
234 printf( "\n\n" );
237 static void dump_codepage(void)
239 unsigned int i, j, uni2cp_offset, pos = 0;
240 const unsigned short *header, *ptr;
242 if (!(header = read_data( &pos, 13 * sizeof(*header) ))) return;
243 printf( "Codepage: %03u\n", header[1] );
244 printf( "Char size: %u\n", header[2] );
245 printf( "Default char A: %04x / %04x\n", header[3], header[5] );
246 printf( "Default char W: %04x / %04x\n", header[4], header[6] );
247 if (header[2] == 2)
249 printf( "Lead bytes: " );
250 for (i = 0; i < 12; i++)
252 unsigned char val = ((unsigned char *)(header + 7))[i];
253 if (!val) break;
254 printf( "%c%02x", (i % 2) ? '-' : ' ', val );
256 printf( "\n" );
258 printf( "\nCharacter map:\n" );
259 pos = header[0] * sizeof(*ptr);
260 if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
261 uni2cp_offset = pos / sizeof(*ptr) + *ptr;
262 if (!(ptr = read_data( &pos, 256 * sizeof(*ptr) ))) return;
263 for (i = 0; i < 256; i++)
265 if (!(i % 16)) printf( "\n%02x:", i );
266 printf( " %04x", ptr[i] );
268 printf( "\n" );
269 if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
270 if (*ptr == 256)
272 if (!(ptr = read_data( &pos, 256 * sizeof(*ptr) ))) return;
273 printf( "\nGlyph table:\n" );
274 for (i = 0; i < 256; i++)
276 if (!(i % 16)) printf( "\n%02x:", i );
277 printf( " %04x", ptr[i] );
279 printf( "\n" );
281 if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
282 if (*ptr)
284 if (!(ptr = read_data( &pos, (uni2cp_offset - pos) * sizeof(*ptr) ))) return;
285 for (i = 0; i < 256; i++)
287 if (!ptr[i] || ptr[i] > pos - 256) continue;
288 for (j = 0; j < 256; j++)
290 if (!(j % 16)) printf( "\n%02x%02x:", i, j );
291 printf( " %04x", ptr[ptr[i] + j] );
294 printf( "\n" );
296 printf( "\nUnicode table:\n" );
297 pos = uni2cp_offset * sizeof(*ptr);
298 if (header[2] == 2)
300 if (!(ptr = read_data( &pos, 65536 * sizeof(*ptr) ))) return;
301 for (i = 0; i < 65536; i++)
303 if (!(i % 16)) printf( "\n%04x:", i );
304 printf( " %04x", ptr[i] );
306 printf( "\n" );
308 else
310 const unsigned char *uni2cp;
311 if (!(uni2cp = read_data( &pos, 65536 ))) return;
312 for (i = 0; i < 65536; i++)
314 if (!(i % 16)) printf( "\n%04x:", i );
315 printf( " %02x", uni2cp[i] );
317 printf( "\n" );
319 printf( "\n" );
322 struct norm_table
324 WCHAR name[13]; /* 00 file name */
325 USHORT checksum[3]; /* 1a checksum? */
326 USHORT version[4]; /* 20 Unicode version */
327 USHORT form; /* 28 normalization form */
328 USHORT len_factor; /* 2a factor for length estimates */
329 USHORT unknown1; /* 2c */
330 USHORT decomp_size; /* 2e decomposition hash size */
331 USHORT comp_size; /* 30 composition hash size */
332 USHORT unknown2; /* 32 */
333 USHORT classes; /* 34 combining classes table offset */
334 USHORT props_level1; /* 36 char properties table level 1 offset */
335 USHORT props_level2; /* 38 char properties table level 2 offset */
336 USHORT decomp_hash; /* 3a decomposition hash table offset */
337 USHORT decomp_map; /* 3c decomposition character map table offset */
338 USHORT decomp_seq; /* 3e decomposition character sequences offset */
339 USHORT comp_hash; /* 40 composition hash table offset */
340 USHORT comp_seq; /* 42 composition character sequences offset */
343 static int offset_scale = 1; /* older versions use byte offsets */
345 #define GET_TABLE(info,table) ((const void *)((const BYTE *)info + (info->table * offset_scale)))
347 static unsigned int get_utf16( const WCHAR *str )
349 if (str[0] >= 0xd800 && str[0] <= 0xdbff &&
350 str[1] >= 0xdc00 && str[1] <= 0xdfff)
351 return 0x10000 + ((str[0] & 0x3ff) << 10) + (str[1] & 0x3ff);
352 return str[0];
355 static BYTE rol( BYTE val, BYTE count )
357 return (val << count) | (val >> (8 - count));
360 static unsigned char get_char_props( const struct norm_table *info, unsigned int ch )
362 const BYTE *level1 = GET_TABLE( info, props_level1 );
363 const BYTE *level2 = GET_TABLE( info, props_level2 );
364 BYTE off = level1[ch / 128];
366 if (!off || off >= 0xfb) return rol( off, 5 );
367 return level2[(off - 1) * 128 + ch % 128];
370 static const WCHAR *get_decomposition( const struct norm_table *info,
371 unsigned int ch, unsigned int *ret_len )
373 const USHORT *hash_table = GET_TABLE( info, decomp_hash );
374 const WCHAR *seq = GET_TABLE(info, decomp_seq );
375 const WCHAR *ret;
376 unsigned int i, pos, end, len, hash;
378 *ret_len = 1 + (ch >= 0x10000);
379 if (!info->decomp_size) return NULL;
380 hash = ch % info->decomp_size;
381 pos = hash_table[hash];
382 if (pos >> 13)
384 if (get_char_props( info, ch ) != 0xbf) return NULL;
385 ret = seq + (pos & 0x1fff);
386 len = pos >> 13;
388 else
390 const struct { WCHAR src; USHORT dst; } *pairs = GET_TABLE( info, decomp_map );
392 /* find the end of the hash bucket */
393 for (i = hash + 1; i < info->decomp_size; i++) if (!(hash_table[i] >> 13)) break;
394 if (i < info->decomp_size) end = hash_table[i];
395 else for (end = pos; pairs[end].src; end++) ;
397 for ( ; pos < end; pos++)
399 if (pairs[pos].src != (WCHAR)ch) continue;
400 ret = seq + (pairs[pos].dst & 0x1fff);
401 len = pairs[pos].dst >> 13;
402 break;
404 if (pos >= end) return NULL;
407 if (len == 7) while (ret[len]) len++;
408 *ret_len = len;
409 return ret;
412 static int cmp_compos( const void *a, const void *b )
414 int ret = ((unsigned int *)a)[0] - ((unsigned int *)b)[0];
415 if (!ret) ret = ((unsigned int *)a)[1] - ((unsigned int *)b)[1];
416 return ret;
419 static void dump_norm(void)
421 const struct norm_table *info;
422 const BYTE *classes;
423 unsigned int i;
424 char name[13];
426 if (!(info = PRD( 0, sizeof(*info) ))) return;
427 for (i = 0; i < sizeof(name); i++) name[i] = info->name[i];
428 printf( "Name: %s\n", name );
429 switch (info->form)
431 case 1: printf( "Form: NFC\n" ); break;
432 case 2: printf( "Form: NFD\n" ); break;
433 case 5: printf( "Form: NFKC\n" ); break;
434 case 6: printf( "Form: NFKD\n" ); break;
435 case 13: printf( "Form: IDNA\n" ); break;
436 default: printf( "Form: %u\n", info->form ); break;
438 printf( "Version: %u.%u.%u\n", info->version[0], info->version[1], info->version[2] );
439 printf( "Factor: %u\n", info->len_factor );
441 if (info->classes == sizeof(*info) / 2) offset_scale = 2;
442 classes = GET_TABLE( info, classes );
444 printf( "\nCharacter classes:\n" );
445 for (i = 0; i < 0x110000; i++)
447 BYTE flags = get_char_props( info, i );
449 if (!(i % 16)) printf( "\n%06x:", i );
450 if (!flags || (flags & 0x3f) == 0x3f)
452 static const char *flagstr[4] = { ".....", "Undef", "QC=No", "Inval" };
453 printf( " %s", flagstr[flags >> 6] );
455 else
457 static const char flagschar[4] = ".+*M";
458 BYTE class = classes[flags & 0x3f];
459 printf( " %c.%03u", flagschar[flags >> 6], class );
463 printf( "\n\nDecompositions:\n\n" );
464 for (i = 0; i < 0x110000; i++)
466 unsigned int j, len;
467 const WCHAR *decomp = get_decomposition( info, i, &len );
468 if (!decomp) continue;
469 printf( "%04x ->", i );
470 for (j = 0; j < len; j++)
472 unsigned int ch = get_utf16( decomp + j );
473 printf( " %04x", ch );
474 if (ch >= 0x10000) j++;
476 printf( "\n" );
478 if (info->comp_size)
480 unsigned int pos, len = (dump_total_len - info->comp_seq * offset_scale) / sizeof(WCHAR);
481 const WCHAR *seq = GET_TABLE( info, comp_seq );
482 unsigned int *map = xmalloc( len * sizeof(*map) );
484 printf( "\nCompositions:\n\n" );
486 /* ignore hash table, simply dump all the sequences */
487 for (i = pos = 0; i < len; pos += 3)
489 map[pos] = get_utf16( seq + i );
490 i += 1 + (map[pos] >= 0x10000);
491 map[pos+1] = get_utf16( seq + i );
492 i += 1 + (map[pos+1] >= 0x10000);
493 map[pos+2] = get_utf16( seq + i );
494 i += 1 + (map[pos+2] >= 0x10000);
496 qsort( map, pos / 3, 3 * sizeof(*map), cmp_compos );
497 for (i = 0; i < pos; i += 3) printf( "%04x %04x -> %04x\n", map[i], map[i + 1], map[i + 2] );
498 free( map );
500 printf( "\n" );
504 struct sortguid
506 GUID id; /* sort GUID */
507 UINT flags; /* flags */
508 UINT compr; /* offset to compression table */
509 UINT except; /* exception table offset in sortkey table */
510 UINT ling_except; /* exception table offset for linguistic casing */
511 UINT casemap; /* linguistic casemap table offset */
514 #define FLAG_HAS_3_BYTE_WEIGHTS 0x01
515 #define FLAG_REVERSEDIACRITICS 0x10
516 #define FLAG_DOUBLECOMPRESSION 0x20
517 #define FLAG_INVERSECASING 0x40
519 struct language_id
521 UINT offset;
522 WCHAR name[32];
525 struct compression
527 UINT offset;
528 WCHAR minchar, maxchar;
529 WORD len[8];
532 struct comprlang
534 struct compression compr;
535 WCHAR name[32];
538 static const char *get_sortkey( UINT key )
540 static char buffer[16];
541 if (!key) return "....";
542 if ((WORD)key == 0x200)
543 sprintf( buffer, "expand %04x", key >> 16 );
544 else
545 sprintf( buffer, "%u.%u.%u.%u", (BYTE)(key >> 8), (BYTE)key, (BYTE)(key >> 16), (BYTE)(key >> 24) );
546 return buffer;
549 static const void *dump_expansions( const UINT *ptr )
551 UINT i, count = *ptr++;
553 printf( "\nExpansions: (count=%04x)\n\n", count );
554 for (i = 0; i < count; i++)
556 const WCHAR *p = (const WCHAR *)(ptr + i);
557 printf( " %04x: %04x %04x\n", i, p[0], p[1] );
559 return ptr + count;
562 static void dump_exceptions( const UINT *sortkeys, DWORD offset )
564 int i, j;
565 const UINT *table = sortkeys + offset;
567 for (i = 0; i < 0x100; i++)
569 if (table[i] == i * 0x100) continue;
570 for (j = 0; j < 0x100; j++)
572 if (sortkeys[table[i] + j] == sortkeys[i * 0x100 + j]) continue;
573 printf( " %04x: %s\n", i * 0x100 + j, get_sortkey( sortkeys[table[i] + j] ));
578 static const void *dump_compression( const struct compression *compr, const WCHAR *table )
580 int i, j, k;
581 const WCHAR *p = table + compr->offset;
583 printf( " min=%04x max=%04x counts=%u,%u,%u,%u,%u,%u,%u,%u\n",
584 compr->minchar, compr->maxchar,
585 compr->len[0], compr->len[1], compr->len[2], compr->len[3],
586 compr->len[4], compr->len[5], compr->len[6], compr->len[7] );
587 for (i = 0; i < 8; i++)
589 for (j = 0; j < compr->len[i]; j++)
591 printf( " " );
592 for (k = 0; k < i + 2; k++) printf( " %04x", *p++ );
593 p = (const WCHAR *)(((ULONG_PTR)p + 3) & ~3);
594 printf( " -> %s\n", get_sortkey( *(const DWORD *)p ));
595 p += 2;
598 return p;
601 static const void *dump_multiple_weights( const UINT *ptr )
603 UINT i, count = *ptr++;
604 const WCHAR *p;
606 printf( "\nMultiple weights: (count=%u)\n\n", count );
607 p = (const WCHAR *)ptr;
608 for (i = 0; i < count; i++)
610 BYTE weight = p[i];
611 BYTE count = p[i] >> 8;
612 printf( "%u - %u\n", weight, weight + count );
614 return ptr + (count + 1) / 2;
617 static void dump_sort( int old_version )
619 const struct
621 UINT sortkeys;
622 UINT casemaps;
623 UINT ctypes;
624 UINT sortids;
625 } *header;
627 const struct compression *compr;
628 const struct sortguid *guids;
629 const struct comprlang *comprlangs;
630 const struct language_id *language_ids = NULL;
631 const WORD *casemaps, *map;
632 const UINT *sortkeys, *ptr;
633 const WCHAR *p = NULL;
634 int i, j, size, len;
635 int nb_casemaps = 0, casemap_offsets[16];
637 if (!(header = PRD( 0, sizeof(*header) ))) return;
639 if (!(sortkeys = PRD( header->sortkeys, header->casemaps - header->sortkeys ))) return;
640 printf( "\nSort keys:\n" );
641 for (i = 0; i < 0x10000; i++)
643 if (!(i % 8)) printf( "\n%04x:", i );
644 printf( " %16s", get_sortkey( sortkeys[i] ));
646 printf( "\n\n" );
648 size = (header->ctypes - header->casemaps) / sizeof(*casemaps);
649 if (!(casemaps = PRD( header->casemaps, size * sizeof(*casemaps) ))) return;
650 len = 0;
651 if (old_version)
653 ptr = (const UINT *)casemaps;
654 len = *ptr++;
655 language_ids = (const struct language_id *)ptr;
656 casemaps = (const WORD *)(language_ids + len);
658 map = casemaps;
659 while (size)
661 const WORD *upper = map + 2;
662 const WORD *lower = map + 2 + map[1];
663 const WORD *end = map + map[1] + 1 + map[map[1] + 1];
665 if (map[0] != 1) break;
666 printf( "\nCase mapping table %u:\n", nb_casemaps );
667 casemap_offsets[nb_casemaps++] = map - casemaps;
668 for (j = 0; j < len; j++)
670 if (language_ids[j].offset != map - casemaps) continue;
671 printf( "Language: %s\n", get_unicode_str( language_ids[j].name, -1 ));
672 break;
674 printf( "\nUpper-case table:\n" );
675 dump_offset_table( upper, lower - upper );
676 printf( "\n\nLower-case table:\n" );
677 dump_offset_table( lower, end - lower );
678 printf( "\n\n" );
679 size -= (end - map);
680 map = end;
683 if (!(p = PRD( header->ctypes, header->sortids - header->ctypes ))) return;
684 printf( "\nCTYPE table:\n\n" );
685 dump_ctype_table( p );
687 printf( "\nSort tables:\n\n" );
688 size = (dump_total_len - header->sortids) / sizeof(*ptr);
689 if (!(ptr = PRD( header->sortids, size * sizeof(*ptr) ))) return;
691 if (old_version)
693 len = *ptr++;
694 for (i = 0; i < len; i++, ptr += 2) printf( "NLS version: %08x %08x\n", ptr[0], ptr[1] );
695 len = *ptr++;
696 for (i = 0; i < len; i++, ptr += 2) printf( "Defined version: %08x %08x\n", ptr[0], ptr[1] );
697 len = *ptr++;
698 printf( "\nReversed diacritics:\n\n" );
699 for (i = 0; i < len; i++)
701 const WCHAR *name = (const WCHAR *)ptr;
702 printf( "%s\n", get_unicode_str( name, -1 ));
703 ptr += 16;
705 len = *ptr++;
706 printf( "\nDouble compression:\n\n" );
707 for (i = 0; i < len; i++)
709 const WCHAR *name = (const WCHAR *)ptr;
710 printf( "%s\n", get_unicode_str( name, -1 ));
711 ptr += 16;
713 ptr = dump_expansions( ptr );
715 printf( "\nCompressions:\n" );
716 size = *ptr++;
717 comprlangs = (const struct comprlang *)ptr;
718 for (i = 0; i < size; i++)
720 printf( "\n %s\n", get_unicode_str( comprlangs[i].name, -1 ));
721 ptr = dump_compression( &comprlangs[i].compr, (const WCHAR *)(comprlangs + size) );
724 ptr = dump_multiple_weights( ptr );
726 size = *ptr++;
727 printf( "\nJamo sort:\n\n" );
728 for (i = 0; i < size; i++, ptr += 2)
730 const struct jamo { BYTE val[5], off, len; } *jamo = (const struct jamo *)ptr;
731 printf( "%04x: %02x %02x %02x %02x %02x off=%02x len=%02x\n", 0x1100 + i, jamo->val[0],
732 jamo->val[1], jamo->val[2], jamo->val[3], jamo->val[4],
733 jamo->off, jamo->len );
736 size = *ptr++;
737 printf( "\nJamo second chars:\n\n" );
738 for (i = 0; i < size; i++, ptr += 2)
740 const struct jamo { WORD ch; BYTE val[5], len; } *jamo = (const struct jamo *)ptr;
741 printf( "%02x: %04x: %02x %02x %02x %02x %02x len=%02x\n", i, jamo->ch, jamo->val[0],
742 jamo->val[1], jamo->val[2], jamo->val[3], jamo->val[4], jamo->len );
745 size = *ptr++;
746 printf( "\nExceptions:\n" );
747 language_ids = (const struct language_id *)ptr;
748 for (i = 0; i < size; i++)
750 printf( "\n %08x %s\n", language_ids[i].offset, get_unicode_str( language_ids[i].name, -1 ));
751 dump_exceptions( sortkeys, language_ids[i].offset );
754 else
756 int guid_count = ptr[1];
757 printf( "NLS version: %08x\n\n", ptr[0] );
758 printf( "Sort GUIDs:\n\n" );
759 guids = (const struct sortguid *)(ptr + 2);
760 for (i = 0; i < guid_count; i++)
762 for (j = 0; j < nb_casemaps; j++) if (casemap_offsets[j] == guids[i].casemap) break;
763 printf( " %s flags=%08x compr=%08x casemap=%d\n", get_guid_str( &guids[i].id ),
764 guids[i].flags, guids[i].compr, j < nb_casemaps ? j : -1 );
767 ptr = dump_expansions( (const UINT *)(guids + guid_count) );
769 size = *ptr++;
770 printf( "\nCompressions:\n" );
771 compr = (const struct compression *)ptr;
772 for (i = 0; i < size; i++)
774 printf( "\n" );
775 for (j = 0; j < guid_count; j++)
776 if (guids[j].compr == i) printf( " %s\n", get_guid_str( &guids[j].id ));
777 ptr = dump_compression( compr + i, (const WCHAR *)(compr + size) );
780 ptr = dump_multiple_weights( ptr );
782 size = *ptr++;
783 printf( "\nJamo sort:\n\n" );
784 for (i = 0; i < size; i++)
786 static const WCHAR hangul_chars[] =
788 0xa960, 0xa961, 0xa962, 0xa963, 0xa964, 0xa965, 0xa966, 0xa967,
789 0xa968, 0xa969, 0xa96a, 0xa96b, 0xa96c, 0xa96d, 0xa96e, 0xa96f,
790 0xa970, 0xa971, 0xa972, 0xa973, 0xa974, 0xa975, 0xa976, 0xa977,
791 0xa978, 0xa979, 0xa97a, 0xa97b, 0xa97c,
792 0xd7b0, 0xd7b1, 0xd7b2, 0xd7b3, 0xd7b4, 0xd7b5, 0xd7b6, 0xd7b7,
793 0xd7b8, 0xd7b9, 0xd7ba, 0xd7bb, 0xd7bc, 0xd7bd, 0xd7be, 0xd7bf,
794 0xd7c0, 0xd7c1, 0xd7c2, 0xd7c3, 0xd7c4, 0xd7c5, 0xd7c6,
795 0xd7cb, 0xd7cc, 0xd7cd, 0xd7ce, 0xd7cf,
796 0xd7d0, 0xd7d1, 0xd7d2, 0xd7d3, 0xd7d4, 0xd7d5, 0xd7d6, 0xd7d7,
797 0xd7d8, 0xd7d9, 0xd7da, 0xd7db, 0xd7dc, 0xd7dd, 0xd7de, 0xd7df,
798 0xd7e0, 0xd7e1, 0xd7e2, 0xd7e3, 0xd7e4, 0xd7e5, 0xd7e6, 0xd7e7,
799 0xd7e8, 0xd7e9, 0xd7ea, 0xd7eb, 0xd7ec, 0xd7ed, 0xd7ee, 0xd7ef,
800 0xd7f0, 0xd7f1, 0xd7f2, 0xd7f3, 0xd7f4, 0xd7f5, 0xd7f6, 0xd7f7,
801 0xd7f8, 0xd7f9, 0xd7fa, 0xd7fb
803 const BYTE *b = (const BYTE *)(ptr + 2 * i);
804 WCHAR wc = i < 0x100 ? 0x1100 + i : hangul_chars[i - 0x100];
805 printf( "%04x: %02x %02x %02x %02x %02x\n", wc, b[0], b[1], b[2], b[3], b[4] );
808 printf( "\nExceptions:\n" );
809 for (i = 0; i < guid_count; i++)
811 if (!guids[i].except) continue;
812 printf( "\n %s\n", get_guid_str( &guids[i].id ));
813 dump_exceptions( sortkeys, guids[i].except );
814 if (!guids[i].ling_except) continue;
815 printf( "\n %s LINGUISTIC_CASING\n", get_guid_str( &guids[i].id ));
816 dump_exceptions( sortkeys, guids[i].ling_except );
819 printf( "\n" );
822 static const USHORT *locale_strings;
823 static DWORD locale_strings_len;
825 static const char *get_locale_string( DWORD offset )
827 static char buffer[1024];
828 int i = 0, len;
829 const WCHAR *p;
831 if (offset >= locale_strings_len) return "<invalid>";
832 len = locale_strings[offset];
833 if (offset + len + 1 > locale_strings_len) return "<invalid>";
834 p = locale_strings + offset + 1;
835 buffer[i++] = '"';
836 while (len--)
838 if (*p < 0x20)
840 i += sprintf( buffer + i, "\\%03o", *p );
842 else if (*p < 0x80)
844 buffer[i++] = *p;
846 else if (*p < 0x800)
848 buffer[i++] = 0xc0 | (*p >> 6);
849 buffer[i++] = 0x80 | (*p & 0x3f);
851 else if (*p >= 0xd800 && *p <= 0xdbff)
853 int val = 0x10000 + ((*p & 0x3ff) << 10) + (p[1] & 0x3ff);
854 buffer[i++] = 0xf0 | (val >> 18);
855 buffer[i++] = 0x80 | ((val >> 12) & 0x3f);
856 buffer[i++] = 0x80 | ((val >> 6) & 0x3f);
857 buffer[i++] = 0x80 | (val & 0x3f);
858 p++;
859 len--;
861 else
863 buffer[i++] = 0xe0 | (*p >> 12);
864 buffer[i++] = 0x80 | ((*p >> 6) & 0x3f);
865 buffer[i++] = 0x80 | (*p & 0x3f);
867 p++;
869 buffer[i++] = '"';
870 buffer[i] = 0;
871 return buffer;
874 static const char *get_locale_strarray( DWORD offset )
876 static char buffer[2048];
877 int i = 0, count;
878 const DWORD *array;
880 if (offset >= locale_strings_len) return "<invalid>";
881 count = locale_strings[offset];
882 if (offset + 1 + count * 2 > locale_strings_len) return "<invalid>";
883 array = (const DWORD *)(locale_strings + offset + 1);
884 buffer[i++] = '{';
885 while (count--)
887 if (i > 1) buffer[i++] = ' ';
888 i += sprintf( buffer + i, "%s", get_locale_string( *array++ ));
890 buffer[i++] = '}';
891 buffer[i] = 0;
892 return buffer;
895 static const char *get_locale_uints( DWORD offset )
897 static char buffer[1024];
898 int len;
899 const unsigned int *p;
901 buffer[0] = 0;
902 if (offset >= locale_strings_len) return "<invalid>";
903 len = locale_strings[offset];
904 if (offset + len + 1 > locale_strings_len) return "<invalid>";
905 if (len < 2) return "[]";
906 for (p = (unsigned int *)(locale_strings + offset + 1); len >= 2; p++, len -= 2)
907 sprintf( buffer + strlen(buffer), " %08x", *p );
908 buffer[0] = '[';
909 strcat( buffer, "]" );
910 return buffer;
913 static void dump_locale_table( const void *data_ptr, unsigned int len )
915 const struct calendar
917 USHORT icalintvalue; /* 00 */
918 USHORT itwodigityearmax; /* 02 */
919 UINT sshortdate; /* 04 */
920 UINT syearmonth; /* 08 */
921 UINT slongdate; /* 0c */
922 UINT serastring; /* 10 */
923 UINT iyearoffsetrange; /* 14 */
924 UINT sdayname; /* 18 */
925 UINT sabbrevdayname; /* 1c */
926 UINT smonthname; /* 20 */
927 UINT sabbrevmonthname; /* 24 */
928 UINT scalname; /* 28 */
929 UINT smonthday; /* 2c */
930 UINT sabbreverastring; /* 30 */
931 UINT sshortestdayname; /* 34 */
932 UINT srelativelongdate; /* 38 */
933 UINT unused[3]; /* 3c */
934 } *calendar;
936 const NLS_LOCALE_HEADER *data = data_ptr;
937 const NLS_LOCALE_LCID_INDEX *id;
938 const NLS_LOCALE_LCNAME_INDEX *lcname;
939 const NLS_LOCALE_DATA *locale;
940 int i, j;
941 int *indices, nb_aliases = 0;
943 printf( "offset: %08x\n", data->offset );
944 printf( "version: %u\n", data->version );
945 printf( "magic: %.4s\n", (char *)&data->magic );
947 locale_strings = (const USHORT *)((const BYTE *)data + data->strings_offset);
948 locale_strings_len = (const USHORT *)((const BYTE *)data + len) - locale_strings;
950 printf( "\nLCID to locale: (count=%u)\n", data->nb_lcids );
951 id = (const NLS_LOCALE_LCID_INDEX *)((const BYTE *)data + data->lcids_offset);
952 for (i = 0; i < data->nb_lcids; i++)
954 printf( " lcid %08x %s\n", id[i].id, get_locale_string( id[i].name ));
957 printf( "\nName to locale: (count=%u)\n", data->nb_lcnames );
958 indices = calloc( data->nb_locales, sizeof(*indices) );
959 lcname = (const NLS_LOCALE_LCNAME_INDEX *)((const BYTE *)data + data->lcnames_offset);
960 for (i = 0; i < data->nb_lcnames; i++)
962 printf( " lcid %08x %s\n", lcname[i].id, get_locale_string( lcname[i].name ));
963 if (indices[lcname[i].idx]++) nb_aliases++;
965 printf( "\nAliases: (count=%u)\n", nb_aliases );
966 for (i = 0; i < data->nb_lcnames; i++)
968 int idx = lcname[i].idx;
969 if (indices[idx] == 1) continue;
970 if (!indices[idx]) printf( " unused index %u\n", i );
971 else
973 printf( " " );
974 for (j = 0; j < data->nb_lcnames; j++)
975 if (lcname[j].idx == idx)
976 printf( " %08x %s", lcname[j].id, get_locale_string( lcname[j].name ));
977 printf( "\n" );
978 indices[idx] = 1;
982 printf( "\nLocales: (count=%u)\n", data->nb_locales );
983 memset( indices, 0, data->nb_locales * sizeof(*indices) );
984 for (i = 0; i < data->nb_lcnames; i++)
986 if (indices[lcname[i].idx]++) continue;
987 locale = (const NLS_LOCALE_DATA *)((const BYTE *)data + data->locales_offset + lcname[i].idx * data->locale_size);
988 printf( "Locale %s\n", get_locale_string( locale->sname ));
989 printf( " LOCALE_SNAME %s\n", get_locale_string( locale->sname ));
990 printf( " LOCALE_SOPENTYPELANGUAGETAG %s\n", get_locale_string( locale->sopentypelanguagetag ));
991 printf( " LOCALE_ILANGUAGE %04x\n", locale->ilanguage );
992 printf( " unique_lcid %04x\n", locale->unique_lcid );
993 printf( " LOCALE_IDIGITS %u\n", locale->idigits );
994 printf( " LOCALE_INEGNUMBER %u\n", locale->inegnumber );
995 printf( " LOCALE_ICURRDIGITS %u\n", locale->icurrdigits );
996 printf( " LOCALE_ICURRENCY %u\n", locale->icurrency );
997 printf( " LOCALE_INEGCURR %u\n", locale->inegcurr );
998 printf( " LOCALE_ILZERO %u\n", locale->ilzero );
999 printf( " LOCALE_INEUTRAL %u\n", !locale->inotneutral );
1000 printf( " LOCALE_IFIRSTDAYOFWEEK %u\n", (locale->ifirstdayofweek + 6) % 7 );
1001 printf( " LOCALE_IFIRSTWEEKOFYEAR %u\n", locale->ifirstweekofyear );
1002 printf( " LOCALE_ICOUNTRY %u\n", locale->icountry );
1003 printf( " LOCALE_IMEASURE %u\n", locale->imeasure );
1004 printf( " LOCALE_IDIGITSUBSTITUTION %u\n", locale->idigitsubstitution );
1005 printf( " LOCALE_SGROUPING %s\n", get_locale_string( locale->sgrouping ));
1006 printf( " LOCALE_SMONGROUPING %s\n", get_locale_string( locale->smongrouping ));
1007 printf( " LOCALE_SLIST %s\n", get_locale_string( locale->slist ));
1008 printf( " LOCALE_SDECIMAL %s\n", get_locale_string( locale->sdecimal ));
1009 printf( " LOCALE_STHOUSAND %s\n", get_locale_string( locale->sthousand ));
1010 printf( " LOCALE_SCURRENCY %s\n", get_locale_string( locale->scurrency ));
1011 printf( " LOCALE_SMONDECIMALSEP %s\n", get_locale_string( locale->smondecimalsep ));
1012 printf( " LOCALE_SMONTHOUSANDSEP %s\n", get_locale_string( locale->smonthousandsep ));
1013 printf( " LOCALE_SPOSITIVESIGN %s\n", get_locale_string( locale->spositivesign ));
1014 printf( " LOCALE_SNEGATIVESIGN %s\n", get_locale_string( locale->snegativesign ));
1015 printf( " LOCALE_S1159 %s\n", get_locale_string( locale->s1159 ));
1016 printf( " LOCALE_S2359 %s\n", get_locale_string( locale->s2359 ));
1017 printf( " LOCALE_SNATIVEDIGITS %s\n", get_locale_strarray( locale->snativedigits ));
1018 printf( " LOCALE_STIMEFORMAT %s\n", get_locale_strarray( locale->stimeformat ));
1019 printf( " LOCALE_SSHORTDATE %s\n", get_locale_strarray( locale->sshortdate ));
1020 printf( " LOCALE_SLONGDATE %s\n", get_locale_strarray( locale->slongdate ));
1021 printf( " LOCALE_SYEARMONTH %s\n", get_locale_strarray( locale->syearmonth ));
1022 printf( " LOCALE_SDURATION %s\n", get_locale_strarray( locale->sduration ));
1023 printf( " LOCALE_IDEFAULTLANGUAGE %04x\n", locale->idefaultlanguage );
1024 printf( " LOCALE_IDEFAULTANSICODEPAGE %u\n", locale->idefaultansicodepage );
1025 printf( " LOCALE_IDEFAULTCODEPAGE %u\n", locale->idefaultcodepage );
1026 printf( " LOCALE_IDEFAULTMACCODEPAGE %u\n", locale->idefaultmaccodepage );
1027 printf( " LOCALE_IDEFAULTEBCDICCODEPAGE %u\n", locale->idefaultebcdiccodepage );
1028 printf( " old_geoid(?) %u\n", locale->old_geoid );
1029 printf( " LOCALE_IPAPERSIZE %u\n", locale->ipapersize );
1030 printf( " islamic_cal %u %u\n", locale->islamic_cal[0], locale->islamic_cal[1] );
1031 printf( " LOCALE_SCALENDARTYPE %s\n", get_locale_string( locale->scalendartype ));
1032 printf( " LOCALE_SABBREVLANGNAME %s\n", get_locale_string( locale->sabbrevlangname ));
1033 printf( " LOCALE_SISO639LANGNAME %s\n", get_locale_string( locale->siso639langname ));
1034 printf( " LOCALE_SENGLANGUAGE %s\n", get_locale_string( locale->senglanguage ));
1035 printf( " LOCALE_SNATIVELANGNAME %s\n", get_locale_string( locale->snativelangname ));
1036 printf( " LOCALE_SENGCOUNTRY %s\n", get_locale_string( locale->sengcountry ));
1037 printf( " LOCALE_SNATIVECTRYNAME %s\n", get_locale_string( locale->snativectryname ));
1038 printf( " LOCALE_SABBREVCTRYNAME %s\n", get_locale_string( locale->sabbrevctryname ));
1039 printf( " LOCALE_SISO3166CTRYNAME %s\n", get_locale_string( locale->siso3166ctryname ));
1040 printf( " LOCALE_SINTLSYMBOL %s\n", get_locale_string( locale->sintlsymbol ));
1041 printf( " LOCALE_SENGCURRNAME %s\n", get_locale_string( locale->sengcurrname ));
1042 printf( " LOCALE_SNATIVECURRNAME %s\n", get_locale_string( locale->snativecurrname ));
1043 printf( " LOCALE_FONTSIGNATURE %s\n", get_locale_uints( locale->fontsignature ));
1044 printf( " LOCALE_SISO639LANGNAME2 %s\n", get_locale_string( locale->siso639langname2 ));
1045 printf( " LOCALE_SISO3166CTRYNAME2 %s\n", get_locale_string( locale->siso3166ctryname2 ));
1046 printf( " LOCALE_SPARENT %s\n", get_locale_string( locale->sparent ));
1047 printf( " LOCALE_SDAYNAME %s\n", get_locale_strarray( locale->sdayname ));
1048 printf( " LOCALE_SABBREVDAYNAME %s\n", get_locale_strarray( locale->sabbrevdayname ));
1049 printf( " LOCALE_SMONTHNAME %s\n", get_locale_strarray( locale->smonthname ));
1050 printf( " LOCALE_SABBREVMONTHNAME %s\n", get_locale_strarray( locale->sabbrevmonthname ));
1051 printf( " LOCALE_SGENITIVEMONTH %s\n", get_locale_strarray( locale->sgenitivemonth ));
1052 printf( " LOCALE_SABBREVGENITIVEMONTH %s\n", get_locale_strarray( locale->sabbrevgenitivemonth ));
1053 printf( " calendar names %s\n", get_locale_strarray( locale->calnames ));
1054 printf( " sort names %s\n", get_locale_strarray( locale->customsorts ));
1055 printf( " LOCALE_INEGATIVEPERCENT %u\n", locale->inegativepercent );
1056 printf( " LOCALE_IPOSITIVEPERCENT %u\n", locale->ipositivepercent );
1057 printf( " unknown1 %04x\n", locale->unknown1 );
1058 printf( " LOCALE_IREADINGLAYOUT %u\n", locale->ireadinglayout );
1059 printf( " unknown2 %04x %04x\n", locale->unknown2[0], locale->unknown2[1] );
1060 printf( " unused1 %04x\n", locale->unused1 );
1061 printf( " LOCALE_SENGLISHDISPLAYNAME %s\n", get_locale_string( locale->sengdisplayname ));
1062 printf( " LOCALE_SNATIVEDISPLAYNAME %s\n", get_locale_string( locale->snativedisplayname ));
1063 printf( " LOCALE_SPERCENT %s\n", get_locale_string( locale->spercent ));
1064 printf( " LOCALE_SNAN %s\n", get_locale_string( locale->snan ));
1065 printf( " LOCALE_SPOSINFINITY %s\n", get_locale_string( locale->sposinfinity ));
1066 printf( " LOCALE_SNEGINFINITY %s\n", get_locale_string( locale->sneginfinity ));
1067 printf( " unused2 %04x\n", locale->unused2 );
1068 printf( " CAL_SERASTRING %s\n", get_locale_string( locale->serastring ));
1069 printf( " CAL_SABBREVERASTRING %s\n", get_locale_string( locale->sabbreverastring ));
1070 printf( " unused3 %04x\n", locale->unused3 );
1071 printf( " LOCALE_SCONSOLEFALLBACKNAME %s\n", get_locale_string( locale->sconsolefallbackname ));
1072 printf( " LOCALE_SSHORTTIME %s\n", get_locale_strarray( locale->sshorttime ));
1073 printf( " LOCALE_SSHORTESTDAYNAME %s\n", get_locale_strarray( locale->sshortestdayname ));
1074 printf( " unused4 %04x\n", locale->unused4 );
1075 printf( " LOCALE_SSORTLOCALE %s\n", get_locale_string( locale->ssortlocale ));
1076 printf( " LOCALE_SKEYBOARDSTOINSTALL %s\n", get_locale_string( locale->skeyboardstoinstall ));
1077 printf( " LOCALE_SSCRIPTS %s\n", get_locale_string( locale->sscripts ));
1078 printf( " LOCALE_SRELATIVELONGDATE %s\n", get_locale_string( locale->srelativelongdate ));
1079 printf( " LOCALE_IGEOID %u\n", locale->igeoid );
1080 printf( " LOCALE_SSHORTESTAM %s\n", get_locale_string( locale->sshortestam ));
1081 printf( " LOCALE_SSHORTESTPM %s\n", get_locale_string( locale->sshortestpm ));
1082 printf( " LOCALE_SMONTHDAY %s\n", get_locale_strarray( locale->smonthday ));
1083 printf( " keyboard layout %s\n", get_locale_string( locale->keyboard_layout ));
1086 printf( "\nCalendars: (count=%u)\n\n", data->nb_calendars );
1087 for (i = 0; i < data->nb_calendars; i++)
1089 calendar = (const struct calendar *)((const BYTE *)data + data->calendars_offset + i * data->calendar_size);
1090 printf( "calendar %u:\n", i + 1 );
1091 printf( " CAL_ICALINTVALUE %u\n", calendar->icalintvalue );
1092 printf( " CAL_ITWODIGITYEARMAX %u\n", calendar->itwodigityearmax );
1093 printf( " CAL_SSHORTDATE %s\n", get_locale_strarray( calendar->sshortdate ));
1094 printf( " CAL_SYEARMONTH %s\n", get_locale_strarray( calendar->syearmonth ));
1095 printf( " CAL_SLONGDATE %s\n", get_locale_strarray( calendar->slongdate ));
1096 printf( " CAL_SERASTRING %s\n", get_locale_strarray( calendar->serastring ));
1097 printf( " CAL_IYEAROFFSETRANGE {" );
1098 if (calendar->iyearoffsetrange)
1100 UINT count = locale_strings[calendar->iyearoffsetrange];
1101 const DWORD *array = (const DWORD *)(locale_strings + calendar->iyearoffsetrange + 1);
1102 while (count--)
1104 const short *p = (const short *)locale_strings + *array++;
1105 printf( " era=%d,from=%d.%d.%d,zero=%d,first=%d", p[1], p[2], p[3], p[4], p[5], p[6] );
1108 printf( " }\n" );
1109 printf( " CAL_SDAYNAME %s\n", get_locale_strarray( calendar->sdayname ));
1110 printf( " CAL_SABBREVDAYNAME %s\n", get_locale_strarray( calendar->sabbrevdayname ));
1111 printf( " CAL_SMONTHNAME %s\n", get_locale_strarray( calendar->smonthname ));
1112 printf( " CAL_SABBREVMONTHNAME %s\n", get_locale_strarray( calendar->sabbrevmonthname ));
1113 printf( " CAL_SCALNAME %s\n", get_locale_string( calendar->scalname ));
1114 printf( " CAL_SMONTHDAY %s\n", get_locale_strarray( calendar->smonthday ));
1115 printf( " CAL_SABBREVERASTRING %s\n", get_locale_strarray( calendar->sabbreverastring ));
1116 printf( " CAL_SSHORTESTDAYNAME %s\n", get_locale_strarray( calendar->sshortestdayname ));
1117 printf( " CAL_SRELATIVELONGDATE %s\n", get_locale_string( calendar->srelativelongdate ));
1118 printf( " unused %04x %04x %04x\n",
1119 calendar->unused[0], calendar->unused[1], calendar->unused[2] );
1121 free( indices );
1124 static void dump_char_maps( const USHORT *ptr )
1126 int len;
1128 printf( "\nMAP_FOLDDIGITS:\n\n" );
1129 len = *ptr++ - 1;
1130 dump_offset_table( ptr, len );
1131 ptr += len;
1133 printf( "\n\nCompatibility map:\n" );
1134 len = *ptr++ - 1;
1135 dump_offset_table( ptr, len );
1136 ptr += len;
1138 printf( "\n\nLCMAP_HIRAGANA:\n" );
1139 len = *ptr++ - 1;
1140 dump_offset_table( ptr, len );
1141 ptr += len;
1143 printf( "\n\nLCMAP_KATAKANA:\n" );
1144 len = *ptr++ - 1;
1145 dump_offset_table( ptr, len );
1146 ptr += len;
1148 printf( "\n\nLCMAP_HALFWIDTH:\n" );
1149 len = *ptr++ - 1;
1150 dump_offset_table( ptr, len );
1151 ptr += len;
1153 printf( "\n\nLCMAP_FULLWIDTH:\n" );
1154 len = *ptr++ - 1;
1155 dump_offset_table( ptr, len );
1156 ptr += len;
1158 printf( "\n\nLCMAP_TRADITIONAL_CHINESE:\n" );
1159 len = *ptr++ - 1;
1160 dump_offset_table( ptr, len );
1161 ptr += len;
1163 printf( "\n\nLCMAP_SIMPLIFIED_CHINESE:\n" );
1164 len = *ptr++ - 1;
1165 dump_offset_table( ptr, len );
1166 ptr += len;
1168 printf( "\n\nUnknown table 1\n" );
1169 len = *ptr++ - 1;
1170 dump_offset_table( ptr, len );
1171 ptr += len;
1173 printf( "\n\nUnknown table 2:\n" );
1174 len = *ptr++;
1175 ptr += 2;
1176 dump_offset_table( ptr, len );
1177 ptr += len;
1178 dump_offset_table( ptr, len );
1179 printf( "\n\n" );
1182 static void dump_scripts( const DWORD *ptr )
1184 const struct range
1186 UINT from;
1187 UINT to;
1188 BYTE mask[16];
1189 } *range;
1190 int i, j, nb_ranges, nb_names;
1191 const WCHAR *names;
1193 nb_ranges = *ptr++;
1194 nb_names = *ptr++;
1195 range = (const struct range *)ptr;
1196 names = (const WCHAR *)(range + nb_ranges);
1197 for (i = 0; i < nb_ranges; i++)
1199 printf( "%08x-%08x", range[i].from, range[i].to );
1200 for (j = 0; j < min( nb_names, 16 * 8 ); j++)
1201 if ((range[i].mask[j / 8] & (1 << (j % 8))))
1202 printf( " %s", get_unicode_str( names + j * 4, 4 ));
1203 printf( "\n" );
1205 printf( "\n" );
1208 static void dump_locale(void)
1210 const struct
1212 UINT ctypes;
1213 UINT unused1;
1214 UINT unused2;
1215 UINT unused3;
1216 UINT locales;
1217 UINT charmaps;
1218 UINT geoids;
1219 UINT scripts;
1220 UINT tables[4];
1221 } *header;
1222 int i, nb_tables;
1223 const void *ptr;
1225 if (!(header = PRD( 0, sizeof(*header) ))) return;
1226 nb_tables = header->ctypes / 4;
1227 for (i = 8; i < nb_tables; i++)
1228 printf( "Table%u: %08x\n", i, header->tables[i - 8] );
1230 if (!(ptr = PRD( header->ctypes, header->locales - header->ctypes ))) return;
1231 printf( "\nCTYPE table:\n\n" );
1232 dump_ctype_table( ptr );
1234 if (!(ptr = PRD( header->locales, header->charmaps - header->locales ))) return;
1235 printf( "\nLocales:\n" );
1236 dump_locale_table( ptr, header->charmaps - header->locales );
1238 if (!(ptr = PRD( header->charmaps, header->geoids - header->charmaps ))) return;
1239 printf( "\nCharacter mapping tables:\n\n" );
1240 dump_char_maps( ptr );
1242 if (!(ptr = PRD( header->geoids, header->scripts - header->geoids ))) return;
1243 printf( "\nGeographic regions:\n\n" );
1244 dump_geo_table( ptr );
1246 if (!(ptr = PRD( header->scripts, dump_total_len - header->scripts ))) return;
1247 printf( "\nScripts:\n\n" );
1248 dump_scripts( ptr );
1251 static void dump_ctype(void)
1253 const USHORT *ptr;
1255 if (!(ptr = PRD( 0, dump_total_len ))) return;
1256 dump_ctype_table( ptr );
1259 static void dump_geo(void)
1261 const USHORT *ptr;
1263 if (!(ptr = PRD( 0, dump_total_len ))) return;
1264 dump_geo_table( ptr );
1267 void nls_dump(void)
1269 const char *name = get_basename( globals.input_name );
1270 if (!strcasecmp( name, "l_intl.nls" )) return dump_casemap();
1271 if (!strncasecmp( name, "c_", 2 )) return dump_codepage();
1272 if (!strncasecmp( name, "norm", 4 )) return dump_norm();
1273 if (!strcasecmp( name, "ctype.nls" )) return dump_ctype();
1274 if (!strcasecmp( name, "geo.nls" )) return dump_geo();
1275 if (!strcasecmp( name, "locale.nls" )) return dump_locale();
1276 if (!strcasecmp( name, "sortdefault.nls" )) return dump_sort( 0 );
1277 if (!strncasecmp( name, "sort", 4 )) return dump_sort( 1 );
1278 fprintf( stderr, "Unrecognized file name '%s'\n", globals.input_name );
1281 enum FileSig get_kind_nls(void)
1283 if (strlen( globals.input_name ) < 5) return SIG_UNKNOWN;
1284 if (strcasecmp( globals.input_name + strlen(globals.input_name) - 4, ".nls" )) return SIG_UNKNOWN;
1285 return SIG_NLS;