Parser.cc (xpdf-4.03) | : | Parser.cc (xpdf-4.04) | ||
---|---|---|---|---|
skipping to change at line 155 | skipping to change at line 155 | |||
buf1.copy(obj); | buf1.copy(obj); | |||
shift(); | shift(); | |||
} | } | |||
return obj; | return obj; | |||
} | } | |||
Stream *Parser::makeStream(Object *dict, Guchar *fileKey, | Stream *Parser::makeStream(Object *dict, Guchar *fileKey, | |||
CryptAlgorithm encAlgorithm, int keyLength, | CryptAlgorithm encAlgorithm, int keyLength, | |||
int objNum, int objGen, int recursion) { | int objNum, int objGen, int recursion) { | |||
Object obj; | ||||
BaseStream *baseStr; | ||||
Stream *str, *str2; | ||||
GFileOffset pos, endPos, length; | ||||
char endstreamBuf[8]; | ||||
GBool foundEndstream; | ||||
int c, i; | ||||
// get stream start position | // get stream start position | |||
lexer->skipToNextLine(); | lexer->skipToNextLine(); | |||
if (!(str = lexer->getStream())) { | Stream *curStr = lexer->getStream(); | |||
if (!curStr) { | ||||
return NULL; | return NULL; | |||
} | } | |||
pos = str->getPos(); | GFileOffset pos = curStr->getPos(); | |||
GBool haveLength = gFalse; | ||||
GFileOffset length = 0; | ||||
GFileOffset endPos; | ||||
// check for length in damaged file | // check for length in damaged file | |||
if (xref && xref->getStreamEnd(pos, &endPos)) { | if (xref && xref->getStreamEnd(pos, &endPos)) { | |||
length = endPos - pos; | length = endPos - pos; | |||
haveLength = gTrue; | ||||
// get length from the stream object | // get length from the stream object | |||
} else { | } else { | |||
Object obj; | ||||
dict->dictLookup("Length", &obj, recursion); | dict->dictLookup("Length", &obj, recursion); | |||
if (obj.isInt()) { | if (obj.isInt()) { | |||
length = (GFileOffset)(Guint)obj.getInt(); | length = (GFileOffset)(Guint)obj.getInt(); | |||
obj.free(); | haveLength = gTrue; | |||
} else { | } else { | |||
error(errSyntaxError, getPos(), "Bad 'Length' attribute in stream"); | error(errSyntaxError, getPos(), | |||
obj.free(); | "Missing or invalid 'Length' attribute in stream"); | |||
return NULL; | ||||
} | } | |||
obj.free(); | ||||
} | } | |||
// in badly damaged PDF files, we can run off the end of the input | // in badly damaged PDF files, we can run off the end of the input | |||
// stream immediately after the "stream" token | // stream immediately after the "stream" token | |||
if (!lexer->getStream()) { | if (!lexer->getStream()) { | |||
return NULL; | return NULL; | |||
} | } | |||
// copy the base stream (Lexer will free stream objects when it gets | // copy the base stream (Lexer will free stream objects when it gets | |||
// to end of stream -- which can happen in the shift() calls below) | // to end of stream -- which can happen in the shift() calls below) | |||
baseStr = (BaseStream *)lexer->getStream()->getBaseStream()->copy(); | BaseStream *baseStr = | |||
(BaseStream *)lexer->getStream()->getBaseStream()->copy(); | ||||
// make new base stream | // 'Length' attribute is missing -- search for 'endstream' | |||
str = baseStr->makeSubStream(pos, gTrue, length, dict); | if (!haveLength) { | |||
GBool foundEndstream = gFalse; | ||||
char endstreamBuf[8]; | ||||
if ((curStr = lexer->getStream())) { | ||||
int c; | ||||
while ((c = curStr->getChar()) != EOF) { | ||||
if (c == 'e' && | ||||
curStr->getBlock(endstreamBuf, 8) == 8 && | ||||
!memcmp(endstreamBuf, "ndstream", 8)) { | ||||
length = curStr->getPos() - 9 - pos; | ||||
foundEndstream = gTrue; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
if (!foundEndstream) { | ||||
error(errSyntaxError, getPos(), "Couldn't find 'endstream' for stream"); | ||||
delete baseStr; | ||||
return NULL; | ||||
} | ||||
} | ||||
// skip over stream data | // make new base stream | |||
lexer->setPos(pos + length); | Stream *str = baseStr->makeSubStream(pos, gTrue, length, dict); | |||
// check for 'endstream' | // look for the 'endstream' marker | |||
// NB: we never reuse the Parser object to parse objects after a | if (haveLength) { | |||
// stream, and we could (if the PDF file is damaged) be in the | // skip over stream data | |||
// middle of binary data at this point, so we check the stream data | lexer->setPos(pos + length); | |||
// directly for 'endstream', rather than calling shift() to parse | ||||
// objects | // check for 'endstream' | |||
foundEndstream = gFalse; | // NB: we never reuse the Parser object to parse objects after a | |||
if ((str2 = lexer->getStream())) { | // stream, and we could (if the PDF file is damaged) be in the | |||
// skip up to 100 whitespace chars | // middle of binary data at this point, so we check the stream | |||
for (i = 0; i < 100; ++i) { | // data directly for 'endstream', rather than calling shift() to | |||
c = str2->getChar(); | // parse objects | |||
if (!Lexer::isSpace(c)) { | GBool foundEndstream = gFalse; | |||
break; | char endstreamBuf[8]; | |||
if ((curStr = lexer->getStream())) { | ||||
// skip up to 100 whitespace chars | ||||
int c; | ||||
for (int i = 0; i < 100; ++i) { | ||||
c = curStr->getChar(); | ||||
if (!Lexer::isSpace(c)) { | ||||
break; | ||||
} | ||||
} | } | |||
} | if (c == 'e') { | |||
if (c == 'e') { | if (curStr->getBlock(endstreamBuf, 8) == 8 && | |||
if (str2->getBlock(endstreamBuf, 8) == 8 || | !memcmp(endstreamBuf, "ndstream", 8)) { | |||
!memcmp(endstreamBuf, "ndstream", 8)) { | foundEndstream = gTrue; | |||
foundEndstream = gTrue; | } | |||
} | } | |||
} | } | |||
} | if (!foundEndstream) { | |||
if (!foundEndstream) { | error(errSyntaxError, getPos(), "Missing 'endstream'"); | |||
error(errSyntaxError, getPos(), "Missing 'endstream'"); | // kludge for broken PDF files: just add 5k to the length, and | |||
// kludge for broken PDF files: just add 5k to the length, and | // hope it's enough | |||
// hope it's enough | // (dict is now owned by str, so we need to copy it before deleting str) | |||
// (dict is now owned by str, so we need to copy it before deleting str) | Object obj; | |||
dict->copy(&obj); | dict->copy(&obj); | |||
delete str; | delete str; | |||
length += 5000; | length += 5000; | |||
str = baseStr->makeSubStream(pos, gTrue, length, &obj); | str = baseStr->makeSubStream(pos, gTrue, length, &obj); | |||
} | ||||
} | } | |||
// free the copied base stream | // free the copied base stream | |||
delete baseStr; | delete baseStr; | |||
// handle decryption | // handle decryption | |||
if (fileKey) { | if (fileKey) { | |||
str = new DecryptStream(str, fileKey, encAlgorithm, keyLength, | // the 'Crypt' filter is used to mark unencrypted metadata streams | |||
objNum, objGen); | //~ this should also check for an empty DecodeParams entry | |||
GBool encrypted = gTrue; | ||||
Object obj; | ||||
dict->dictLookup("Filter", &obj, recursion); | ||||
if (obj.isName("Crypt")) { | ||||
encrypted = gFalse; | ||||
} else if (obj.isArray() && obj.arrayGetLength() >= 1) { | ||||
Object obj2; | ||||
if (obj.arrayGet(0, &obj2)->isName("Crypt")) { | ||||
encrypted = gFalse; | ||||
} | ||||
obj2.free(); | ||||
} | ||||
obj.free(); | ||||
if (encrypted) { | ||||
str = new DecryptStream(str, fileKey, encAlgorithm, keyLength, | ||||
objNum, objGen); | ||||
} | ||||
} | } | |||
// get filters | // get filters | |||
str = str->addFilters(dict, recursion); | str = str->addFilters(dict, recursion); | |||
return str; | return str; | |||
} | } | |||
void Parser::shift() { | void Parser::shift() { | |||
if (inlineImg > 0) { | if (inlineImg > 0) { | |||
End of changes. 16 change blocks. | ||||
49 lines changed or deleted | 96 lines changed or added |