KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > pdfbox > pdfwriter > COSWriter


1 /**
2  * Copyright (c) 2003-2006, www.pdfbox.org
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. Neither the name of pdfbox; nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * http://www.pdfbox.org
29  *
30  */

31 package org.pdfbox.pdfwriter;
32
33 import java.io.IOException JavaDoc;
34 import java.io.InputStream JavaDoc;
35 import java.io.OutputStream JavaDoc;
36 import java.security.MessageDigest JavaDoc;
37 import java.security.NoSuchAlgorithmException JavaDoc;
38 import java.text.DecimalFormat JavaDoc;
39 import java.text.NumberFormat JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.util.Collections JavaDoc;
42 import java.util.HashSet JavaDoc;
43 import java.util.Hashtable JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Locale JavaDoc;
47 import java.util.Map JavaDoc;
48 import java.util.Set JavaDoc;
49
50 import org.pdfbox.cos.COSArray;
51 import org.pdfbox.cos.COSBase;
52 import org.pdfbox.cos.COSBoolean;
53 import org.pdfbox.cos.COSDictionary;
54 import org.pdfbox.cos.COSDocument;
55 import org.pdfbox.cos.COSFloat;
56 import org.pdfbox.cos.COSInteger;
57 import org.pdfbox.cos.COSName;
58 import org.pdfbox.cos.COSNull;
59 import org.pdfbox.cos.COSObject;
60 import org.pdfbox.cos.COSStream;
61 import org.pdfbox.cos.COSString;
62 import org.pdfbox.cos.ICOSVisitor;
63 import org.pdfbox.exceptions.COSVisitorException;
64 import org.pdfbox.exceptions.CryptographyException;
65 import org.pdfbox.pdmodel.PDDocument;
66 import org.pdfbox.pdmodel.encryption.SecurityHandler;
67 import org.pdfbox.persistence.util.COSObjectKey;
68
69 /**
70  * this class acts on a in-memory representation of a pdf document.
71  *
72  * todo no support for incremental updates
73  * todo single xref section only
74  * todo no linearization
75  *
76  * @author Michael Traut
77  * @author <a HREF="mailto:ben@benlitchfield.com">Ben Litchfield</a>
78  * @version $Revision: 1.36 $
79  */

80 public class COSWriter implements ICOSVisitor
81 {
82     /**
83      * The dictionary open token.
84      */

85     public static final byte[] DICT_OPEN = "<<".getBytes();
86     /**
87      * The dictionary close token.
88      */

89     public static final byte[] DICT_CLOSE = ">>".getBytes();
90     /**
91      * space character.
92      */

93     public static final byte[] SPACE = " ".getBytes();
94     /**
95      * The start to a PDF comment.
96      */

97     public static final byte[] COMMENT = "%".getBytes();
98
99     /**
100      * The output version of the PDF.
101      */

102     public static final byte[] VERSION = "PDF-1.4".getBytes();
103     /**
104      * Garbage bytes used to create the PDF header.
105      */

106     public static final byte[] GARBAGE = new byte[] {(byte)0xf6, (byte)0xe4, (byte)0xfc, (byte)0xdf};
107     /**
108      * The EOF constant.
109      */

110     public static final byte[] EOF = "%%EOF".getBytes();
111     // pdf tokens
112

113     /**
114      * The reference token.
115      */

116     public static final byte[] REFERENCE = "R".getBytes();
117     /**
118      * The XREF token.
119      */

120     public static final byte[] XREF = "xref".getBytes();
121     /**
122      * The xref free token.
123      */

124     public static final byte[] XREF_FREE = "f".getBytes();
125     /**
126      * The xref used token.
127      */

128     public static final byte[] XREF_USED = "n".getBytes();
129     /**
130      * The trailer token.
131      */

132     public static final byte[] TRAILER = "trailer".getBytes();
133     /**
134      * The start xref token.
135      */

136     public static final byte[] STARTXREF = "startxref".getBytes();
137     /**
138      * The starting object token.
139      */

140     public static final byte[] OBJ = "obj".getBytes();
141     /**
142      * The end object token.
143      */

144     public static final byte[] ENDOBJ = "endobj".getBytes();
145     /**
146      * The array open token.
147      */

148     public static final byte[] ARRAY_OPEN = "[".getBytes();
149     /**
150      * The array close token.
151      */

152     public static final byte[] ARRAY_CLOSE = "]".getBytes();
153     /**
154      * The open stream token.
155      */

156     public static final byte[] STREAM = "stream".getBytes();
157     /**
158      * The close stream token.
159      */

160     public static final byte[] ENDSTREAM = "endstream".getBytes();
161
162     private NumberFormat JavaDoc formatXrefOffset = new DecimalFormat JavaDoc("0000000000");
163     /**
164      * The decimal format for the xref object generation number data.
165      */

166     private NumberFormat JavaDoc formatXrefGeneration = new DecimalFormat JavaDoc("00000");
167
168     private NumberFormat JavaDoc formatDecimal = NumberFormat.getNumberInstance( Locale.US );
169
170     // the stream where we create the pdf output
171
private OutputStream JavaDoc output;
172     // the stream used to write standard cos data
173
private COSStandardOutputStream standardOutput;
174
175     // the start position of the x ref section
176
private long startxref = 0;
177
178     // the current object number
179
private long number = 0;
180
181     // maps the object to the keys generated in the writer
182
// these are used for indirect refrences in other objects
183
//A hashtable is used on purpose over a hashmap
184
//so that null entries will not get added.
185
private Map JavaDoc objectKeys = new Hashtable JavaDoc();
186
187     // the list of x ref entries to be made so far
188
private List JavaDoc xRefEntries = new ArrayList JavaDoc();
189
190     //A list of objects to write.
191
private List JavaDoc objectsToWrite = new ArrayList JavaDoc();
192
193     //a list of objects already written
194
private Set JavaDoc writtenObjects = new HashSet JavaDoc();
195     //An 'actual' is any COSBase that is not a COSObject.
196
//need to keep a list of the actuals that are added
197
//as well as the objects because there is a problem
198
//when adding a COSObject and then later adding
199
//the actual for that object, so we will track
200
//actuals separately.
201
private Set JavaDoc actualsAdded = new HashSet JavaDoc();
202     
203     private COSObjectKey currentObjectKey = null;
204    
205     private PDDocument document = null;
206     
207     private boolean willEncrypt = false;
208
209     /**
210      * COSWriter constructor comment.
211      *
212      * @param os The wrapped output stream.
213      */

214     public COSWriter(OutputStream JavaDoc os)
215     {
216         super();
217         setOutput(os);
218         setStandardOutput(new COSStandardOutputStream(getOutput()));
219         formatDecimal.setMaximumFractionDigits( 10 );
220         formatDecimal.setGroupingUsed( false );
221     }
222     /**
223      * add an entry in the x ref table for later dump.
224      *
225      * @param entry The new entry to add.
226      */

227     protected void addXRefEntry(COSWriterXRefEntry entry)
228     {
229         getXRefEntries().add(entry);
230     }
231
232     /**
233      * This will close the stream.
234      *
235      * @throws IOException If the underlying stream throws an exception.
236      */

237     public void close() throws IOException JavaDoc
238     {
239         if (getStandardOutput() != null)
240         {
241             getStandardOutput().close();
242         }
243         if (getOutput() != null)
244         {
245             getOutput().close();
246         }
247     }
248
249     /**
250      * This will get the current object number.
251      *
252      * @return The current object number.
253      */

254     protected long getNumber()
255     {
256         return number;
257     }
258
259     /**
260      * This will get all available object keys.
261      *
262      * @return A map of all object keys.
263      */

264     public java.util.Map JavaDoc getObjectKeys()
265     {
266         return objectKeys;
267     }
268
269     /**
270      * This will get the output stream.
271      *
272      * @return The output stream.
273      */

274     protected java.io.OutputStream JavaDoc getOutput()
275     {
276         return output;
277     }
278
279     /**
280      * This will get the standard output stream.
281      *
282      * @return The standard output stream.
283      */

284     protected COSStandardOutputStream getStandardOutput()
285     {
286         return standardOutput;
287     }
288
289     /**
290      * This will get the current start xref.
291      *
292      * @return The current start xref.
293      */

294     protected long getStartxref()
295     {
296         return startxref;
297     }
298     /**
299      * This will get the xref entries.
300      *
301      * @return All available xref entries.
302      */

303     protected java.util.List JavaDoc getXRefEntries()
304     {
305         return xRefEntries;
306     }
307
308     /**
309      * This will set the current object number.
310      *
311      * @param newNumber The new object number.
312      */

313     protected void setNumber(long newNumber)
314     {
315         number = newNumber;
316     }
317
318     /**
319      * This will set the output stream.
320      *
321      * @param newOutput The new output stream.
322      */

323     private void setOutput( OutputStream JavaDoc newOutput )
324     {
325         output = newOutput;
326     }
327
328     /**
329      * This will set the standard output stream.
330      *
331      * @param newStandardOutput The new standard output stream.
332      */

333     private void setStandardOutput(COSStandardOutputStream newStandardOutput)
334     {
335         standardOutput = newStandardOutput;
336     }
337
338     /**
339      * This will set the start xref.
340      *
341      * @param newStartxref The new start xref attribute.
342      */

343     protected void setStartxref(long newStartxref)
344     {
345         startxref = newStartxref;
346     }
347
348     /**
349      * This will write the body of the document.
350      *
351      * @param doc The document to write the body for.
352      *
353      * @throws IOException If there is an error writing the data.
354      * @throws COSVisitorException If there is an error generating the data.
355      */

356     protected void doWriteBody(COSDocument doc) throws IOException JavaDoc, COSVisitorException
357     {
358         COSDictionary trailer = doc.getTrailer();
359         COSDictionary root = (COSDictionary)trailer.getDictionaryObject( COSName.ROOT );
360         COSDictionary info = (COSDictionary)trailer.getDictionaryObject( COSName.getPDFName( "Info" ) );
361         COSDictionary encrypt = (COSDictionary)trailer.getDictionaryObject( COSName.getPDFName( "Encrypt" ) );
362         if( root != null )
363         {
364             addObjectToWrite( root );
365         }
366         if( info != null )
367         {
368             addObjectToWrite( info );
369         }
370         
371
372         while( objectsToWrite.size() > 0 )
373         {
374             COSBase nextObject = (COSBase)objectsToWrite.remove( 0 );
375             doWriteObject( nextObject );
376         }
377         
378         
379         willEncrypt = false;
380         
381         if( encrypt != null )
382         {
383             addObjectToWrite( encrypt );
384         }
385         
386         while( objectsToWrite.size() > 0 )
387         {
388             COSBase nextObject = (COSBase)objectsToWrite.remove( 0 );
389             doWriteObject( nextObject );
390         }
391
392         // write all objects
393
/**
394         for (Iterator i = doc.getObjects().iterator(); i.hasNext();)
395         {
396             COSObject obj = (COSObject) i.next();
397             doWriteObject(obj);
398         }**/

399     }
400
401     private void addObjectToWrite( COSBase object )
402     {
403         COSBase actual = object;
404         if( actual instanceof COSObject )
405         {
406             actual = ((COSObject)actual).getObject();
407         }
408         
409         if( !writtenObjects.contains( object ) &&
410             !objectsToWrite.contains( object ) &&
411             !actualsAdded.contains( actual ) )
412         {
413             objectsToWrite.add( object );
414             if( actual != null )
415             {
416                 actualsAdded.add( actual );
417             }
418         }
419     }
420
421     /**
422      * This will write a COS object.
423      *
424      * @param obj The object to write.
425      *
426      * @throws COSVisitorException If there is an error visiting objects.
427      */

428     public void doWriteObject( COSBase obj ) throws COSVisitorException
429     {
430         try
431         {
432             writtenObjects.add( obj );
433             // find the physical reference
434
currentObjectKey = getObjectKey( obj );
435             // add a x ref entry
436
addXRefEntry( new COSWriterXRefEntry(getStandardOutput().getPos(), obj, currentObjectKey));
437             // write the object
438
getStandardOutput().write(String.valueOf(currentObjectKey.getNumber()).getBytes());
439             getStandardOutput().write(SPACE);
440             getStandardOutput().write(String.valueOf(currentObjectKey.getGeneration()).getBytes());
441             getStandardOutput().write(SPACE);
442             getStandardOutput().write(OBJ);
443             getStandardOutput().writeEOL();
444             obj.accept( this );
445             getStandardOutput().writeEOL();
446             getStandardOutput().write(ENDOBJ);
447             getStandardOutput().writeEOL();
448         }
449         catch (IOException JavaDoc e)
450         {
451             throw new COSVisitorException(e);
452         }
453     }
454
455     /**
456      * This will write the header to the PDF document.
457      *
458      * @param doc The document to get the data from.
459      *
460      * @throws IOException If there is an error writing to the stream.
461      */

462     protected void doWriteHeader(COSDocument doc) throws IOException JavaDoc
463     {
464         getStandardOutput().write( doc.getHeaderString().getBytes() );
465         getStandardOutput().writeEOL();
466         getStandardOutput().write(COMMENT);
467         getStandardOutput().write(GARBAGE);
468         getStandardOutput().writeEOL();
469     }
470
471
472     /**
473      * This will write the trailer to the PDF document.
474      *
475      * @param doc The document to create the trailer for.
476      *
477      * @throws IOException If there is an IOError while writing the document.
478      * @throws COSVisitorException If there is an error while generating the data.
479      */

480     protected void doWriteTrailer(COSDocument doc) throws IOException JavaDoc, COSVisitorException
481     {
482         getStandardOutput().write(TRAILER);
483         getStandardOutput().writeEOL();
484
485         COSDictionary trailer = doc.getTrailer();
486         //sort xref, needed only if object keys not regenerated
487
Collections.sort(getXRefEntries());
488         COSWriterXRefEntry lastEntry = (COSWriterXRefEntry)getXRefEntries().get( getXRefEntries().size()-1);
489         trailer.setInt(COSName.getPDFName("Size"), (int)lastEntry.getKey().getNumber()+1);
490         trailer.removeItem( COSName.PREV );
491         /**
492         COSObject catalog = doc.getCatalog();
493         if (catalog != null)
494         {
495             trailer.setItem(COSName.getPDFName("Root"), catalog);
496         }
497         */

498         trailer.accept(this);
499
500         getStandardOutput().write(STARTXREF);
501         getStandardOutput().writeEOL();
502         getStandardOutput().write(String.valueOf(getStartxref()).getBytes());
503         getStandardOutput().writeEOL();
504         getStandardOutput().write(EOF);
505     }
506
507     /**
508      * write the x ref section for the pdf file
509      *
510      * currently, the pdf is reconstructed from the scratch, so we write a single section
511      *
512      * todo support for incremental writing?
513      *
514      * @param doc The document to write the xref from.
515      *
516      * @throws IOException If there is an error writing the data to the stream.
517      */

518     protected void doWriteXRef(COSDocument doc) throws IOException JavaDoc
519     {
520         String JavaDoc offset;
521         String JavaDoc generation;
522
523         // sort xref, needed only if object keys not regenerated
524
Collections.sort(getXRefEntries());
525         COSWriterXRefEntry lastEntry = (COSWriterXRefEntry)getXRefEntries().get( getXRefEntries().size()-1 );
526
527         // remember the position where x ref is written
528
setStartxref(getStandardOutput().getPos());
529         //
530
getStandardOutput().write(XREF);
531         getStandardOutput().writeEOL();
532         // write start object number and object count for this x ref section
533
// we assume starting from scratch
534
getStandardOutput().write(String.valueOf(0).getBytes());
535         getStandardOutput().write(SPACE);
536         getStandardOutput().write(String.valueOf(lastEntry.getKey().getNumber() + 1).getBytes());
537         getStandardOutput().writeEOL();
538         // write initial start object with ref to first deleted object and magic generation number
539
offset = formatXrefOffset.format(0);
540         generation = formatXrefGeneration.format(65535);
541         getStandardOutput().write(offset.getBytes());
542         getStandardOutput().write(SPACE);
543         getStandardOutput().write(generation.getBytes());
544         getStandardOutput().write(SPACE);
545         getStandardOutput().write(XREF_FREE);
546         getStandardOutput().writeCRLF();
547         // write entry for every object
548
long lastObjectNumber = 0;
549         for (Iterator JavaDoc i = getXRefEntries().iterator(); i.hasNext();)
550         {
551             COSWriterXRefEntry entry = (COSWriterXRefEntry) i.next();
552             while( lastObjectNumber<entry.getKey().getNumber()-1 )
553             {
554                 offset = formatXrefOffset.format(0);
555                 generation = formatXrefGeneration.format(65535);
556                 getStandardOutput().write(offset.getBytes());
557                 getStandardOutput().write(SPACE);
558                 getStandardOutput().write(generation.getBytes());
559                 getStandardOutput().write(SPACE);
560                 getStandardOutput().write(XREF_FREE);
561                 getStandardOutput().writeCRLF();
562                 lastObjectNumber++;
563             }
564             lastObjectNumber = entry.getKey().getNumber();
565             offset = formatXrefOffset.format(entry.getOffset());
566             generation = formatXrefGeneration.format(entry.getKey().getGeneration());
567             getStandardOutput().write(offset.getBytes());
568             getStandardOutput().write(SPACE);
569             getStandardOutput().write(generation.getBytes());
570             getStandardOutput().write(SPACE);
571             getStandardOutput().write(entry.isFree() ? XREF_FREE : XREF_USED);
572             getStandardOutput().writeCRLF();
573         }
574     }
575
576     /**
577      * This will get the object key for the object.
578      *
579      * @param obj The object to get the key for.
580      *
581      * @return The object key for the object.
582      */

583     private COSObjectKey getObjectKey( COSBase obj )
584     {
585         COSBase actual = obj;
586         if( actual instanceof COSObject )
587         {
588             actual = ((COSObject)obj).getObject();
589         }
590         COSObjectKey key = null;
591         if( actual != null )
592         {
593             key = (COSObjectKey)objectKeys.get(actual);
594         }
595         if( key == null )
596         {
597             key = (COSObjectKey)objectKeys.get(obj);
598         }
599         if (key == null)
600         {
601             setNumber(getNumber()+1);
602             key = new COSObjectKey(getNumber(),0);
603             objectKeys.put(obj, key);
604             if( actual != null )
605             {
606                 objectKeys.put(actual, key);
607             }
608         }
609         return key;
610     }
611
612     /**
613      * visitFromArray method comment.
614      *
615      * @param obj The object that is being visited.
616      *
617      * @throws COSVisitorException If there is an exception while visiting this object.
618      *
619      * @return null
620      */

621     public Object JavaDoc visitFromArray( COSArray obj ) throws COSVisitorException
622     {
623         try
624         {
625             int count = 0;
626             getStandardOutput().write(ARRAY_OPEN);
627             for (Iterator JavaDoc i = obj.iterator(); i.hasNext();)
628             {
629                 COSBase current = (COSBase) i.next();
630                 if( current instanceof COSDictionary )
631                 {
632                     addObjectToWrite( current );
633                     writeReference( current );
634                 }
635                 else if( current instanceof COSObject )
636                 {
637                     COSBase subValue = ((COSObject)current).getObject();
638                     if( subValue instanceof COSDictionary || subValue == null )
639                     {
640                         addObjectToWrite( current );
641                         writeReference( current );
642                     }
643                     else
644                     {
645                         subValue.accept( this );
646                     }
647                 }
648                 else if( current == null )
649                 {
650                     COSNull.NULL.accept( this );
651                 }
652                 else
653                 {
654                     current.accept(this);
655                 }
656                 count++;
657                 if (i.hasNext())
658                 {
659                     if (count % 10 == 0)
660                     {
661                         getStandardOutput().writeEOL();
662                     }
663                     else
664                     {
665                         getStandardOutput().write(SPACE);
666                     }
667                 }
668             }
669             getStandardOutput().write(ARRAY_CLOSE);
670             getStandardOutput().writeEOL();
671             return null;
672         }
673         catch (IOException JavaDoc e)
674         {
675             throw new COSVisitorException(e);
676         }
677     }
678
679     /**
680      * visitFromBoolean method comment.
681      *
682      * @param obj The object that is being visited.
683      *
684      * @throws COSVisitorException If there is an exception while visiting this object.
685      *
686      * @return null
687      */

688     public Object JavaDoc visitFromBoolean(COSBoolean obj) throws COSVisitorException
689     {
690         
691         try
692         {
693             obj.writePDF( getStandardOutput() );
694             return null;
695         }
696         catch (IOException JavaDoc e)
697         {
698             throw new COSVisitorException(e);
699         }
700     }
701
702     /**
703      * visitFromDictionary method comment.
704      *
705      * @param obj The object that is being visited.
706      *
707      * @throws COSVisitorException If there is an exception while visiting this object.
708      *
709      * @return null
710      */

711     public Object JavaDoc visitFromDictionary(COSDictionary obj) throws COSVisitorException
712     {
713         try
714         {
715             getStandardOutput().write(DICT_OPEN);
716             getStandardOutput().writeEOL();
717             for (Iterator JavaDoc i = obj.keyList().iterator(); i.hasNext();)
718             {
719                 COSName name = (COSName) i.next();
720                 COSBase value = obj.getItem(name);
721                 if (value != null)
722                 {
723                     name.accept(this);
724                     getStandardOutput().write(SPACE);
725                     if( value instanceof COSDictionary )
726                     {
727                         addObjectToWrite( value );
728                         writeReference( value );
729                     }
730                     else if( value instanceof COSObject )
731                     {
732                         COSBase subValue = ((COSObject)value).getObject();
733                         if( subValue instanceof COSDictionary || subValue == null )
734                         {
735                             addObjectToWrite( value );
736                             writeReference( value );
737                         }
738                         else
739                         {
740                             subValue.accept( this );
741                         }
742                     }
743                     else
744                     {
745                         value.accept(this);
746                     }
747                     getStandardOutput().writeEOL();
748
749                 }
750                 else
751                 {
752                     //then we won't write anything, there are a couple cases
753
//were the value of an entry in the COSDictionary will
754
//be a dangling reference that points to nothing
755
//so we will just not write out the entry if that is the case
756
}
757             }
758             getStandardOutput().write(DICT_CLOSE);
759             getStandardOutput().writeEOL();
760             return null;
761         }
762         catch( IOException JavaDoc e )
763         {
764             throw new COSVisitorException(e);
765         }
766     }
767
768     /**
769      * The visit from document method.
770      *
771      * @param doc The object that is being visited.
772      *
773      * @throws COSVisitorException If there is an exception while visiting this object.
774      *
775      * @return null
776      */

777     public Object JavaDoc visitFromDocument(COSDocument doc) throws COSVisitorException
778     {
779         try
780         {
781             doWriteHeader(doc);
782             doWriteBody(doc);
783             doWriteXRef(doc);
784             doWriteTrailer(doc);
785             return null;
786         }
787         catch (IOException JavaDoc e)
788         {
789             throw new COSVisitorException(e);
790         }
791     }
792
793     /**
794      * visitFromFloat method comment.
795      *
796      * @param obj The object that is being visited.
797      *
798      * @throws COSVisitorException If there is an exception while visiting this object.
799      *
800      * @return null
801      */

802     public Object JavaDoc visitFromFloat(COSFloat obj) throws COSVisitorException
803     {
804         
805         try
806         {
807             obj.writePDF( getStandardOutput() );
808             return null;
809         }
810         catch (IOException JavaDoc e)
811         {
812             throw new COSVisitorException(e);
813         }
814     }
815
816     /**
817      * visitFromFloat method comment.
818      *
819      * @param obj The object that is being visited.
820      *
821      * @throws COSVisitorException If there is an exception while visiting this object.
822      *
823      * @return null
824      */

825     public Object JavaDoc visitFromInt(COSInteger obj) throws COSVisitorException
826     {
827         try
828         {
829             obj.writePDF( getStandardOutput() );
830             return null;
831         }
832         catch (IOException JavaDoc e)
833         {
834             throw new COSVisitorException(e);
835         }
836     }
837
838     /**
839      * visitFromName method comment.
840      *
841      * @param obj The object that is being visited.
842      *
843      * @throws COSVisitorException If there is an exception while visiting this object.
844      *
845      * @return null
846      */

847     public Object JavaDoc visitFromName(COSName obj) throws COSVisitorException
848     {
849         try
850         {
851             obj.writePDF( getStandardOutput() );
852             return null;
853         }
854         catch (IOException JavaDoc e)
855         {
856             throw new COSVisitorException(e);
857         }
858     }
859
860     /**
861      * visitFromNull method comment.
862      *
863      * @param obj The object that is being visited.
864      *
865      * @throws COSVisitorException If there is an exception while visiting this object.
866      *
867      * @return null
868      */

869     public Object JavaDoc visitFromNull(COSNull obj) throws COSVisitorException
870     {
871         try
872         {
873             obj.writePDF( getStandardOutput() );
874             return null;
875         }
876         catch (IOException JavaDoc e)
877         {
878             throw new COSVisitorException(e);
879         }
880     }
881
882     /**
883      * visitFromObjRef method comment.
884      *
885      * @param obj The object that is being visited.
886      *
887      * @throws COSVisitorException If there is an exception while visiting this object.
888      */

889     public void writeReference(COSBase obj) throws COSVisitorException
890     {
891         try
892         {
893             COSObjectKey key = getObjectKey(obj);
894             getStandardOutput().write(String.valueOf(key.getNumber()).getBytes());
895             getStandardOutput().write(SPACE);
896             getStandardOutput().write(String.valueOf(key.getGeneration()).getBytes());
897             getStandardOutput().write(SPACE);
898             getStandardOutput().write(REFERENCE);
899         }
900         catch (IOException JavaDoc e)
901         {
902             throw new COSVisitorException(e);
903         }
904     }
905
906     /**
907      * visitFromStream method comment.
908      *
909      * @param obj The object that is being visited.
910      *
911      * @throws COSVisitorException If there is an exception while visiting this object.
912      *
913      * @return null
914      */

915     public Object JavaDoc visitFromStream(COSStream obj) throws COSVisitorException
916     {
917         try
918         {
919             if(willEncrypt)
920             {
921                 document.getSecurityHandler().decryptStream(
922                     obj,
923                     currentObjectKey.getNumber(),
924                     currentObjectKey.getGeneration());
925             }
926             
927             InputStream JavaDoc input = obj.getFilteredStream();
928             // set the length of the stream and write stream dictionary
929
COSObject lengthObject = new COSObject( null );
930             
931             obj.setItem(COSName.LENGTH, lengthObject);
932             //obj.accept(this);
933
// write the stream content
934
visitFromDictionary( obj );
935             getStandardOutput().write(STREAM);
936             getStandardOutput().writeCRLF();
937             byte[] buffer = new byte[1024];
938             int amountRead = 0;
939             int totalAmountWritten = 0;
940             while( (amountRead = input.read(buffer,0,1024)) != -1 )
941             {
942                 getStandardOutput().write( buffer, 0, amountRead );
943                 totalAmountWritten += amountRead;
944             }
945             lengthObject.setObject( new COSInteger( totalAmountWritten ) );
946             getStandardOutput().writeCRLF();
947             getStandardOutput().write(ENDSTREAM);
948             getStandardOutput().writeEOL();
949             return null;
950         }
951         catch( Exception JavaDoc e )
952         {
953             throw new COSVisitorException(e);
954         }
955     }
956
957     /**
958      * visitFromString method comment.
959      *
960      * @param obj The object that is being visited.
961      *
962      * @return null
963      *
964      * @throws COSVisitorException If there is an exception while visiting this object.
965      */

966     public Object JavaDoc visitFromString(COSString obj) throws COSVisitorException
967     {
968         try
969         {
970             if(willEncrypt)
971             {
972                 document.getSecurityHandler().decryptString(
973                     obj,
974                     currentObjectKey.getNumber(),
975                     currentObjectKey.getGeneration());
976             }
977                         
978             obj.writePDF( getStandardOutput() );
979         }
980         catch (Exception JavaDoc e)
981         {
982             throw new COSVisitorException(e);
983         }
984         return null;
985     }
986
987     /**
988      * This will write the pdf document.
989      *
990      * @param doc The document to write.
991      *
992      * @throws COSVisitorException If an error occurs while generating the data.
993      */

994     public void write(COSDocument doc) throws COSVisitorException
995     {
996         PDDocument pdDoc = new PDDocument( doc );
997         write( pdDoc );
998     }
999
1000    /**
1001     * This will write the pdf document.
1002     *
1003     * @param doc The document to write.
1004     *
1005     * @throws COSVisitorException If an error occurs while generating the data.
1006     */

1007    public void write(PDDocument doc) throws COSVisitorException
1008    {
1009        document = doc;
1010        
1011        SecurityHandler securityHandler = document.getSecurityHandler();
1012        if(securityHandler != null)
1013        {
1014            try
1015            {
1016                securityHandler.prepareDocumentForEncryption(document);
1017                this.willEncrypt = true;
1018            }
1019            catch(IOException JavaDoc e)
1020            {
1021                throw new COSVisitorException( e );
1022            }
1023            catch(CryptographyException e)
1024            {
1025                throw new COSVisitorException( e );
1026            }
1027        }
1028        else
1029        {
1030                this.willEncrypt = false;
1031        }
1032                
1033        COSDocument cosDoc = document.getDocument();
1034        COSDictionary trailer = cosDoc.getTrailer();
1035        COSArray idArray = (COSArray)trailer.getDictionaryObject( "ID" );
1036        if( idArray == null )
1037        {
1038            try
1039            {
1040                
1041                //algothim says to use time/path/size/values in doc to generate
1042
//the id. We don't have path or size, so do the best we can
1043
MessageDigest JavaDoc md = MessageDigest.getInstance( "MD5" );
1044                md.update( Long.toString( System.currentTimeMillis()).getBytes() );
1045                COSDictionary info = (COSDictionary)trailer.getDictionaryObject( "Info" );
1046                if( info != null )
1047                {
1048                    Iterator JavaDoc values = info.getValues().iterator();
1049                    while( values.hasNext() )
1050                    {
1051                        md.update( values.next().toString().getBytes() );
1052                    }
1053                }
1054                idArray = new COSArray();
1055                COSString id = new COSString( md.digest() );
1056                idArray.add( id );
1057                idArray.add( id );
1058                trailer.setItem( "ID", idArray );
1059            }
1060            catch( NoSuchAlgorithmException JavaDoc e )
1061            {
1062                throw new COSVisitorException( e );
1063            }
1064        }
1065        
1066        /*
1067        List objects = doc.getObjects();
1068        Iterator iter = objects.iterator();
1069        long maxNumber = 0;
1070        while( iter.hasNext() )
1071        {
1072            COSObject object = (COSObject)iter.next();
1073            if( object.getObjectNumber() != null &&
1074                object.getGenerationNumber() != null )
1075            {
1076                COSObjectKey key = new COSObjectKey( object.getObjectNumber().longValue(),
1077                                                     object.getGenerationNumber().longValue() );
1078                objectKeys.put( object.getObject(), key );
1079                objectKeys.put( object, key );
1080                maxNumber = Math.max( key.getNumber(), maxNumber );
1081                setNumber( maxNumber );
1082            }
1083        }*/

1084        cosDoc.accept(this);
1085    }
1086}
Popular Tags