|
|
9953f6 |
|
|
|
9953f6 |
#include "arch.h"
|
|
|
9953f6 |
|
|
|
9953f6 |
#include <assert.h></assert.h>
|
|
|
9953f6 |
#include <stdlib.h></stdlib.h>
|
|
|
9953f6 |
#include <string.h></string.h>
|
|
|
576e4a |
//#include <stdio.h></stdio.h>
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
enum {
|
|
|
9953f6 |
NO_CODE = 0xffff,
|
|
|
9953f6 |
DICT_SIZE = 0xffff };
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
int arch_init(Arch *a) {
|
|
|
9953f6 |
memset(a, 0, sizeof(*a));
|
|
|
576e4a |
a->entries = (Entry*)calloc(sizeof(Entry), DICT_SIZE);
|
|
|
9953f6 |
if (!a->entries) return RES_FAIL;
|
|
|
9953f6 |
for(int i = 0; i < 256; ++i) {
|
|
|
9953f6 |
Entry *e = a->entries + i;
|
|
|
9953f6 |
memset(e->children, 0xff, sizeof(e->children));
|
|
|
9953f6 |
e->value = i;
|
|
|
9953f6 |
a->root.children[i] = i;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
a->nextcode = 0x100;
|
|
|
9953f6 |
a->codebits = 9;
|
|
|
9953f6 |
return RES_DONE;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
void arch_deinit(Arch *a) {
|
|
|
9953f6 |
free(a->entries);
|
|
|
9953f6 |
memset(a, 0, sizeof(*a));
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
576e4a |
static void arch_entry_use(Arch *a, Entry *e) {
|
|
|
576e4a |
if (!e->parent) return;
|
|
|
576e4a |
if (e->next) {
|
|
|
576e4a |
if (e->prev) e->prev->next = e->next;
|
|
|
576e4a |
else a->first = e->next;
|
|
|
576e4a |
e->next->prev = e->prev;
|
|
|
576e4a |
e->prev = a->last;
|
|
|
576e4a |
e->next = NULL;
|
|
|
576e4a |
a->last = a->last->next = e;
|
|
|
576e4a |
}
|
|
|
576e4a |
arch_entry_use(a, e->parent);
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
static Entry* arch_entry_add(Arch *a, Entry *parent, Byte value) {
|
|
|
9953f6 |
Entry *e;
|
|
|
9953f6 |
Code nextcode = a->nextcode;
|
|
|
9953f6 |
if (nextcode < DICT_SIZE) {
|
|
|
9953f6 |
++a->nextcode;
|
|
|
9953f6 |
if (!(nextcode & a->nextcode)) ++a->codebits;
|
|
|
9953f6 |
assert(a->codebits <= 16);
|
|
|
576e4a |
assert(nextcode < DICT_SIZE);
|
|
|
576e4a |
e = a->entries + nextcode;
|
|
|
9953f6 |
memset(e->children, 0xff, sizeof(e->children));
|
|
|
576e4a |
e->prev = a->last; e->next = NULL;
|
|
|
576e4a |
if (a->last) a->last->next = e;
|
|
|
576e4a |
else a->first = e;
|
|
|
576e4a |
a->last = e;
|
|
|
9953f6 |
} else {
|
|
|
576e4a |
arch_entry_use(a, parent);
|
|
|
576e4a |
|
|
|
9953f6 |
e = a->first;
|
|
|
9953f6 |
assert(e);
|
|
|
576e4a |
assert(e != parent);
|
|
|
9953f6 |
assert(e->parent);
|
|
|
9953f6 |
assert(e->parent->children[e->value] == e - a->entries);
|
|
|
9953f6 |
e->parent->children[e->value] = NO_CODE;
|
|
|
576e4a |
|
|
|
576e4a |
//assert(!e->prev);
|
|
|
576e4a |
//assert(e->next);
|
|
|
576e4a |
//a->first = e->next; e->prev = a->last;
|
|
|
576e4a |
//e->next = e->next->prev = NULL;
|
|
|
576e4a |
//a->last = a->last->next = e;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
assert(parent);
|
|
|
9953f6 |
assert(parent->children[value] == NO_CODE);
|
|
|
576e4a |
e->value = value;
|
|
|
9953f6 |
e->parent = parent;
|
|
|
9953f6 |
parent->children[value] = e - a->entries;
|
|
|
576e4a |
//printf("add code: %d\n", (int)(e - a->entries));
|
|
|
576e4a |
//for(int i = 0; i < 256; ++i) assert(e->children[i] == NO_CODE);
|
|
|
9953f6 |
|
|
|
576e4a |
arch_entry_use(a, e);
|
|
|
9953f6 |
return e;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
int arch_deflate(Arch *a, int final) {
|
|
|
9953f6 |
if (a->rb.bits) return RES_FAIL;
|
|
|
9953f6 |
while(1) {
|
|
|
576e4a |
if (a->wb.end - a->wb.cur < 5) return RES_RETRY;
|
|
|
9953f6 |
Entry *e = &a->root;
|
|
|
9953f6 |
Byte *bp = a->rb.cur;
|
|
|
576e4a |
Bits codebits = a->codebits;
|
|
|
9953f6 |
while(1) {
|
|
|
9953f6 |
Byte b;
|
|
|
9953f6 |
if (!buf_read_byte(&a->rb, &b)) {
|
|
|
576e4a |
if (final) { arch_entry_use(a, e); break; }
|
|
|
9953f6 |
a->rb.cur = bp;
|
|
|
9953f6 |
break;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
if (e->children[b] == NO_CODE) { e = arch_entry_add(a, e, b); break; }
|
|
|
576e4a |
e = a->entries + e->children[b];
|
|
|
9953f6 |
}
|
|
|
9953f6 |
if (bp == a->rb.cur) break;
|
|
|
9953f6 |
|
|
|
9953f6 |
assert(e);
|
|
|
9953f6 |
assert(e != &a->root);
|
|
|
576e4a |
|
|
|
576e4a |
Code code; Byte b = e->value;
|
|
|
576e4a |
if (e->parent) { code = e->parent - a->entries; }
|
|
|
576e4a |
else { code = a->nextcode; assert(final); }
|
|
|
576e4a |
//printf("pos: %d/%d, code %d/%d, byte %d (%c)\n", (int)(a->rb.cur - a->rb.begin), (int)(a->rb.end - a->rb.begin), (int)code, (int)a->nextcode, (int)b, (char)b);
|
|
|
576e4a |
if ( !buf_write_bits(&a->wb, (((Word)code) << 8) | b, codebits + 8) ) return RES_FAIL;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
if (final && a->rb.cur >= a->rb.end) { buf_write_pad(&a->wb); return RES_DONE; }
|
|
|
9953f6 |
return RES_RETRY;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
static int arch_entry_write(Arch *a, Entry *e, TinySize count) {
|
|
|
9953f6 |
if (!e->parent) {
|
|
|
9953f6 |
if (a->wb.end - a->wb.cur < count) return 0;
|
|
|
9953f6 |
} else {
|
|
|
9953f6 |
if (!arch_entry_write(a, e->parent, count+1)) return 0;
|
|
|
9953f6 |
}
|
|
|
576e4a |
//fputc(e->value, stdout);
|
|
|
9953f6 |
buf_write_byte(&a->wb, e->value);
|
|
|
9953f6 |
return 1;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
|
|
|
9953f6 |
int arch_inflate(Arch *a, int final) {
|
|
|
9953f6 |
if (a->wb.bits) return RES_FAIL;
|
|
|
9953f6 |
while(1) {
|
|
|
9953f6 |
Byte *bp = a->rb.cur;
|
|
|
9953f6 |
Bits bb = a->rb.bits;
|
|
|
9953f6 |
|
|
|
576e4a |
Word w;
|
|
|
576e4a |
if (!buf_read_bits(&a->rb, &w, a->codebits + 8)) break;
|
|
|
576e4a |
Code code = w >> 8;
|
|
|
576e4a |
Byte b = w;
|
|
|
9953f6 |
|
|
|
576e4a |
//printf("pos: %d/%d + %d, code %d/%d, byte %d (%c)\n", (int)(a->rb.cur - a->rb.begin), (int)(a->rb.end - a->rb.begin), (int)a->rb.bits, (int)code, (int)a->nextcode, (int)b, (char)b);
|
|
|
576e4a |
if (code < a->nextcode) {
|
|
|
576e4a |
Entry *e = &a->entries[code];
|
|
|
576e4a |
if (!arch_entry_write(a, e, 1)) {
|
|
|
576e4a |
a->rb.cur = bp;
|
|
|
576e4a |
a->rb.bits = bb;
|
|
|
576e4a |
return RES_RETRY;
|
|
|
576e4a |
}
|
|
|
576e4a |
//fputc(b, stdout); fputc('\n', stdout);
|
|
|
576e4a |
if (e->children[b] == NO_CODE) e = arch_entry_add(a, e, b); else arch_entry_use(a, e);
|
|
|
576e4a |
} else
|
|
|
576e4a |
if (code != a->nextcode) {
|
|
|
576e4a |
return RES_FAIL;
|
|
|
576e4a |
} else {
|
|
|
576e4a |
//printf("pos: %d/%d + %d, code %d/%d, byte %d (%c)\n", (int)(a->rb.cur - a->rb.begin), (int)(a->rb.end - a->rb.begin), (int)a->rb.bits, (int)code, (int)a->nextcode, (int)b, (char)b);
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
576e4a |
if (!buf_write_byte(&a->wb, b)) return RES_FAIL;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|
|
|
9953f6 |
if (final) { buf_read_pad(&a->rb); return RES_DONE; }
|
|
|
9953f6 |
return RES_RETRY;
|
|
|
9953f6 |
}
|
|
|
9953f6 |
|