1dc7c1d199c8eaef40b49adc5ff6ba7e57f68717
[reactos.git] / reactos / tools / wmc / write.c
1 /*
2 * Wine Message Compiler output generation
3 *
4 * Copyright 2000 Bertho A. Stultiens (BS)
5 *
6 */
7
8 #include <windows.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <ctype.h>
14
15 #include "wmc.h"
16 #include "utils.h"
17 #include "lang.h"
18 #include "write.h"
19
20 /*
21 * The binary resource layout is as follows:
22 *
23 * +===============+
24 * Header | NBlocks |
25 * +===============+
26 * Block 0 | Low ID |
27 * +---------------+
28 * | High ID |
29 * +---------------+
30 * | Offset |---+
31 * +===============+ |
32 * Block 1 | Low ID | |
33 * +---------------+ |
34 * | High ID | |
35 * +---------------+ |
36 * | Offset |------+
37 * +===============+ | |
38 * | | | |
39 * ... ... | |
40 * | | | |
41 * +===============+ <-+ |
42 * B0 LoID | Len | Flags | |
43 * +---+---+---+---+ |
44 * | b | l | a | b | |
45 * +---+---+---+---+ |
46 * | l | a | \0| \0| |
47 * +===============+ |
48 * | | |
49 * ... ... |
50 * | | |
51 * +===============+ |
52 * B0 HiID | Len | Flags | |
53 * +---+---+---+---+ |
54 * | M | o | r | e | |
55 * +---+---+---+---+ |
56 * | b | l | a | \0| |
57 * +===============+ <----+
58 * B1 LoID | Len | Flags |
59 * +---+---+---+---+
60 * | J | u | n | k |
61 * +---+---+---+---+
62 * | \0| \0| \0| \0|
63 * +===============+
64 * | |
65 * ... ...
66 * | |
67 * +===============+
68 *
69 * All Fields are aligned on their natural boundaries. The length
70 * field (Len) covers both the length of the string and the header
71 * fields (Len and Flags). Strings are '\0' terminated. Flags is 0
72 * for normal character strings and 1 for unicode strings.
73 */
74
75 static char str_header[] =
76 "/* This file is generated with wmc version " WMC_FULLVERSION ". Do not edit! */\n"
77 "/* Source : %s */\n"
78 "/* Cmdline: %s */\n"
79 "/* Date : %s */\n"
80 "\n"
81 ;
82
83 static char *dup_u2c(int cp, const WCHAR *uc)
84 {
85 int len = unistrlen(uc);
86 char *cptr = xmalloc(len+1);
87 // const union cptable *cpdef = find_codepage(cp);
88 // if(!cpdef)
89 // internal_error(__FILE__, __LINE__, "Codepage %d not found (vanished?)", cp);
90 // if((len = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, cptr, len+1, NULL, NULL)) < 0)
91 if((len = WideCharToMultiByte(cp, 0, uc, unistrlen(uc)+1, cptr, len+1, NULL, NULL)) < 0)
92 internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", len);
93 return cptr;
94 }
95
96 static void killnl(char *s, int ddd)
97 {
98 char *tmp;
99 tmp = strstr(s, "\r\n");
100 if(tmp)
101 {
102 if(ddd && tmp - s > 3)
103 {
104 tmp[0] = tmp[1] = tmp[2] = '.';
105 tmp[3] = '\0';
106 }
107 else
108 *tmp = '\0';
109 }
110 tmp = strchr(s, '\n');
111 if(tmp)
112 {
113 if(ddd && tmp - s > 3)
114 {
115 tmp[0] = tmp[1] = tmp[2] = '.';
116 tmp[3] = '\0';
117 }
118 else
119 *tmp = '\0';
120 }
121 }
122
123 static int killcomment(char *s)
124 {
125 char *tmp = s;
126 int b = 0;
127 while((tmp = strstr(tmp, "/*")))
128 {
129 tmp[1] = 'x';
130 b++;
131 }
132 tmp = s;
133 while((tmp = strstr(tmp, "*/")))
134 {
135 tmp[0] = 'x';
136 b++;
137 }
138 return b;
139 }
140
141 void write_h_file(const char *fname)
142 {
143 node_t *ndp;
144 char *cptr;
145 char *cast;
146 FILE *fp;
147 token_t *ttab;
148 int ntab;
149 int i;
150 int once = 0;
151 int idx_en = 0;
152
153 fp = fopen(fname, "w");
154 if(!fp)
155 {
156 perror(fname);
157 exit(1);
158 }
159 cptr = ctime(&now);
160 killnl(cptr, 0);
161 fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline, cptr);
162 fprintf(fp, "#ifndef __WMCGENERATED_%08lx_H\n", now);
163 fprintf(fp, "#define __WMCGENERATED_%08lx_H\n", now);
164 fprintf(fp, "\n");
165
166 /* Write severity and facility aliases */
167 get_tokentable(&ttab, &ntab);
168 fprintf(fp, "/* Severity codes */\n");
169 for(i = 0; i < ntab; i++)
170 {
171 if(ttab[i].type == tok_severity && ttab[i].alias)
172 {
173 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
174 fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
175 free(cptr);
176 }
177 }
178 fprintf(fp, "\n");
179
180 fprintf(fp, "/* Facility codes */\n");
181 for(i = 0; i < ntab; i++)
182 {
183 if(ttab[i].type == tok_facility && ttab[i].alias)
184 {
185 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
186 fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
187 free(cptr);
188 }
189 }
190 fprintf(fp, "\n");
191
192 /* Write the message codes */
193 fprintf(fp, "/* Message definitions */\n");
194 for(ndp = nodehead; ndp; ndp = ndp->next)
195 {
196 switch(ndp->type)
197 {
198 case nd_comment:
199 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.comment+1);
200 killnl(cptr, 0);
201 killcomment(cptr);
202 if(*cptr)
203 fprintf(fp, "/* %s */\n", cptr);
204 else
205 fprintf(fp, "\n");
206 free(cptr);
207 break;
208 case nd_msg:
209 if(!once)
210 {
211 /*
212 * Search for an english text.
213 * If not found, then use the first in the list
214 */
215 once++;
216 for(i = 0; i < ndp->u.msg->nmsgs; i++)
217 {
218 if(ndp->u.msg->msgs[i]->lan == 0x409)
219 {
220 idx_en = i;
221 break;
222 }
223 }
224 fprintf(fp, "\n");
225 }
226 fprintf(fp, "/* MessageId : 0x%08x */\n", ndp->u.msg->realid);
227 cptr = dup_u2c(ndp->u.msg->msgs[idx_en]->cp, ndp->u.msg->msgs[idx_en]->msg);
228 killnl(cptr, 0);
229 killcomment(cptr);
230 fprintf(fp, "/* Approx. msg: %s */\n", cptr);
231 free(cptr);
232 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.msg->sym);
233 if(ndp->u.msg->cast)
234 cast = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.msg->cast);
235 else
236 cast = NULL;
237 switch(ndp->u.msg->base)
238 {
239 case 8:
240 if(cast)
241 fprintf(fp, "#define %s\t((%s)0%oL)\n\n", cptr, cast, ndp->u.msg->realid);
242 else
243 fprintf(fp, "#define %s\t0%oL\n\n", cptr, ndp->u.msg->realid);
244 break;
245 case 10:
246 if(cast)
247 fprintf(fp, "#define %s\t((%s)%dL)\n\n", cptr, cast, ndp->u.msg->realid);
248 else
249 fprintf(fp, "#define %s\t%dL\n\n", cptr, ndp->u.msg->realid);
250 break;
251 case 16:
252 if(cast)
253 fprintf(fp, "#define %s\t((%s)0x%08xL)\n\n", cptr, cast, ndp->u.msg->realid);
254 else
255 fprintf(fp, "#define %s\t0x%08xL\n\n", cptr, ndp->u.msg->realid);
256 break;
257 default:
258 internal_error(__FILE__, __LINE__, "Invalid base for number print");
259 }
260 free(cptr);
261 if(cast)
262 free(cast);
263 break;
264 default:
265 internal_error(__FILE__, __LINE__, "Invalid node type %d", ndp->type);
266 }
267 }
268 fprintf(fp, "\n#endif\n");
269 fclose(fp);
270 }
271
272 static void write_rcbin(FILE *fp)
273 {
274 lan_blk_t *lbp;
275 token_t *ttab;
276 int ntab;
277 int i;
278
279 get_tokentable(&ttab, &ntab);
280
281 for(lbp = lanblockhead; lbp; lbp = lbp->next)
282 {
283 char *cptr = NULL;
284 fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
285 for(i = 0; i < ntab; i++)
286 {
287 if(ttab[i].type == tok_language && ttab[i].token == lbp->lan)
288 {
289 if(ttab[i].alias)
290 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
291 break;
292 }
293 }
294 if(!cptr)
295 internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x", lbp->lan);
296 fprintf(fp, "1 MESSAGETABLE \"%s.bin\"\n", cptr);
297 free(cptr);
298 }
299 }
300
301 static char *make_string(WCHAR *uc, int len, int codepage)
302 {
303 char *str = xmalloc(7*len + 1);
304 char *cptr = str;
305 int i;
306 int b;
307
308 if(!codepage)
309 {
310 *cptr++ = ' ';
311 *cptr++ = 'L';
312 *cptr++ = '"';
313 for(i = b = 0; i < len; i++, uc++)
314 {
315 int n;
316 if(*uc < 0x100)
317 {
318 if(isprint(*uc))
319 {
320 *cptr++ = (char)*uc;
321 b++;
322 }
323 else
324 {
325 switch(*uc)
326 {
327 case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
328 case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
329 case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
330 case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
331 case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
332 case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
333 case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
334 case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
335 case '"': *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
336 default:
337 n = sprintf(cptr, "\\x%04x", *uc & 0xffff);
338 cptr += n;
339 b += n;
340 }
341 }
342 }
343 else
344 {
345 n = sprintf(cptr, "\\x%04x", *uc & 0xffff);
346 cptr += n;
347 b += n;
348 }
349 if(i < len-1 && b >= 72)
350 {
351 *cptr++ = '"';
352 *cptr++ = ',';
353 *cptr++ = '\n';
354 *cptr++ = ' ';
355 *cptr++ = 'L';
356 *cptr++ = '"';
357 b = 0;
358 }
359 }
360 len = (len + 3) & ~3;
361 for(; i < len; i++)
362 {
363 *cptr++ = '\\';
364 *cptr++ = 'x';
365 *cptr++ = '0';
366 *cptr++ = '0';
367 *cptr++ = '0';
368 *cptr++ = '0';
369 }
370 *cptr++ = '"';
371 *cptr = '\0';
372 }
373 else
374 {
375 char *tmp = xmalloc(2*len+1);
376 char *cc = tmp;
377 // const union cptable *cpdef = find_codepage(codepage);
378
379 // assert(cpdef != NULL);
380 // if((i = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
381 if((i = WideCharToMultiByte(codepage, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
382 internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", i);
383 *cptr++ = ' ';
384 *cptr++ = '"';
385 for(i = b = 0; i < len; i++, cc++)
386 {
387 int n;
388 if(isprint(*cc))
389 {
390 *cptr++ = *cc;
391 b++;
392 }
393 else
394 {
395 switch(*cc)
396 {
397 case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
398 case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
399 case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
400 case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
401 case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
402 case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
403 case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
404 case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
405 case '"': *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
406 default:
407 n = sprintf(cptr, "\\x%02x", *cc & 0xff);
408 cptr += n;
409 b += n;
410 }
411 }
412 if(i < len-1 && b >= 72)
413 {
414 *cptr++ = '"';
415 *cptr++ = ',';
416 *cptr++ = '\n';
417 *cptr++ = ' ';
418 *cptr++ = '"';
419 b = 0;
420 }
421 }
422 len = (len + 3) & ~3;
423 for(; i < len; i++)
424 {
425 *cptr++ = '\\';
426 *cptr++ = 'x';
427 *cptr++ = '0';
428 *cptr++ = '0';
429 }
430 *cptr++ = '"';
431 *cptr = '\0';
432 free(tmp);
433 }
434 return str;
435 }
436
437
438 static char *make_bin_string(WCHAR *uc, int len, int *retlen, int codepage)
439 {
440 char *str = xmalloc(7 * len + 1);
441 int i;
442 int b;
443
444 if(!codepage)
445 {
446 WCHAR *cptr = (WCHAR*)str;
447
448 for(i = b = 0; i < len; i++, uc++)
449 {
450 *cptr++ = *uc;
451 }
452 len = (len + 1) & ~1;
453 for(; i < len; i++)
454 {
455 *cptr++ = 0;
456 }
457 *retlen = len * 2;
458 }
459 else
460 {
461 char *tmp = xmalloc(2*len+1);
462 char *cc = tmp;
463 char *cptr = str;
464 // const union cptable *cpdef = find_codepage(codepage);
465
466 // assert(cpdef != NULL);
467 // if((i = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
468 if((i = WideCharToMultiByte(codepage, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
469 internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", i);
470 for(i = b = 0; i < len; i++, cc++)
471 {
472 *cptr++ = *cc;
473 b++;
474 }
475 len = (len + 3) & ~3;
476 for(; i < len; i++)
477 {
478 *cptr++ = 0;
479 }
480 free(tmp);
481 *retlen = len;
482 }
483 return str;
484 }
485
486 static void write_rcinline(FILE *fp)
487 {
488 lan_blk_t *lbp;
489 int i;
490 int j;
491
492 for(lbp = lanblockhead; lbp; lbp = lbp->next)
493 {
494 unsigned offs = 4 * (lbp->nblk * 3 + 1);
495 fprintf(fp, "\n1 MESSAGETABLE\n");
496 fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
497 fprintf(fp, "{\n");
498 fprintf(fp, " /* NBlocks */ 0x%08xL,\n", lbp->nblk);
499 for(i = 0; i < lbp->nblk; i++)
500 {
501 fprintf(fp, " /* Lo,Hi,Offs */ 0x%08xL, 0x%08xL, 0x%08xL,\n",
502 lbp->blks[i].idlo,
503 lbp->blks[i].idhi,
504 offs);
505 offs += lbp->blks[i].size;
506 }
507 for(i = 0; i < lbp->nblk; i++)
508 {
509 block_t *blk = &lbp->blks[i];
510 for(j = 0; j < blk->nmsg; j++)
511 {
512 char *cptr;
513 int l = blk->msgs[j]->len;
514 char *comma = j == blk->nmsg-1 && i == lbp->nblk-1 ? "" : ",";
515 cptr = make_string(blk->msgs[j]->msg, l, unicodeout ? 0 : blk->msgs[j]->cp);
516 fprintf(fp, "\n /* Msg 0x%08x */ 0x%04x, 0x000%c,\n",
517 blk->idlo + j,
518 (unicodeout ? (l*2+3)&~3 : (l+3)&~3)+4,
519 unicodeout ? '1' : '0');
520 fprintf(fp, "%s%s\n", cptr, comma);
521 free(cptr);
522 }
523 }
524 fprintf(fp, "}\n");
525 }
526 }
527
528 void write_rc_file(const char *fname)
529 {
530 FILE *fp;
531 char *cptr;
532
533 fp = fopen(fname, "w");
534 if(!fp)
535 {
536 perror(fname);
537 exit(1);
538 }
539 cptr = ctime(&now);
540 killnl(cptr, 0);
541 fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline, cptr);
542
543 if(rcinline)
544 write_rcinline(fp);
545 else
546 write_rcbin(fp);
547 fclose(fp);
548 }
549
550 void write_bin_files(void)
551 {
552 lan_blk_t *lbp;
553 token_t *ttab;
554 int ntab;
555 int i;
556 int j;
557 char fname[16];
558 FILE *fp;
559
560 get_tokentable(&ttab, &ntab);
561
562 for (lbp = lanblockhead; lbp; lbp = lbp->next)
563 {
564 unsigned offs = 4 * (lbp->nblk * 3 + 1);
565
566 char *cptr = NULL;
567 for(i = 0; i < ntab; i++)
568 {
569 if (ttab[i].type == tok_language && ttab[i].token == lbp->lan)
570 {
571 if (ttab[i].alias)
572 cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
573 break;
574 }
575 }
576
577 if (!cptr)
578 internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x", lbp->lan);
579 sprintf(fname, "%s.bin", cptr);
580 free(cptr);
581
582 fp = fopen(fname, "wb");
583 if (!fp)
584 {
585 perror(fname);
586 exit(1);
587 }
588
589 /* NBlocks */
590 fwrite(&lbp->nblk, sizeof(unsigned long), 1, fp);
591 for(i = 0; i < lbp->nblk; i++)
592 {
593 /* Lo */
594 fwrite(&lbp->blks[i].idlo, sizeof(unsigned long), 1, fp);
595 /* Hi */
596 fwrite(&lbp->blks[i].idhi, sizeof(unsigned long), 1, fp);
597 /* Offs */
598 fwrite(&offs, sizeof(unsigned long), 1, fp);
599 offs += lbp->blks[i].size;
600 }
601
602 for (i = 0; i < lbp->nblk; i++)
603 {
604 block_t *blk = &lbp->blks[i];
605 for (j = 0; j < blk->nmsg; j++)
606 {
607 char *cptr;
608 int l = blk->msgs[j]->len;
609 int retlen = 0;
610
611 unsigned short length = (unicodeout ? (l*2+3)&~3 : (l+3)&~3)+4;
612 unsigned short flags = unicodeout ? 1 : 0;
613
614 /* Lo */
615 fwrite(&length, sizeof(unsigned short), 1, fp);
616 /* Hi */
617 fwrite(&flags, sizeof(unsigned short), 1, fp);
618
619 /* message text */
620 cptr = make_bin_string(blk->msgs[j]->msg, l, &retlen, unicodeout ? 0 : blk->msgs[j]->cp);
621 fwrite(cptr, retlen, 1, fp);
622
623 free(cptr);
624 }
625 }
626
627 fclose(fp);
628 }
629 }
630
631 /* EOF */