001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.cos;
031:
032: import java.io.IOException;
033: import java.io.InputStream;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.List;
037: import java.util.Map;
038: import de.intarsys.pdf.parser.COSLoadException;
039: import de.intarsys.pdf.parser.PDFParser;
040: import de.intarsys.pdf.st.STDocument;
041: import de.intarsys.pdf.st.STXRefSection;
042: import de.intarsys.tools.locator.ILocator;
043: import de.intarsys.tools.locator.LocatorViewport;
044: import de.intarsys.tools.randomaccess.IRandomAccess;
045: import de.intarsys.tools.stream.StreamTools;
046:
047: /**
048: * Some tools to ease life with COS.
049: */
050: public class COSTools {
051: private COSTools() {
052: super ();
053: }
054:
055: /**
056: * Tries to force a dictionary out of the COSObject.
057: *
058: * @param object
059: * The object to be cast to a {@link COSDictionary}
060: * @return {@link COSDictionary} or null
061: */
062: public static COSDictionary toDictionary(COSObject object) {
063: COSDictionary dict = null;
064: if (object instanceof COSDictionary) {
065: dict = (COSDictionary) object;
066: } else if (object instanceof COSStream) {
067: dict = ((COSStream) object).getDict();
068: }
069: return dict;
070: }
071:
072: /**
073: * Try the best in marshalling java objects directly to {@link COSObject}.
074: * Collections will be marshalled recursively.
075: *
076: * @param javaObject
077: * the java object to be marshalled
078: *
079: * @return The resulting {@link COSObject}
080: */
081: static public COSObject createObject(Object javaObject) {
082: COSObject result = null;
083: if (javaObject instanceof String) {
084: result = COSString.create((String) javaObject);
085: } else if (javaObject instanceof Integer) {
086: result = COSInteger.create(((Integer) javaObject)
087: .intValue());
088: } else if (javaObject instanceof Float) {
089: result = COSFixed.create(((Float) javaObject).floatValue());
090: } else if (javaObject instanceof Double) {
091: result = COSFixed
092: .create(((Double) javaObject).floatValue());
093: } else if (javaObject instanceof Boolean) {
094: result = COSBoolean.create(((Boolean) javaObject)
095: .booleanValue());
096: } else if (javaObject == null) {
097: result = COSNull.create();
098: } else if (javaObject instanceof Map) {
099: result = COSDictionary.create(((Map) javaObject).size());
100: for (Iterator it = ((Map) javaObject).entrySet().iterator(); it
101: .hasNext();) {
102: Map.Entry entry = (Map.Entry) it.next();
103: String key = String.valueOf(entry.getKey());
104: Object value = entry.getValue();
105: ((COSDictionary) result).put(COSName.create(key),
106: createObject(value));
107: }
108: } else if (javaObject instanceof List) {
109: result = COSArray.create(((List) javaObject).size());
110: for (Iterator it = ((List) javaObject).iterator(); it
111: .hasNext();) {
112: Object value = it.next();
113: ((COSArray) result).add(createObject(value));
114: }
115: } else if (javaObject instanceof byte[]) {
116: result = COSName.create((byte[]) javaObject);
117: } else if (javaObject instanceof char[]) {
118: result = COSString.create(new String((char[]) javaObject));
119: } else if (javaObject instanceof float[]) {
120: float[] floats = (float[]) javaObject;
121: result = COSArray.create(floats.length);
122: for (int i = 0; i < floats.length; i++) {
123: ((COSArray) result).add(COSFixed.create(floats[i]));
124: }
125: } else if (javaObject instanceof double[]) {
126: double[] doubles = (double[]) javaObject;
127: result = COSArray.create(doubles.length);
128: for (int i = 0; i < doubles.length; i++) {
129: ((COSArray) result).add(COSFixed.create(doubles[i]));
130: }
131: } else if (javaObject instanceof int[]) {
132: int[] ints = (int[]) javaObject;
133: result = COSArray.create(ints.length);
134: for (int i = 0; i < ints.length; i++) {
135: ((COSArray) result).add(COSInteger.create(ints[i]));
136: }
137: } else if (javaObject instanceof Byte) {
138: result = COSInteger.create(((Byte) javaObject).intValue());
139: } else if (javaObject instanceof Short) {
140: result = COSInteger.create(((Short) javaObject).intValue());
141: } else if (javaObject instanceof Long) {
142: result = COSInteger.create(((Long) javaObject).intValue());
143: } else if (javaObject instanceof InputStream) {
144: result = COSStream.create(null);
145: byte[] bytes;
146: try {
147: bytes = StreamTools
148: .toByteArray((InputStream) javaObject);
149: } catch (IOException e) {
150: bytes = new byte[] {};
151: }
152: ((COSStream) result).setDecodedBytes(bytes);
153: } else if (javaObject instanceof COSObject) {
154: result = (COSObject) javaObject;
155: } else {
156: throw new IllegalArgumentException(String
157: .valueOf(javaObject)
158: + " can not be marshalled to a cos object"); //$NON-NLS-1$
159: }
160: return result;
161: }
162:
163: /**
164: * A collection of {@link ILocator} instances, representing the versions
165: * created when writing incrementally.
166: *
167: * @param doc
168: * The original document.
169: * @return A collection of {@link ILocator} instances, representing the
170: * versions created when writing incrementally.
171: * @throws IOException
172: * @throws COSLoadException
173: */
174: static public List getVersions(COSDocument doc) throws IOException,
175: COSLoadException {
176: List result = new ArrayList();
177: STDocument stDoc = doc.stGetDoc();
178: STXRefSection xRef = stDoc.getXRefSection();
179: if (stDoc.getRandomAccess() == null) {
180: return result;
181: }
182: long successorOffset = stDoc.getRandomAccess().getLength();
183: while (xRef != null) {
184: COSDictionary cosDict = xRef.cosGetDict();
185: if (!cosDict.get(COSTrailer.DK_Root).isNull()) {
186: // the dummy trailer in a linearized pdf does not need /Root
187: long end = searchNextEOF(stDoc.getRandomAccess(), xRef
188: .getOffset(), successorOffset);
189: if (end != -1) {
190: LocatorViewport locator = new LocatorViewport(xRef
191: .getDoc().getLocator());
192: locator
193: .setName(xRef.getDoc().getLocator()
194: .getLocalName()
195: + "_v" + xRef.getIncrementalCount() + ".pdf"); //$NON-NLS-1$ //$NON-NLS-2$
196: locator.setStart(0);
197: locator.setEnd(end);
198: locator.setReadOnly();
199: result.add(locator);
200: }
201: }
202: successorOffset = xRef.getOffset();
203: xRef = xRef.getPrevious();
204: }
205: return result;
206: }
207:
208: static protected long searchNextEOF(IRandomAccess input,
209: long start, long end) throws IOException, COSLoadException {
210: input.seek(start);
211: int comparisonIndex = 0;
212: for (int i = input.read(); (i != -1)
213: && (input.getOffset() < end); i = input.read()) {
214: if (i == PDFParser.TOKEN_EOF[comparisonIndex]) {
215: comparisonIndex++;
216: if (comparisonIndex == PDFParser.TOKEN_EOF.length) {
217: readUptoNewLine(input);
218: return input.getOffset();
219: }
220: } else {
221: comparisonIndex = 0;
222: }
223: }
224: return -1;
225: }
226:
227: static protected boolean readUptoNewLine(IRandomAccess input)
228: throws IOException {
229: int i;
230: while (true) {
231: i = input.read();
232: if (i == -1) {
233: return false;
234: }
235: if (PDFParser.isEOL(i)) {
236: if (i == PDFParser.CHAR_CR) {
237: i = input.read();
238: if (i != PDFParser.CHAR_LF) {
239: input.seekBy(-1);
240: }
241: }
242: return true;
243: }
244: }
245: }
246: }
|