Line 402... |
Line 402... |
402 |
}
|
402 |
}
|
403 |
|
403 |
|
404 |
|
404 |
|
405 |
/* mvcomp applies the MV-COMPRESSION algorithm to data and returns the compressed size
|
405 |
/* mvcomp applies the MV-COMPRESSION algorithm to data and returns the compressed size
|
406 |
* updates len with the number of input bytes left unprocessed */
|
406 |
* updates len with the number of input bytes left unprocessed */
|
407 |
static unsigned short mvcomp(void *dstbuf, size_t dstbufsz, const unsigned char *src, size_t *len) {
|
407 |
static unsigned short mvcomp(void *dstbuf, size_t dstbufsz, const unsigned char *src, size_t *len, unsigned short *maxbytesahead) {
|
408 |
unsigned short complen = 0;
|
408 |
unsigned short complen = 0;
|
409 |
unsigned short *dst = dstbuf;
|
409 |
unsigned short *dst = dstbuf;
|
410 |
unsigned short bytesprocessed = 0;
|
410 |
unsigned short bytesprocessed = 0;
|
411 |
unsigned char litqueue[32];
|
411 |
unsigned char litqueue[32];
|
412 |
unsigned char litqueuelen = 0;
|
412 |
unsigned char litqueuelen = 0;
|
413 |
|
413 |
|
- |
|
414 |
*maxbytesahead = 0;
|
- |
|
415 |
|
414 |
/* read src byte by byte, len times, each time look for a match of 15,14,13..2 chars in the back buffer */
|
416 |
/* read src byte by byte, len times, each time look for a match of 15,14,13..2 chars in the back buffer */
|
415 |
while (*len > 0) {
|
417 |
while (*len > 0) {
|
416 |
unsigned short matchlen;
|
418 |
unsigned short matchlen;
|
417 |
unsigned short minmatch;
|
419 |
unsigned short minmatch;
|
418 |
unsigned short offset;
|
420 |
unsigned short offset;
|
419 |
matchlen = 16;
|
421 |
matchlen = 16;
|
420 |
if (*len < matchlen) matchlen = (unsigned short)(*len);
|
422 |
if (*len < matchlen) matchlen = (unsigned short)(*len);
|
421 |
|
423 |
|
- |
|
424 |
/* monitor the amount of bytes that the compressed stream is "ahead" of
|
- |
|
425 |
* uncompressed data, this is an information used later to size a proper
|
- |
|
426 |
* buffer for in-place depacking */
|
- |
|
427 |
if (complen + litqueuelen + 2 > bytesprocessed) {
|
- |
|
428 |
unsigned short mvstreamlen = complen + litqueuelen + 2;
|
- |
|
429 |
if (*maxbytesahead < (mvstreamlen - bytesprocessed)) *maxbytesahead = mvstreamlen - bytesprocessed;
|
- |
|
430 |
}
|
- |
|
431 |
|
422 |
/* abort if no space in output buffer, but do NOT break a literal queue */
|
432 |
/* abort if no space in output buffer, but do NOT break a literal queue */
|
423 |
if ((complen >= dstbufsz - 32) && (litqueuelen == 0)) return(complen);
|
433 |
if ((complen >= dstbufsz - 32) && (litqueuelen == 0)) return(complen);
|
424 |
|
434 |
|
425 |
/* look for a minimum match of 2 bytes, unless I have some pending literal bytes
|
435 |
/* look for a minimum match of 2 bytes, unless I have some pending literal bytes
|
426 |
* awaiting, in which case I am going through a new data pattern and it is more
|
436 |
* awaiting, in which case I am going through a new data pattern and it is more
|
Line 506... |
Line 516... |
506 |
}
|
516 |
}
|
507 |
|
517 |
|
508 |
|
518 |
|
509 |
/* write the language block (id, dict, strings) into the LNG file.
|
519 |
/* write the language block (id, dict, strings) into the LNG file.
|
510 |
* strings are compressed if compflag != 0 */
|
520 |
* strings are compressed if compflag != 0 */
|
511 |
static int svl_write_lang(const struct svl_lang *l, FILE *fd, int compflag) {
|
521 |
static int svl_write_lang(const struct svl_lang *l, FILE *fd, int compflag, unsigned short *buffrequired) {
|
512 |
unsigned short strings_bytes = svl_strings_bytes(l);
|
522 |
unsigned short strings_bytes = svl_strings_bytes(l);
|
513 |
unsigned short langid = *((unsigned short *)(&l->id));
|
523 |
unsigned short langid = *((unsigned short *)(&l->id));
|
514 |
const char *stringsptr = l->strings;
|
524 |
const char *stringsptr = l->strings;
|
515 |
|
525 |
|
516 |
/* if compressed then do the magic */
|
526 |
/* if compressed then do the magic */
|
517 |
if (compflag) {
|
527 |
if (compflag) {
|
518 |
static char compstrings[65000];
|
528 |
static char compstrings[65000];
|
519 |
unsigned short comp_bytes;
|
529 |
unsigned short comp_bytes;
|
520 |
size_t stringslen = strings_bytes;
|
530 |
size_t stringslen = strings_bytes;
|
- |
|
531 |
unsigned short mvcompbytesahead;
|
521 |
comp_bytes = mvcomp(compstrings, sizeof(compstrings), l->strings, &stringslen);
|
532 |
comp_bytes = mvcomp(compstrings, sizeof(compstrings), l->strings, &stringslen, &mvcompbytesahead);
|
- |
|
533 |
if (mvcompbytesahead + stringslen > *buffrequired) {
|
- |
|
534 |
*buffrequired = mvcompbytesahead + stringslen;
|
- |
|
535 |
}
|
522 |
if (comp_bytes < strings_bytes) {
|
536 |
if (comp_bytes < strings_bytes) {
|
523 |
printf("lang %c%c mvcomp-ressed (%u bytes -> %u bytes)\n", l->id[0], l->id[1], strings_bytes, comp_bytes);
|
537 |
printf("lang %c%c mvcomp-ressed (%u bytes -> %u bytes) mvcomp stream at most %u bytes ahead of raw data (%u bytes needed for in-place decomp)\n", l->id[0], l->id[1], strings_bytes, comp_bytes, mvcompbytesahead, strings_bytes + mvcompbytesahead);
|
524 |
langid |= 0x8000; /* LNG langblock flag that means "this lang is compressed" */
|
538 |
langid |= 0x8000; /* LNG langblock flag that means "this lang is compressed" */
|
525 |
strings_bytes = comp_bytes;
|
539 |
strings_bytes = comp_bytes;
|
526 |
stringsptr = compstrings;
|
540 |
stringsptr = compstrings;
|
527 |
} else {
|
541 |
} else {
|
528 |
printf("lang %c%c left UNCOMPRESSED (uncomp=%u bytes ; mvcomp=%u bytes)\n", l->id[0], l->id[1], strings_bytes, comp_bytes);
|
542 |
printf("lang %c%c left UNCOMPRESSED (uncomp=%u bytes ; mvcomp=%u bytes)\n", l->id[0], l->id[1], strings_bytes, comp_bytes);
|
Line 546... |
Line 560... |
546 |
fd = fopen(fn, "wb");
|
560 |
fd = fopen(fn, "wb");
|
547 |
if (fd == NULL) {
|
561 |
if (fd == NULL) {
|
548 |
return(0);
|
562 |
return(0);
|
549 |
}
|
563 |
}
|
550 |
|
564 |
|
551 |
/* the maximum mvcomp overhead is 3.23% (ie. an increase of 1 byte for every
|
- |
|
552 |
* 31 bytes of source, because 31 source bytes are encoded as a 32 bytes
|
- |
|
553 |
* sequence). The necessary buffer for in-place decompression is therefore
|
- |
|
554 |
* FILESIZE + (FILESIZE / 31) + 1 */
|
- |
|
555 |
allocsz = biggest_langsz + (biggest_langsz / 31) + 1;
|
565 |
allocsz = biggest_langsz + (biggest_langsz / 20);
|
556 |
printf("biggest lang block is %u bytes -> allocating a %u bytes buffer (3.23%% margin for inplace mvcomp decompression)\n", biggest_langsz, allocsz);
|
566 |
printf("biggest lang block is %u bytes -> allocating a %u bytes buffer (5%% safety margin)\n", biggest_langsz, allocsz);
|
557 |
fprintf(fd, "/* THIS FILE HAS BEEN GENERATED BY TLUMACZ (PART OF THE SVARLANG LIBRARY) */\r\n");
|
567 |
fprintf(fd, "/* THIS FILE HAS BEEN GENERATED BY TLUMACZ (PART OF THE SVARLANG LIBRARY) */\r\n");
|
558 |
fprintf(fd, "const unsigned short svarlang_memsz = %uu;\r\n", allocsz);
|
568 |
fprintf(fd, "const unsigned short svarlang_memsz = %uu;\r\n", allocsz);
|
559 |
fprintf(fd, "const unsigned short svarlang_string_count = %uu;\r\n\r\n", l->num_strings);
|
569 |
fprintf(fd, "const unsigned short svarlang_string_count = %uu;\r\n\r\n", l->num_strings);
|
560 |
fprintf(fd, "char svarlang_mem[%u] = {\r\n", allocsz);
|
570 |
fprintf(fd, "char svarlang_mem[%u] = {\r\n", allocsz);
|
561 |
|
571 |
|
Line 744... |
Line 754... |
744 |
|
754 |
|
745 |
/* write lang ID to file, followed string table size, and then
|
755 |
/* write lang ID to file, followed string table size, and then
|
746 |
the dictionary and string table for current language
|
756 |
the dictionary and string table for current language
|
747 |
skip this for reference language if /excref given */
|
757 |
skip this for reference language if /excref given */
|
748 |
if ((reflang != NULL) || (excref == 0)) {
|
758 |
if ((reflang != NULL) || (excref == 0)) {
|
- |
|
759 |
/* also updates the biggest_langsz variable to accomodate enough space
|
- |
|
760 |
* for in-place decompression of mvcomp-compressed lang blocks */
|
749 |
if (!svl_write_lang(lang, fd, mvcomp_enabled)) {
|
761 |
if (!svl_write_lang(lang, fd, mvcomp_enabled, &biggest_langsz)) {
|
750 |
fprintf(stderr, "ERROR WRITING TO OUTPUT FILE\r\n");
|
762 |
fprintf(stderr, "ERROR WRITING TO OUTPUT FILE\r\n");
|
751 |
ecode = 1;
|
763 |
ecode = 1;
|
752 |
goto exit_main;
|
764 |
goto exit_main;
|
753 |
}
|
765 |
}
|
754 |
} else {
|
766 |
} else {
|