|
Packit |
3f21c4 |
/* Copyright (C) 2001-2012 Artifex Software, Inc.
|
|
Packit |
3f21c4 |
All Rights Reserved.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
This software is provided AS-IS with no warranty, either express or
|
|
Packit |
3f21c4 |
implied.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
This software is distributed under license and may not be copied,
|
|
Packit |
3f21c4 |
modified or distributed except as expressly authorized under the terms
|
|
Packit |
3f21c4 |
of the license contained in the file LICENSE in this distribution.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Refer to licensing information at http://www.artifex.com or contact
|
|
Packit |
3f21c4 |
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
|
|
Packit |
3f21c4 |
CA 94903, U.S.A., +1(415)492-9861, for further information.
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/*
|
|
Packit |
3f21c4 |
jbig2dec
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* symbol dictionary segment decode and support */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
3f21c4 |
#include "config.h"
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#include "os_types.h"
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#include <stddef.h>
|
|
Packit |
3f21c4 |
#include <string.h> /* memset() */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#include "jbig2.h"
|
|
Packit |
3f21c4 |
#include "jbig2_priv.h"
|
|
Packit |
3f21c4 |
#include "jbig2_arith.h"
|
|
Packit |
3f21c4 |
#include "jbig2_arith_int.h"
|
|
Packit |
3f21c4 |
#include "jbig2_arith_iaid.h"
|
|
Packit |
3f21c4 |
#include "jbig2_huffman.h"
|
|
Packit |
3f21c4 |
#include "jbig2_generic.h"
|
|
Packit |
3f21c4 |
#include "jbig2_mmr.h"
|
|
Packit |
3f21c4 |
#include "jbig2_symbol_dict.h"
|
|
Packit |
3f21c4 |
#include "jbig2_text.h"
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#if defined(OUTPUT_PBM) || defined(DUMP_SYMDICT)
|
|
Packit |
3f21c4 |
#include <stdio.h>
|
|
Packit |
3f21c4 |
#include "jbig2_image.h"
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Table 13 */
|
|
Packit |
3f21c4 |
typedef struct {
|
|
Packit |
3f21c4 |
bool SDHUFF;
|
|
Packit |
3f21c4 |
bool SDREFAGG;
|
|
Packit |
3f21c4 |
uint32_t SDNUMINSYMS;
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *SDINSYMS;
|
|
Packit |
3f21c4 |
uint32_t SDNUMNEWSYMS;
|
|
Packit |
3f21c4 |
uint32_t SDNUMEXSYMS;
|
|
Packit |
3f21c4 |
Jbig2HuffmanTable *SDHUFFDH;
|
|
Packit |
3f21c4 |
Jbig2HuffmanTable *SDHUFFDW;
|
|
Packit |
3f21c4 |
Jbig2HuffmanTable *SDHUFFBMSIZE;
|
|
Packit |
3f21c4 |
Jbig2HuffmanTable *SDHUFFAGGINST;
|
|
Packit |
3f21c4 |
int SDTEMPLATE;
|
|
Packit |
3f21c4 |
int8_t sdat[8];
|
|
Packit |
3f21c4 |
bool SDRTEMPLATE;
|
|
Packit |
3f21c4 |
int8_t sdrat[4];
|
|
Packit |
3f21c4 |
} Jbig2SymbolDictParams;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Utility routines */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef DUMP_SYMDICT
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
jbig2_dump_symbol_dict(Jbig2Ctx *ctx, Jbig2Segment *segment)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *dict = (Jbig2SymbolDict *) segment->result;
|
|
Packit |
3f21c4 |
int index;
|
|
Packit |
3f21c4 |
char filename[24];
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (dict == NULL)
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "dumping symbol dict as %d individual png files\n", dict->n_symbols);
|
|
Packit |
3f21c4 |
for (index = 0; index < dict->n_symbols; index++) {
|
|
Packit |
3f21c4 |
snprintf(filename, sizeof(filename), "symbol_%02d-%04d.png", segment->number, index);
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "dumping symbol %d/%d as '%s'", index, dict->n_symbols, filename);
|
|
Packit |
3f21c4 |
#ifdef HAVE_LIBPNG
|
|
Packit |
3f21c4 |
jbig2_image_write_png_file(dict->glyphs[index], filename);
|
|
Packit |
3f21c4 |
#else
|
|
Packit |
3f21c4 |
jbig2_image_write_pbm_file(dict->glyphs[index], filename);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#endif /* DUMP_SYMDICT */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* return a new empty symbol dict */
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *
|
|
Packit |
3f21c4 |
jbig2_sd_new(Jbig2Ctx *ctx, uint32_t n_symbols)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *new_dict = NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
new_dict = jbig2_new(ctx, Jbig2SymbolDict, 1);
|
|
Packit |
3f21c4 |
if (new_dict != NULL) {
|
|
Packit |
3f21c4 |
new_dict->glyphs = jbig2_new(ctx, Jbig2Image *, n_symbols);
|
|
Packit |
3f21c4 |
new_dict->n_symbols = n_symbols;
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to allocate new empty symbol dict");
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (new_dict->glyphs != NULL) {
|
|
Packit |
3f21c4 |
memset(new_dict->glyphs, 0, n_symbols * sizeof(Jbig2Image *));
|
|
Packit |
3f21c4 |
} else if (new_dict->n_symbols > 0) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to allocate glyphs for new empty symbol dict");
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, new_dict);
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return new_dict;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* release the memory associated with a symbol dict */
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
jbig2_sd_release(Jbig2Ctx *ctx, Jbig2SymbolDict *dict)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
uint32_t i;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (dict == NULL)
|
|
Packit |
3f21c4 |
return;
|
|
Packit |
3f21c4 |
for (i = 0; i < dict->n_symbols; i++)
|
|
Packit |
3f21c4 |
if (dict->glyphs[i])
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, dict->glyphs[i]);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, dict->glyphs);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, dict);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* get a particular glyph by index */
|
|
Packit |
3f21c4 |
Jbig2Image *
|
|
Packit |
3f21c4 |
jbig2_sd_glyph(Jbig2SymbolDict *dict, unsigned int id)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
if (dict == NULL)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
return dict->glyphs[id];
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* count the number of dictionary segments referred to by the given segment */
|
|
Packit |
3f21c4 |
uint32_t
|
|
Packit |
3f21c4 |
jbig2_sd_count_referred(Jbig2Ctx *ctx, Jbig2Segment *segment)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int index;
|
|
Packit |
3f21c4 |
Jbig2Segment *rsegment;
|
|
Packit |
3f21c4 |
uint32_t n_dicts = 0;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (index = 0; index < segment->referred_to_segment_count; index++) {
|
|
Packit |
3f21c4 |
rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
|
|
Packit |
3f21c4 |
if (rsegment && ((rsegment->flags & 63) == 0) &&
|
|
Packit |
3f21c4 |
rsegment->result && (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL))
|
|
Packit |
3f21c4 |
n_dicts++;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return (n_dicts);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* return an array of pointers to symbol dictionaries referred to by the given segment */
|
|
Packit |
3f21c4 |
Jbig2SymbolDict **
|
|
Packit |
3f21c4 |
jbig2_sd_list_referred(Jbig2Ctx *ctx, Jbig2Segment *segment)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int index;
|
|
Packit |
3f21c4 |
Jbig2Segment *rsegment;
|
|
Packit |
3f21c4 |
Jbig2SymbolDict **dicts;
|
|
Packit |
3f21c4 |
uint32_t n_dicts = jbig2_sd_count_referred(ctx, segment);
|
|
Packit |
3f21c4 |
uint32_t dindex = 0;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
dicts = jbig2_new(ctx, Jbig2SymbolDict *, n_dicts);
|
|
Packit |
3f21c4 |
if (dicts == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate referred list of symbol dictionaries");
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (index = 0; index < segment->referred_to_segment_count; index++) {
|
|
Packit |
3f21c4 |
rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
|
|
Packit |
3f21c4 |
if (rsegment && ((rsegment->flags & 63) == 0) && rsegment->result &&
|
|
Packit |
3f21c4 |
(((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL)) {
|
|
Packit |
3f21c4 |
/* add this referred to symbol dictionary */
|
|
Packit |
3f21c4 |
dicts[dindex++] = (Jbig2SymbolDict *) rsegment->result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (dindex != n_dicts) {
|
|
Packit |
3f21c4 |
/* should never happen */
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "counted %d symbol dictionaries but built a list with %d.\n", n_dicts, dindex);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return (dicts);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* generate a new symbol dictionary by concatenating a list of
|
|
Packit |
3f21c4 |
existing dictionaries */
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *
|
|
Packit |
3f21c4 |
jbig2_sd_cat(Jbig2Ctx *ctx, uint32_t n_dicts, Jbig2SymbolDict **dicts)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
uint32_t i, j, k, symbols;
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *new_dict = NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* count the imported symbols and allocate a new array */
|
|
Packit |
3f21c4 |
symbols = 0;
|
|
Packit |
3f21c4 |
for (i = 0; i < n_dicts; i++)
|
|
Packit |
3f21c4 |
symbols += dicts[i]->n_symbols;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* fill a new array with cloned glyph pointers */
|
|
Packit |
3f21c4 |
new_dict = jbig2_sd_new(ctx, symbols);
|
|
Packit |
3f21c4 |
if (new_dict != NULL) {
|
|
Packit |
3f21c4 |
k = 0;
|
|
Packit |
3f21c4 |
for (i = 0; i < n_dicts; i++)
|
|
Packit |
3f21c4 |
for (j = 0; j < dicts[i]->n_symbols; j++)
|
|
Packit |
3f21c4 |
new_dict->glyphs[k++] = jbig2_image_clone(ctx, dicts[i]->glyphs[j]);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate new symbol dictionary");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return new_dict;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Decoding routines */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5 */
|
|
Packit |
3f21c4 |
static Jbig2SymbolDict *
|
|
Packit |
3f21c4 |
jbig2_decode_symbol_dict(Jbig2Ctx *ctx,
|
|
Packit |
3f21c4 |
Jbig2Segment *segment,
|
|
Packit |
3f21c4 |
const Jbig2SymbolDictParams *params, const byte *data, size_t size, Jbig2ArithCx *GB_stats, Jbig2ArithCx *GR_stats)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *SDNEWSYMS = NULL;
|
|
Packit |
3f21c4 |
Jbig2SymbolDict *SDEXSYMS = NULL;
|
|
Packit |
3f21c4 |
uint32_t HCHEIGHT;
|
|
Packit |
3f21c4 |
uint32_t NSYMSDECODED;
|
|
Packit |
3f21c4 |
uint32_t SYMWIDTH, TOTWIDTH;
|
|
Packit |
3f21c4 |
uint32_t HCFIRSTSYM;
|
|
Packit |
3f21c4 |
uint32_t *SDNEWSYMWIDTHS = NULL;
|
|
Packit |
3f21c4 |
int SBSYMCODELEN = 0;
|
|
Packit |
3f21c4 |
Jbig2WordStream *ws = NULL;
|
|
Packit |
3f21c4 |
Jbig2HuffmanState *hs = NULL;
|
|
Packit |
3f21c4 |
Jbig2HuffmanTable *SDHUFFRDX = NULL;
|
|
Packit |
3f21c4 |
Jbig2HuffmanTable *SBHUFFRSIZE = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithState *as = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIntCtx *IADH = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIntCtx *IADW = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIntCtx *IAEX = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIntCtx *IAAI = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIaidCtx *IAID = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIntCtx *IARDX = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithIntCtx *IARDY = NULL;
|
|
Packit |
3f21c4 |
int code = 0;
|
|
Packit |
3f21c4 |
Jbig2SymbolDict **refagg_dicts = NULL;
|
|
Packit |
3f21c4 |
int n_refagg_dicts = 1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Jbig2TextRegionParams *tparams = NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (3) */
|
|
Packit |
3f21c4 |
HCHEIGHT = 0;
|
|
Packit |
3f21c4 |
NSYMSDECODED = 0;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
ws = jbig2_word_stream_buf_new(ctx, data, size);
|
|
Packit |
3f21c4 |
if (ws == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate ws in jbig2_decode_symbol_dict");
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
as = jbig2_arith_new(ctx, ws);
|
|
Packit |
3f21c4 |
if (as == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate as in jbig2_decode_symbol_dict");
|
|
Packit |
3f21c4 |
jbig2_word_stream_buf_free(ctx, ws);
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (!params->SDHUFF) {
|
|
Packit |
3f21c4 |
IADH = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
IADW = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
IAEX = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
IAAI = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
if ((IADH == NULL) || (IADW == NULL) || (IAEX == NULL) || (IAAI == NULL)) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap");
|
|
Packit |
3f21c4 |
goto cleanup1;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (params->SDREFAGG) {
|
|
Packit |
3f21c4 |
int64_t tmp = params->SDNUMINSYMS + params->SDNUMNEWSYMS;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (SBSYMCODELEN = 0; ((int64_t) 1 << SBSYMCODELEN) < tmp; SBSYMCODELEN++);
|
|
Packit |
3f21c4 |
IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
|
|
Packit |
3f21c4 |
IARDX = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
IARDY = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
if ((IAID == NULL) || (IARDX == NULL) || (IARDY == NULL)) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap");
|
|
Packit |
3f21c4 |
goto cleanup2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded symbol dictionary");
|
|
Packit |
3f21c4 |
hs = jbig2_huffman_new(ctx, ws);
|
|
Packit |
3f21c4 |
SDHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
|
|
Packit |
3f21c4 |
SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
|
|
Packit |
3f21c4 |
if ((hs == NULL) || (SDHUFFRDX == NULL) || (SBHUFFRSIZE == NULL)) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap");
|
|
Packit |
3f21c4 |
goto cleanup2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (!params->SDREFAGG) {
|
|
Packit |
3f21c4 |
SDNEWSYMWIDTHS = jbig2_new(ctx, uint32_t, params->SDNUMNEWSYMS);
|
|
Packit |
3f21c4 |
if (SDNEWSYMWIDTHS == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate storage for (%u) symbol widths", params->SDNUMNEWSYMS);
|
|
Packit |
3f21c4 |
goto cleanup2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS);
|
|
Packit |
3f21c4 |
if (SDNEWSYMS == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "could not allocate storage for (%u) new symbols", params->SDNUMNEWSYMS);
|
|
Packit |
3f21c4 |
goto cleanup2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (4a) */
|
|
Packit |
3f21c4 |
while (NSYMSDECODED < params->SDNUMNEWSYMS) {
|
|
Packit |
3f21c4 |
int32_t HCDH, DW;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.6 */
|
|
Packit |
3f21c4 |
if (params->SDHUFF) {
|
|
Packit |
3f21c4 |
HCDH = jbig2_huffman_get(hs, params->SDHUFFDH, &code);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
code = jbig2_arith_int_decode(IADH, as, &HCDH);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (code != 0) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error or OOB decoding height class delta (%d)\n", code);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (!params->SDHUFF && jbig2_arith_has_reached_marker(as)) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "prevent DOS while decoding height classes");
|
|
Packit |
3f21c4 |
goto cleanup2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (4b) */
|
|
Packit |
3f21c4 |
HCHEIGHT = HCHEIGHT + HCDH;
|
|
Packit |
3f21c4 |
SYMWIDTH = 0;
|
|
Packit |
3f21c4 |
TOTWIDTH = 0;
|
|
Packit |
3f21c4 |
HCFIRSTSYM = NSYMSDECODED;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if ((int32_t) HCHEIGHT < 0) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Invalid HCHEIGHT value");
|
|
Packit |
3f21c4 |
goto cleanup2;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#ifdef JBIG2_DEBUG
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "HCHEIGHT = %d", HCHEIGHT);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoding height class %d with %d syms decoded", HCHEIGHT, NSYMSDECODED);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (;;) {
|
|
Packit |
3f21c4 |
/* 6.5.7 */
|
|
Packit |
3f21c4 |
if (params->SDHUFF) {
|
|
Packit |
3f21c4 |
DW = jbig2_huffman_get(hs, params->SDHUFFDW, &code);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
code = jbig2_arith_int_decode(IADW, as, &DW;;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (code < 0)
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (4c.i) */
|
|
Packit |
3f21c4 |
if (code == 1) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, " OOB signals end of height class %d", HCHEIGHT);
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* check for broken symbol table */
|
|
Packit |
3f21c4 |
if (NSYMSDECODED >= params->SDNUMNEWSYMS) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "No OOB signalling end of height class %d", HCHEIGHT);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
SYMWIDTH = SYMWIDTH + DW;
|
|
Packit |
3f21c4 |
TOTWIDTH = TOTWIDTH + SYMWIDTH;
|
|
Packit |
3f21c4 |
if ((int32_t) SYMWIDTH < 0) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Invalid SYMWIDTH value (%d) at symbol %d", SYMWIDTH, NSYMSDECODED + 1);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#ifdef JBIG2_DEBUG
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "SYMWIDTH = %d TOTWIDTH = %d", SYMWIDTH, TOTWIDTH);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
/* 6.5.5 (4c.ii) */
|
|
Packit |
3f21c4 |
if (!params->SDHUFF || params->SDREFAGG) {
|
|
Packit |
3f21c4 |
#ifdef JBIG2_DEBUG
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "SDHUFF = %d; SDREFAGG = %d", params->SDHUFF, params->SDREFAGG);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
/* 6.5.8 */
|
|
Packit |
3f21c4 |
if (!params->SDREFAGG) {
|
|
Packit |
3f21c4 |
Jbig2GenericRegionParams region_params;
|
|
Packit |
3f21c4 |
int sdat_bytes;
|
|
Packit |
3f21c4 |
Jbig2Image *image;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Table 16 */
|
|
Packit |
3f21c4 |
region_params.MMR = 0;
|
|
Packit |
3f21c4 |
region_params.GBTEMPLATE = params->SDTEMPLATE;
|
|
Packit |
3f21c4 |
region_params.TPGDON = 0;
|
|
Packit |
3f21c4 |
region_params.USESKIP = 0;
|
|
Packit |
3f21c4 |
sdat_bytes = params->SDTEMPLATE == 0 ? 8 : 2;
|
|
Packit |
3f21c4 |
memcpy(region_params.gbat, params->sdat, sdat_bytes);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
|
|
Packit |
3f21c4 |
if (image == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate image in jbig2_decode_symbol_dict");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
code = jbig2_decode_generic_region(ctx, segment, ®ion_params, as, image, GB_stats);
|
|
Packit |
3f21c4 |
if (code < 0) {
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
SDNEWSYMS->glyphs[NSYMSDECODED] = image;
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
/* 6.5.8.2 refinement/aggregate symbol */
|
|
Packit |
3f21c4 |
uint32_t REFAGGNINST;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (params->SDHUFF) {
|
|
Packit |
3f21c4 |
REFAGGNINST = jbig2_huffman_get(hs, params->SDHUFFAGGINST, &code);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
code = jbig2_arith_int_decode(IAAI, as, (int32_t *) & REFAGGNINST);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (code || (int32_t) REFAGGNINST <= 0) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid number of symbols or OOB in aggregate glyph");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "aggregate symbol coding (%d instances)", REFAGGNINST);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (REFAGGNINST > 1) {
|
|
Packit |
3f21c4 |
Jbig2Image *image;
|
|
Packit |
3f21c4 |
uint32_t i;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (tparams == NULL) {
|
|
Packit |
3f21c4 |
/* First time through, we need to initialise the */
|
|
Packit |
3f21c4 |
/* various tables for Huffman or adaptive encoding */
|
|
Packit |
3f21c4 |
/* as well as the text region parameters structure */
|
|
Packit |
3f21c4 |
refagg_dicts = jbig2_new(ctx, Jbig2SymbolDict *, n_refagg_dicts);
|
|
Packit |
3f21c4 |
if (refagg_dicts == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory allocating dictionary array");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
refagg_dicts[0] = jbig2_sd_new(ctx, params->SDNUMINSYMS + params->SDNUMNEWSYMS);
|
|
Packit |
3f21c4 |
if (refagg_dicts[0] == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory allocating symbol dictionary");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
for (i = 0; i < params->SDNUMINSYMS; i++) {
|
|
Packit |
3f21c4 |
refagg_dicts[0]->glyphs[i] = jbig2_image_clone(ctx, params->SDINSYMS->glyphs[i]);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
tparams = jbig2_new(ctx, Jbig2TextRegionParams, 1);
|
|
Packit |
3f21c4 |
if (tparams == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory creating text region params");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (!params->SDHUFF) {
|
|
Packit |
3f21c4 |
/* Values from Table 17, section 6.5.8.2 (2) */
|
|
Packit |
3f21c4 |
tparams->IADT = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IAFS = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IADS = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IAIT = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
/* Table 31 */
|
|
Packit |
3f21c4 |
for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < (int)(params->SDNUMINSYMS + params->SDNUMNEWSYMS); SBSYMCODELEN++);
|
|
Packit |
3f21c4 |
tparams->IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
|
|
Packit |
3f21c4 |
tparams->IARI = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IARDW = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IARDH = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IARDX = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
tparams->IARDY = jbig2_arith_int_ctx_new(ctx);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
tparams->SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F); /* Table B.6 */
|
|
Packit |
3f21c4 |
tparams->SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H); /* Table B.8 */
|
|
Packit |
3f21c4 |
tparams->SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K); /* Table B.11 */
|
|
Packit |
3f21c4 |
tparams->SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
|
|
Packit |
3f21c4 |
tparams->SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
|
|
Packit |
3f21c4 |
tparams->SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
|
|
Packit |
3f21c4 |
tparams->SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
tparams->SBHUFF = params->SDHUFF;
|
|
Packit |
3f21c4 |
tparams->SBREFINE = 1;
|
|
Packit |
3f21c4 |
tparams->SBSTRIPS = 1;
|
|
Packit |
3f21c4 |
tparams->SBDEFPIXEL = 0;
|
|
Packit |
3f21c4 |
tparams->SBCOMBOP = JBIG2_COMPOSE_OR;
|
|
Packit |
3f21c4 |
tparams->TRANSPOSED = 0;
|
|
Packit |
3f21c4 |
tparams->REFCORNER = JBIG2_CORNER_TOPLEFT;
|
|
Packit |
3f21c4 |
tparams->SBDSOFFSET = 0;
|
|
Packit |
3f21c4 |
tparams->SBRTEMPLATE = params->SDRTEMPLATE;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
tparams->SBNUMINSTANCES = REFAGGNINST;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
|
|
Packit |
3f21c4 |
if (image == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory creating symbol image");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* multiple symbols are handled as a text region */
|
|
Packit |
3f21c4 |
code = jbig2_decode_text_region(ctx, segment, tparams, (const Jbig2SymbolDict * const *)refagg_dicts,
|
|
Packit |
3f21c4 |
n_refagg_dicts, image, data, size, GR_stats, as, ws);
|
|
Packit |
3f21c4 |
if (code < 0)
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
SDNEWSYMS->glyphs[NSYMSDECODED] = image;
|
|
Packit |
3f21c4 |
refagg_dicts[0]->glyphs[params->SDNUMINSYMS + NSYMSDECODED] = jbig2_image_clone(ctx, SDNEWSYMS->glyphs[NSYMSDECODED]);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
/* 6.5.8.2.2 */
|
|
Packit |
3f21c4 |
/* bool SBHUFF = params->SDHUFF; */
|
|
Packit |
3f21c4 |
Jbig2RefinementRegionParams rparams;
|
|
Packit |
3f21c4 |
Jbig2Image *image;
|
|
Packit |
3f21c4 |
uint32_t ID;
|
|
Packit |
3f21c4 |
int32_t RDX, RDY;
|
|
Packit |
3f21c4 |
int BMSIZE = 0;
|
|
Packit |
3f21c4 |
uint32_t ninsyms = params->SDNUMINSYMS;
|
|
Packit |
3f21c4 |
int code1 = 0;
|
|
Packit |
3f21c4 |
int code2 = 0;
|
|
Packit |
3f21c4 |
int code3 = 0;
|
|
Packit |
3f21c4 |
int code4 = 0;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.8.2.2 (2, 3, 4, 5) */
|
|
Packit |
3f21c4 |
if (params->SDHUFF) {
|
|
Packit |
3f21c4 |
ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code4);
|
|
Packit |
3f21c4 |
RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code1);
|
|
Packit |
3f21c4 |
RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code2);
|
|
Packit |
3f21c4 |
BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code3);
|
|
Packit |
3f21c4 |
jbig2_huffman_skip(hs);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
code1 = jbig2_arith_iaid_decode(IAID, as, (int32_t *) & ID);
|
|
Packit |
3f21c4 |
code2 = jbig2_arith_int_decode(IARDX, as, &RDX);
|
|
Packit |
3f21c4 |
code3 = jbig2_arith_int_decode(IARDY, as, &RDY);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if ((code1 < 0) || (code2 < 0) || (code3 < 0) || (code4 < 0)) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode data");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (ID >= ninsyms + NSYMSDECODED) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "refinement references unknown symbol %d", ID);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
|
|
Packit |
3f21c4 |
"symbol is a refinement of id %d with the " "refinement applied at (%d,%d)", ID, RDX, RDY);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
|
|
Packit |
3f21c4 |
if (image == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory creating symbol image");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* Table 18 */
|
|
Packit |
3f21c4 |
rparams.GRTEMPLATE = params->SDRTEMPLATE;
|
|
Packit |
3f21c4 |
rparams.reference = (ID < ninsyms) ? params->SDINSYMS->glyphs[ID] : SDNEWSYMS->glyphs[ID - ninsyms];
|
|
Packit |
3f21c4 |
/* SumatraPDF: fail on missing glyphs */
|
|
Packit |
3f21c4 |
if (rparams.reference == NULL) {
|
|
Packit |
3f21c4 |
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "missing glyph %d/%d!", ID, ninsyms);
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
rparams.DX = RDX;
|
|
Packit |
3f21c4 |
rparams.DY = RDY;
|
|
Packit |
3f21c4 |
rparams.TPGRON = 0;
|
|
Packit |
3f21c4 |
memcpy(rparams.grat, params->sdrat, 4);
|
|
Packit |
3f21c4 |
code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, image, GR_stats);
|
|
Packit |
3f21c4 |
if (code < 0)
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
SDNEWSYMS->glyphs[NSYMSDECODED] = image;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.8.2.2 (7) */
|
|
Packit |
3f21c4 |
if (params->SDHUFF) {
|
|
Packit |
3f21c4 |
if (BMSIZE == 0)
|
|
Packit |
3f21c4 |
BMSIZE = image->height * image->stride;
|
|
Packit |
3f21c4 |
jbig2_huffman_advance(hs, BMSIZE);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef OUTPUT_PBM
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
char name[64];
|
|
Packit |
3f21c4 |
FILE *out;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
snprintf(name, 64, "sd.%04d.%04d.pbm", segment->number, NSYMSDECODED);
|
|
Packit |
3f21c4 |
out = fopen(name, "wb");
|
|
Packit |
3f21c4 |
jbig2_image_write_pbm(SDNEWSYMS->glyphs[NSYMSDECODED], out);
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "writing out glyph as '%s' ...", name);
|
|
Packit |
3f21c4 |
fclose(out);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (4c.iii) */
|
|
Packit |
3f21c4 |
if (params->SDHUFF && !params->SDREFAGG) {
|
|
Packit |
3f21c4 |
SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (4c.iv) */
|
|
Packit |
3f21c4 |
NSYMSDECODED = NSYMSDECODED + 1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoded symbol %u of %u (%ux%u)", NSYMSDECODED, params->SDNUMNEWSYMS, SYMWIDTH, HCHEIGHT);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
} /* end height class decode loop */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.5 (4d) */
|
|
Packit |
3f21c4 |
if (params->SDHUFF && !params->SDREFAGG) {
|
|
Packit |
3f21c4 |
/* 6.5.9 */
|
|
Packit |
3f21c4 |
Jbig2Image *image;
|
|
Packit |
3f21c4 |
uint32_t BMSIZE = jbig2_huffman_get(hs, params->SDHUFFBMSIZE, &code);
|
|
Packit |
3f21c4 |
uint32_t j;
|
|
Packit |
3f21c4 |
int x;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (code) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding size of collective bitmap!");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* skip any bits before the next byte boundary */
|
|
Packit |
3f21c4 |
jbig2_huffman_skip(hs);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT);
|
|
Packit |
3f21c4 |
if (image == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate collective bitmap image!");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (BMSIZE == 0) {
|
|
Packit |
3f21c4 |
/* if BMSIZE == 0 bitmap is uncompressed */
|
|
Packit |
3f21c4 |
const byte *src = data + jbig2_huffman_offset(hs);
|
|
Packit |
3f21c4 |
const int stride = (image->width >> 3) + ((image->width & 7) ? 1 : 0);
|
|
Packit |
3f21c4 |
byte *dst = image->data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* SumatraPDF: prevent read access violation */
|
|
Packit |
3f21c4 |
if ((size - jbig2_huffman_offset(hs) < image->height * stride) || (size < jbig2_huffman_offset(hs))) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%d/%d)", image->height * stride,
|
|
Packit |
3f21c4 |
size - jbig2_huffman_offset(hs));
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
BMSIZE = image->height * stride;
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
|
|
Packit |
3f21c4 |
"reading %dx%d uncompressed bitmap" " for %d symbols (%d bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (j = 0; j < image->height; j++) {
|
|
Packit |
3f21c4 |
memcpy(dst, src, stride);
|
|
Packit |
3f21c4 |
dst += image->stride;
|
|
Packit |
3f21c4 |
src += stride;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
Jbig2GenericRegionParams rparams;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* SumatraPDF: prevent read access violation */
|
|
Packit |
3f21c4 |
if (size - jbig2_huffman_offset(hs) < BMSIZE) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%d/%d)", BMSIZE, size - jbig2_huffman_offset(hs));
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
|
|
Packit |
3f21c4 |
"reading %dx%d collective bitmap for %d symbols (%d bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
rparams.MMR = 1;
|
|
Packit |
3f21c4 |
code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data + jbig2_huffman_offset(hs), BMSIZE, image);
|
|
Packit |
3f21c4 |
if (code) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding MMR bitmap image!");
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* advance past the data we've just read */
|
|
Packit |
3f21c4 |
jbig2_huffman_advance(hs, BMSIZE);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* copy the collective bitmap into the symbol dictionary */
|
|
Packit |
3f21c4 |
x = 0;
|
|
Packit |
3f21c4 |
for (j = HCFIRSTSYM; j < NSYMSDECODED; j++) {
|
|
Packit |
3f21c4 |
Jbig2Image *glyph;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
glyph = jbig2_image_new(ctx, SDNEWSYMWIDTHS[j], HCHEIGHT);
|
|
Packit |
3f21c4 |
if (glyph == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to copy the collective bitmap into symbol dictionary");
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
jbig2_image_compose(ctx, glyph, image, -x, 0, JBIG2_COMPOSE_REPLACE);
|
|
Packit |
3f21c4 |
x += SDNEWSYMWIDTHS[j];
|
|
Packit |
3f21c4 |
SDNEWSYMS->glyphs[j] = glyph;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, image);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
} /* end of symbol decode loop */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 6.5.10 */
|
|
Packit |
3f21c4 |
SDEXSYMS = jbig2_sd_new(ctx, params->SDNUMEXSYMS);
|
|
Packit |
3f21c4 |
if (SDEXSYMS == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate symbols exported from symbols dictionary");
|
|
Packit |
3f21c4 |
goto cleanup4;
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
uint32_t i = 0;
|
|
Packit |
3f21c4 |
uint32_t j = 0;
|
|
Packit |
3f21c4 |
uint32_t k;
|
|
Packit |
3f21c4 |
int exflag = 0;
|
|
Packit |
3f21c4 |
uint32_t limit = params->SDNUMINSYMS + params->SDNUMNEWSYMS;
|
|
Packit |
3f21c4 |
uint32_t exrunlength;
|
|
Packit |
3f21c4 |
int zerolength = 0;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
while (i < limit) {
|
|
Packit |
3f21c4 |
if (params->SDHUFF)
|
|
Packit |
3f21c4 |
exrunlength = jbig2_huffman_get(hs, SBHUFFRSIZE, &code);
|
|
Packit |
3f21c4 |
else
|
|
Packit |
3f21c4 |
code = jbig2_arith_int_decode(IAEX, as, (int32_t *)&exrunlength);
|
|
Packit |
3f21c4 |
/* prevent infinite loop */
|
|
Packit |
3f21c4 |
zerolength = exrunlength > 0 ? 0 : zerolength + 1;
|
|
Packit |
3f21c4 |
if (code || (exrunlength > limit - i) || (zerolength > 4) || (exflag && (exrunlength + j > params->SDNUMEXSYMS))) {
|
|
Packit |
3f21c4 |
if (code)
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode exrunlength for exported symbols");
|
|
Packit |
3f21c4 |
else if (exrunlength <= 0)
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "runlength too small in export symbol table (%d <= 0)\n", exrunlength);
|
|
Packit |
3f21c4 |
else
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
|
|
Packit |
3f21c4 |
"runlength too large in export symbol table (%d > %d - %d)\n", exrunlength, params->SDNUMEXSYMS, j);
|
|
Packit |
3f21c4 |
/* skip to the cleanup code and return SDEXSYMS = NULL */
|
|
Packit |
3f21c4 |
jbig2_sd_release(ctx, SDEXSYMS);
|
|
Packit |
3f21c4 |
SDEXSYMS = NULL;
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
for (k = 0; k < exrunlength; k++) {
|
|
Packit |
3f21c4 |
if (exflag) {
|
|
Packit |
3f21c4 |
SDEXSYMS->glyphs[j++] = (i < params->SDNUMINSYMS) ?
|
|
Packit |
3f21c4 |
jbig2_image_clone(ctx, params->SDINSYMS->glyphs[i]) : jbig2_image_clone(ctx, SDNEWSYMS->glyphs[i - params->SDNUMINSYMS]);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
i++;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
exflag = !exflag;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
cleanup4:
|
|
Packit |
3f21c4 |
if (tparams != NULL) {
|
|
Packit |
3f21c4 |
if (!params->SDHUFF) {
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IADT);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IAFS);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IADS);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IAIT);
|
|
Packit |
3f21c4 |
jbig2_arith_iaid_ctx_free(ctx, tparams->IAID);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IARI);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IARDW);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IARDH);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IARDX);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, tparams->IARDY);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFFS);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFDS);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFDT);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFRDX);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFRDY);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFRDW);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, tparams->SBHUFFRDH);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, tparams);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (refagg_dicts != NULL) {
|
|
Packit |
3f21c4 |
if (refagg_dicts[0] != NULL)
|
|
Packit |
3f21c4 |
jbig2_sd_release(ctx, refagg_dicts[0]);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, refagg_dicts);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
cleanup2:
|
|
Packit |
3f21c4 |
jbig2_sd_release(ctx, SDNEWSYMS);
|
|
Packit |
3f21c4 |
if (params->SDHUFF && !params->SDREFAGG) {
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, SDHUFFRDX);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, SBHUFFRSIZE);
|
|
Packit |
3f21c4 |
jbig2_huffman_free(ctx, hs);
|
|
Packit |
3f21c4 |
jbig2_arith_iaid_ctx_free(ctx, IAID);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, IARDX);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, IARDY);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
cleanup1:
|
|
Packit |
3f21c4 |
jbig2_word_stream_buf_free(ctx, ws);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, as);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, IADH);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, IADW);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, IAEX);
|
|
Packit |
3f21c4 |
jbig2_arith_int_ctx_free(ctx, IAAI);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return SDEXSYMS;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2 */
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2SymbolDictParams params;
|
|
Packit |
3f21c4 |
uint16_t flags;
|
|
Packit |
3f21c4 |
uint32_t sdat_bytes;
|
|
Packit |
3f21c4 |
uint32_t offset;
|
|
Packit |
3f21c4 |
Jbig2ArithCx *GB_stats = NULL;
|
|
Packit |
3f21c4 |
Jbig2ArithCx *GR_stats = NULL;
|
|
Packit |
3f21c4 |
int table_index = 0;
|
|
Packit |
3f21c4 |
const Jbig2HuffmanParams *huffman_params;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (segment->data_length < 10)
|
|
Packit |
3f21c4 |
goto too_short;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.1.1 */
|
|
Packit |
3f21c4 |
flags = jbig2_get_uint16(segment_data);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* zero params to ease cleanup later */
|
|
Packit |
3f21c4 |
memset(¶ms, 0, sizeof(Jbig2SymbolDictParams));
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
params.SDHUFF = flags & 1;
|
|
Packit |
3f21c4 |
params.SDREFAGG = (flags >> 1) & 1;
|
|
Packit |
3f21c4 |
params.SDTEMPLATE = (flags >> 10) & 3;
|
|
Packit |
3f21c4 |
params.SDRTEMPLATE = (flags >> 12) & 1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (params.SDHUFF) {
|
|
Packit |
3f21c4 |
switch ((flags & 0x000c) >> 2) {
|
|
Packit |
3f21c4 |
case 0: /* Table B.4 */
|
|
Packit |
3f21c4 |
params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_D);
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case 1: /* Table B.5 */
|
|
Packit |
3f21c4 |
params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_E);
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case 3: /* Custom table from referred segment */
|
|
Packit |
3f21c4 |
huffman_params = jbig2_find_table(ctx, segment, table_index);
|
|
Packit |
3f21c4 |
if (huffman_params == NULL) {
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom DH huffman table not found (%d)", table_index);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
params.SDHUFFDH = jbig2_build_huffman_table(ctx, huffman_params);
|
|
Packit |
3f21c4 |
++table_index;
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case 2:
|
|
Packit |
3f21c4 |
default:
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (params.SDHUFFDH == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate DH huffman table");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
switch ((flags & 0x0030) >> 4) {
|
|
Packit |
3f21c4 |
case 0: /* Table B.2 */
|
|
Packit |
3f21c4 |
params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_B);
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case 1: /* Table B.3 */
|
|
Packit |
3f21c4 |
params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_C);
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case 3: /* Custom table from referred segment */
|
|
Packit |
3f21c4 |
huffman_params = jbig2_find_table(ctx, segment, table_index);
|
|
Packit |
3f21c4 |
if (huffman_params == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom DW huffman table not found (%d)", table_index);
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
params.SDHUFFDW = jbig2_build_huffman_table(ctx, huffman_params);
|
|
Packit |
3f21c4 |
++table_index;
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case 2:
|
|
Packit |
3f21c4 |
default:
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table");
|
|
Packit |
3f21c4 |
goto cleanup; /* Jump direct to cleanup to avoid 2 errors being given */
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (params.SDHUFFDW == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate DW huffman table");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (flags & 0x0040) {
|
|
Packit |
3f21c4 |
/* Custom table from referred segment */
|
|
Packit |
3f21c4 |
huffman_params = jbig2_find_table(ctx, segment, table_index);
|
|
Packit |
3f21c4 |
if (huffman_params == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom BMSIZE huffman table not found (%d)", table_index);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, huffman_params);
|
|
Packit |
3f21c4 |
++table_index;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
/* Table B.1 */
|
|
Packit |
3f21c4 |
params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (params.SDHUFFBMSIZE == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate BMSIZE huffman table");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (flags & 0x0080) {
|
|
Packit |
3f21c4 |
/* Custom table from referred segment */
|
|
Packit |
3f21c4 |
huffman_params = jbig2_find_table(ctx, segment, table_index);
|
|
Packit |
3f21c4 |
if (huffman_params == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom REFAGG huffman table not found (%d)", table_index);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, huffman_params);
|
|
Packit |
3f21c4 |
++table_index;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
/* Table B.1 */
|
|
Packit |
3f21c4 |
params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (params.SDHUFFAGGINST == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate REFAGG huffman table");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* FIXME: there are quite a few of these conditions to check */
|
|
Packit |
3f21c4 |
/* maybe #ifdef CONFORMANCE and a separate routine */
|
|
Packit |
3f21c4 |
if (!params.SDHUFF) {
|
|
Packit |
3f21c4 |
if (flags & 0x000c) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDH is not.");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (flags & 0x0030) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDW is not.");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (flags & 0x0080) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "bitmap coding context is used (NYI) symbol data likely to be garbage!");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.1.2 */
|
|
Packit |
3f21c4 |
sdat_bytes = params.SDHUFF ? 0 : params.SDTEMPLATE == 0 ? 8 : 2;
|
|
Packit |
3f21c4 |
memcpy(params.sdat, segment_data + 2, sdat_bytes);
|
|
Packit |
3f21c4 |
offset = 2 + sdat_bytes;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.1.3 */
|
|
Packit |
3f21c4 |
if (params.SDREFAGG && !params.SDRTEMPLATE) {
|
|
Packit |
3f21c4 |
if (offset + 4 > segment->data_length)
|
|
Packit |
3f21c4 |
goto too_short;
|
|
Packit |
3f21c4 |
memcpy(params.sdrat, segment_data + offset, 4);
|
|
Packit |
3f21c4 |
offset += 4;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (offset + 8 > segment->data_length)
|
|
Packit |
3f21c4 |
goto too_short;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.1.4 */
|
|
Packit |
3f21c4 |
params.SDNUMEXSYMS = jbig2_get_uint32(segment_data + offset);
|
|
Packit |
3f21c4 |
/* 7.4.2.1.5 */
|
|
Packit |
3f21c4 |
params.SDNUMNEWSYMS = jbig2_get_uint32(segment_data + offset + 4);
|
|
Packit |
3f21c4 |
offset += 8;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
|
|
Packit |
3f21c4 |
"symbol dictionary, flags=%04x, %u exported syms, %u new syms", flags, params.SDNUMEXSYMS, params.SDNUMNEWSYMS);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.2 (2) */
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
uint32_t n_dicts = jbig2_sd_count_referred(ctx, segment);
|
|
Packit |
3f21c4 |
Jbig2SymbolDict **dicts = NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (n_dicts > 0) {
|
|
Packit |
3f21c4 |
dicts = jbig2_sd_list_referred(ctx, segment);
|
|
Packit |
3f21c4 |
if (dicts == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate dicts in symbol dictionary");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
params.SDINSYMS = jbig2_sd_cat(ctx, n_dicts, dicts);
|
|
Packit |
3f21c4 |
if (params.SDINSYMS == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol array in symbol dictionary");
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, dicts);
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, dicts);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (params.SDINSYMS != NULL) {
|
|
Packit |
3f21c4 |
params.SDNUMINSYMS = params.SDINSYMS->n_symbols;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.2 (3, 4) */
|
|
Packit |
3f21c4 |
if (flags & 0x0100) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as used (NYI)");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
int stats_size = params.SDTEMPLATE == 0 ? 65536 : params.SDTEMPLATE == 1 ? 8192 : 1024;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
|
|
Packit |
3f21c4 |
if (GB_stats == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate GB_stats in jbig2_symbol_dictionary");
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
memset(GB_stats, 0, stats_size);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13;
|
|
Packit |
3f21c4 |
GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
|
|
Packit |
3f21c4 |
if (GR_stats == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate GR_stats in jbig2_symbol_dictionary");
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, GB_stats);
|
|
Packit |
3f21c4 |
goto cleanup;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
memset(GR_stats, 0, stats_size);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
segment->result = (void *)jbig2_decode_symbol_dict(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, GB_stats, GR_stats);
|
|
Packit |
3f21c4 |
#ifdef DUMP_SYMDICT
|
|
Packit |
3f21c4 |
if (segment->result)
|
|
Packit |
3f21c4 |
jbig2_dump_symbol_dict(ctx, segment);
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* 7.4.2.2 (7) */
|
|
Packit |
3f21c4 |
if (flags & 0x0200) {
|
|
Packit |
3f21c4 |
/* todo: retain GB_stats, GR_stats */
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, GR_stats);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, GB_stats);
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as retained (NYI)");
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, GR_stats);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, GB_stats);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
cleanup:
|
|
Packit |
3f21c4 |
if (params.SDHUFF) {
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, params.SDHUFFDH);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, params.SDHUFFDW);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE);
|
|
Packit |
3f21c4 |
jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
jbig2_sd_release(ctx, params.SDINSYMS);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return (segment->result != NULL) ? 0 : -1;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
too_short:
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
|
|
Packit |
3f21c4 |
}
|