/* * Copyright (c) 2004 * Kevin Atkinson * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation. Kevin Atkinson makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * */ /* * Format: * ::= 0x02 + 0x1F 0xFF * ::= * * ::= 0x00..0x1D | 0x1E 0xFF* 0x00..0xFE * ::= 0x20..0xFF | * ::= 0x1F 0x20..0x3F * * To decompress: * Take the first PREFIX_LEN characters from the previous line * and concatenate that with the rest, unescaping as necessary. * The PREFIX_LEN is the sum of the characters in . * To unescape take the second character of and subtract 0x20. * If the prefix length is computed before unescaping characters. */ #include #include #include #include #if defined(__CYGWIN__) || defined (_WIN32) # include # include # define SETBIN(fno) _setmode( _fileno( fno ), _O_BINARY ) #else # define SETBIN(fno) #endif #define HEAD "prezip, a prefix delta compressor. Version 0.1, 2004-04-23" typedef struct Word { char * str; size_t alloc; } Word; #define INSURE_SPACE(cur,p,need)\ do {\ size_t pos = p - (cur)->str;\ if (pos + need + 1 < (cur)->alloc) break;\ (cur)->alloc = (cur)->alloc*3/2;\ (cur)->str = (char *)realloc((cur)->str, (cur)->alloc);\ p = (cur)->str + pos;\ } while (0) #define ADV(w, c) do {char * s = w + c;\ while(w != s) {\ if (*w == 0) ret = 3;\ ++w;}} while (0) int main (int argc, const char *argv[]) { if (argc < 2) { goto usage; } else if (strcmp(argv[1], "-z") == 0) { Word w1,w2; Word * prev = &w1; Word * cur = &w2; char * w = 0; char * p = 0; int c,l; char CRtest1stLine = 0; /* Test 1st line of word-list for CR */ char CRremoveAll = 0; /* Remove All CR if 1st line has CR */ w1.str = (char *)malloc(256); w1.alloc = 256; w2.str = (char *)malloc(256); w2.alloc = 256; SETBIN (stdout); putc(2, stdout); c = 0; while (c != EOF) { /* get next word */ w = cur->str; while (c = getc(stdin), c != EOF && c != '\n') { if (c >= 32) { INSURE_SPACE(cur, w, 1); *w++ = c; } else { INSURE_SPACE(cur, w, 2); *w++ = 31; *w++ = c + 32; } } /* Remove trailing Carriage Returns from input word-list */ if (c != EOF) { if (CRtest1stLine) { /* Expect all following lines to include/exclude CR */ if (CRremoveAll && *(w - 1) == 45 && *(w - 2) == 31) { --w; --w; } } else { /* Autosense 1st line for Carriage Return */ if (*(w - 1) == 45 && *(w - 2) == 31) { /* 1st line has CR, so all lines must have CR */ CRremoveAll = 1; --w; --w; } CRtest1stLine = 1; } } *w = 0; p = prev->str; w = cur->str; /* get the length of the prefix */ l = 0; while (p[l] != '\0' && p[l] == w[l]) ++l; /* prefix compress, and write word */ if (l < 30) { putc(l, stdout); } else { int i = l - 30; putc(30, stdout); while (i >= 255) {putc(255, stdout); i -= 255;} putc(i, stdout); } fputs(w+l, stdout); /* swap prev and next */ { Word * tmp = cur; cur = prev; prev = tmp; } } putc(31, stdout); putc(255, stdout); fflush(stdout); free(w1.str); free(w2.str); } else if (strcmp(argv[1], "-d") == 0) { int ret = 0; Word cur; int c; char * w; unsigned char ch; cur.str = (char *)malloc(256); cur.alloc = 256; w = cur.str; SETBIN (stdin); c = getc(stdin); if (c == 2) { while (c != EOF && ret <= 0) { ret = -1; if (c != 2) {ret = 3; break;} c = getc(stdin); while (ret < 0) { w = cur.str; ADV(w, c); if (c == 30) { while (c = getc(stdin), c == 255) ADV(w, 255); ADV(w, c); } while (c = getc(stdin), c > 30) { INSURE_SPACE(&cur,w,1); *w++ = (char)c; } *w = '\0'; for (w = cur.str; *w; w++) { if (*w != 31) { putc(*w, stdout); } else { ++w; ch = *w; if (32 <= ch && ch < 64) { putc(ch - 32, stdout); } else if (ch == 255) { if (w[1] != '\0') ret = 3; else ret = 0; } else { ret = 3; } } } if (ret < 0 && c == EOF) ret = 4; if (ret != 0) putc('\n', stdout); } } } else if (c == 1) { while (c != -1) { if (c == 0) c = getc(stdin); --c; w = cur.str + c; while (c = getc(stdin), c > 32) { INSURE_SPACE(&cur,w,1); *w++ = (char)c; } *w = '\0'; fputs(cur.str, stdout); putc('\n', stdout); } } else { ret = 2; } assert(ret >= 0); if (ret > 0 && argc > 2) fputs(argv[2], stderr); if (ret == 2) fputs("unknown format\n", stderr); else if (ret == 3) fputs("corrupt input\n", stderr); else if (ret == 4) fputs("unexpected EOF\n", stderr); free (cur.str); return ret; } else if (strcmp(argv[1], "-v") == 0) { printf("%s\n", HEAD); } else { goto usage; } return 0; usage: printf("%s\n" "Usage:\n" " To Compress: %s -z\n" " To Decompress: %s -d\n", HEAD, argv[0], argv[0]); return 1; }