/* * version 1.5 2001-06-26 * slightly more robust * "compression" levels * '-I' for decode * '-n' option * ident strings can not contain whitespace * version 1.4 2001-06-24 * version 1.3 1999-09-12 * version 1.2 1995-03-01 * version 1.1 1995-05-30 * version 1.0 1994-12-13 * * remember to transfer files with * Content-Encoding: 8bit * Content-Transfer-Encoding: 8bit * * this is written in ISO-C89 * + getopt (e.g. -D_POSIX_C_SOURCE=2) * * basex -v -i "id" output * basex -d -I -v output * * -V show version * -d decode * -v verbose * -i use identifier id * -I print id to stderr on decryption * -n do NOT create output * -1 VERY conservative * -5 rather conservative (almost rfc2822) * -7 non-rfc2822, but should work (default) * -9 maximum level (not that much better) * * ESCAPE -> ESCAPE 'A' * 0x00 -> ESCAPE 'B' * 0x0a -> ESCAPE 'C' * 0x0d -> ESCAPE 'D' * ESCAPE x, x != A-D unchanged * * uses adler32 checksum */ /* next include is for getopt only */ #include #include #include #include #define MAXLINE (60000+3) #define ESCAPE 0xff #define MAXBLK 5000000L /* max. blksize on decode */ #define ID1 "BASEX ENCODED DATA" /* file header */ #define ID2 "X" /* control header */ #define ID3 '|' /* data header */ char version[] = "basex version 1.5 - 2001-06-26"; typedef unsigned long u32; /* 4 byte unsigned int */ typedef unsigned char u8; /* 1 byte unsigned int */ int verbose = 0; int showident = 0; int complevel = 7; int nooutput = 0; int linelen; int blklen; extern char *optarg; /*extern int optind, opterr, optopt; */ u32 adler32 (u8 * data, int len) { u32 s1 = 1; u32 s2 = 0; u32 modulo = 65521; while (--len) { s1 += *data++; if (s1 >= modulo) s1 -= modulo; s2 += s1; if (s2 >= modulo) s2 -= modulo; }; return (s2 << 16) + s1; } void out_char (FILE * o, int code) { static char line[MAXLINE + 1]; static int llen = 0; if (code == -2) { if (llen) { line[llen] = 0; if (!nooutput) fprintf (o, "%c%s\n", ID3, line); } } else if (code == -1) { llen = 0; } else { line[llen++] = code; if (llen >= linelen) { llen = 0; line[linelen] = 0; if (!nooutput) fprintf (o, "%c%s\n", ID3, line); } } } int encode (FILE * i, FILE * o, char *id) { u8 *block; long blklen; int len; if (complevel <= 1) { linelen = 120; blklen = 50000; } else if (complevel <= 5) { linelen = 996; blklen = 50000; } else if (complevel <= 7) { linelen = 7996; blklen = 50000; } else { linelen = 60000; blklen = 5000000; } block = malloc (blklen); if (!block) { fprintf (stderr, "unable to allocate %ld bytes", blklen * 2); return 11; } if (!nooutput) { fprintf (o, "%s\n", ID1); fprintf (o, "%s VERSION 2\n", ID2); if (id) fprintf (o, "%s IDENT %s\n", ID2, id); } /*fprintf (o, "%s CODEC AFE0C0DE\n", ID2);*/ /* default */ while ((len = fread (block, 1, blklen, i)) > 0) { u32 sum = adler32 (block, len); u8 *p = block; if (!nooutput) fprintf (o, "%s BLOCK %d %08lx\n", ID2, len, sum); out_char (o, -1); while (len--) { int c = *p++ ^ (u8) sum++; if (c == ESCAPE) { out_char (o, ESCAPE); if (len) { switch (*p ^ (u8) sum) { case 'A': case 'B': case 'C': case 'D': out_char (o, 'A'); break; default: /* nothing */; } } else out_char (o, 'A'); } else if (c == 0x00) { out_char (o, ESCAPE); out_char (o, 'B'); } else if (c == 0x0a) { out_char (o, ESCAPE); out_char (o, 'C'); } else if (c == 0x0d) { out_char (o, ESCAPE); out_char (o, 'D'); } else { out_char (o, c); } } out_char (o, -2); } if (!nooutput) fprintf (o, "%s END\n", ID2); free (block); return 0; } int in_char (FILE * i, int code) { static int llen; static char line[MAXLINE + 3]; if (code == -1) { llen = MAXLINE + 1; return 0; } else { if (llen > MAXLINE || line[llen] == 0 || line[llen] == '\r' || line[llen] == '\n') { do { if (!fgets (line, sizeof (line), i)) { perror ("error on block read (file truncated?)"); return -1; } } while (line[0] != ID3); llen = 1; } return (unsigned char) line[llen++]; } } int decodeblock (FILE * i, u8 * data, int len, int sum) { int ch; (void) in_char (i, -1); while (len--) { ch = in_char (i, 0); if (ch < 0) return 8; retry: if (ch == ESCAPE) { switch ((ch = in_char (i, 0))) { case 'A': ch = ESCAPE; break; case 'B': ch = 0x00; break; case 'C': ch = 0x0a; break; case 'D': ch = 0x0d; break; default: *data++ = (u8) ESCAPE ^ (u8) sum++; len--; goto retry; } } *data++ = (u8) ch ^ (u8) sum++; } return 0; } int decode (FILE * i, FILE * o) { char input[255]; char *opt = input + sizeof (ID2) - 1 + 1; long blklen; int err; u32 sum, sum2; u32 codec = 0xafe1c0de; int version = 0; char ident[255]; ident[0] = 0; do { if (!fgets (input, sizeof (input), i)) { perror ("unable to find start of encoded data"); return 1; } } while (strncmp (input, ID1, sizeof (ID1) - 1)); if (verbose) fprintf (stderr, "basex header found, processing options\n"); for (;;) { if (!fgets (input, sizeof (input), i)) { perror ("error while processing options"); return 2; } if (strncmp (input, ID2, sizeof (ID2) - 1) || *(opt - 1) != ' ') { fprintf (stderr, "garbage instead of option, ignored\n"); } else { if (sscanf (opt, "VERSION %d\n", &version) == 1) { if (verbose) fprintf (stderr, "option version %d\n", version); if (version != 2) { fprintf (stderr, "unsupported version %d\n", version); return 5; } } else if (sscanf (opt, "CODEC %8lx\n", &codec) == 1) { if (verbose) fprintf (stderr, "option codec %lx\n", codec); } else if (sscanf (opt, "IDENT %[^\n]\n", ident) == 1) { if (verbose || showident) fprintf (stderr, "option ident %s\n", ident); } else if (strcmp (opt, "END\n") == 0) { if (verbose) fprintf (stderr, "option end\n"); return 0; } else if (sscanf (opt, "BLOCK %ld %08lx\n", &blklen, &sum) == 2) { u8 *block; if (verbose) fprintf (stderr, "option block len %ld, checksum %08lx\n", blklen, sum); if (blklen > MAXBLK) { fprintf (stderr, "block length too large (%ld>%ld)\n", blklen, MAXBLK); return 4; } switch (codec) { case 0xafe1c0de: block = malloc (blklen); if (!block) { fprintf (stderr, "unable to allocate %ld bytes", blklen); return 11; } err = decodeblock (i, block, blklen, sum); if (err) return err; sum2 = adler32 (block, blklen); if (sum != sum2) { fprintf (stderr, "checksumming error %08lx != %08lx\n", sum, sum2); return 9; } if (!nooutput && fwrite (block, blklen, 1, o) <= 0) { perror ("write error"); return 10; } free (block); break; default: fprintf (stderr, "unknown codec %08lx\n", codec); return 3; } } else { fprintf (stderr, "unknown or unrecognized option %s\n", opt); return 2; } } } } int main (int argc, char *argv[]) { int dec = 0; char *id = 0; for (;;) { int c = getopt (argc, argv, "Vvdi:In123456789"); if (c == EOF) break; switch (c) { case 'V': puts (version); exit (EXIT_SUCCESS); break; case 'v': verbose = 1; break; case 'd': dec = 1; break; case 'i': id = optarg; break; case 'I': showident = 1; break; case 'n': nooutput = 1; break; case '1': case '2': case '3': case '4': complevel = 1; break; case '5': case '6': complevel = 5; break; case '7': case '8': complevel = 7; break; case '9': complevel = 9; break; case '?': fprintf (stderr, "encode: basex [-v] [-n] [-i id] [-1 | -5 | -7 | -9]\n"); fprintf (stderr, "decode: basex [-d] [-v] [-n] [-I]\n"); break; } } if (verbose) fprintf (stderr, "mode %s\n", dec ? "decoding" : "encoding"); if (dec) return decode (stdin, stdout); else return encode (stdin, stdout, id); }