nls.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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. #include "config.h"
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <assert.h>
  24. #include "windef.h"
  25. #include "winedump.h"
  26. static const void *read_data( unsigned int *pos, unsigned int size )
  27. {
  28. const void *ret = PRD( *pos, size );
  29. *pos += size;
  30. return ret;
  31. }
  32. static unsigned short mapchar( const unsigned short *table, unsigned int len, unsigned short ch )
  33. {
  34. unsigned int off = table[ch >> 8] + ((ch >> 4) & 0x0f);
  35. if (off >= len) return 0;
  36. off = table[off] + (ch & 0x0f);
  37. if (off >= len) return 0;
  38. return ch + table[off];
  39. }
  40. static void dump_offset_table( const unsigned short *table, unsigned int len )
  41. {
  42. int i, ch;
  43. for (i = 0; i < 0x10000; i++)
  44. {
  45. if (!(i % 16)) printf( "\n%04x:", i );
  46. ch = mapchar( table, len, i );
  47. if (ch == i) printf( " ...." );
  48. else printf( " %04x", ch );
  49. }
  50. }
  51. struct ctype
  52. {
  53. WORD c1, c2, c3;
  54. };
  55. static const char *get_ctype( const struct ctype *ctype )
  56. {
  57. static char buffer[100];
  58. static const char *c1[] = { "up ", "lo ", "dg ", "sp ", "pt ", "cl ", "bl ", "xd ", "al " };
  59. static const char *c2[] = { " ", "L ", "R ", "EN", "ES", "ET",
  60. "AN", "CS", "B ", "S ", "WS", "ON" };
  61. static const char *c3[] = { "ns ", "di ", "vo ", "sy ", "ka ", "hi ", "hw ", "fw ",
  62. "id ", "ks ", "lx ", "hi ", "lo ", " ", " ", "al " };
  63. int i;
  64. strcpy( buffer, "| " );
  65. for (i = 0; i < ARRAY_SIZE(c1); i++)
  66. strcat( buffer, (ctype->c1 & (1 << i)) ? c1[i] : "__ " );
  67. strcat( buffer, "| " );
  68. strcat( buffer, ctype->c2 < ARRAY_SIZE(c2) ? c2[ctype->c2] : "??" );
  69. strcat( buffer, " | " );
  70. for (i = 0; i < ARRAY_SIZE(c3); i++)
  71. strcat( buffer, (ctype->c3 & (1 << i)) ? c3[i] : "__ " );
  72. strcat( buffer, "|" );
  73. return buffer;
  74. }
  75. static void dump_ctype_table( const USHORT *ptr )
  76. {
  77. const struct ctype *ctypes = (const struct ctype *)(ptr + 2);
  78. const BYTE *types = (const BYTE *)ptr + ptr[1] + 2;
  79. int i, len = (ptr[1] - 2) / sizeof(*ctypes);
  80. printf( " CTYPE1 CTYPE2 CTYPE3\n" );
  81. for (i = 0; i < 0x10000; i++)
  82. {
  83. const BYTE *b = types + ((const WORD *)types)[i >> 8];
  84. b = types + ((const WORD *)b)[(i >> 4) & 0x0f] + (i & 0x0f);
  85. if (*b < len) printf( "%04x %s\n", i, get_ctype( ctypes + *b ));
  86. else printf( "%04x ??? %02x\n", i, *b );
  87. }
  88. printf( "\n" );
  89. }
  90. static void dump_casemap(void)
  91. {
  92. unsigned int pos = 0, upper_len, lower_len;
  93. const unsigned short *header, *upper, *lower;
  94. if (!(header = read_data( &pos, 2 * sizeof(*header) ))) return;
  95. upper_len = header[1];
  96. if (!(upper = read_data( &pos, upper_len * sizeof(*upper) )))
  97. {
  98. printf( "Invalid len %04x\n", header[1] );
  99. return;
  100. }
  101. lower_len = dump_total_len / sizeof(*lower) - 2 - upper_len;
  102. if (!(lower = read_data( &pos, lower_len * sizeof(*lower) ))) return;
  103. printf( "Magic: %04x\n", header[0] );
  104. printf( "Upper-case table:\n" );
  105. dump_offset_table( upper, upper_len );
  106. printf( "\n\nLower-case table:\n" );
  107. dump_offset_table( lower, lower_len );
  108. printf( "\n\n" );
  109. }
  110. static void dump_codepage(void)
  111. {
  112. unsigned int i, j, uni2cp_offset, pos = 0;
  113. const unsigned short *header, *ptr;
  114. if (!(header = read_data( &pos, 13 * sizeof(*header) ))) return;
  115. printf( "Codepage: %03u\n", header[1] );
  116. printf( "Char size: %u\n", header[2] );
  117. printf( "Default char A: %04x / %04x\n", header[3], header[5] );
  118. printf( "Default char W: %04x / %04x\n", header[4], header[6] );
  119. if (header[2] == 2)
  120. {
  121. printf( "Lead bytes: " );
  122. for (i = 0; i < 12; i++)
  123. {
  124. unsigned char val = ((unsigned char *)(header + 7))[i];
  125. if (!val) break;
  126. printf( "%c%02x", (i % 2) ? '-' : ' ', val );
  127. }
  128. printf( "\n" );
  129. }
  130. printf( "\nCharacter map:\n" );
  131. pos = header[0] * sizeof(*ptr);
  132. if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
  133. uni2cp_offset = pos / sizeof(*ptr) + *ptr;
  134. if (!(ptr = read_data( &pos, 256 * sizeof(*ptr) ))) return;
  135. for (i = 0; i < 256; i++)
  136. {
  137. if (!(i % 16)) printf( "\n%02x:", i );
  138. printf( " %04x", ptr[i] );
  139. }
  140. printf( "\n" );
  141. if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
  142. if (*ptr == 256)
  143. {
  144. if (!(ptr = read_data( &pos, 256 * sizeof(*ptr) ))) return;
  145. printf( "\nGlyph table:\n" );
  146. for (i = 0; i < 256; i++)
  147. {
  148. if (!(i % 16)) printf( "\n%02x:", i );
  149. printf( " %04x", ptr[i] );
  150. }
  151. printf( "\n" );
  152. }
  153. if (!(ptr = read_data( &pos, sizeof(*ptr) ))) return;
  154. if (*ptr)
  155. {
  156. if (!(ptr = read_data( &pos, (uni2cp_offset - pos) * sizeof(*ptr) ))) return;
  157. for (i = 0; i < 256; i++)
  158. {
  159. if (!ptr[i] || ptr[i] > pos - 256) continue;
  160. for (j = 0; j < 256; j++)
  161. {
  162. if (!(j % 16)) printf( "\n%02x%02x:", i, j );
  163. printf( " %04x", ptr[ptr[i] + j] );
  164. }
  165. }
  166. printf( "\n" );
  167. }
  168. printf( "\nUnicode table:\n" );
  169. pos = uni2cp_offset * sizeof(*ptr);
  170. if (header[2] == 2)
  171. {
  172. if (!(ptr = read_data( &pos, 65536 * sizeof(*ptr) ))) return;
  173. for (i = 0; i < 65536; i++)
  174. {
  175. if (!(i % 16)) printf( "\n%04x:", i );
  176. printf( " %04x", ptr[i] );
  177. }
  178. printf( "\n" );
  179. }
  180. else
  181. {
  182. const unsigned char *uni2cp;
  183. if (!(uni2cp = read_data( &pos, 65536 ))) return;
  184. for (i = 0; i < 65536; i++)
  185. {
  186. if (!(i % 16)) printf( "\n%04x:", i );
  187. printf( " %02x", uni2cp[i] );
  188. }
  189. printf( "\n" );
  190. }
  191. printf( "\n" );
  192. }
  193. struct norm_table
  194. {
  195. WCHAR name[13]; /* 00 file name */
  196. USHORT checksum[3]; /* 1a checksum? */
  197. USHORT version[4]; /* 20 Unicode version */
  198. USHORT form; /* 28 normalization form */
  199. USHORT len_factor; /* 2a factor for length estimates */
  200. USHORT unknown1; /* 2c */
  201. USHORT decomp_size; /* 2e decomposition hash size */
  202. USHORT comp_size; /* 30 composition hash size */
  203. USHORT unknown2; /* 32 */
  204. USHORT classes; /* 34 combining classes table offset */
  205. USHORT props_level1; /* 36 char properties table level 1 offset */
  206. USHORT props_level2; /* 38 char properties table level 2 offset */
  207. USHORT decomp_hash; /* 3a decomposition hash table offset */
  208. USHORT decomp_map; /* 3c decomposition character map table offset */
  209. USHORT decomp_seq; /* 3e decomposition character sequences offset */
  210. USHORT comp_hash; /* 40 composition hash table offset */
  211. USHORT comp_seq; /* 42 composition character sequences offset */
  212. };
  213. static int offset_scale = 1; /* older versions use byte offsets */
  214. #define GET_TABLE(info,table) ((const void *)((const BYTE *)info + (info->table * offset_scale)))
  215. static unsigned int get_utf16( const WCHAR *str )
  216. {
  217. if (str[0] >= 0xd800 && str[0] <= 0xdbff &&
  218. str[1] >= 0xdc00 && str[1] <= 0xdfff)
  219. return 0x10000 + ((str[0] & 0x3ff) << 10) + (str[1] & 0x3ff);
  220. return str[0];
  221. }
  222. static BYTE rol( BYTE val, BYTE count )
  223. {
  224. return (val << count) | (val >> (8 - count));
  225. }
  226. static unsigned char get_char_props( const struct norm_table *info, unsigned int ch )
  227. {
  228. const BYTE *level1 = GET_TABLE( info, props_level1 );
  229. const BYTE *level2 = GET_TABLE( info, props_level2 );
  230. BYTE off = level1[ch / 128];
  231. if (!off || off >= 0xfb) return rol( off, 5 );
  232. return level2[(off - 1) * 128 + ch % 128];
  233. }
  234. static const WCHAR *get_decomposition( const struct norm_table *info,
  235. unsigned int ch, unsigned int *ret_len )
  236. {
  237. const USHORT *hash_table = GET_TABLE( info, decomp_hash );
  238. const WCHAR *seq = GET_TABLE(info, decomp_seq );
  239. const WCHAR *ret;
  240. unsigned int i, pos, end, len, hash;
  241. *ret_len = 1 + (ch >= 0x10000);
  242. if (!info->decomp_size) return NULL;
  243. hash = ch % info->decomp_size;
  244. pos = hash_table[hash];
  245. if (pos >> 13)
  246. {
  247. if (get_char_props( info, ch ) != 0xbf) return NULL;
  248. ret = seq + (pos & 0x1fff);
  249. len = pos >> 13;
  250. }
  251. else
  252. {
  253. const struct { WCHAR src; USHORT dst; } *pairs = GET_TABLE( info, decomp_map );
  254. /* find the end of the hash bucket */
  255. for (i = hash + 1; i < info->decomp_size; i++) if (!(hash_table[i] >> 13)) break;
  256. if (i < info->decomp_size) end = hash_table[i];
  257. else for (end = pos; pairs[end].src; end++) ;
  258. for ( ; pos < end; pos++)
  259. {
  260. if (pairs[pos].src != (WCHAR)ch) continue;
  261. ret = seq + (pairs[pos].dst & 0x1fff);
  262. len = pairs[pos].dst >> 13;
  263. break;
  264. }
  265. if (pos >= end) return NULL;
  266. }
  267. if (len == 7) while (ret[len]) len++;
  268. *ret_len = len;
  269. return ret;
  270. }
  271. static int cmp_compos( const void *a, const void *b )
  272. {
  273. int ret = ((unsigned int *)a)[0] - ((unsigned int *)b)[0];
  274. if (!ret) ret = ((unsigned int *)a)[1] - ((unsigned int *)b)[1];
  275. return ret;
  276. }
  277. static void dump_norm(void)
  278. {
  279. const struct norm_table *info;
  280. const BYTE *classes;
  281. unsigned int i;
  282. char name[13];
  283. if (!(info = PRD( 0, sizeof(*info) ))) return;
  284. for (i = 0; i < sizeof(name); i++) name[i] = info->name[i];
  285. printf( "Name: %s\n", name );
  286. switch (info->form)
  287. {
  288. case 1: printf( "Form: NFC\n" ); break;
  289. case 2: printf( "Form: NFD\n" ); break;
  290. case 5: printf( "Form: NFKC\n" ); break;
  291. case 6: printf( "Form: NFKD\n" ); break;
  292. case 13: printf( "Form: IDNA\n" ); break;
  293. default: printf( "Form: %u\n", info->form ); break;
  294. }
  295. printf( "Version: %u.%u.%u\n", info->version[0], info->version[1], info->version[2] );
  296. printf( "Factor: %u\n", info->len_factor );
  297. if (info->classes == sizeof(*info) / 2) offset_scale = 2;
  298. classes = GET_TABLE( info, classes );
  299. printf( "\nCharacter classes:\n" );
  300. for (i = 0; i < 0x110000; i++)
  301. {
  302. BYTE flags = get_char_props( info, i );
  303. if (!(i % 16)) printf( "\n%06x:", i );
  304. if (!flags || (flags & 0x3f) == 0x3f)
  305. {
  306. static const char *flagstr[4] = { ".....", "Undef", "QC=No", "Inval" };
  307. printf( " %s", flagstr[flags >> 6] );
  308. }
  309. else
  310. {
  311. static const char flagschar[4] = ".+*M";
  312. BYTE class = classes[flags & 0x3f];
  313. printf( " %c.%03u", flagschar[flags >> 6], class );
  314. }
  315. }
  316. printf( "\n\nDecompositions:\n\n" );
  317. for (i = 0; i < 0x110000; i++)
  318. {
  319. unsigned int j, len;
  320. const WCHAR *decomp = get_decomposition( info, i, &len );
  321. if (!decomp) continue;
  322. printf( "%04x ->", i );
  323. for (j = 0; j < len; j++)
  324. {
  325. unsigned int ch = get_utf16( decomp + j );
  326. printf( " %04x", ch );
  327. if (ch >= 0x10000) j++;
  328. }
  329. printf( "\n" );
  330. }
  331. if (info->comp_size)
  332. {
  333. unsigned int pos, len = (dump_total_len - info->comp_seq * offset_scale) / sizeof(WCHAR);
  334. const WCHAR *seq = GET_TABLE( info, comp_seq );
  335. unsigned int *map = xmalloc( len * sizeof(*map) );
  336. printf( "\nCompositions:\n\n" );
  337. /* ignore hash table, simply dump all the sequences */
  338. for (i = pos = 0; i < len; pos += 3)
  339. {
  340. map[pos] = get_utf16( seq + i );
  341. i += 1 + (map[pos] >= 0x10000);
  342. map[pos+1] = get_utf16( seq + i );
  343. i += 1 + (map[pos+1] >= 0x10000);
  344. map[pos+2] = get_utf16( seq + i );
  345. i += 1 + (map[pos+2] >= 0x10000);
  346. }
  347. qsort( map, pos / 3, 3 * sizeof(*map), cmp_compos );
  348. for (i = 0; i < pos; i += 3) printf( "%04x %04x -> %04x\n", map[i], map[i + 1], map[i + 2] );
  349. free( map );
  350. }
  351. printf( "\n" );
  352. }
  353. struct sortguid
  354. {
  355. GUID id; /* sort GUID */
  356. DWORD flags; /* flags */
  357. DWORD compr; /* offset to compression table */
  358. DWORD except; /* exception table offset in sortkey table */
  359. DWORD ling_except; /* exception table offset for linguistic casing */
  360. DWORD casemap; /* linguistic casemap table offset */
  361. };
  362. #define FLAG_HAS_3_BYTE_WEIGHTS 0x01
  363. #define FLAG_REVERSEDIACRITICS 0x10
  364. #define FLAG_DOUBLECOMPRESSION 0x20
  365. #define FLAG_INVERSECASING 0x40
  366. struct language_id
  367. {
  368. DWORD offset;
  369. WCHAR name[32];
  370. };
  371. struct compression
  372. {
  373. DWORD offset;
  374. WCHAR minchar, maxchar;
  375. WORD len[8];
  376. };
  377. struct comprlang
  378. {
  379. struct compression compr;
  380. WCHAR name[32];
  381. };
  382. static const char *get_sortkey( DWORD key )
  383. {
  384. static char buffer[16];
  385. if (!key) return "....";
  386. if ((WORD)key == 0x200)
  387. sprintf( buffer, "expand %04x", key >> 16 );
  388. else
  389. sprintf( buffer, "%u.%u.%u.%u", (BYTE)(key >> 8), (BYTE)key, (BYTE)(key >> 16), (BYTE)(key >> 24) );
  390. return buffer;
  391. }
  392. static const void *dump_expansions( const DWORD *ptr )
  393. {
  394. DWORD i, count = *ptr++;
  395. printf( "\nExpansions: (count=%04x)\n\n", count );
  396. for (i = 0; i < count; i++)
  397. {
  398. const WCHAR *p = (const WCHAR *)(ptr + i);
  399. printf( " %04x: %04x %04x\n", i, p[0], p[1] );
  400. }
  401. return ptr + count;
  402. }
  403. static void dump_exceptions( const DWORD *sortkeys, DWORD offset )
  404. {
  405. int i, j;
  406. const DWORD *table = sortkeys + offset;
  407. for (i = 0; i < 0x100; i++)
  408. {
  409. if (table[i] == i * 0x100) continue;
  410. for (j = 0; j < 0x100; j++)
  411. {
  412. if (sortkeys[table[i] + j] == sortkeys[i * 0x100 + j]) continue;
  413. printf( " %04x: %s\n", i * 0x100 + j, get_sortkey( sortkeys[table[i] + j] ));
  414. }
  415. }
  416. }
  417. static const void *dump_compression( const struct compression *compr, const WCHAR *table )
  418. {
  419. int i, j, k;
  420. const WCHAR *p = table + compr->offset;
  421. printf( " min=%04x max=%04x counts=%u,%u,%u,%u,%u,%u,%u,%u\n",
  422. compr->minchar, compr->maxchar,
  423. compr->len[0], compr->len[1], compr->len[2], compr->len[3],
  424. compr->len[4], compr->len[5], compr->len[6], compr->len[7] );
  425. for (i = 0; i < 8; i++)
  426. {
  427. for (j = 0; j < compr->len[i]; j++)
  428. {
  429. printf( " " );
  430. for (k = 0; k < i + 2; k++) printf( " %04x", *p++ );
  431. p = (const WCHAR *)(((ULONG_PTR)p + 3) & ~3);
  432. printf( " -> %s\n", get_sortkey( *(const DWORD *)p ));
  433. p += 2;
  434. }
  435. }
  436. return p;
  437. }
  438. static const void *dump_multiple_weights( const DWORD *ptr )
  439. {
  440. int i, count = *ptr++;
  441. const WCHAR *p;
  442. printf( "\nMultiple weights: (count=%u)\n\n", count );
  443. p = (const WCHAR *)ptr;
  444. for (i = 0; i < count; i++)
  445. {
  446. BYTE weight = p[i];
  447. BYTE count = p[i] >> 8;
  448. printf( "%u - %u\n", weight, weight + count );
  449. }
  450. return ptr + (count + 1) / 2;
  451. }
  452. static void dump_sort( int old_version )
  453. {
  454. const struct
  455. {
  456. DWORD sortkeys;
  457. DWORD casemaps;
  458. DWORD ctypes;
  459. DWORD sortids;
  460. } *header;
  461. const struct compression *compr;
  462. const struct sortguid *guids;
  463. const struct comprlang *comprlangs;
  464. const struct language_id *language_ids = NULL;
  465. const WORD *casemaps, *map;
  466. const DWORD *sortkeys, *ptr;
  467. const WCHAR *p = NULL;
  468. int i, j, size, len;
  469. int nb_casemaps = 0, casemap_offsets[16];
  470. if (!(header = PRD( 0, sizeof(*header) ))) return;
  471. if (!(sortkeys = PRD( header->sortkeys, header->casemaps - header->sortkeys ))) return;
  472. printf( "\nSort keys:\n" );
  473. for (i = 0; i < 0x10000; i++)
  474. {
  475. if (!(i % 8)) printf( "\n%04x:", i );
  476. printf( " %16s", get_sortkey( sortkeys[i] ));
  477. }
  478. printf( "\n\n" );
  479. size = (header->ctypes - header->casemaps) / sizeof(*casemaps);
  480. if (!(casemaps = PRD( header->casemaps, size * sizeof(*casemaps) ))) return;
  481. len = 0;
  482. if (old_version)
  483. {
  484. ptr = (const DWORD *)casemaps;
  485. len = *ptr++;
  486. language_ids = (const struct language_id *)ptr;
  487. casemaps = (const WORD *)(language_ids + len);
  488. }
  489. map = casemaps;
  490. while (size)
  491. {
  492. const WORD *upper = map + 2;
  493. const WORD *lower = map + 2 + map[1];
  494. const WORD *end = map + map[1] + 1 + map[map[1] + 1];
  495. if (map[0] != 1) break;
  496. printf( "\nCase mapping table %u:\n", nb_casemaps );
  497. casemap_offsets[nb_casemaps++] = map - casemaps;
  498. for (j = 0; j < len; j++)
  499. {
  500. if (language_ids[j].offset != map - casemaps) continue;
  501. printf( "Language: %s\n", get_unicode_str( language_ids[j].name, -1 ));
  502. break;
  503. }
  504. printf( "\nUpper-case table:\n" );
  505. dump_offset_table( upper, lower - upper );
  506. printf( "\n\nLower-case table:\n" );
  507. dump_offset_table( lower, end - lower );
  508. printf( "\n\n" );
  509. size -= (end - map);
  510. map = end;
  511. }
  512. if (!(p = PRD( header->ctypes, header->sortids - header->ctypes ))) return;
  513. printf( "\nCTYPE table:\n\n" );
  514. dump_ctype_table( p );
  515. printf( "\nSort tables:\n\n" );
  516. size = (dump_total_len - header->sortids) / sizeof(*ptr);
  517. if (!(ptr = PRD( header->sortids, size * sizeof(*ptr) ))) return;
  518. if (old_version)
  519. {
  520. len = *ptr++;
  521. for (i = 0; i < len; i++, ptr += 2) printf( "NLS version: %08x %08x\n", ptr[0], ptr[1] );
  522. len = *ptr++;
  523. for (i = 0; i < len; i++, ptr += 2) printf( "Defined version: %08x %08x\n", ptr[0], ptr[1] );
  524. len = *ptr++;
  525. printf( "\nReversed diacritics:\n\n" );
  526. for (i = 0; i < len; i++)
  527. {
  528. const WCHAR *name = (const WCHAR *)ptr;
  529. printf( "%s\n", get_unicode_str( name, -1 ));
  530. ptr += 16;
  531. }
  532. len = *ptr++;
  533. printf( "\nDouble compression:\n\n" );
  534. for (i = 0; i < len; i++)
  535. {
  536. const WCHAR *name = (const WCHAR *)ptr;
  537. printf( "%s\n", get_unicode_str( name, -1 ));
  538. ptr += 16;
  539. }
  540. ptr = dump_expansions( ptr );
  541. printf( "\nCompressions:\n" );
  542. size = *ptr++;
  543. comprlangs = (const struct comprlang *)ptr;
  544. for (i = 0; i < size; i++)
  545. {
  546. printf( "\n %s\n", get_unicode_str( comprlangs[i].name, -1 ));
  547. ptr = dump_compression( &comprlangs[i].compr, (const WCHAR *)(comprlangs + size) );
  548. }
  549. ptr = dump_multiple_weights( ptr );
  550. size = *ptr++;
  551. printf( "\nJamo sort:\n\n" );
  552. for (i = 0; i < size; i++, ptr += 2)
  553. {
  554. const struct jamo { BYTE val[5], off, len; } *jamo = (const struct jamo *)ptr;
  555. printf( "%04x: %02x %02x %02x %02x %02x off=%02x len=%02x\n", 0x1100 + i, jamo->val[0],
  556. jamo->val[1], jamo->val[2], jamo->val[3], jamo->val[4],
  557. jamo->off, jamo->len );
  558. }
  559. size = *ptr++;
  560. printf( "\nJamo second chars:\n\n" );
  561. for (i = 0; i < size; i++, ptr += 2)
  562. {
  563. const struct jamo { WORD ch; BYTE val[5], len; } *jamo = (const struct jamo *)ptr;
  564. printf( "%02x: %04x: %02x %02x %02x %02x %02x len=%02x\n", i, jamo->ch, jamo->val[0],
  565. jamo->val[1], jamo->val[2], jamo->val[3], jamo->val[4], jamo->len );
  566. }
  567. size = *ptr++;
  568. printf( "\nExceptions:\n" );
  569. language_ids = (const struct language_id *)ptr;
  570. for (i = 0; i < size; i++)
  571. {
  572. printf( "\n %08x %s\n", language_ids[i].offset, get_unicode_str( language_ids[i].name, -1 ));
  573. dump_exceptions( sortkeys, language_ids[i].offset );
  574. }
  575. }
  576. else
  577. {
  578. int guid_count = ptr[1];
  579. printf( "NLS version: %08x\n\n", ptr[0] );
  580. printf( "Sort GUIDs:\n\n" );
  581. guids = (const struct sortguid *)(ptr + 2);
  582. for (i = 0; i < guid_count; i++)
  583. {
  584. for (j = 0; j < nb_casemaps; j++) if (casemap_offsets[j] == guids[i].casemap) break;
  585. printf( " %s flags=%08x compr=%08x casemap=%d\n", get_guid_str( &guids[i].id ),
  586. guids[i].flags, guids[i].compr, j < nb_casemaps ? j : -1 );
  587. }
  588. ptr = dump_expansions( (const DWORD *)(guids + guid_count) );
  589. size = *ptr++;
  590. printf( "\nCompressions:\n" );
  591. compr = (const struct compression *)ptr;
  592. for (i = 0; i < size; i++)
  593. {
  594. printf( "\n" );
  595. for (j = 0; j < guid_count; j++)
  596. if (guids[j].compr == i) printf( " %s\n", get_guid_str( &guids[j].id ));
  597. ptr = dump_compression( compr + i, (const WCHAR *)(compr + size) );
  598. }
  599. ptr = dump_multiple_weights( ptr );
  600. size = *ptr++;
  601. printf( "\nJamo sort:\n\n" );
  602. for (i = 0; i < size; i++)
  603. {
  604. static const WCHAR hangul_chars[] =
  605. {
  606. 0xa960, 0xa961, 0xa962, 0xa963, 0xa964, 0xa965, 0xa966, 0xa967,
  607. 0xa968, 0xa969, 0xa96a, 0xa96b, 0xa96c, 0xa96d, 0xa96e, 0xa96f,
  608. 0xa970, 0xa971, 0xa972, 0xa973, 0xa974, 0xa975, 0xa976, 0xa977,
  609. 0xa978, 0xa979, 0xa97a, 0xa97b, 0xa97c,
  610. 0xd7b0, 0xd7b1, 0xd7b2, 0xd7b3, 0xd7b4, 0xd7b5, 0xd7b6, 0xd7b7,
  611. 0xd7b8, 0xd7b9, 0xd7ba, 0xd7bb, 0xd7bc, 0xd7bd, 0xd7be, 0xd7bf,
  612. 0xd7c0, 0xd7c1, 0xd7c2, 0xd7c3, 0xd7c4, 0xd7c5, 0xd7c6,
  613. 0xd7cb, 0xd7cc, 0xd7cd, 0xd7ce, 0xd7cf,
  614. 0xd7d0, 0xd7d1, 0xd7d2, 0xd7d3, 0xd7d4, 0xd7d5, 0xd7d6, 0xd7d7,
  615. 0xd7d8, 0xd7d9, 0xd7da, 0xd7db, 0xd7dc, 0xd7dd, 0xd7de, 0xd7df,
  616. 0xd7e0, 0xd7e1, 0xd7e2, 0xd7e3, 0xd7e4, 0xd7e5, 0xd7e6, 0xd7e7,
  617. 0xd7e8, 0xd7e9, 0xd7ea, 0xd7eb, 0xd7ec, 0xd7ed, 0xd7ee, 0xd7ef,
  618. 0xd7f0, 0xd7f1, 0xd7f2, 0xd7f3, 0xd7f4, 0xd7f5, 0xd7f6, 0xd7f7,
  619. 0xd7f8, 0xd7f9, 0xd7fa, 0xd7fb
  620. };
  621. const BYTE *b = (const BYTE *)(ptr + 2 * i);
  622. WCHAR wc = i < 0x100 ? 0x1100 + i : hangul_chars[i - 0x100];
  623. printf( "%04x: %02x %02x %02x %02x %02x\n", wc, b[0], b[1], b[2], b[3], b[4] );
  624. }
  625. printf( "\nExceptions:\n" );
  626. for (i = 0; i < guid_count; i++)
  627. {
  628. if (!guids[i].except) continue;
  629. printf( "\n %s\n", get_guid_str( &guids[i].id ));
  630. dump_exceptions( sortkeys, guids[i].except );
  631. if (!guids[i].ling_except) continue;
  632. printf( "\n %s LINGUISTIC_CASING\n", get_guid_str( &guids[i].id ));
  633. dump_exceptions( sortkeys, guids[i].ling_except );
  634. }
  635. }
  636. printf( "\n" );
  637. }
  638. void nls_dump(void)
  639. {
  640. const char *name = get_basename( globals.input_name );
  641. if (!strcasecmp( name, "l_intl.nls" )) return dump_casemap();
  642. if (!strncasecmp( name, "c_", 2 )) return dump_codepage();
  643. if (!strncasecmp( name, "norm", 4 )) return dump_norm();
  644. if (!strcasecmp( name, "sortdefault.nls" )) return dump_sort( 0 );
  645. if (!strncasecmp( name, "sort", 4 )) return dump_sort( 1 );
  646. fprintf( stderr, "Unrecognized file name '%s'\n", globals.input_name );
  647. }
  648. enum FileSig get_kind_nls(void)
  649. {
  650. if (strlen( globals.input_name ) < 5) return SIG_UNKNOWN;
  651. if (strcasecmp( globals.input_name + strlen(globals.input_name) - 4, ".nls" )) return SIG_UNKNOWN;
  652. return SIG_NLS;
  653. }