001: /*
002: Copyright © 2006 Stefano Chizzolini. http://clown.stefanochizzolini.it
003:
004: Contributors:
005: * Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it):
006: contributed code is Copyright © 2006 by Stefano Chizzolini.
007:
008: This file should be part of the source code distribution of "PDF Clown library"
009: (the Program): see the accompanying README files for more info.
010:
011: This Program is free software; you can redistribute it and/or modify it under
012: the terms of the GNU General Public License as published by the Free Software
013: Foundation; either version 2 of the License, or (at your option) any later version.
014:
015: This Program is distributed in the hope that it will be useful, but WITHOUT ANY
016: WARRANTY, either expressed or implied; without even the implied warranty of
017: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
018:
019: You should have received a copy of the GNU General Public License along with this
020: Program (see README files); if not, go to the GNU website (http://www.gnu.org/).
021:
022: Redistribution and use, with or without modification, are permitted provided that such
023: redistributions retain the above copyright notice, license and disclaimer, along with
024: this list of conditions.
025: */
026:
027: package it.stefanochizzolini.clown.objects;
028:
029: import it.stefanochizzolini.clown.bytes.Buffer;
030: import it.stefanochizzolini.clown.bytes.IBuffer;
031: import it.stefanochizzolini.clown.bytes.IOutputStream;
032: import it.stefanochizzolini.clown.bytes.filters.Filter;
033: import it.stefanochizzolini.clown.files.File;
034: import java.util.Iterator;
035:
036: /**
037: PDF stream object [PDF:1.6:3.2.7].
038: */
039: public class PdfStream extends PdfDataObject {
040: // <class>
041: // <dynamic>
042: // <fields>
043: private IBuffer body;
044: private PdfDictionary header;
045:
046: // </fields>
047:
048: // <constructors>
049: public PdfStream() {
050: this (new PdfDictionary(), new Buffer());
051: }
052:
053: public PdfStream(PdfDictionary header) {
054: this (header, new Buffer());
055: }
056:
057: public PdfStream(IBuffer body) {
058: this (new PdfDictionary(), body);
059: }
060:
061: public PdfStream(PdfDictionary header, IBuffer body) {
062: this .header = header;
063: this .body = body;
064: }
065:
066: // </constructors>
067:
068: // <interface>
069: // <public>
070: @Override
071: public Object clone(File context) {
072: PdfStream clone = new PdfStream((PdfDictionary) header
073: .clone(context), body.clone());
074:
075: return clone;
076: }
077:
078: /**
079: Gets the decoded stream body.
080: */
081: public IBuffer getBody() {
082: /*
083: NOTE: Encoding filters are removed by default because they belong to a lower layer
084: (token layer), so that it's appropriate and consistent to transparently keep the object layer
085: unaware of such a facility.
086: */
087: return getBody(true);
088: }
089:
090: /**
091: Gets the stream body.
092: @param decode Defines whether the body has to be decoded.
093: */
094: public IBuffer getBody(boolean decode) {
095: if (decode) {
096: // Get 'Filter' entry!
097: /*
098: NOTE: Such an entry defines possible encodings applied to the stream.
099: */
100: PdfDirectObject filterObj = header.get(PdfName.Filter);
101: // Is the stream encoded?
102: if (filterObj != null) {
103: /*
104: NOTE: If the stream is encoded, we must decode it before continuing.
105: */
106: // TODO:IMPL 'DecodeParms' entry management!!!
107: PdfDataObject filterDataObj = File.resolve(filterObj);
108: if (filterDataObj instanceof PdfName) // PdfName.
109: {
110: body.decode(Filter.get((PdfName) filterDataObj));
111: } else // MUST be PdfArray.
112: {
113: for (Iterator<PdfDirectObject> iterator = ((PdfArray) filterDataObj)
114: .iterator(); iterator.hasNext(); filterObj = iterator
115: .next()) {
116: body.decode(Filter.get((PdfName) File
117: .resolve(filterObj)));
118: }
119: }
120:
121: // Update 'Filter' entry!
122: header.put(PdfName.Filter, null); // The stream is free from encodings.
123: }
124: }
125:
126: return body;
127: }
128:
129: public PdfDictionary getHeader() {
130: return header;
131: }
132:
133: // </public>
134:
135: // <internal>
136: @Override
137: int writeTo(IOutputStream stream) {
138: int size = 0;
139: boolean unencodedBody;
140: byte[] bodyData;
141: int bodyLength;
142:
143: // 1. Header.
144: // Encoding.
145: /*
146: NOTE: As the contract establishes that a stream instance should be kept
147: free from encodings in order to be editable, encoding is NOT applied to
148: the actual online stream, but to its serialized representation only.
149: That is, as encoding is just a serialization practise, it is excluded from
150: alive, instanced streams.
151: */
152: PdfDirectObject filterObj = header.get(PdfName.Filter);
153: // Is the body free from encodings?
154: if (filterObj == null) // Unencoded body.
155: {
156: /*
157: NOTE: As online representation is unencoded,
158: header entries related to the encoded stream body are temporary
159: (instrumental to the current serialization process).
160: */
161: unencodedBody = true;
162:
163: // Set the filter to apply!
164: filterObj = PdfName.FlateDecode; // zlib/deflate filter.
165: // Get encoded body data applying the filter to the stream!
166: bodyData = body.encode(Filter.get((PdfName) filterObj));
167: // Set encoded length!
168: bodyLength = bodyData.length;
169: // Update 'Filter' entry!
170: header.put(PdfName.Filter, filterObj);
171: } else // Encoded body.
172: {
173: unencodedBody = false;
174:
175: // Get encoded body data!
176: bodyData = body.toByteArray();
177: // Set encoded length!
178: bodyLength = (int) body.getLength();
179: }
180: // Set encoded length!
181: header.put(PdfName.Length, new PdfLong(bodyLength));
182:
183: size += header.writeTo(stream);
184:
185: // Is the body free from encodings?
186: if (unencodedBody) {
187: // Restore actual header entries!
188: ((PdfLong) header.get(PdfName.Length)).setValue(body
189: .getLength());
190: header.put(PdfName.Filter, null);
191: }
192:
193: // 2. Body.
194: size += stream.write("\rstream\r");
195: size += stream.write(bodyData);
196: size += stream.write("\rendstream");
197:
198: return size;
199: }
200: // </internal>
201: // </interface>
202: // </dynamic>
203: // </class>
204: }
|