/* * Copyright 2006-2017 ICEsoft Technologies Canada Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.icepdf.core.pobjects; import org.icepdf.core.io.SeekableByteArrayInputStream; import org.icepdf.core.io.SeekableInput; import org.icepdf.core.io.SeekableInputConstrainedWrapper; import org.icepdf.core.util.Library; import org.icepdf.core.util.Parser; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * @author Mark Collette * @since 2.0 */ public class ObjectStream extends Stream { private static final Logger logger = Logger.getLogger(Form.class.toString()); public static final Name N_KEY = new Name("N"); public static final Name FIRST_KEY = new Name("First"); private boolean init; private SeekableInput decodedStream; private int[] objectNumbers; private long[] objectOffset; /** * Create a new instance of a Stream. * * @param l library containing a hash of all document objects * @param h HashMap of parameters specific to the Stream object. * @param streamInputWrapper Accessor to stream byte data */ public ObjectStream(Library l, HashMap h, SeekableInputConstrainedWrapper streamInputWrapper) { super(l, h, streamInputWrapper); } public synchronized void init() { if (init) return; init = true; int numObjects = library.getInt(entries, N_KEY); long firstObjectsOffset = library.getLong(entries, FIRST_KEY); // get the stream data decodedStream = new SeekableByteArrayInputStream(getDecodedStreamBytes(0)); // decodedStream.beginThreadAccess(); objectNumbers = new int[numObjects]; objectOffset = new long[numObjects]; try { Parser parser = new Parser(decodedStream); for (int i = 0; i < numObjects; i++) { objectNumbers[i] = parser.getIntSurroundedByWhitespace(); objectOffset[i] = parser.getLongSurroundedByWhitespace() + firstObjectsOffset; } } catch (Exception e) { logger.log(Level.SEVERE, "Error loading object stream instance: ", e); } // finally { // decodedStream.endThreadAccess(); // } } public Object loadObject(Library library, int objectIndex) { //System.out.println("ObjectStream.loadObject() objectIndex: " + objectIndex); init(); if (objectNumbers == null || objectOffset == null || objectNumbers.length != objectOffset.length || objectIndex < 0 || objectIndex >= objectNumbers.length) { //System.out.println("ObjectStream.loadObject() init failed"); return null; } try { int objectNumber = objectNumbers[objectIndex]; long position = objectOffset[objectIndex]; //System.out.println("ObjectStream.loadObject() objectNumber: " + objectNumber + ", position: " + position); decodedStream.beginThreadAccess(); decodedStream.seekAbsolute(position); Parser parser = new Parser(decodedStream, Parser.PARSE_MODE_OBJECT_STREAM); // Parser.getObject() either does 1 of 3 things: // 1. Gets a core object (Dictionary or Stream), adds it to Library // by object Reference, returns PObject // 2. Gets a non-core-object, leaves it on stack, returns null // 3. Gets a non-core-object, returns it Object ob = parser.getObject(library); if (ob == null) { Reference ref = new Reference(objectNumber, 0); PObject pObject = parser.addPObject(library, ref); ob = pObject.getObject(); } else if (!(ob instanceof PObject)) { Reference ref = new Reference(objectNumber, 0); library.addObject(ob, ref); } // assign object reference, needed for encrypting and state saving if (ob != null && ob instanceof Dictionary) { ((Dictionary) ob).setPObjectReference( new Reference(objectNumber, 0)); } //System.out.println("ObjectStream.loadObject() ob: " + ob + ", ob.class: " + ob.getClass().getName()); return ob; } catch (Exception e) { logger.log(Level.FINE, "Error loading PDF object.", e); return null; } finally { decodedStream.endThreadAccess(); } } }