Subversion Repositories Kolibri OS

Rev

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  /* memset() */
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
}