diff options
Diffstat (limited to 'lib/dteutils.cpp')
-rw-r--r-- | lib/dteutils.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/lib/dteutils.cpp b/lib/dteutils.cpp new file mode 100644 index 0000000..4ae8668 --- /dev/null +++ b/lib/dteutils.cpp @@ -0,0 +1,342 @@ +/* + * PSX-Tools Bundle Pack + * Copyright (C) 2002 Nicolas "Pixel" Noble + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include "fileutils.h" +#include "generic.h" + +class thingtree { + public: + static void addstring(const char *, long); + static long look(const char *); + static void destroy(); + private: + thingtree(); + thingtree(char, bool, thingtree *, long); + ~thingtree(); + char thischar; + bool terminal; + thingtree * father, * child, * brother; + long thingentry; + static thingtree * root; +}; + +thingtree * thingtree::root = 0; + +thingtree::thingtree(char gchar, bool gterm, thingtree * gfather, long gthingentry) : thischar(gchar), terminal(gterm), thingentry(gthingentry) { + if (!gfather) { + if (!root) { + root = new thingtree(); + } + father = root; + } else { + father = gfather; + } + brother = father->child; + father->child = this; +} + +thingtree::thingtree() : thischar(0), terminal(false), father(0), child(0), brother(0) { } + +long thingtree::look(const char * s) { + const char * p; + long currentthing = -1; + thingtree * ptr = root; + + if (!ptr) { + printm(M_ERROR, "Error: thingtree not initialised\n"); + exit(-1); + } + + for (p = s; *p; p++) { +// printm(M_INFO, "Looking for '%c'\n", *p); + for (ptr = ptr->child; ptr; ptr = ptr->brother) { +// printm(M_INFO, "Looking in %p: %c\n", ptr, ptr->thischar); + if (ptr->thischar == *p) { + if (ptr->terminal) { + currentthing = ptr->thingentry; + } + break; + } + } + if (!ptr) { +// printm(M_INFO, "Not found.\n"); + break; + } + } + + if (currentthing == -1) { + printm(M_ERROR, "Error, can't find any entry for string '%s'\n", s); + } + + return currentthing; +} + +void thingtree::addstring(const char * s, long thingentry) { + const char * p; + thingtree * ptr, * fptr; + + if (!root) { + root = new thingtree(); + } + +// printm(M_INFO, "Creating new thingtree entry: %li='%s'\n", thingentry, s); + + ptr = root; + for (p = s; *p; p++) { + fptr = ptr; +// printm(M_INFO, "Finding entry for '%c'\n", *p); + for (ptr = ptr->child; ptr; ptr = ptr->brother) { +// printm(M_INFO, "Browsing childs: %p = %c\n", ptr, ptr->thischar); + if (ptr->thischar == *p) + break; + } + + if (!ptr) { +// printm(M_INFO, "Creating new branch for %c\n", *p); + ptr = new thingtree(*p, *(p + 1) == 0, fptr, thingentry); +// printm(M_INFO, "Created branch %p\n", ptr); + } else { + if (*(p + 1) == 0) { + ptr->terminal = true; + ptr->thingentry = thingentry; + } + } + } +} + +void thingtree::destroy() { + delete root; + root = 0; +} + +thingtree::~thingtree() { + if (father->child == this) + father->child = brother; + + while (child) + delete child; +} + +char * things[256]; + +char * dte_text; +char dte_flags[256 * 256]; +long dte_counters[256 * 256]; +long dte_entries[256]; +char alloweds[256]; +long dte_usage[256]; + +long dte_most; +long dte_counter; +long dte_text_size; +int dte_size; +long gain; +long nb_dte = 0; +long tnb_dte = 0; + +void dte_reset(void) { + memset(dte_counters, 0, 0x40000); + dte_most = 0; + dte_counter = 0; +} + +void build_dte(void) { + int i; + unsigned short t, t2; + unsigned short p = 0; + + for (i = 0; i < dte_text_size; i++) { + t = *((unsigned short *) (dte_text + i)); + t2 = *((unsigned short *) (dte_text + i + 1)); + if (t == p) { + p = 0; + continue; + } + p = t; + if (!dte_flags[t]) { +// if ((!dte_flags[t]) && (dte_flags[t2] != 3)) { + if ((dte_counters[t]++) == 0) { + nb_dte++; + } + if (dte_counters[t] > dte_counter) { + dte_most = t; + dte_counter = dte_counters[t]; + } +// } else if (dte_flags[t] == 3) { +// i++; + } + } +} + +void push_entry(long entry) { + int i; + char t[3], c1, c2; + t[2] = 0; + + c1 = dte_most & 0xff; + c2 = dte_most >> 8; + t[0] = things[c1][0]; + t[1] = things[c2][0]; + + for (i = 0; i < 256; i++) { + if (!dte_entries[i]) { + dte_entries[i] = entry; + things[i] = strdup(t); + thingtree::addstring(t, i); + break; + } + } +} + +char * read_line(FILE * f, char * b) { + int r, pos = 0; + + while (!feof(f)) { + if ((r = fgetc(f)) == EOF) + break; + if (r == 0x0d) { + if ((r = fgetc(f)) == EOF) + break; + } + if (r == 0x0a) { + b[pos] = 0; + return b; + } + b[pos++] = r; + } + + b[pos] = 0; + + return b; +} + +void dte_compress() { + int i, j; + char c1, c2; + + for (i = 0; i < 256; i++) { + for (j = 0; j < 256; j++) { + dte_flags[i * 256 + j] = alloweds[i] ? alloweds[j] ? 0 : 1 : 1; + } + } + + gain = 0; + + printm(M_STATUS, "Going for it: dte_size = %i\n", dte_size); + for (i = 0; i < dte_size; i++) { + dte_reset(); + build_dte(); + if (!tnb_dte) + tnb_dte = nb_dte; + c1 = dte_most & 0xff; + c2 = dte_most >> 8; + c1 = things[c1][0]; + c2 = things[c2][0]; + printm(M_INFO, "Entry #%i, most count: %li, couple = 0x%04x = (%c %c)\n", i, dte_counter, (int) dte_most, c1, c2); + dte_flags[dte_most] = 3; + gain += dte_counter; + push_entry(dte_most); + } + + printm(M_STATUS, "Estimated gain: %li bytes, new file size = %li\n", gain, dte_text_size - gain); +} + +void read_thingy(FILE * f) { + char line[256], * st, * thing; + long code; + int i; + + st = line + 2; + thing = line + 5; + line[0] = '0'; + line[1] = 'x'; + + dte_size = 0; + + for (i = 0; i < 256; i++) { + dte_entries[i] = -1; + } + + while (!feof(f)) { + if (strlen(read_line(f, st))) { + line[4] = 0; + sscanf(line, "%li", &code); + switch (strlen(thing)) { + case 0: + dte_size++; + dte_entries[code] = 0; + break; + case 1: + alloweds[code] = 1; + default: + things[code] = strdup(thing); + thingtree::addstring(thing, code); + } + } + } +} + +void read_thingy_file(FILE * f) { + char line[10240], * p, * c, trans[5]; + long code; + int ptr = 0, i; + + for (i = 0; i < 256; i++) { + dte_usage[i] = 0; + } + + while (!feof(f)) { + if (!strlen(p = read_line(f, line))) + continue; + while (*p) { + if (*p == '<') { + if (!(c = strchr(p, '>'))) { + printm(M_ERROR, "Error in file: '<' not closed.\n"); + exit(-1); + } + p++; + if ((c - p) == 2) { + *c = 0; + sprintf(trans, "0x%s", p); + sscanf(trans, "%li", &code); + dte_text[ptr++] = code; + printm(M_BARE, "0x%02x-", code); + } else { + printm(M_BARE, "Unknow %s-", p); + } + p = c + 1; + } else { + if ((code = thingtree::look(p)) == -1) + exit(-1); + dte_text[ptr++] = code; + p += strlen(things[code]); + printm(M_BARE, "%s-", things[code]); + dte_usage[code]++; + } + } + printm(M_BARE, "\n"); + } + + dte_text[ptr] = dte_text[ptr + 1] = dte_text[ptr + 2] = dte_text[ptr + 3] = 0; + dte_text_size = ptr; +} |