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.util.Arrays;
034: import java.util.Iterator;
035: import java.util.Map;
036: import de.intarsys.pdf.writer.COSWriter;
037: import de.intarsys.tools.collection.EmptyIterator;
038: import de.intarsys.tools.randomaccess.IRandomAccess;
039:
040: /**
041: * A "proxy object" used to intercept the visitor callback from the serializer.
042: *
043: */
044: abstract public class COSObjectProxy extends COSCompositeObject
045: implements Cloneable {
046: /** The position when the signal from the serializer was detected */
047: private long position = -1;
048:
049: private int length;
050:
051: private COSObject object;
052:
053: /**
054: * Create a {@link COSObjectProxy}
055: */
056: public COSObjectProxy() {
057: //
058: }
059:
060: public Object accept(ICOSObjectVisitor visitor)
061: throws COSVisitorException {
062: if (object != null) {
063: return object.accept(visitor);
064: }
065: if (visitor instanceof ICOSProxyVisitor) {
066: return ((ICOSProxyVisitor) visitor).visitFromProxy(this );
067: }
068: return null;
069: }
070:
071: public Iterator basicIterator() {
072: if (object == null) {
073: return EmptyIterator.UNIQUE;
074: }
075: return object.basicIterator();
076: }
077:
078: protected String basicToString() {
079: if (object == null) {
080: return "COSObjectProxy: empty"; //$NON-NLS-1$
081: }
082: return object.stringValue();
083: }
084:
085: protected Object clone() {
086: try {
087: return super .clone();
088: } catch (CloneNotSupportedException e) {
089: return null;
090: }
091: }
092:
093: protected COSObject copyBasic() {
094: if (object != null) {
095: return object.copyBasic();
096: }
097: COSObjectProxy proxy = (COSObjectProxy) clone();
098: proxy.reserveData(getLength());
099: return proxy;
100: }
101:
102: public COSObject copyDeep(Map copied) {
103: if (object != null) {
104: return object.copyDeep(copied);
105: }
106: return super .copyDeep(copied);
107: }
108:
109: public COSObject copyShallow() {
110: if (object != null) {
111: return object.copyShallow();
112: }
113: return super .copyShallow();
114: }
115:
116: /**
117: * Realize the represented object.
118: *
119: * @param randomAccessData
120: * @return the represented object
121: * @throws IOException
122: */
123: abstract protected COSObject createCOSObject(
124: IRandomAccess randomAccessData) throws IOException;
125:
126: public COSObject dereference() {
127: return (object == null) ? this : object;
128: }
129:
130: /**
131: * Attention: The user must handle encryption by himself. The COSWriter
132: * doesn't handle encryption in this state.
133: *
134: * @param writer
135: * @throws IOException
136: */
137: public void ended(COSWriter writer) throws IOException {
138: if (object != null) {
139: // already done
140: return;
141: }
142: IOException createObjException = null;
143: IRandomAccess data = writer.getRandomAccess();
144: data.mark();
145: try {
146: try {
147: object = createCOSObject(data);
148: } catch (IOException e) {
149: createObjException = e;
150: }
151: data.seek(getPosition());
152: if (object != null) {
153: writer.writeObject(object);
154: } else {
155: writer.writeObject(COSNull.create());
156: }
157: long endPosition = getPosition() + getLength();
158: if (data.getOffset() < endPosition) {
159: // remove EOL (0x0D, 0x0A) marker
160: data.seek(data.getOffset() - 2);
161: long dif = endPosition - data.getOffset();
162: byte[] padding = new byte[(int) dif];
163: Arrays.fill(padding, (byte) ' ');
164: writer.write(padding);
165: } else if (data.getOffset() > endPosition) {
166: throw new IOException(
167: "Destroyed document, wrote more bytes than reserved!"); //$NON-NLS-1$
168: }
169: if (createObjException != null) {
170: throw createObjException;
171: }
172: } finally {
173: data.reset();
174: }
175: }
176:
177: /**
178: * The length within the data stream for the serialization of this.
179: *
180: * @return The length within the data stream for the serialization of this.
181: */
182: public int getLength() {
183: return length;
184: }
185:
186: /**
187: * The object represented by this.
188: *
189: * @return The object represented by this.
190: */
191: public COSObject getObject() {
192: return object;
193: }
194:
195: /**
196: * The position within the data stream for the serialization of this.
197: *
198: * @return The position within the data stream for the serialization of
199: * this.
200: */
201: public long getPosition() {
202: return position;
203: }
204:
205: public Iterator iterator() {
206: if (object == null) {
207: return EmptyIterator.UNIQUE;
208: }
209: return object.iterator();
210: }
211:
212: /**
213: * Reserve <code>length</code> bytes for the serialization of this.
214: *
215: * @param pLength
216: * Number of bytes to be reserved.
217: */
218: public void reserveData(int pLength) {
219: this .length = pLength;
220: }
221:
222: public Object saveState() {
223: return null;
224: }
225:
226: protected void setObject(COSObject object) {
227: this .object = object;
228: }
229:
230: /**
231: * Assign the position within the data stream.
232: *
233: * @param position
234: * The position within the data stream.
235: */
236: public void setPosition(long position) {
237: this.position = position;
238: }
239: }
|