ref: 65b4b234ef4c5d12d8d5f9d624d51595f9e8f14f
dir: /jbig2_symbol_dict.c/
/*
jbig2dec
Copyright (C) 2001-2002 artofcode LLC.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
$Id: jbig2_symbol_dict.c,v 1.20 2003/03/05 12:25:54 giles Exp $
symbol dictionary segment decode and support
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os_types.h"
#include <stddef.h>
#include <string.h> /* memset() */
#include "jbig2.h"
#include "jbig2_priv.h"
#include "jbig2_arith.h"
#include "jbig2_arith_int.h"
#include "jbig2_generic.h"
#include "jbig2_symbol_dict.h"
#if defined(OUTPUT_PBM) || defined(HAVE_LIBPNG)
#include <stdio.h>
#include "jbig2_image.h"
#endif
/* Table 13 */
typedef struct {
bool SDHUFF;
bool SDREFAGG;
int32_t SDNUMINSYMS;
/* SDINSYMS */
uint32_t SDNUMNEWSYMS;
uint32_t SDNUMEXSYMS;
/* SDHUFFDH */
/* SDHUFFDW */
/* SDHUFFBMSIZE */
/* SDHUFFAGGINST */
int SDTEMPLATE;
int8_t sdat[8];
bool SDRTEMPLATE;
int8_t sdrat[4];
} Jbig2SymbolDictParams;
#ifdef DEBUG
void
jbig2_dump_symbol_dict(Jbig2SymbolDict *dict)
{
int index;
char filename[24];
fprintf(stderr, "dumping symbol dict as %d individual png files\n", dict->n_symbols);
for (index = 0; index < dict->n_symbols; index++) {
snprintf(filename, sizeof(filename), "symbol_%04d.png", index);
#ifdef HAVE_LIBPNG
jbig2_image_write_png_file(dict->glyphs[index], filename);
#else
jbig2_image_write_pbm_file(dict->glyphs[index], filename);
#endif
}
}
#endif /* DEBUG */
/* 6.5 */
static Jbig2SymbolDict *
jbig2_decode_symbol_dict(Jbig2Ctx *ctx,
Jbig2Segment *segment,
const Jbig2SymbolDictParams *params,
const byte *data, size_t size,
Jbig2ArithCx *GB_stats)
{
Jbig2SymbolDict *SDNEWSYMS;
int32_t HCHEIGHT;
uint32_t NSYMSDECODED;
int32_t SYMWIDTH, TOTWIDTH;
uint32_t HCFIRSTSYM;
Jbig2ArithState *as = NULL;
Jbig2ArithIntCtx *IADH = NULL;
Jbig2ArithIntCtx *IADW = NULL;
int code;
/* 6.5.5 (3) */
HCHEIGHT = 0;
NSYMSDECODED = 0;
if (!params->SDHUFF)
{
Jbig2WordStream *ws = jbig2_word_stream_buf_new(ctx, data, size);
as = jbig2_arith_new(ctx, ws);
IADH = jbig2_arith_int_ctx_new(ctx);
IADW = jbig2_arith_int_ctx_new(ctx);
}
SDNEWSYMS = jbig2_alloc(ctx->allocator, params->SDNUMNEWSYMS * sizeof(*SDNEWSYMS));
SDNEWSYMS->n_symbols = params->SDNUMNEWSYMS;
SDNEWSYMS->glyphs = (Jbig2Image **)jbig2_alloc(ctx->allocator, SDNEWSYMS->n_symbols * sizeof(Jbig2Image*));
/* 6.5.5 (4a) */
while (NSYMSDECODED < params->SDNUMNEWSYMS)
{
int32_t HCDH, DW;
/* 6.5.6 */
if (params->SDHUFF)
; /* todo */
else
{
code = jbig2_arith_int_decode(IADH, as, &HCDH);
}
/* 6.5.5 (4b) */
HCHEIGHT = HCHEIGHT + HCDH;
SYMWIDTH = 0;
TOTWIDTH = 0;
HCFIRSTSYM = NSYMSDECODED;
if (HCHEIGHT < 0)
{
/* todo: mem cleanup */
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"Invalid HCHEIGHT value");
return NULL;
}
#ifdef DEBUG
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
"HCHEIGHT = %d", HCHEIGHT);
#endif
for (;;)
{
/* 6.5.7 */
if (params->SDHUFF)
; /* todo */
else
{
code = jbig2_arith_int_decode(IADW, as, &DW);
}
/* 6.5.5 (4c.i) */
if (code == 1)
break;
SYMWIDTH = SYMWIDTH + DW;
TOTWIDTH = TOTWIDTH + SYMWIDTH;
if (SYMWIDTH < 0)
{
/* todo: mem cleanup */
code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"Invalid SYMWIDTH value");
return NULL;
}
#ifdef DEBUG
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
"SYMWIDTH = %d", SYMWIDTH);
#endif
/* 6.5.5 (4c.ii) */
if (!params->SDHUFF || params->SDREFAGG)
{
/* 6.5.8 */
if (!params->SDREFAGG)
{
Jbig2GenericRegionParams region_params;
int sdat_bytes;
Jbig2Image *image;
/* Table 16 */
region_params.MMR = 0;
region_params.GBTEMPLATE = params->SDTEMPLATE;
region_params.TPGDON = 0;
region_params.USESKIP = 0;
sdat_bytes = params->SDTEMPLATE == 0 ? 8 : 2;
memcpy(region_params.gbat, params->sdat, sdat_bytes);
image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT);
code = jbig2_decode_generic_region(ctx, segment, ®ion_params,
as, image, GB_stats);
/* todo: handle errors */
SDNEWSYMS->glyphs[NSYMSDECODED] = image;
#ifdef OUTPUT_PBM
jbig2_image_write_pbm(image, stdout);
#endif
}
}
/* 6.5.5 (4c.iv) */
NSYMSDECODED = NSYMSDECODED + 1;
#ifdef DEBUG
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
"%d of %d decoded", NSYMSDECODED, params->SDNUMNEWSYMS);
#endif
}
}
jbig2_free(ctx->allocator, GB_stats);
return SDNEWSYMS;
}
/* 7.4.2 */
int
jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment,
const byte *segment_data)
{
Jbig2SymbolDictParams params;
uint16_t flags;
int sdat_bytes;
int offset;
Jbig2ArithCx *GB_stats = NULL;
if (segment->data_length < 10)
goto too_short;
/* 7.4.2.1.1 */
flags = jbig2_get_int16(segment_data);
params.SDHUFF = flags & 1;
params.SDREFAGG = (flags >> 1) & 1;
params.SDTEMPLATE = (flags >> 10) & 3;
params.SDRTEMPLATE = (flags >> 12) & 1;
if (params.SDHUFF) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"symbol dictionary uses the Huffman encoding variant (NYI)");
return 0;
}
/* FIXME: there are quite a few of these conditions to check */
/* maybe #ifdef CONFORMANCE and a separate routine */
if(!params.SDHUFF && (flags & 0x000c))
{
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"SDHUFF is zero, but contrary to spec SDHUFFDH is not.");
}
if(!params.SDHUFF && (flags & 0x0030))
{
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"SDHUFF is zero, but contrary to spec SDHUFFDW is not.");
}
if (flags & 0x0080)
{
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"bitmap coding context is used (NYI) symbol data likely to be garbage!");
}
/* 7.4.2.1.2 */
sdat_bytes = params.SDHUFF ? 0 : params.SDTEMPLATE == 0 ? 8 : 2;
memcpy(params.sdat, segment_data + 2, sdat_bytes);
offset = 2 + sdat_bytes;
/* 7.4.2.1.3 */
if (params.SDREFAGG && !params.SDRTEMPLATE)
{
if (offset + 4 > segment->data_length)
goto too_short;
memcpy(params.sdrat, segment_data + offset, 4);
offset += 4;
}
if (offset + 8 > segment->data_length)
goto too_short;
/* 7.4.2.1.4 */
params.SDNUMEXSYMS = jbig2_get_int32(segment_data + offset);
/* 7.4.2.1.5 */
params.SDNUMNEWSYMS = jbig2_get_int32(segment_data + offset + 4);
offset += 8;
jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
"symbol dictionary, flags=%04x, %d exported syms, %d new syms",
flags, params.SDNUMEXSYMS, params.SDNUMNEWSYMS);
/* 7.4.2.2 (4) */
if (!params.SDHUFF)
{
int stats_size = params.SDTEMPLATE == 0 ? 65536 :
params.SDTEMPLATE == 1 ? 8192 : 1024;
GB_stats = jbig2_alloc(ctx->allocator, stats_size);
memset(GB_stats, 0, stats_size);
}
if (flags & 0x0100)
{
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
"segment marks bitmap coding context as retained (NYI)");
}
segment->result = (void *)jbig2_decode_symbol_dict(ctx, segment,
¶ms,
segment_data + offset,
segment->data_length - offset,
GB_stats);
#ifdef DEBUG
jbig2_dump_symbol_dict(segment->result);
#endif
return 0;
/* todo: retain or free GB_stats */
too_short:
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
"Segment too short");
}