📄 sshzlib.c
字号:
return 0; tab = *ztab; for (code = 0; code <= tab->mask; code++) if (tab->table[code].nexttable != NULL) zlib_freetable(&tab->table[code].nexttable); sfree(tab->table); tab->table = NULL; sfree(tab); *ztab = NULL; return (0);}struct zlib_decompress_ctx { struct zlib_table *staticlentable, *staticdisttable; struct zlib_table *currlentable, *currdisttable, *lenlentable; enum { START, OUTSIDEBLK, TREES_HDR, TREES_LENLEN, TREES_LEN, TREES_LENREP, INBLK, GOTLENSYM, GOTLEN, GOTDISTSYM, UNCOMP_LEN, UNCOMP_NLEN, UNCOMP_DATA } state; int sym, hlit, hdist, hclen, lenptr, lenextrabits, lenaddon, len, lenrep; int uncomplen; unsigned char lenlen[19]; unsigned char lengths[286 + 32]; unsigned long bits; int nbits; unsigned char window[WINSIZE]; int winpos; unsigned char *outblk; int outlen, outsize;};void *zlib_decompress_init(void){ struct zlib_decompress_ctx *dctx = snew(struct zlib_decompress_ctx); unsigned char lengths[288]; memset(lengths, 8, 144); memset(lengths + 144, 9, 256 - 144); memset(lengths + 256, 7, 280 - 256); memset(lengths + 280, 8, 288 - 280); dctx->staticlentable = zlib_mktable(lengths, 288); memset(lengths, 5, 32); dctx->staticdisttable = zlib_mktable(lengths, 32); dctx->state = START; /* even before header */ dctx->currlentable = dctx->currdisttable = dctx->lenlentable = NULL; dctx->bits = 0; dctx->nbits = 0; dctx->winpos = 0; return dctx;}void zlib_decompress_cleanup(void *handle){ struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle; if (dctx->currlentable && dctx->currlentable != dctx->staticlentable) zlib_freetable(&dctx->currlentable); if (dctx->currdisttable && dctx->currdisttable != dctx->staticdisttable) zlib_freetable(&dctx->currdisttable); if (dctx->lenlentable) zlib_freetable(&dctx->lenlentable); zlib_freetable(&dctx->staticlentable); zlib_freetable(&dctx->staticdisttable); sfree(dctx);}static int zlib_huflookup(unsigned long *bitsp, int *nbitsp, struct zlib_table *tab){ unsigned long bits = *bitsp; int nbits = *nbitsp; while (1) { struct zlib_tableentry *ent; ent = &tab->table[bits & tab->mask]; if (ent->nbits > nbits) return -1; /* not enough data */ bits >>= ent->nbits; nbits -= ent->nbits; if (ent->code == -1) tab = ent->nexttable; else { *bitsp = bits; *nbitsp = nbits; return ent->code; } if (!tab) { /* * There was a missing entry in the table, presumably * due to an invalid Huffman table description, and the * subsequent data has attempted to use the missing * entry. Return a decoding failure. */ return -2; } }}static void zlib_emit_char(struct zlib_decompress_ctx *dctx, int c){ dctx->window[dctx->winpos] = c; dctx->winpos = (dctx->winpos + 1) & (WINSIZE - 1); if (dctx->outlen >= dctx->outsize) { dctx->outsize = dctx->outlen + 512; dctx->outblk = sresize(dctx->outblk, dctx->outsize, unsigned char); } dctx->outblk[dctx->outlen++] = c;}#define EATBITS(n) ( dctx->nbits -= (n), dctx->bits >>= (n) )int zlib_decompress_block(void *handle, unsigned char *block, int len, unsigned char **outblock, int *outlen){ struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle; const coderecord *rec; int code, blktype, rep, dist, nlen, header; static const unsigned char lenlenmap[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; dctx->outblk = snewn(256, unsigned char); dctx->outsize = 256; dctx->outlen = 0; while (len > 0 || dctx->nbits > 0) { while (dctx->nbits < 24 && len > 0) { dctx->bits |= (*block++) << dctx->nbits; dctx->nbits += 8; len--; } switch (dctx->state) { case START: /* Expect 16-bit zlib header. */ if (dctx->nbits < 16) goto finished; /* done all we can */ /* * The header is stored as a big-endian 16-bit integer, * in contrast to the general little-endian policy in * the rest of the format :-( */ header = (((dctx->bits & 0xFF00) >> 8) | ((dctx->bits & 0x00FF) << 8)); EATBITS(16); /* * Check the header: * * - bits 8-11 should be 1000 (Deflate/RFC1951) * - bits 12-15 should be at most 0111 (window size) * - bit 5 should be zero (no dictionary present) * - we don't care about bits 6-7 (compression rate) * - bits 0-4 should be set up to make the whole thing * a multiple of 31 (checksum). */ if ((header & 0x0F00) != 0x0800 || (header & 0xF000) > 0x7000 || (header & 0x0020) != 0x0000 || (header % 31) != 0) goto decode_error; dctx->state = OUTSIDEBLK; break; case OUTSIDEBLK: /* Expect 3-bit block header. */ if (dctx->nbits < 3) goto finished; /* done all we can */ EATBITS(1); blktype = dctx->bits & 3; EATBITS(2); if (blktype == 0) { int to_eat = dctx->nbits & 7; dctx->state = UNCOMP_LEN; EATBITS(to_eat); /* align to byte boundary */ } else if (blktype == 1) { dctx->currlentable = dctx->staticlentable; dctx->currdisttable = dctx->staticdisttable; dctx->state = INBLK; } else if (blktype == 2) { dctx->state = TREES_HDR; } break; case TREES_HDR: /* * Dynamic block header. Five bits of HLIT, five of * HDIST, four of HCLEN. */ if (dctx->nbits < 5 + 5 + 4) goto finished; /* done all we can */ dctx->hlit = 257 + (dctx->bits & 31); EATBITS(5); dctx->hdist = 1 + (dctx->bits & 31); EATBITS(5); dctx->hclen = 4 + (dctx->bits & 15); EATBITS(4); dctx->lenptr = 0; dctx->state = TREES_LENLEN; memset(dctx->lenlen, 0, sizeof(dctx->lenlen)); break; case TREES_LENLEN: if (dctx->nbits < 3) goto finished; while (dctx->lenptr < dctx->hclen && dctx->nbits >= 3) { dctx->lenlen[lenlenmap[dctx->lenptr++]] = (unsigned char) (dctx->bits & 7); EATBITS(3); } if (dctx->lenptr == dctx->hclen) { dctx->lenlentable = zlib_mktable(dctx->lenlen, 19); dctx->state = TREES_LEN; dctx->lenptr = 0; } break; case TREES_LEN: if (dctx->lenptr >= dctx->hlit + dctx->hdist) { dctx->currlentable = zlib_mktable(dctx->lengths, dctx->hlit); dctx->currdisttable = zlib_mktable(dctx->lengths + dctx->hlit, dctx->hdist); zlib_freetable(&dctx->lenlentable); dctx->lenlentable = NULL; dctx->state = INBLK; break; } code = zlib_huflookup(&dctx->bits, &dctx->nbits, dctx->lenlentable); if (code == -1) goto finished; if (code == -2) goto decode_error; if (code < 16) dctx->lengths[dctx->lenptr++] = code; else { dctx->lenextrabits = (code == 16 ? 2 : code == 17 ? 3 : 7); dctx->lenaddon = (code == 18 ? 11 : 3); dctx->lenrep = (code == 16 && dctx->lenptr > 0 ? dctx->lengths[dctx->lenptr - 1] : 0); dctx->state = TREES_LENREP; } break; case TREES_LENREP: if (dctx->nbits < dctx->lenextrabits) goto finished; rep = dctx->lenaddon + (dctx->bits & ((1 << dctx->lenextrabits) - 1)); EATBITS(dctx->lenextrabits); while (rep > 0 && dctx->lenptr < dctx->hlit + dctx->hdist) { dctx->lengths[dctx->lenptr] = dctx->lenrep; dctx->lenptr++; rep--; } dctx->state = TREES_LEN; break; case INBLK: code = zlib_huflookup(&dctx->bits, &dctx->nbits, dctx->currlentable); if (code == -1) goto finished; if (code == -2) goto decode_error; if (code < 256) zlib_emit_char(dctx, code); else if (code == 256) { dctx->state = OUTSIDEBLK; if (dctx->currlentable != dctx->staticlentable) { zlib_freetable(&dctx->currlentable); dctx->currlentable = NULL; } if (dctx->currdisttable != dctx->staticdisttable) { zlib_freetable(&dctx->currdisttable); dctx->currdisttable = NULL; } } else if (code < 286) { /* static tree can give >285; ignore */ dctx->state = GOTLENSYM; dctx->sym = code; } break; case GOTLENSYM: rec = &lencodes[dctx->sym - 257]; if (dctx->nbits < rec->extrabits) goto finished; dctx->len = rec->min + (dctx->bits & ((1 << rec->extrabits) - 1)); EATBITS(rec->extrabits); dctx->state = GOTLEN; break; case GOTLEN: code = zlib_huflookup(&dctx->bits, &dctx->nbits, dctx->currdisttable); if (code == -1) goto finished; if (code == -2) goto decode_error; dctx->state = GOTDISTSYM; dctx->sym = code; break; case GOTDISTSYM: rec = &distcodes[dctx->sym]; if (dctx->nbits < rec->extrabits) goto finished; dist = rec->min + (dctx->bits & ((1 << rec->extrabits) - 1)); EATBITS(rec->extrabits); dctx->state = INBLK; while (dctx->len--) zlib_emit_char(dctx, dctx->window[(dctx->winpos - dist) & (WINSIZE - 1)]); break; case UNCOMP_LEN: /* * Uncompressed block. We expect to see a 16-bit LEN. */ if (dctx->nbits < 16) goto finished; dctx->uncomplen = dctx->bits & 0xFFFF; EATBITS(16); dctx->state = UNCOMP_NLEN; break; case UNCOMP_NLEN: /* * Uncompressed block. We expect to see a 16-bit NLEN, * which should be the one's complement of the previous * LEN. */ if (dctx->nbits < 16) goto finished; nlen = dctx->bits & 0xFFFF; EATBITS(16); if (dctx->uncomplen == 0) dctx->state = OUTSIDEBLK; /* block is empty */ else dctx->state = UNCOMP_DATA; break; case UNCOMP_DATA: if (dctx->nbits < 8) goto finished; zlib_emit_char(dctx, dctx->bits & 0xFF); EATBITS(8); if (--dctx->uncomplen == 0) dctx->state = OUTSIDEBLK; /* end of uncompressed block */ break; } } finished: *outblock = dctx->outblk; *outlen = dctx->outlen; return 1; decode_error: sfree(dctx->outblk); *outblock = dctx->outblk = NULL; *outlen = 0; return 0;}#ifdef ZLIB_STANDALONE#include <stdio.h>#include <string.h>int main(int argc, char **argv){ unsigned char buf[16], *outbuf; int ret, outlen; void *handle; int noheader = FALSE, opts = TRUE; char *filename = NULL; FILE *fp; while (--argc) { char *p = *++argv; if (p[0] == '-' && opts) { if (!strcmp(p, "-d")) noheader = TRUE; else if (!strcmp(p, "--")) opts = FALSE; /* next thing is filename */ else { fprintf(stderr, "unknown command line option '%s'\n", p); return 1; } } else if (!filename) { filename = p; } else { fprintf(stderr, "can only handle one filename\n"); return 1; } } handle = zlib_decompress_init(); if (noheader) { /* * Provide missing zlib header if -d was specified. */ zlib_decompress_block(handle, "\x78\x9C", 2, &outbuf, &outlen); assert(outlen == 0); } if (filename) fp = fopen(filename, "rb"); else fp = stdin; if (!fp) { assert(filename); fprintf(stderr, "unable to open '%s'\n", filename); return 1; } while (1) { ret = fread(buf, 1, sizeof(buf), fp); if (ret <= 0) break; zlib_decompress_block(handle, buf, ret, &outbuf, &outlen); if (outbuf) { if (outlen) fwrite(outbuf, 1, outlen, stdout); sfree(outbuf); } else { fprintf(stderr, "decoding error\n"); return 1; } } zlib_decompress_cleanup(handle); if (filename) fclose(fp); return 0;}#elseconst struct ssh_compress ssh_zlib = { "zlib", zlib_compress_init, zlib_compress_cleanup, zlib_compress_block, zlib_decompress_init, zlib_decompress_cleanup, zlib_decompress_block, zlib_disable_compression, "zlib (RFC1950)"};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -