+/* read header */
+
+code_t *read_header (char *filename) {
+ byte_t buffer[NB_BYTES * (NB_BYTES - 1) / 2 / 8 + NB_BYTES + 6] = {0};
+ code_t *table = NULL;
+ byte_t *codes = NULL;
+ byte_t cur;
+ int lengths[NB_BYTES] = {0};
+ FILE *fid = NULL;
+ int mode = 0;
+ size_t i, j, l, nb, size;
+
+ VERBOSE (DEBUG, PRINTF ("start reading header\n"));
+
+ /* open file */
+ fid = fopen (filename, "rb");
+ if (fid == NULL) {
+ VERBOSE (ERROR, _fprintf (stdout, "can't open file '%s'\n", filename));
+ return NULL;
+ }
+ VERBOSE (INFO, _fprintf (stdout, "file '%s' opened\n", filename));
+
+ /* read magic number */
+ nb = fread (buffer, 1, 6, fid);
+ VERBOSE (DEBUG, PRINTF ("nb, buffer: %d 0x%02x 0x%02x\n", nb, buffer[0], buffer[1]));
+ if ((nb == 6) && (buffer[0] == 'M') && (buffer[1] == 'Z')) {
+ mode = (buffer[2] == '1') ? 1 : (buffer[2] == '2') ? 2 : 0;
+ size = (buffer[3] << 8) + buffer[4];
+ VERBOSE (DEBUG, PRINTF ("mode, size: %d %d\n", mode, size));
+ if (size > NB_BYTES * (NB_BYTES - 1) / 2 / 8 + NB_BYTES) {
+ mode = 0;
+ } else {
+ nb = fread (buffer, 1, size, fid);
+ VERBOSE (DEBUG, PRINTF ("nb read: %d\n", nb));
+ if (nb != size) {
+ mode = 0;
+ }
+ }
+ }
+ fclose (fid);
+ if (mode == 0) {
+ VERBOSE (ERROR, _fprintf (stdout, "incorrect file\n"));
+ return NULL;
+ }
+
+ /* analyse header */
+ codes = buffer;
+ switch (mode) {
+ case 1:
+ for (i = 0; i < NB_BYTES; i++) {
+ lengths[i] = *(codes++);
+ }
+ break;
+ case 2:
+ nb = *(codes++) + 1;
+ VERBOSE (DEBUG, PRINTF ("nb codes: %d\n", nb));
+ for (i = 0; i < nb; i++) {
+ j = *(codes++);
+ lengths[j] = *(codes++);
+ }
+ break;
+ }
+ VERBOSE (DEBUG, for (i = 0; i < NB_BYTES; i++) if (lengths[i]) PRINTF ("%d: %d\n", i, lengths[i]));
+
+ /* check lengths */
+ for (i = 0, l = 0; i < NB_BYTES; i++) {
+ l += lengths[i];
+ }
+ if (((mode == 1) && (size - 256 != (l + 7) / 8)) ||
+ ((mode == 2) && (size - 2 * nb - 1 != (l + 7) / 8))) {
+ VERBOSE (ERROR, _fprintf (stdout, "incorrect code table length\n"));
+ return NULL;
+ }
+
+ /* allocate table */
+ table = (code_t *) calloc (NB_BYTES, sizeof (code_t));
+ if (table == NULL) {
+ VERBOSE (ERROR, _fprintf (stdout, "can't allocate memory\n"));
+ return NULL;
+ }
+
+ /* decode code */
+ cur = *(codes++);
+ l = 8;
+ for (i = 0; i < NB_BYTES; i++) {
+ if (lengths[i] == 0) {
+ continue;
+ }
+ while (lengths[i]--) {
+ codcat ((char *)(table + i), sizeof (code_t), ((cur & 0x80) == 0) ? "0" : "1");
+ l--;
+ cur <<= 1;
+ if (l == 0) {
+ cur = *(codes++);
+ l = 8;
+ }
+ }
+ }
+
+ VERBOSE (DEBUG, PRINTF ("end reading header\n"));
+
+ return table;
+}
+
+/* write decompressed file */
+
+int write_decompress (char *output, char *input, code_t *codes)
+{
+ byte_t bufin[BUFFER_SIZE] = {0};
+ byte_t bufout[BUFFER_SIZE] = {0};
+ byte_t bufhea[MAX(NB_BYTES * (NB_BYTES - 1) / 2 / 8 + NB_BYTES + 6, BUFFER_SIZE)] = {0};
+ char bits[(NB_BYTES - 1) + 1] = {0};
+ FILE *fin, *fout;
+ int i, j, k, nb, size, rem;
+ int is_found;
+ int l = 0;
+ byte_t *pt;
+
+ VERBOSE (DEBUG, PRINTF ("start writing decompressed file\n"));
+
+ /* open file for reading */
+ fin = fopen (input, "rb");
+ if (fin == NULL) {
+ VERBOSE (ERROR, _fprintf (stdout, "can't open file '%s' for reading\n", input));
+ return 1;
+ }
+ VERBOSE (INFO, _fprintf (stdout, "file '%s' opened\n", input));
+
+ /* read magic number */
+ nb = fread (bufhea, 1, 6, fin);
+ if (nb != 6) {
+ VERBOSE (ERROR, _fprintf (stdout, "can't read file\n"));
+ fclose (fin);
+ return 1;
+ }
+ size = (bufhea[3] << 8) + bufhea[4];
+ VERBOSE (DEBUG, _fprintf (stdout, "table size: %d\n", size));
+ rem = bufhea[5];
+ VERBOSE (DEBUG, _fprintf (stdout, "remainder: %d\n", rem));
+ nb = fread (bufhea, 1, size, fin);
+ if (nb != size) {
+ VERBOSE (ERROR, _fprintf (stdout, "can't read file\n"));
+ fclose (fin);
+ return 1;
+ }
+
+ /* open file for writing */
+ fout = fopen (output, "wb");
+ if (fout == NULL) {
+ VERBOSE (ERROR, _fprintf (stdout, "can't open file '%s' for writing\n", output));
+ return 2;
+ }
+ VERBOSE (INFO, _fprintf (stdout, "file '%s' opened\n", output));
+
+ /* write file */
+ pt = bufout;
+ while (!feof (fin)) {
+ nb = fread (bufin, 1, BUFFER_SIZE, fin);
+ VERBOSE (DEBUG, PRINTF ("nbread: %d\n", nb));
+ for (i = 0; i < nb; i++) {
+ for (j = 0; j < 8; j++) {
+ codcat (bits, sizeof (bits), ((bufin[i] & 0x80) == 0) ? "0" : "1");
+ bufin[i] <<= 1;
+ l++;
+ VERBOSE (DEBUG, PRINTF ("bits: %d - %s\n", codlen (bits), bits));
+
+ /* look for correct code */
+ is_found = 0;
+ for (k = 0; (k < NB_BYTES) && (!is_found); k++) {
+ if (codcmp ((char *)(codes + k), bits) == 0) {
+ is_found = 1;
+ VERBOSE (DEBUG, PRINTF ("found: %d\n", k));
+ *pt= k;
+ bits[0] = 0;
+ if (pt - bufout == BUFFER_SIZE - 1) {
+ VERBOSE (DEBUG, PRINTF ("nb buffer out: %u\n", (pt - bufout)));
+ fwrite (bufout, 1, BUFFER_SIZE, fout);
+ pt = bufout;
+ } else {
+ pt++;
+ }
+ }
+ }
+ if ((i == nb - 1) && (l % 256 == rem) && (feof (fin))) {
+ VERBOSE (DEBUG, PRINTF ("break\n"));
+ break;
+ }
+ }
+ }
+ }
+ if (pt != bufout) {
+ VERBOSE (DEBUG, PRINTF ("nb buffer out: %u\n", (pt - bufout)));
+ fwrite (bufout, 1, pt - bufout, fout);
+ }
+
+ /* close files */
+ fclose (fin);
+ fclose (fout);
+
+ VERBOSE (DEBUG, PRINTF ("end writing decompressed file\n"));
+
+ return 0;
+}
+