Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8619 | maxcodehac | 1 | /* |
2 | jbig2dec |
||
3 | |||
4 | Copyright (C) 2001-2005 Artifex Software, Inc. |
||
5 | |||
6 | This software is distributed under license and may not |
||
7 | be copied, modified or distributed except as expressly |
||
8 | authorized under the terms of the license contained in |
||
9 | the file LICENSE in this distribution. |
||
10 | |||
11 | For further licensing information refer to http://artifex.com/ or |
||
12 | contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, |
||
13 | San Rafael, CA 94903, U.S.A., +1(415)492-9861. |
||
14 | */ |
||
15 | |||
16 | /* symbol dictionary segment decode and support */ |
||
17 | |||
18 | #ifdef HAVE_CONFIG_H |
||
19 | #include "config.h" |
||
20 | #endif |
||
21 | #include "os_types.h" |
||
22 | |||
23 | #include |
||
24 | #include |
||
25 | |||
26 | #include "jbig2.h" |
||
27 | #include "jbig2_priv.h" |
||
28 | #include "jbig2_arith.h" |
||
29 | #include "jbig2_arith_int.h" |
||
30 | #include "jbig2_arith_iaid.h" |
||
31 | #include "jbig2_huffman.h" |
||
32 | #include "jbig2_generic.h" |
||
33 | #include "jbig2_mmr.h" |
||
34 | #include "jbig2_symbol_dict.h" |
||
35 | #include "jbig2_text.h" |
||
36 | |||
37 | #if defined(OUTPUT_PBM) || defined(DUMP_SYMDICT) |
||
38 | #include |
||
39 | #include "jbig2_image.h" |
||
40 | #endif |
||
41 | |||
42 | /* Table 13 */ |
||
43 | typedef struct { |
||
44 | bool SDHUFF; |
||
45 | bool SDREFAGG; |
||
46 | int32_t SDNUMINSYMS; |
||
47 | Jbig2SymbolDict *SDINSYMS; |
||
48 | uint32_t SDNUMNEWSYMS; |
||
49 | uint32_t SDNUMEXSYMS; |
||
50 | Jbig2HuffmanTable *SDHUFFDH; |
||
51 | Jbig2HuffmanTable *SDHUFFDW; |
||
52 | Jbig2HuffmanTable *SDHUFFBMSIZE; |
||
53 | Jbig2HuffmanTable *SDHUFFAGGINST; |
||
54 | int SDTEMPLATE; |
||
55 | int8_t sdat[8]; |
||
56 | bool SDRTEMPLATE; |
||
57 | int8_t sdrat[4]; |
||
58 | } Jbig2SymbolDictParams; |
||
59 | |||
60 | |||
61 | /* Utility routines */ |
||
62 | |||
63 | #ifdef DUMP_SYMDICT |
||
64 | void |
||
65 | jbig2_dump_symbol_dict(Jbig2Ctx *ctx, Jbig2Segment *segment) |
||
66 | { |
||
67 | Jbig2SymbolDict *dict = (Jbig2SymbolDict *)segment->result; |
||
68 | int index; |
||
69 | char filename[24]; |
||
70 | |||
71 | if (dict == NULL) return; |
||
72 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
73 | "dumping symbol dict as %d individual png files\n", dict->n_symbols); |
||
74 | for (index = 0; index < dict->n_symbols; index++) { |
||
75 | snprintf(filename, sizeof(filename), "symbol_%02d-%04d.png", |
||
76 | segment->number, index); |
||
77 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
78 | "dumping symbol %d/%d as '%s'", index, dict->n_symbols, filename); |
||
79 | #ifdef HAVE_LIBPNG |
||
80 | jbig2_image_write_png_file(dict->glyphs[index], filename); |
||
81 | #else |
||
82 | jbig2_image_write_pbm_file(dict->glyphs[index], filename); |
||
83 | #endif |
||
84 | } |
||
85 | } |
||
86 | #endif /* DUMP_SYMDICT */ |
||
87 | |||
88 | /* return a new empty symbol dict */ |
||
89 | Jbig2SymbolDict * |
||
90 | jbig2_sd_new(Jbig2Ctx *ctx, int n_symbols) |
||
91 | { |
||
92 | Jbig2SymbolDict *new = NULL; |
||
93 | |||
94 | new = (Jbig2SymbolDict *)jbig2_alloc(ctx->allocator, |
||
95 | sizeof(Jbig2SymbolDict)); |
||
96 | if (new != NULL) { |
||
97 | new->glyphs = (Jbig2Image **)jbig2_alloc(ctx->allocator, |
||
98 | n_symbols*sizeof(Jbig2Image*)); |
||
99 | new->n_symbols = n_symbols; |
||
100 | } else { |
||
101 | return NULL; |
||
102 | } |
||
103 | |||
104 | if (new->glyphs != NULL) { |
||
105 | memset(new->glyphs, 0, n_symbols*sizeof(Jbig2Image*)); |
||
106 | } else { |
||
107 | jbig2_free(ctx->allocator, new); |
||
108 | return NULL; |
||
109 | } |
||
110 | |||
111 | return new; |
||
112 | } |
||
113 | |||
114 | /* release the memory associated with a symbol dict */ |
||
115 | void |
||
116 | jbig2_sd_release(Jbig2Ctx *ctx, Jbig2SymbolDict *dict) |
||
117 | { |
||
118 | int i; |
||
119 | |||
120 | if (dict == NULL) return; |
||
121 | for (i = 0; i < dict->n_symbols; i++) |
||
122 | if (dict->glyphs[i]) jbig2_image_release(ctx, dict->glyphs[i]); |
||
123 | jbig2_free(ctx->allocator, dict->glyphs); |
||
124 | jbig2_free(ctx->allocator, dict); |
||
125 | } |
||
126 | |||
127 | /* get a particular glyph by index */ |
||
128 | Jbig2Image * |
||
129 | jbig2_sd_glyph(Jbig2SymbolDict *dict, unsigned int id) |
||
130 | { |
||
131 | if (dict == NULL) return NULL; |
||
132 | return dict->glyphs[id]; |
||
133 | } |
||
134 | |||
135 | /* count the number of dictionary segments referred to by the given segment */ |
||
136 | int |
||
137 | jbig2_sd_count_referred(Jbig2Ctx *ctx, Jbig2Segment *segment) |
||
138 | { |
||
139 | int index; |
||
140 | Jbig2Segment *rsegment; |
||
141 | int n_dicts = 0; |
||
142 | |||
143 | for (index = 0; index < segment->referred_to_segment_count; index++) { |
||
144 | rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]); |
||
145 | if (rsegment && ((rsegment->flags & 63) == 0)) n_dicts++; |
||
146 | } |
||
147 | |||
148 | return (n_dicts); |
||
149 | } |
||
150 | |||
151 | /* return an array of pointers to symbol dictionaries referred to by the given segment */ |
||
152 | Jbig2SymbolDict ** |
||
153 | jbig2_sd_list_referred(Jbig2Ctx *ctx, Jbig2Segment *segment) |
||
154 | { |
||
155 | int index; |
||
156 | Jbig2Segment *rsegment; |
||
157 | Jbig2SymbolDict **dicts; |
||
158 | int n_dicts = jbig2_sd_count_referred(ctx, segment); |
||
159 | int dindex = 0; |
||
160 | |||
161 | dicts = jbig2_alloc(ctx->allocator, sizeof(Jbig2SymbolDict *) * n_dicts); |
||
162 | for (index = 0; index < segment->referred_to_segment_count; index++) { |
||
163 | rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]); |
||
164 | if (rsegment && ((rsegment->flags & 63) == 0)) { |
||
165 | /* add this referred to symbol dictionary */ |
||
166 | dicts[dindex++] = (Jbig2SymbolDict *)rsegment->result; |
||
167 | } |
||
168 | } |
||
169 | |||
170 | if (dindex != n_dicts) { |
||
171 | /* should never happen */ |
||
172 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
173 | "counted %d symbol dictionaries but build a list with %d.\n", |
||
174 | n_dicts, dindex); |
||
175 | } |
||
176 | |||
177 | return (dicts); |
||
178 | } |
||
179 | |||
180 | /* generate a new symbol dictionary by concatenating a list of |
||
181 | existing dictionaries */ |
||
182 | Jbig2SymbolDict * |
||
183 | jbig2_sd_cat(Jbig2Ctx *ctx, int n_dicts, Jbig2SymbolDict **dicts) |
||
184 | { |
||
185 | int i,j,k, symbols; |
||
186 | Jbig2SymbolDict *new = NULL; |
||
187 | |||
188 | /* count the imported symbols and allocate a new array */ |
||
189 | symbols = 0; |
||
190 | for(i = 0; i < n_dicts; i++) |
||
191 | symbols += dicts[i]->n_symbols; |
||
192 | |||
193 | /* fill a new array with cloned glyph pointers */ |
||
194 | new = jbig2_sd_new(ctx, symbols); |
||
195 | if (new != NULL) { |
||
196 | k = 0; |
||
197 | for (i = 0; i < n_dicts; i++) |
||
198 | for (j = 0; j < dicts[i]->n_symbols; j++) |
||
199 | new->glyphs[k++] = jbig2_image_clone(ctx, dicts[i]->glyphs[j]); |
||
200 | } |
||
201 | |||
202 | return new; |
||
203 | } |
||
204 | |||
205 | |||
206 | /* Decoding routines */ |
||
207 | |||
208 | /* 6.5 */ |
||
209 | static Jbig2SymbolDict * |
||
210 | jbig2_decode_symbol_dict(Jbig2Ctx *ctx, |
||
211 | Jbig2Segment *segment, |
||
212 | const Jbig2SymbolDictParams *params, |
||
213 | const byte *data, size_t size, |
||
214 | Jbig2ArithCx *GB_stats, |
||
215 | Jbig2ArithCx *GR_stats) |
||
216 | { |
||
217 | Jbig2SymbolDict *SDNEWSYMS; |
||
218 | Jbig2SymbolDict *SDEXSYMS; |
||
219 | int32_t HCHEIGHT; |
||
220 | uint32_t NSYMSDECODED; |
||
221 | int32_t SYMWIDTH, TOTWIDTH; |
||
222 | uint32_t HCFIRSTSYM; |
||
223 | uint32_t *SDNEWSYMWIDTHS = NULL; |
||
224 | int SBSYMCODELEN = 0; |
||
225 | Jbig2WordStream *ws = NULL; |
||
226 | Jbig2HuffmanState *hs = NULL; |
||
227 | Jbig2HuffmanTable *SDHUFFRDX = NULL; |
||
228 | Jbig2ArithState *as = NULL; |
||
229 | Jbig2ArithIntCtx *IADH = NULL; |
||
230 | Jbig2ArithIntCtx *IADW = NULL; |
||
231 | Jbig2ArithIntCtx *IAEX = NULL; |
||
232 | Jbig2ArithIntCtx *IAAI = NULL; |
||
233 | Jbig2ArithIaidCtx *IAID = NULL; |
||
234 | Jbig2ArithIntCtx *IARDX = NULL; |
||
235 | Jbig2ArithIntCtx *IARDY = NULL; |
||
236 | int code = 0; |
||
237 | Jbig2SymbolDict **refagg_dicts; |
||
238 | int n_refagg_dicts = 1; |
||
239 | |||
240 | Jbig2TextRegionParams *tparams = NULL; |
||
241 | |||
242 | /* 6.5.5 (3) */ |
||
243 | HCHEIGHT = 0; |
||
244 | NSYMSDECODED = 0; |
||
245 | |||
246 | ws = jbig2_word_stream_buf_new(ctx, data, size); |
||
247 | |||
248 | if (!params->SDHUFF) { |
||
249 | as = jbig2_arith_new(ctx, ws); |
||
250 | IADH = jbig2_arith_int_ctx_new(ctx); |
||
251 | IADW = jbig2_arith_int_ctx_new(ctx); |
||
252 | IAEX = jbig2_arith_int_ctx_new(ctx); |
||
253 | IAAI = jbig2_arith_int_ctx_new(ctx); |
||
254 | if (params->SDREFAGG) { |
||
255 | int tmp = params->SDINSYMS->n_symbols + params->SDNUMNEWSYMS; |
||
256 | for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < tmp; SBSYMCODELEN++); |
||
257 | IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN); |
||
258 | IARDX = jbig2_arith_int_ctx_new(ctx); |
||
259 | IARDY = jbig2_arith_int_ctx_new(ctx); |
||
260 | } |
||
261 | } else { |
||
262 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
263 | "huffman coded symbol dictionary"); |
||
264 | hs = jbig2_huffman_new(ctx, ws); |
||
265 | SDHUFFRDX = jbig2_build_huffman_table(ctx, |
||
266 | &jbig2_huffman_params_O); |
||
267 | if (!params->SDREFAGG) { |
||
268 | SDNEWSYMWIDTHS = jbig2_alloc(ctx->allocator, |
||
269 | sizeof(*SDNEWSYMWIDTHS)*params->SDNUMNEWSYMS); |
||
270 | if (SDNEWSYMWIDTHS == NULL) { |
||
271 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
272 | "could not allocate storage for symbol widths"); |
||
273 | return NULL; |
||
274 | } |
||
275 | } |
||
276 | } |
||
277 | |||
278 | SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS); |
||
279 | |||
280 | /* 6.5.5 (4a) */ |
||
281 | while (NSYMSDECODED < params->SDNUMNEWSYMS) { |
||
282 | int32_t HCDH, DW; |
||
283 | |||
284 | /* 6.5.6 */ |
||
285 | if (params->SDHUFF) { |
||
286 | HCDH = jbig2_huffman_get(hs, params->SDHUFFDH, &code); |
||
287 | } else { |
||
288 | code = jbig2_arith_int_decode(IADH, as, &HCDH); |
||
289 | } |
||
290 | |||
291 | if (code != 0) { |
||
292 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
293 | "error or OOB decoding height class delta (%d)\n", code); |
||
294 | } |
||
295 | |||
296 | /* 6.5.5 (4b) */ |
||
297 | HCHEIGHT = HCHEIGHT + HCDH; |
||
298 | SYMWIDTH = 0; |
||
299 | TOTWIDTH = 0; |
||
300 | HCFIRSTSYM = NSYMSDECODED; |
||
301 | |||
302 | if (HCHEIGHT < 0) { |
||
303 | /* todo: mem cleanup */ |
||
304 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
305 | "Invalid HCHEIGHT value"); |
||
306 | return NULL; |
||
307 | } |
||
308 | #ifdef JBIG2_DEBUG |
||
309 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
310 | "HCHEIGHT = %d", HCHEIGHT); |
||
311 | #endif |
||
312 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
313 | "decoding height class %d with %d syms decoded", HCHEIGHT, NSYMSDECODED); |
||
314 | |||
315 | for (;;) { |
||
316 | /* check for broken symbol table */ |
||
317 | if (NSYMSDECODED > params->SDNUMNEWSYMS) |
||
318 | { |
||
319 | /* todo: mem cleanup? */ |
||
320 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
321 | "No OOB signalling end of height class %d", HCHEIGHT); |
||
322 | break; |
||
323 | } |
||
324 | /* 6.5.7 */ |
||
325 | if (params->SDHUFF) { |
||
326 | DW = jbig2_huffman_get(hs, params->SDHUFFDW, &code); |
||
327 | } else { |
||
328 | code = jbig2_arith_int_decode(IADW, as, &DW); |
||
329 | } |
||
330 | |||
331 | /* 6.5.5 (4c.i) */ |
||
332 | if (code == 1) { |
||
333 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
334 | " OOB signals end of height class %d", HCHEIGHT); |
||
335 | break; |
||
336 | } |
||
337 | SYMWIDTH = SYMWIDTH + DW; |
||
338 | TOTWIDTH = TOTWIDTH + SYMWIDTH; |
||
339 | if (SYMWIDTH < 0) { |
||
340 | /* todo: mem cleanup */ |
||
341 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
342 | "Invalid SYMWIDTH value (%d) at symbol %d", SYMWIDTH, NSYMSDECODED+1); |
||
343 | return NULL; |
||
344 | } |
||
345 | #ifdef JBIG2_DEBUG |
||
346 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
347 | "SYMWIDTH = %d TOTWIDTH = %d", SYMWIDTH, TOTWIDTH); |
||
348 | #endif |
||
349 | /* 6.5.5 (4c.ii) */ |
||
350 | if (!params->SDHUFF || params->SDREFAGG) { |
||
351 | #ifdef JBIG2_DEBUG |
||
352 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
353 | "SDHUFF = %d; SDREFAGG = %d", params->SDHUFF, params->SDREFAGG); |
||
354 | #endif |
||
355 | /* 6.5.8 */ |
||
356 | if (!params->SDREFAGG) { |
||
357 | Jbig2GenericRegionParams region_params; |
||
358 | int sdat_bytes; |
||
359 | Jbig2Image *image; |
||
360 | |||
361 | /* Table 16 */ |
||
362 | region_params.MMR = 0; |
||
363 | region_params.GBTEMPLATE = params->SDTEMPLATE; |
||
364 | region_params.TPGDON = 0; |
||
365 | region_params.USESKIP = 0; |
||
366 | sdat_bytes = params->SDTEMPLATE == 0 ? 8 : 2; |
||
367 | memcpy(region_params.gbat, params->sdat, sdat_bytes); |
||
368 | |||
369 | image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT); |
||
370 | |||
371 | code = jbig2_decode_generic_region(ctx, segment, ®ion_params, |
||
372 | as, image, GB_stats); |
||
373 | /* todo: handle errors */ |
||
374 | |||
375 | SDNEWSYMS->glyphs[NSYMSDECODED] = image; |
||
376 | |||
377 | } else { |
||
378 | /* 6.5.8.2 refinement/aggregate symbol */ |
||
379 | uint32_t REFAGGNINST; |
||
380 | |||
381 | if (params->SDHUFF) { |
||
382 | REFAGGNINST = jbig2_huffman_get(hs, params->SDHUFFAGGINST, &code); |
||
383 | } else { |
||
384 | code = jbig2_arith_int_decode(IAAI, as, (int32_t*)&REFAGGNINST); |
||
385 | } |
||
386 | if (code || (int32_t)REFAGGNINST <= 0) { |
||
387 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
388 | "invalid number of symbols or OOB in aggregate glyph"); |
||
389 | return NULL; |
||
390 | } |
||
391 | |||
392 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
393 | "aggregate symbol coding (%d instances)", REFAGGNINST); |
||
394 | |||
395 | if (REFAGGNINST > 1) { |
||
396 | Jbig2Image *image; |
||
397 | int i; |
||
398 | |||
399 | if (tparams == NULL) |
||
400 | { |
||
401 | /* First time through, we need to initialise the */ |
||
402 | /* various tables for Huffman or adaptive encoding */ |
||
403 | /* as well as the text region parameters structure */ |
||
404 | refagg_dicts = jbig2_alloc(ctx->allocator, sizeof(Jbig2SymbolDict *) * n_refagg_dicts); |
||
405 | if (refagg_dicts == NULL) { |
||
406 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
407 | "Out of memory allocating dictionary array"); |
||
408 | return NULL; |
||
409 | } |
||
410 | refagg_dicts[0] = jbig2_sd_new(ctx, params->SDNUMINSYMS + params->SDNUMNEWSYMS); |
||
411 | if (refagg_dicts[0] == NULL) { |
||
412 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
413 | "Out of memory allocating symbol dictionary"); |
||
414 | jbig2_free(ctx->allocator, refagg_dicts); |
||
415 | return NULL; |
||
416 | } |
||
417 | refagg_dicts[0]->n_symbols = params->SDNUMINSYMS + params->SDNUMNEWSYMS; |
||
418 | for (i=0;i < params->SDNUMINSYMS;i++) |
||
419 | { |
||
420 | refagg_dicts[0]->glyphs[i] = jbig2_image_clone(ctx, params->SDINSYMS->glyphs[i]); |
||
421 | } |
||
422 | |||
423 | tparams = jbig2_alloc(ctx->allocator, sizeof(Jbig2TextRegionParams)); |
||
424 | if (tparams == NULL) { |
||
425 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
426 | "Out of memory creating text region params"); |
||
427 | jbig2_sd_release(ctx, refagg_dicts[0]); |
||
428 | jbig2_free(ctx->allocator, refagg_dicts); |
||
429 | return NULL; |
||
430 | } |
||
431 | if (!params->SDHUFF) { |
||
432 | /* Values from Table 17, section 6.5.8.2 (2) */ |
||
433 | tparams->IADT = jbig2_arith_int_ctx_new(ctx); |
||
434 | tparams->IAFS = jbig2_arith_int_ctx_new(ctx); |
||
435 | tparams->IADS = jbig2_arith_int_ctx_new(ctx); |
||
436 | tparams->IAIT = jbig2_arith_int_ctx_new(ctx); |
||
437 | /* Table 31 */ |
||
438 | for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < |
||
439 | (int)(params->SDNUMINSYMS + params->SDNUMNEWSYMS); SBSYMCODELEN++); |
||
440 | tparams->IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN); |
||
441 | tparams->IARI = jbig2_arith_int_ctx_new(ctx); |
||
442 | tparams->IARDW = jbig2_arith_int_ctx_new(ctx); |
||
443 | tparams->IARDH = jbig2_arith_int_ctx_new(ctx); |
||
444 | tparams->IARDX = jbig2_arith_int_ctx_new(ctx); |
||
445 | tparams->IARDY = jbig2_arith_int_ctx_new(ctx); |
||
446 | } else { |
||
447 | tparams->SBHUFFFS = jbig2_build_huffman_table(ctx, |
||
448 | &jbig2_huffman_params_F); /* Table B.6 */ |
||
449 | tparams->SBHUFFDS = jbig2_build_huffman_table(ctx, |
||
450 | &jbig2_huffman_params_H); /* Table B.8 */ |
||
451 | tparams->SBHUFFDT = jbig2_build_huffman_table(ctx, |
||
452 | &jbig2_huffman_params_K); /* Table B.11 */ |
||
453 | tparams->SBHUFFRDW = jbig2_build_huffman_table(ctx, |
||
454 | &jbig2_huffman_params_O); /* Table B.15 */ |
||
455 | tparams->SBHUFFRDH = jbig2_build_huffman_table(ctx, |
||
456 | &jbig2_huffman_params_O); /* Table B.15 */ |
||
457 | tparams->SBHUFFRDX = jbig2_build_huffman_table(ctx, |
||
458 | &jbig2_huffman_params_O); /* Table B.15 */ |
||
459 | tparams->SBHUFFRDY = jbig2_build_huffman_table(ctx, |
||
460 | &jbig2_huffman_params_O); /* Table B.15 */ |
||
461 | } |
||
462 | tparams->SBHUFF = params->SDHUFF; |
||
463 | tparams->SBREFINE = 1; |
||
464 | tparams->SBSTRIPS = 1; |
||
465 | tparams->SBDEFPIXEL = 0; |
||
466 | tparams->SBCOMBOP = JBIG2_COMPOSE_OR; |
||
467 | tparams->TRANSPOSED = 0; |
||
468 | tparams->REFCORNER = JBIG2_CORNER_TOPLEFT; |
||
469 | tparams->SBDSOFFSET = 0; |
||
470 | tparams->SBRTEMPLATE = params->SDRTEMPLATE; |
||
471 | } |
||
472 | tparams->SBNUMINSTANCES = REFAGGNINST; |
||
473 | |||
474 | image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT); |
||
475 | if (image == NULL) { |
||
476 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
477 | "Out of memory creating symbol image"); |
||
478 | jbig2_free(ctx->allocator, tparams); |
||
479 | jbig2_sd_release(ctx, refagg_dicts[0]); |
||
480 | jbig2_free(ctx->allocator, refagg_dicts); |
||
481 | return NULL; |
||
482 | } |
||
483 | |||
484 | /* multiple symbols are handled as a text region */ |
||
485 | jbig2_decode_text_region(ctx, segment, tparams, (const Jbig2SymbolDict * const *)refagg_dicts, |
||
486 | n_refagg_dicts, image, data, size, GR_stats, as, (Jbig2WordStream *)NULL); |
||
487 | |||
488 | SDNEWSYMS->glyphs[NSYMSDECODED] = image; |
||
489 | refagg_dicts[0]->glyphs[params->SDNUMINSYMS + NSYMSDECODED] = jbig2_image_clone(ctx, SDNEWSYMS->glyphs[NSYMSDECODED]); |
||
490 | } else { |
||
491 | /* 6.5.8.2.2 */ |
||
492 | /* bool SBHUFF = params->SDHUFF; */ |
||
493 | Jbig2RefinementRegionParams rparams; |
||
494 | Jbig2Image *image; |
||
495 | uint32_t ID; |
||
496 | int32_t RDX, RDY; |
||
497 | int ninsyms = params->SDINSYMS->n_symbols; |
||
498 | |||
499 | if (params->SDHUFF) { |
||
500 | ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN); |
||
501 | RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code); |
||
502 | RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code); |
||
503 | } else { |
||
504 | code = jbig2_arith_iaid_decode(IAID, as, (int32_t*)&ID); |
||
505 | code = jbig2_arith_int_decode(IARDX, as, &RDX); |
||
506 | code = jbig2_arith_int_decode(IARDY, as, &RDY); |
||
507 | } |
||
508 | |||
509 | if (ID >= ninsyms+NSYMSDECODED) { |
||
510 | code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
511 | "refinement references unknown symbol %d", ID); |
||
512 | return NULL; |
||
513 | } |
||
514 | |||
515 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
516 | "symbol is a refinement of id %d with the refinement applied at (%d,%d)", |
||
517 | ID, RDX, RDY); |
||
518 | |||
519 | image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT); |
||
520 | |||
521 | /* Table 18 */ |
||
522 | rparams.GRTEMPLATE = params->SDRTEMPLATE; |
||
523 | rparams.reference = (ID < ninsyms) ? |
||
524 | params->SDINSYMS->glyphs[ID] : |
||
525 | SDNEWSYMS->glyphs[ID-ninsyms]; |
||
526 | rparams.DX = RDX; |
||
527 | rparams.DY = RDY; |
||
528 | rparams.TPGRON = 0; |
||
529 | memcpy(rparams.grat, params->sdrat, 4); |
||
530 | jbig2_decode_refinement_region(ctx, segment, |
||
531 | &rparams, as, image, GR_stats); |
||
532 | |||
533 | SDNEWSYMS->glyphs[NSYMSDECODED] = image; |
||
534 | |||
535 | } |
||
536 | } |
||
537 | |||
538 | #ifdef OUTPUT_PBM |
||
539 | { |
||
540 | char name[64]; |
||
541 | FILE *out; |
||
542 | snprintf(name, 64, "sd.%04d.%04d.pbm", |
||
543 | segment->number, NSYMSDECODED); |
||
544 | out = fopen(name, "wb"); |
||
545 | jbig2_image_write_pbm(SDNEWSYMS->glyphs[NSYMSDECODED], out); |
||
546 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
547 | "writing out glyph as '%s' ...", name); |
||
548 | fclose(out); |
||
549 | } |
||
550 | #endif |
||
551 | |||
552 | } |
||
553 | |||
554 | /* 6.5.5 (4c.iii) */ |
||
555 | if (params->SDHUFF && !params->SDREFAGG) { |
||
556 | SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH; |
||
557 | } |
||
558 | |||
559 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
560 | "decoded symbol %d of %d (%dx%d)", |
||
561 | NSYMSDECODED, params->SDNUMNEWSYMS, |
||
562 | SYMWIDTH, HCHEIGHT); |
||
563 | |||
564 | /* 6.5.5 (4c.iv) */ |
||
565 | NSYMSDECODED = NSYMSDECODED + 1; |
||
566 | |||
567 | } /* end height class decode loop */ |
||
568 | |||
569 | /* 6.5.5 (4d) */ |
||
570 | if (params->SDHUFF && !params->SDREFAGG) { |
||
571 | /* 6.5.9 */ |
||
572 | Jbig2Image *image; |
||
573 | int BMSIZE = jbig2_huffman_get(hs, params->SDHUFFBMSIZE, &code); |
||
574 | int j, x; |
||
575 | |||
576 | if (code || (BMSIZE < 0)) { |
||
577 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
578 | "error decoding size of collective bitmap!"); |
||
579 | /* todo: memory cleanup */ |
||
580 | return NULL; |
||
581 | } |
||
582 | |||
583 | /* skip any bits before the next byte boundary */ |
||
584 | jbig2_huffman_skip(hs); |
||
585 | |||
586 | image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT); |
||
587 | if (image == NULL) { |
||
588 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
589 | "could not allocate collective bitmap image!"); |
||
590 | /* todo: memory cleanup */ |
||
591 | return NULL; |
||
592 | } |
||
593 | |||
594 | if (BMSIZE == 0) { |
||
595 | /* if BMSIZE == 0 bitmap is uncompressed */ |
||
596 | const byte *src = data + jbig2_huffman_offset(hs); |
||
597 | const int stride = (image->width >> 3) + |
||
598 | ((image->width & 7) ? 1 : 0); |
||
599 | byte *dst = image->data; |
||
600 | |||
601 | BMSIZE = image->height * stride; |
||
602 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
603 | "reading %dx%d uncompressed bitmap" |
||
604 | " for %d symbols (%d bytes)", |
||
605 | image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE); |
||
606 | |||
607 | for (j = 0; j < image->height; j++) { |
||
608 | memcpy(dst, src, stride); |
||
609 | dst += image->stride; |
||
610 | src += stride; |
||
611 | } |
||
612 | } else { |
||
613 | Jbig2GenericRegionParams rparams; |
||
614 | |||
615 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, |
||
616 | "reading %dx%d collective bitmap for %d symbols (%d bytes)", |
||
617 | image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE); |
||
618 | |||
619 | rparams.MMR = 1; |
||
620 | code = jbig2_decode_generic_mmr(ctx, segment, &rparams, |
||
621 | data + jbig2_huffman_offset(hs), BMSIZE, image); |
||
622 | if (code) { |
||
623 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
624 | "error decoding MMR bitmap image!"); |
||
625 | /* todo: memory cleanup */ |
||
626 | return NULL; |
||
627 | } |
||
628 | } |
||
629 | |||
630 | /* advance past the data we've just read */ |
||
631 | jbig2_huffman_advance(hs, BMSIZE); |
||
632 | |||
633 | /* copy the collective bitmap into the symbol dictionary */ |
||
634 | x = 0; |
||
635 | for (j = HCFIRSTSYM; j < NSYMSDECODED; j++) { |
||
636 | Jbig2Image *glyph; |
||
637 | glyph = jbig2_image_new(ctx, SDNEWSYMWIDTHS[j], HCHEIGHT); |
||
638 | jbig2_image_compose(ctx, glyph, image, |
||
639 | -x, 0, JBIG2_COMPOSE_REPLACE); |
||
640 | x += SDNEWSYMWIDTHS[j]; |
||
641 | SDNEWSYMS->glyphs[j] = glyph; |
||
642 | } |
||
643 | jbig2_image_release(ctx, image); |
||
644 | } |
||
645 | |||
646 | } /* end of symbol decode loop */ |
||
647 | |||
648 | if (tparams != NULL) |
||
649 | { |
||
650 | if (!params->SDHUFF) |
||
651 | { |
||
652 | jbig2_arith_int_ctx_free(ctx, tparams->IADT); |
||
653 | jbig2_arith_int_ctx_free(ctx, tparams->IAFS); |
||
654 | jbig2_arith_int_ctx_free(ctx, tparams->IADS); |
||
655 | jbig2_arith_int_ctx_free(ctx, tparams->IAIT); |
||
656 | jbig2_arith_iaid_ctx_free(ctx, tparams->IAID); |
||
657 | jbig2_arith_int_ctx_free(ctx, tparams->IARI); |
||
658 | jbig2_arith_int_ctx_free(ctx, tparams->IARDW); |
||
659 | jbig2_arith_int_ctx_free(ctx, tparams->IARDH); |
||
660 | jbig2_arith_int_ctx_free(ctx, tparams->IARDX); |
||
661 | jbig2_arith_int_ctx_free(ctx, tparams->IARDY); |
||
662 | } |
||
663 | else |
||
664 | { |
||
665 | jbig2_release_huffman_table(ctx, tparams->SBHUFFFS); |
||
666 | jbig2_release_huffman_table(ctx, tparams->SBHUFFDS); |
||
667 | jbig2_release_huffman_table(ctx, tparams->SBHUFFDT); |
||
668 | jbig2_release_huffman_table(ctx, tparams->SBHUFFRDX); |
||
669 | jbig2_release_huffman_table(ctx, tparams->SBHUFFRDY); |
||
670 | jbig2_release_huffman_table(ctx, tparams->SBHUFFRDW); |
||
671 | jbig2_release_huffman_table(ctx, tparams->SBHUFFRDH); |
||
672 | } |
||
673 | jbig2_free(ctx->allocator, tparams); |
||
674 | tparams = NULL; |
||
675 | jbig2_sd_release(ctx, refagg_dicts[0]); |
||
676 | jbig2_free(ctx->allocator, refagg_dicts); |
||
677 | } |
||
678 | |||
679 | jbig2_free(ctx->allocator, GB_stats); |
||
680 | |||
681 | /* 6.5.10 */ |
||
682 | SDEXSYMS = jbig2_sd_new(ctx, params->SDNUMEXSYMS); |
||
683 | { |
||
684 | int i = 0; |
||
685 | int j = 0; |
||
686 | int k, m, exflag = 0; |
||
687 | int32_t exrunlength; |
||
688 | |||
689 | if (params->SDINSYMS != NULL) |
||
690 | m = params->SDINSYMS->n_symbols; |
||
691 | else |
||
692 | m = 0; |
||
693 | while (j < params->SDNUMEXSYMS) { |
||
694 | if (params->SDHUFF) |
||
695 | /* FIXME: implement reading from huff table B.1 */ |
||
696 | exrunlength = params->SDNUMEXSYMS; |
||
697 | else |
||
698 | code = jbig2_arith_int_decode(IAEX, as, &exrunlength); |
||
699 | if (exrunlength > params->SDNUMEXSYMS - j) { |
||
700 | jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
701 | "runlength too large in export symbol table (%d > %d - %d)\n", |
||
702 | exrunlength, params->SDNUMEXSYMS, j); |
||
703 | jbig2_sd_release(ctx, SDEXSYMS); |
||
704 | /* skip to the cleanup code and return SDEXSYMS = NULL */ |
||
705 | SDEXSYMS = NULL; |
||
706 | break; |
||
707 | } |
||
708 | for(k = 0; k < exrunlength; k++) |
||
709 | if (exflag) { |
||
710 | SDEXSYMS->glyphs[j++] = (i < m) ? |
||
711 | jbig2_image_clone(ctx, params->SDINSYMS->glyphs[i]) : |
||
712 | jbig2_image_clone(ctx, SDNEWSYMS->glyphs[i-m]); |
||
713 | i++; |
||
714 | } |
||
715 | exflag = !exflag; |
||
716 | } |
||
717 | } |
||
718 | |||
719 | jbig2_sd_release(ctx, SDNEWSYMS); |
||
720 | |||
721 | if (!params->SDHUFF) { |
||
722 | jbig2_arith_int_ctx_free(ctx, IADH); |
||
723 | jbig2_arith_int_ctx_free(ctx, IADW); |
||
724 | jbig2_arith_int_ctx_free(ctx, IAEX); |
||
725 | jbig2_arith_int_ctx_free(ctx, IAAI); |
||
726 | if (params->SDREFAGG) { |
||
727 | jbig2_arith_iaid_ctx_free(ctx, IAID); |
||
728 | jbig2_arith_int_ctx_free(ctx, IARDX); |
||
729 | jbig2_arith_int_ctx_free(ctx, IARDY); |
||
730 | } |
||
731 | jbig2_free(ctx->allocator, as); |
||
732 | } else { |
||
733 | if (params->SDREFAGG) { |
||
734 | jbig2_free(ctx->allocator, SDNEWSYMWIDTHS); |
||
735 | } |
||
736 | jbig2_release_huffman_table(ctx, SDHUFFRDX); |
||
737 | jbig2_free(ctx->allocator, hs); |
||
738 | } |
||
739 | |||
740 | jbig2_word_stream_buf_free(ctx, ws); |
||
741 | |||
742 | return SDEXSYMS; |
||
743 | } |
||
744 | |||
745 | /* 7.4.2 */ |
||
746 | int |
||
747 | jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, |
||
748 | const byte *segment_data) |
||
749 | { |
||
750 | Jbig2SymbolDictParams params; |
||
751 | uint16_t flags; |
||
752 | int sdat_bytes; |
||
753 | int offset; |
||
754 | Jbig2ArithCx *GB_stats = NULL; |
||
755 | Jbig2ArithCx *GR_stats = NULL; |
||
756 | |||
757 | if (segment->data_length < 10) |
||
758 | goto too_short; |
||
759 | |||
760 | /* 7.4.2.1.1 */ |
||
761 | flags = jbig2_get_int16(segment_data); |
||
762 | params.SDHUFF = flags & 1; |
||
763 | params.SDREFAGG = (flags >> 1) & 1; |
||
764 | params.SDTEMPLATE = (flags >> 10) & 3; |
||
765 | params.SDRTEMPLATE = (flags >> 12) & 1; |
||
766 | |||
767 | params.SDHUFFDH = NULL; |
||
768 | params.SDHUFFDW = NULL; |
||
769 | params.SDHUFFBMSIZE = NULL; |
||
770 | params.SDHUFFAGGINST = NULL; |
||
771 | |||
772 | if (params.SDHUFF) { |
||
773 | switch ((flags & 0x000c) >> 2) { |
||
774 | case 0: /* Table B.4 */ |
||
775 | params.SDHUFFDH = jbig2_build_huffman_table(ctx, |
||
776 | &jbig2_huffman_params_D); |
||
777 | break; |
||
778 | case 1: /* Table B.5 */ |
||
779 | params.SDHUFFDH = jbig2_build_huffman_table(ctx, |
||
780 | &jbig2_huffman_params_E); |
||
781 | break; |
||
782 | case 3: /* Custom table from referred segment */ |
||
783 | /* We handle this case later by leaving the table as NULL */ |
||
784 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
785 | "symbol dictionary uses custom DH huffman table (NYI)"); |
||
786 | case 2: |
||
787 | default: |
||
788 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
789 | "symbol dictionary specified invalid huffman table"); |
||
790 | break; |
||
791 | } |
||
792 | switch ((flags & 0x0030) >> 4) { |
||
793 | case 0: /* Table B.2 */ |
||
794 | params.SDHUFFDW = jbig2_build_huffman_table(ctx, |
||
795 | &jbig2_huffman_params_B); |
||
796 | break; |
||
797 | case 1: /* Table B.3 */ |
||
798 | params.SDHUFFDW = jbig2_build_huffman_table(ctx, |
||
799 | &jbig2_huffman_params_C); |
||
800 | break; |
||
801 | case 3: /* Custom table from referred segment */ |
||
802 | /* We handle this case later by leaving the table as NULL */ |
||
803 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
804 | "symbol dictionary uses custom DW huffman table (NYI)"); |
||
805 | case 2: |
||
806 | default: |
||
807 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
808 | "symbol dictionary specified invalid huffman table"); |
||
809 | break; |
||
810 | } |
||
811 | if (flags & 0x0040) { |
||
812 | /* Custom table from referred segment */ |
||
813 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
814 | "symbol dictionary uses custom BMSIZE huffman table (NYI)"); |
||
815 | } else { |
||
816 | /* Table B.1 */ |
||
817 | params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, |
||
818 | &jbig2_huffman_params_A); |
||
819 | } |
||
820 | if (flags & 0x0080) { |
||
821 | /* Custom table from referred segment */ |
||
822 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
823 | "symbol dictionary uses custom REFAGG huffman table (NYI)"); |
||
824 | } else { |
||
825 | /* Table B.1 */ |
||
826 | params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, |
||
827 | &jbig2_huffman_params_A); |
||
828 | } |
||
829 | } |
||
830 | |||
831 | /* FIXME: there are quite a few of these conditions to check */ |
||
832 | /* maybe #ifdef CONFORMANCE and a separate routine */ |
||
833 | if (!params.SDHUFF) { |
||
834 | if (flags & 0x000c) { |
||
835 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
836 | "SDHUFF is zero, but contrary to spec SDHUFFDH is not."); |
||
837 | } |
||
838 | if (flags & 0x0030) { |
||
839 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
840 | "SDHUFF is zero, but contrary to spec SDHUFFDW is not."); |
||
841 | } |
||
842 | } |
||
843 | |||
844 | if (flags & 0x0080) { |
||
845 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
846 | "bitmap coding context is used (NYI) symbol data likely to be garbage!"); |
||
847 | } |
||
848 | |||
849 | /* 7.4.2.1.2 */ |
||
850 | sdat_bytes = params.SDHUFF ? 0 : params.SDTEMPLATE == 0 ? 8 : 2; |
||
851 | memcpy(params.sdat, segment_data + 2, sdat_bytes); |
||
852 | offset = 2 + sdat_bytes; |
||
853 | |||
854 | /* 7.4.2.1.3 */ |
||
855 | if (params.SDREFAGG && !params.SDRTEMPLATE) { |
||
856 | if (offset + 4 > segment->data_length) |
||
857 | goto too_short; |
||
858 | memcpy(params.sdrat, segment_data + offset, 4); |
||
859 | offset += 4; |
||
860 | } else { |
||
861 | /* sdrat is meaningless if SDRTEMPLATE is 1, but set a value |
||
862 | to avoid confusion if anybody looks */ |
||
863 | memset(params.sdrat, 0, 4); |
||
864 | } |
||
865 | |||
866 | if (offset + 8 > segment->data_length) |
||
867 | goto too_short; |
||
868 | |||
869 | /* 7.4.2.1.4 */ |
||
870 | params.SDNUMEXSYMS = jbig2_get_int32(segment_data + offset); |
||
871 | /* 7.4.2.1.5 */ |
||
872 | params.SDNUMNEWSYMS = jbig2_get_int32(segment_data + offset + 4); |
||
873 | offset += 8; |
||
874 | |||
875 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
876 | "symbol dictionary, flags=%04x, %d exported syms, %d new syms", |
||
877 | flags, params.SDNUMEXSYMS, params.SDNUMNEWSYMS); |
||
878 | |||
879 | /* 7.4.2.2 (2) */ |
||
880 | { |
||
881 | int n_dicts = jbig2_sd_count_referred(ctx, segment); |
||
882 | Jbig2SymbolDict **dicts = NULL; |
||
883 | |||
884 | params.SDINSYMS = NULL; |
||
885 | if (n_dicts > 0) { |
||
886 | dicts = jbig2_sd_list_referred(ctx, segment); |
||
887 | params.SDINSYMS = jbig2_sd_cat(ctx, n_dicts, dicts); |
||
888 | } |
||
889 | if (params.SDINSYMS != NULL) { |
||
890 | params.SDNUMINSYMS = params.SDINSYMS->n_symbols; |
||
891 | } else { |
||
892 | params.SDNUMINSYMS = 0; |
||
893 | } |
||
894 | } |
||
895 | |||
896 | /* 7.4.2.2 (4) */ |
||
897 | if (!params.SDHUFF) { |
||
898 | int stats_size = params.SDTEMPLATE == 0 ? 65536 : |
||
899 | params.SDTEMPLATE == 1 ? 8192 : 1024; |
||
900 | GB_stats = jbig2_alloc(ctx->allocator, stats_size); |
||
901 | memset(GB_stats, 0, stats_size); |
||
902 | if (params.SDREFAGG) { |
||
903 | stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13; |
||
904 | GR_stats = jbig2_alloc(ctx->allocator, stats_size); |
||
905 | memset(GR_stats, 0, stats_size); |
||
906 | } |
||
907 | } |
||
908 | |||
909 | if (flags & 0x0100) { |
||
910 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
911 | "segment marks bitmap coding context as retained (NYI)"); |
||
912 | } |
||
913 | |||
914 | segment->result = (void *)jbig2_decode_symbol_dict(ctx, segment, |
||
915 | ¶ms, |
||
916 | segment_data + offset, |
||
917 | segment->data_length - offset, |
||
918 | GB_stats, GR_stats); |
||
919 | #ifdef DUMP_SYMDICT |
||
920 | if (segment->result) jbig2_dump_symbol_dict(ctx, segment); |
||
921 | #endif |
||
922 | |||
923 | if (params.SDHUFF) { |
||
924 | jbig2_release_huffman_table(ctx, params.SDHUFFDH); |
||
925 | jbig2_release_huffman_table(ctx, params.SDHUFFDW); |
||
926 | jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE); |
||
927 | jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST); |
||
928 | } |
||
929 | |||
930 | /* todo: retain or free GB_stats, GR_stats */ |
||
931 | |||
932 | return (segment->result != NULL) ? 0 : -1; |
||
933 | |||
934 | too_short: |
||
935 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
936 | "Segment too short"); |
||
937 | }><>><>>>>>>>>> |