Subversion Repositories SvarDOS

Rev

Rev 2016 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2016 Rev 2083
Line 1... Line 1...
1
/*
1
/*
2
 * Copyright (C) 2021-2023 Mateusz Viste
2
 * Copyright (C) 2021-2024 Mateusz Viste
3
 *
3
 *
4
 * Dictionary-based lookups contributed by Bernd Boeckmann, 2023
4
 * Dictionary-based lookups contributed by Bernd Boeckmann, 2023
5
 *
5
 *
6
 * usage: tlumacz en fr pl etc
6
 * usage: tlumacz en fr pl etc
7
 *
7
 *
-
 
8
 * computes:
8
 * computes an out.lng file that contains all language resources.
9
 * OUT.LNG -> contains all language resources.
-
 
10
 * OUTC.LNG -> same as OUT.LNG but with compressed strings (slower to load).
9
 *
11
 *
-
 
12
 * === COMPRESSION ===========================================================
-
 
13
 * The compression scheme is very simple. It is applied only to strings (ie.
-
 
14
 * not the dictionnary) and it is basically a stream of 16-bit values (WORDs),
-
 
15
 * where each WORD value contains the following bits "LLLL OOOO OOOO OOOO":
-
 
16
 *
-
 
17
 * OOOO OOOO OOOO = a backreference offset ("look that many bytes back")
-
 
18
 * LLLL = the number of bytes to copy from the backreference
-
 
19
 *
-
 
20
 * Special case: a WORD that is smaller than 256 represents a single literal
-
 
21
 * byte.
-
 
22
 *
-
 
23
 * To recognize a compressed lang block one has to look at the id of the block
-
 
24
 * (16-bit language id). If its highest bit is set (0x8000) then the lang block
-
 
25
 * is compressed.
10
 */
26
 */
11
 
27
 
12
 
28
 
13
#include <stdio.h>
29
#include <stdio.h>
14
#include <stdlib.h>
30
#include <stdlib.h>
Line 332... Line 348...
332
static int svl_write_header(unsigned short num_strings, FILE *fd) {
348
static int svl_write_header(unsigned short num_strings, FILE *fd) {
333
  return((fwrite("SvL\x1a", 1, 4, fd) == 4) && (fwrite(&num_strings, 1, 2, fd) == 2));
349
  return((fwrite("SvL\x1a", 1, 4, fd) == 4) && (fwrite(&num_strings, 1, 2, fd) == 2));
334
}
350
}
335
 
351
 
336
 
352
 
-
 
353
/* mvcomp applies the MV-COMPRESSION algorithm to data and returns the compressed size */
-
 
354
static unsigned short mvcomp(char *dstbuf, const char *src, unsigned short len) {
-
 
355
  unsigned short complen = 0;
-
 
356
  unsigned short *dst = (void *)dstbuf;
-
 
357
  unsigned short bytesprocessed = 0;
-
 
358
 
-
 
359
  /* read src byte by byte, len times, each time look for a match of 15,14,13..2 chars in the back buffer */
-
 
360
  while (len > 0) {
-
 
361
    unsigned short matchlen;
-
 
362
    unsigned short offset;
-
 
363
    matchlen = 15;
-
 
364
    if (len < matchlen) matchlen = len;
-
 
365
 
-
 
366
    for (; matchlen > 1; matchlen--) {
-
 
367
      /* start at offset - 4095 and try to match something */
-
 
368
      offset = 4095;
-
 
369
      if (offset > bytesprocessed) offset = bytesprocessed;
-
 
370
 
-
 
371
      for (; offset > matchlen; offset--) {
-
 
372
        if (memcmp(src, src - offset, matchlen) == 0) {
-
 
373
          printf("Found match of %u bytes at offset -%u: '%c%c%c...'\n", matchlen, offset, src[0], src[1], src[2]);
-
 
374
          goto FOUND;
-
 
375
        }
-
 
376
      }
-
 
377
    }
-
 
378
 
-
 
379
    /* if here: no match found, write a literal byte */
-
 
380
    *dst = *src;
-
 
381
    dst++;
-
 
382
    src++;
-
 
383
    bytesprocessed++;
-
 
384
    len--;
-
 
385
    complen += 2;
-
 
386
    continue;
-
 
387
 
-
 
388
    FOUND: /* found a match of matchlen bytes at -offset */
-
 
389
    *dst = (matchlen << 12) | offset;
-
 
390
    dst++;
-
 
391
    src += matchlen;
-
 
392
    bytesprocessed += matchlen;
-
 
393
    len -= matchlen;
-
 
394
    complen += 2;
-
 
395
  }
-
 
396
 
-
 
397
  return(complen);
-
 
398
}
-
 
399
 
-
 
400
 
-
 
401
/* write the language block (id, dict, strings) into the LNG file.
-
 
402
 * strings are compressed if compflag != 0 */
337
static int svl_write_lang(const struct svl_lang *l, FILE *fd) {
403
static int svl_write_lang(const struct svl_lang *l, FILE *fd, int compflag) {
338
  unsigned short strings_bytes = svl_strings_bytes(l);
404
  unsigned short strings_bytes = svl_strings_bytes(l);
-
 
405
  unsigned short langid = *((unsigned short *)(&l->id));
-
 
406
  const char *stringsptr = l->strings;
339
 
407
 
-
 
408
  /* if compressed then do the magic */
-
 
409
  if (compflag) {
-
 
410
    static char compstrings[65000];
-
 
411
    langid |= 0x8000; /* LNG langblock flag that means "this lang is compressed" */
-
 
412
    strings_bytes = mvcomp(compstrings, l->strings, strings_bytes);
-
 
413
    stringsptr = compstrings;
-
 
414
  }
-
 
415
 
340
  return((fwrite(&l->id, 1, 2, fd) == 2) &&
416
  return((fwrite(&langid, 1, 2, fd) == 2) &&
341
         (fwrite(&strings_bytes, 1, 2, fd) == 2) &&
417
         (fwrite(&strings_bytes, 1, 2, fd) == 2) &&
342
         (fwrite(l->dict, 1, svl_dict_bytes(l), fd) == svl_dict_bytes(l)) &&
418
         (fwrite(l->dict, 1, svl_dict_bytes(l), fd) == svl_dict_bytes(l)) &&
343
         (fwrite(l->strings, 1, svl_strings_bytes(l), fd) == svl_strings_bytes(l)));
419
         (fwrite(stringsptr, 1, strings_bytes, fd) == strings_bytes));
344
}
420
}
345
 
421
 
346
 
422
 
347
static int svl_write_c_source(const struct svl_lang *l, const char *fn, unsigned short biggest_langsz) {
423
static int svl_write_c_source(const struct svl_lang *l, const char *fn, unsigned short biggest_langsz) {
348
  FILE *fd;
424
  FILE *fd;
Line 452... Line 528...
452
  return(1);
528
  return(1);
453
}
529
}
454
 
530
 
455
 
531
 
456
int main(int argc, char **argv) {
532
int main(int argc, char **argv) {
457
  FILE *fd;
533
  FILE *fd, *fdc;
458
  int ecode = 0;
534
  int ecode = 0;
459
  int i, output_format = C_OUTPUT;
535
  int i, output_format = C_OUTPUT;
460
  unsigned short biggest_langsz = 0;
536
  unsigned short biggest_langsz = 0;
461
  struct svl_lang *lang = NULL, *reflang = NULL;
537
  struct svl_lang *lang = NULL, *reflang = NULL;
462
 
538
 
Line 472... Line 548...
472
  fd = fopen("out.lng", "wb");
548
  fd = fopen("out.lng", "wb");
473
  if (fd == NULL) {
549
  if (fd == NULL) {
474
    fprintf(stderr, "ERROR: FAILED TO CREATE OR OPEN OUT.LNG");
550
    fprintf(stderr, "ERROR: FAILED TO CREATE OR OPEN OUT.LNG");
475
    return(1);
551
    return(1);
476
  }
552
  }
-
 
553
  fdc = fopen("outc.lng", "wb");
-
 
554
  if (fd == NULL) {
-
 
555
    fclose(fd);
-
 
556
    puts("ERR: failed to open or create OUTC.LNG");
-
 
557
    return(1);
-
 
558
  }
477
 
559
 
478
  /* write lang blocks */
560
  /* write lang blocks */
479
  for (i = 1; i < argc; i++) {
561
  for (i = 1; i < argc; i++) {
480
    unsigned short sz;
562
    unsigned short sz;
481
    char id[3];
563
    char id[3];
Line 523... Line 605...
523
      if (!svl_write_header(lang->num_strings, fd)) {
605
      if (!svl_write_header(lang->num_strings, fd)) {
524
        fprintf(stderr, "ERROR WRITING TO OUTPUT FILE\r\n");
606
        fprintf(stderr, "ERROR WRITING TO OUTPUT FILE\r\n");
525
        ecode = 1;
607
        ecode = 1;
526
        goto exit_main;
608
        goto exit_main;
527
      }
609
      }
-
 
610
      if (!svl_write_header(lang->num_strings, fdc)) {
-
 
611
        fprintf(stderr, "ERROR WRITING TO OUTPUT (COMPRESSED) FILE\r\n");
-
 
612
        ecode = 1;
-
 
613
        break;
-
 
614
      }
528
    }
615
    }
529
 
616
 
530
    /* write lang ID to file, followed string table size, and then
617
    /* write lang ID to file, followed string table size, and then
531
       the dictionary and string table for current language */
618
       the dictionary and string table for current language */
532
    if (!svl_write_lang(lang, fd)) {
619
    if (!svl_write_lang(lang, fd, 0)) { /* UNCOMPRESSED */
533
      fprintf(stderr, "ERROR WRITING TO OUTPUT FILE\r\n");
620
      fprintf(stderr, "ERROR WRITING TO OUTPUT FILE\r\n");
534
      ecode = 1;
621
      ecode = 1;
535
      goto exit_main;
622
      goto exit_main;
536
    }
623
    }
537
 
624
 
-
 
625
    /* write lang ID to file, followed string table size, and then
-
 
626
       the dictionary and string table for current language */
-
 
627
    if (!svl_write_lang(lang, fdc, 1)) { /* COMPRESSED */
-
 
628
      fprintf(stderr, "ERROR WRITING TO OUTPUT (COMPRESSED) FILE\r\n");
-
 
629
      ecode = 1;
-
 
630
      goto exit_main;
-
 
631
    }
-
 
632
 
538
    /* remember reference data for other languages */
633
    /* remember reference data for other languages */
539
    if (!reflang) {
634
    if (!reflang) {
540
      reflang = lang;
635
      reflang = lang;
541
    } else {
636
    } else {
542
      svl_lang_free(lang);
637
      svl_lang_free(lang);
Line 553... Line 648...
553
  /* compute the deflang file containing a dump of the reference block */
648
  /* compute the deflang file containing a dump of the reference block */
554
  if (output_format == C_OUTPUT) {
649
  if (output_format == C_OUTPUT) {
555
    if (!svl_write_c_source(reflang, "deflang.c", biggest_langsz)) {
650
    if (!svl_write_c_source(reflang, "deflang.c", biggest_langsz)) {
556
      fprintf(stderr, "ERROR: FAILED TO OPEN OR CREATE DEFLANG.C\r\n");
651
      fprintf(stderr, "ERROR: FAILED TO OPEN OR CREATE DEFLANG.C\r\n");
557
      ecode = 1;
652
      ecode = 1;
558
    }    
653
    }
559
  } else {
654
  } else {
560
    if (!svl_write_asm_source(reflang, "deflang.inc", biggest_langsz, output_format)) {
655
    if (!svl_write_asm_source(reflang, "deflang.inc", biggest_langsz, output_format)) {
561
      fprintf(stderr, "ERROR: FAILED TO OPEN OR CREATE DEFLANG.INC\r\n");
656
      fprintf(stderr, "ERROR: FAILED TO OPEN OR CREATE DEFLANG.INC\r\n");
562
      ecode = 1;
657
      ecode = 1;
563
    }
658
    }
Line 568... Line 663...
568
    svl_lang_free(lang);
663
    svl_lang_free(lang);
569
  }
664
  }
570
  if (reflang) {
665
  if (reflang) {
571
    svl_lang_free(reflang);
666
    svl_lang_free(reflang);
572
    reflang = NULL;
667
    reflang = NULL;
573
    lang = NULL;    
668
    lang = NULL;
574
  }
669
  }
575
 
670
 
576
  fclose(fd);
671
  fclose(fd);
577
 
672
 
578
  return(ecode);
673
  return(ecode);