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
30 static const void *read_data( unsigned int *pos
, unsigned int size
)
32 const void *ret
= PRD( *pos
, size
);
37 static unsigned short mapchar( const unsigned short *table
, unsigned int len
, unsigned short ch
)
39 unsigned int off
= table
[ch
>> 8] + ((ch
>> 4) & 0x0f);
40 if (off
>= len
) return 0;
41 off
= table
[off
] + (ch
& 0x0f);
42 if (off
>= len
) return 0;
43 return ch
+ table
[off
];
46 static void dump_offset_table( const unsigned short *table
, unsigned int len
)
50 for (i
= 0; i
< 0x10000; i
++)
52 if (!(i
% 16)) printf( "\n%04x:", i
);
53 ch
= mapchar( table
, len
, i
);
54 if (ch
== i
) printf( " ...." );
55 else printf( " %04x", ch
);
64 static const char *get_ctype( const struct ctype
*ctype
)
66 static char buffer
[100];
67 static const char *c1
[] = { "up ", "lo ", "dg ", "sp ", "pt ", "cl ", "bl ", "xd ", "al " };
68 static const char *c2
[] = { " ", "L ", "R ", "EN", "ES", "ET",
69 "AN", "CS", "B ", "S ", "WS", "ON" };
70 static const char *c3
[] = { "ns ", "di ", "vo ", "sy ", "ka ", "hi ", "hw ", "fw ",
71 "id ", "ks ", "lx ", "hi ", "lo ", " ", " ", "al " };
73 strcpy( buffer
, "| " );
74 for (i
= 0; i
< ARRAY_SIZE(c1
); i
++)
75 strcat( buffer
, (ctype
->c1
& (1 << i
)) ? c1
[i
] : "__ " );
76 strcat( buffer
, "| " );
77 strcat( buffer
, ctype
->c2
< ARRAY_SIZE(c2
) ? c2
[ctype
->c2
] : "??" );
78 strcat( buffer
, " | " );
79 for (i
= 0; i
< ARRAY_SIZE(c3
); i
++)
80 strcat( buffer
, (ctype
->c3
& (1 << i
)) ? c3
[i
] : "__ " );
81 strcat( buffer
, "|" );
85 static void dump_ctype_table( const USHORT
*ptr
)
87 const struct ctype
*ctypes
= (const struct ctype
*)(ptr
+ 2);
88 const BYTE
*types
= (const BYTE
*)ptr
+ ptr
[1] + 2;
89 int i
, len
= (ptr
[1] - 2) / sizeof(*ctypes
);
91 printf( " CTYPE1 CTYPE2 CTYPE3\n" );
92 for (i
= 0; i
< 0x10000; i
++)
94 const BYTE
*b
= types
+ ((const WORD
*)types
)[i
>> 8];
95 b
= types
+ ((const WORD
*)b
)[(i
>> 4) & 0x0f] + (i
& 0x0f);
96 if (*b
< len
) printf( "%04x %s\n", i
, get_ctype( ctypes
+ *b
));
97 else printf( "%04x ??? %02x\n", i
, *b
);
102 static void dump_casemap(void)
104 unsigned int pos
= 0, upper_len
, lower_len
;
105 const unsigned short *header
, *upper
, *lower
;
107 if (!(header
= read_data( &pos
, 2 * sizeof(*header
) ))) return;
108 upper_len
= header
[1];
109 if (!(upper
= read_data( &pos
, upper_len
* sizeof(*upper
) )))
111 printf( "Invalid len %04x\n", header
[1] );
114 lower_len
= dump_total_len
/ sizeof(*lower
) - 2 - upper_len
;
115 if (!(lower
= read_data( &pos
, lower_len
* sizeof(*lower
) ))) return;
117 printf( "Magic: %04x\n", header
[0] );
118 printf( "Upper-case table:\n" );
119 dump_offset_table( upper
, upper_len
);
120 printf( "\n\nLower-case table:\n" );
121 dump_offset_table( lower
, lower_len
);
125 static void dump_codepage(void)
127 unsigned int i
, j
, uni2cp_offset
, pos
= 0;
128 const unsigned short *header
, *ptr
;
130 if (!(header
= read_data( &pos
, 13 * sizeof(*header
) ))) return;
131 printf( "Codepage: %03u\n", header
[1] );
132 printf( "Char size: %u\n", header
[2] );
133 printf( "Default char A: %04x / %04x\n", header
[3], header
[5] );
134 printf( "Default char W: %04x / %04x\n", header
[4], header
[6] );
137 printf( "Lead bytes: " );
138 for (i
= 0; i
< 12; i
++)
140 unsigned char val
= ((unsigned char *)(header
+ 7))[i
];
142 printf( "%c%02x", (i
% 2) ? '-' : ' ', val
);
146 printf( "\nCharacter map:\n" );
147 pos
= header
[0] * sizeof(*ptr
);
148 if (!(ptr
= read_data( &pos
, sizeof(*ptr
) ))) return;
149 uni2cp_offset
= pos
/ sizeof(*ptr
) + *ptr
;
150 if (!(ptr
= read_data( &pos
, 256 * sizeof(*ptr
) ))) return;
151 for (i
= 0; i
< 256; i
++)
153 if (!(i
% 16)) printf( "\n%02x:", i
);
154 printf( " %04x", ptr
[i
] );
157 if (!(ptr
= read_data( &pos
, sizeof(*ptr
) ))) return;
160 if (!(ptr
= read_data( &pos
, 256 * sizeof(*ptr
) ))) return;
161 printf( "\nGlyph table:\n" );
162 for (i
= 0; i
< 256; i
++)
164 if (!(i
% 16)) printf( "\n%02x:", i
);
165 printf( " %04x", ptr
[i
] );
169 if (!(ptr
= read_data( &pos
, sizeof(*ptr
) ))) return;
172 if (!(ptr
= read_data( &pos
, (uni2cp_offset
- pos
) * sizeof(*ptr
) ))) return;
173 for (i
= 0; i
< 256; i
++)
175 if (!ptr
[i
] || ptr
[i
] > pos
- 256) continue;
176 for (j
= 0; j
< 256; j
++)
178 if (!(j
% 16)) printf( "\n%02x%02x:", i
, j
);
179 printf( " %04x", ptr
[ptr
[i
] + j
] );
184 printf( "\nUnicode table:\n" );
185 pos
= uni2cp_offset
* sizeof(*ptr
);
188 if (!(ptr
= read_data( &pos
, 65536 * sizeof(*ptr
) ))) return;
189 for (i
= 0; i
< 65536; i
++)
191 if (!(i
% 16)) printf( "\n%04x:", i
);
192 printf( " %04x", ptr
[i
] );
198 const unsigned char *uni2cp
;
199 if (!(uni2cp
= read_data( &pos
, 65536 ))) return;
200 for (i
= 0; i
< 65536; i
++)
202 if (!(i
% 16)) printf( "\n%04x:", i
);
203 printf( " %02x", uni2cp
[i
] );
212 WCHAR name
[13]; /* 00 file name */
213 USHORT checksum
[3]; /* 1a checksum? */
214 USHORT version
[4]; /* 20 Unicode version */
215 USHORT form
; /* 28 normalization form */
216 USHORT len_factor
; /* 2a factor for length estimates */
217 USHORT unknown1
; /* 2c */
218 USHORT decomp_size
; /* 2e decomposition hash size */
219 USHORT comp_size
; /* 30 composition hash size */
220 USHORT unknown2
; /* 32 */
221 USHORT classes
; /* 34 combining classes table offset */
222 USHORT props_level1
; /* 36 char properties table level 1 offset */
223 USHORT props_level2
; /* 38 char properties table level 2 offset */
224 USHORT decomp_hash
; /* 3a decomposition hash table offset */
225 USHORT decomp_map
; /* 3c decomposition character map table offset */
226 USHORT decomp_seq
; /* 3e decomposition character sequences offset */
227 USHORT comp_hash
; /* 40 composition hash table offset */
228 USHORT comp_seq
; /* 42 composition character sequences offset */
231 static int offset_scale
= 1; /* older versions use byte offsets */
233 #define GET_TABLE(info,table) ((const void *)((const BYTE *)info + (info->table * offset_scale)))
235 static unsigned int get_utf16( const WCHAR
*str
)
237 if (str
[0] >= 0xd800 && str
[0] <= 0xdbff &&
238 str
[1] >= 0xdc00 && str
[1] <= 0xdfff)
239 return 0x10000 + ((str
[0] & 0x3ff) << 10) + (str
[1] & 0x3ff);
243 static BYTE
rol( BYTE val
, BYTE count
)
245 return (val
<< count
) | (val
>> (8 - count
));
248 static unsigned char get_char_props( const struct norm_table
*info
, unsigned int ch
)
250 const BYTE
*level1
= GET_TABLE( info
, props_level1
);
251 const BYTE
*level2
= GET_TABLE( info
, props_level2
);
252 BYTE off
= level1
[ch
/ 128];
254 if (!off
|| off
>= 0xfb) return rol( off
, 5 );
255 return level2
[(off
- 1) * 128 + ch
% 128];
258 static const WCHAR
*get_decomposition( const struct norm_table
*info
,
259 unsigned int ch
, unsigned int *ret_len
)
261 const USHORT
*hash_table
= GET_TABLE( info
, decomp_hash
);
262 const WCHAR
*seq
= GET_TABLE(info
, decomp_seq
);
264 unsigned int i
, pos
, end
, len
, hash
;
266 *ret_len
= 1 + (ch
>= 0x10000);
267 if (!info
->decomp_size
) return NULL
;
268 hash
= ch
% info
->decomp_size
;
269 pos
= hash_table
[hash
];
272 if (get_char_props( info
, ch
) != 0xbf) return NULL
;
273 ret
= seq
+ (pos
& 0x1fff);
278 const struct { WCHAR src
; USHORT dst
; } *pairs
= GET_TABLE( info
, decomp_map
);
280 /* find the end of the hash bucket */
281 for (i
= hash
+ 1; i
< info
->decomp_size
; i
++) if (!(hash_table
[i
] >> 13)) break;
282 if (i
< info
->decomp_size
) end
= hash_table
[i
];
283 else for (end
= pos
; pairs
[end
].src
; end
++) ;
285 for ( ; pos
< end
; pos
++)
287 if (pairs
[pos
].src
!= (WCHAR
)ch
) continue;
288 ret
= seq
+ (pairs
[pos
].dst
& 0x1fff);
289 len
= pairs
[pos
].dst
>> 13;
292 if (pos
>= end
) return NULL
;
295 if (len
== 7) while (ret
[len
]) len
++;
300 static int cmp_compos( const void *a
, const void *b
)
302 int ret
= ((unsigned int *)a
)[0] - ((unsigned int *)b
)[0];
303 if (!ret
) ret
= ((unsigned int *)a
)[1] - ((unsigned int *)b
)[1];
307 static void dump_norm(void)
309 const struct norm_table
*info
;
314 if (!(info
= PRD( 0, sizeof(*info
) ))) return;
315 for (i
= 0; i
< sizeof(name
); i
++) name
[i
] = info
->name
[i
];
316 printf( "Name: %s\n", name
);
319 case 1: printf( "Form: NFC\n" ); break;
320 case 2: printf( "Form: NFD\n" ); break;
321 case 5: printf( "Form: NFKC\n" ); break;
322 case 6: printf( "Form: NFKD\n" ); break;
323 case 13: printf( "Form: IDNA\n" ); break;
324 default: printf( "Form: %u\n", info
->form
); break;
326 printf( "Version: %u.%u.%u\n", info
->version
[0], info
->version
[1], info
->version
[2] );
327 printf( "Factor: %u\n", info
->len_factor
);
329 if (info
->classes
== sizeof(*info
) / 2) offset_scale
= 2;
330 classes
= GET_TABLE( info
, classes
);
332 printf( "\nCharacter classes:\n" );
333 for (i
= 0; i
< 0x110000; i
++)
335 BYTE flags
= get_char_props( info
, i
);
337 if (!(i
% 16)) printf( "\n%06x:", i
);
338 if (!flags
|| (flags
& 0x3f) == 0x3f)
340 static const char *flagstr
[4] = { ".....", "Undef", "QC=No", "Inval" };
341 printf( " %s", flagstr
[flags
>> 6] );
345 static const char flagschar
[4] = ".+*M";
346 BYTE
class = classes
[flags
& 0x3f];
347 printf( " %c.%03u", flagschar
[flags
>> 6], class );
351 printf( "\n\nDecompositions:\n\n" );
352 for (i
= 0; i
< 0x110000; i
++)
355 const WCHAR
*decomp
= get_decomposition( info
, i
, &len
);
356 if (!decomp
) continue;
357 printf( "%04x ->", i
);
358 for (j
= 0; j
< len
; j
++)
360 unsigned int ch
= get_utf16( decomp
+ j
);
361 printf( " %04x", ch
);
362 if (ch
>= 0x10000) j
++;
368 unsigned int pos
, len
= (dump_total_len
- info
->comp_seq
* offset_scale
) / sizeof(WCHAR
);
369 const WCHAR
*seq
= GET_TABLE( info
, comp_seq
);
370 unsigned int *map
= xmalloc( len
* sizeof(*map
) );
372 printf( "\nCompositions:\n\n" );
374 /* ignore hash table, simply dump all the sequences */
375 for (i
= pos
= 0; i
< len
; pos
+= 3)
377 map
[pos
] = get_utf16( seq
+ i
);
378 i
+= 1 + (map
[pos
] >= 0x10000);
379 map
[pos
+1] = get_utf16( seq
+ i
);
380 i
+= 1 + (map
[pos
+1] >= 0x10000);
381 map
[pos
+2] = get_utf16( seq
+ i
);
382 i
+= 1 + (map
[pos
+2] >= 0x10000);
384 qsort( map
, pos
/ 3, 3 * sizeof(*map
), cmp_compos
);
385 for (i
= 0; i
< pos
; i
+= 3) printf( "%04x %04x -> %04x\n", map
[i
], map
[i
+ 1], map
[i
+ 2] );
394 GUID id
; /* sort GUID */
395 DWORD flags
; /* flags */
396 DWORD compr
; /* offset to compression table */
397 DWORD except
; /* exception table offset in sortkey table */
398 DWORD ling_except
; /* exception table offset for linguistic casing */
399 DWORD casemap
; /* linguistic casemap table offset */
402 #define FLAG_HAS_3_BYTE_WEIGHTS 0x01
403 #define FLAG_REVERSEDIACRITICS 0x10
404 #define FLAG_DOUBLECOMPRESSION 0x20
405 #define FLAG_INVERSECASING 0x40
416 WCHAR minchar
, maxchar
;
422 struct compression compr
;
426 static const char *get_sortkey( DWORD key
)
428 static char buffer
[16];
429 if (!key
) return "....";
430 if ((WORD
)key
== 0x200)
431 sprintf( buffer
, "expand %04x", key
>> 16 );
433 sprintf( buffer
, "%u.%u.%u.%u", (BYTE
)(key
>> 8), (BYTE
)key
, (BYTE
)(key
>> 16), (BYTE
)(key
>> 24) );
437 static const void *dump_expansions( const DWORD
*ptr
)
439 DWORD i
, count
= *ptr
++;
441 printf( "\nExpansions: (count=%04x)\n\n", count
);
442 for (i
= 0; i
< count
; i
++)
444 const WCHAR
*p
= (const WCHAR
*)(ptr
+ i
);
445 printf( " %04x: %04x %04x\n", i
, p
[0], p
[1] );
450 static void dump_exceptions( const DWORD
*sortkeys
, DWORD offset
)
453 const DWORD
*table
= sortkeys
+ offset
;
455 for (i
= 0; i
< 0x100; i
++)
457 if (table
[i
] == i
* 0x100) continue;
458 for (j
= 0; j
< 0x100; j
++)
460 if (sortkeys
[table
[i
] + j
] == sortkeys
[i
* 0x100 + j
]) continue;
461 printf( " %04x: %s\n", i
* 0x100 + j
, get_sortkey( sortkeys
[table
[i
] + j
] ));
466 static const void *dump_compression( const struct compression
*compr
, const WCHAR
*table
)
469 const WCHAR
*p
= table
+ compr
->offset
;
471 printf( " min=%04x max=%04x counts=%u,%u,%u,%u,%u,%u,%u,%u\n",
472 compr
->minchar
, compr
->maxchar
,
473 compr
->len
[0], compr
->len
[1], compr
->len
[2], compr
->len
[3],
474 compr
->len
[4], compr
->len
[5], compr
->len
[6], compr
->len
[7] );
475 for (i
= 0; i
< 8; i
++)
477 for (j
= 0; j
< compr
->len
[i
]; j
++)
480 for (k
= 0; k
< i
+ 2; k
++) printf( " %04x", *p
++ );
481 p
= (const WCHAR
*)(((ULONG_PTR
)p
+ 3) & ~3);
482 printf( " -> %s\n", get_sortkey( *(const DWORD
*)p
));
489 static const void *dump_multiple_weights( const DWORD
*ptr
)
491 int i
, count
= *ptr
++;
494 printf( "\nMultiple weights: (count=%u)\n\n", count
);
495 p
= (const WCHAR
*)ptr
;
496 for (i
= 0; i
< count
; i
++)
499 BYTE count
= p
[i
] >> 8;
500 printf( "%u - %u\n", weight
, weight
+ count
);
502 return ptr
+ (count
+ 1) / 2;
505 static void dump_sort( int old_version
)
515 const struct compression
*compr
;
516 const struct sortguid
*guids
;
517 const struct comprlang
*comprlangs
;
518 const struct language_id
*language_ids
= NULL
;
519 const WORD
*casemaps
, *map
;
520 const DWORD
*sortkeys
, *ptr
;
521 const WCHAR
*p
= NULL
;
523 int nb_casemaps
= 0, casemap_offsets
[16];
525 if (!(header
= PRD( 0, sizeof(*header
) ))) return;
527 if (!(sortkeys
= PRD( header
->sortkeys
, header
->casemaps
- header
->sortkeys
))) return;
528 printf( "\nSort keys:\n" );
529 for (i
= 0; i
< 0x10000; i
++)
531 if (!(i
% 8)) printf( "\n%04x:", i
);
532 printf( " %16s", get_sortkey( sortkeys
[i
] ));
536 size
= (header
->ctypes
- header
->casemaps
) / sizeof(*casemaps
);
537 if (!(casemaps
= PRD( header
->casemaps
, size
* sizeof(*casemaps
) ))) return;
541 ptr
= (const DWORD
*)casemaps
;
543 language_ids
= (const struct language_id
*)ptr
;
544 casemaps
= (const WORD
*)(language_ids
+ len
);
549 const WORD
*upper
= map
+ 2;
550 const WORD
*lower
= map
+ 2 + map
[1];
551 const WORD
*end
= map
+ map
[1] + 1 + map
[map
[1] + 1];
553 if (map
[0] != 1) break;
554 printf( "\nCase mapping table %u:\n", nb_casemaps
);
555 casemap_offsets
[nb_casemaps
++] = map
- casemaps
;
556 for (j
= 0; j
< len
; j
++)
558 if (language_ids
[j
].offset
!= map
- casemaps
) continue;
559 printf( "Language: %s\n", get_unicode_str( language_ids
[j
].name
, -1 ));
562 printf( "\nUpper-case table:\n" );
563 dump_offset_table( upper
, lower
- upper
);
564 printf( "\n\nLower-case table:\n" );
565 dump_offset_table( lower
, end
- lower
);
571 if (!(p
= PRD( header
->ctypes
, header
->sortids
- header
->ctypes
))) return;
572 printf( "\nCTYPE table:\n\n" );
573 dump_ctype_table( p
);
575 printf( "\nSort tables:\n\n" );
576 size
= (dump_total_len
- header
->sortids
) / sizeof(*ptr
);
577 if (!(ptr
= PRD( header
->sortids
, size
* sizeof(*ptr
) ))) return;
582 for (i
= 0; i
< len
; i
++, ptr
+= 2) printf( "NLS version: %08x %08x\n", ptr
[0], ptr
[1] );
584 for (i
= 0; i
< len
; i
++, ptr
+= 2) printf( "Defined version: %08x %08x\n", ptr
[0], ptr
[1] );
586 printf( "\nReversed diacritics:\n\n" );
587 for (i
= 0; i
< len
; i
++)
589 const WCHAR
*name
= (const WCHAR
*)ptr
;
590 printf( "%s\n", get_unicode_str( name
, -1 ));
594 printf( "\nDouble compression:\n\n" );
595 for (i
= 0; i
< len
; i
++)
597 const WCHAR
*name
= (const WCHAR
*)ptr
;
598 printf( "%s\n", get_unicode_str( name
, -1 ));
601 ptr
= dump_expansions( ptr
);
603 printf( "\nCompressions:\n" );
605 comprlangs
= (const struct comprlang
*)ptr
;
606 for (i
= 0; i
< size
; i
++)
608 printf( "\n %s\n", get_unicode_str( comprlangs
[i
].name
, -1 ));
609 ptr
= dump_compression( &comprlangs
[i
].compr
, (const WCHAR
*)(comprlangs
+ size
) );
612 ptr
= dump_multiple_weights( ptr
);
615 printf( "\nJamo sort:\n\n" );
616 for (i
= 0; i
< size
; i
++, ptr
+= 2)
618 const struct jamo
{ BYTE val
[5], off
, len
; } *jamo
= (const struct jamo
*)ptr
;
619 printf( "%04x: %02x %02x %02x %02x %02x off=%02x len=%02x\n", 0x1100 + i
, jamo
->val
[0],
620 jamo
->val
[1], jamo
->val
[2], jamo
->val
[3], jamo
->val
[4],
621 jamo
->off
, jamo
->len
);
625 printf( "\nJamo second chars:\n\n" );
626 for (i
= 0; i
< size
; i
++, ptr
+= 2)
628 const struct jamo
{ WORD ch
; BYTE val
[5], len
; } *jamo
= (const struct jamo
*)ptr
;
629 printf( "%02x: %04x: %02x %02x %02x %02x %02x len=%02x\n", i
, jamo
->ch
, jamo
->val
[0],
630 jamo
->val
[1], jamo
->val
[2], jamo
->val
[3], jamo
->val
[4], jamo
->len
);
634 printf( "\nExceptions:\n" );
635 language_ids
= (const struct language_id
*)ptr
;
636 for (i
= 0; i
< size
; i
++)
638 printf( "\n %08x %s\n", language_ids
[i
].offset
, get_unicode_str( language_ids
[i
].name
, -1 ));
639 dump_exceptions( sortkeys
, language_ids
[i
].offset
);
644 int guid_count
= ptr
[1];
645 printf( "NLS version: %08x\n\n", ptr
[0] );
646 printf( "Sort GUIDs:\n\n" );
647 guids
= (const struct sortguid
*)(ptr
+ 2);
648 for (i
= 0; i
< guid_count
; i
++)
650 for (j
= 0; j
< nb_casemaps
; j
++) if (casemap_offsets
[j
] == guids
[i
].casemap
) break;
651 printf( " %s flags=%08x compr=%08x casemap=%d\n", get_guid_str( &guids
[i
].id
),
652 guids
[i
].flags
, guids
[i
].compr
, j
< nb_casemaps
? j
: -1 );
655 ptr
= dump_expansions( (const DWORD
*)(guids
+ guid_count
) );
658 printf( "\nCompressions:\n" );
659 compr
= (const struct compression
*)ptr
;
660 for (i
= 0; i
< size
; i
++)
663 for (j
= 0; j
< guid_count
; j
++)
664 if (guids
[j
].compr
== i
) printf( " %s\n", get_guid_str( &guids
[j
].id
));
665 ptr
= dump_compression( compr
+ i
, (const WCHAR
*)(compr
+ size
) );
668 ptr
= dump_multiple_weights( ptr
);
671 printf( "\nJamo sort:\n\n" );
672 for (i
= 0; i
< size
; i
++)
674 static const WCHAR hangul_chars
[] =
676 0xa960, 0xa961, 0xa962, 0xa963, 0xa964, 0xa965, 0xa966, 0xa967,
677 0xa968, 0xa969, 0xa96a, 0xa96b, 0xa96c, 0xa96d, 0xa96e, 0xa96f,
678 0xa970, 0xa971, 0xa972, 0xa973, 0xa974, 0xa975, 0xa976, 0xa977,
679 0xa978, 0xa979, 0xa97a, 0xa97b, 0xa97c,
680 0xd7b0, 0xd7b1, 0xd7b2, 0xd7b3, 0xd7b4, 0xd7b5, 0xd7b6, 0xd7b7,
681 0xd7b8, 0xd7b9, 0xd7ba, 0xd7bb, 0xd7bc, 0xd7bd, 0xd7be, 0xd7bf,
682 0xd7c0, 0xd7c1, 0xd7c2, 0xd7c3, 0xd7c4, 0xd7c5, 0xd7c6,
683 0xd7cb, 0xd7cc, 0xd7cd, 0xd7ce, 0xd7cf,
684 0xd7d0, 0xd7d1, 0xd7d2, 0xd7d3, 0xd7d4, 0xd7d5, 0xd7d6, 0xd7d7,
685 0xd7d8, 0xd7d9, 0xd7da, 0xd7db, 0xd7dc, 0xd7dd, 0xd7de, 0xd7df,
686 0xd7e0, 0xd7e1, 0xd7e2, 0xd7e3, 0xd7e4, 0xd7e5, 0xd7e6, 0xd7e7,
687 0xd7e8, 0xd7e9, 0xd7ea, 0xd7eb, 0xd7ec, 0xd7ed, 0xd7ee, 0xd7ef,
688 0xd7f0, 0xd7f1, 0xd7f2, 0xd7f3, 0xd7f4, 0xd7f5, 0xd7f6, 0xd7f7,
689 0xd7f8, 0xd7f9, 0xd7fa, 0xd7fb
691 const BYTE
*b
= (const BYTE
*)(ptr
+ 2 * i
);
692 WCHAR wc
= i
< 0x100 ? 0x1100 + i
: hangul_chars
[i
- 0x100];
693 printf( "%04x: %02x %02x %02x %02x %02x\n", wc
, b
[0], b
[1], b
[2], b
[3], b
[4] );
696 printf( "\nExceptions:\n" );
697 for (i
= 0; i
< guid_count
; i
++)
699 if (!guids
[i
].except
) continue;
700 printf( "\n %s\n", get_guid_str( &guids
[i
].id
));
701 dump_exceptions( sortkeys
, guids
[i
].except
);
702 if (!guids
[i
].ling_except
) continue;
703 printf( "\n %s LINGUISTIC_CASING\n", get_guid_str( &guids
[i
].id
));
704 dump_exceptions( sortkeys
, guids
[i
].ling_except
);
712 const char *name
= get_basename( globals
.input_name
);
713 if (!strcasecmp( name
, "l_intl.nls" )) return dump_casemap();
714 if (!strncasecmp( name
, "c_", 2 )) return dump_codepage();
715 if (!strncasecmp( name
, "norm", 4 )) return dump_norm();
716 if (!strcasecmp( name
, "sortdefault.nls" )) return dump_sort( 0 );
717 if (!strncasecmp( name
, "sort", 4 )) return dump_sort( 1 );
718 fprintf( stderr
, "Unrecognized file name '%s'\n", globals
.input_name
);
721 enum FileSig
get_kind_nls(void)
723 if (strlen( globals
.input_name
) < 5) return SIG_UNKNOWN
;
724 if (strcasecmp( globals
.input_name
+ strlen(globals
.input_name
) - 4, ".nls" )) return SIG_UNKNOWN
;