1 | /* | |
2 | * $Id: PdfStream.java 4065 2009-09-16 23:09:11Z psoares33 $ | |
3 | * | |
4 | * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie | |
5 | * | |
6 | * The contents of this file are subject to the Mozilla Public License Version 1.1 | |
7 | * (the "License"); you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
9 | * | |
10 | * Software distributed under the License is distributed on an "AS IS" basis, | |
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 | * for the specific language governing rights and limitations under the License. | |
13 | * | |
14 | * The Original Code is 'iText, a free JAVA-PDF library'. | |
15 | * | |
16 | * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by | |
17 | * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. | |
18 | * All Rights Reserved. | |
19 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer | |
20 | * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. | |
21 | * | |
22 | * Contributor(s): all the names of the contributors are added in the source code | |
23 | * where applicable. | |
24 | * | |
25 | * Alternatively, the contents of this file may be used under the terms of the | |
26 | * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the | |
27 | * provisions of LGPL are applicable instead of those above. If you wish to | |
28 | * allow use of your version of this file only under the terms of the LGPL | |
29 | * License and not to allow others to use your version of this file under | |
30 | * the MPL, indicate your decision by deleting the provisions above and | |
31 | * replace them with the notice and other provisions required by the LGPL. | |
32 | * If you do not delete the provisions above, a recipient may use your version | |
33 | * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. | |
34 | * | |
35 | * This library is free software; you can redistribute it and/or modify it | |
36 | * under the terms of the MPL as stated above or under the terms of the GNU | |
37 | * Library General Public License as published by the Free Software Foundation; | |
38 | * either version 2 of the License, or any later version. | |
39 | * | |
40 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
41 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
42 | * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more | |
43 | * details. | |
44 | * | |
45 | * If you didn't download this code from the following link, you should check if | |
46 | * you aren't using an obsolete version: | |
47 | * http://www.lowagie.com/iText/ | |
48 | */ | |
49 | ||
50 | package com.lowagie.text.pdf; | |
51 | ||
52 | import java.io.ByteArrayOutputStream; | |
53 | import java.io.IOException; | |
54 | import java.io.InputStream; | |
55 | import java.io.OutputStream; | |
56 | import java.util.zip.Deflater; | |
57 | import java.util.zip.DeflaterOutputStream; | |
58 | import com.lowagie.text.error_messages.MessageLocalization; | |
59 | ||
60 | import com.lowagie.text.DocWriter; | |
61 | import com.lowagie.text.Document; | |
62 | import com.lowagie.text.ExceptionConverter; | |
63 | ||
64 | ||
65 | /** | |
66 | * <CODE>PdfStream</CODE> is the Pdf stream object. | |
67 | * <P> | |
68 | * A stream, like a string, is a sequence of characters. However, an application can | |
69 | * read a small portion of a stream at a time, while a string must be read in its entirety. | |
70 | * For this reason, objects with potentially large amounts of data, such as images and | |
71 | * page descriptions, are represented as streams.<BR> | |
72 | * A stream consists of a dictionary that describes a sequence of characters, followed by | |
73 | * the keyword <B>stream</B>, followed by zero or more lines of characters, followed by | |
74 | * the keyword <B>endstream</B>.<BR> | |
75 | * All streams must be <CODE>PdfIndirectObject</CODE>s. The stream dictionary must be a direct | |
76 | * object. The keyword <B>stream</B> that follows the stream dictionary should be followed by | |
77 | * a carriage return and linefeed or just a linefeed.<BR> | |
78 | * Remark: In this version only the FLATEDECODE-filter is supported.<BR> | |
79 | * This object is described in the 'Portable Document Format Reference Manual version 1.7' | |
80 | * section 3.2.7 (page 60-63).<BR> | |
81 | * | |
82 | * @see PdfObject | |
83 | * @see PdfDictionary | |
84 | */ | |
85 | ||
86 | public class PdfStream extends PdfDictionary { | |
87 | | |
88 | // membervariables | |
89 | ||
90 | /** | |
91 | * A possible compression level. | |
92 | * @since 2.1.3 | |
93 | */ | |
94 | public static final int DEFAULT_COMPRESSION = -1; | |
95 | /** | |
96 | * A possible compression level. | |
97 | * @since 2.1.3 | |
98 | */ | |
99 | public static final int NO_COMPRESSION = 0; | |
100 | /** | |
101 | * A possible compression level. | |
102 | * @since 2.1.3 | |
103 | */ | |
104 | public static final int BEST_SPEED = 1; | |
105 | /** | |
106 | * A possible compression level. | |
107 | * @since 2.1.3 | |
108 | */ | |
109 | public static final int BEST_COMPRESSION = 9; | |
110 | | |
111 | | |
112 | /** is the stream compressed? */ | |
113 | protected boolean compressed = false; | |
114 | /** | |
115 | * The level of compression. | |
116 | * @since 2.1.3 | |
117 | */ | |
118 | protected int compressionLevel = NO_COMPRESSION; | |
119 | | |
120 | protected ByteArrayOutputStream streamBytes = null; | |
121 | protected InputStream inputStream; | |
122 | protected PdfIndirectReference ref; | |
123 | protected int inputStreamLength = -1; | |
124 | protected PdfWriter writer; | |
125 | protected int rawLength; | |
126 | ||
127 | static final byte[] STARTSTREAM = DocWriter.getISOBytes("stream\n"); | |
128 | static final byte[] ENDSTREAM = DocWriter.getISOBytes("\nendstream"); | |
129 | static final int SIZESTREAM = STARTSTREAM.length + ENDSTREAM.length; | |
130 | ||
131 | // constructors | |
132 | | |
133 | /** | |
134 | * Constructs a <CODE>PdfStream</CODE>-object. | |
135 | * | |
136 | * @param bytes content of the new <CODE>PdfObject</CODE> as an array of <CODE>byte</CODE>. | |
137 | */ | |
138 | | |
139 | public PdfStream(byte[] bytes) { | |
140 | super(); | |
141 | type = STREAM; | |
142 | this.bytes = bytes; | |
143 | rawLength = bytes.length; | |
144 |
1
1. |
put(PdfName.LENGTH, new PdfNumber(bytes.length)); |
145 | } | |
146 | | |
147 | /** | |
148 | * Creates an efficient stream. No temporary array is ever created. The <CODE>InputStream</CODE> | |
149 | * is totally consumed but is not closed. The general usage is: | |
150 | * <p> | |
151 | * <pre> | |
152 | * InputStream in = ...; | |
153 | * PdfStream stream = new PdfStream(in, writer); | |
154 | * stream.flateCompress(); | |
155 | * writer.addToBody(stream); | |
156 | * stream.writeLength(); | |
157 | * in.close(); | |
158 | * </pre> | |
159 | * @param inputStream the data to write to this stream | |
160 | * @param writer the <CODE>PdfWriter</CODE> for this stream | |
161 | */ | |
162 | public PdfStream(InputStream inputStream, PdfWriter writer) { | |
163 | super(); | |
164 | type = STREAM; | |
165 | this.inputStream = inputStream; | |
166 | this.writer = writer; | |
167 | ref = writer.getPdfIndirectReference(); | |
168 |
1
1. |
put(PdfName.LENGTH, ref); |
169 | } | |
170 | | |
171 | /** | |
172 | * Constructs a <CODE>PdfStream</CODE>-object. | |
173 | */ | |
174 | | |
175 | protected PdfStream() { | |
176 | super(); | |
177 | type = STREAM; | |
178 | } | |
179 | | |
180 | /** | |
181 | * Writes the stream length to the <CODE>PdfWriter</CODE>. | |
182 | * <p> | |
183 | * This method must be called and can only be called if the constructor {@link #PdfStream(InputStream,PdfWriter)} | |
184 | * is used to create the stream. | |
185 | * @throws IOException on error | |
186 | * @see #PdfStream(InputStream,PdfWriter) | |
187 | */ | |
188 | public void writeLength() throws IOException { | |
189 |
1
1. writeLength : negated conditional → NO_COVERAGE |
if (inputStream == null) |
190 | throw new UnsupportedOperationException(MessageLocalization.getComposedMessage("writelength.can.only.be.called.in.a.contructed.pdfstream.inputstream.pdfwriter")); | |
191 |
1
1. writeLength : negated conditional → NO_COVERAGE |
if (inputStreamLength == -1) |
192 | throw new IOException(MessageLocalization.getComposedMessage("writelength.can.only.be.called.after.output.of.the.stream.body")); | |
193 | writer.addToBody(new PdfNumber(inputStreamLength), ref, false); | |
194 | } | |
195 | | |
196 | /** | |
197 | * Gets the raw length of the stream. | |
198 | * @return the raw length of the stream | |
199 | */ | |
200 | public int getRawLength() { | |
201 | return rawLength; | |
202 | } | |
203 | | |
204 | /** | |
205 | * Compresses the stream. | |
206 | */ | |
207 | public void flateCompress() { | |
208 |
1
1. flateCompress : removed call to com/lowagie/text/pdf/PdfStream::flateCompress → NO_COVERAGE |
flateCompress(DEFAULT_COMPRESSION); |
209 | } | |
210 | | |
211 | /** | |
212 | * Compresses the stream. | |
213 | * @param compressionLevel the compression level (0 = best speed, 9 = best compression, -1 is default) | |
214 | * @since 2.1.3 | |
215 | */ | |
216 | public void flateCompress(int compressionLevel) { | |
217 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (!Document.compress) |
218 | return; | |
219 | // check if the flateCompress-method has already been | |
220 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (compressed) { |
221 | return; | |
222 | } | |
223 | this.compressionLevel = compressionLevel; | |
224 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (inputStream != null) { |
225 | compressed = true; | |
226 | return; | |
227 | } | |
228 | // check if a filter already exists | |
229 | PdfObject filter = PdfReader.getPdfObject(get(PdfName.FILTER)); | |
230 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (filter != null) { |
231 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (filter.isName()) { |
232 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (PdfName.FLATEDECODE.equals(filter)) |
233 | return; | |
234 | } | |
235 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
else if (filter.isArray()) { |
236 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (((PdfArray) filter).contains(PdfName.FLATEDECODE)) |
237 | return; | |
238 | } | |
239 | else { | |
240 | throw new RuntimeException(MessageLocalization.getComposedMessage("stream.could.not.be.compressed.filter.is.not.a.name.or.array")); | |
241 | } | |
242 | } | |
243 | try { | |
244 | // compress | |
245 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); | |
246 | Deflater deflater = new Deflater(compressionLevel); | |
247 | DeflaterOutputStream zip = new DeflaterOutputStream(stream, deflater); | |
248 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (streamBytes != null) |
249 |
1
1. flateCompress : removed call to java/io/ByteArrayOutputStream::writeTo → NO_COVERAGE |
streamBytes.writeTo(zip); |
250 | else | |
251 |
1
1. flateCompress : removed call to java/util/zip/DeflaterOutputStream::write → NO_COVERAGE |
zip.write(bytes); |
252 |
1
1. flateCompress : removed call to java/util/zip/DeflaterOutputStream::close → NO_COVERAGE |
zip.close(); |
253 |
1
1. flateCompress : removed call to java/util/zip/Deflater::end → NO_COVERAGE |
deflater.end(); |
254 | // update the object | |
255 | streamBytes = stream; | |
256 | bytes = null; | |
257 |
1
1. flateCompress : removed call to com/lowagie/text/pdf/PdfStream::put → NO_COVERAGE |
put(PdfName.LENGTH, new PdfNumber(streamBytes.size())); |
258 |
1
1. flateCompress : negated conditional → NO_COVERAGE |
if (filter == null) { |
259 |
1
1. flateCompress : removed call to com/lowagie/text/pdf/PdfStream::put → NO_COVERAGE |
put(PdfName.FILTER, PdfName.FLATEDECODE); |
260 | } | |
261 | else { | |
262 | PdfArray filters = new PdfArray(filter); | |
263 | filters.add(PdfName.FLATEDECODE); | |
264 |
1
1. flateCompress : removed call to com/lowagie/text/pdf/PdfStream::put → NO_COVERAGE |
put(PdfName.FILTER, filters); |
265 | } | |
266 | compressed = true; | |
267 | } | |
268 | catch(IOException ioe) { | |
269 | throw new ExceptionConverter(ioe); | |
270 | } | |
271 | } | |
272 | ||
273 | // public int getStreamLength(PdfWriter writer) { | |
274 | // if (dicBytes == null) | |
275 | // toPdf(writer); | |
276 | // if (streamBytes != null) | |
277 | // return streamBytes.size() + dicBytes.length + SIZESTREAM; | |
278 | // else | |
279 | // return bytes.length + dicBytes.length + SIZESTREAM; | |
280 | // } | |
281 | | |
282 | protected void superToPdf(PdfWriter writer, OutputStream os) throws IOException { | |
283 | super.toPdf(writer, os); | |
284 | } | |
285 | | |
286 | /** | |
287 | * @see com.lowagie.text.pdf.PdfDictionary#toPdf(com.lowagie.text.pdf.PdfWriter, java.io.OutputStream) | |
288 | */ | |
289 | public void toPdf(PdfWriter writer, OutputStream os) throws IOException { | |
290 |
2
1. toPdf : negated conditional → NO_COVERAGE 2. toPdf : negated conditional → NO_COVERAGE |
if (inputStream != null && compressed) |
291 |
1
1. toPdf : removed call to com/lowagie/text/pdf/PdfStream::put → NO_COVERAGE |
put(PdfName.FILTER, PdfName.FLATEDECODE); |
292 | PdfEncryption crypto = null; | |
293 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (writer != null) |
294 | crypto = writer.getEncryption(); | |
295 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (crypto != null) { |
296 | PdfObject filter = get(PdfName.FILTER); | |
297 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (filter != null) { |
298 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (PdfName.CRYPT.equals(filter)) |
299 | crypto = null; | |
300 |
1
1. toPdf : negated conditional → NO_COVERAGE |
else if (filter.isArray()) { |
301 | PdfArray a = (PdfArray)filter; | |
302 |
2
1. toPdf : negated conditional → NO_COVERAGE 2. toPdf : negated conditional → NO_COVERAGE |
if (!a.isEmpty() && PdfName.CRYPT.equals(a.getPdfObject(0))) |
303 | crypto = null; | |
304 | } | |
305 | } | |
306 | } | |
307 | PdfObject nn = get(PdfName.LENGTH); | |
308 |
3
1. toPdf : negated conditional → NO_COVERAGE 2. toPdf : negated conditional → NO_COVERAGE 3. toPdf : negated conditional → NO_COVERAGE |
if (crypto != null && nn != null && nn.isNumber()) { |
309 | int sz = ((PdfNumber)nn).intValue(); | |
310 |
1
1. toPdf : removed call to com/lowagie/text/pdf/PdfStream::put → NO_COVERAGE |
put(PdfName.LENGTH, new PdfNumber(crypto.calculateStreamSize(sz))); |
311 |
1
1. toPdf : removed call to com/lowagie/text/pdf/PdfStream::superToPdf → NO_COVERAGE |
superToPdf(writer, os); |
312 |
1
1. toPdf : removed call to com/lowagie/text/pdf/PdfStream::put → NO_COVERAGE |
put(PdfName.LENGTH, nn); |
313 | } | |
314 | else | |
315 |
1
1. toPdf : removed call to com/lowagie/text/pdf/PdfStream::superToPdf → NO_COVERAGE |
superToPdf(writer, os); |
316 |
1
1. toPdf : removed call to java/io/OutputStream::write → NO_COVERAGE |
os.write(STARTSTREAM); |
317 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (inputStream != null) { |
318 | rawLength = 0; | |
319 | DeflaterOutputStream def = null; | |
320 | OutputStreamCounter osc = new OutputStreamCounter(os); | |
321 | OutputStreamEncryption ose = null; | |
322 | OutputStream fout = osc; | |
323 |
2
1. toPdf : negated conditional → NO_COVERAGE 2. toPdf : negated conditional → NO_COVERAGE |
if (crypto != null && !crypto.isEmbeddedFilesOnly()) |
324 | fout = ose = crypto.getEncryptionStream(fout); | |
325 | Deflater deflater = null; | |
326 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (compressed) { |
327 | deflater = new Deflater(compressionLevel); | |
328 | fout = def = new DeflaterOutputStream(fout, deflater, 0x8000); | |
329 | } | |
330 | ||
331 | byte[] buf = new byte[4192]; | |
332 | while (true) { | |
333 | int n = inputStream.read(buf); | |
334 |
2
1. toPdf : changed conditional boundary → NO_COVERAGE 2. toPdf : negated conditional → NO_COVERAGE |
if (n <= 0) |
335 | break; | |
336 |
1
1. toPdf : removed call to java/io/OutputStream::write → NO_COVERAGE |
fout.write(buf, 0, n); |
337 |
1
1. toPdf : Replaced integer addition with subtraction → NO_COVERAGE |
rawLength += n; |
338 | } | |
339 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (def != null) { |
340 |
1
1. toPdf : removed call to java/util/zip/DeflaterOutputStream::finish → NO_COVERAGE |
def.finish(); |
341 |
1
1. toPdf : removed call to java/util/zip/Deflater::end → NO_COVERAGE |
deflater.end(); |
342 | } | |
343 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (ose != null) |
344 |
1
1. toPdf : removed call to com/lowagie/text/pdf/OutputStreamEncryption::finish → NO_COVERAGE |
ose.finish(); |
345 | inputStreamLength = osc.getCounter(); | |
346 | } | |
347 | else { | |
348 |
2
1. toPdf : negated conditional → NO_COVERAGE 2. toPdf : negated conditional → NO_COVERAGE |
if (crypto != null && !crypto.isEmbeddedFilesOnly()) { |
349 | byte[] b; | |
350 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (streamBytes != null) { |
351 | b = crypto.encryptByteArray(streamBytes.toByteArray()); | |
352 | } | |
353 | else { | |
354 | b = crypto.encryptByteArray(bytes); | |
355 | } | |
356 |
1
1. toPdf : removed call to java/io/OutputStream::write → NO_COVERAGE |
os.write(b); |
357 | } | |
358 | else { | |
359 |
1
1. toPdf : negated conditional → NO_COVERAGE |
if (streamBytes != null) |
360 |
1
1. toPdf : removed call to java/io/ByteArrayOutputStream::writeTo → NO_COVERAGE |
streamBytes.writeTo(os); |
361 | else | |
362 |
1
1. toPdf : removed call to java/io/OutputStream::write → NO_COVERAGE |
os.write(bytes); |
363 | } | |
364 | } | |
365 |
1
1. toPdf : removed call to java/io/OutputStream::write → NO_COVERAGE |
os.write(ENDSTREAM); |
366 | } | |
367 | | |
368 | /** | |
369 | * Writes the data content to an <CODE>OutputStream</CODE>. | |
370 | * @param os the destination to write to | |
371 | * @throws IOException on error | |
372 | */ | |
373 | public void writeContent(OutputStream os) throws IOException { | |
374 |
1
1. writeContent : negated conditional → NO_COVERAGE |
if (streamBytes != null) |
375 |
1
1. writeContent : removed call to java/io/ByteArrayOutputStream::writeTo → NO_COVERAGE |
streamBytes.writeTo(os); |
376 |
1
1. writeContent : negated conditional → NO_COVERAGE |
else if (bytes != null) |
377 |
1
1. writeContent : removed call to java/io/OutputStream::write → NO_COVERAGE |
os.write(bytes); |
378 | } | |
379 | | |
380 | /** | |
381 | * @see com.lowagie.text.pdf.PdfObject#toString() | |
382 | */ | |
383 | public String toString() { | |
384 | if (get(PdfName.TYPE) == null) return "Stream"; | |
385 | return "Stream of type: " + get(PdfName.TYPE); | |
386 | } | |
387 | } | |
Mutations | ||
144 |
1.1 |
|
168 |
1.1 |
|
189 |
1.1 |
|
191 |
1.1 |
|
208 |
1.1 |
|
217 |
1.1 |
|
220 |
1.1 |
|
224 |
1.1 |
|
230 |
1.1 |
|
231 |
1.1 |
|
232 |
1.1 |
|
235 |
1.1 |
|
236 |
1.1 |
|
248 |
1.1 |
|
249 |
1.1 |
|
251 |
1.1 |
|
252 |
1.1 |
|
253 |
1.1 |
|
257 |
1.1 |
|
258 |
1.1 |
|
259 |
1.1 |
|
264 |
1.1 |
|
290 |
1.1 2.2 |
|
291 |
1.1 |
|
293 |
1.1 |
|
295 |
1.1 |
|
297 |
1.1 |
|
298 |
1.1 |
|
300 |
1.1 |
|
302 |
1.1 2.2 |
|
308 |
1.1 2.2 3.3 |
|
310 |
1.1 |
|
311 |
1.1 |
|
312 |
1.1 |
|
315 |
1.1 |
|
316 |
1.1 |
|
317 |
1.1 |
|
323 |
1.1 2.2 |
|
326 |
1.1 |
|
334 |
1.1 2.2 |
|
336 |
1.1 |
|
337 |
1.1 |
|
339 |
1.1 |
|
340 |
1.1 |
|
341 |
1.1 |
|
343 |
1.1 |
|
344 |
1.1 |
|
348 |
1.1 2.2 |
|
350 |
1.1 |
|
356 |
1.1 |
|
359 |
1.1 |
|
360 |
1.1 |
|
362 |
1.1 |
|
365 |
1.1 |
|
374 |
1.1 |
|
375 |
1.1 |
|
376 |
1.1 |
|
377 |
1.1 |