001: /*
002: Copyright © 2006,2007 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,2007 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.files;
028:
029: import it.stefanochizzolini.clown.bytes.FileInputStream;
030: import it.stefanochizzolini.clown.bytes.IInputStream;
031: import it.stefanochizzolini.clown.bytes.IOutputStream;
032: import it.stefanochizzolini.clown.bytes.OutputStream;
033: import it.stefanochizzolini.clown.documents.Document;
034: import it.stefanochizzolini.clown.objects.IPdfIndirectObject;
035: import it.stefanochizzolini.clown.objects.PdfDataObject;
036: import it.stefanochizzolini.clown.objects.PdfDictionary;
037: import it.stefanochizzolini.clown.objects.PdfDirectObject;
038: import it.stefanochizzolini.clown.objects.PdfName;
039: import it.stefanochizzolini.clown.objects.PdfObject;
040: import it.stefanochizzolini.clown.objects.PdfReference;
041: import it.stefanochizzolini.clown.tokens.FileFormatException;
042: import it.stefanochizzolini.clown.tokens.Reader;
043: import it.stefanochizzolini.clown.tokens.Writer;
044: import it.stefanochizzolini.clown.tokens.XRefEntry;
045: import it.stefanochizzolini.clown.util.NotImplementedException;
046:
047: import java.util.Random;
048:
049: /**
050: PDF file representation.
051: @version 0.0.5
052: @since 0.0.0
053: */
054: public class File {
055: // <class>
056: // <static>
057: // <fields>
058: private static Random hashCodeGenerator = new Random();
059:
060: // </fields>
061:
062: // <interface>
063: // <public>
064: /**
065: Forces a generic object to be expressed as its corresponding data object.
066: */
067: public static PdfDataObject resolve(PdfObject object) {
068: if (object instanceof IPdfIndirectObject)
069: return ((IPdfIndirectObject) object).getDataObject();
070: else
071: return (PdfDataObject) object;
072: }
073:
074: /**
075: Forces a direct object to be updated (whether possible).
076: */
077: public static boolean update(PdfDirectObject object) {
078: /*
079: NOTE: Only PDF references are able to be updated. Other direct types
080: are dependent on their respective containers for update.
081: */
082: if (object instanceof PdfReference) {
083: ((PdfReference) object).getIndirectObject().update();
084: return true;
085: }
086:
087: return false;
088: }
089:
090: // </public>
091: // </interface>
092: // </static>
093:
094: // <dynamic>
095: // <fields>
096: private Document document;
097: private int hashCode = File.hashCodeGenerator.nextInt();
098: private IndirectObjects indirectObjects;
099: private Reader reader;
100: private PdfDictionary trailer;
101: private String version;
102: private XRefEntry[] xrefEntries;
103:
104: // </fields>
105:
106: // <constructors>
107: public File() {
108: this .version = "1.6";
109: this .trailer = new PdfDictionary();
110: this .indirectObjects = new IndirectObjects(this , null);
111: this .document = new Document(this );
112: }
113:
114: public File(String path) throws FileFormatException,
115: java.io.FileNotFoundException {
116: this (new FileInputStream(
117: new java.io.RandomAccessFile(path, "r")));
118: }
119:
120: public File(IInputStream stream) throws FileFormatException {
121: this .reader = new Reader(stream, this );
122:
123: this .version = reader.readVersion();
124: this .trailer = reader.readTrailer();
125:
126: // Is this file encrypted?
127: if (trailer.containsKey(PdfName.Encrypt))
128: throw new NotImplementedException(
129: "Encrypted files are currently not supported.");
130:
131: this .xrefEntries = reader.readXRefTable(trailer);
132: this .indirectObjects = new IndirectObjects(this , xrefEntries);
133: this .document = new Document(trailer.get(PdfName.Root));
134: }
135:
136: // </constructors>
137:
138: // <interface>
139: // <public>
140: public Document getDocument() {
141: return document;
142: }
143:
144: public IndirectObjects getIndirectObjects() {
145: return indirectObjects;
146: }
147:
148: public Reader getReader() {
149: return reader;
150: }
151:
152: public PdfDictionary getTrailer() {
153: return trailer;
154: }
155:
156: public String getVersion() {
157: return version;
158: }
159:
160: //TODO:IMPL avoid direct exposure of array (corruptible!)!!!
161: public XRefEntry[] getXRefEntries() {
162: return xrefEntries;
163: }
164:
165: public int hashCode() {
166: return hashCode;
167: }
168:
169: /**
170: Registers an <b>internal data object</b>.
171: @since 0.0.4
172: */
173: public PdfReference register(PdfDataObject object) {
174: return indirectObjects.add(object).getReference();
175: }
176:
177: /**
178: Unregisters an <b>internal object</b>.
179: @since 0.0.5
180: */
181: public void unregister(PdfReference reference) {
182: indirectObjects.remove(reference.getObjectNumber());
183: }
184:
185: /**
186: Serializes the file to the specified file-system path.
187: @param path Target path.
188: @param mode Serialization mode.
189: */
190: public void writeTo(String path, SerializationModeEnum mode) {
191: writeTo(new java.io.File(path), mode);
192: }
193:
194: /**
195: Serializes the file to the specified file-system file.
196: @param file Target file.
197: @param mode Serialization mode.
198: */
199: public void writeTo(java.io.File file, SerializationModeEnum mode) {
200: OutputStream outputStream;
201: java.io.BufferedOutputStream baseOutputStream;
202: try {
203: file.createNewFile();
204: baseOutputStream = new java.io.BufferedOutputStream(
205: new java.io.FileOutputStream(file));
206: outputStream = new OutputStream(baseOutputStream);
207: } catch (Exception e) {
208: throw new RuntimeException(file.getPath()
209: + " file couldn't be created.", e);
210: }
211:
212: try {
213: writeTo(outputStream, mode);
214:
215: baseOutputStream.flush();
216: baseOutputStream.close();
217: } catch (Exception e) {
218: throw new RuntimeException(file.getPath()
219: + " file writing has failed.", e);
220: }
221: }
222:
223: /**
224: Serializes the file to the specified stream.
225: <h3>Remarks</h3>
226: <p>It's caller responsibility to close the stream after this method ends.</p>
227: @param stream Target stream.
228: @param mode Serialization mode.
229: */
230: public void writeTo(IOutputStream stream, SerializationModeEnum mode) {
231: Writer writer = new Writer(stream, this );
232:
233: switch (mode) {
234: case Incremental:
235: if (reader != null) {
236: writer.writeIncremental();
237: break;
238: }
239: // If reader IS null, fall through to Standard!
240: case Standard:
241: writer.writeStandard();
242: break;
243: case Linearized:
244: throw new NotImplementedException();
245: }
246: }
247: // </public>
248: // </interface>
249: // </dynamic>
250: // </class>
251: }
|