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.IOException;
033: import java.util.Iterator;
034: import de.intarsys.pdf.cos.COSArray;
035: import de.intarsys.pdf.cos.COSInteger;
036: import de.intarsys.pdf.cos.COSObjectKey;
037: import de.intarsys.pdf.writer.COSWriter;
038: import de.intarsys.tools.randomaccess.RandomAccessByteArray;
039:
040: /**
041: * A XRef serializer to a XRef stream.
042: */
043: public class XRefStreamWriter extends AbstractXRefWriter {
044: /**
045: *
046: */
047: class SearchVisitor implements IXRefEntryVisitor {
048: private long highestOffset = 0;
049:
050: private int highestGeneration = 0;
051:
052: public void visitFromCompressed(STXRefEntryCompressed entry) {
053: checkOffset(entry.getStreamObjectNumber());
054: checkGeneration(entry.getIndex());
055: }
056:
057: public void visitFromFree(STXRefEntryFree entry) {
058: checkOffset(entry.getNextFreeObjectNumber());
059: checkGeneration(entry.getGenerationNumber());
060: }
061:
062: public void visitFromOccupied(STXRefEntryOccupied entry) {
063: checkOffset(entry.getOffset());
064: checkGeneration(entry.getGenerationNumber());
065: }
066:
067: private void checkOffset(long offset) {
068: if (offset > highestOffset) {
069: highestOffset = offset;
070: }
071: }
072:
073: private void checkGeneration(int generation) {
074: if (generation > highestGeneration) {
075: highestGeneration = generation;
076: }
077: }
078:
079: public long getHighestOffset() {
080: return highestOffset;
081: }
082:
083: public int getHighestGeneration() {
084: return highestGeneration;
085: }
086: }
087:
088: public static byte[] TYPE_FREE = { 0 };
089:
090: public static byte[] TYPE_OCCUPIED = { 1 };
091:
092: public static byte[] TYPE_COMPRESSED = { 2 };
093:
094: private int[] wSize;
095:
096: public XRefStreamWriter(COSWriter cosWriter) {
097: super (cosWriter);
098: }
099:
100: protected void visitFromSubsection(STXRefSubsection section) {
101: COSArray index = ((STStreamXRefSection) section
102: .getXRefSection()).getIndex();
103: index.add(COSInteger.create(section.getStart()));
104: index.add(COSInteger.create(section.getSize()));
105: }
106:
107: private void initWSize(STXRefSection xRefSection) {
108: // search highest 2nd column
109: SearchVisitor search = new SearchVisitor();
110:
111: for (Iterator i = xRefSection.entryIterator(); i.hasNext();) {
112: STXRefEntry entry = ((STXRefEntry) i.next());
113: try {
114: entry.accept(search);
115: } catch (XRefEntryVisitorException e) {
116: // won't happen
117: }
118: }
119: wSize = new int[3];
120: wSize[0] = 1;
121: wSize[1] = byteSizeOf((int) search.getHighestOffset());
122: wSize[2] = byteSizeOf(search.getHighestGeneration());
123:
124: COSArray wArray = COSArray.create(3);
125: for (int i = 0; i < 3; i++) {
126: wArray.add(COSInteger.create(wSize[i]));
127: }
128: ((STStreamXRefSection) xRefSection).setW(wArray);
129: }
130:
131: private int byteSizeOf(int number) {
132: int mask = 0xff000000;
133: for (int size = 4; size > 0; size--) {
134: if ((number & mask) != 0) {
135: return size;
136: }
137: mask = mask >> 8;
138: }
139: return 0;
140: }
141:
142: protected void initialize(STXRefSection xRefSection)
143: throws IOException {
144: super .initialize(xRefSection);
145: STStreamXRefSection xrefStream = (STStreamXRefSection) xRefSection;
146: setRandomAccess(new RandomAccessByteArray(null));
147: initWSize(xrefStream);
148: xrefStream.setIndex(COSArray.create());
149: COSObjectKey key = xrefStream.cosGetStream()
150: .getIndirectObject().getKey();
151: if (key == null) {
152: int size = xrefStream.getSize();
153: key = new COSObjectKey(size, 0);
154: xrefStream.cosGetStream().getIndirectObject().setKey(key);
155: xrefStream.setSize(size + 1);
156: }
157: xRefSection.addEntry(new STXRefEntryOccupied(key, xRefSection
158: .getOffset()));
159: }
160:
161: protected void finish(STXRefSection xRefSection) throws IOException {
162: byte[] innerBytes = ((RandomAccessByteArray) getRandomAccess())
163: .toByteArray();
164: ((STStreamXRefSection) xRefSection).cosGetStream()
165: .setDecodedBytes(innerBytes);
166: getCosWriter().writeIndirectObject(
167: ((STStreamXRefSection) xRefSection).cosGetStream()
168: .getIndirectObject());
169: super .finish(xRefSection);
170: }
171:
172: protected void write(int col1, int col2, byte[] type)
173: throws IOException {
174: getRandomAccess().write(type);
175: write(col1, wSize[1]);
176: write(col2, wSize[2]);
177: }
178:
179: private void write(int data, int numBytes) throws IOException {
180: switch (numBytes) {
181: case 4:
182: getRandomAccess().write((data & 0xFF000000) >> 24);
183: case 3:
184: getRandomAccess().write((data & 0x00FF0000) >> 16);
185: case 2:
186: getRandomAccess().write((data & 0x0000FF00) >> 8);
187: case 1:
188: getRandomAccess().write(data & 0x000000FF);
189: break;
190: default:
191:
192: // should not happen
193: }
194: }
195:
196: protected byte[] getTypeCompressed() {
197: return TYPE_COMPRESSED;
198: }
199:
200: protected byte[] getTypeFree() {
201: return TYPE_FREE;
202: }
203:
204: protected byte[] getTypeOccupied() {
205: return TYPE_OCCUPIED;
206: }
207: }
|