/* depend: */
/* cflags: */
-/* linker: */
+/* linker: atoi.o code.o debug.o fdprintf.o */
-#include <assert.h>
-#include <getopt.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include "atoi.h"
+#include "code.h"
+#include "debug.h"
+#include "fdprintf.h"
/* constants */
+#define BUFFER_SIZE 4096
+
#define COMPRESS 1
#define DECOMPRESS 2
-#define NB_CHARS 256
-#define BUFFER_SIZE 4096
-
-#define DEBUG 4
-#define INFO 3
-#define WARNING 2
-#define ERROR 1
+#ifndef O_RAW
+#define O_RAW 0
+#endif /* O_RAW */
/* macros */
-#define CEIL(x, y) (((x) + (y) - 1) / (y))
-#define MIN(x, y) (((x) < (y)) ? (x) : (y))
-#define MAX(x, y) (((x) > (y)) ? (x) : (y))
-#define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0)
-#define PRINTF(args...) do { fprintf (stdout, args); fflush (stdout); } while (0)
-
/* gobal variables */
char *progname = NULL;
-int verbose = 2;
/* help function */
-void usage (int ret)
+int usage (int ret)
{
- FILE *fd = ret ? stderr : stdout;
- fprintf (fd, "usage: %s\n", progname);
- fprintf (fd, " -h : help message\n");
- fprintf (fd, " -i <file>: input file\n");
- fprintf (fd, " -o <file>: output file\n");
- fprintf (fd, " -v : verbose level (%d)\n", verbose);
-
- exit (ret);
+ int fd = ret ? stdfderr : stdfdout;
+ fdprintf (fd, "usage: %s\n", progname);
+ fdprintf (fd, " -c : mode compress\n");
+ fdprintf (fd, " -d : mode decompress\n");
+ fdprintf (fd, " -h : help message\n");
+ fdprintf (fd, " -i <file>: input file\n");
+ fdprintf (fd, " -o <file>: output file\n");
+ fdprintf (fd, " -v : verbose level (%d)\n", verbose);
+
+ return ret;
}
/* create occurence table */
int *create_table (char *filename)
{
- char buffer[BUFFER_SIZE] = {0};
+ byte_t buffer[BUFFER_SIZE] = {0};
int nbread;
- int *table = NULL;
- FILE *fid = NULL;
+ static int table[NB_BYTES] = {0};
+ int fid = 0;
- VERBOSE (DEBUG, PRINTF ("start create occurence table\n"));
-
- /* memory allocation */
- table = (int *) calloc (NB_CHARS, sizeof (int));
- if (table == NULL) {
- VERBOSE (ERROR, printf ("can't allocate memory\n"));
- return NULL;
- }
- VERBOSE (INFO, printf ("memory allocated\n"));
+ VERBOSE (DEBUG, PRINTOUT ("start creating occurence table\n"));
/* open file */
- fid = fopen (filename, "rb");
- if (fid == NULL) {
- VERBOSE (ERROR, printf ("can't open file '%s'\n", filename));
- free (table);
+ fid = open (filename, O_RDONLY|O_RAW);
+ if (fid == -1) {
+ VERBOSE (ERROR, PRINTERR ("can't open file '%s'\n", filename));
return NULL;
}
- VERBOSE (INFO, printf ("file '%s' opened\n", filename));
+ VERBOSE (INFO, PRINTOUT ("file '%s' opened\n", filename));
/* read file */
- while (!feof (fid)) {
- nbread = fread (buffer, 1, BUFFER_SIZE, fid);
- VERBOSE (DEBUG, PRINTF ("nbread: %d\n", nbread));
+ while ((nbread = read (fid, buffer, BUFFER_SIZE)) > 0) {
+ VERBOSE (DEBUG, PRINTOUT ("nbread: %d\n", nbread));
while (nbread--) {
table[(int)buffer[nbread]]++;
}
}
/* close file */
- fclose (fid);
+ close (fid);
- VERBOSE (DEBUG, PRINTF ("end create occurence table\n"));
+ VERBOSE (DEBUG, PRINTOUT ("end creating occurence table\n"));
return table;
}
{
int i;
- printf ("Occurence table\n");
- for (i = 0; i < NB_CHARS; i++) {
+ PRINTOUT ("Occurence table\n");
+ for (i = 0; i < NB_BYTES; i++) {
if (table[i]) {
- printf ("0x%02x '%c': %d\n", i, ((i < 32) || (i > 127)) ? '.' : i, table[i]);
+ PRINTOUT ("0x%02x '%c': %d\n", i, ((i < 32) || (i > 127)) ? '.' : i, table[i]);
}
}
}
-/* leaf structure */
-
-typedef struct _leaf_t
-{
- struct _leaf_t *left;
- struct _leaf_t *right;
- int occ;
- char c;
-} leaf_t;
-
/* initialize forest */
leaf_t **init_forest (int *table)
{
- leaf_t **leafs = NULL;
+ static leaf_t *leafs[NB_BYTES + 1] = {0};
int nb_leafs = 0;
int i, l;
- VERBOSE (DEBUG, PRINTF ("start initiliazing forest\n"));
+ VERBOSE (DEBUG, PRINTOUT ("start initiliazing forest\n"));
/* count number of leafs */
- for (i = 0; i < NB_CHARS; i++) {
+ for (i = 0; i < NB_BYTES; i++) {
if (table[i] > 0) {
nb_leafs++;
}
}
- /* allocate memory */
- leafs = (leaf_t **) calloc (nb_leafs + 1, sizeof (leaf_t *));
- if (leafs == NULL) {
- VERBOSE (ERROR, printf ("can't allocate memory\n"));
- return NULL;
- }
-
/* initialize leafs */
- for (i = 0, l = 0; i < NB_CHARS; i++) {
+ for (i = 0, l = 0; i < NB_BYTES; i++) {
if (table[i] > 0) {
- leafs[l] = (leaf_t *) calloc (1, sizeof (leaf_t));
+ leafs[l] = getleaf (1);
if (leafs[l] == NULL) {
- VERBOSE (ERROR, printf ("can't allocate memory\n"));
+ VERBOSE (ERROR, PRINTERR ("can't allocate memory\n"));
return NULL;
}
leafs[l]->occ = table[i];
}
}
- VERBOSE (DEBUG, PRINTF ("end initiliazing forest\n"));
+ VERBOSE (DEBUG, PRINTOUT ("end initiliazing forest\n"));
return leafs;
}
{
leaf_t *branch = NULL;
int nb_leafs = 0;
- int last, ante;
+ int last = -1;
+ int ante;
int i, j;
- VERBOSE (DEBUG, PRINTF ("start creating tree\n"));
+ VERBOSE (DEBUG, PRINTOUT ("start creating tree\n"));
/* count number of leafs */
while (leafs[nb_leafs] != NULL) {
/* create branch */
if ((last == -1) || (ante == -1)) {
- VERBOSE (ERROR, printf ("error during tree building\n"));
+ VERBOSE (ERROR, PRINTERR ("error during tree building\n"));
return NULL;
}
- branch = (leaf_t *) calloc (1, sizeof (leaf_t));
+ branch = getleaf (1);
if (branch == NULL) {
- VERBOSE (ERROR, printf ("can't allocate memory\n"));
+ VERBOSE (ERROR, PRINTERR ("can't allocate memory\n"));
return NULL;
}
branch->left = leafs[last];
leafs[ante] = NULL;
}
- VERBOSE (DEBUG, PRINTF ("end creating tree\n"));
-
- return leafs[last];
-}
-
-/* free tree */
+ VERBOSE (DEBUG, PRINTOUT ("end creating tree\n"));
-void free_tree (leaf_t *root) {
- if (root) {
- if (root->left) {
- free_tree (root->left);
- }
- if (root->right) {
- free_tree (root->right);
- }
- free (root);
- }
+ return (last != -1) ? leafs[last] : NULL;
}
-/* code structure */
-
-typedef struct {
- char code[NB_CHARS - 1 + 1];
-} code_t;
-
/* explore tree */
void explore_tree (code_t *table, leaf_t *root, char *code, int index)
{
+
+ VERBOSE (DEBUG, PRINTOUT ("start exploring code tree\n"));
+
if ((root->left == NULL) && (root->right == NULL)) {
- strcpy ((char *)(table + (int)(root->c)), code);
+ codcpy ((char *)(table + (int)(root->c)), sizeof (code_t), code);
}
else {
- strcpy (code + index, "1");
+ codcpy (code + index, sizeof (code_t), "1");
explore_tree (table, root->left, code, index + 1);
- strcpy (code + index, "0");
+ codcpy (code + index, sizeof (code_t), "0");
explore_tree (table, root->right, code, index + 1);
}
+
+ VERBOSE (DEBUG, PRINTOUT ("end exploring code tree\n"));
}
/* create code table */
-
code_t *create_code (leaf_t *root)
{
- code_t *table = NULL;
+ static code_t table[NB_BYTES] = {0};
code_t code = {0};
- VERBOSE (DEBUG, PRINTF ("start creating code table\n"));
-
- /* allocate table */
- table = (code_t *) calloc (NB_CHARS, sizeof (code_t));
- if (table == NULL) {
- VERBOSE (ERROR, printf ("can't allocate memory\n"));
- return NULL;
- }
+ VERBOSE (DEBUG, PRINTOUT ("start creating code table\n"));
explore_tree (table, root, (char *)&code, 0);
- VERBOSE (DEBUG, PRINTF ("end creating code table\n"));
+ VERBOSE (DEBUG, PRINTOUT ("end creating code table\n"));
return table;
}
char *code;
int i;
- printf ("Code table\n");
- for (i = 0; i < NB_CHARS; i++) {
+ PRINTOUT ("Code table\n");
+ for (i = 0; i < NB_BYTES; i++) {
code = (char *)(codes + i);
- if (strlen (code) == 0) {
+ if (codlen (code) == 0) {
continue;
}
- printf ("0x%02x '%c': %s\n", i, ((i < 32) || (i > 127)) ? '.' : i, code);
+ PRINTOUT ("0x%02x '%c': %s\n", i, ((i < 32) || (i > 127)) ? '.' : i, code);
}
}
/* encode header and code table */
-char *encode_header_table (code_t *codes, int *occ)
+byte_t *encode_header_table (code_t *codes, int *occ)
{
- unsigned char buffer[NB_CHARS * (NB_CHARS - 1) / 2 / 8 + NB_CHARS + 2] = {0};
- char bits[(NB_CHARS - 1) + 8 + 1] = {0};
+ static byte_t buffer[NB_BYTES * (NB_BYTES - 1) / 2 / 8 + NB_BYTES + 6] = {0};
+ char bits[(NB_BYTES - 1) + 8 + 1] = {0};
char *code;
- unsigned char *header = buffer;
+ byte_t *header = buffer;
int i, j, length, mode;
int nb = 0;
int size = 0;
- VERBOSE (DEBUG, PRINTF ("start encoding header and code table\n"));
+ VERBOSE (DEBUG, PRINTOUT ("start encoding header and code table\n"));
/* mode 1 or 2 */
- for (i = 0; i < NB_CHARS; i++) {
+ for (i = 0; i < NB_BYTES; i++) {
code = (char *)(codes + i);
- if (strlen (code) > 0) {
+ if (codlen (code) > 0) {
nb++;
- size += strlen (code) * occ[i];
+ size += codlen (code) * occ[i];
}
}
- mode = (NB_CHARS < 2 * nb + 1) ? 1 : 2;
- VERBOSE (DEBUG, PRINTF ("nb chars: %d\n", nb));
- VERBOSE (DEBUG, PRINTF ("mode: %d\n", mode));
- VERBOSE (DEBUG, PRINTF ("size: %d\n", size));
+ mode = (NB_BYTES < 2 * nb + 1) ? 1 : 2;
+ VERBOSE (DEBUG, PRINTOUT ("nb chars: %d\n", nb));
+ VERBOSE (DEBUG, PRINTOUT ("mode: %d\n", mode));
+ VERBOSE (DEBUG, PRINTOUT ("size: %d\n", size));
+ VERBOSE (DEBUG, PRINTOUT ("rem: %d\n", size % 256));
/* header */
- strcpy ((char *)header, (mode == 1) ? "MZ1 " : "MZ2 ");
+ codcpy ((char *)header, sizeof (buffer), (mode == 1) ? "M1Z " : "M2Z ");
header += 6;
/* size */
switch (mode) {
case 1:
- for (i = 0; i < NB_CHARS; i++) {
+ for (i = 0; i < NB_BYTES; i++) {
code = (char *)(codes + i);
- *(header++) = (unsigned char) strlen (code);
+ *(header++) = (byte_t) codlen (code);
}
break;
case 2:
- *(header++) = (unsigned char)(nb - 1);
- for (i = 0; i < NB_CHARS; i++) {
+ *(header++) = (byte_t)(nb - 1);
+ for (i = 0; i < NB_BYTES; i++) {
code = (char *)(codes + i);
- if (strlen (code) > 0) {
- *(header++) = (unsigned char)i;
- *(header++) = (unsigned char) strlen (code);
+ if (codlen (code) > 0) {
+ *(header++) = (byte_t) i;
+ *(header++) = (byte_t) codlen (code);
}
}
break;
}
/* bits */
- for (i = 0; i < NB_CHARS; i++) {
+ for (i = 0; i < NB_BYTES; i++) {
code = (char *)(codes + i);
- if (strlen (code) > 0) {
- strcat (bits, code);
- while (strlen (bits) > (8 - 1)) {
+ if (codlen (code) > 0) {
+ codcat (bits, sizeof (code_t), code);
+ while (codlen (bits) > (8 - 1)) {
for (j = 0; j < 8; j++) {
*header <<= 1;
if (bits[j] == '1') {
(*header)++;
}
}
- strcpy (bits, bits + 8);
+ codcpy (bits, sizeof (code_t), bits + 8);
header++;
}
}
}
- if (strlen (bits) > 0) {
- for (j = 0; j < (int)strlen (bits); j++) {
+ if (codlen (bits) > 0) {
+ for (j = 0; j < (int)codlen (bits); j++) {
*header <<= 1;
if (bits[j] == '1') {
(*header)++;
}
}
+ for (j = (int)codlen (bits); j < 8; j++) {
+ *header <<= 1;
+ }
header++;
}
/* length */
length = (int)(header - buffer - 6);
- VERBOSE (DEBUG, PRINTF ("lengh: %d %02x %02x\n", length, length >> 8, length & 0xff));
- buffer[3] = (unsigned char)(length >> 8);
- buffer[4] = (unsigned char)(length & 0xff);
- buffer[5] = (unsigned char)(size % 8);
+ VERBOSE (DEBUG, PRINTOUT ("lengh: %d %02x %02x\n", length, length >> 8, length & 0xff));
+ buffer[3] = (byte_t)(length >> 8);
+ buffer[4] = (byte_t)(length & 0xff);
+ buffer[5] = (byte_t)(size % 256);
+ header = buffer;
- /* allocation */
- header = (unsigned char *) calloc (length + 6, 1);
- memcpy (header, buffer, length + 6);
+ VERBOSE (DEBUG, PRINTOUT ("end encoding header and code table\n"));
- VERBOSE (DEBUG, PRINTF ("end encoding header and code table\n"));
-
- return (char *)header;
+ return header;
}
/* print header */
-void print_header (char *header)
+void print_header (byte_t *header)
{
int length, i;
- length = ((unsigned char)(header[3]) << 8) + (unsigned char)(header[4]);
- VERBOSE (DEBUG, PRINTF ("lengh: %d\n", length));
+ length = (header[3] << 8) + header[4];
+ VERBOSE (DEBUG, PRINTOUT ("lengh: %d\n", length));
for (i = 0; i < length + 6; i++) {
- printf ("%02x", (unsigned char)header[i]);
+ PRINTOUT ("%02x", header[i]);
}
- printf ("\n");
+ PRINTOUT ("\n");
}
/* write crompressed file */
-int write_compress (char *output, char *input, code_t *codes, char *header)
+int write_compress (char *output, char *input, code_t *codes, byte_t *header)
{
- char bufin[BUFFER_SIZE] = {0};
- char bufout[BUFFER_SIZE] = {0};
- char bits[(NB_CHARS - 1) + 8 + 1] = {0};
- FILE *fin, *fout;
+ byte_t bufin[BUFFER_SIZE] = {0};
+ byte_t bufout[BUFFER_SIZE] = {0};
+ char bits[(NB_BYTES - 1) + 8 + 1] = {0};
+ int fin, fout;
int length = 0;
- int i, j, nbread;
- char *pt;
+ int i, j, nbread, nbwrite;
+ byte_t *pt;
- VERBOSE (DEBUG, PRINTF ("start writting compressed file\n"));
+ VERBOSE (DEBUG, PRINTOUT ("start writting compressed file\n"));
/* open input file */
- fin = fopen (input, "rb");
- if (fin == NULL) {
- VERBOSE (ERROR, printf ("can't open file '%s'\n", input));
+ fin = open (input, O_RDONLY|O_RAW);
+ if (fin == -1) {
+ VERBOSE (ERROR, PRINTERR ("can't open file '%s' for reading\n", input));
return 1;
}
- VERBOSE (INFO, printf ("file '%s' opened\n", input));
+ VERBOSE (INFO, PRINTOUT ("file '%s' opened\n", input));
/* open output file */
- fout = fopen (output, "wb");
- if (fin == NULL) {
- VERBOSE (ERROR, printf ("can't open file '%s'\n", output));
+ fout = open (output, O_WRONLY|O_CREAT|O_RAW, 0700);
+ if (fout == -1) {
+ VERBOSE (ERROR, PRINTERR ("can't open file '%s' for writing\n", output));
+ close (fin);
return 1;
}
- VERBOSE (INFO, printf ("file '%s' opened\n", output));
+ VERBOSE (INFO, PRINTOUT ("file '%s' opened\n", output));
/* write header */
- length = ((unsigned char)(header[3]) << 8) + (unsigned char)(header[4]);
- VERBOSE (DEBUG, PRINTF ("lengh: %d\n", length));
- fwrite (header, 1, length + 6, fout);
+ length = (header[3] << 8) + header[4];
+ VERBOSE (DEBUG, PRINTOUT ("lengh: %d\n", length));
+ nbwrite = write (fout, header, length + 6);
+ if (nbwrite != length + 6) {
+ VERBOSE (ERROR, PRINTERR ("can't write %d bytes in file '%s'\n", length + 6 - nbwrite, output));
+ close (fout);
+ close (fin);
+ return 1;
+ }
+
/* write file */
pt = bufout;
- while (!feof (fin)) {
- nbread = fread (bufin, 1, BUFFER_SIZE, fin);
- VERBOSE (DEBUG, PRINTF ("nbread: %d\n", nbread));
+ while ((nbread = read (fin, bufin, BUFFER_SIZE)) > 0) {
+ VERBOSE (DEBUG, PRINTOUT ("nbread: %d\n", nbread));
for (i = 0; i < nbread; i++) {
- strcat (bits, (char *)(codes + bufin[i]));
- while (strlen (bits) > (8 - 1)) {
+ codcat (bits, sizeof (code_t), (char *)(codes + bufin[i]));
+ while (codlen (bits) > (8 - 1)) {
for (j = 0; j < 8; j++) {
*pt <<= 1;
if (bits[j] == '1') {
(*pt)++;
}
}
- strcpy (bits, bits + 8);
- if (pt - bufout < BUFFER_SIZE) {
- pt++;
- } else {
- fwrite (bufout, 1, BUFFER_SIZE, fout);
+ codcpy (bits, sizeof (code_t), bits + 8);
+ if (pt - bufout == BUFFER_SIZE - 1) {
+ nbwrite = write (fout, bufout, BUFFER_SIZE);
+ if (nbwrite != BUFFER_SIZE) {
+ VERBOSE (ERROR, PRINTERR ("can't write %d bytes in file '%s'\n", BUFFER_SIZE - nbwrite, output));
+ close (fout);
+ close (fin);
+ return 1;
+ }
pt = bufout;
+ } else {
+ pt++;
}
}
}
}
- if (strlen (bits) > 0) {
- for (j = 0; j < (int)strlen (bits); j++) {
+ VERBOSE (DEBUG, PRINTOUT ("lastest bits : %d\n", codlen (bits)));
+ if (codlen (bits) > 0) {
+ for (j = 0; j < (int)codlen (bits); j++) {
*pt <<= 1;
if (bits[j] == '1') {
(*pt)++;
}
}
- if (pt - bufout < BUFFER_SIZE) {
- pt++;
- } else {
- fwrite (bufout, 1, BUFFER_SIZE, fout);
- pt = bufout;
+ for (j = (int)codlen (bits); j < 8; j++) {
+ *pt <<= 1;
}
pt++;
}
if (pt != bufout) {
- fwrite (bufout, 1, pt - bufout, fout);
+ VERBOSE (DEBUG, PRINTOUT ("last partial buffer written: %u\n", pt - bufout));
+ nbwrite = write (fout, bufout, pt - bufout);
+ if (nbwrite != pt - bufout) {
+ VERBOSE (ERROR, PRINTERR ("can't write %d bytes in file '%s'\n", pt - bufout - nbwrite, output));
+ close (fout);
+ close (fin);
+ return 1;
+ }
}
/* closing */
- fclose (fin);
- fclose (fout);
+ close (fin);
+ close (fout);
+
+ VERBOSE (DEBUG, PRINTOUT ("end writting compressed file\n"));
+
+ return 0;
+}
+
+/* read header */
+
+code_t *read_header (char *filename) {
+ static code_t table[NB_BYTES] = {0};
+ byte_t buffer[NB_BYTES * (NB_BYTES - 1) / 2 / 8 + NB_BYTES + 6] = {0};
+ byte_t *codes = NULL;
+ byte_t cur;
+ int lengths[NB_BYTES] = {0};
+ int fid;
+ int mode = 0;
+ int i, j, l, nb, size;
+
+ VERBOSE (DEBUG, PRINTOUT ("start reading header\n"));
+
+ /* open file */
+ fid = open (filename, O_RDONLY|O_RAW);
+ if (fid == -1) {
+ VERBOSE (ERROR, PRINTERR ("can't open file '%s'\n", filename));
+ return NULL;
+ }
+ VERBOSE (INFO, PRINTOUT ("file '%s' opened\n", filename));
+
+ /* read magic number */
+ nb = read (fid, buffer, 6);
+ VERBOSE (DEBUG, PRINTOUT ("nb, buffer: %d 0x%02x 0x%02x\n", nb, buffer[0], buffer[1]));
+ if ((nb == 6) && (buffer[0] == 'M') && (buffer[2] == 'Z')) {
+ mode = (buffer[1] == '1') ? 1 : (buffer[1] == '2') ? 2 : 0;
+ size = (buffer[3] << 8) + buffer[4];
+ VERBOSE (DEBUG, PRINTOUT ("mode, size: %d %d\n", mode, size));
+ if (size > NB_BYTES * (NB_BYTES - 1) / 2 / 8 + NB_BYTES) {
+ mode = 0;
+ } else {
+ nb = read (fid, buffer, size);
+ VERBOSE (DEBUG, PRINTOUT ("nb read: %d/%d\n", nb, size));
+ if (nb != size) {
+ mode = 0;
+ }
+ }
+ }
+ close (fid);
+ if (mode == 0) {
+ VERBOSE (ERROR, PRINTERR ("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, PRINTOUT ("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]) PRINTOUT ("%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, PRINTERR ("incorrect code table length: %d %d %d\n", size, nb, l));
+ 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, PRINTOUT ("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};
+ int fin, fout;
+ int i, j, k, nb, size, nbwrite, rem;
+ int is_found;
+ int l = 0;
+ byte_t *pt;
+
+ VERBOSE (DEBUG, PRINTOUT ("start writing decompressed file\n"));
+
+ /* open file for reading */
+ fin = open (input, O_RDONLY|O_RAW);
+ if (fin == -1) {
+ VERBOSE (ERROR, PRINTERR ("can't open file '%s' for reading\n", input));
+ return 1;
+ }
+ VERBOSE (INFO, PRINTOUT ("file '%s' opened\n", input));
- VERBOSE (DEBUG, PRINTF ("end writting compressed file\n"));
+ /* read magic number */
+ nb = read (fin, bufhea, 6);
+ if (nb != 6) {
+ VERBOSE (ERROR, PRINTERR ("can't read file\n"));
+ close (fin);
+ return 1;
+ }
+ size = (bufhea[3] << 8) + bufhea[4];
+ VERBOSE (DEBUG, PRINTOUT ("table size: %d\n", size));
+ rem = bufhea[5];
+ VERBOSE (DEBUG, PRINTOUT ("remainder: %d\n", rem));
+ nb = read (fin, bufhea, size);
+ if (nb != size) {
+ VERBOSE (ERROR, PRINTERR ("can't read file\n"));
+ close (fin);
+ return 1;
+ }
+
+ /* open file for writing */
+ fout = open (output, O_WRONLY|O_CREAT|O_RAW, 0700);
+ if (fout == -1) {
+ VERBOSE (ERROR, PRINTERR ("can't open file '%s' for writing\n", output));
+ close (fin);
+ return 1;
+ }
+ VERBOSE (INFO, PRINTOUT ("file '%s' opened\n", output));
+
+ /* write file */
+ pt = bufout;
+ while ((nb = read (fin, bufin, BUFFER_SIZE)) > 0) {
+ VERBOSE (DEBUG, PRINTOUT ("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, PRINTOUT ("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, PRINTOUT ("found: %d\n", k));
+ *pt= k;
+ bits[0] = 0;
+ if (pt - bufout == BUFFER_SIZE - 1) {
+ VERBOSE (DEBUG, PRINTOUT ("nb buffer out: %u\n", (pt - bufout)));
+ nbwrite = write (fout, bufout, BUFFER_SIZE);
+ if (nbwrite != BUFFER_SIZE) {
+ VERBOSE (ERROR, PRINTERR ("can't write %d bytes in file '%s'\n'", BUFFER_SIZE - nbwrite, output));
+ close (fout);
+ close (fin);
+ return 1;
+ }
+ pt = bufout;
+ } else {
+ pt++;
+ }
+ }
+ }
+ if ((i == nb - 1) && (l % 256 == rem) && (nb != BUFFER_SIZE)) {
+ VERBOSE (DEBUG, PRINTOUT ("break\n"));
+ break;
+ }
+ }
+ }
+ }
+ if (pt != bufout) {
+ VERBOSE (DEBUG, PRINTOUT ("nb buffer out: %u\n", (pt - bufout)));
+ nbwrite = write (fout, bufout, pt - bufout);
+ if (nbwrite != pt - bufout) {
+ VERBOSE (ERROR, PRINTERR ("can't write %d bytes in file '%s'\n'", pt - bufout - nbwrite, output));
+ close (fout);
+ close (fin);
+ return 1;
+ }
+ }
+
+ /* close files */
+ close (fin);
+ close (fout);
+
+ VERBOSE (DEBUG, PRINTOUT ("end writing decompressed file\n"));
return 0;
}
leaf_t **leafs = NULL;
leaf_t *root = NULL;
code_t *codes = NULL;
- char *header = NULL;
+ byte_t *header = NULL;
int mode = COMPRESS;
- int rc = 0;
+ int rc = 1;
progname = argv[0];
int c;
- VERBOSE (DEBUG, PRINTF ("start argument processing\n"));
- while ((c = getopt(argc, argv, "cdhi:o:v:")) != EOF) {
+ char * arg;
+ VERBOSE (DEBUG, PRINTOUT ("start processing arguments\n"));
+ while (argc-- > 1) {
+ arg = *(++argv);
+ if (arg[0] != '-') {
+ PRINTERR ("%s: invalid option -- %s\n", progname, arg);
+ return usage (1);
+ }
+ c = arg[1];
+ VERBOSE (DEBUG, PRINTOUT ("option: %c\n", c));
switch (c) {
case 'c':
mode = COMPRESS;
mode = DECOMPRESS;
break;
case 'i':
- VERBOSE (DEBUG, PRINTF ("-i\n"));
- VERBOSE (DEBUG, PRINTF ("optarg: %s\n", optarg));
- input = optarg;
+ input = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL;
+ VERBOSE (DEBUG, PRINTOUT ("input: %s\n", input));
break;
case 'o':
- VERBOSE (DEBUG, PRINTF ("-o\n"));
- output = optarg;
+ output = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL;
+ VERBOSE (DEBUG, PRINTOUT ("output: %s\n", output));
break;
case 'v':
- VERBOSE (DEBUG, PRINTF ("-v\n"));
- verbose = atoi (optarg);
- VERBOSE (INFO, printf ("verbose: %d\n", verbose));
+ arg = (arg[2]) ? arg + 2 : (--argc > 0 ) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ PRINTERR ("%s: missing verbose level\n", progname);
+ return usage (1);
+ }
+ verbose = atoi (arg);
+ VERBOSE (INFO, PRINTOUT ("verbose: %d\n", verbose));
break;
case 'h':
default:
- usage (c != 'h');
+ return usage (c != 'h');
}
}
- if (argc - optind != 0) {
- fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]);
- usage (1);
+ if ((input == NULL) || (output == NULL)) {
+ PRINTERR ("%s: missing file\n", progname);
+ return usage (1);
}
- VERBOSE (DEBUG, PRINTF ("end argument processing\n"));
+ VERBOSE (DEBUG, PRINTOUT ("end processing arguments\n"));
switch (mode) {
case COMPRESS:
rc = write_compress (output, input, codes, header);
break;
case DECOMPRESS:
- rc = 1;
+ codes = read_header (input);
+ if (codes == NULL) break;
+ VERBOSE (INFO, print_code_table (codes));
+ rc = write_decompress (output, input, codes);
break;
}
- /* clean everything */
- if (header) free (header);
- if (codes) free (codes);
- if (root) free_tree (root);
- if (leafs) free (leafs);
- if (table) free (table);
-
return rc;
}
// test: compress.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
// test: compress.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
// test: compress.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
-
-// vim: ts=4 sw=4 et
+// test: compress.exe -v 2>&1 | grep -q 'missing verbose level'
+// test: compress.exe -c -i compress.c 2>&1 | grep -q 'missing file'
+// test: compress.exe -c -v 4 -i compress.c -o compress.mz | grep -q "Occurence table"
+// test: compress.exe -c -i compress.c -o compress.mz
+// test: ls -sS1 compress.c compress.mz | tail -1 | grep -q compress.mz
+// test: compress.exe -d -i compress.mz -o tmp.c
+// test: cmp compress.c tmp.c; x=$?; rm compress.mz tmp.c; test x$x = x0
+// test: compress.exe -c -i test/compress.c -o compress.mz 2>&1 | grep -q "can't open file"
+// test: compress.exe -c -i compress.c -o test/compress.mz 2>&1 | grep -q "can't open file"
+
+/* vim: set ts=4 sw=4 et: */