Created
February 21, 2019 13:45
-
-
Save countingpine/602453d330ea055a4bcab90ca2a7ed02 to your computer and use it in GitHub Desktop.
Simple, uncompressed DEFLATE compressor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
/* block size must be 65535 or less */ | |
#define MAX_BLOCK_SIZE 65535 | |
#define START 1 | |
#define FINISH 2 | |
#define writebyte(c) do {if (outleft) {*out++ = (c); outleft--;} else return 1;} while (0) | |
#define writeword_le(w) do {writebyte((w) & 255); writebyte(((w) >> 8) & 255);} while (0) | |
#define writeword_be(w) do {writebyte(((w) >> 8) & 255); writebyte((w) & 255);} while (0) | |
#define writedword_be(d) do {writeword_be(((d) >> 16) & 65535); writeword_be((d) & 65535);} while (0) | |
int simple_deflate(uint8_t *out, unsigned *outlen_p, uint8_t const *in, unsigned inlen, uint32_t *adler32, unsigned flags) { | |
unsigned outleft = *outlen_p; | |
unsigned adl1, adl2; | |
unsigned i; | |
if (adler32) { | |
if (flags & START) *adler32 = 0x00000001; | |
adl1 = *adler32 & 0xffff; | |
adl2 = *adler32 >> 16; | |
for (i = 0; i < inlen; i++) { | |
adl1 += in[i]; adl2 += adl1; | |
adl1 %= 65521; adl2 %= 65521; | |
} | |
*adler32 = adl1 | adl2 << 16; | |
} | |
if (flags & START) { | |
/* a valid, ASCII-compatible DEFLATE header */ | |
writebyte('x'); | |
writebyte('^'); | |
} | |
while (inlen > MAX_BLOCK_SIZE) { | |
/* not last block; uncompressed */ | |
writebyte(0); | |
/* block length */ | |
writeword_le(MAX_BLOCK_SIZE); | |
writeword_le(~MAX_BLOCK_SIZE); | |
for (i = 0; i < MAX_BLOCK_SIZE; i++) { | |
writebyte(*in++); | |
inlen--; | |
} | |
} | |
if (inlen > 0 || (flags & FINISH)) { | |
/* last block?; uncompressed */ | |
writebyte(!!(flags & FINISH)); | |
/* block length */ | |
writeword_le(inlen); | |
writeword_le(~inlen); | |
while (inlen) { | |
writebyte(*in++); | |
inlen--; | |
} | |
} | |
if (adler32 && (flags & FINISH)) { | |
/* Adler32 checksum footer */ | |
writedword_be(*adler32); | |
} | |
*outlen_p -= outleft; | |
return 0; | |
} | |
#define READ_BLOCK_SIZE (MAX_BLOCK_SIZE * 2) | |
#include <stdio.h> | |
int main(int arg_c, char **arg_v) { | |
uint8_t inbuf[READ_BLOCK_SIZE], outbuf[2 + READ_BLOCK_SIZE + 4 * (READ_BLOCK_SIZE / MAX_BLOCK_SIZE + 1) + 4]; | |
unsigned inlen, outlen; | |
unsigned flags = START; | |
uint32_t adler32; | |
if (arg_c < 3) return 1; | |
FILE *infile = fopen(arg_v[1], "rb"); if (!infile) return 2; | |
FILE *outfile = fopen(arg_v[2], "wb"); if (!outfile) {fclose(infile); return 3;} | |
while (!feof(infile)) { | |
inlen = fread(inbuf, 1, READ_BLOCK_SIZE, infile); | |
outlen = sizeof(outbuf); | |
if (feof(infile)) | |
flags |= FINISH; | |
if (simple_deflate(outbuf, &outlen, inbuf, inlen, &adler32, flags)) { fclose(infile); fclose(outfile); return -1; } | |
flags &= ~START; | |
fwrite(outbuf, 1, outlen, outfile); | |
} | |
fclose(infile); | |
fclose(outfile); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment