ref: c4b1d31271695d1eeda60abcd3fd540dd24d4cc0
parent: 36eea46cc5e00f504952353091210b095c7587f7
author: Sebastian Rasmussen <sebras@gmail.com>
date: Tue Apr 24 22:47:39 EDT 2018
jbig2dec: Share arithmetic/huffman decoding contexts/tables. Previously text regions had their own arithmetic/huffman decoding contexts/tables, separate from those used to decode fields in the symbol dictionary itself. This is incorrect. Annex E.3.7 describes how to reset the arithmetic coding contexts. Only the top-level symbol dictionary decoding procedure described in chapter 7.4.2.2 references this annex. Neither the symbol dictionary decoding procedure outlined in chapter 6.5 in the specification, nor chapter 6.5.8 describing how to decode the symbol bitmap itself (and thereby implicitly chapter 6.2 describing the generic region decoding procedure, 6.4 explaining the text region decoding procedure and 6.5.8.2.2 describing how to decode bitmaps with only one symbol in the refinement/aggregate coding) refer to annex E.3.7. It is therefore incorrect to separate the arithmetic integer decoding contexts from the ones used to parse the symbol dictionary fields as the specification calls for these to be reused. This created a problem when decoding page 3 in the sample bitstream in Annex H.1. More specifically in Annex H.1, step 37 (f) xi E where the refinement flag was decoded as 3 instead of the expected 0. This was because the IAID arithmetic coding context used in step 37 (f) xi D had not been shared with that in step 37 (f) v as is expected in the specification. The result was that page 3 of the sample bitstream was never decoded. Potentially this may also have affected other JBIG2 bitstreams. Sharing the arithmetic coding contexts between the symbol dictionary decoding procedure and the text region decoder resolves the issue
--- a/jbig2_symbol_dict.c
+++ b/jbig2_symbol_dict.c
@@ -239,17 +239,11 @@
int SBSYMCODELEN = 0;
Jbig2WordStream *ws = NULL;
Jbig2HuffmanState *hs = NULL;
- Jbig2HuffmanTable *SDHUFFRDX = NULL;
- Jbig2HuffmanTable *SDHUFFRDY = NULL;
- Jbig2HuffmanTable *SBHUFFRSIZE = NULL;
Jbig2ArithState *as = NULL;
Jbig2ArithIntCtx *IADH = NULL;
Jbig2ArithIntCtx *IADW = NULL;
Jbig2ArithIntCtx *IAEX = NULL;
Jbig2ArithIntCtx *IAAI = NULL;
- Jbig2ArithIaidCtx *IAID = NULL;
- Jbig2ArithIntCtx *IARDX = NULL;
- Jbig2ArithIntCtx *IARDY = NULL;
int code = 0;
Jbig2SymbolDict **refagg_dicts = NULL;
uint32_t i;
@@ -279,10 +273,11 @@
if (params->SDHUFF) {
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded symbol dictionary");
hs = jbig2_huffman_new(ctx, ws);
- SDHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
- SDHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O);
- SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A);
- if (hs == NULL || SDHUFFRDX == NULL || SDHUFFRDY == NULL || SBHUFFRSIZE == NULL) {
+ tparams.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
+ tparams.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
+ tparams.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); /* Table B.1 */
+ if (hs == NULL || tparams.SBHUFFRDX == NULL ||
+ tparams.SBHUFFRDY == NULL || tparams.SBHUFFRSIZE == NULL) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap");
goto cleanup;
}
@@ -292,6 +287,18 @@
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate storage for (%u) symbol widths", params->SDNUMNEWSYMS);
goto cleanup;
}
+ } else {
+ tparams.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F); /* Table B.6 */
+ tparams.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H); /* Table B.8 */
+ tparams.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K); /* Table B.11 */
+ tparams.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
+ tparams.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
+ if (tparams.SBHUFFFS == NULL || tparams.SBHUFFDS == NULL ||
+ tparams.SBHUFFDT == NULL || tparams.SBHUFFRDW == NULL ||
+ tparams.SBHUFFRDH == NULL) {
+ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory creating text region huffman decoder entries");
+ goto cleanup;
+ }
}
} else {
IADH = jbig2_arith_int_ctx_new(ctx);
@@ -302,61 +309,33 @@
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap");
goto cleanup;
}
- if (params->SDREFAGG) {
- int64_t tmp = params->SDNUMINSYMS + params->SDNUMNEWSYMS;
-
- for (SBSYMCODELEN = 0; ((int64_t) 1 << SBSYMCODELEN) < tmp; SBSYMCODELEN++);
- IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
- IARDX = jbig2_arith_int_ctx_new(ctx);
- IARDY = jbig2_arith_int_ctx_new(ctx);
- if (IAID == NULL || IARDX == NULL || IARDY == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap");
- goto cleanup;
- }
- }
- }
-
- /* First time through, we need to initialise the */
- /* various tables for Huffman or adaptive encoding */
- /* as well as the text region parameters structure */
- if (params->SDHUFF) {
- tparams.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F); /* Table B.6 */
- tparams.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H); /* Table B.8 */
- tparams.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K); /* Table B.11 */
- tparams.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
- tparams.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
- tparams.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
- tparams.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */
- tparams.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); /* Table B.1 */
- if (tparams.SBHUFFFS == NULL || tparams.SBHUFFDS == NULL ||
- tparams.SBHUFFDT == NULL || tparams.SBHUFFRDW == NULL ||
- tparams.SBHUFFRDH == NULL || tparams.SBHUFFRDX == NULL ||
- tparams.SBHUFFRDY == NULL || tparams.SBHUFFRSIZE == NULL) {
- jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory creating text region huffman decoder entries");
- goto cleanup;
- }
- } else {
- /* Values from Table 17, section 6.5.8.2 (2) */
- tparams.IADT = jbig2_arith_int_ctx_new(ctx);
- tparams.IAFS = jbig2_arith_int_ctx_new(ctx);
- tparams.IADS = jbig2_arith_int_ctx_new(ctx);
- tparams.IAIT = jbig2_arith_int_ctx_new(ctx);
- /* Table 31 */
for (SBSYMCODELEN = 0; ((uint64_t) 1 << SBSYMCODELEN) < ((uint64_t) params->SDNUMINSYMS + params->SDNUMNEWSYMS); SBSYMCODELEN++);
tparams.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN);
- tparams.IARI = jbig2_arith_int_ctx_new(ctx);
- tparams.IARDW = jbig2_arith_int_ctx_new(ctx);
- tparams.IARDH = jbig2_arith_int_ctx_new(ctx);
tparams.IARDX = jbig2_arith_int_ctx_new(ctx);
tparams.IARDY = jbig2_arith_int_ctx_new(ctx);
- if (tparams.IADT == NULL || tparams.IAFS == NULL ||
- tparams.IADS == NULL || tparams.IAIT == NULL ||
- tparams.IAID == NULL || tparams.IARI == NULL ||
- tparams.IARDW == NULL || tparams.IARDH == NULL ||
- tparams.IARDX == NULL || tparams.IARDY == NULL) {
+ if (tparams.IAID == NULL || tparams.IARDX == NULL ||
+ tparams.IARDY == NULL) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "out of memory creating text region arith decoder entries");
goto cleanup;
}
+ if (params->SDREFAGG) {
+ /* Values from Table 17, section 6.5.8.2 (2) */
+ tparams.IADT = jbig2_arith_int_ctx_new(ctx);
+ tparams.IAFS = jbig2_arith_int_ctx_new(ctx);
+ tparams.IADS = jbig2_arith_int_ctx_new(ctx);
+ tparams.IAIT = jbig2_arith_int_ctx_new(ctx);
+ /* Table 31 */
+ tparams.IARI = jbig2_arith_int_ctx_new(ctx);
+ tparams.IARDW = jbig2_arith_int_ctx_new(ctx);
+ tparams.IARDH = jbig2_arith_int_ctx_new(ctx);
+ if (tparams.IADT == NULL || tparams.IAFS == NULL ||
+ tparams.IADS == NULL || tparams.IAIT == NULL ||
+ tparams.IARI == NULL || tparams.IARDW == NULL ||
+ tparams.IARDH == NULL) {
+ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "out of memory creating text region arith decoder entries");
+ goto cleanup;
+ }
+ }
}
tparams.SBHUFF = params->SDHUFF;
tparams.SBREFINE = 1;
@@ -368,7 +347,6 @@
tparams.SBDSOFFSET = 0;
tparams.SBRTEMPLATE = params->SDRTEMPLATE;
-
SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS);
if (SDNEWSYMS == NULL) {
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "could not allocate storage for (%u) new symbols", params->SDNUMNEWSYMS);
@@ -554,14 +532,14 @@
/* 6.5.8.2.2 (2, 3, 4, 5) */
if (params->SDHUFF) {
ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code1);
- RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code2);
- RDY = jbig2_huffman_get(hs, SDHUFFRDY, &code3);
- BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code4);
+ RDX = jbig2_huffman_get(hs, tparams.SBHUFFRDX, &code2);
+ RDY = jbig2_huffman_get(hs, tparams.SBHUFFRDY, &code3);
+ BMSIZE = jbig2_huffman_get(hs, tparams.SBHUFFRSIZE, &code4);
code5 = jbig2_huffman_skip(hs);
} else {
- code1 = jbig2_arith_iaid_decode(ctx, IAID, as, (int32_t *) & ID);
- code2 = jbig2_arith_int_decode(ctx, IARDX, as, &RDX);
- code3 = jbig2_arith_int_decode(ctx, IARDY, as, &RDY);
+ code1 = jbig2_arith_iaid_decode(ctx, tparams.IAID, as, (int32_t *) & ID);
+ code2 = jbig2_arith_int_decode(ctx, tparams.IARDX, as, &RDX);
+ code3 = jbig2_arith_int_decode(ctx, tparams.IARDY, as, &RDY);
}
if (code1 < 0 || code2 < 0 || code3 < 0 || code4 < 0 || code5 < 0) {
@@ -771,7 +749,7 @@
while (i < limit) {
if (params->SDHUFF)
- EXRUNLENGTH = jbig2_huffman_get(hs, SBHUFFRSIZE, &code);
+ EXRUNLENGTH = jbig2_huffman_get(hs, tparams.SBHUFFRSIZE, &code);
else
code = jbig2_arith_int_decode(ctx, IAEX, as, (int32_t *) &EXRUNLENGTH);
if (code < 0) {
@@ -816,6 +794,13 @@
cleanup:
jbig2_image_release(ctx, glyph);
jbig2_image_release(ctx, image);
+ if (refagg_dicts != NULL) {
+ if (refagg_dicts[0] != NULL)
+ jbig2_sd_release(ctx, refagg_dicts[0]);
+ /* skip releasing refagg_dicts[1] as that is the same as SDNEWSYMS */
+ jbig2_free(ctx->allocator, refagg_dicts);
+ }
+ jbig2_sd_release(ctx, SDNEWSYMS);
if (params->SDHUFF) {
jbig2_release_huffman_table(ctx, tparams.SBHUFFRSIZE);
jbig2_release_huffman_table(ctx, tparams.SBHUFFRDY);
@@ -825,6 +810,10 @@
jbig2_release_huffman_table(ctx, tparams.SBHUFFDT);
jbig2_release_huffman_table(ctx, tparams.SBHUFFDS);
jbig2_release_huffman_table(ctx, tparams.SBHUFFFS);
+ if (!params->SDREFAGG) {
+ jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
+ }
+ jbig2_huffman_free(ctx, hs);
} else {
jbig2_arith_int_ctx_free(ctx, tparams.IARDY);
jbig2_arith_int_ctx_free(ctx, tparams.IARDX);
@@ -836,28 +825,6 @@
jbig2_arith_int_ctx_free(ctx, tparams.IADS);
jbig2_arith_int_ctx_free(ctx, tparams.IAFS);
jbig2_arith_int_ctx_free(ctx, tparams.IADT);
- }
- if (refagg_dicts != NULL) {
- if (refagg_dicts[0] != NULL)
- jbig2_sd_release(ctx, refagg_dicts[0]);
- /* skip releasing refagg_dicts[1] as that is the same as SDNEWSYMS */
- jbig2_free(ctx->allocator, refagg_dicts);
- }
- jbig2_sd_release(ctx, SDNEWSYMS);
- if (params->SDHUFF) {
- if (!params->SDREFAGG) {
- jbig2_free(ctx->allocator, SDNEWSYMWIDTHS);
- }
- jbig2_release_huffman_table(ctx, SBHUFFRSIZE);
- jbig2_release_huffman_table(ctx, SDHUFFRDY);
- jbig2_release_huffman_table(ctx, SDHUFFRDX);
- jbig2_huffman_free(ctx, hs);
- } else {
- if (params->SDREFAGG) {
- jbig2_arith_iaid_ctx_free(ctx, IAID);
- jbig2_arith_int_ctx_free(ctx, IARDX);
- jbig2_arith_int_ctx_free(ctx, IARDY);
- }
jbig2_arith_int_ctx_free(ctx, IAAI);
jbig2_arith_int_ctx_free(ctx, IAEX);
jbig2_arith_int_ctx_free(ctx, IADW);