Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winedump/nls.c
4389 views
1
/*
2
* Dump a NLS file
3
*
4
* Copyright 2020 Alexandre Julliard
5
*
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.
10
*
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.
15
*
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
19
*/
20
21
#include "config.h"
22
23
#include <stdarg.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <assert.h>
27
28
#include "winedump.h"
29
#include "winnls.h"
30
#include "winternl.h"
31
32
static const void *read_data( unsigned int *pos, unsigned int size )
33
{
34
const void *ret = PRD( *pos, size );
35
*pos += size;
36
return ret;
37
}
38
39
static unsigned short mapchar( const unsigned short *table, unsigned int len, unsigned short ch )
40
{
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];
46
}
47
48
static unsigned int mapchar_high( const unsigned short *table, unsigned int len, unsigned int ch )
49
{
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];
57
}
58
59
static void dump_offset_table( const unsigned short *table, unsigned int len )
60
{
61
int i, j, empty, ch;
62
63
for (i = empty = 0; i < 0x10000; i += 16)
64
{
65
for (j = 0; j < 16; j++) if (mapchar( table, len, i + j ) != i + j) break;
66
if (i && j == 16)
67
{
68
empty++;
69
continue;
70
}
71
if (empty) printf( "\n[...]" );
72
empty = 0;
73
printf( "\n%04x:", i );
74
for (j = 0; j < 16; j++)
75
{
76
ch = mapchar( table, len, i + j );
77
if (ch == i + j) printf( " ...." );
78
else printf( " %04x", ch );
79
}
80
}
81
if (table[0] >= 0x500)
82
{
83
for (i = 0x10000; i < 0x110000; i += 16)
84
{
85
for (j = 0; j < 16; j++) if (mapchar_high( table, len, i + j ) != i + j) break;
86
if (j == 16)
87
{
88
empty++;
89
continue;
90
}
91
if (empty) printf( "\n[...]" );
92
empty = 0;
93
printf( "\n%06x:", i );
94
for (j = 0; j < 16; j++)
95
{
96
ch = mapchar_high( table, len, i + j );
97
if (ch == i + j) printf( " ......" );
98
else printf( " %06x", ch );
99
}
100
}
101
}
102
if (empty) printf( "\n[...]" );
103
}
104
105
struct ctype
106
{
107
WORD c1, c2, c3;
108
};
109
110
static const char *get_ctype( const struct ctype *ctype )
111
{
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;
129
}
130
131
static void dump_ctype_table( const USHORT *ptr )
132
{
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);
136
137
printf( " CTYPE1 CTYPE2 CTYPE3\n" );
138
for (i = 0; i < 0x10000; i++)
139
{
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 );
144
}
145
printf( "\n" );
146
}
147
148
static void dump_geo_table( const void *ptr )
149
{
150
const struct data
151
{
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;
159
160
const struct id
161
{
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;
175
176
const union locale
177
{
178
struct /* old version */
179
{
180
UINT lcid;
181
UINT id;
182
UINT lcid2;
183
} old;
184
struct /* new version */
185
{
186
WCHAR name[4];
187
UINT idx;
188
} new;
189
} *locale;
190
int i;
191
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++)
195
{
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 ));
203
}
204
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++)
208
{
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 ) );
211
}
212
}
213
214
static void dump_casemap(void)
215
{
216
unsigned int pos = 0, upper_len, lower_len;
217
const unsigned short *header, *upper, *lower;
218
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) )))
222
{
223
printf( "Invalid len %04x\n", header[1] );
224
return;
225
}
226
lower_len = dump_total_len / sizeof(*lower) - 2 - upper_len;
227
if (!(lower = read_data( &pos, lower_len * sizeof(*lower) ))) return;
228
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" );
235
}
236
237
static void dump_codepage(void)
238
{
239
unsigned int i, j, uni2cp_offset, pos = 0;
240
const unsigned short *header, *ptr;
241
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)
248
{
249
printf( "Lead bytes: " );
250
for (i = 0; i < 12; i++)
251
{
252
unsigned char val = ((unsigned char *)(header + 7))[i];
253
if (!val) break;
254
printf( "%c%02x", (i % 2) ? '-' : ' ', val );
255
}
256
printf( "\n" );
257
}
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++)
264
{
265
if (!(i % 16)) printf( "\n%02x:", i );
266
printf( " %04x", ptr[i] );
267
}
268
printf( "\n" );
269
if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
270
if (*ptr == 256)
271
{
272
if (!(ptr = read_data( &pos, 256 * sizeof(*ptr) ))) return;
273
printf( "\nGlyph table:\n" );
274
for (i = 0; i < 256; i++)
275
{
276
if (!(i % 16)) printf( "\n%02x:", i );
277
printf( " %04x", ptr[i] );
278
}
279
printf( "\n" );
280
}
281
if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
282
if (*ptr)
283
{
284
if (!(ptr = read_data( &pos, (uni2cp_offset - pos) * sizeof(*ptr) ))) return;
285
for (i = 0; i < 256; i++)
286
{
287
if (!ptr[i] || ptr[i] > pos - 256) continue;
288
for (j = 0; j < 256; j++)
289
{
290
if (!(j % 16)) printf( "\n%02x%02x:", i, j );
291
printf( " %04x", ptr[ptr[i] + j] );
292
}
293
}
294
printf( "\n" );
295
}
296
printf( "\nUnicode table:\n" );
297
pos = uni2cp_offset * sizeof(*ptr);
298
if (header[2] == 2)
299
{
300
if (!(ptr = read_data( &pos, 65536 * sizeof(*ptr) ))) return;
301
for (i = 0; i < 65536; i++)
302
{
303
if (!(i % 16)) printf( "\n%04x:", i );
304
printf( " %04x", ptr[i] );
305
}
306
printf( "\n" );
307
}
308
else
309
{
310
const unsigned char *uni2cp;
311
if (!(uni2cp = read_data( &pos, 65536 ))) return;
312
for (i = 0; i < 65536; i++)
313
{
314
if (!(i % 16)) printf( "\n%04x:", i );
315
printf( " %02x", uni2cp[i] );
316
}
317
printf( "\n" );
318
}
319
printf( "\n" );
320
}
321
322
struct norm_table
323
{
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 */
341
};
342
343
static int offset_scale = 1; /* older versions use byte offsets */
344
345
#define GET_TABLE(info,table) ((const void *)((const BYTE *)info + (info->table * offset_scale)))
346
347
static unsigned int get_utf16( const WCHAR *str )
348
{
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];
353
}
354
355
static BYTE rol( BYTE val, BYTE count )
356
{
357
return (val << count) | (val >> (8 - count));
358
}
359
360
static unsigned char get_char_props( const struct norm_table *info, unsigned int ch )
361
{
362
const BYTE *level1 = GET_TABLE( info, props_level1 );
363
const BYTE *level2 = GET_TABLE( info, props_level2 );
364
BYTE off = level1[ch / 128];
365
366
if (!off || off >= 0xfb) return rol( off, 5 );
367
return level2[(off - 1) * 128 + ch % 128];
368
}
369
370
static const WCHAR *get_decomposition( const struct norm_table *info,
371
unsigned int ch, unsigned int *ret_len )
372
{
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;
377
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)
383
{
384
if (get_char_props( info, ch ) != 0xbf) return NULL;
385
ret = seq + (pos & 0x1fff);
386
len = pos >> 13;
387
}
388
else
389
{
390
const struct { WCHAR src; USHORT dst; } *pairs = GET_TABLE( info, decomp_map );
391
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++) ;
396
397
for ( ; pos < end; pos++)
398
{
399
if (pairs[pos].src != (WCHAR)ch) continue;
400
ret = seq + (pairs[pos].dst & 0x1fff);
401
len = pairs[pos].dst >> 13;
402
break;
403
}
404
if (pos >= end) return NULL;
405
}
406
407
if (len == 7) while (ret[len]) len++;
408
*ret_len = len;
409
return ret;
410
}
411
412
static int cmp_compos( const void *a, const void *b )
413
{
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;
417
}
418
419
static void dump_norm(void)
420
{
421
const struct norm_table *info;
422
const BYTE *classes;
423
unsigned int i;
424
char name[13];
425
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)
430
{
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;
437
}
438
printf( "Version: %u.%u.%u\n", info->version[0], info->version[1], info->version[2] );
439
printf( "Factor: %u\n", info->len_factor );
440
441
if (info->classes == sizeof(*info) / 2) offset_scale = 2;
442
classes = GET_TABLE( info, classes );
443
444
printf( "\nCharacter classes:\n" );
445
for (i = 0; i < 0x110000; i++)
446
{
447
BYTE flags = get_char_props( info, i );
448
449
if (!(i % 16)) printf( "\n%06x:", i );
450
if (!flags || (flags & 0x3f) == 0x3f)
451
{
452
static const char *flagstr[4] = { ".....", "Undef", "QC=No", "Inval" };
453
printf( " %s", flagstr[flags >> 6] );
454
}
455
else
456
{
457
static const char flagschar[4] = ".+*M";
458
BYTE class = classes[flags & 0x3f];
459
printf( " %c.%03u", flagschar[flags >> 6], class );
460
}
461
}
462
463
printf( "\n\nDecompositions:\n\n" );
464
for (i = 0; i < 0x110000; i++)
465
{
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++)
471
{
472
unsigned int ch = get_utf16( decomp + j );
473
printf( " %04x", ch );
474
if (ch >= 0x10000) j++;
475
}
476
printf( "\n" );
477
}
478
if (info->comp_size)
479
{
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) );
483
484
printf( "\nCompositions:\n\n" );
485
486
/* ignore hash table, simply dump all the sequences */
487
for (i = pos = 0; i < len; pos += 3)
488
{
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);
495
}
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 );
499
}
500
printf( "\n" );
501
}
502
503
504
struct sortguid
505
{
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 */
512
};
513
514
#define FLAG_HAS_3_BYTE_WEIGHTS 0x01
515
#define FLAG_REVERSEDIACRITICS 0x10
516
#define FLAG_DOUBLECOMPRESSION 0x20
517
#define FLAG_INVERSECASING 0x40
518
519
struct language_id
520
{
521
UINT offset;
522
WCHAR name[32];
523
};
524
525
struct compression
526
{
527
UINT offset;
528
WCHAR minchar, maxchar;
529
WORD len[8];
530
};
531
532
struct comprlang
533
{
534
struct compression compr;
535
WCHAR name[32];
536
};
537
538
static const char *get_sortkey( UINT key )
539
{
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;
547
}
548
549
static const void *dump_expansions( const UINT *ptr )
550
{
551
UINT i, count = *ptr++;
552
553
printf( "\nExpansions: (count=%04x)\n\n", count );
554
for (i = 0; i < count; i++)
555
{
556
const WCHAR *p = (const WCHAR *)(ptr + i);
557
printf( " %04x: %04x %04x\n", i, p[0], p[1] );
558
}
559
return ptr + count;
560
}
561
562
static void dump_exceptions( const UINT *sortkeys, DWORD offset )
563
{
564
int i, j;
565
const UINT *table = sortkeys + offset;
566
567
for (i = 0; i < 0x100; i++)
568
{
569
if (table[i] == i * 0x100) continue;
570
for (j = 0; j < 0x100; j++)
571
{
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] ));
574
}
575
}
576
}
577
578
static const void *dump_compression( const struct compression *compr, const WCHAR *table )
579
{
580
int i, j, k;
581
const WCHAR *p = table + compr->offset;
582
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++)
588
{
589
for (j = 0; j < compr->len[i]; j++)
590
{
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;
596
}
597
}
598
return p;
599
}
600
601
static const void *dump_multiple_weights( const UINT *ptr )
602
{
603
UINT i, count = *ptr++;
604
const WCHAR *p;
605
606
printf( "\nMultiple weights: (count=%u)\n\n", count );
607
p = (const WCHAR *)ptr;
608
for (i = 0; i < count; i++)
609
{
610
BYTE weight = p[i];
611
BYTE count = p[i] >> 8;
612
printf( "%u - %u\n", weight, weight + count );
613
}
614
return ptr + (count + 1) / 2;
615
}
616
617
static void dump_sort( int old_version )
618
{
619
const struct
620
{
621
UINT sortkeys;
622
UINT casemaps;
623
UINT ctypes;
624
UINT sortids;
625
} *header;
626
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];
636
637
if (!(header = PRD( 0, sizeof(*header) ))) return;
638
639
if (!(sortkeys = PRD( header->sortkeys, header->casemaps - header->sortkeys ))) return;
640
printf( "\nSort keys:\n" );
641
for (i = 0; i < 0x10000; i++)
642
{
643
if (!(i % 8)) printf( "\n%04x:", i );
644
printf( " %16s", get_sortkey( sortkeys[i] ));
645
}
646
printf( "\n\n" );
647
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)
652
{
653
ptr = (const UINT *)casemaps;
654
len = *ptr++;
655
language_ids = (const struct language_id *)ptr;
656
casemaps = (const WORD *)(language_ids + len);
657
}
658
map = casemaps;
659
while (size)
660
{
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];
664
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++)
669
{
670
if (language_ids[j].offset != map - casemaps) continue;
671
printf( "Language: %s\n", get_unicode_str( language_ids[j].name, -1 ));
672
break;
673
}
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;
681
}
682
683
if (!(p = PRD( header->ctypes, header->sortids - header->ctypes ))) return;
684
printf( "\nCTYPE table:\n\n" );
685
dump_ctype_table( p );
686
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;
690
691
if (old_version)
692
{
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++)
700
{
701
const WCHAR *name = (const WCHAR *)ptr;
702
printf( "%s\n", get_unicode_str( name, -1 ));
703
ptr += 16;
704
}
705
len = *ptr++;
706
printf( "\nDouble compression:\n\n" );
707
for (i = 0; i < len; i++)
708
{
709
const WCHAR *name = (const WCHAR *)ptr;
710
printf( "%s\n", get_unicode_str( name, -1 ));
711
ptr += 16;
712
}
713
ptr = dump_expansions( ptr );
714
715
printf( "\nCompressions:\n" );
716
size = *ptr++;
717
comprlangs = (const struct comprlang *)ptr;
718
for (i = 0; i < size; i++)
719
{
720
printf( "\n %s\n", get_unicode_str( comprlangs[i].name, -1 ));
721
ptr = dump_compression( &comprlangs[i].compr, (const WCHAR *)(comprlangs + size) );
722
}
723
724
ptr = dump_multiple_weights( ptr );
725
726
size = *ptr++;
727
printf( "\nJamo sort:\n\n" );
728
for (i = 0; i < size; i++, ptr += 2)
729
{
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 );
734
}
735
736
size = *ptr++;
737
printf( "\nJamo second chars:\n\n" );
738
for (i = 0; i < size; i++, ptr += 2)
739
{
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 );
743
}
744
745
size = *ptr++;
746
printf( "\nExceptions:\n" );
747
language_ids = (const struct language_id *)ptr;
748
for (i = 0; i < size; i++)
749
{
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 );
752
}
753
}
754
else
755
{
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++)
761
{
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 );
765
}
766
767
ptr = dump_expansions( (const UINT *)(guids + guid_count) );
768
769
size = *ptr++;
770
printf( "\nCompressions:\n" );
771
compr = (const struct compression *)ptr;
772
for (i = 0; i < size; i++)
773
{
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) );
778
}
779
780
ptr = dump_multiple_weights( ptr );
781
782
size = *ptr++;
783
printf( "\nJamo sort:\n\n" );
784
for (i = 0; i < size; i++)
785
{
786
static const WCHAR hangul_chars[] =
787
{
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
802
};
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] );
806
}
807
808
printf( "\nExceptions:\n" );
809
for (i = 0; i < guid_count; i++)
810
{
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 );
817
}
818
}
819
printf( "\n" );
820
}
821
822
static const USHORT *locale_strings;
823
static DWORD locale_strings_len;
824
825
static const char *get_locale_string( DWORD offset )
826
{
827
static char buffer[1024];
828
int i = 0, len;
829
const WCHAR *p;
830
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--)
837
{
838
if (*p < 0x20)
839
{
840
i += sprintf( buffer + i, "\\%03o", *p );
841
}
842
else if (*p < 0x80)
843
{
844
buffer[i++] = *p;
845
}
846
else if (*p < 0x800)
847
{
848
buffer[i++] = 0xc0 | (*p >> 6);
849
buffer[i++] = 0x80 | (*p & 0x3f);
850
}
851
else if (*p >= 0xd800 && *p <= 0xdbff)
852
{
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--;
860
}
861
else
862
{
863
buffer[i++] = 0xe0 | (*p >> 12);
864
buffer[i++] = 0x80 | ((*p >> 6) & 0x3f);
865
buffer[i++] = 0x80 | (*p & 0x3f);
866
}
867
p++;
868
}
869
buffer[i++] = '"';
870
buffer[i] = 0;
871
return buffer;
872
}
873
874
static const char *get_locale_strarray( DWORD offset )
875
{
876
static char buffer[2048];
877
int i = 0, count;
878
const DWORD *array;
879
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--)
886
{
887
if (i > 1) buffer[i++] = ' ';
888
i += sprintf( buffer + i, "%s", get_locale_string( *array++ ));
889
}
890
buffer[i++] = '}';
891
buffer[i] = 0;
892
return buffer;
893
}
894
895
static const char *get_locale_uints( DWORD offset )
896
{
897
static char buffer[1024];
898
int len;
899
const unsigned int *p;
900
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;
911
}
912
913
static void dump_locale_table( const void *data_ptr, unsigned int len )
914
{
915
const struct calendar
916
{
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;
935
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;
942
943
printf( "offset: %08x\n", data->offset );
944
printf( "version: %u\n", data->version );
945
printf( "magic: %.4s\n", (char *)&data->magic );
946
947
locale_strings = (const USHORT *)((const BYTE *)data + data->strings_offset);
948
locale_strings_len = (const USHORT *)((const BYTE *)data + len) - locale_strings;
949
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++)
953
{
954
printf( " lcid %08x %s\n", id[i].id, get_locale_string( id[i].name ));
955
}
956
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++)
961
{
962
printf( " lcid %08x %s\n", lcname[i].id, get_locale_string( lcname[i].name ));
963
if (indices[lcname[i].idx]++) nb_aliases++;
964
}
965
printf( "\nAliases: (count=%u)\n", nb_aliases );
966
for (i = 0; i < data->nb_lcnames; i++)
967
{
968
int idx = lcname[i].idx;
969
if (indices[idx] == 1) continue;
970
if (!indices[idx]) printf( " unused index %u\n", i );
971
else
972
{
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;
979
}
980
}
981
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++)
985
{
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 ));
1084
}
1085
1086
printf( "\nCalendars: (count=%u)\n\n", data->nb_calendars );
1087
for (i = 0; i < data->nb_calendars; i++)
1088
{
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)
1099
{
1100
UINT count = locale_strings[calendar->iyearoffsetrange];
1101
const DWORD *array = (const DWORD *)(locale_strings + calendar->iyearoffsetrange + 1);
1102
while (count--)
1103
{
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] );
1106
}
1107
}
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] );
1120
}
1121
free( indices );
1122
}
1123
1124
static void dump_char_maps( const USHORT *ptr )
1125
{
1126
int len;
1127
1128
printf( "\nMAP_FOLDDIGITS:\n\n" );
1129
len = *ptr++ - 1;
1130
dump_offset_table( ptr, len );
1131
ptr += len;
1132
1133
printf( "\n\nCompatibility map:\n" );
1134
len = *ptr++ - 1;
1135
dump_offset_table( ptr, len );
1136
ptr += len;
1137
1138
printf( "\n\nLCMAP_HIRAGANA:\n" );
1139
len = *ptr++ - 1;
1140
dump_offset_table( ptr, len );
1141
ptr += len;
1142
1143
printf( "\n\nLCMAP_KATAKANA:\n" );
1144
len = *ptr++ - 1;
1145
dump_offset_table( ptr, len );
1146
ptr += len;
1147
1148
printf( "\n\nLCMAP_HALFWIDTH:\n" );
1149
len = *ptr++ - 1;
1150
dump_offset_table( ptr, len );
1151
ptr += len;
1152
1153
printf( "\n\nLCMAP_FULLWIDTH:\n" );
1154
len = *ptr++ - 1;
1155
dump_offset_table( ptr, len );
1156
ptr += len;
1157
1158
printf( "\n\nLCMAP_TRADITIONAL_CHINESE:\n" );
1159
len = *ptr++ - 1;
1160
dump_offset_table( ptr, len );
1161
ptr += len;
1162
1163
printf( "\n\nLCMAP_SIMPLIFIED_CHINESE:\n" );
1164
len = *ptr++ - 1;
1165
dump_offset_table( ptr, len );
1166
ptr += len;
1167
1168
printf( "\n\nUnknown table 1\n" );
1169
len = *ptr++ - 1;
1170
dump_offset_table( ptr, len );
1171
ptr += len;
1172
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" );
1180
}
1181
1182
static void dump_scripts( const DWORD *ptr )
1183
{
1184
const struct range
1185
{
1186
UINT from;
1187
UINT to;
1188
BYTE mask[16];
1189
} *range;
1190
int i, j, nb_ranges, nb_names;
1191
const WCHAR *names;
1192
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++)
1198
{
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" );
1204
}
1205
printf( "\n" );
1206
}
1207
1208
static void dump_locale(void)
1209
{
1210
const struct
1211
{
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;
1224
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] );
1229
1230
if (!(ptr = PRD( header->ctypes, header->locales - header->ctypes ))) return;
1231
printf( "\nCTYPE table:\n\n" );
1232
dump_ctype_table( ptr );
1233
1234
if (!(ptr = PRD( header->locales, header->charmaps - header->locales ))) return;
1235
printf( "\nLocales:\n" );
1236
dump_locale_table( ptr, header->charmaps - header->locales );
1237
1238
if (!(ptr = PRD( header->charmaps, header->geoids - header->charmaps ))) return;
1239
printf( "\nCharacter mapping tables:\n\n" );
1240
dump_char_maps( ptr );
1241
1242
if (!(ptr = PRD( header->geoids, header->scripts - header->geoids ))) return;
1243
printf( "\nGeographic regions:\n\n" );
1244
dump_geo_table( ptr );
1245
1246
if (!(ptr = PRD( header->scripts, dump_total_len - header->scripts ))) return;
1247
printf( "\nScripts:\n\n" );
1248
dump_scripts( ptr );
1249
}
1250
1251
static void dump_ctype(void)
1252
{
1253
const USHORT *ptr;
1254
1255
if (!(ptr = PRD( 0, dump_total_len ))) return;
1256
dump_ctype_table( ptr );
1257
}
1258
1259
static void dump_geo(void)
1260
{
1261
const USHORT *ptr;
1262
1263
if (!(ptr = PRD( 0, dump_total_len ))) return;
1264
dump_geo_table( ptr );
1265
}
1266
1267
void nls_dump(void)
1268
{
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 );
1279
}
1280
1281
enum FileSig get_kind_nls(void)
1282
{
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;
1286
}
1287
1288