#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <assert.h>
#define X(shift) (1 << (shift)) static int test_mask[32] = { X(0x00), X(0x01), X(0x02), X(0x03), X(0x04), X(0x05), X(0x06), X(0x07), X(0x08), X(0x09), X(0x0a), X(0x0b), X(0x0c), X(0x0d), X(0x0e), X(0x0f), X(0x10), X(0x11), X(0x12), X(0x13), X(0x14), X(0x15), X(0x16), X(0x17), X(0x18), X(0x19), X(0x1a), X(0x1b), X(0x1c), X(0x1d), X(0x1e), X(0x1f), };
struct lzwc_ctx { size_t lc_bpp; size_t lc_bitcnt; size_t lc_dicode; size_t lc_testbl[4096 * 256 / sizeof(size_t) / 8]; size_t lc_dictbl[4096 * 256];
size_t lc_outcnt; char lc_outbuff[8192 + 4];
size_t lc_outbit_cnt; uint32_t lc_outbit_buff; };
inline void lzwc_restart(struct lzwc_ctx * ctxp) { ctxp->lc_dicode = (1 << ctxp->lc_bpp) + 2; ctxp->lc_bitcnt = (ctxp->lc_bpp + 1); if (ctxp->lc_dicode >= (1 << ctxp->lc_bitcnt)) ctxp->lc_bitcnt++; memset(ctxp->lc_testbl, 0, sizeof(ctxp-> lc_testbl)); }
inline void lzwc_init(struct lzwc_ctx * ctxp, int bpp) { memset(ctxp, 0, sizeof(struct lzwc_ctx)); ctxp->lc_bpp = bpp; lzwc_restart(ctxp); }
inline int lzwc_find(struct lzwc_ctx * ctxp, int prefix, int code) { int key = (prefix << 8) | code; assert (code < (1 << ctxp->lc_bpp)); if (ctxp->lc_testbl[key >> 5] & test_mask[key & 0x1F]) return ctxp->lc_dictbl[key]; return -1; }
inline int lzwc_update(struct lzwc_ctx * ctxp, int prefix, int code) { int key = (prefix << 8) | code; ctxp->lc_testbl[key >> 5] |= test_mask[key & 0x1F]; ctxp->lc_dictbl[key] = ctxp->lc_dicode++; return ctxp->lc_dicode; }
void lzwc_output(struct lzwc_ctx * ctxp, size_t code, FILE *fp) { size_t mask = (1 << ctxp->lc_bitcnt) - 1;
ctxp->lc_outbit_buff |= ((code & mask) << ctxp->lc_outbit_cnt); ctxp->lc_outbit_cnt += ctxp->lc_bitcnt;
while (ctxp->lc_outbit_cnt >= 8) { char outch = (ctxp->lc_outbit_buff & 0xFF); ctxp->lc_outbuff[ctxp->lc_outcnt++] = outch; ctxp->lc_outbit_buff >>= 8; ctxp->lc_outbit_cnt -= 8; } if (ctxp->lc_outcnt >= 8192) { fwrite(ctxp->lc_outbuff, 1, ctxp->lc_outcnt, fp); ctxp->lc_outcnt = 0; } if (mask < ctxp->lc_dicode) { ++ctxp->lc_bitcnt; } }
void lzwc_clear(struct lzwc_ctx * ctxp, FILE * fp) { int clear = (1 << ctxp->lc_bpp); lzwc_output(ctxp, clear, fp); }
void lzwc_finish(struct lzwc_ctx * ctxp, size_t code, FILE *fp) { int fin_code = (1 << ctxp->lc_bpp) + 1; lzwc_output(ctxp, code, fp); lzwc_output(ctxp, fin_code, fp); lzwc_output(ctxp, 0, fp); fwrite(ctxp->lc_outbuff, 1, ctxp->lc_outcnt, fp); ctxp->lc_outcnt = 0; }
int main(int argc, char *argv[]) { int prefix = -1; int i, j, count; uint8_t buffer[8192];
struct lzwc_ctx * ctxp = NULL; ctxp = (struct lzwc_ctx *) malloc( sizeof(struct lzwc_ctx) ); assert (ctxp != NULL); lzwc_init(ctxp, 8);
FILE *fout = fopen("output.lzw", "wb"); lzwc_clear(ctxp, fout);
for (i = 1; i < argc; i++) { FILE *fp = fopen(argv[i], "rb");
if (fp == NULL) continue;
while ( !feof(fp) ) { count = fread(buffer, 1, sizeof(buffer), fp); for (j = 0; j < count; j++) { int code = buffer[j]; if (prefix == -1) { prefix = code; continue; } int prefix1 = lzwc_find(ctxp, prefix, code); if (prefix1 != -1) { assert(prefix1 <= ctxp->lc_dicode); prefix = prefix1; continue; } lzwc_output(ctxp, prefix, fout); if (lzwc_update(ctxp, prefix, code) < 4096) { prefix = code; continue; } lzwc_clear(ctxp, fout); prefix = code; lzwc_restart(ctxp); } } fclose(fp); } lzwc_finish(ctxp, prefix, fout); free(ctxp); fclose(fout); return 0; }
|