Blame jbig2_symbol_dict.c

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, &region_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(&params, 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, &params, 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
}