org.jpedal.io.ObjectDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
The newest version!
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/support/
*
* (C) Copyright 1997-2015 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* ObjectDecoder.java
* ---------------
*/
package org.jpedal.io;
import org.jpedal.io.types.*;
import org.jpedal.objects.raw.*;
import org.jpedal.color.ColorSpaces;
import org.jpedal.utils.*;
import java.io.*;
/**
*
*/
public class ObjectDecoder implements Serializable {
public PdfFileReader objectReader;
public DecryptionFactory decryption;
//string representation of key only used in debugging
private Object PDFkey;
static final byte[] endPattern = { 101, 110, 100, 111, 98, 106 }; //pattern endobj
//
public static final boolean debugFastCode =false; //objRef.equals("68 0 R")
/**/
private int pdfKeyType, PDFkeyInt;
/**used in debugging output*/
public static String padding="";
boolean isInlineImage;
private int endPt=-1;
public ObjectDecoder(final PdfFileReader pdfFileReader) {
init(pdfFileReader);
}
private void init(final PdfFileReader objectReader){
this.objectReader=objectReader;
this.decryption=objectReader.getDecryptionObject();
}
/**
* read a dictionary object
*/
public int readDictionaryAsObject(final PdfObject pdfObject, int i, final byte[] raw){
if(endPt==-1) {
endPt = raw.length;
}
//used to debug issues by printing out details for obj
//(set to non-final above)
//debugFastCode =pdfObject.getObjectRefAsString().equals("5 0 R");
if(debugFastCode) {
padding += " ";
}
final int length=raw.length;
//show details in debug mode
if(debugFastCode) {
ObjectUtils.showData(pdfObject, i, length, raw, padding);
}
/**
* main loop for read all values from Object data and store in PDF object
*/
i = readObjectDataValues(pdfObject, i, raw, length);
/**
* look for stream afterwards
*/
if(!pdfObject.ignoreStream() && pdfObject.getGeneralType(-1)!=PdfDictionary.ID) {
Stream.readStreamData(pdfObject, i, raw, length, objectReader);
}
/**
* we need full names for Forms
*/
if(pdfObject.getObjectType()==PdfDictionary.Form) {
Form.setFieldNames(pdfObject, objectReader);
}
/**
* reset indent in debugging
*/
if(debugFastCode){
final int len=padding.length();
if(len>3) {
padding = padding.substring(0, len - 3);
}
}
return i;
}
/**
* get the values from the data stream and store in PdfObject
* @param pdfObject
* @param i
* @param raw
* @param length
* @return
*/
private int readObjectDataValues(final PdfObject pdfObject, int i, final byte[] raw, final int length) {
int level=0;
//allow for no << at start
if(isInlineImage) {
level = 1;
}
while(true){
if(i=length ||
(endPt !=-1 && i>= endPt))||
(raw[i] == 101 && raw[i + 1] == 110 && raw[i + 2] == 100 && raw[i + 3] == 111)||
(raw[i]=='s' && raw[i+1]=='t' && raw[i+2]=='r' && raw[i+3]=='e' && raw[i+4]=='a' && raw[i+5]=='m')) {
break;
}
/**
* process value
*/
if(raw[i]==60 && raw[i+1]==60){
i++;
level++;
}else if(raw[i]==62 && i+1!=length && raw[i+1]==62 && raw[i-1]!=62){
i++;
level--;
if(level==0) {
break;
}
}else if (raw[i] == 47 && (raw[i+1] == 47 || raw[i+1]==32)) { //allow for oddity of //DeviceGray and / /DeviceGray in colorspace
i++;
}else if (raw[i] == 47) { //everything from /
i++; //skip /
final int keyStart=i;
final int keyLength= Dictionary.findDictionaryEnd(i, raw, length);
i += keyLength;
if(i==length) {
break;
}
//if BDC see if string
boolean isStringPair=false;
if(pdfObject.getID()== PdfDictionary.BDC) {
isStringPair = Dictionary.isStringPair(i, raw, isStringPair);
}
final int type=pdfObject.getObjectType();
if(debugFastCode) {
System.out.println("type=" + type + ' ' + ' ' + pdfObject.getID() + " chars=" + (char) raw[i - 1] + (char) raw[i] + (char) raw[i + 1] + ' ' + pdfObject + " i=" + i + ' ' + isStringPair);
}
//see if map of objects
final boolean isMap = isMapObject(pdfObject, i, raw, length, keyStart, keyLength, isStringPair, type);
if(raw[i]==47 || raw[i]==40 || (raw[i] == 91 && raw[i+1]!=']')) //move back cursor
{
i--;
}
//check for unknown value and ignore
if(pdfKeyType==-1) {
i = ObjectUtils.handleUnknownType(i, raw, length);
}
/**
* now read value
*/
if(PDFkeyInt==-1 || pdfKeyType==-1){
if(debugFastCode) {
System.out.println(padding + pdfObject.getObjectRefAsString() + " =================Not implemented=" + PDFkey + " pdfKeyType=" + pdfKeyType);
}
}else{
i = setValue(pdfObject, i, raw, length, isMap);
}
//special case if Dest defined as names object and indirect
}else if(raw[i]=='[' && level==0 && pdfObject.getObjectType()==PdfDictionary.Outlines){
final Array objDecoder=new Array(objectReader,i, raw.length, PdfDictionary.VALUE_IS_MIXED_ARRAY,null, PdfDictionary.Names);
objDecoder.readArray(false, raw, pdfObject, PdfDictionary.Dest);
}
i++;
}
return i;
}
private boolean isMapObject(final PdfObject pdfObject, final int i, final byte[] raw, final int length, final int keyStart, final int keyLength, final boolean stringPair, final int type) {
final boolean isMap;//ensure all go into 'pool'
if(type== PdfDictionary.MCID && (pdfObject.getID()==PdfDictionary.RoleMap ||
(pdfObject.getID()==PdfDictionary.BDC && stringPair) ||
(pdfObject.getID()==PdfDictionary.A && raw[i-2]=='/'))){
pdfKeyType=PdfDictionary.VALUE_IS_NAME;
//used in debug and this case
PDFkey=PdfDictionary.getKey(keyStart,keyLength,raw);
PDFkeyInt=PdfDictionary.MCID;
isMap=true;
}else{
isMap=false;
PDFkey=null;
getKeyType(pdfObject, i, raw, length, keyLength, keyStart, type);
}
return isMap;
}
private void getKeyType(final PdfObject pdfObject, final int i, final byte[] raw, final int length, final int keyLength, final int keyStart, final int type) {
/**
* get Dictionary key and type of value it takes
*/
if(debugFastCode)//used in debug
{
PDFkey = PdfDictionary.getKey(keyStart, keyLength, raw);
}
PDFkeyInt=PdfDictionary.getIntKey(keyStart,keyLength,raw);
//correct mapping
if(PDFkeyInt==PdfDictionary.Indexed && (type==PdfDictionary.MK ||type==PdfDictionary.Form || type==PdfDictionary.Linearized || type==PdfDictionary.Group)) {
PDFkeyInt = PdfDictionary.I;
}
if(isInlineImage) {
PDFkeyInt = PdfObjectFactory.getInlineID(PDFkeyInt);
}
final int id=pdfObject.getID();
if(type==PdfDictionary.Resources && (PDFkeyInt==PdfDictionary.ColorSpace
|| PDFkeyInt==PdfDictionary.ExtGState || PDFkeyInt==PdfDictionary.Shading
|| PDFkeyInt==PdfDictionary.XObject || PDFkeyInt==PdfDictionary.Font|| PDFkeyInt==PdfDictionary.Pattern)){
pdfKeyType=PdfDictionary.VALUE_IS_DICTIONARY_PAIRS;
//}else if (type==PdfDictionary.Form && id== PdfDictionary.AA && PDFkeyInt== PdfDictionary.K){
// pdfKeyType= PdfDictionary.VALUE_IS_UNREAD_DICTIONARY;
}else if (type==PdfDictionary.Outlines && PDFkeyInt== PdfDictionary.D){
PDFkeyInt= PdfDictionary.Dest;
pdfKeyType= PdfDictionary.VALUE_IS_MIXED_ARRAY;
}else if ((type==PdfDictionary.Form || type==PdfDictionary.MK) && PDFkeyInt== PdfDictionary.D){
if(id==PdfDictionary.AP || id==PdfDictionary.AA){
pdfKeyType= PdfDictionary.VALUE_IS_VARIOUS;
}else if(id==PdfDictionary.Win){
pdfKeyType= PdfDictionary.VALUE_IS_TEXTSTREAM;
}else{
PDFkeyInt= PdfDictionary.Dest;
pdfKeyType= PdfDictionary.VALUE_IS_MIXED_ARRAY;
}
}else if ((type==PdfDictionary.Form || type==PdfDictionary.MK) && (id==PdfDictionary.AP || id==PdfDictionary.AA) && PDFkeyInt== PdfDictionary.A){
pdfKeyType= PdfDictionary.VALUE_IS_VARIOUS;
}else if (PDFkeyInt== PdfDictionary.Order && type==PdfDictionary.OCProperties){
pdfKeyType= PdfDictionary. VALUE_IS_OBJECT_ARRAY;
}else if (PDFkeyInt== PdfDictionary.Name && type==PdfDictionary.OCProperties){
pdfKeyType= PdfDictionary.VALUE_IS_TEXTSTREAM;
}else if ((type==PdfDictionary.ColorSpace || type==PdfDictionary.Function) && PDFkeyInt== PdfDictionary.N){
pdfKeyType= PdfDictionary.VALUE_IS_FLOAT;
}else if(PDFkeyInt==PdfDictionary.Gamma && type==PdfDictionary.ColorSpace &&
pdfObject.getParameterConstant(PdfDictionary.ColorSpace)== ColorSpaces.CalGray){ //its a number not an array
pdfKeyType= PdfDictionary.VALUE_IS_FLOAT;
}else if(id==PdfDictionary.Win && pdfObject.getObjectType()==PdfDictionary.Form &&
(PDFkeyInt==PdfDictionary.P || PDFkeyInt==PdfDictionary.O)){
pdfKeyType= PdfDictionary.VALUE_IS_TEXTSTREAM;
}else if (isInlineImage && PDFkeyInt==PdfDictionary.ColorSpace){
pdfKeyType= PdfDictionary.VALUE_IS_DICTIONARY;
}else {
pdfKeyType = PdfDictionary.getKeyType(PDFkeyInt, type);
}
//handle array of Function in Shading by using keyArray
if(id==PdfDictionary.Shading && PDFkeyInt==PdfDictionary.Function){
//get next non number/char value
int ptr=i;
while((raw[ptr]>=48 && raw[ptr]<58) || raw[ptr]==32){
ptr++;
}
if(raw[ptr]=='['){
pdfKeyType=PdfDictionary.VALUE_IS_KEY_ARRAY;
}
}
//allow for other values in D,N,R definitions
if(pdfKeyType==-1 && id== PdfDictionary.ClassMap){
pdfKeyType = Dictionary.getPairedValues(pdfObject, i, raw, pdfKeyType, length, keyLength, keyStart);
}else
//allow for other values in D,N,R definitions as key pairs
if(((((id==PdfDictionary.N || id==PdfDictionary.D || id==PdfDictionary.R))) &&
pdfObject.getParentID()==PdfDictionary.AP &&
pdfObject.getObjectType()==PdfDictionary.Form
&& raw[i]!='[' )){
//get next non number/char value
int ptr=i;
while((raw[ptr]>=48 && raw[ptr]<58) || raw[ptr]==32){
ptr++;
}
//decide if pair
if(raw[keyStart]=='L' && raw[keyStart+1]=='e' && raw[keyStart+2]=='n' && raw[keyStart+3]=='g' && raw[keyStart+4]=='t' && raw[keyStart+5]=='h'){
}else if(raw[keyStart]=='O' && raw[keyStart+1]=='n'){
}else if(raw[keyStart]=='O' && raw[keyStart+1]=='f' && raw[keyStart+2]=='f'){
}else
if(raw[ptr]=='R'){
pdfKeyType = Dictionary.getPairedValues(pdfObject, i, raw, pdfKeyType, length, keyLength, keyStart);
if(debugFastCode) {
System.out.println("new Returns " + pdfKeyType + " i=" + i);
}
}
}
/**/
//DecodeParms can be an array as well as a dictionary so check next char and alter if so
if(PDFkeyInt==PdfDictionary.DecodeParms) {
pdfKeyType = setTypeForDecodeParams(i, raw, length, pdfKeyType);
}
if(debugFastCode && pdfKeyType==-1 && pdfObject.getObjectType()!=PdfDictionary.Page){
System.out.println(id+" "+type);
System.out.println(padding +PDFkey+" NO type setting for "+PdfDictionary.getKey(keyStart,keyLength,raw)+" id="+i);
}
}
private int setValue(final PdfObject pdfObject,int i, final byte[] raw, final int length, final boolean map) {
//if we only need top level do not read whole tree
final boolean ignoreRecursion=pdfObject.ignoreRecursion();
if(debugFastCode) {
System.out.println(padding + pdfObject.getObjectRefAsString() + " =================Reading value for key=" + PDFkey + " (" + PDFkeyInt + ") type=" + PdfDictionary.showAsConstant(pdfKeyType) + " ignorRecursion=" + ignoreRecursion + ' ' + pdfObject);
}
//resolve now in this case as we need to ensure all parts present
if(pdfKeyType==PdfDictionary.VALUE_IS_UNREAD_DICTIONARY && pdfObject.isDataExternal()) {
pdfKeyType = PdfDictionary.VALUE_IS_DICTIONARY;
}
switch(pdfKeyType){
//read text stream (this is text) and also special case of [] in W in CID Fonts
case PdfDictionary.VALUE_IS_TEXTSTREAM:{
i = TextStream.setTextStreamValue(pdfObject, i, raw, ignoreRecursion,PDFkeyInt, objectReader);
break;
}case PdfDictionary.VALUE_IS_NAMETREE:{
i = Name.setNameTreeValue(pdfObject, i, raw, length, ignoreRecursion,PDFkeyInt,objectReader);
break;
//readDictionary keys << /A 12 0 R /B 13 0 R >>
}case PdfDictionary.VALUE_IS_DICTIONARY_PAIRS:{
i = Dictionary.setDictionaryValue(pdfObject, i, raw, length, ignoreRecursion,objectReader,PDFkeyInt);
break;
//Strings
}case PdfDictionary.VALUE_IS_STRING_ARRAY:{
final Array objDecoder=new Array(objectReader,i, endPt, PdfDictionary.VALUE_IS_STRING_ARRAY);
i=objDecoder.readArray(ignoreRecursion, raw, pdfObject, PDFkeyInt);
break;
//read Object Refs in [] (may be indirect ref)
}case PdfDictionary.VALUE_IS_BOOLEAN_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_BOOLEAN_ARRAY);
i=objDecoder.readArray(false, raw, pdfObject, PDFkeyInt);
break;
//read Object Refs in [] (may be indirect ref)
}case PdfDictionary.VALUE_IS_KEY_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_KEY_ARRAY);
i=objDecoder.readArray(ignoreRecursion, raw, pdfObject, PDFkeyInt);
break;
//read numbers in [] (may be indirect ref)
}case PdfDictionary.VALUE_IS_MIXED_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_MIXED_ARRAY);
i=objDecoder.readArray(ignoreRecursion, raw, pdfObject, PDFkeyInt);
break;
//read numbers in [] (may be indirect ref) same as Mixed but allow for recursion and store as objects
}case PdfDictionary.VALUE_IS_OBJECT_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_OBJECT_ARRAY);
i=objDecoder.readArray(false, raw, pdfObject, PDFkeyInt);
break;
//read numbers in [] (may be indirect ref)
}case PdfDictionary.VALUE_IS_DOUBLE_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_DOUBLE_ARRAY);
i=objDecoder.readArray(false, raw, pdfObject,PDFkeyInt);
break;
//read numbers in [] (may be indirect ref)
}case PdfDictionary.VALUE_IS_INT_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_INT_ARRAY);
i=objDecoder.readArray(false, raw, pdfObject, PDFkeyInt);
break;
//read numbers in [] (may be indirect ref)
}case PdfDictionary.VALUE_IS_FLOAT_ARRAY:{
final Array objDecoder=new Array(objectReader, i, endPt, PdfDictionary.VALUE_IS_FLOAT_ARRAY);
i=objDecoder.readArray(false, raw, pdfObject, PDFkeyInt);
break;
//read String (may be indirect ref)
}case PdfDictionary.VALUE_IS_NAME:{
i = Name.setNameStringValue(pdfObject, i, raw, map,PDFkey, PDFkeyInt, objectReader);
break;
//read true or false
}case PdfDictionary.VALUE_IS_BOOLEAN:{
i = BooleanValue.set(pdfObject, i, raw, PDFkeyInt);
break;
//read known set of values
}case PdfDictionary.VALUE_IS_STRING_CONSTANT:{
i = StringValue.setStringConstantValue(pdfObject, i, raw,PDFkeyInt);
break;
//read known set of values
}case PdfDictionary.VALUE_IS_STRING_KEY:{
i = StringValue.setStringKeyValue(pdfObject, i, raw,PDFkeyInt);
break;
//read number (may be indirect ref)
}case PdfDictionary.VALUE_IS_INT:{
//roll on
i++;
//move cursor to start of text
while(raw[i]==10 || raw[i]==13 || raw[i]==32 || raw[i]==47) {
i++;
}
i = NumberValue.setNumberValue(pdfObject, i, raw, PDFkeyInt,objectReader);
break;
//read float number (may be indirect ref)
}case PdfDictionary.VALUE_IS_FLOAT:{
i = FloatValue.setFloatValue(pdfObject, i, raw, length,PDFkeyInt,objectReader);
break;
//read known Dictionary object which may be direct or indirect
}case PdfDictionary.VALUE_IS_UNREAD_DICTIONARY:{
i = setUnreadDictionaryValue(pdfObject, i, raw);
break;
}case PdfDictionary.VALUE_IS_VARIOUS:{
if(raw.length-5>0 && raw[i+1]=='n' && raw[i+2]=='u' && raw[i+3]=='l' && raw[i+4]=='l'){ //ignore null value and skip (ie /N null)
i += 5;
}else{
i = setVariousValue(pdfObject, i, raw, length, PDFkeyInt, map, ignoreRecursion,objectReader);
}
break;
}case PdfDictionary.VALUE_IS_DICTIONARY:{
i = setDictionaryValue(pdfObject, i, raw, ignoreRecursion);
break;
}
}
return i;
}
static int stripComment(final int length, int i, final byte[] raw) {
while(i='0' && raw[ii]<='9')) {
pdfKeyType = PdfDictionary.VALUE_IS_OBJECT_ARRAY;
}
}
return pdfKeyType;
}
private int setDictionaryValue(final PdfObject pdfObject,int i, final byte[] raw, final boolean ignoreRecursion) {
/**
* workout actual end as not always returned right
*/
int end=i;
int nextC=i;
//ignore any gaps
while(raw[nextC]==10 || raw[nextC]==32 || raw[nextC]==9) {
nextC++;
}
//allow for null object
if(raw[nextC]=='n' && raw[nextC+1]=='u' && raw[nextC+2]=='l' && raw[nextC+3]=='l'){
i=nextC+4;
return i;
}else if(raw[nextC]=='[' && raw[nextC+1]==']'){ //allow for empty object []
i=nextC;
return i;
}
if(raw[i]!='<' && raw[i+1]!='<') {
end += 2;
}
boolean inDictionary=true;
final boolean isKey=raw[end-1]=='/';
while(inDictionary){
if(raw[end]=='<'&& raw[end+1]=='<'){
int level2=1;
end++;
while(level2>0){
if(raw[end]=='<'&& raw[end+1]=='<'){
level2++;
end += 2;
}else if(raw[end-1]=='>'&& raw[end]=='>'){
level2--;
if(level2>0) {
end += 2;
}
}else if(raw[end]=='('){ //scan (strings) as can contain >>
end++;
while(raw[end]!=')' || ObjectUtils.isEscaped(raw, end)) {
end++;
}
}else {
end++;
}
}
inDictionary=false;
}else if(raw[end]=='R' ){
inDictionary=false;
}else if(isKey && (raw[end]==' ' || raw[end]==13 || raw[end]==10 || raw[end]==9)){
inDictionary=false;
}else if(raw[end]=='/'){
inDictionary=false;
end--;
}else if(raw[end]=='>' && raw[end+1]=='>'){
inDictionary=false;
end--;
}else {
end++;
}
}
//boolean save=debugFastCode;
Dictionary.readDictionary(pdfObject,i, raw, PDFkeyInt, ignoreRecursion, objectReader, isInlineImage);
//use correct value
return end;
}
private int setUnreadDictionaryValue(final PdfObject pdfObject, int i, final byte[] raw) {
if(raw[i]!='<') //roll on
{
i++;
}
while(raw[i]==10 || raw[i]==13 || raw[i]==32 || raw[i]==9) //move cursor to start of text
{
i++;
}
final int start=i;
final int keyStart;
int keyLength;
//create and store stub
final PdfObject valueObj= ObjectFactory.createObject(PDFkeyInt,pdfObject.getObjectRefAsString(), pdfObject.getObjectType(), pdfObject.getID());
valueObj.setID(PDFkeyInt);
if(raw[i]=='n' && raw[i+1]=='u' && raw[i+2]=='l' && raw[i+3]=='l'){ //allow for null
}else {
pdfObject.setDictionary(PDFkeyInt, valueObj);
}
int status=PdfObject.UNDECODED_DIRECT; //assume not object and reset below if wrong
//some objects can have a common value (ie /ToUnicode /Identity-H
if(raw[i]==47){ //not worth caching
//move cursor to start of text
while(raw[i]==10 || raw[i]==13 || raw[i]==32 || raw[i]==47 || raw[i]==60) {
i++;
}
keyStart=i;
keyLength=0;
//move cursor to end of text
while(raw[i]!=10 && raw[i]!=13 && raw[i]!=32 && raw[i]!=47 && raw[i]!=60 && raw[i]!=62){
i++;
keyLength++;
}
i--;// move back so loop works
//store value
final int constant=valueObj.setConstant(PDFkeyInt,keyStart,keyLength,raw);
if(constant== PdfDictionary.Unknown || isInlineImage){
final byte[] newStr=new byte[keyLength];
System.arraycopy(raw, keyStart, newStr, 0, keyLength);
final String s=new String(newStr);
valueObj.setGeneralStringValue(s);
}
status=PdfObject.DECODED;
}else //allow for empty object
if(raw[i]=='e' && raw[i+1]=='n' && raw[i+2]=='d' && raw[i+3]=='o' && raw[i+4]=='b' ){
}else{ //we need to ref from ref elsewhere which may be indirect [ref], hence loop
//roll onto first valid char
while((raw[i]==91 && PDFkeyInt!=PdfDictionary.ColorSpace) || raw[i]==32 || raw[i]==13 || raw[i]==10){
i++;
}
//roll on and ignore
if(raw[i]=='<' && raw[i+1]=='<'){
i += 2;
int reflevel=1;
while(reflevel>0){
if(raw[i]=='<' && raw[i+1]=='<'){
i += 2;
reflevel++;
}else if(raw[i]=='(' ){ //allow for << (>>) >>
i++;
while(raw[i]!=')' || ObjectUtils.isEscaped(raw, i)) {
i++;
}
}else if(raw[i]=='>' && i+1==raw.length){
reflevel=0;
}else if(raw[i]=='>' && raw[i+1]=='>'){
i += 2;
reflevel--;
}else {
i++;
}
}
}else if(raw[i]=='['){
i++;
int reflevel=1;
while(reflevel>0){
if(raw[i]=='(' ){ //allow for [[ in stream ie [/Indexed /DeviceRGB 255 (abc[[z
i++;
while(raw[i]!=')' || ObjectUtils.isEscaped(raw, i)) {
i++;
}
}else if(raw[i]=='[' ){
reflevel++;
}else if(raw[i]==']'){
reflevel--;
}
i++;
}
i--;
}else if(raw[i]=='n' && raw[i+1]=='u' && raw[i+2]=='l' && raw[i+3]=='l'){ //allow for null
i += 4;
}else{ //must be a ref
//assume not object and reset below if wrong
status=PdfObject.UNDECODED_REF;
while(raw[i]!='R' || raw[i-1]=='e') { //second condition to stop spurious match on DeviceRGB
i++;
if(i==raw.length) {
break;
}
}
i++;
if(i>=raw.length) {
i = raw.length - 1;
}
}
}
valueObj.setStatus(status);
if(status!=PdfObject.DECODED){
final int StrLength=i-start;
final byte[] unresolvedData=new byte[StrLength];
System.arraycopy(raw, start, unresolvedData, 0, StrLength);
//check for returns in data if ends with R and correct to space
if(unresolvedData[StrLength-1]==82){
for(int jj=0;jj') //move back so loop works
{
i--;
}
return i;
}
public static int handleValue(final PdfObject pdfObject, int i, final int PDFkeyInt, int j, final int ref, final int generation, final byte[] data, final PdfFileReader objectReader) {
final int keyStart;
int keyLength;
final int dataLen=data.length;
if (data[j] == 47) {
j++; //roll on past /
keyStart = j;
keyLength = 0;
//move cursor to end of text
while (j='0' && raw[jj]<='9'){
ptr=jj;
jj=len;
}
}
//check first non-number is R
int end=ptr;
while((raw[end]>='0' && raw[end]<='9') || raw[end]==' ' || raw[end]==10 || raw[end]==13 || raw[end]==9) {
end++;
}
//and store if it is a ref
if(raw[end]=='R') {
pdfObject.setRef(new String(raw, ptr, len - ptr));
}
}else if(raw[raw.length-1]=='R'){
objectRef=new String(raw);
pdfObject.setRef(objectRef);
}
Dictionary.readDictionaryFromRefOrDirect(-1,pdfObject,objectRef, 0, raw , -1,objectReader);
}
}
}
/**
* set end if not end of data stream
*/
public void setEndPt(final int dataPointer) {
this.endPt=dataPointer;
}
}