Long offsetOrObjstmObNr = xrefTrailerResolver.getXrefTable().get(objKey);
// sanity test to circumvent loops with broken documents
if (requireExistingNotCompressedObj && ((offsetOrObjstmObNr == null)))
{
addValidationError(new ValidationError(ERROR_SYNTAX_MISSING_OFFSET,
"Object must be defined and must not be compressed object: " + objKey.getNumber() + ":"
+ objKey.getGeneration()));
throw new SyntaxValidationException("Object must be defined and must not be compressed object: "
+ objKey.getNumber() + ":" + objKey.getGeneration(), validationResult);
}
if (offsetOrObjstmObNr == null)
{
// not defined object -> NULL object (Spec. 1.7, chap. 3.2.9)
pdfObject.setObject(COSNull.NULL);
}
else if (offsetOrObjstmObNr == 0)
{
addValidationError(new ValidationError(ERROR_SYNTAX_INVALID_OFFSET, "Object {" + objKey.getNumber()
+ ":" + objKey.getGeneration() + "} has an offset of 0"));
}
else if (offsetOrObjstmObNr > 0)
{
// offset of indirect object in file
// ---- go to object start
setPdfSource(offsetOrObjstmObNr);
// ---- we must have an indirect object
long readObjNr = 0;
int readObjGen = 0;
long offset = pdfSource.getOffset();
String line = readLine();
Pattern pattern = Pattern.compile("(\\d+)\\s(\\d+)\\sobj");
Matcher matcher = pattern.matcher(line);
if (matcher.matches())
{
readObjNr = Integer.parseInt(matcher.group(1));
readObjGen = Integer.parseInt(matcher.group(2));
}
else
{
addValidationError(new ValidationError(ERROR_SYNTAX_OBJ_DELIMITER, "Single space expected [offset="+offset+"; key="+offsetOrObjstmObNr.toString()+"; line="+line+"; object="+pdfObject.toString()+"]"));
// reset pdfSource cursor to read object information
pdfSource.seek(offset);
readObjNr = readObjectNumber();
readObjGen = readGenerationNumber();
skipSpaces(); // skip spaces between Object Generation number and the 'obj' keyword
for (char c : OBJ_MARKER)
{
if (pdfSource.read() != c)
{
addValidationError(new ValidationError(ERROR_SYNTAX_OBJ_DELIMITER, "Expected pattern '"
+ new String(OBJ_MARKER) + " but missed at character '" + c + "'"));
throw new SyntaxValidationException("Expected pattern '" + new String(OBJ_MARKER)
+ " but missed at character '" + c + "'", validationResult);
}
}
}
// ---- consistency check
if ((readObjNr != objKey.getNumber()) || (readObjGen != objKey.getGeneration()))
{
throw new IOException("XREF for " + objKey.getNumber() + ":" + objKey.getGeneration()
+ " points to wrong object: " + readObjNr + ":" + readObjGen);
}
skipSpaces();
COSBase pb = parseDirObject();
skipSpaces();
long endObjectOffset = pdfSource.getOffset();
String endObjectKey = readString();
if (endObjectKey.equals("stream"))
{
pdfSource.seek(endObjectOffset);
if (pb instanceof COSDictionary)
{
COSStream stream = parseCOSStream((COSDictionary) pb);
if (securityHandler != null)
{
securityHandler.decryptStream(stream, objNr, objGenNr);
}
pb = stream;
}
else
{
// this is not legal
// the combination of a dict and the stream/endstream forms a complete stream object
throw new IOException("Stream not preceded by dictionary (offset: " + offsetOrObjstmObNr + ").");
}
skipSpaces();
endObjectOffset = pdfSource.getOffset();
endObjectKey = readString();
// we have case with a second 'endstream' before endobj
if (!endObjectKey.startsWith("endobj"))
{
if (endObjectKey.startsWith("endstream"))
{
endObjectKey = endObjectKey.substring(9).trim();
if (endObjectKey.length() == 0)
{
// no other characters in extra endstream line
endObjectKey = readString(); // read next line
}
}
}
}
else if (securityHandler != null)
{
// decrypt
if (pb instanceof COSString)
{
decrypt((COSString) pb, objNr, objGenNr);
}
else if (pb instanceof COSDictionary)
{
for (Entry<COSName, COSBase> entry : ((COSDictionary) pb).entrySet())
{
// TODO: specially handle 'Contents' entry of signature dictionary like in
// SecurityHandler#decryptDictionary
if (entry.getValue() instanceof COSString)
{
decrypt((COSString) entry.getValue(), objNr, objGenNr);
}
}
}
else if (pb instanceof COSArray)
{
final COSArray array = (COSArray) pb;
for (int aIdx = 0, len = array.size(); aIdx < len; aIdx++)
{
if (array.get(aIdx) instanceof COSString)
{
decrypt((COSString) array.get(aIdx), objNr, objGenNr);
}
}
}
}
pdfObject.setObject(pb);
if (!endObjectKey.startsWith("endobj"))
{
throw new IOException("Object (" + readObjNr + ":" + readObjGen + ") at offset "
+ offsetOrObjstmObNr + " does not end with 'endobj'.");
}
else
{
offset = pdfSource.getOffset();
pdfSource.seek(endObjectOffset - 1);
if (!nextIsEOL())
{
addValidationError(new ValidationError(PreflightConstants.ERROR_SYNTAX_OBJ_DELIMITER,
"EOL expected before the 'endobj' keyword at offset "+pdfSource.getOffset()));
}
pdfSource.seek(offset);
}
if (!nextIsEOL())
{
addValidationError(new ValidationError(PreflightConstants.ERROR_SYNTAX_OBJ_DELIMITER,
"EOL expected after the 'endobj' keyword at offset "+pdfSource.getOffset()));
}
releasePdfSourceInputStream();
}