On further consideration, I believe getPos() is the wrong function to
call (and is implemented wrong anyway). I believe the newly attached
patch is more correct.
(Although, it doesn't look like JBIG2Stream::getPos is ever called anyway.)
I'm not sure why it bothers to subclass FilterStream though.
David Benjamin
On 06/07/2009 08:46 PM, David Benjamin wrote:
So, I've been tracking down a bug in JBIG2Stream. It fails to render
PDFs at [1] (second column) by misdetecting segments of incorrect length
(and then eats up useful bytes at line 1445). JBIG2Stream appears to
bypass FilterStream::str and uses it's own curStr[2], so getPos() is
wrong at the beginning.
Attached is a (trivial) patch to fix this. I'm not entirely sure if this
is the "correct" thing to do here; the current setup feels pretty iffy
anyway, but I get the feeling getPos() should not suddenly jump in the
middle of a stream? I don't really know poppler's code, so I'm not sure
what guarantees are Stream/FilterStream supposed to provide to users or
if they're exported API in the first place.
(At least internally in JBIG2Stream the only non-error-reporting use of
getPos is the segment-length-detection bit.)
[1] http://www.adobe.com/products/acrcapture/agentpack/index.html
[2] It seems to want to swap the stream out temporarily at reset()...
I'm not sure why; I'm unfamiliar with JBIG2.
commit 783c8bcefe589590332f730bd2fa6821fa50d8f9
Author: David Benjamin <[email protected]>
Date: Sun Jun 7 20:41:38 2009 -0400
Fix getPos() in JBIG2Stream
FilterStream's getPos() calls str->getPos() which is bypassed in JBIG2Stream in
favor of curStr in JBIG2Stream::reset(). This broke extraneous-byte-detection
logic and misparsed PDFs on
http://www.adobe.com/products/acrcapture/agentpack/index.html
Given JBIG2Stream's setup, getPos() is the wrong method to call. Use
curStr->getPos() instead.
diff --git a/poppler/JBIG2Stream.cc b/poppler/JBIG2Stream.cc
index 56a6490..d55797a 100644
--- a/poppler/JBIG2Stream.cc
+++ b/poppler/JBIG2Stream.cc
@@ -1252,6 +1252,13 @@ int JBIG2Stream::lookChar() {
return EOF;
}
+int JBIG2Stream::getPos() {
+ if (pageBitmap == NULL) {
+ return 0;
+ }
+ return dataPtr - pageBitmap->getDataPtr();
+}
+
GooString *JBIG2Stream::getPSFilter(int psLevel, char *indent) {
return NULL;
}
@@ -1333,12 +1340,12 @@ void JBIG2Stream::readSegments() {
}
// keep track of the start of the segment data
- segDataPos = getPos();
+ segDataPos = curStr->getPos();
// check for missing page information segment
if (!pageBitmap && ((segType >= 4 && segType <= 7) ||
(segType >= 20 && segType <= 43))) {
- error(getPos(), "First JBIG2 segment associated with a page must be a page information segment");
+ error(curStr->getPos(), "First JBIG2 segment associated with a page must be a page information segment");
goto syntaxError;
}
@@ -1410,7 +1417,7 @@ void JBIG2Stream::readSegments() {
readExtensionSeg(segLength);
break;
default:
- error(getPos(), "Unknown segment type in JBIG2 stream");
+ error(curStr->getPos(), "Unknown segment type in JBIG2 stream");
for (i = 0; i < segLength; ++i) {
if ((c1 = curStr->getChar()) == EOF) {
goto eofError2;
@@ -1425,7 +1432,7 @@ void JBIG2Stream::readSegments() {
if (segLength != 0xffffffff) {
- int segExtraBytes = segDataPos + segLength - getPos();
+ int segExtraBytes = segDataPos + segLength - curStr->getPos();
if (segExtraBytes > 0) {
// If we didn't read all of the bytes in the segment data,
@@ -1436,7 +1443,7 @@ void JBIG2Stream::readSegments() {
// arithmetic-coded symbol dictionary segments when numNewSyms
// == 0. Segments like this often occur for blank pages.
- error(getPos(), "%d extraneous byte%s after segment",
+ error(curStr->getPos(), "%d extraneous byte%s after segment",
segExtraBytes, (segExtraBytes > 1) ? "s" : "");
// Burn through the remaining bytes -- inefficient, but
@@ -1452,7 +1459,7 @@ void JBIG2Stream::readSegments() {
// If we read more bytes than we should have, according to the
// segment length field, note an error.
- error(getPos(), "Previous segment handler read too many bytes");
+ error(curStr->getPos(), "Previous segment handler read too many bytes");
}
@@ -1470,7 +1477,7 @@ void JBIG2Stream::readSegments() {
eofError2:
gfree(refSegs);
eofError1:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
@@ -1560,7 +1567,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
if (seg->getType() == jbig2SegSymbolDict) {
j = ((JBIG2SymbolDict *)seg)->getSize();
if (numInputSyms > UINT_MAX - j) {
- error(getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Too many input symbols in JBIG2 symbol dictionary");
delete codeTables;
goto eofError;
}
@@ -1574,7 +1581,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
}
}
if (numInputSyms > UINT_MAX - numNewSyms) {
- error(getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Too many input symbols in JBIG2 symbol dictionary");
delete codeTables;
goto eofError;
}
@@ -1692,7 +1699,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
arithDecoder->decodeInt(&dh, iadhStats);
}
if (dh < 0 && (Guint)-dh >= symHeight) {
- error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
goto syntaxError;
}
symHeight += dh;
@@ -1714,12 +1721,12 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
}
}
if (dw < 0 && (Guint)-dw >= symWidth) {
- error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
goto syntaxError;
}
symWidth += dw;
if (i >= numNewSyms) {
- error(getPos(), "Too many symbols in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Too many symbols in JBIG2 symbol dictionary");
goto syntaxError;
}
@@ -1759,7 +1766,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
arithDecoder->decodeInt(&refDY, iardyStats);
}
if (symID >= numInputSyms + i) {
- error(getPos(), "Invalid symbol ID in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Invalid symbol ID in JBIG2 symbol dictionary");
goto syntaxError;
}
refBitmap = bitmaps[symID];
@@ -1834,7 +1841,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
}
if (i + run > numInputSyms + numNewSyms ||
(ex && j + run > numExSyms)) {
- error(getPos(), "Too many exported symbols in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Too many exported symbols in JBIG2 symbol dictionary");
for ( ; j < numExSyms; ++j) symbolDict->setBitmap(j, NULL);
delete symbolDict;
goto syntaxError;
@@ -1849,7 +1856,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
ex = !ex;
}
if (j != numExSyms) {
- error(getPos(), "Too few symbols in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Too few symbols in JBIG2 symbol dictionary");
for ( ; j < numExSyms; ++j) symbolDict->setBitmap(j, NULL);
delete symbolDict;
goto syntaxError;
@@ -1877,7 +1884,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
return gTrue;
codeTableError:
- error(getPos(), "Missing code table in JBIG2 symbol dictionary");
+ error(curStr->getPos(), "Missing code table in JBIG2 symbol dictionary");
delete codeTables;
syntaxError:
@@ -1893,7 +1900,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
return gFalse;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
return gFalse;
}
@@ -1981,7 +1988,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
codeTables->append(seg);
}
} else {
- error(getPos(), "Invalid segment reference in JBIG2 text region");
+ error(curStr->getPos(), "Invalid segment reference in JBIG2 text region");
delete codeTables;
return;
}
@@ -2190,13 +2197,13 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
return;
codeTableError:
- error(getPos(), "Missing code table in JBIG2 text region");
+ error(curStr->getPos(), "Missing code table in JBIG2 text region");
gfree(codeTables);
delete syms;
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
return;
}
@@ -2297,7 +2304,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
}
if (symID >= (Guint)numSyms) {
- error(getPos(), "Invalid symbol number in JBIG2 text region");
+ error(curStr->getPos(), "Invalid symbol number in JBIG2 text region");
} else {
// get the symbol bitmap
@@ -2464,7 +2471,7 @@ void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) {
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm,
@@ -2506,22 +2513,22 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm,
goto eofError;
}
if (w == 0 || h == 0 || w >= INT_MAX / h) {
- error(getPos(), "Bad bitmap size in JBIG2 halftone segment");
+ error(curStr->getPos(), "Bad bitmap size in JBIG2 halftone segment");
return;
}
if (gridH == 0 || gridW >= INT_MAX / gridH) {
- error(getPos(), "Bad grid size in JBIG2 halftone segment");
+ error(curStr->getPos(), "Bad grid size in JBIG2 halftone segment");
return;
}
// get pattern dictionary
if (nRefSegs != 1) {
- error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
+ error(curStr->getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
return;
}
seg = findSegment(refSegs[0]);
if (seg == NULL || seg->getType() != jbig2SegPatternDict) {
- error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
+ error(curStr->getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
return;
}
@@ -2624,7 +2631,7 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm,
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm,
@@ -2700,14 +2707,14 @@ void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm,
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
inline void JBIG2Stream::mmrAddPixels(int a1, int blackPixels,
int *codingLine, int *a0i, int w) {
if (a1 > codingLine[*a0i]) {
if (a1 > w) {
- error(getPos(), "JBIG2 MMR row is wrong length (%d)", a1);
+ error(curStr->getPos(), "JBIG2 MMR row is wrong length (%d)", a1);
a1 = w;
}
if ((*a0i & 1) ^ blackPixels) {
@@ -2721,7 +2728,7 @@ inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels,
int *codingLine, int *a0i, int w) {
if (a1 > codingLine[*a0i]) {
if (a1 > w) {
- error(getPos(), "JBIG2 MMR row is wrong length (%d)", a1);
+ error(curStr->getPos(), "JBIG2 MMR row is wrong length (%d)", a1);
a1 = w;
}
if ((*a0i & 1) ^ blackPixels) {
@@ -2730,7 +2737,7 @@ inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels,
codingLine[*a0i] = a1;
} else if (a1 < codingLine[*a0i]) {
if (a1 < 0) {
- error(getPos(), "Invalid JBIG2 MMR code");
+ error(curStr->getPos(), "Invalid JBIG2 MMR code");
a1 = 0;
}
while (*a0i > 0 && a1 <= codingLine[*a0i - 1]) {
@@ -2767,7 +2774,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
mmrDecoder->reset();
if (w > INT_MAX - 2) {
- error(getPos(), "Bad width in JBIG2 generic bitmap");
+ error(curStr->getPos(), "Bad width in JBIG2 generic bitmap");
// force a call to gmalloc(-1), which will throw an exception
w = -3;
}
@@ -2924,7 +2931,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
mmrAddPixels(w, 0, codingLine, &a0i, w);
break;
default:
- error(getPos(), "Illegal code in JBIG2 MMR bitmap data");
+ error(curStr->getPos(), "Illegal code in JBIG2 MMR bitmap data");
mmrAddPixels(w, 0, codingLine, &a0i, w);
break;
}
@@ -2947,7 +2954,7 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
mmrDecoder->skipTo(mmrDataLength);
} else {
if (mmrDecoder->get24Bits() != 0x001001) {
- error(getPos(), "Missing EOFB in JBIG2 MMR bitmap data");
+ error(curStr->getPos(), "Missing EOFB in JBIG2 MMR bitmap data");
}
}
@@ -3187,13 +3194,13 @@ void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm,
// get referenced bitmap
if (nRefSegs > 1) {
- error(getPos(), "Bad reference in JBIG2 generic refinement segment");
+ error(curStr->getPos(), "Bad reference in JBIG2 generic refinement segment");
return;
}
if (nRefSegs == 1) {
seg = findSegment(refSegs[0]);
if (seg == NULL || seg->getType() != jbig2SegBitmap) {
- error(getPos(), "Bad bitmap reference in JBIG2 generic refinement segment");
+ error(curStr->getPos(), "Bad bitmap reference in JBIG2 generic refinement segment");
return;
}
refBitmap = (JBIG2Bitmap *)seg;
@@ -3230,7 +3237,7 @@ void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm,
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
@@ -3459,7 +3466,7 @@ void JBIG2Stream::readPageInfoSeg(Guint length) {
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
void JBIG2Stream::readEndOfStripeSeg(Guint length) {
@@ -3541,7 +3548,7 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) {
return;
eofError:
- error(getPos(), "Unexpected EOF in JBIG2 stream");
+ error(curStr->getPos(), "Unexpected EOF in JBIG2 stream");
}
void JBIG2Stream::readExtensionSeg(Guint length) {
diff --git a/poppler/JBIG2Stream.h b/poppler/JBIG2Stream.h
index ca1fee7..d484531 100644
--- a/poppler/JBIG2Stream.h
+++ b/poppler/JBIG2Stream.h
@@ -36,6 +36,7 @@ public:
virtual StreamKind getKind() { return strJBIG2; }
virtual void reset();
virtual void close();
+ virtual int getPos();
virtual int getChar();
virtual int lookChar();
virtual GooString *getPSFilter(int psLevel, char *indent);
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler