summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'jbig2dec')
-rw-r--r--jbig2dec/CHANGES21
-rw-r--r--jbig2dec/Makefile.am2
-rw-r--r--jbig2dec/Makefile.unix6
-rwxr-xr-xjbig2dec/autogen.sh2
-rw-r--r--jbig2dec/config_win32.h9
-rw-r--r--jbig2dec/jbig2.c12
-rw-r--r--jbig2dec/jbig2.h7
-rw-r--r--jbig2dec/jbig2_arith.c98
-rw-r--r--jbig2dec/jbig2_arith.h3
-rw-r--r--jbig2dec/jbig2_arith_iaid.c5
-rw-r--r--jbig2dec/jbig2_arith_int.c29
-rw-r--r--jbig2dec/jbig2_generic.c675
-rw-r--r--jbig2dec/jbig2_halftone.c12
-rw-r--r--jbig2dec/jbig2_huffman.c10
-rw-r--r--jbig2dec/jbig2_hufftab.c318
-rw-r--r--jbig2dec/jbig2_hufftab.h305
-rw-r--r--jbig2dec/jbig2_image.c386
-rw-r--r--jbig2dec/jbig2_mmr.c131
-rw-r--r--jbig2dec/jbig2_page.c17
-rw-r--r--jbig2dec/jbig2_priv.h22
-rw-r--r--jbig2dec/jbig2_refinement.c37
-rw-r--r--jbig2dec/jbig2_segment.c4
-rw-r--r--jbig2dec/jbig2_symbol_dict.c12
-rw-r--r--jbig2dec/jbig2_text.c3
-rw-r--r--jbig2dec/jbig2dec.12
-rw-r--r--jbig2dec/jbig2dec.c8
-rw-r--r--jbig2dec/memento.c147
-rw-r--r--jbig2dec/memento.h36
-rw-r--r--jbig2dec/msvc.mak12
-rwxr-xr-xjbig2dec/test_jbig2dec.py160
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(&params);
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: