flate

deflate implementation
git clone git://git.suckless.org/flate
Log | Files | Refs | README

commit f03a6f1d3efa723e6af183b54c76fc37a9c2cf4c
parent 7e14ecf2e5698d7c6e25e8f0bda8987afc25065c
Author: nsz <nszabolcs@gmail.com>
Date:   Mon, 24 Aug 2009 08:44:52 +0200

sflate += pkzip stream
Diffstat:
sflate.c | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 145 insertions(+), 21 deletions(-)

diff --git a/sflate.c b/sflate.c @@ -3,6 +3,28 @@ #include <string.h> #include "flate.h" +static void set32(uchar *p, uint n) { + p[0] = n >> 24; + p[1] = n >> 16; + p[2] = n >> 8; + p[3] = n; +} + +static void set32le(uchar *p, uint n) { + p[0] = n; + p[1] = n >> 8; + p[2] = n >> 16; + p[3] = n >> 24; +} + +static int check32(uchar *p, uint n) { + return n == ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +} + +static int check32le(uchar *p, uint n) { + return n == (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +} + enum { ZlibCM = 7 << 4, ZlibCINFO = 8, @@ -22,10 +44,7 @@ int deflate_zlib_header(uchar *p, int n) { int deflate_zlib_footer(uchar *p, int n, uint sum, uint len, uint zlen) { if (n < 4) return FlateErr; - p[0] = sum >> 24; - p[1] = sum >> 16; - p[2] = sum >> 8; - p[3] = sum; + set32(p, sum); return 4; } @@ -42,8 +61,7 @@ int inflate_zlib_header(uchar *p, int n) { } int inflate_zlib_footer(uchar *p, int n, uint sum, uint len, uint zlen) { - if (n < 4 || - sum != ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])) + if (n < 4 || !check32(p, sum)) return FlateErr; return 4; } @@ -62,12 +80,9 @@ enum { }; int deflate_gzip_header(uchar *p, int n) { - int k; - if (n < 10) return FlateErr; - for (k = 0; k < n; k++) - p[k] = 0; + memset(p, 0, 10); p[0] = GZipID1; p[1] = GZipID2; p[2] = GZipCM; @@ -79,14 +94,8 @@ int deflate_gzip_header(uchar *p, int n) { int deflate_gzip_footer(uchar *p, int n, uint sum, uint len, uint zlen) { if (n < 8) return FlateErr; - p[0] = sum; - p[1] = sum >> 8; - p[2] = sum >> 16; - p[3] = sum >> 24; - p[4] = len; - p[5] = len >> 8; - p[6] = len >> 16; - p[7] = len >> 24; + set32le(p, sum); + set32le(p+4, len); return 8; } @@ -127,14 +136,118 @@ int inflate_gzip_header(uchar *p, int n) { } int inflate_gzip_footer(uchar *p, int n, uint sum, uint len, uint zlen) { - if (n < 8 || - sum != (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)) || - len != (p[4] | (p[5] << 8) | (p[6] << 16) | (p[7] << 24))) + if (n < 8 || !check32le(p, sum) || !check32le(p+4, len)) return FlateErr; return 8; } +static char pkname[] = "sflate_stream"; + +enum { + PKHeadID = 0x04034b50, + PKDataID = 0x08074b50, + PKDirID = 0x02014b50, + PKFootID = 0x06054b50, + PKVersion = 20, + PKFlag = 1 << 3, + PKMethod = 8, + PKDate = (2009 - 1980) << 25, + PKHeadSize = 30, + PKDirSize = 46, + PKNameLen = sizeof(pkname) - 1 +}; + +int deflate_pkzip_header(uchar *p, int n) { + if (n < PKHeadSize + PKNameLen) + return FlateErr; + memset(p, 0, PKHeadSize); + set32le(p, PKHeadID); + set32le(p+4, PKVersion); + set32le(p+6, PKFlag); + set32le(p+8, PKMethod); + set32le(p+10, PKDate); + set32le(p+26, PKNameLen); + memcpy(p + PKHeadSize, pkname, PKNameLen); + return PKHeadSize + PKNameLen; +} + +int deflate_pkzip_footer(uchar *p, int n, uint sum, uint len, uint zlen) { + if (n < PKDirSize + PKNameLen + 22) + return FlateErr; +/* if (n < 16 + PKDirSize + PKNameLen + 22) + return FlateErr; + set32le(p, PKDataID); + set32le(p+4, sum); + set32le(p+8, zlen); + set32le(p+12, len); + p += 16; +*/ + memset(p, 0, PKDirSize); + set32le(p, PKDirID); + set32le(p+4, PKVersion | (PKVersion << 16)); + set32le(p+8, PKFlag); + set32le(p+10, PKMethod); + set32le(p+12, PKDate); + set32le(p+16, sum); + set32le(p+20, zlen); + set32le(p+24, len); + set32le(p+28, PKNameLen); + memcpy(p + PKDirSize, pkname, PKNameLen); + p += PKDirSize + PKNameLen; + memset(p, 0, 22); + set32le(p, PKFootID); + p[8] = p[10] = 1; + set32le(p+12, PKDirSize + PKNameLen); + set32le(p+16, zlen + PKHeadSize + PKNameLen); + return PKDirSize + PKNameLen + 22; +/* set32le(p+12, 16 + PKDirSize + PKNameLen); + set32le(p+16, zlen + PKHeadSize + PKNameLen); + return 16 + PKDirSize + PKNameLen + 22; +*/ +} + +int inflate_pkzip_header(uchar *p, int n) { + int k = 30; + + if (k > n) + return FlateErr; + if (!check32le(p, PKHeadID)) + return FlateErr; + if ((p[4] | (p[5] << 8)) > PKVersion) + return FlateErr; + if ((p[8] | (p[9] << 8)) != PKMethod) + return FlateErr; + k += p[26] | (p[27] << 8); + k += p[28] | (p[29] << 8); + if (k > n) + return FlateErr; + return k; +} + +int inflate_pkzip_footer(uchar *p, int n, uint sum, uint len, uint zlen) { + int k = PKDirSize + 22; + + if (k > n) + return FlateErr; + if (check32le(p, PKDataID)) { + p += 16; + k += 16; + if (k > n) + return FlateErr; + } + if (!check32le(p, PKDirID)) + return FlateErr; + if (!check32le(p+16, sum)) + return FlateErr; + if (!check32le(p+20, zlen)) + return FlateErr; + if (!check32le(p+24, len)) + return FlateErr; + return k; +} + + /* example usage */ static int (*header)(uchar *, int); @@ -343,6 +456,17 @@ int main(int argc, char *argv[]) { n = call(stdin, stdout); break; case 'p': + if (comp == 'c') { + header = deflate_pkzip_header; + footer = deflate_pkzip_footer; + } else { + header = inflate_pkzip_header; + footer = inflate_pkzip_footer; + } + checksum = crc32; + crc32init(); + n = call(stdin, stdout); + break; default: err = "uninplemented."; n = FlateErr;