diff options
Diffstat (limited to 'jbig2dec')
30 files changed, 1593 insertions, 898 deletions
diff --git a/jbig2dec/CHANGES b/jbig2dec/CHANGES index 052a0382..f0101b8b 100644 --- a/jbig2dec/CHANGES +++ b/jbig2dec/CHANGES @@ -1,14 +1,21 @@ -Version 0.17 (2019 October 1) +Version 0.18 (2020 February 11) -* Updated documentation with accurate contact information. +* Performance enhancements related to decoding of MMR and generic + regions as well as composing images onto pages. + +* Bug fixes for a few issues reported by Coverity and OSS-Fuzz. + +Version 0.17 (2019 September 16) + +* Improved test suite by verifying input file contents and adding + all ubc test streams. Fixed bugs where previously missing ubc + test streams were decoded incorrectly. + +* Bug fixes for a few issues reported by Coverity. * Moved version number to jbig2.h, and adapted configure correspondingly. Added pkg-config file to be installed - along side library. Added run-time check of version - number so that the correct header is used with the matching - binary library. - -* Bug fixes. + along side library. Version 0.16 (2019 April 04) diff --git a/jbig2dec/Makefile.am b/jbig2dec/Makefile.am index e207b7a7..da46c350 100644 --- a/jbig2dec/Makefile.am +++ b/jbig2dec/Makefile.am @@ -12,7 +12,7 @@ AM_CFLAGS = $(XCFLAGS) libjbig2dec_la_LDFLAGS = -version-info @JBIG2DEC_LT_CURRENT@:@JBIG2DEC_LT_REVISION@:@JBIG2DEC_LT_AGE@ -no-undefined libjbig2dec_la_SOURCES = jbig2.c \ - jbig2_arith.c jbig2_arith_int.c jbig2_arith_iaid.c jbig2_huffman.c \ + jbig2_arith.c jbig2_arith_int.c jbig2_arith_iaid.c jbig2_huffman.c jbig2_hufftab.c \ jbig2_segment.c jbig2_page.c \ jbig2_symbol_dict.c jbig2_text.c \ jbig2_generic.c jbig2_refinement.c jbig2_mmr.c \ diff --git a/jbig2dec/Makefile.unix b/jbig2dec/Makefile.unix index 24bb12d1..cd386b5d 100644 --- a/jbig2dec/Makefile.unix +++ b/jbig2dec/Makefile.unix @@ -8,9 +8,9 @@ CFLAGS := -Wall -Wextra -Wno-unused-parameter -g -O2 LIB_SRCS := \ jbig2_arith.c jbig2_arith_int.c jbig2_arith_iaid.c \ - jbig2_huffman.c jbig2_segment.c jbig2_page.c jbig2_symbol_dict.c \ - jbig2_text.c jbig2_halftone.c jbig2_generic.c jbig2_refinement.c \ - jbig2_mmr.c jbig2_image.c jbig2.c + jbig2_huffman.c jbig2_hufftab.c jbig2_segment.c jbig2_page.c \ + jbig2_symbol_dict.c jbig2_text.c jbig2_halftone.c jbig2_generic.c \ + jbig2_refinement.c jbig2_mmr.c jbig2_image.c jbig2.c LIB_OBJS := $(LIB_SRCS:%.c=%.o) LIB_HDRS := \ jbig2.h jbig2_arith.h jbig2_arith_iaid.h jbig2_arith_int.h \ diff --git a/jbig2dec/autogen.sh b/jbig2dec/autogen.sh index 1dbe143c..41a5d971 100755 --- a/jbig2dec/autogen.sh +++ b/jbig2dec/autogen.sh @@ -22,7 +22,7 @@ VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/" VERSIONMKMAJ="sed -e s/\([0-9][0-9]*\)[^0-9].*/\\1/" VERSIONMKMIN="sed -e s/.*[0-9][0-9]*\.//" -JBIG2VERSIONGREP="sed -e s/^.*(\([0-9]\+\)).*/\\1/" +JBIG2VERSIONGREP="sed -e s/^.*(\([0-9][0-9]*\)).*/\\1/" JBIG2MAJOR=$(grep 'define JBIG2_VERSION_MAJOR' jbig2.h | $JBIG2VERSIONGREP) JBIG2MINOR=$(grep 'define JBIG2_VERSION_MINOR' jbig2.h | $JBIG2VERSIONGREP) sed -e "s/^\(AC_INIT[^,]*,\)[^,]*\(,.*\)$/\1 [$JBIG2MAJOR.$JBIG2MINOR]\2/" configure.ac.in > configure.ac diff --git a/jbig2dec/config_win32.h b/jbig2dec/config_win32.h index cef8acdb..959d07e4 100644 --- a/jbig2dec/config_win32.h +++ b/jbig2dec/config_win32.h @@ -41,6 +41,15 @@ typedef unsigned __int64 uint64_t; /* VS 2008 and later have vsnprintf */ # if _MSC_VER < 1500 # define vsnprintf _vsnprintf +/* Previously we defined inline as nothing for 2005 and below */ +# define inline +#else +/* VS 2008 has __inline but not inline, later versiosn (unknown exactly where) define inline + * so cater for it being defined already. + */ +# if !(defined(inline)) +# define inline __inline +# endif # endif /* VS 2014 and later have (finally) snprintf */ diff --git a/jbig2dec/jbig2.c b/jbig2dec/jbig2.c index 07c7969f..3fc6bf86 100644 --- a/jbig2dec/jbig2.c +++ b/jbig2dec/jbig2.c @@ -179,24 +179,32 @@ jbig2_ctx_new_imp(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCt #define get_int16(bptr)\ (((int)get_uint16(bptr) ^ 0x8000) - 0x8000) +/* coverity[ -tainted_data_return ] */ +/* coverity[ -tainted_data_argument : arg-0 ] */ int16_t jbig2_get_int16(const byte *bptr) { return get_int16(bptr); } +/* coverity[ -tainted_data_return ] */ +/* coverity[ -tainted_data_argument : arg-0 ] */ uint16_t jbig2_get_uint16(const byte *bptr) { return get_uint16(bptr); } +/* coverity[ -tainted_data_return ] */ +/* coverity[ -tainted_data_argument : arg-0 ] */ int32_t jbig2_get_int32(const byte *bptr) { return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2); } +/* coverity[ -tainted_data_return ] */ +/* coverity[ -tainted_data_argument : arg-0 ] */ uint32_t jbig2_get_uint32(const byte *bptr) { @@ -373,7 +381,7 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) p += 4; segment->data_length = p - s; - jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "unknown length determined to be %u", segment->data_length); + jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "unknown length determined to be %lu", (long) segment->data_length); } else if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix) return 0; /* need more data */ @@ -384,7 +392,7 @@ jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) if (ctx->state == JBIG2_FILE_RANDOM_BODIES) { if (ctx->segment_index == ctx->n_segments) ctx->state = JBIG2_FILE_EOF; - } else { /* JBIG2_FILE_SEQUENCIAL_BODY */ + } else { /* JBIG2_FILE_SEQUENTIAL_BODY */ ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER; } if (code < 0) { diff --git a/jbig2dec/jbig2.h b/jbig2dec/jbig2.h index 16bb95ac..fb195fec 100644 --- a/jbig2dec/jbig2.h +++ b/jbig2dec/jbig2.h @@ -26,7 +26,7 @@ extern "C" #define _JBIG2_H #define JBIG2_VERSION_MAJOR (0) -#define JBIG2_VERSION_MINOR (17) +#define JBIG2_VERSION_MINOR (18) /* warning levels */ typedef enum { @@ -106,6 +106,11 @@ int jbig2_complete_page(Jbig2Ctx *ctx); #endif /* _JBIG2_H */ +/* If we don't have a definition for inline, make it nothing so the code will compile */ +#ifndef inline +#define inline +#endif + #ifdef __cplusplus } #endif diff --git a/jbig2dec/jbig2_arith.c b/jbig2dec/jbig2_arith.c index 6416fad6..04566337 100644 --- a/jbig2dec/jbig2_arith.c +++ b/jbig2dec/jbig2_arith.c @@ -42,21 +42,16 @@ struct _Jbig2ArithState { int offset; }; -#undef SOFTWARE_CONVENTION - /* - A note on the "software conventions". - - Previously, I had misinterpreted the spec, and had thought that the - spec's description of the "software convention" was wrong. Now I - believe that this code is both correct and matches the spec, with - SOFTWARE_CONVENTION defined or not. Thanks to William Rucklidge for - the clarification. - - In any case, my benchmarking indicates no speed difference at all. - Therefore, for now we will just use the normative version. - - */ + Previous versions of this code had a #define to allow + us to choose between using the revised arithmetic decoding + specified in the 'Software Convention' section of the spec. + Back to back tests showed that the 'Software Convention' + version was indeed slightly faster. We therefore enable it + by default. We also strip the option out, because a) it + makes the code harder to read, and b) such things are an + invitation to bitrot. +*/ static void jbig2_arith_bytein(Jbig2ArithState *as) @@ -66,6 +61,23 @@ jbig2_arith_bytein(Jbig2ArithState *as) /* invariant: as->next_word_bytes > 0 */ + /* This code confused me no end when I first read it, so a quick note + * to save others (and future me's) from being similarly confused. + * 'next_word' does indeed contain 'next_word_bytes' of valid data + * (always starting at the most significant byte). The confusing + * thing is that the first byte has always already been read. + * i.e. it serves only as an indication that the last byte we read + * was FF or not. + * + * The jbig2 bytestream uses FF bytes, followed by a byte > 0x8F as + * marker bytes. These never occur in normal streams of arithmetic + * encoding, so meeting one terminates the stream (with an infinite + * series of 1 bits). + * + * If we meet an FF byte, we return it as normal. We just 'remember' + * that fact for the next byte we read. + */ + /* Figure G.3 */ B = (byte)((as->next_word >> 24) & 0xFF); if (B == 0xFF) { @@ -83,9 +95,6 @@ jbig2_arith_bytein(Jbig2ArithState *as) #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (aa)\n", B); #endif -#ifndef SOFTWARE_CONVENTION - as->C += 0xFF00; -#endif as->CT = 8; as->next_word = 0xFF000000 | (as->next_word >> 8); as->next_word_bytes = 4; @@ -94,11 +103,7 @@ jbig2_arith_bytein(Jbig2ArithState *as) #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (a)\n", B); #endif -#ifdef SOFTWARE_CONVENTION as->C += 0xFE00 - (B1 << 9); -#else - as->C += B1 << 9; -#endif as->CT = 7; } } else { @@ -107,9 +112,6 @@ jbig2_arith_bytein(Jbig2ArithState *as) #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (ba)\n", B); #endif -#ifndef SOFTWARE_CONVENTION - as->C += 0xFF00; -#endif as->CT = 8; } else { as->next_word_bytes--; @@ -118,11 +120,7 @@ jbig2_arith_bytein(Jbig2ArithState *as) fprintf(stderr, "read %02x (b)\n", B); #endif -#ifdef SOFTWARE_CONVENTION as->C += 0xFE00 - (B1 << 9); -#else - as->C += (B1 << 9); -#endif as->CT = 7; } } @@ -141,11 +139,7 @@ jbig2_arith_bytein(Jbig2ArithState *as) as->next_word_bytes = new_bytes; } B = (byte)((as->next_word >> 24) & 0xFF); -#ifdef SOFTWARE_CONVENTION as->C += 0xFF00 - (B << 8); -#else - as->C += (B << 8); -#endif } } @@ -172,11 +166,7 @@ jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws) result->offset = new_bytes; /* Figure E.20 */ -#ifdef SOFTWARE_CONVENTION result->C = (~(result->next_word >> 8)) & 0xFF0000; -#else - result->C = (result->next_word >> 8) & 0xFF0000; -#endif jbig2_arith_bytein(result); result->C <<= 7; @@ -195,7 +185,7 @@ typedef struct { byte lps_xor; /* lps_xor = index ^ NLPS ^ (SWITCH << 7) */ } Jbig2ArithQe; -const Jbig2ArithQe jbig2_arith_Qe[MAX_QE_ARRAY_SIZE] = { +static const Jbig2ArithQe jbig2_arith_Qe[MAX_QE_ARRAY_SIZE] = { {0x5601, 1 ^ 0, 1 ^ 0 ^ 0x80}, {0x3401, 2 ^ 1, 6 ^ 1}, {0x1801, 3 ^ 2, 9 ^ 2}, @@ -258,34 +248,22 @@ jbig2_arith_renormd(Jbig2ArithState *as) } while ((as->A & 0x8000) == 0); } -bool -jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx, int *code) +int +jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx) { Jbig2ArithCx cx = *pcx; const Jbig2ArithQe *pqe; unsigned int index = cx & 0x7f; bool D; - if (index >= MAX_QE_ARRAY_SIZE) { - *code = -1; - return 0; - } else { - pqe = &jbig2_arith_Qe[index]; - } + if (index >= MAX_QE_ARRAY_SIZE) + return -1; /* Error */ + + pqe = &jbig2_arith_Qe[index]; /* Figure E.15 */ as->A -= pqe->Qe; - if ( -#ifdef SOFTWARE_CONVENTION - /* Note: I do not think this is correct. See above. */ - (as->C >> 16) < as->A -#else - !((as->C >> 16) < pqe->Qe) -#endif - ) { -#ifndef SOFTWARE_CONVENTION - as->C -= pqe->Qe << 16; -#endif + if ((as->C >> 16) < as->A) { if ((as->A & 0x8000) == 0) { /* MPS_EXCHANGE, Figure E.16 */ if (as->A < pqe->Qe) { @@ -296,16 +274,12 @@ jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx, int *code) *pcx ^= pqe->mps_xor; } jbig2_arith_renormd(as); - *code = 0; return D; } else { - *code = 0; return cx >> 7; } } else { -#ifdef SOFTWARE_CONVENTION as->C -= (as->A) << 16; -#endif /* LPS_EXCHANGE, Figure E.17 */ if (as->A < pqe->Qe) { as->A = pqe->Qe; @@ -317,7 +291,6 @@ jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx, int *code) *pcx ^= pqe->lps_xor; } jbig2_arith_renormd(as); - *code = 0; return D; } } @@ -378,7 +351,6 @@ main(int argc, char **argv) Jbig2ArithState *as; int i; Jbig2ArithCx cx = 0; - int code; ctx = jbig2_ctx_new(NULL, 0, NULL, NULL, NULL); @@ -394,7 +366,7 @@ main(int argc, char **argv) #else (void) #endif - jbig2_arith_decode(as, &cx, &code); + jbig2_arith_decode(as, &cx); #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "%3d: D = %d, ", i, D); diff --git a/jbig2dec/jbig2_arith.h b/jbig2dec/jbig2_arith.h index be9382b8..f50d232f 100644 --- a/jbig2dec/jbig2_arith.h +++ b/jbig2dec/jbig2_arith.h @@ -31,7 +31,8 @@ typedef unsigned char Jbig2ArithCx; Jbig2ArithState *jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws); /* decode a bit */ -bool jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx, int *code); +/* Normally returns 0 or 1. May return negative in case of error. */ +int jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx); /* returns true if the end of the data stream has been reached (for sanity checks) */ bool jbig2_arith_has_reached_marker(Jbig2ArithState *as); diff --git a/jbig2dec/jbig2_arith_iaid.c b/jbig2dec/jbig2_arith_iaid.c index d2177a3e..caa79c80 100644 --- a/jbig2dec/jbig2_arith_iaid.c +++ b/jbig2dec/jbig2_arith_iaid.c @@ -75,12 +75,11 @@ jbig2_arith_iaid_decode(Jbig2Ctx *ctx, Jbig2ArithIaidCtx *actx, Jbig2ArithState int PREV = 1; int D; int i; - int code = 0; /* A.3 (2) */ for (i = 0; i < SBSYMCODELEN; i++) { - D = jbig2_arith_decode(as, &IAIDx[PREV], &code); - if (code) + D = jbig2_arith_decode(as, &IAIDx[PREV]); + if (D < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAIDx code"); #ifdef VERBOSE fprintf(stderr, "IAID%x: D = %d\n", PREV, D); diff --git a/jbig2dec/jbig2_arith_int.c b/jbig2dec/jbig2_arith_int.c index 05ec1b85..378ac9d3 100644 --- a/jbig2dec/jbig2_arith_int.c +++ b/jbig2dec/jbig2_arith_int.c @@ -70,38 +70,37 @@ jbig2_arith_int_decode(Jbig2Ctx *ctx, Jbig2ArithIntCtx *actx, Jbig2ArithState *a int bit; int n_tail, offset; int i; - int code = 0; - S = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + S = jbig2_arith_decode(as, &IAx[PREV]); + if (S < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx S"); PREV = (PREV << 1) | S; - bit = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + bit = jbig2_arith_decode(as, &IAx[PREV]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx decision bit 0"); PREV = (PREV << 1) | bit; if (bit) { - bit = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + bit = jbig2_arith_decode(as, &IAx[PREV]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx decision bit 1"); PREV = (PREV << 1) | bit; if (bit) { - bit = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + bit = jbig2_arith_decode(as, &IAx[PREV]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx decision bit 2"); PREV = (PREV << 1) | bit; if (bit) { - bit = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + bit = jbig2_arith_decode(as, &IAx[PREV]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx decision bit 3"); PREV = (PREV << 1) | bit; if (bit) { - bit = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + bit = jbig2_arith_decode(as, &IAx[PREV]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx decision bit 4"); PREV = (PREV << 1) | bit; @@ -131,8 +130,8 @@ jbig2_arith_int_decode(Jbig2Ctx *ctx, Jbig2ArithIntCtx *actx, Jbig2ArithState *a V = 0; for (i = 0; i < n_tail; i++) { - bit = jbig2_arith_decode(as, &IAx[PREV], &code); - if (code) + bit = jbig2_arith_decode(as, &IAx[PREV]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode IAx V bit %d", i); PREV = ((PREV << 1) & 511) | (PREV & 256) | bit; V = (V << 1) | bit; diff --git a/jbig2dec/jbig2_generic.c b/jbig2dec/jbig2_generic.c index 6c28352d..32211aad 100644 --- a/jbig2dec/jbig2_generic.c +++ b/jbig2dec/jbig2_generic.c @@ -346,6 +346,16 @@ NEWCONTEXT |= (line_m2 >> (10-x_minor)) & 0x80; The optimized decoding functions for GBTEMPLATE 0, 1 and 3 all work similarly. */ +/* Get a bit. No bounds checking. */ +static inline int +jbig2_image_get_pixel_fast(Jbig2Image *image, int x, int y) +{ + const int byte = (x >> 3) + y * image->stride; + const int bit = 7 - (x & 7); + + return ((image->data[byte] >> bit) & 1); +} + /* return the appropriate context size for the given template */ int jbig2_generic_stats_size(Jbig2Ctx *ctx, int template) @@ -381,7 +391,6 @@ jbig2_decode_generic_template0(Jbig2Ctx *ctx, uint32_t line_m1; uint32_t line_m2; uint32_t padded_width = (GBW + 7) & -8; - int code = 0; line_m1 = line1 ? line1[0] : 0; line_m2 = line2 ? line2[0] << 6 : 0; @@ -401,10 +410,10 @@ jbig2_decode_generic_template0(Jbig2Ctx *ctx, /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { - bool bit; + int bit; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 optimized"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x7bf7) << 1) | bit | ((line_m1 >> (7 - x_minor)) & 0x10) | ((line_m2 >> (7 - x_minor)) & 0x800); @@ -434,8 +443,7 @@ jbig2_decode_generic_template0_unopt(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; - int code = 0; + int bit; if (pixel_outside_field(params->gbat[0], params->gbat[1]) || pixel_outside_field(params->gbat[2], params->gbat[3]) || @@ -444,36 +452,56 @@ jbig2_decode_generic_template0_unopt(Jbig2Ctx *ctx, return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); - /* this version is generic and easy to understand, but very slow */ - for (y = 0; y < GBH; y++) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x000F; /* First 4 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; + CONTEXT |= (pd>>8) & 0x03E0; /* Next 5 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; + CONTEXT |= (ppd>>2) & 0x7000; /* Next 3 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 unoptimized"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } } - CONTEXT = 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 13; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 unoptimized"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } return 0; } @@ -487,40 +515,59 @@ jbig2_decode_generic_template1_unopt(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; - int code = 0; + int bit; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); - /* this version is generic and easy to understand, but very slow */ - for (y = 0; y < GBH; y++) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x0007; /* First 3 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3; + CONTEXT |= (pd>>9) & 0x01F0; /* Next 5 pixels */ + CONTEXT |= (ppd>>4) & 0x1E00; /* Next 4 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 unoptimized"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } } - CONTEXT = 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 2) << 9; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 10; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 11; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 unoptimized"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } return 0; } @@ -537,7 +584,6 @@ jbig2_decode_generic_template1(Jbig2Ctx *ctx, byte *line2 = NULL; byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; - int code = 0; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); @@ -570,10 +616,10 @@ jbig2_decode_generic_template1(Jbig2Ctx *ctx, /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { - bool bit; + int bit; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 optimized"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0xefb) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x8) | ((line_m2 >> (8 - x_minor)) & 0x200); @@ -600,37 +646,59 @@ jbig2_decode_generic_template2_unopt(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; - int code = 0; + int bit; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); - /* this version is generic and easy to understand, but very slow */ - for (y = 0; y < GBH; y++) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x003; /* First 2 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2; + CONTEXT |= (pd>>11) & 0x078; /* Next 4 pixels */ + CONTEXT |= (ppd>>7) & 0x380; /* Next 3 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 unoptimized"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } } - CONTEXT = 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 unoptimized"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } return 0; @@ -648,7 +716,6 @@ jbig2_decode_generic_template2(Jbig2Ctx *ctx, byte *line2 = NULL; byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; - int code = 0; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); @@ -681,10 +748,10 @@ jbig2_decode_generic_template2(Jbig2Ctx *ctx, /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { - bool bit; + int bit; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 optimized"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1bd) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80); @@ -713,7 +780,6 @@ jbig2_decode_generic_template3(Jbig2Ctx *ctx, byte *line1 = NULL; byte *gbreg_line = (byte *) image->data; uint32_t x, y; - int code; #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); @@ -741,10 +807,10 @@ jbig2_decode_generic_template3(Jbig2Ctx *ctx, /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { - bool bit; + int bit; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 optimized"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1f7) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x10); @@ -770,37 +836,47 @@ jbig2_decode_generic_template3_unopt(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; - int code = 0; + int bit; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); - /* this version is generic and easy to understand, but very slow */ - for (y = 0; y < GBH; y++) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint32_t pd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x00F; /* First 4 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; + CONTEXT |= (pd>>9) & 0x3E0; /* Next 5 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 unoptimized"); + } + pd = pd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) + pd |= *pline++; } - CONTEXT = 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 unoptimized"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } return 0; } @@ -828,9 +904,9 @@ jbig2_decode_generic_template0_TPGDON(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; int LTP = 0; - int code = 0; + int gmin, gmax; + uint32_t left, right, top; if (pixel_outside_field(params->gbat[0], params->gbat[1]) || pixel_outside_field(params->gbat[2], params->gbat[3]) || @@ -839,37 +915,178 @@ jbig2_decode_generic_template0_TPGDON(Jbig2Ctx *ctx, return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); + /* JBig2 has 'standard' values for gbat (see 6.2.5.4 of the spec). + * Have an optimised version for those locations. This greatly + * simplifies some of the fetches. It's almost like they thought + * it through. */ + if (params->gbat[0] == 3 && params->gbat[1] == -1 && + params->gbat[2] == -3 && params->gbat[3] == -1 && + params->gbat[4] == 2 && params->gbat[5] == -2 && + params->gbat[6] == -2 && params->gbat[7] == -2) + { + for (y = 0; y < GBH; y++) { + int bit = jbig2_arith_decode(as, &GB_stats[0x9B25]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON1"); + LTP ^= bit; + if (!LTP) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } + for (x = 0; x < GBW; x++) { + if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { + bit = 0; + } else { + CONTEXT = out_byte & 0x00F; /* First 4 pixels */ + CONTEXT |= (pd>>8) & 0x7F0; /* Next 7 pixels */ + CONTEXT |= (ppd>>2) & 0xF800; /* Final 5 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON2"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + *d++ = (uint8_t)out_byte; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } + } + } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + } else { + copy_prev_row(image, y); + } + } + return 0; + } + + /* We divide the width into 3 regions 0..left...right...GBW, + * between left and right, we know that our accesses will never + * step outside the image, enabling us to use faster accessors. */ + left = 4; + right = 2; + gmin = gmax = params->gbat[0]; + if (params->gbat[2] < gmin) + gmin = params->gbat[2]; + if (gmax < params->gbat[2]) + gmax = params->gbat[2]; + if (params->gbat[4] < gmin) + gmin = params->gbat[4]; + if (gmax < params->gbat[4]) + gmax = params->gbat[4]; + if (params->gbat[6] < gmin) + gmin = params->gbat[6]; + if (gmax < params->gbat[6]) + gmax = params->gbat[6]; + if ((int)left < -gmin) + left = -gmin; + if ((int)right < gmax) + right = gmax; + if (right > GBW) + right = GBW; + right = GBW - right; + /* So 0 <= x < left or right <= x < GBW needs bounds checking. */ + + /* Now we do the same for the height, but here there is no bottom + * region, as we only ever look up for y. */ + top = 2; + gmin = params->gbat[1]; + if (params->gbat[3] < gmin) + gmin = params->gbat[3]; + if (params->gbat[5] < gmin) + gmin = params->gbat[5]; + if (params->gbat[7] < gmin) + gmin = params->gbat[7]; + if ((int)top < -gmin) + top = -gmin; + /* So 0 <= y < top needs bounds checking. */ + for (y = 0; y < GBH; y++) { - LTP ^= jbig2_arith_decode(as, &GB_stats[0x9B25], &code); - if (code) + int bit = jbig2_arith_decode(as, &GB_stats[0x9B25]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON1"); + LTP ^= bit; if (!LTP) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x000F; /* First 4 pixels */ + CONTEXT |= (pd>>8) & 0x03E0; /* Skip one, next 5 pixels */ + CONTEXT |= (ppd>>2) & 0x7000; /* Skip 2, next 3 pixels, skip one */ + if (y >= top && x >= left && x < right) + { + CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[0], y + params->gbat[1]) << 4; + CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[2], y + params->gbat[3]) << 10; + CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[4], y + params->gbat[5]) << 11; + CONTEXT |= jbig2_image_get_pixel_fast(image, x + params->gbat[6], y + params->gbat[7]) << 15; + } + else + { + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; + } + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON2"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } } - CONTEXT = jbig2_image_get_pixel(image, x - 1, y); - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 13; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template0 TPGDON2"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } else { copy_prev_row(image, y); } @@ -887,42 +1104,64 @@ jbig2_decode_generic_template1_TPGDON(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; int LTP = 0; - int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { - LTP ^= jbig2_arith_decode(as, &GB_stats[0x0795], &code); - if (code) + int bit = jbig2_arith_decode(as, &GB_stats[0x0795]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON1"); + LTP ^= bit; if (!LTP) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x0007; /* First 3 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3; + CONTEXT |= (pd>>9) & 0x01F0; /* next 5 pixels */ + CONTEXT |= (ppd>>4) & 0x1E00; /* next 4 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON2"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } } - CONTEXT = jbig2_image_get_pixel(image, x - 1, y); - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 2) << 9; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 10; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 11; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template1 TPGDON2"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } else { copy_prev_row(image, y); } @@ -940,39 +1179,64 @@ jbig2_decode_generic_template2_TPGDON(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; int LTP = 0; - int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { - LTP ^= jbig2_arith_decode(as, &GB_stats[0xE5], &code); - if (code) + int bit = jbig2_arith_decode(as, &GB_stats[0xE5]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON1"); + LTP ^= bit; if (!LTP) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint8_t *ppline = &image->data[image->stride * (y-2)]; + uint32_t pd = 0; + uint32_t ppd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + if (y > 1) { + ppd = (*ppline++ << 8); + if (GBW > 8) + ppd |= *ppline++; + } + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x003; /* First 2 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2; + CONTEXT |= (pd>>11) & 0x078; /* next 4 pixels */ + CONTEXT |= (ppd>>7) & 0x380; /* next 3 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON2"); + } + pd = pd<<1; + ppd = ppd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) { + pd |= *pline++; + if (y > 1) + ppd |= *ppline++; + } } - CONTEXT = jbig2_image_get_pixel(image, x - 1, y); - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template2 TPGDON2"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } else { copy_prev_row(image, y); } @@ -990,39 +1254,52 @@ jbig2_decode_generic_template3_TPGDON(Jbig2Ctx *ctx, const uint32_t GBH = image->height; uint32_t CONTEXT; uint32_t x, y; - bool bit; int LTP = 0; - int code = 0; if (pixel_outside_field(params->gbat[0], params->gbat[1])) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "adaptive template pixel is out of field"); for (y = 0; y < GBH; y++) { - LTP ^= jbig2_arith_decode(as, &GB_stats[0x0195], &code); - if (code) + int bit = jbig2_arith_decode(as, &GB_stats[0x0195]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON1"); + LTP ^= bit; if (!LTP) { + uint32_t out_byte = 0; + int out_bits_to_go_in_byte = 8; + uint8_t *d = &image->data[image->stride * y]; + uint8_t *pline = &image->data[image->stride * (y-1)]; + uint32_t pd = 0; + if (y > 0) { + pd = (*pline++ << 8); + if (GBW > 8) + pd |= *pline++; + } for (x = 0; x < GBW; x++) { if (params->USESKIP && jbig2_image_get_pixel(params->SKIP, x, y)) { - jbig2_image_set_pixel(image, x, y, 0); - continue; + bit = 0; + } else { + CONTEXT = out_byte & 0x0F; /* First 4 pixels */ + CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; + CONTEXT |= (pd>>9) & 0x3E0; /* next 5 pixels */ + bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); + if (bit < 0) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON2"); + } + pd = pd<<1; + out_byte = (out_byte<<1) | bit; + out_bits_to_go_in_byte--; + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; + if (out_bits_to_go_in_byte == 0) { + out_bits_to_go_in_byte = 8; + d++; + if (x+9 < GBW && y > 0) + pd |= *pline++; } - CONTEXT = jbig2_image_get_pixel(image, x - 1, y); - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; - CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; - CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; - CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; - CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6; - CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; - CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; - CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9; - bit = jbig2_arith_decode(as, &GB_stats[CONTEXT], &code); - if (code) - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling generic template3 TPGDON2"); - jbig2_image_set_pixel(image, x, y, bit); } + if (out_bits_to_go_in_byte != 8) + *d = (uint8_t)out_byte<<out_bits_to_go_in_byte; } else { copy_prev_row(image, y); } @@ -1075,7 +1352,7 @@ jbig2_decode_generic_region(Jbig2Ctx *ctx, if (image->stride * image->height > (1 << 26) && segment->data_length < image->stride * image->height / (1 << 16)) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, - "region is far larger than data provided (%d << %d), aborting to prevent DOS", segment->data_length, image->stride * image->height); + "region is far larger than data provided (%li << %d), aborting to prevent DOS", (long) segment->data_length, image->stride * image->height); } if (!params->MMR && params->TPGDON) diff --git a/jbig2dec/jbig2_halftone.c b/jbig2dec/jbig2_halftone.c index 8a18fc70..e67c6d18 100644 --- a/jbig2dec/jbig2_halftone.c +++ b/jbig2dec/jbig2_halftone.c @@ -50,6 +50,12 @@ jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *im uint32_t i; int j; + if (N == 0) { + /* We've wrapped. */ + jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "params->GRAYMAX out of range"); + return NULL; + } + /* allocate a new struct */ new = jbig2_new(ctx, Jbig2PatternDict, 1); if (new != NULL) { @@ -458,7 +464,7 @@ jbig2_decode_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Image *HSKIP = NULL; Jbig2PatternDict *HPATS; uint32_t i; - uint32_t mg, ng; + int32_t mg, ng; int32_t x, y; uint16_t gray_val; int code = 0; @@ -481,8 +487,8 @@ jbig2_decode_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, for (mg = 0; mg < params->HGH; ++mg) { for (ng = 0; ng < params->HGW; ++ng) { - x = (params->HGX + mg * (int32_t) params->HRY + ng * (int32_t) params->HRX) >> 8; - y = (params->HGY + mg * (int32_t) params->HRX - ng * (int32_t) params->HRY) >> 8; + x = (params->HGX + mg * params->HRY + ng * params->HRX) >> 8; + y = (params->HGY + mg * params->HRX - ng * params->HRY) >> 8; if (x + HPATS->HPW <= 0 || x >= (int32_t) image->width || y + HPATS->HPH <= 0 || y >= (int32_t) image->height) { jbig2_image_set_pixel(HSKIP, ng, mg, 1); diff --git a/jbig2dec/jbig2_huffman.c b/jbig2dec/jbig2_huffman.c index 908ab59c..a3bc001a 100644 --- a/jbig2dec/jbig2_huffman.c +++ b/jbig2dec/jbig2_huffman.c @@ -299,7 +299,7 @@ jbig2_huffman_get(Jbig2HuffmanState *hs, const Jbig2HuffmanTable *table, bool *o entry = &table->entries[log_table_size > 0 ? this_word >> (32 - log_table_size) : 0]; flags = entry->flags; PREFLEN = entry->PREFLEN; - if (flags == (byte) -1 && PREFLEN == (byte) -1 && entry->u.RANGELOW == -1) { + if (flags == (byte) -1 || PREFLEN == (byte) -1) { if (oob) *oob = -1; return jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "encountered unpopulated huffman table entry"); @@ -583,6 +583,11 @@ jbig2_table(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) code_table_flags, HTOOB, HTPS, HTRS, HTLOW, HTHIGH); #endif + if (HTLOW >= HTHIGH) { + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid Huffman Table range"); + goto error_exit; + } + /* allocate HuffmanParams & HuffmanLine */ params = jbig2_new(ctx, Jbig2HuffmanParams, 1); if (params == NULL) { @@ -747,7 +752,7 @@ static int test1() { Jbig2Ctx *ctx; Jbig2HuffmanTable *tables[5]; - Jbig2HuffmanState *hs; + Jbig2HuffmanState *hs = NULL; Jbig2WordStream ws; bool oob; int32_t code; @@ -799,6 +804,7 @@ static int test1() success = 1; cleanup: + jbig2_huffman_free(ctx, hs); for (i = 0; i < 5; i++) jbig2_release_huffman_table(ctx, tables[i]); jbig2_ctx_free(ctx); diff --git a/jbig2dec/jbig2_hufftab.c b/jbig2dec/jbig2_hufftab.c new file mode 100644 index 00000000..80b9bf26 --- /dev/null +++ b/jbig2dec/jbig2_hufftab.c @@ -0,0 +1,318 @@ +/* Copyright (C) 2001-2019 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* + jbig2dec +*/ + +/* predefined Huffman table definitions + -- See Annex B of the JBIG2 specification */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "os_types.h" + +#include <stdlib.h> + +#include "jbig2.h" +#include "jbig2_priv.h" +#include "jbig2_huffman.h" +#include "jbig2_hufftab.h" + +#define JBIG2_COUNTOF(x) (sizeof((x)) / sizeof((x)[0])) + +/* Table B.1 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_A[] = { + {1, 4, 0}, + {2, 8, 16}, + {3, 16, 272}, + {0, 32, -1}, /* low */ + {3, 32, 65808} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_A = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_A), jbig2_huffman_lines_A }; + +/* Table B.2 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_B[] = { + {1, 0, 0}, + {2, 0, 1}, + {3, 0, 2}, + {4, 3, 3}, + {5, 6, 11}, + {0, 32, -1}, /* low */ + {6, 32, 75}, /* high */ + {6, 0, 0} /* OOB */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_B = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_B), jbig2_huffman_lines_B }; + +/* Table B.3 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_C[] = { + {8, 8, -256}, + {1, 0, 0}, + {2, 0, 1}, + {3, 0, 2}, + {4, 3, 3}, + {5, 6, 11}, + {8, 32, -257}, /* low */ + {7, 32, 75}, /* high */ + {6, 0, 0} /* OOB */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_C = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_C), jbig2_huffman_lines_C }; + +/* Table B.4 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_D[] = { + {1, 0, 1}, + {2, 0, 2}, + {3, 0, 3}, + {4, 3, 4}, + {5, 6, 12}, + {0, 32, -1}, /* low */ + {5, 32, 76}, /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_D = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_D), jbig2_huffman_lines_D }; + +/* Table B.5 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_E[] = { + {7, 8, -255}, + {1, 0, 1}, + {2, 0, 2}, + {3, 0, 3}, + {4, 3, 4}, + {5, 6, 12}, + {7, 32, -256}, /* low */ + {6, 32, 76} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_E = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_E), jbig2_huffman_lines_E }; + +/* Table B.6 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_F[] = { + {5, 10, -2048}, + {4, 9, -1024}, + {4, 8, -512}, + {4, 7, -256}, + {5, 6, -128}, + {5, 5, -64}, + {4, 5, -32}, + {2, 7, 0}, + {3, 7, 128}, + {3, 8, 256}, + {4, 9, 512}, + {4, 10, 1024}, + {6, 32, -2049}, /* low */ + {6, 32, 2048} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_F = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_F), jbig2_huffman_lines_F }; + +/* Table B.7 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_G[] = { + {4, 9, -1024}, + {3, 8, -512}, + {4, 7, -256}, + {5, 6, -128}, + {5, 5, -64}, + {4, 5, -32}, + {4, 5, 0}, + {5, 5, 32}, + {5, 6, 64}, + {4, 7, 128}, + {3, 8, 256}, + {3, 9, 512}, + {3, 10, 1024}, + {5, 32, -1025}, /* low */ + {5, 32, 2048} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_G = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_G), jbig2_huffman_lines_G }; + +/* Table B.8 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_H[] = { + {8, 3, -15}, + {9, 1, -7}, + {8, 1, -5}, + {9, 0, -3}, + {7, 0, -2}, + {4, 0, -1}, + {2, 1, 0}, + {5, 0, 2}, + {6, 0, 3}, + {3, 4, 4}, + {6, 1, 20}, + {4, 4, 22}, + {4, 5, 38}, + {5, 6, 70}, + {5, 7, 134}, + {6, 7, 262}, + {7, 8, 390}, + {6, 10, 646}, + {9, 32, -16}, /* low */ + {9, 32, 1670}, /* high */ + {2, 0, 0} /* OOB */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_H = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_H), jbig2_huffman_lines_H }; + +/* Table B.9 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_I[] = { + {8, 4, -31}, + {9, 2, -15}, + {8, 2, -11}, + {9, 1, -7}, + {7, 1, -5}, + {4, 1, -3}, + {3, 1, -1}, + {3, 1, 1}, + {5, 1, 3}, + {6, 1, 5}, + {3, 5, 7}, + {6, 2, 39}, + {4, 5, 43}, + {4, 6, 75}, + {5, 7, 139}, + {5, 8, 267}, + {6, 8, 523}, + {7, 9, 779}, + {6, 11, 1291}, + {9, 32, -32}, /* low */ + {9, 32, 3339}, /* high */ + {2, 0, 0} /* OOB */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_I = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_I), jbig2_huffman_lines_I }; + +/* Table B.10 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_J[] = { + {7, 4, -21}, + {8, 0, -5}, + {7, 0, -4}, + {5, 0, -3}, + {2, 2, -2}, + {5, 0, 2}, + {6, 0, 3}, + {7, 0, 4}, + {8, 0, 5}, + {2, 6, 6}, + {5, 5, 70}, + {6, 5, 102}, + {6, 6, 134}, + {6, 7, 198}, + {6, 8, 326}, + {6, 9, 582}, + {6, 10, 1094}, + {7, 11, 2118}, + {8, 32, -22}, /* low */ + {8, 32, 4166}, /* high */ + {2, 0, 0} /* OOB */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_J = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_J), jbig2_huffman_lines_J }; + +/* Table B.11 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_K[] = { + {1, 0, 1}, + {2, 1, 2}, + {4, 0, 4}, + {4, 1, 5}, + {5, 1, 7}, + {5, 2, 9}, + {6, 2, 13}, + {7, 2, 17}, + {7, 3, 21}, + {7, 4, 29}, + {7, 5, 45}, + {7, 6, 77}, + {0, 32, -1}, /* low */ + {7, 32, 141} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_K = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_K), jbig2_huffman_lines_K }; + +/* Table B.12 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_L[] = { + {1, 0, 1}, + {2, 0, 2}, + {3, 1, 3}, + {5, 0, 5}, + {5, 1, 6}, + {6, 1, 8}, + {7, 0, 10}, + {7, 1, 11}, + {7, 2, 13}, + {7, 3, 17}, + {7, 4, 25}, + {8, 5, 41}, + {8, 32, 73}, + {0, 32, -1}, /* low */ + {0, 32, 0} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_L = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_L), jbig2_huffman_lines_L }; + +/* Table B.13 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_M[] = { + {1, 0, 1}, + {3, 0, 2}, + {4, 0, 3}, + {5, 0, 4}, + {4, 1, 5}, + {3, 3, 7}, + {6, 1, 15}, + {6, 2, 17}, + {6, 3, 21}, + {6, 4, 29}, + {6, 5, 45}, + {7, 6, 77}, + {0, 32, -1}, /* low */ + {7, 32, 141} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_M = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_M), jbig2_huffman_lines_M }; + +/* Table B.14 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_N[] = { + {3, 0, -2}, + {3, 0, -1}, + {1, 0, 0}, + {3, 0, 1}, + {3, 0, 2}, + {0, 32, -1}, /* low */ + {0, 32, 3}, /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_N = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_N), jbig2_huffman_lines_N }; + +/* Table B.15 */ +static const Jbig2HuffmanLine jbig2_huffman_lines_O[] = { + {7, 4, -24}, + {6, 2, -8}, + {5, 1, -4}, + {4, 0, -2}, + {3, 0, -1}, + {1, 0, 0}, + {3, 0, 1}, + {4, 0, 2}, + {5, 1, 3}, + {6, 2, 5}, + {7, 4, 9}, + {7, 32, -25}, /* low */ + {7, 32, 25} /* high */ +}; + +const Jbig2HuffmanParams jbig2_huffman_params_O = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_O), jbig2_huffman_lines_O }; diff --git a/jbig2dec/jbig2_hufftab.h b/jbig2dec/jbig2_hufftab.h index 29a39db0..68d1b619 100644 --- a/jbig2dec/jbig2_hufftab.h +++ b/jbig2dec/jbig2_hufftab.h @@ -18,298 +18,25 @@ */ /* predefined Huffman table definitions - -- See Annex B of the JBIG2 specification */ + -- See Annex B.5 of the JBIG2 specification */ #ifndef _JBIG2_HUFFTAB_H #define _JBIG2_HUFFTAB_H -/* types are in jbig2_huffman.h, you must include that first */ - -#define JBIG2_COUNTOF(x) (sizeof((x)) / sizeof((x)[0])) - -/* Table B.1 */ -const Jbig2HuffmanLine jbig2_huffman_lines_A[] = { - {1, 4, 0}, - {2, 8, 16}, - {3, 16, 272}, - {0, 32, -1}, /* low */ - {3, 32, 65808} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_A = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_A), jbig2_huffman_lines_A }; - -/* Table B.2 */ -const Jbig2HuffmanLine jbig2_huffman_lines_B[] = { - {1, 0, 0}, - {2, 0, 1}, - {3, 0, 2}, - {4, 3, 3}, - {5, 6, 11}, - {0, 32, -1}, /* low */ - {6, 32, 75}, /* high */ - {6, 0, 0} /* OOB */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_B = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_B), jbig2_huffman_lines_B }; - -/* Table B.3 */ -const Jbig2HuffmanLine jbig2_huffman_lines_C[] = { - {8, 8, -256}, - {1, 0, 0}, - {2, 0, 1}, - {3, 0, 2}, - {4, 3, 3}, - {5, 6, 11}, - {8, 32, -257}, /* low */ - {7, 32, 75}, /* high */ - {6, 0, 0} /* OOB */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_C = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_C), jbig2_huffman_lines_C }; - -/* Table B.4 */ -const Jbig2HuffmanLine jbig2_huffman_lines_D[] = { - {1, 0, 1}, - {2, 0, 2}, - {3, 0, 3}, - {4, 3, 4}, - {5, 6, 12}, - {0, 32, -1}, /* low */ - {5, 32, 76}, /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_D = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_D), jbig2_huffman_lines_D }; - -/* Table B.5 */ -const Jbig2HuffmanLine jbig2_huffman_lines_E[] = { - {7, 8, -255}, - {1, 0, 1}, - {2, 0, 2}, - {3, 0, 3}, - {4, 3, 4}, - {5, 6, 12}, - {7, 32, -256}, /* low */ - {6, 32, 76} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_E = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_E), jbig2_huffman_lines_E }; - -/* Table B.6 */ -const Jbig2HuffmanLine jbig2_huffman_lines_F[] = { - {5, 10, -2048}, - {4, 9, -1024}, - {4, 8, -512}, - {4, 7, -256}, - {5, 6, -128}, - {5, 5, -64}, - {4, 5, -32}, - {2, 7, 0}, - {3, 7, 128}, - {3, 8, 256}, - {4, 9, 512}, - {4, 10, 1024}, - {6, 32, -2049}, /* low */ - {6, 32, 2048} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_F = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_F), jbig2_huffman_lines_F }; - -/* Table B.7 */ -const Jbig2HuffmanLine jbig2_huffman_lines_G[] = { - {4, 9, -1024}, - {3, 8, -512}, - {4, 7, -256}, - {5, 6, -128}, - {5, 5, -64}, - {4, 5, -32}, - {4, 5, 0}, - {5, 5, 32}, - {5, 6, 64}, - {4, 7, 128}, - {3, 8, 256}, - {3, 9, 512}, - {3, 10, 1024}, - {5, 32, -1025}, /* low */ - {5, 32, 2048} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_G = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_G), jbig2_huffman_lines_G }; - -/* Table B.8 */ -const Jbig2HuffmanLine jbig2_huffman_lines_H[] = { - {8, 3, -15}, - {9, 1, -7}, - {8, 1, -5}, - {9, 0, -3}, - {7, 0, -2}, - {4, 0, -1}, - {2, 1, 0}, - {5, 0, 2}, - {6, 0, 3}, - {3, 4, 4}, - {6, 1, 20}, - {4, 4, 22}, - {4, 5, 38}, - {5, 6, 70}, - {5, 7, 134}, - {6, 7, 262}, - {7, 8, 390}, - {6, 10, 646}, - {9, 32, -16}, /* low */ - {9, 32, 1670}, /* high */ - {2, 0, 0} /* OOB */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_H = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_H), jbig2_huffman_lines_H }; - -/* Table B.9 */ -const Jbig2HuffmanLine jbig2_huffman_lines_I[] = { - {8, 4, -31}, - {9, 2, -15}, - {8, 2, -11}, - {9, 1, -7}, - {7, 1, -5}, - {4, 1, -3}, - {3, 1, -1}, - {3, 1, 1}, - {5, 1, 3}, - {6, 1, 5}, - {3, 5, 7}, - {6, 2, 39}, - {4, 5, 43}, - {4, 6, 75}, - {5, 7, 139}, - {5, 8, 267}, - {6, 8, 523}, - {7, 9, 779}, - {6, 11, 1291}, - {9, 32, -32}, /* low */ - {9, 32, 3339}, /* high */ - {2, 0, 0} /* OOB */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_I = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_I), jbig2_huffman_lines_I }; - -/* Table B.10 */ -const Jbig2HuffmanLine jbig2_huffman_lines_J[] = { - {7, 4, -21}, - {8, 0, -5}, - {7, 0, -4}, - {5, 0, -3}, - {2, 2, -2}, - {5, 0, 2}, - {6, 0, 3}, - {7, 0, 4}, - {8, 0, 5}, - {2, 6, 6}, - {5, 5, 70}, - {6, 5, 102}, - {6, 6, 134}, - {6, 7, 198}, - {6, 8, 326}, - {6, 9, 582}, - {6, 10, 1094}, - {7, 11, 2118}, - {8, 32, -22}, /* low */ - {8, 32, 4166}, /* high */ - {2, 0, 0} /* OOB */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_J = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_J), jbig2_huffman_lines_J }; - -/* Table B.11 */ -const Jbig2HuffmanLine jbig2_huffman_lines_K[] = { - {1, 0, 1}, - {2, 1, 2}, - {4, 0, 4}, - {4, 1, 5}, - {5, 1, 7}, - {5, 2, 9}, - {6, 2, 13}, - {7, 2, 17}, - {7, 3, 21}, - {7, 4, 29}, - {7, 5, 45}, - {7, 6, 77}, - {0, 32, -1}, /* low */ - {7, 32, 141} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_K = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_K), jbig2_huffman_lines_K }; - -/* Table B.12 */ -const Jbig2HuffmanLine jbig2_huffman_lines_L[] = { - {1, 0, 1}, - {2, 0, 2}, - {3, 1, 3}, - {5, 0, 5}, - {5, 1, 6}, - {6, 1, 8}, - {7, 0, 10}, - {7, 1, 11}, - {7, 2, 13}, - {7, 3, 17}, - {7, 4, 25}, - {8, 5, 41}, - {8, 32, 73}, - {0, 32, -1}, /* low */ - {0, 32, 0} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_L = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_L), jbig2_huffman_lines_L }; - -/* Table B.13 */ -const Jbig2HuffmanLine jbig2_huffman_lines_M[] = { - {1, 0, 1}, - {3, 0, 2}, - {4, 0, 3}, - {5, 0, 4}, - {4, 1, 5}, - {3, 3, 7}, - {6, 1, 15}, - {6, 2, 17}, - {6, 3, 21}, - {6, 4, 29}, - {6, 5, 45}, - {7, 6, 77}, - {0, 32, -1}, /* low */ - {7, 32, 141} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_M = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_M), jbig2_huffman_lines_M }; - -/* Table B.14 */ -const Jbig2HuffmanLine jbig2_huffman_lines_N[] = { - {3, 0, -2}, - {3, 0, -1}, - {1, 0, 0}, - {3, 0, 1}, - {3, 0, 2}, - {0, 32, -1}, /* low */ - {0, 32, 3}, /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_N = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_N), jbig2_huffman_lines_N }; - -/* Table B.15 */ -const Jbig2HuffmanLine jbig2_huffman_lines_O[] = { - {7, 4, -24}, - {6, 2, -8}, - {5, 1, -4}, - {4, 0, -2}, - {3, 0, -1}, - {1, 0, 0}, - {3, 0, 1}, - {4, 0, 2}, - {5, 1, 3}, - {6, 2, 5}, - {7, 4, 9}, - {7, 32, -25}, /* low */ - {7, 32, 25} /* high */ -}; - -const Jbig2HuffmanParams jbig2_huffman_params_O = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_O), jbig2_huffman_lines_O }; - -#undef JBIG2_COUNTOF +extern const Jbig2HuffmanParams jbig2_huffman_params_A; +extern const Jbig2HuffmanParams jbig2_huffman_params_B; +extern const Jbig2HuffmanParams jbig2_huffman_params_C; +extern const Jbig2HuffmanParams jbig2_huffman_params_D; +extern const Jbig2HuffmanParams jbig2_huffman_params_E; +extern const Jbig2HuffmanParams jbig2_huffman_params_F; +extern const Jbig2HuffmanParams jbig2_huffman_params_G; +extern const Jbig2HuffmanParams jbig2_huffman_params_H; +extern const Jbig2HuffmanParams jbig2_huffman_params_I; +extern const Jbig2HuffmanParams jbig2_huffman_params_J; +extern const Jbig2HuffmanParams jbig2_huffman_params_K; +extern const Jbig2HuffmanParams jbig2_huffman_params_L; +extern const Jbig2HuffmanParams jbig2_huffman_params_M; +extern const Jbig2HuffmanParams jbig2_huffman_params_N; +extern const Jbig2HuffmanParams jbig2_huffman_params_O; #endif /* _JBIG2_HUFFTAB_H */ diff --git a/jbig2dec/jbig2_image.c b/jbig2dec/jbig2_image.c index 05a81bd7..70c985a9 100644 --- a/jbig2dec/jbig2_image.c +++ b/jbig2dec/jbig2_image.c @@ -33,6 +33,9 @@ #if !defined (INT32_MAX) #define INT32_MAX 0x7fffffff #endif +#if !defined (UINT32_MAX) +#define UINT32_MAX 0xffffffffu +#endif /* allocate a Jbig2Image structure and its associated bitmap */ Jbig2Image * @@ -164,137 +167,232 @@ jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, uint32_t width, uint32_t he return image; } -/* composite one jbig2_image onto another - slow but general version */ -static int -jbig2_image_compose_unopt(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op) +static inline void +template_image_compose_opt(const uint8_t * JBIG2_RESTRICT ss, uint8_t * JBIG2_RESTRICT dd, int early, int late, uint8_t leftmask, uint8_t rightmask, uint32_t bytewidth_, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride, Jbig2ComposeOp op) { - uint32_t i, j; - uint32_t sw = src->width; - uint32_t sh = src->height; - uint32_t sx = 0; - uint32_t sy = 0; - - /* clip to the dst image boundaries */ - if (x < 0) { - sx += -x; - if (sw < (uint32_t) -x) - sw = 0; - else - sw -= -x; - x = 0; - } - if (y < 0) { - sy += -y; - if (sh < (uint32_t) -y) - sh = 0; - else - sh -= -y; - y = 0; - } - if ((uint32_t) x + sw >= dst->width) { - if (dst->width >= (uint32_t) x) - sw = dst->width - x; - else - sw = 0; - } - if ((uint32_t) y + sh >= dst->height) { - if (dst->height >= (uint32_t) y) - sh = dst->height - y; - else - sh = 0; - } + int i; + uint32_t j; + int bytewidth = (int)bytewidth_; - switch (op) { - case JBIG2_COMPOSE_OR: - for (j = 0; j < sh; j++) { - for (i = 0; i < sw; i++) { - jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) | jbig2_image_get_pixel(dst, i + x, j + y)); - } - } - break; - case JBIG2_COMPOSE_AND: - for (j = 0; j < sh; j++) { - for (i = 0; i < sw; i++) { - jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) & jbig2_image_get_pixel(dst, i + x, j + y)); - } - } - break; - case JBIG2_COMPOSE_XOR: - for (j = 0; j < sh; j++) { - for (i = 0; i < sw; i++) { - jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) ^ jbig2_image_get_pixel(dst, i + x, j + y)); - } + if (bytewidth == 1) { + for (j = 0; j < h; j++) { + /* Only 1 byte! */ + uint8_t v = (((early ? 0 : ss[0]<<8) | (late ? 0 : ss[1]))>>shift); + if (op == JBIG2_COMPOSE_OR) + *dd |= v & leftmask; + else if (op == JBIG2_COMPOSE_AND) + *dd &= (v & leftmask) | ~leftmask; + else if (op == JBIG2_COMPOSE_XOR) + *dd ^= v & leftmask; + else if (op == JBIG2_COMPOSE_XNOR) + *dd ^= (~v) & leftmask; + else /* Replace */ + *dd = (v & leftmask) | (*dd & ~leftmask); + dd += dstride; + ss += sstride; } - break; - case JBIG2_COMPOSE_XNOR: - for (j = 0; j < sh; j++) { - for (i = 0; i < sw; i++) { - jbig2_image_set_pixel(dst, i + x, j + y, (jbig2_image_get_pixel(src, i + sx, j + sy) == jbig2_image_get_pixel(dst, i + x, j + y))); + return; + } + bytewidth -= 2; + if (shift == 0) { + ss++; + for (j = 0; j < h; j++) { + /* Left byte */ + const uint8_t * JBIG2_RESTRICT s = ss; + uint8_t * JBIG2_RESTRICT d = dd; + if (op == JBIG2_COMPOSE_OR) + *d++ |= *s++ & leftmask; + else if (op == JBIG2_COMPOSE_AND) + *d++ &= (*s++ & leftmask) | ~leftmask; + else if (op == JBIG2_COMPOSE_XOR) + *d++ ^= *s++ & leftmask; + else if (op == JBIG2_COMPOSE_XNOR) + *d++ ^= (~*s++) & leftmask; + else /* Replace */ + *d = (*s++ & leftmask) | (*d & ~leftmask), d++; + /* Central run */ + for (i = bytewidth; i != 0; i--) { + if (op == JBIG2_COMPOSE_OR) + *d++ |= *s++; + else if (op == JBIG2_COMPOSE_AND) + *d++ &= *s++; + else if (op == JBIG2_COMPOSE_XOR) + *d++ ^= *s++; + else if (op == JBIG2_COMPOSE_XNOR) + *d++ ^= ~*s++; + else /* Replace */ + *d++ = *s++; } + /* Right byte */ + if (op == JBIG2_COMPOSE_OR) + *d |= *s & rightmask; + else if (op == JBIG2_COMPOSE_AND) + *d &= (*s & rightmask) | ~rightmask; + else if (op == JBIG2_COMPOSE_XOR) + *d ^= *s & rightmask; + else if (op == JBIG2_COMPOSE_XNOR) + *d ^= (~*s) & rightmask; + else /* Replace */ + *d = (*s & rightmask) | (*d & ~rightmask); + dd += dstride; + ss += sstride; } - break; - case JBIG2_COMPOSE_REPLACE: - for (j = 0; j < sh; j++) { - for (i = 0; i < sw; i++) { - jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy)); + } else { + for (j = 0; j < h; j++) { + /* Left byte */ + const uint8_t * JBIG2_RESTRICT s = ss; + uint8_t * JBIG2_RESTRICT d = dd; + uint8_t s0, s1, v; + s0 = early ? 0 : *s; + s++; + s1 = *s++; + v = ((s0<<8) | s1)>>shift; + if (op == JBIG2_COMPOSE_OR) + *d++ |= v & leftmask; + else if (op == JBIG2_COMPOSE_AND) + *d++ &= (v & leftmask) | ~leftmask; + else if (op == JBIG2_COMPOSE_XOR) + *d++ ^= v & leftmask; + else if (op == JBIG2_COMPOSE_XNOR) + *d++ ^= (~v) & leftmask; + else /* Replace */ + *d = (v & leftmask) | (*d & ~leftmask), d++; + /* Central run */ + for (i = bytewidth; i > 0; i--) { + s0 = s1; s1 = *s++; + v = ((s0<<8) | s1)>>shift; + if (op == JBIG2_COMPOSE_OR) + *d++ |= v; + else if (op == JBIG2_COMPOSE_AND) + *d++ &= v; + else if (op == JBIG2_COMPOSE_XOR) + *d++ ^= v; + else if (op == JBIG2_COMPOSE_XNOR) + *d++ ^= ~v; + else /* Replace */ + *d++ = v; } + /* Right byte */ + s0 = s1; s1 = (late ? 0 : *s); + v = (((s0<<8) | s1)>>shift); + if (op == JBIG2_COMPOSE_OR) + *d |= v & rightmask; + else if (op == JBIG2_COMPOSE_AND) + *d &= (v & rightmask) | ~rightmask; + else if (op == JBIG2_COMPOSE_XOR) + *d ^= v & rightmask; + else if (op == JBIG2_COMPOSE_XNOR) + *d ^= ~v & rightmask; + else /* Replace */ + *d = (v & rightmask) | (*d & ~rightmask); + dd += dstride; + ss += sstride; } - break; } +} - return 0; +static void +jbig2_image_compose_opt_OR(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride) +{ + if (early || late) + template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR); + else + template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_OR); +} + +static void +jbig2_image_compose_opt_AND(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride) +{ + if (early || late) + template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_AND); + else + template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_AND); +} + +static void +jbig2_image_compose_opt_XOR(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride) +{ + if (early || late) + template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XOR); + else + template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XOR); +} + +static void +jbig2_image_compose_opt_XNOR(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride) +{ + if (early || late) + template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XNOR); + else + template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_XNOR); +} + +static void +jbig2_image_compose_opt_REPLACE(const uint8_t *s, uint8_t *d, int early, int late, uint8_t mask, uint8_t rightmask, uint32_t bytewidth, uint32_t h, uint32_t shift, uint32_t dstride, uint32_t sstride) +{ + if (early || late) + template_image_compose_opt(s, d, early, late, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE); + else + template_image_compose_opt(s, d, 0, 0, mask, rightmask, bytewidth, h, shift, dstride, sstride, JBIG2_COMPOSE_REPLACE); } /* composite one jbig2_image onto another */ int jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op) { - uint32_t i, j; uint32_t w, h; - uint32_t leftbyte, rightbyte; uint32_t shift; - uint8_t *s, *ss; - uint8_t *d, *dd; - uint8_t mask, rightmask; + uint32_t leftbyte; + uint8_t *ss; + uint8_t *dd; + uint8_t leftmask, rightmask; + int early = x >= 0; + int late; + uint32_t bytewidth; + uint32_t syoffset = 0; if (src == NULL) return 0; - /* The optimized code for the OR operator below doesn't - handle the source image partially placed outside the - destination (above and/or to the left). The affected - intersection of the destination is computed correctly, - however the correct subset of the source image is not - chosen. Instead the upper left corner of the source image - is always used. - - In the unoptimized version that handles all operators - (including OR) the correct subset of the source image is - chosen. - - The workaround is to check whether the x/y coordinates to - the composition operator are negative and in this case use - the unoptimized implementation. - - TODO: Fix the optimized OR implementation if possible. */ - if (op != JBIG2_COMPOSE_OR || x < 0 || y < 0) { - /* hand off the the general routine */ - return jbig2_image_compose_unopt(ctx, dst, src, x, y, op); + if ((UINT32_MAX - src->width < (x > 0 ? x : -x)) || + (UINT32_MAX - src->height < (y > 0 ? y : -y))) + { +#ifdef JBIG2_DEBUG + jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "overflow in compose_image"); +#endif + return 0; } - /* optimized code for the prevalent OR operator */ + /* This code takes a src image and combines it onto dst at offset (x,y), with operation op. */ + + /* Data is packed msb first within a byte, so with bits numbered: 01234567. + * Second byte is: 89abcdef. So to combine into a run, we use: + * (s[0]<<8) | s[1] == 0123456789abcdef. + * To read from src into dst at offset 3, we need to read: + * read: 0123456789abcdef... + * write: 0123456798abcdef... + * In general, to read from src and write into dst at offset x, we need to shift + * down by (x&7) bits to allow for bit alignment. So shift = x&7. + * So the 'central' part of our runs will see us doing: + * *d++ op= ((s[0]<<8)|s[1])>>shift; + * with special cases on the left and right edges of the run to mask. + * With the left hand edge, we have to be careful not to 'underread' the start of + * the src image; this is what the early flag is about. Similarly we have to be + * careful not to read off the right hand edge; this is what the late flag is for. + */ /* clip */ w = src->width; h = src->height; - ss = src->data; + shift = (x & 7); + ss = src->data - early; if (x < 0) { if (w < (uint32_t) -x) w = 0; else w += x; + ss += (-x-1)>>3; x = 0; } if (y < 0) { @@ -302,10 +400,23 @@ jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int h = 0; else h += y; + syoffset = -y * src->stride; y = 0; } - w = ((uint32_t) x + w < dst->width) ? w : ((dst->width >= (uint32_t) x) ? dst->width - (uint32_t) x : 0); - h = ((uint32_t) y + h < dst->height) ? h : ((dst->height >= (uint32_t) y) ? dst->height - (uint32_t) y : 0); + if ((uint32_t)x + w > dst->width) + { + if (dst->width < (uint32_t)x) + w = 0; + else + w = dst->width - x; + } + if ((uint32_t)y + h > dst->height) + { + if (dst->height < (uint32_t)y) + h = 0; + else + h = dst->height - y; + } #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "compositing %dx%d at (%d, %d) after clipping", w, h, x, y); #endif @@ -319,55 +430,32 @@ jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int } leftbyte = (uint32_t) x >> 3; - rightbyte = ((uint32_t) x + w - 1) >> 3; - shift = x & 7; - - /* general OR case */ - s = ss; - d = dd = dst->data + y * dst->stride + leftbyte; - if (d < dst->data || - leftbyte > dst->stride || - d - leftbyte + (size_t) h * dst->stride > dst->data + (size_t) dst->height * dst->stride || - s - leftbyte + (size_t) (h - 1) * src->stride + rightbyte > src->data + (size_t) src->height * src->stride) { - return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "preventing heap overflow in jbig2_image_compose"); - } - if (leftbyte == rightbyte) { - mask = 0x100 - (0x100 >> w); - for (j = 0; j < h; j++) { - *d |= (*s & mask) >> shift; - d += dst->stride; - s += src->stride; - } - } else if (shift == 0) { - rightmask = (w & 7) ? 0x100 - (1 << (8 - (w & 7))) : 0xFF; - for (j = 0; j < h; j++) { - for (i = leftbyte; i < rightbyte; i++) - *d++ |= *s++; - *d |= *s & rightmask; - d = (dd += dst->stride); - s = (ss += src->stride); - } - } else { - bool overlap = (((w + 7) >> 3) < ((x + w + 7) >> 3) - (x >> 3)); - - mask = 0x100 - (1 << shift); - if (overlap) - rightmask = (0x100 - (0x100 >> ((x + w) & 7))) >> (8 - shift); - else - rightmask = 0x100 - (0x100 >> (w & 7)); - for (j = 0; j < h; j++) { - *d++ |= (*s & mask) >> shift; - for (i = leftbyte; i < rightbyte - 1; i++) { - *d |= ((*s++ & ~mask) << (8 - shift)); - *d++ |= ((*s & mask) >> shift); - } - if (overlap) - *d |= (*s & rightmask) << (8 - shift); - else - *d |= ((s[0] & ~mask) << (8 - shift)) | ((s[1] & rightmask) >> shift); - d = (dd += dst->stride); - s = (ss += src->stride); - } + dd = dst->data + y * dst->stride + leftbyte; + bytewidth = (((uint32_t) x + w - 1) >> 3) - leftbyte + 1; + leftmask = 255>>(x&7); + rightmask = (((x+w)&7) == 0) ? 255 : ~(255>>((x+w)&7)); + if (bytewidth == 1) + leftmask &= rightmask; + late = (ss + bytewidth >= src->data + ((src->width+7)>>3)); + ss += syoffset; + + switch(op) + { + case JBIG2_COMPOSE_OR: + jbig2_image_compose_opt_OR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride); + break; + case JBIG2_COMPOSE_AND: + jbig2_image_compose_opt_AND(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride); + break; + case JBIG2_COMPOSE_XOR: + jbig2_image_compose_opt_XOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride); + break; + case JBIG2_COMPOSE_XNOR: + jbig2_image_compose_opt_XNOR(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride); + break; + case JBIG2_COMPOSE_REPLACE: + jbig2_image_compose_opt_REPLACE(ss, dd, early, late, leftmask, rightmask, bytewidth, h, shift, dst->stride, src->stride); + break; } return 0; diff --git a/jbig2dec/jbig2_mmr.c b/jbig2dec/jbig2_mmr.c index c3229df7..dcb36753 100644 --- a/jbig2dec/jbig2_mmr.c +++ b/jbig2dec/jbig2_mmr.c @@ -27,6 +27,7 @@ #endif #include "os_types.h" +#include <assert.h> #include <stddef.h> #include <stdio.h> #include <string.h> @@ -745,7 +746,10 @@ const mmr_table_node jbig2_mmr_black_decode[] = { static uint32_t jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w) { - int a, b; + int a; + uint8_t all8; + uint16_t all16; + uint32_t all32; if (line == NULL) return w; @@ -760,13 +764,128 @@ jbig2_find_changing_element(const byte *line, uint32_t x, uint32_t w) return x; } - while (x < w) { - b = getbit(line, x); - if (a != b) - break; - x++; + /* We will be looking for a uint8 or uint16 or uint32 that has at least one + bit different from <a>, so prepare some useful values for comparison. */ + all8 = (a) ? 0xff : 0; + all16 = (a) ? 0xffff : 0; + all32 = (a) ? 0xffffffff : 0; + + /* Check individual bits up to next 8-bit boundary. + + [Would it be worth looking at top 4 bits, then at 2 bits then at 1 bit, + instead of iterating over all 8 bits? */ + + if ( ((uint8_t*) line)[ x / 8] == all8) { + /* Don't bother checking individual bits if the enclosing uint8 equals + all8 - just move to the next byte. */ + x = x / 8 * 8 + 8; + if (x >= w) { + x = w; + goto end; + } + } else { + for(;;) { + if (x == w) { + goto end; + } + if (x % 8 == 0) { + break; + } + if (getbit(line, x) != a) { + goto end; + } + x += 1; + } + } + + assert(x % 8 == 0); + /* Check next uint8 if we are not on 16-bit boundary. */ + if (x % 16) { + if (w - x < 8) { + goto check1; + } + if ( ((uint8_t*) line)[ x / 8] != all8) { + goto check1; + } + x += 8; /* This will make x a multiple of 16. */ + } + + assert(x % 16 == 0); + /* Check next uint16 if we are not on 32-bit boundary. */ + if (x % 32) { + if (w - x < 16) { + goto check8; + } + if ( ((uint16_t*) line)[ x / 16] != all16) { + goto check8_no_eof; + } + x += 16; /* This will make x a multiple of 32. */ + } + + /* We are now on a 32-bit boundary. Check uint32's until we reach last + sub-32-bit region. */ + assert(x % 32 == 0); + for(;;) { + if (w - x < 32) { + /* We could still look at the uint32 here - if it equals all32, we + know there is no match before <w> so could do {x = w; goto end;}. + + But for now we simply fall into the epilogue checking, which will + look at the next uint16, then uint8, then last 8 bits. */ + goto check16; + } + if (((uint32_t*) line)[x/32] != all32) { + goto check16_no_eof; + } + x += 32; + } + + /* Check next uint16. */ +check16: + assert(x % 16 == 0); + if (w - x < 16) { + goto check8; + } +check16_no_eof: + assert(w - x >= 16); + if ( ((uint16_t*) line)[x/16] != all16) { + goto check8_no_eof; + } + x += 16; + + /* Check next uint8. */ +check8: + assert(x % 8 == 0); + if (w - x < 8) { + goto check1; + } +check8_no_eof: + assert(w - x >= 8); + if ( ((uint8_t*) line)[x/8] != all8) { + goto check1; + } + x += 8; + + /* Check up to the next 8 bits. */ +check1: + assert(x % 8 == 0); + if ( ((uint8_t*) line)[ x / 8] == all8) { + x = w; + goto end; + } + { + for(;;) { + if (x == w) { + goto end; + } + if (getbit(line, x) != a) { + goto end; + } + x += 1; + } } +end: return x; } diff --git a/jbig2dec/jbig2_page.c b/jbig2dec/jbig2_page.c index c07842b7..47445597 100644 --- a/jbig2dec/jbig2_page.c +++ b/jbig2dec/jbig2_page.c @@ -34,6 +34,13 @@ #include "jbig2_page.h" #include "jbig2_segment.h" +#if !defined (INT32_MAX) +#define INT32_MAX 0x7fffffff +#endif +#if !defined (UINT32_MAX) +#define UINT32_MAX 0xffffffff +#endif + /* dump the page struct info */ static void dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page) @@ -262,13 +269,21 @@ jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *image, uint32_ { int code; + if (x > INT32_MAX || y > INT32_MAX) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unsupported image coordinates"); + /* ensure image exists first */ if (page->image == NULL) return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page info possibly missing, no image defined"); /* grow the page to accommodate a new stripe if necessary */ if (page->striped && page->height == 0xFFFFFFFF) { - uint32_t new_height = y + image->height; + uint32_t new_height; + + if (y > UINT32_MAX - image->height) + return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "adding image at coordinate would grow page out of bounds"); + new_height = y + image->height; + if (page->image->height < new_height) { Jbig2Image *resized_image = NULL; diff --git a/jbig2dec/jbig2_priv.h b/jbig2dec/jbig2_priv.h index 0fee2b99..cf117e6c 100644 --- a/jbig2dec/jbig2_priv.h +++ b/jbig2dec/jbig2_priv.h @@ -20,9 +20,8 @@ #ifndef _JBIG2_PRIV_H #define _JBIG2_PRIV_H -/* To enable Memento, either uncomment the following, or arrange to - * predefine MEMENTO whilst building. */ -/* #define MEMENTO */ +/* To enable Memento predefine MEMENTO while building by setting + CFLAGS=-DMEMENTO. */ /* If we are being compiled as part of a larger project that includes * Memento, that project should define JBIG_EXTERNAL_MEMENTO_H to point @@ -116,7 +115,11 @@ void *jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num) #define jbig2_renew(ctx, p, t, size) ((t *)jbig2_realloc(ctx->allocator, (p), size, sizeof(t))) -int jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t seg_idx, const char *fmt, ...); +int jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t seg_idx, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__ ((format (__printf__, 4, 5))) +#endif + ; /* The word stream design is a compromise between simplicity and trying to amortize the number of method calls. Each ::get_next_word @@ -133,4 +136,15 @@ Jbig2WordStream *jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size void jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws); +/* restrict is standard in C99, but not in all C++ compilers. */ +#if defined (__STDC_VERSION_) && (__STDC_VERSION__ >= 199901L) /* C99 */ +#define JBIG2_RESTRICT restrict +#elif defined(_MSC_VER) && (_MSC_VER >= 1600) /* MSVC 10 or newer */ +#define JBIG2_RESTRICT __restrict +#elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC 3 or newer */ +#define JBIG2_RESTRICT __restrict +#else /* Unknown or ancient */ +#define JBIG2_RESTRICT +#endif + #endif /* _JBIG2_PRIV_H */ diff --git a/jbig2dec/jbig2_refinement.c b/jbig2dec/jbig2_refinement.c index 2c3ba29e..7c391b03 100644 --- a/jbig2dec/jbig2_refinement.c +++ b/jbig2dec/jbig2_refinement.c @@ -57,8 +57,7 @@ jbig2_decode_refinement_template0_unopt(Jbig2Ctx *ctx, const int dy = params->GRREFERENCEDY; uint32_t CONTEXT; int x, y; - bool bit; - int code = 0; + int bit; if (pixel_outside_field(params->grat[0], params->grat[1]) || refpixel_outside_field(params->grat[2], params->grat[3])) @@ -81,8 +80,8 @@ jbig2_decode_refinement_template0_unopt(Jbig2Ctx *ctx, CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12; - bit = jbig2_arith_decode(as, &GR_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling refinement template0"); jbig2_image_set_pixel(image, x, y, bit); } @@ -120,8 +119,7 @@ jbig2_decode_refinement_template1_unopt(Jbig2Ctx *ctx, const int dy = params->GRREFERENCEDY; uint32_t CONTEXT; int x, y; - bool bit; - int code = 0; + int bit; for (y = 0; y < GRH; y++) { for (x = 0; x < GRW; x++) { @@ -136,8 +134,8 @@ jbig2_decode_refinement_template1_unopt(Jbig2Ctx *ctx, CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9; - bit = jbig2_arith_decode(as, &GR_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling refinement template0"); jbig2_image_set_pixel(image, x, y, bit); } @@ -177,7 +175,6 @@ jbig2_decode_refinement_template1(Jbig2Ctx *ctx, byte *grreg_line = (byte *) image->data; byte *grref_line = (byte *) params->reference->data; int x, y; - int code = 0; for (y = 0; y < GRH; y++) { const int padded_width = (GRW + 7) & -8; @@ -212,10 +209,10 @@ jbig2_decode_refinement_template1(Jbig2Ctx *ctx, /* this is the speed critical inner-loop */ for (x_minor = 0; x_minor < minor_width; x_minor++) { - bool bit; + int bit; - bit = jbig2_arith_decode(as, &GR_stats[CONTEXT], &code); - if (code) + bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode arithmetic code when handling refinement template1"); result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x0d6) << 1) | bit | @@ -308,10 +305,9 @@ jbig2_decode_refinement_TPGRON(Jbig2Ctx *ctx, const Jbig2RefinementRegionParams { const int GRW = image->width; const int GRH = image->height; - int x, y, iv, bit, LTP = 0; + int x, y, iv, LTP = 0; uint32_t start_context = (params->GRTEMPLATE ? 0x40 : 0x100); ContextBuilder mkctx = (params->GRTEMPLATE ? mkctx1 : mkctx0); - int code = 0; if (params->GRTEMPLATE == 0 && (pixel_outside_field(params->grat[0], params->grat[1]) || @@ -320,13 +316,14 @@ jbig2_decode_refinement_TPGRON(Jbig2Ctx *ctx, const Jbig2RefinementRegionParams "adaptive template pixel is out of field"); for (y = 0; y < GRH; y++) { - LTP ^= jbig2_arith_decode(as, &GR_stats[start_context], &code); - if (code) + int bit = jbig2_arith_decode(as, &GR_stats[start_context]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode arithmetic code when handling refinement TPGRON1"); + LTP ^= bit; if (!LTP) { for (x = 0; x < GRW; x++) { - bit = jbig2_arith_decode(as, &GR_stats[mkctx(params, image, x, y)], &code); - if (code) + bit = jbig2_arith_decode(as, &GR_stats[mkctx(params, image, x, y)]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode arithmetic code when handling refinement TPGRON1"); jbig2_image_set_pixel(image, x, y, bit); } @@ -334,8 +331,8 @@ jbig2_decode_refinement_TPGRON(Jbig2Ctx *ctx, const Jbig2RefinementRegionParams for (x = 0; x < GRW; x++) { iv = implicit_value(params, image, x, y); if (iv < 0) { - bit = jbig2_arith_decode(as, &GR_stats[mkctx(params, image, x, y)], &code); - if (code) + int bit = jbig2_arith_decode(as, &GR_stats[mkctx(params, image, x, y)]); + if (bit < 0) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to decode arithmetic code when handling refinement TPGRON1"); jbig2_image_set_pixel(image, x, y, bit); } else diff --git a/jbig2dec/jbig2_segment.c b/jbig2dec/jbig2_segment.c index 9c47f630..2b561969 100644 --- a/jbig2dec/jbig2_segment.c +++ b/jbig2dec/jbig2_segment.c @@ -87,7 +87,7 @@ jbig2_parse_segment_header(Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, size_t referred_to_segment_size = result->number <= 256 ? 1 : result->number <= 65536 ? 2 : 4; /* 7.2.5 */ pa_size = result->flags & 0x40 ? 4 : 1; /* 7.2.6 */ if (offset + referred_to_segment_count * referred_to_segment_size + pa_size + 4 > buf_size) { - jbig2_error(ctx, JBIG2_SEVERITY_FATAL, result->number, "insufficient data to parse segment header", -1); + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, result->number, "insufficient data to parse segment header"); jbig2_free(ctx->allocator, result); return NULL; } @@ -334,7 +334,7 @@ int jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, - "segment %d, flags=%x, type=%d, data_length=%d", segment->number, segment->flags, segment->flags & 63, segment->data_length); + "segment %d, flags=%x, type=%d, data_length=%ld", segment->number, segment->flags, segment->flags & 63, (long) segment->data_length); switch (segment->flags & 63) { case 0: return jbig2_symbol_dictionary(ctx, segment, segment_data); diff --git a/jbig2dec/jbig2_symbol_dict.c b/jbig2dec/jbig2_symbol_dict.c index 93ea09d5..7d0c3a1d 100644 --- a/jbig2dec/jbig2_symbol_dict.c +++ b/jbig2dec/jbig2_symbol_dict.c @@ -664,14 +664,14 @@ jbig2_decode_symbol_dict(Jbig2Ctx *ctx, /* SumatraPDF: prevent read access violation */ if (size < jbig2_huffman_offset(hs) || (size - jbig2_huffman_offset(hs) < (size_t) image->height * stride) || (size < jbig2_huffman_offset(hs))) { - jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding uncompressed (%d/%d)", image->height * stride, - size - jbig2_huffman_offset(hs)); + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding uncompressed (%d/%li)", image->height * stride, + (long) (size - jbig2_huffman_offset(hs))); goto cleanup; } BMSIZE = (size_t) image->height * stride; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, - "reading %dx%d uncompressed bitmap for %d symbols (%d bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE); + "reading %dx%d uncompressed bitmap for %d symbols (%li bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, (long) BMSIZE); for (j = 0; j < image->height; j++) { memcpy(dst, src, stride); @@ -683,12 +683,12 @@ jbig2_decode_symbol_dict(Jbig2Ctx *ctx, /* SumatraPDF: prevent read access violation */ if (size < jbig2_huffman_offset(hs) || size < BMSIZE || size - jbig2_huffman_offset(hs) < BMSIZE) { - jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%d/%d)", BMSIZE, size - jbig2_huffman_offset(hs)); + jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%li/%li)", (long) BMSIZE, (long) (size - jbig2_huffman_offset(hs))); goto cleanup; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, - "reading %dx%d collective bitmap for %d symbols (%d bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE); + "reading %dx%d collective bitmap for %d symbols (%li bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, (long) BMSIZE); rparams.MMR = 1; code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data + jbig2_huffman_offset(hs), BMSIZE, image); @@ -1034,7 +1034,7 @@ jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segmen jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder states for generic regions"); goto cleanup; } - memset(GB_stats, 0, stats_size); + memset(GB_stats, 0, sizeof (Jbig2ArithCx) * stats_size); stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13; GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); diff --git a/jbig2dec/jbig2_text.c b/jbig2dec/jbig2_text.c index 7fb9eb08..57b31de0 100644 --- a/jbig2dec/jbig2_text.c +++ b/jbig2dec/jbig2_text.c @@ -221,9 +221,8 @@ cleanup1: jbig2_release_huffman_table(ctx, runcodes); if (SBSYMCODES == NULL) { - code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to construct symbol ID huffman table"); jbig2_huffman_free(ctx, hs); - return code; + return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to construct symbol ID huffman table"); } } diff --git a/jbig2dec/jbig2dec.1 b/jbig2dec/jbig2dec.1 index 3933d381..01f960a5 100644 --- a/jbig2dec/jbig2dec.1 +++ b/jbig2dec/jbig2dec.1 @@ -1,4 +1,4 @@ -.TH jbig2dec 1 "2019 September 17" "Version 0.17" "jbig2dec Manual" +.TH jbig2dec 1 "2020 February 11" "Version 0.18" "jbig2dec Manual" .SH NAME jbig2dec \- File format converter specialized in JBIG2 decoding diff --git a/jbig2dec/jbig2dec.c b/jbig2dec/jbig2dec.c index 5e3f5e5a..4f95589b 100644 --- a/jbig2dec/jbig2dec.c +++ b/jbig2dec/jbig2dec.c @@ -35,6 +35,12 @@ #include "os_types.h" #include "sha1.h" +#ifdef JBIG_EXTERNAL_MEMENTO_H +#include JBIG_EXTERNAL_MEMENTO_H +#else +#include "memento.h" +#endif + #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_image.h" @@ -589,6 +595,8 @@ main(int argc, char **argv) cleanup: flush_errors(¶ms); jbig2_ctx_free(ctx); + if (params.last_message) + free(params.last_message); if (params.output_filename) free(params.output_filename); if (params.hash) diff --git a/jbig2dec/memento.c b/jbig2dec/memento.c index 8ebe0e57..ab48bfbb 100644 --- a/jbig2dec/memento.c +++ b/jbig2dec/memento.c @@ -45,10 +45,12 @@ int atexit(void (*)(void)); #ifndef _MSC_VER #include <stdint.h> #include <limits.h> +#include <unistd.h> #endif #include <stdlib.h> #include <stdarg.h> +#include <string.h> #ifdef __ANDROID__ #define MEMENTO_ANDROID @@ -59,9 +61,11 @@ int atexit(void (*)(void)); #ifdef _MSC_VER #define FMTZ "%llu" #define FMTZ_CAST _int64 +#define FMTP "0x%p" #else #define FMTZ "%zu" #define FMTZ_CAST size_t +#define FMTP "%p" #endif #define UB(x) ((intptr_t)((x) & 0xFF)) @@ -251,7 +255,8 @@ enum { Memento_Flag_BreakOnFree = 4, Memento_Flag_BreakOnRealloc = 8, Memento_Flag_Freed = 16, - Memento_Flag_KnownLeak = 32 + Memento_Flag_KnownLeak = 32, + Memento_Flag_Reported = 64 }; enum { @@ -452,6 +457,7 @@ extern void backtrace_symbols_fd(void **, size_t, int); extern char **backtrace_symbols(void **, size_t); #define MEMENTO_BACKTRACE_MAX 256 +static void (*print_stack_value)(void *address); /* Libbacktrace gubbins - relies on us having libdl to load the .so */ #ifdef HAVE_LIBDL @@ -489,7 +495,6 @@ static backtrace_create_state_type backtrace_create_state; static backtrace_pcinfo_type backtrace_pcinfo; static struct backtrace_state *my_backtrace_state; static void *libbt; -static void (*print_stack_value)(void *address); static char backtrace_exe[4096]; static void *current_addr; @@ -535,7 +540,30 @@ static void print_stack_libbt(void *addr) static void print_stack_libbt_failed(void *addr) { - char **strings = backtrace_symbols(&addr, 1); + char **strings; +#if 0 + /* Let's use a hack from Julian Smith to call gdb to extract the information */ + /* Disabled for now, as I can't make this work. */ + static char command[1024]; + int e; + static int gdb_invocation_failed = 0; + + if (gdb_invocation_failed == 0) + { + snprintf(command, sizeof(command), + //"gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null", + "gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null| egrep -v '(Thread debugging using)|(Using host libthread_db library)|(A debugging session is active)|(will be detached)|(Quit anyway)|(No such file or directory)|(^0x)|(^$)'", + getpid(), addr); + printf("%s\n", command); + e = system(command); + if (e == 0) + return; /* That'll do! */ + gdb_invocation_failed = 1; /* If it's failed once, it'll probably keep failing. */ + } +#endif + + /* We couldn't even get gdb! Make do. */ + strings = backtrace_symbols(&addr, 1); if (strings == NULL || strings[0] == NULL) { @@ -553,6 +581,12 @@ static void print_stack_libbt_failed(void *addr) static int init_libbt(void) { + static int libbt_inited = 0; + + if (libbt_inited) + return 0; + libbt_inited = 1; + libbt = dlopen("libbacktrace.so", RTLD_LAZY); if (libbt == NULL) libbt = dlopen("/opt/lib/libbacktrace.so", RTLD_LAZY); @@ -588,6 +622,9 @@ static int init_libbt(void) return 1; fail: + fprintf(stderr, + "MEMENTO: libbacktrace.so failed to load; backtraces will be sparse.\n" + "MEMENTO: See memento.h for how to rectify this.\n"); libbt = NULL; backtrace_create_state = NULL; backtrace_syminfo = NULL; @@ -602,7 +639,7 @@ static void print_stack_default(void *addr) if (strings == NULL || strings[0] == NULL) { - fprintf(stderr, " [0x%p]\n", addr); + fprintf(stderr, " ["FMTP"]\n", addr); } #ifdef HAVE_LIBDL else if (strchr(strings[0], ':') == NULL) @@ -614,7 +651,7 @@ static void print_stack_default(void *addr) { memcpy(backtrace_exe, strings[0], s - strings[0]); backtrace_exe[s-strings[0]] = 0; - if (init_libbt()) + init_libbt(); print_stack_value(addr); } } @@ -846,12 +883,12 @@ static void Memento_showStacktrace(void **stack, int numberOfFrames) const char *sym = info.dli_sname ? info.dli_sname : "<unknown>"; char *demangled = __cxa_demangle(sym, NULL, 0, &status); int offset = stack[i] - info.dli_saddr; - fprintf(stderr, " [%p]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset); + fprintf(stderr, " ["FMTP"]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset); free(demangled); } else { - fprintf(stderr, " [%p]\n", stack[i]); + fprintf(stderr, " ["FMTP"]\n", stack[i]); } } } @@ -1255,14 +1292,19 @@ static int Memento_appBlock(Memento_Blocks *blks, } #endif /* MEMENTO_LEAKONLY */ -static void showBlock(Memento_BlkHeader *b, int space) +static int showBlock(Memento_BlkHeader *b, int space) { - fprintf(stderr, "0x%p:(size=" FMTZ ",num=%d)", + int seq; + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); + fprintf(stderr, FMTP":(size=" FMTZ ",num=%d)", MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence); if (b->label) fprintf(stderr, "%c(%s)", space, b->label); if (b->flags & Memento_Flag_KnownLeak) fprintf(stderr, "(Known Leak)"); + seq = b->sequence; + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + return seq; } static void blockDisplay(Memento_BlkHeader *b, int n) @@ -1291,7 +1333,9 @@ static int Memento_listBlock(Memento_BlkHeader *b, size_t *counts = (size_t *)arg; blockDisplay(b, 0); counts[0]++; + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); counts[1]+= b->rawsize; + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); return 0; } @@ -1300,15 +1344,19 @@ static void doNestedDisplay(Memento_BlkHeader *b, { /* Try and avoid recursion if we can help it */ do { + Memento_BlkHeader *c = NULL; blockDisplay(b, depth); + VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader)); if (b->sibling) { - if (b->child) - doNestedDisplay(b->child, depth+1); + c = b->child; b = b->sibling; } else { b = b->child; depth++; } + VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); + if (c) + doNestedDisplay(c, depth+1); } while (b); } @@ -1494,7 +1542,7 @@ static int showInfo(Memento_BlkHeader *b, void *arg) { Memento_BlkDetails *details; - fprintf(stderr, "0x%p:(size="FMTZ",num=%d)", + fprintf(stderr, FMTP":(size="FMTZ",num=%d)", MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence); if (b->label) fprintf(stderr, " (%s)", b->label); @@ -1526,9 +1574,15 @@ static int Memento_nonLeakBlocksLeaked(void) Memento_BlkHeader *blk = memento.used.head; while (blk) { - if ((blk->flags & Memento_Flag_KnownLeak) == 0) + Memento_BlkHeader *next; + int leaked; + VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk)); + leaked = ((blk->flags & Memento_Flag_KnownLeak) == 0); + next = blk->next; + VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk)); + if (leaked) return 1; - blk = blk->next; + blk = next; } return 0; } @@ -1583,6 +1637,9 @@ static void Memento_init(void) env = getenv("MEMENTO_FAILAT"); memento.failAt = (env ? atoi(env) : 0); + env = getenv("MEMENTO_BREAKAT"); + memento.breakAt = (env ? atoi(env) : 0); + env = getenv("MEMENTO_PARANOIA"); memento.paranoia = (env ? atoi(env) : 0); if (memento.paranoia == 0) @@ -1804,6 +1861,7 @@ static void Memento_startFailing(void) { if (!memento.failing) { fprintf(stderr, "Starting to fail...\n"); + Memento_bt(); fflush(stderr); memento.failing = 1; memento.failAt = memento.sequence; @@ -2347,7 +2405,11 @@ static int checkBlockUser(Memento_BlkHeader *memblk, const char *action) } fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, memento.sequence); + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; Memento_breakpointLocked(); + } return 1; } #endif @@ -2394,7 +2456,11 @@ static int checkBlock(Memento_BlkHeader *memblk, const char *action) } fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, memento.sequence); + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; Memento_breakpointLocked(); + } return 1; } #endif @@ -2585,6 +2651,11 @@ static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg data->preCorrupt = 0; data->postCorrupt = 0; data->freeCorrupt = 0; + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; + Memento_breakpointLocked(); + } } else memblk->lastCheckedOK = memento.sequence; @@ -2604,7 +2675,7 @@ static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg) fprintf(stderr, " "); showBlock(memblk, ' '); if (data->freeCorrupt) { - fprintf(stderr, " index %d (address 0x%p) onwards", (int)data->index, + fprintf(stderr, " index %d (address "FMTP") onwards", (int)data->index, &((char *)MEMBLK_TOBLK(memblk))[data->index]); if (data->preCorrupt) { fprintf(stderr, "+ preguard"); @@ -2621,9 +2692,16 @@ static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg) (data->preCorrupt ? "+" : "")); } } + VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(Memento_BlkHeader)); fprintf(stderr, " corrupted.\n" " Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, memento.sequence); + if ((memblk->flags & Memento_Flag_Reported) == 0) + { + memblk->flags |= Memento_Flag_Reported; + Memento_breakpointLocked(); + } + VALGRIND_MAKE_MEM_NOACCESS(memblk, sizeof(Memento_BlkHeader)); data->preCorrupt = 0; data->postCorrupt = 0; data->freeCorrupt = 0; @@ -2702,6 +2780,7 @@ int Memento_check(void) int Memento_find(void *a) { findBlkData data; + int s; MEMENTO_LOCK(); data.addr = a; @@ -2709,27 +2788,27 @@ int Memento_find(void *a) data.flags = 0; Memento_appBlocks(&memento.used, Memento_containsAddr, &data); if (data.blk != NULL) { - fprintf(stderr, "Address 0x%p is in %sallocated block ", + fprintf(stderr, "Address "FMTP" is in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); + s = showBlock(data.blk, ' '); fprintf(stderr, "\n"); MEMENTO_UNLOCK(); - return data.blk->sequence; + return s; } data.blk = NULL; data.flags = 0; Memento_appBlocks(&memento.free, Memento_containsAddr, &data); if (data.blk != NULL) { - fprintf(stderr, "Address 0x%p is in %sfreed block ", + fprintf(stderr, "Address "FMTP" is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); - showBlock(data.blk, ' '); + s = showBlock(data.blk, ' '); fprintf(stderr, "\n"); MEMENTO_UNLOCK(); - return data.blk->sequence; + return s; } MEMENTO_UNLOCK(); return 0; @@ -2745,13 +2824,15 @@ void Memento_breakOnFree(void *a) data.flags = 0; Memento_appBlocks(&memento.used, Memento_containsAddr, &data); if (data.blk != NULL) { - fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", + fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, ") is freed\n"); + VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader)); data.blk->flags |= Memento_Flag_BreakOnFree; + VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader)); MEMENTO_UNLOCK(); return; } @@ -2759,7 +2840,7 @@ void Memento_breakOnFree(void *a) data.flags = 0; Memento_appBlocks(&memento.free, Memento_containsAddr, &data); if (data.blk != NULL) { - fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ", + fprintf(stderr, "Can't stop on free; address "FMTP" is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); @@ -2768,7 +2849,7 @@ void Memento_breakOnFree(void *a) MEMENTO_UNLOCK(); return; } - fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a); + fprintf(stderr, "Can't stop on free; address "FMTP" is not in a known block.\n", a); MEMENTO_UNLOCK(); } @@ -2782,13 +2863,15 @@ void Memento_breakOnRealloc(void *a) data.flags = 0; Memento_appBlocks(&memento.used, Memento_containsAddr, &data); if (data.blk != NULL) { - fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", + fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, ") is freed (or realloced)\n"); + VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader)); data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc; + VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader)); MEMENTO_UNLOCK(); return; } @@ -2796,7 +2879,7 @@ void Memento_breakOnRealloc(void *a) data.flags = 0; Memento_appBlocks(&memento.free, Memento_containsAddr, &data); if (data.blk != NULL) { - fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ", + fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); @@ -2805,7 +2888,7 @@ void Memento_breakOnRealloc(void *a) MEMENTO_UNLOCK(); return; } - fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a); + fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is not in a known block.\n", a); MEMENTO_UNLOCK(); } @@ -2834,6 +2917,11 @@ void Memento_stopLeaking(void) memento.leaking--; } +int Memento_squeezing(void) +{ + return memento.squeezing; +} + #endif /* MEMENTO_CPP_EXTRAS_ONLY */ #ifdef __cplusplus @@ -3033,4 +3121,9 @@ void (Memento_stopLeaking)(void) { } +int (Memento_squeezing)(void) +{ + return 0; +} + #endif diff --git a/jbig2dec/memento.h b/jbig2dec/memento.h index d8cf5b34..b822479f 100644 --- a/jbig2dec/memento.h +++ b/jbig2dec/memento.h @@ -75,8 +75,7 @@ * An example: * Suppose we have a gs invocation that crashes with memory corruption. * * Build with -DMEMENTO. - * * In your debugger put breakpoints on Memento_inited and - * Memento_Breakpoint. + * * In your debugger put a breakpoint on Memento_breakpoint. * * Run the program. It will stop in Memento_inited. * * Execute Memento_setParanoia(1); (In VS use Ctrl-Alt-Q). (Note #1) * * Continue execution. @@ -92,9 +91,9 @@ * and 1458 - so if we rerun and stop the program at 1457, we can then * step through, possibly with a data breakpoint at 0x172e710 and see * when it occurs. - * * So restart the program from the beginning. When we hit Memento_inited - * execute Memento_breakAt(1457); (and maybe Memento_setParanoia(1), or - * Memento_setParanoidAt(1457)) + * * So restart the program from the beginning. When we stop after + * initialisation execute Memento_breakAt(1457); (and maybe + * Memento_setParanoia(1), or Memento_setParanoidAt(1457)) * * Continue execution until we hit Memento_breakpoint. * * Now you can step through and watch the memory corruption happen. * @@ -157,6 +156,30 @@ * Both Windows and GCC provide separate new[] and delete[] operators * for arrays. Apparently some systems do not. If this is the case for * your system, define MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS. + * + * "libbacktrace.so failed to load" + * + * In order to give nice backtraces on unix, Memento will try to use + * a libbacktrace dynamic library. If it can't find it, you'll see + * that warning, and your backtraces won't include file/line information. + * + * To fix this you'll need to build your own libbacktrace. Don't worry + * it's really easy: + * git clone git://github.com/ianlancetaylor/libbacktrace + * cd libbacktrace + * ./configure + * make + * + * This leaves the build .so as .libs/libbacktrace.so + * + * Memento will look for this on LD_LIBRARY_PATH, or in /opt/lib/, + * or in /lib/, or in /usr/lib/, or in /usr/local/lib/. I recommend + * using /opt/lib/ as this won't conflict with anything that you + * get via a package manager like apt. + * + * sudo mkdir /opt + * sudo mkdir /opt/lib + * sudo cp .libs/libbacktrace.so /opt/lib/ */ #ifndef MEMENTO_H @@ -238,6 +261,8 @@ void Memento_stopLeaking(void); int Memento_sequence(void); +int Memento_squeezing(void); + void Memento_fin(void); void Memento_bt(void); @@ -299,6 +324,7 @@ void Memento_bt(void); #define Memento_fin() do {} while (0) #define Memento_bt() do {} while (0) #define Memento_sequence() (0) +#define Memento_squeezing() (0) #endif /* MEMENTO */ diff --git a/jbig2dec/msvc.mak b/jbig2dec/msvc.mak index 94bc548f..5c2d6bd9 100644 --- a/jbig2dec/msvc.mak +++ b/jbig2dec/msvc.mak @@ -42,10 +42,11 @@ FE=-Fe # OBJS=getopt$(OBJ) getopt1$(OBJ) jbig2$(OBJ) jbig2_arith$(OBJ) \ jbig2_arith_iaid$(OBJ) jbig2_arith_int$(OBJ) jbig2_huffman$(OBJ) \ - jbig2_generic$(OBJ) jbig2_refinement$(OBJ) jbig2_halftone$(OBJ)\ - jbig2_image$(OBJ) jbig2_image_pbm$(OBJ) $(JBIG2_IMAGE_PNG_OBJ) \ - jbig2_segment$(OBJ) jbig2_symbol_dict$(OBJ) jbig2_text$(OBJ) \ - jbig2_mmr$(OBJ) jbig2_page$(OBJ) jbig2dec$(OBJ) sha1$(OBJ) + jbig2_hufftab$(OBJ) jbig2_generic$(OBJ) jbig2_refinement$(OBJ) \ + jbig2_halftone$(OBJ) jbig2_image$(OBJ) jbig2_image_pbm$(OBJ) \ + $(JBIG2_IMAGE_PNG_OBJ) jbig2_segment$(OBJ) jbig2_symbol_dict$(OBJ) \ + jbig2_text$(OBJ) jbig2_mmr$(OBJ) jbig2_page$(OBJ) jbig2dec$(OBJ) \ + sha1$(OBJ) HDRS=getopt.h jbig2.h jbig2_arith.h jbig2_arith_iaid.h jbig2_arith_int.h \ jbig2_generic.h jbig2_huffman.h jbig2_hufftab.h jbig2_image.h \ @@ -83,6 +84,9 @@ jbig2_refinement$(OBJ): jbig2_refinement.c $(HDRS) jbig2_huffman$(OBJ): jbig2_huffman.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_huffman.c +jbig2_hufftab$(OBJ): jbig2_hufftab.c $(HDRS) + $(CC) $(CFLAGS) -c jbig2_hufftab.c + jbig2_image$(OBJ): jbig2_image.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_image.c diff --git a/jbig2dec/test_jbig2dec.py b/jbig2dec/test_jbig2dec.py index a8414383..629b685e 100755 --- a/jbig2dec/test_jbig2dec.py +++ b/jbig2dec/test_jbig2dec.py @@ -4,6 +4,7 @@ import os, re import sys, time +import hashlib class SelfTest: 'generic class for self tests' @@ -60,92 +61,82 @@ class KnownFileHash(SelfTest): # hashes of known test inputs known_NOTHING_DECODED = "da39a3ee5e6b4b0d3255bfef95601890afd80709" + known_WHITE_PAGE_DECODED = "28a6bd83a8a3a36910fbc1f5ce06c962e4332911" known_042_DECODED = "ebfdf6e2fc5ff3ee2271c2fa19de0e52712046e8" known_amb_DECODED = "3d4b7992d506894662b53415bd3d0d2a2f8b7953" # these are known test files in the form # (filename, sha-1(file), sha-1(decoded document) - known_hashes = ( ('../ubc/042_1.jb2', - "673e1ee5c55ab241b171e476ba1168a42733ddaa", - known_042_DECODED), - ('../ubc/042_2.jb2', - "9aa2804e2d220952035c16fb3c907547884067c5", - known_042_DECODED), - ('../ubc/042_3.jb2', - "9663a5f35727f13e61a0a2f0a64207b1f79e7d67", - known_042_DECODED), - ('../ubc/042_4.jb2', - "014df658c8b99b600c2ceac3f1d53c7cc2b4917c", - known_042_DECODED), - ('../ubc/042_5.jb2', - "264720a6ccbbf72aa6a2cfb6343f43b8e6f2da4b", - known_042_DECODED), - ('../ubc/042_6.jb2', - "96f7dc9df4a1b305f9ac082dd136f85ef5b108fe", - known_042_DECODED), - ('../ubc/042_7.jb2', - "5526371ba9dc2b8743f20ae3e05a7e60b3dcba76", - known_042_DECODED), - ('../ubc/042_8.jb2', - "4bf0c87dfaf40d67c36f2a083579eeda26d54641", - known_042_DECODED), - ('../ubc/042_9.jb2', - "53e630e7fe2fe6e1d6164758e15fc93382e07f55", - known_042_DECODED), - ('../ubc/042_10.jb2', - "5ca1364367e25cb8f642e9dc677a94d5cfed0c8b", - known_042_DECODED), - ('../ubc/042_11.jb2', - "bc194caf022bc5345fc41259e05cea3c08245216", - known_042_DECODED), - ('../ubc/042_12.jb2', - "f354df8eb4849bc707f088739e322d1fe3a14ef3", - known_042_DECODED), - ('../ubc/042_13.jb2', - "7d428bd542f58591b254d9827f554b0552c950a7", - known_NOTHING_DECODED), - ('../ubc/042_14.jb2', - "c40fe3a02acb6359baf9b40fc9c49bc0800be589", - known_NOTHING_DECODED), - ('../ubc/042_15.jb2', - "a9e39fc1ecb178aec9f05039514d75ea3246246c", - known_042_DECODED), - ('../ubc/042_16.jb2', - "4008bbca43670f3c90eaee26516293ba95baaf3d", - known_042_DECODED), - ('../ubc/042_17.jb2', - "0ff95637b64c57d659a41c582da03e25321551fb", - known_042_DECODED), - ('../ubc/042_18.jb2', - "87381d044f00c4329200e44decbe91bebfa31595", - known_042_DECODED), - ('../ubc/042_19.jb2', - "387d95a140b456d4742622c788cf5b51cebbf438", - known_042_DECODED), - ('../ubc/042_20.jb2', - "85c19e9ec42b8ddd6b860a1bebea1c67610e7a59", - known_042_DECODED), - ('../ubc/042_21.jb2', - "ab535c7d7a61a7b9dc53d546e7419ca78ac7f447", - known_042_DECODED), - ('../ubc/042_22.jb2', - "a9e2b365be63716dbde74b0661c3c6efd2a6844d", - known_042_DECODED), - ('../ubc/042_23.jb2', - "8ffa40a05e93e10982b38a2233a8da58c1b5c343", - known_042_DECODED), - ('../ubc/042_24.jb2', - "2553fe65111c58f6412de51d8cdc71651e778ccf", - known_042_DECODED), - ('../ubc/042_25.jb2', - "52de4a3b86252d896a8d783ba71dd0699333dd69", - known_042_DECODED), - ('../ubc/amb_1.jb2', - "d6d6d1c981dc37a09108c1e3ed990aa5b345fa6a", - known_amb_DECODED), - ('../ubc/amb_2.jb2', - "9af6616a89eb03f8934de72626e301a716366c3c", - known_amb_DECODED) + known_hashes = ( + ('tests/ubc/042_1.jb2', "673e1ee5c55ab241b171e476ba1168a42733ddaa", known_042_DECODED), + ('tests/ubc/042_2.jb2', "9aa2804e2d220952035c16fb3c907547884067c5", known_042_DECODED), + ('tests/ubc/042_3.jb2', "9663a5f35727f13e61a0a2f0a64207b1f79e7d67", known_042_DECODED), + ('tests/ubc/042_4.jb2', "014df658c8b99b600c2ceac3f1d53c7cc2b4917c", known_042_DECODED), + ('tests/ubc/042_5.jb2', "264720a6ccbbf72aa6a2cfb6343f43b8e6f2da4b", known_042_DECODED), + ('tests/ubc/042_6.jb2', "96f7dc9df4a1b305f9ac082dd136f85ef5b108fe", known_042_DECODED), + ('tests/ubc/042_7.jb2', "5526371ba9dc2b8743f20ae3e05a7e60b3dcba76", known_042_DECODED), + ('tests/ubc/042_8.jb2', "4bf0c87dfaf40d67c36f2a083579eeda26d54641", known_042_DECODED), + ('tests/ubc/042_9.jb2', "53e630e7fe2fe6e1d6164758e15fc93382e07f55", known_042_DECODED), + ('tests/ubc/042_10.jb2', "5ca1364367e25cb8f642e9dc677a94d5cfed0c8b", known_042_DECODED), + ('tests/ubc/042_11.jb2', "bc194caf022bc5345fc41259e05cea3c08245216", known_042_DECODED), + ('tests/ubc/042_12.jb2', "f354df8eb4849bc707f088739e322d1fe3a14ef3", known_042_DECODED), + ('tests/ubc/042_13.jb2', "7d428bd542f58591b254d9827f554b0552c950a7", known_WHITE_PAGE_DECODED), + ('tests/ubc/042_14.jb2', "c40fe3a02acb6359baf9b40fc9c49bc0800be589", known_WHITE_PAGE_DECODED), + ('tests/ubc/042_15.jb2', "a9e39fc1ecb178aec9f05039514d75ea3246246c", known_042_DECODED), + ('tests/ubc/042_16.jb2', "4008bbca43670f3c90eaee26516293ba95baaf3d", known_042_DECODED), + ('tests/ubc/042_17.jb2', "0ff95637b64c57d659a41c582da03e25321551fb", known_042_DECODED), + ('tests/ubc/042_18.jb2', "87381d044f00c4329200e44decbe91bebfa31595", known_042_DECODED), + ('tests/ubc/042_19.jb2', "387d95a140b456d4742622c788cf5b51cebbf438", known_042_DECODED), + ('tests/ubc/042_20.jb2', "85c19e9ec42b8ddd6b860a1bebea1c67610e7a59", known_042_DECODED), + ('tests/ubc/042_21.jb2', "ab535c7d7a61a7b9dc53d546e7419ca78ac7f447", known_042_DECODED), + ('tests/ubc/042_22.jb2', "a9e2b365be63716dbde74b0661c3c6efd2a6844d", known_042_DECODED), + ('tests/ubc/042_23.jb2', "8ffa40a05e93e10982b38a2233a8da58c1b5c343", known_042_DECODED), + ('tests/ubc/042_24.jb2', "2553fe65111c58f6412de51d8cdc71651e778ccf", known_042_DECODED), + ('tests/ubc/042_25.jb2', "52de4a3b86252d896a8d783ba71dd0699333dd69", known_042_DECODED), + + ('tests/ubc/amb_1.jb2', "d6d6d1c981dc37a09108c1e3ed990aa5b345fa6a", known_amb_DECODED), + ('tests/ubc/amb_2.jb2', "9af6616a89eb03f8934de72626e301a716366c3c", known_amb_DECODED), + + ('tests/ubc/200-10-0.jb2', "f6014b43775640ef0874497e0873f8deb291cc32", "49cddf903d3451ba23297a6b68502504093979cf"), + ('tests/ubc/200-10-0-stripe.jb2', "d19f58cd180afd1ae2afd11c96471e98c7c6f125", "ac89ae2046c4859348418830287982b6d60bf39b"), + ('tests/ubc/200-10-45.jb2', "504297b028810f812cbf075597f589a9fb82121b", "38aa99e40c6a746391c26c953223bcd4549cadd0"), + ('tests/ubc/200-10-45-stripe.jb2', "0d9f2a63c9fd224a6b60a9b7c0cd658f47551edd", "2921889fc5ffaafb348084761aa7c54831ec57ba"), + ('tests/ubc/200-20-0.jb2', "a40aaf33dd4c3225728ddfc0fad12167ceff1b17", "cc1732742d5d68c6d5c3f4eec9d5887e9ee24cd0"), + ('tests/ubc/200-20-0-stripe.jb2', "d499a89baf69a1b5f6fa450ec20b21136052b4cd", "743aa86e7abc9e238e23d02fbc993b048589282a"), + ('tests/ubc/200-20-45.jb2', "a39f1e2670f1c08dbd07d14a99965bf7253e6318", "7213fb351f65397c12accf662787aa3bc028c40f"), + ('tests/ubc/200-20-45-stripe.jb2', "3aa44cdef38fc8e34376480408ca99364ccbf0ee", "9021716b3eca4da549508db691655eddc4d51548"), + ('tests/ubc/200-2-0.jb2', "087f529ba6e3cc5fca3773c1d07e39fb642f5052", "534fceffada398444ce065088a37b6d6517a3406"), + ('tests/ubc/200-2-0-stripe.jb2', "dc227f7531ccecda08511bda9359864c66a8d230", "56f0e25ae5863a75d69a1825b820ba004e48d2c4"), + ('tests/ubc/200-3-0.jb2', "024a20b82e794eb469b4fae2b4f930c5c079fd6b", "57fe3645b028e6c7a68dcf707674f889038ee4b5"), + ('tests/ubc/200-3-0-stripe.jb2', "2322db7dc956863b7257d28a212431e304661998", "32ea498b28a46bf04e0b799c70114ab99ce7d15e"), + ('tests/ubc/200-3-45.jb2', "21ba06f8cfcc31b5bd7fa39ad98093180d3e05aa", "83e01d0a83d167fe00f7389e5fec0a660841aeef"), + ('tests/ubc/200-3-45-stripe.jb2', "6dfe3cbb019ef0c30ecae7d2196b1b3fd7634288", "20c2ade5766eeb3a70dca9963029c0a74171064b"), + ('tests/ubc/200-4-0.jb2', "c7d8d8b8a97388b0fcc6e5e3d8708fbce0881edf", "b85fe470db7542789b0632dc87dbdc721e07ddf5"), + ('tests/ubc/200-4-0-stripe.jb2', "840f076fd542b2ae8d0d1663ed7efd5683326bc7", "0acd5a6f24637dad4b948fa24563b1fae04996be"), + ('tests/ubc/200-4-45.jb2', "6ed49af06268d57137436ffeea2def6f93ea17eb", "5177abf7e9d641ca4f553bd4847134e51bb1159a"), + ('tests/ubc/200-4-45-stripe.jb2', "0dfc5b59a046ab05364298b1767334298fa03eeb", "944a399d8763007ae0477f69b80ec28d7fbe6edd"), + ('tests/ubc/200-5-0.jb2', "47770e4144b022790af00098ac830ac8665f62a0", "515eaf8e4537bbda841abf3b7ffbd1b4728c7597"), + ('tests/ubc/200-5-0-stripe.jb2', "23f784c297c204bc1bf7cd1559a7c38a95097266", "c69e97f9e1a7e45d6eb3975ecb8a4a7dd7f09e2e"), + ('tests/ubc/200-5-45.jb2', "193376e966e8bc22868e38791289e810953b5483", "77fff5286023b77316221d5c36a6d40f8b905ca9"), + ('tests/ubc/200-5-45-stripe.jb2', "d211863df684b5c113c2e29aec72c6a533681356", "efd7b9ae877bf3d71c0baa604a1014e1218ada90"), + ('tests/ubc/200-6-0.jb2', "e66a8cff6c00575018253a06f9309192cc796fb2", "7b5dae69e6f8953463dd29707f77225cd8a543ad"), + ('tests/ubc/200-6-0-stripe.jb2', "55ba1b94e73d96defbb7abbe35ccf13b4e1ac89f", "e8a1b55780dde4102f37ca5fafeff29bbd30e867"), + ('tests/ubc/200-6-45.jb2', "71d167f8af4e6c2a3202c26873aedf490e8da8f2", "9093ba8bfc65b87dddc310d437b8ca626ee2283c"), + ('tests/ubc/200-6-45-stripe.jb2', "abcf8f71f9ce0cb65c43942ecf0cfda7ece5d7ff", "397a48e4f3a3261928b2175699104117e36349e6"), + ('tests/ubc/200-8-0.jb2', "e7004846acb5529d5335c16315d11c188edea89d", "8cfa43f514911d35d9666e52ae51bbd93a9bddfc"), + ('tests/ubc/200-8-0-stripe.jb2', "0d96be49231e7e5a52c41bfa7303768465a9fa81", "021fbcfa12122999cded6beea3b7aa3c7018acbd"), + ('tests/ubc/200-8-45.jb2', "e28403c3bf1014a5b5e9c3c3e5e99cae47aa09ab", "669986963011b174d5352d38e6c77f459ff3bebd"), + ('tests/ubc/200-8-45-stripe.jb2', "c2e19b3e51d06c102a06643f3ea15f77d6df3788", "ceb0ef29cb68fe53d9abceb45ab182c1e6a39ff7"), + ('tests/ubc/200-lossless.jb2', "b9989aea1a3edd65e38e7fbeaa89a29d7a2aa342", "94d9324437bc27955e610ef4fbbd684ad3107fea"), + ('tests/ubc/600-10-0.jb2', "46c9af206382243d838f86ea45c63e7ca2900b68", "0ad323815315270f02f8220ed3b69133a1639f74"), + ('tests/ubc/600-10-45.jb2', "1f143e95bf57d8d2696525797e198efd785f7221", "16002bb4e4cefbb58da5dde531b1064b9e6ad1a7"), + ('tests/ubc/600-20-0.jb2', "8c874b1fb89e714ef8c64f33d292db2aea4fd05f", "a537aac28d9e0ea27d43a38024962f86aa1e403b"), + ('tests/ubc/600-20-45.jb2', "a9c94915dd140916bc14db7b4bc9fc5d7e73b5a9", "5af6ec6f2e8ae68cfb6df3f82bf47ee2f6c4f0b5"), + ('tests/ubc/600-30-0.jb2', "f0b9eea13b5c7a18742238778f1a3b7e1a4d3361", "6feaffc771381922a578bc54c4b50d18e7933ea1"), + ('tests/ubc/600-30-45.jb2', "65bb4202b575bba6063ef3597a5eefa356b5e660", "768788c5176d5ffb5d8d0855d8ab34312611f67d"), + ('tests/ubc/600-6-0.jb2', "c54abd4bdbb26b1f1209dc03ab10c05cdfd7a63a", "baba4bc5359c0fafc54efcba14da2bd5943222be"), + ('tests/ubc/600-6-45.jb2', "94f4f6ea60eda33e0cd8bb94a5a0f90dc05f96a7", "bc3afe7c37533ca43f3244e6877ce38b3e978e9f"), + ('tests/ubc/600-lossless.jb2', "60ecd5ddfb0984e3d2691bc385f425a50c753019", "f632d82b3c3d500098ad560e5ab91c69bd20827f") ) def __init__(self, file, file_hash, decode_hash): @@ -159,11 +150,18 @@ class KnownFileHash(SelfTest): def runTest(self): '''jbig2dec should return proper document hashes for known files''' + # verify that the input file hash is correct + sha1 = hashlib.sha1() + with open(self.file, 'rb') as f: + sha1.update(f.read()) + self.assertEqual(self.file_hash, sha1.hexdigest()) + # invoke jbig2dec on our file instance = os.popen('./jbig2dec -q -o /dev/null --hash ' + self.file) lines = instance.readlines() exit_code = instance.close() self.failIf(exit_code, 'jbig2dec should exit normally') + # test here for correct hash hash_pattern = re.compile('[0-9a-f]{%d}' % len(decode_hash)) for line in lines: |