1 /***********************************************************
2 encode.c -- sliding dictionary with percolating update
3 ***********************************************************/
6 #include <string.h> /* memmove() */
11 #define HASH(p, c) ((p) + 2 * DICSIZ + ((c) << (DICBIT - 9)))
12 #define MAX_HASH_VAL HASH(DICSIZ + UCHAR_MAX, UCHAR_MAX)
16 static uchar *text, *childcount;
17 static node pos, avail, *position, *parent, *prev, *next = NULL;
20 #if MAXMATCH <= (UCHAR_MAX + 1)
26 extern struct lha_opts opts;
38 text = malloc(DICSIZ * 2 + MAXMATCH);
39 level = malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*level));
40 childcount = malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*childcount));
42 position = malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*position));
44 position = malloc(DICSIZ * sizeof(*position));
46 parent = malloc(DICSIZ * 2 * sizeof(*parent));
47 prev = malloc(DICSIZ * 2 * sizeof(*prev));
48 next = malloc((MAX_HASH_VAL + 1) * sizeof(*next));
50 error("Out of memory.");
58 for (i = DICSIZ; i <= DICSIZ + UCHAR_MAX; i++) {
61 position[i] = NIL; /* sentinel */
64 for (i = DICSIZ; i < DICSIZ * 2; i++)
67 for (i = 1; i < DICSIZ - 1; i++)
69 next[DICSIZ - 1] = NIL;
70 for (i = DICSIZ * 2; i <= MAX_HASH_VAL; i++)
75 child(node q, uchar c)
76 /* q's child for character c (NIL if not found) */
81 parent[NIL] = q; /* sentinel */
82 while (parent[r] != q)
88 makechild(node q, uchar c, node r)
89 /* Let r be q's child for character c. */
121 replace_node(node old, node new)
125 /* replace old into new */
134 parent[new] = parent[old];
138 split(struct match_t *match, node old)
146 replace_node(old, new);
148 level[new] = match->len;
151 /* new child -> old */
152 makechild(new, text[match->pos + match->len], old);
155 makechild(new, text[pos + match->len], pos);
159 insert_node(struct match_t *match)
164 if (match->len >= 4) {
166 r = (match->pos + 1) | DICSIZ;
167 while ((q = parent[r]) == NIL)
169 while (level[q] >= match->len) {
175 while (position[t] < 0) {
180 position[t] = pos | PERC_FLAG;
190 q = text[pos] + DICSIZ;
192 if ((r = child(q, c)) == NIL) {
193 makechild(q, c, pos);
200 /* found match->len */
201 /* scan match->pos candidate r */
209 match->pos = position[r] & ~PERC_FLAG; /* 0x8000U */
211 if (match->pos >= pos)
212 match->pos -= DICSIZ;
213 t1 = &text[pos + match->len];
214 t2 = &text[match->pos + match->len];
215 while (match->len < j) {
224 if (match->len >= MAXMATCH)
228 if ((r = child(q, *t1)) == NIL) {
229 makechild(q, *t1, pos);
234 /* replace r into pos */
235 replace_node(r, pos);
238 next[r] = pos; /* special use of next[] */
242 delete_node_1(node s)
261 if (parent[pos] == NIL)
269 if (r >= DICSIZ || --childcount[r] > 1)
272 t = position[r] & ~PERC_FLAG;
281 while ((u = position[q]) & PERC_FLAG) {
287 position[q] = (s | DICSIZ);
295 position[q] = s | DICSIZ | PERC_FLAG;
298 s = child(r, text[t + level[r]]);
310 get_next_match(struct match_t *match)
315 if (++pos == DICSIZ * 2) {
316 memmove(&text[0], &text[DICSIZ], DICSIZ + MAXMATCH);
317 n = fread_crc(&text[DICSIZ + MAXMATCH], DICSIZ, infile);
320 if (outfile != stdout && opts.quiet < 1) {
331 struct match_t match, lastmatch;
335 huf_encode_start(opts.method);
336 remainder = fread_crc(&text[DICSIZ], DICSIZ + MAXMATCH, infile);
338 if (outfile != stdout && opts.quiet < 1) {
344 if (match.len > remainder)
345 match.len = remainder;
346 while (remainder > 0 && !unpackable) {
348 get_next_match(&match);
349 if (match.len > remainder)
350 match.len = remainder;
351 if (match.len > lastmatch.len || lastmatch.len < THRESHOLD)
352 output(text[pos - 1], 0);
354 output(lastmatch.len + (UCHAR_MAX + 1 - THRESHOLD),
355 (pos - lastmatch.pos - 2) & (DICSIZ - 1));
356 while (--lastmatch.len > 0)
357 get_next_match(&match);
358 if (match.len > remainder)
359 match.len = remainder;