Skip to content

Instantly share code, notes, and snippets.

@countingpine
Created February 21, 2019 13:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save countingpine/602453d330ea055a4bcab90ca2a7ed02 to your computer and use it in GitHub Desktop.
Save countingpine/602453d330ea055a4bcab90ca2a7ed02 to your computer and use it in GitHub Desktop.
Simple, uncompressed DEFLATE compressor
#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