Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7640 views
1
#include "mupdf/fitz.h"
2
3
/* TODO: error checking */
4
5
enum
6
{
7
MIN_BITS = 9,
8
MAX_BITS = 12,
9
NUM_CODES = (1 << MAX_BITS),
10
LZW_CLEAR = 256,
11
LZW_EOD = 257,
12
LZW_FIRST = 258,
13
MAX_LENGTH = 4097
14
};
15
16
typedef struct lzw_code_s lzw_code;
17
18
struct lzw_code_s
19
{
20
int prev; /* prev code (in string) */
21
unsigned short length; /* string len, including this token */
22
unsigned char value; /* data value */
23
unsigned char first_char; /* first token of string */
24
};
25
26
typedef struct fz_lzwd_s fz_lzwd;
27
28
struct fz_lzwd_s
29
{
30
fz_stream *chain;
31
int eod;
32
33
int early_change;
34
35
int code_bits; /* num bits/code */
36
int code; /* current code */
37
int old_code; /* previously recognized code */
38
int next_code; /* next free entry */
39
40
lzw_code table[NUM_CODES];
41
42
unsigned char bp[MAX_LENGTH];
43
unsigned char *rp, *wp;
44
45
unsigned char buffer[4096];
46
};
47
48
static int
49
next_lzwd(fz_context *ctx, fz_stream *stm, int len)
50
{
51
fz_lzwd *lzw = stm->state;
52
lzw_code *table = lzw->table;
53
unsigned char *buf = lzw->buffer;
54
unsigned char *p = buf;
55
unsigned char *ep;
56
unsigned char *s;
57
int codelen;
58
59
int code_bits = lzw->code_bits;
60
int code = lzw->code;
61
int old_code = lzw->old_code;
62
int next_code = lzw->next_code;
63
64
if (len > sizeof(lzw->buffer))
65
len = sizeof(lzw->buffer);
66
ep = buf + len;
67
68
while (lzw->rp < lzw->wp && p < ep)
69
*p++ = *lzw->rp++;
70
71
while (p < ep)
72
{
73
if (lzw->eod)
74
return EOF;
75
76
code = fz_read_bits(ctx, lzw->chain, code_bits);
77
78
if (fz_is_eof_bits(ctx, lzw->chain))
79
{
80
lzw->eod = 1;
81
break;
82
}
83
84
if (code == LZW_EOD)
85
{
86
lzw->eod = 1;
87
break;
88
}
89
90
if (next_code > NUM_CODES && code != LZW_CLEAR)
91
{
92
fz_warn(ctx, "missing clear code in lzw decode");
93
code = LZW_CLEAR;
94
}
95
96
if (code == LZW_CLEAR)
97
{
98
code_bits = MIN_BITS;
99
next_code = LZW_FIRST;
100
old_code = -1;
101
continue;
102
}
103
104
/* if stream starts without a clear code, old_code is undefined... */
105
if (old_code == -1)
106
{
107
old_code = code;
108
}
109
else if (next_code == NUM_CODES)
110
{
111
/* TODO: Ghostscript checks for a following LZW_CLEAR before tolerating */
112
fz_warn(ctx, "tolerating a single out of range code in lzw decode");
113
next_code++;
114
}
115
else if (code > next_code || next_code >= NUM_CODES)
116
{
117
fz_warn(ctx, "out of range code encountered in lzw decode");
118
}
119
else
120
{
121
/* add new entry to the code table */
122
table[next_code].prev = old_code;
123
table[next_code].first_char = table[old_code].first_char;
124
table[next_code].length = table[old_code].length + 1;
125
if (code < next_code)
126
table[next_code].value = table[code].first_char;
127
else if (code == next_code)
128
table[next_code].value = table[next_code].first_char;
129
else
130
fz_warn(ctx, "out of range code encountered in lzw decode");
131
132
next_code ++;
133
134
if (next_code > (1 << code_bits) - lzw->early_change - 1)
135
{
136
code_bits ++;
137
if (code_bits > MAX_BITS)
138
code_bits = MAX_BITS;
139
}
140
141
old_code = code;
142
}
143
144
/* code maps to a string, copy to output (in reverse...) */
145
if (code > 255)
146
{
147
codelen = table[code].length;
148
lzw->rp = lzw->bp;
149
lzw->wp = lzw->bp + codelen;
150
151
assert(codelen < MAX_LENGTH);
152
153
s = lzw->wp;
154
do {
155
*(--s) = table[code].value;
156
code = table[code].prev;
157
} while (code >= 0 && s > lzw->bp);
158
}
159
160
/* ... or just a single character */
161
else
162
{
163
lzw->bp[0] = code;
164
lzw->rp = lzw->bp;
165
lzw->wp = lzw->bp + 1;
166
}
167
168
/* copy to output */
169
while (lzw->rp < lzw->wp && p < ep)
170
*p++ = *lzw->rp++;
171
}
172
173
lzw->code_bits = code_bits;
174
lzw->code = code;
175
lzw->old_code = old_code;
176
lzw->next_code = next_code;
177
178
stm->rp = buf;
179
stm->wp = p;
180
if (buf == p)
181
return EOF;
182
stm->pos += p - buf;
183
184
return *stm->rp++;
185
}
186
187
static void
188
close_lzwd(fz_context *ctx, void *state_)
189
{
190
fz_lzwd *lzw = (fz_lzwd *)state_;
191
fz_sync_bits(ctx, lzw->chain);
192
fz_drop_stream(ctx, lzw->chain);
193
fz_free(ctx, lzw);
194
}
195
196
/* Default: early_change = 1 */
197
fz_stream *
198
fz_open_lzwd(fz_context *ctx, fz_stream *chain, int early_change)
199
{
200
fz_lzwd *lzw = NULL;
201
int i;
202
203
fz_var(lzw);
204
205
fz_try(ctx)
206
{
207
lzw = fz_malloc_struct(ctx, fz_lzwd);
208
lzw->chain = chain;
209
lzw->eod = 0;
210
lzw->early_change = early_change;
211
212
for (i = 0; i < 256; i++)
213
{
214
lzw->table[i].value = i;
215
lzw->table[i].first_char = i;
216
lzw->table[i].length = 1;
217
lzw->table[i].prev = -1;
218
}
219
220
for (i = 256; i < NUM_CODES; i++)
221
{
222
lzw->table[i].value = 0;
223
lzw->table[i].first_char = 0;
224
lzw->table[i].length = 0;
225
lzw->table[i].prev = -1;
226
}
227
228
lzw->code_bits = MIN_BITS;
229
lzw->code = -1;
230
lzw->next_code = LZW_FIRST;
231
lzw->old_code = -1;
232
lzw->rp = lzw->bp;
233
lzw->wp = lzw->bp;
234
}
235
fz_catch(ctx)
236
{
237
fz_free(ctx, lzw);
238
fz_drop_stream(ctx, chain);
239
fz_rethrow(ctx);
240
}
241
242
return fz_new_stream(ctx, lzw, next_lzwd, close_lzwd);
243
}
244
245