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.st;
031:
032: import java.io.ByteArrayInputStream;
033: import java.io.IOException;
034: import java.util.Iterator;
035: import de.intarsys.pdf.cos.COSArray;
036: import de.intarsys.pdf.cos.COSIndirectObject;
037: import de.intarsys.pdf.cos.COSInteger;
038: import de.intarsys.pdf.cos.COSNumber;
039: import de.intarsys.pdf.cos.COSObject;
040: import de.intarsys.pdf.cos.COSObjectKey;
041: import de.intarsys.pdf.cos.COSStream;
042: import de.intarsys.pdf.parser.COSDocumentParser;
043: import de.intarsys.pdf.parser.COSLoadException;
044: import de.intarsys.tools.randomaccess.IRandomAccess;
045:
046: /**
047: * A parser for XRef streams.
048: */
049: public class XRefStreamParser extends AbstractXRefParser {
050: private int[] wSizeDefault = { 1, 2, 1 };
051:
052: private int[] wSize;
053:
054: private ByteArrayInputStream in;
055:
056: public XRefStreamParser(STDocument doc, COSDocumentParser parser) {
057: super (doc, parser);
058: }
059:
060: private void initWBytes(STStreamXRefSection xRef) {
061: COSArray w = xRef.getW();
062: if (w == null) {
063: wSize = wSizeDefault;
064: return;
065: }
066: wSize = new int[3];
067: for (int i = 0; i < w.size(); i++) {
068: wSize[i] = ((COSInteger) w.get(i)).intValue();
069: }
070: for (int i = w.size(); i < 3; i++) {
071: wSize[i] = 0;
072: }
073: }
074:
075: protected STXRefSection parseXRef(IRandomAccess randomAcces)
076: throws IOException, COSLoadException {
077: long offset = randomAcces.getOffset();
078: COSStream stream = (COSStream) getDoc().getParser()
079: .parseIndirectObject(randomAcces, null);
080: ((COSIndirectObject) stream.containable()).setDirty(false);
081: STStreamXRefSection xRefSection = new STStreamXRefSection(
082: getDoc(), offset, stream);
083: parseStreamContent(xRefSection);
084: return xRefSection;
085: }
086:
087: private void parseStreamContent(STStreamXRefSection section)
088: throws IOException {
089: initWBytes(section);
090: in = new ByteArrayInputStream(section.cosGetStream()
091: .getDecodedBytes());
092: COSArray index = section.getIndex();
093: for (Iterator i = index.iterator(); i.hasNext();) {
094: COSNumber cosStart = ((COSObject) i.next()).asNumber();
095: if (!i.hasNext()) {
096: continue;
097: }
098: COSNumber cosCount = ((COSObject) i.next()).asNumber();
099: if (cosStart == null || cosCount == null) {
100: continue;
101: }
102: int start = cosStart.intValue();
103: int count = cosCount.intValue();
104: for (int io = 0; io < count; io++) {
105: int type = readType(in);
106: switch (type) {
107: case 0:
108: section.addEntry(parseType0(in, start + io));
109: break;
110: case 1:
111: section.addEntry(parseType1(in, start + io));
112: break;
113: case 2:
114: section.addEntry(parseType2(in, start + io));
115: break;
116: default:
117: parseTypeUnknown(in);
118: }
119: }
120: }
121: }
122:
123: private void parseTypeUnknown(ByteArrayInputStream pIn) {
124: read(pIn, wSize[1], -1);
125: read(pIn, wSize[1], -1);
126: }
127:
128: private STXRefEntry parseType2(ByteArrayInputStream pIn,
129: int objectNumber) {
130: int keyStmObject = read(pIn, wSize[1], -1);
131: int indexOfObject = read(pIn, wSize[2], 0);
132: COSObjectKey objectStreamKey = new COSObjectKey(keyStmObject, 0);
133: return new STXRefEntryCompressed(new COSObjectKey(objectNumber,
134: 0), objectStreamKey, indexOfObject);
135: }
136:
137: private STXRefEntry parseType1(ByteArrayInputStream pIn,
138: int objectNumber) {
139: int offset = read(pIn, wSize[1], -1);
140: int genNum = read(pIn, wSize[2], 0);
141: return new STXRefEntryOccupied(new COSObjectKey(objectNumber,
142: genNum), offset);
143: }
144:
145: private STXRefEntry parseType0(ByteArrayInputStream pIn,
146: int objectNumber) {
147: int nextFree = read(pIn, wSize[1], -1);
148: int nextGenNum = read(pIn, wSize[2], -1);
149: return new STXRefEntryFree(new COSObjectKey(objectNumber,
150: nextGenNum), nextFree);
151: }
152:
153: private int readType(ByteArrayInputStream pIn) {
154: return read(pIn, wSize[0], 1);
155: }
156:
157: private int read(ByteArrayInputStream pIn, int numBytes,
158: int defaultValue) {
159: if (numBytes == 0) {
160: return defaultValue;
161: }
162: int result = 0;
163: for (int i = 0; i < numBytes; i++) {
164: result <<= 8;
165: result += pIn.read();
166: }
167: return result;
168: }
169:
170: protected void loadPrevious(IRandomAccess randomAccess,
171: STXRefSection xRefSection) throws IOException,
172: COSLoadException {
173: int offset = xRefSection.getPreviousOffset();
174: if (offset != -1) {
175: AbstractXRefParser parser = new XRefStreamParser(getDoc(),
176: getParser());
177: randomAccess.seek(offset);
178: STXRefSection xrefStream = parser.parse(randomAccess);
179: xRefSection.setPrevious(xrefStream);
180: }
181: }
182:
183: /*
184: * (non-Javadoc)
185: *
186: * @see de.intarsys.pdf.st.AbstractXRefParser#parse(de.intarsys.tools.randomaccess.IRandomAccess)
187: */
188: public STXRefSection parse(IRandomAccess randomAcces)
189: throws IOException, COSLoadException {
190: STXRefSection xRefSection = parseXRef(randomAcces);
191: loadPrevious(randomAcces, xRefSection);
192: return xRefSection;
193: }
194: }
|