diff options
Diffstat (limited to 'infcodes.c')
-rw-r--r-- | infcodes.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/infcodes.c b/infcodes.c new file mode 100644 index 0000000..ffae26d --- /dev/null +++ b/infcodes.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* infcodes.c -- process literals and length/distance pairs | ||
2 | * Copyright (C) 1995 Mark Adler | ||
3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
4 | */ | ||
5 | |||
6 | #include "zutil.h" | ||
7 | #include "inftrees.h" | ||
8 | #include "infutil.h" | ||
9 | #include "infcodes.h" | ||
10 | |||
11 | /* simplify the use of the inflate_huft type with some defines */ | ||
12 | #define base more.Base | ||
13 | #define next more.Next | ||
14 | #define exop word.what.Exop | ||
15 | #define bits word.what.Bits | ||
16 | |||
17 | /* inflate codes private state */ | ||
18 | struct inflate_codes_state { | ||
19 | |||
20 | /* mode */ | ||
21 | enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ | ||
22 | START, /* x: set up for LEN */ | ||
23 | LEN, /* i: get length/literal/eob next */ | ||
24 | LENEXT, /* i: getting length extra (have base) */ | ||
25 | DIST, /* i: get distance next */ | ||
26 | DISTEXT, /* i: getting distance extra */ | ||
27 | COPY, /* o: copying bytes in window, waiting for space */ | ||
28 | LIT, /* o: got literal, waiting for output space */ | ||
29 | WASH, /* o: got eob, possibly still output waiting */ | ||
30 | END, /* x: got eob and all data flushed */ | ||
31 | BAD} /* x: got error */ | ||
32 | mode; /* current inflate_codes mode */ | ||
33 | |||
34 | /* mode dependent information */ | ||
35 | uInt len; | ||
36 | union { | ||
37 | struct { | ||
38 | inflate_huft *tree; /* pointer into tree */ | ||
39 | uInt need; /* bits needed */ | ||
40 | } code; /* if LEN or DIST, where in tree */ | ||
41 | uInt lit; /* if LIT, literal */ | ||
42 | struct { | ||
43 | uInt get; /* bits to get for extra */ | ||
44 | uInt dist; /* distance back to copy from */ | ||
45 | } copy; /* if EXT or COPY, where and how much */ | ||
46 | } sub; /* submode */ | ||
47 | |||
48 | /* mode independent information */ | ||
49 | Byte lbits; /* ltree bits decoded per branch */ | ||
50 | Byte dbits; /* dtree bits decoder per branch */ | ||
51 | inflate_huft *ltree; /* literal/length/eob tree */ | ||
52 | inflate_huft *dtree; /* distance tree */ | ||
53 | |||
54 | }; | ||
55 | |||
56 | |||
57 | struct inflate_codes_state *inflate_codes_new(bl, bd, tl, td, z) | ||
58 | uInt bl, bd; | ||
59 | inflate_huft *tl, *td; | ||
60 | z_stream *z; | ||
61 | { | ||
62 | struct inflate_codes_state *c; | ||
63 | |||
64 | if ((c = (struct inflate_codes_state *) | ||
65 | ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) | ||
66 | { | ||
67 | c->mode = START; | ||
68 | c->lbits = (Byte)bl; | ||
69 | c->dbits = (Byte)bd; | ||
70 | c->ltree = tl; | ||
71 | c->dtree = td; | ||
72 | } | ||
73 | return c; | ||
74 | } | ||
75 | |||
76 | |||
77 | int inflate_codes(s, z, r) | ||
78 | struct inflate_blocks_state *s; | ||
79 | z_stream *z; | ||
80 | int r; | ||
81 | { | ||
82 | uInt j; /* temporary storage */ | ||
83 | inflate_huft *t; /* temporary pointer */ | ||
84 | int e; /* extra bits or operation */ | ||
85 | uLong b; /* bit buffer */ | ||
86 | uInt k; /* bits in bit buffer */ | ||
87 | Byte *p; /* input data pointer */ | ||
88 | uInt n; /* bytes available there */ | ||
89 | Byte *q; /* output window write pointer */ | ||
90 | uInt m; /* bytes to end of window or read pointer */ | ||
91 | Byte *f; /* pointer to copy strings from */ | ||
92 | struct inflate_codes_state *c = s->sub.codes; /* codes state */ | ||
93 | |||
94 | /* copy input/output information to locals (UPDATE macro restores) */ | ||
95 | LOAD | ||
96 | |||
97 | /* process input and output based on current state */ | ||
98 | while (1) switch (c->mode) | ||
99 | { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ | ||
100 | case START: /* x: set up for LEN */ | ||
101 | /* %%% check for avail in and out to do fast loop %%% */ | ||
102 | c->sub.code.need = c->lbits; | ||
103 | c->sub.code.tree = c->ltree; | ||
104 | c->mode = LEN; | ||
105 | case LEN: /* i: get length/literal/eob next */ | ||
106 | j = c->sub.code.need; | ||
107 | NEEDBITS(j) | ||
108 | t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); | ||
109 | DUMPBITS(t->bits) | ||
110 | if ((e = (int)(t->exop)) < 0) | ||
111 | { | ||
112 | if (e == -128) /* invalid code */ | ||
113 | { | ||
114 | c->mode = BAD; | ||
115 | z->msg = "invalid huffman code"; | ||
116 | r = Z_DATA_ERROR; | ||
117 | LEAVE | ||
118 | } | ||
119 | e = -e; | ||
120 | if (e & 64) /* end of block */ | ||
121 | { | ||
122 | c->mode = END; | ||
123 | break; | ||
124 | } | ||
125 | c->sub.code.need = e; | ||
126 | c->sub.code.tree = t->next; | ||
127 | break; | ||
128 | } | ||
129 | if (e & 16) /* literal */ | ||
130 | { | ||
131 | c->sub.lit = t->base; | ||
132 | c->mode = LIT; | ||
133 | break; | ||
134 | } | ||
135 | c->sub.copy.get = e; | ||
136 | c->len = t->base; | ||
137 | c->mode = LENEXT; | ||
138 | case LENEXT: /* i: getting length extra (have base) */ | ||
139 | j = c->sub.copy.get; | ||
140 | NEEDBITS(j) | ||
141 | c->len += (uInt)b & inflate_mask[j]; | ||
142 | DUMPBITS(j) | ||
143 | c->sub.code.need = c->dbits; | ||
144 | c->sub.code.tree = c->dtree; | ||
145 | c->mode = DIST; | ||
146 | case DIST: /* i: get distance next */ | ||
147 | j = c->sub.code.need; | ||
148 | NEEDBITS(j) | ||
149 | t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); | ||
150 | DUMPBITS(t->bits) | ||
151 | if ((e = (int)(t->exop)) < 0) | ||
152 | { | ||
153 | if (e == -128) | ||
154 | { | ||
155 | c->mode = BAD; | ||
156 | z->msg = "invalid huffman code"; | ||
157 | r = Z_DATA_ERROR; | ||
158 | LEAVE | ||
159 | } | ||
160 | c->sub.code.need = -e; | ||
161 | c->sub.code.tree = t->next; | ||
162 | break; | ||
163 | } | ||
164 | c->sub.copy.dist = t->base; | ||
165 | c->sub.copy.get = e; | ||
166 | c->mode = DISTEXT; | ||
167 | case DISTEXT: /* i: getting distance extra */ | ||
168 | j = c->sub.copy.get; | ||
169 | NEEDBITS(j) | ||
170 | c->sub.copy.dist += (uInt)b & inflate_mask[j]; | ||
171 | DUMPBITS(j) | ||
172 | c->mode = COPY; | ||
173 | case COPY: /* o: copying bytes in window, waiting for space */ | ||
174 | f = q - s->window < c->sub.copy.dist ? | ||
175 | s->end - (c->sub.copy.dist - (q - s->window)) : | ||
176 | q - c->sub.copy.dist; | ||
177 | while (c->len) | ||
178 | { | ||
179 | NEEDOUT | ||
180 | OUTBYTE(*f++) | ||
181 | if (f == s->end) | ||
182 | f = s->window; | ||
183 | c->len--; | ||
184 | } | ||
185 | c->mode = START; | ||
186 | break; | ||
187 | case LIT: /* o: got literal, waiting for output space */ | ||
188 | NEEDOUT | ||
189 | OUTBYTE(c->sub.lit) | ||
190 | c->mode = START; | ||
191 | break; | ||
192 | case WASH: /* o: got eob, possibly more output */ | ||
193 | FLUSH | ||
194 | if (s->read != s->write) | ||
195 | LEAVE | ||
196 | c->mode = END; | ||
197 | case END: | ||
198 | r = Z_STREAM_END; | ||
199 | LEAVE | ||
200 | case BAD: /* x: got error */ | ||
201 | r = Z_DATA_ERROR; | ||
202 | LEAVE | ||
203 | default: | ||
204 | r = Z_STREAM_ERROR; | ||
205 | LEAVE | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | void inflate_codes_free(c, z) | ||
211 | struct inflate_codes_state *c; | ||
212 | z_stream *z; | ||
213 | { | ||
214 | inflate_trees_free(c->dtree, z); | ||
215 | inflate_trees_free(c->ltree, z); | ||
216 | ZFREE(z, c); | ||
217 | } | ||