KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > it > stefanochizzolini > clown > files > IndirectObjects


1 /*
2   Copyright © 2006 Stefano Chizzolini. http://clown.stefanochizzolini.it
3
4   Contributors:
5     * Stefano Chizzolini (original code developer, info@stefanochizzolini.it):
6       contributed code is Copyright © 2006 by Stefano Chizzolini.
7
8   This file should be part of the source code distribution of "PDF Clown library"
9   (the Program): see the accompanying README files for more info.
10
11   This Program is free software; you can redistribute it and/or modify it under
12   the terms of the GNU General Public License as published by the Free Software
13   Foundation; either version 2 of the License, or (at your option) any later version.
14
15   This Program is distributed in the hope that it will be useful, but WITHOUT ANY
16   WARRANTY, either expressed or implied; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
18
19   You should have received a copy of the GNU General Public License along with this
20   Program (see README files); if not, go to the GNU website (http://www.gnu.org/).
21
22   Redistribution and use, with or without modification, are permitted provided that such
23   redistributions retain the above copyright notice, license and disclaimer, along with
24   this list of conditions.
25 */

26
27 package it.stefanochizzolini.clown.files;
28
29 import it.stefanochizzolini.clown.objects.PdfDataObject;
30 import it.stefanochizzolini.clown.objects.PdfIndirectObject;
31 import it.stefanochizzolini.clown.tokens.XRefEntry;
32 import it.stefanochizzolini.clown.tokens.XRefEntryUsageEnum;
33 import it.stefanochizzolini.clown.util.NotImplementedException;
34
35 import java.util.ArrayList JavaDoc;
36 import java.util.Collection JavaDoc;
37 import java.util.Hashtable JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.ListIterator JavaDoc;
41 import java.util.NoSuchElementException JavaDoc;
42 import java.util.TreeMap JavaDoc;
43
44 /**
45   Collection of the <b>alive indirect objects</b> available inside the file.
46   <h3>Remarks</h3>
47   <p>According to the PDF spec, <i>indirect object entries may be free
48   (no data object associated) or in-use (data object associated)</i>.</p>
49   <p>We can effectively subdivide indirect objects in two possibly-overriding
50   collections: the <b>original indirect objects</b> (coming from the associated
51   preexisting file) and the <b>newly-registered indirect objects</b> (coming
52   from new data objects or original indirect objects manipulated during the
53   current session).</p>
54   <p><i>To ensure that the modifications applied to an original indirect object
55   are committed to being persistent</i> is critical that the modified original
56   indirect object is newly-registered (practically overriding the original
57   indirect object).</p>
58   <p><b>Alive indirect objects</b> encompass all the newly-registered ones plus
59   not-overridden original ones.</p>
60 */

61 public class IndirectObjects
62   implements List JavaDoc<PdfIndirectObject>
63 {
64   // <class>
65
// <dynamic>
66
// <fields>
67
/**
68     Associated file.
69   */

70   private File file;
71
72   /**
73     Map of matching references of imported indirect objects.
74     <h3>Remarks</h3>
75     <p>This collection is used to prevent duplications among imported indirect
76     objects.</p>
77     <p><code>Key</code> is the external indirect object hashcode, <code>Value</code> is the
78     matching internal indirect object.</p>
79   */

80   private Hashtable JavaDoc<Integer JavaDoc,PdfIndirectObject> importedObjects = new Hashtable JavaDoc<Integer JavaDoc,PdfIndirectObject>();
81   /**
82     Collection of newly-registered indirect objects.
83   */

84   private TreeMap JavaDoc<Integer JavaDoc,PdfIndirectObject> modifiedObjects = new TreeMap JavaDoc<Integer JavaDoc,PdfIndirectObject>();
85   /**
86     Collection of instantiated original indirect objects.
87     <h3>Remarks</h3>
88     <p>This collection is useful as a cache to avoid unconsistent parsing duplications.</p>
89   */

90   private TreeMap JavaDoc<Integer JavaDoc,PdfIndirectObject> wokenObjects = new TreeMap JavaDoc<Integer JavaDoc,PdfIndirectObject>();
91
92   /**
93     Object counter.
94   */

95   private int lastObjectNumber = -1; // Empty.
96
/**
97     Offsets of the original indirect objects inside the associated file (to say:
98     implicit collection of the original indirect objects).
99     <h3>Remarks
100     <p>This information is vital to randomly retrieve the indirect-object persistent
101     representation inside the associated file.</p>
102   */

103   private XRefEntry[] xrefEntries;
104
105   private UpdateModeEnum updateMode = UpdateModeEnum.Manual;
106   // </fields>
107

108   // <constructors>
109
IndirectObjects(
110     File file,
111     XRefEntry[] xrefEntries
112     )
113   {
114     this.file = file;
115     this.xrefEntries = xrefEntries;
116     // Are there original indirect objects?
117
if(this.xrefEntries == null)
118     {
119       /*
120       [PDF:1.6:3.4.3] Mandatory head of the linked list of free objects
121       at object number 0.
122       */

123       // Register the leading free-object!
124
lastObjectNumber++;
125       modifiedObjects.put(
126         lastObjectNumber,
127         new PdfIndirectObject(
128           this.file,
129           null,
130           new XRefEntry(
131             lastObjectNumber,
132             65535,
133             0,
134             XRefEntryUsageEnum.Free
135             )
136           )
137         );
138     }
139     else
140     {
141       // Adjust the object counter!
142
lastObjectNumber = xrefEntries.length - 1;
143     }
144   }
145   // </constructors>
146

147   // <interface>
148
// <public>
149
public File getFile(
150     )
151   {return file;}
152
153   /**
154     Register an <b>internal data object</b>.
155     <h3>Remarks</h3>
156     <p>Alternatives:<ul>
157     <li>To register a modified internal indirect object, use
158     {@link #set(int,PdfIndirectObject) set(int,PdfIndirectObject)}.</li>
159     <li>To register an external indirect object, use
160     {@link #addExternal(PdfIndirectObject) addExternal(PdfIndirectObject)}.</li>
161     </ul></p>
162   */

163   public PdfIndirectObject add(
164     PdfDataObject object
165     )
166   {
167     // Wrap the data object inside a new indirect object!
168
lastObjectNumber++;
169     PdfIndirectObject indirectObject = new PdfIndirectObject(
170       file,
171       object,
172       new XRefEntry(
173         lastObjectNumber,
174         0,
175         0,
176         XRefEntryUsageEnum.InUse
177         )
178       );
179     // Register the object!
180
modifiedObjects.put(lastObjectNumber,indirectObject);
181
182     return indirectObject;
183   }
184
185   /**
186     Registers and gets an <b>external indirect object</b>.
187     <h3>Remarks</h3>
188     <p>External indirect objects come from alien PDF files. <i>This is a powerful
189     way to import the content of one file into another</i>.</p>
190     <p>Alternatives:<ul>
191     <li>To register a modified internal indirect object, use
192     {@link #set(int,PdfIndirectObject) set(int,PdfIndirectObject)}.</li>
193     <li>To register an internal data object, use
194     {@link #add(PdfDataObject) add(PdfDataObject)}.</li></ul></p>
195   */

196   public PdfIndirectObject addExternal(
197     PdfIndirectObject object
198     )
199   {
200     PdfIndirectObject indirectObject = importedObjects.get(object.hashCode());
201     // Hasn't the external indirect object been imported yet?
202
if(indirectObject == null)
203     {
204       // Register the clone of the data object corresponding to the external indirect object!
205
indirectObject = add((PdfDataObject)object.getDataObject().clone(file));
206       // Keep track of the imported indirect object!
207
importedObjects.put(object.hashCode(),indirectObject);
208     }
209
210     return indirectObject;
211   }
212
213   public Collection JavaDoc<? extends PdfIndirectObject> addAllExternal(
214     Collection JavaDoc<? extends PdfIndirectObject> objects
215     )
216   {
217     ArrayList JavaDoc<PdfIndirectObject> addedObjects = new ArrayList JavaDoc<PdfIndirectObject>(objects.size());
218     for(PdfIndirectObject object : objects)
219     {addedObjects.add((PdfIndirectObject)addExternal(object));}
220
221     return addedObjects;
222   }
223
224   // <List>
225
public void add(
226     int index,
227     PdfIndirectObject object
228     )
229   {throw new UnsupportedOperationException JavaDoc();}
230
231   public boolean addAll(
232     int index,
233     Collection JavaDoc<? extends PdfIndirectObject> objects
234     )
235   {throw new UnsupportedOperationException JavaDoc();}
236
237   /**
238     Gets an indirect object with the specified object number.
239     @param index Object number of the indirect object to get.
240     @return Indirect object corresponding to the specified object number.
241   */

242   public PdfIndirectObject get(
243     int index
244     )
245   {
246     // Try among the new objects!
247
PdfIndirectObject object = modifiedObjects.get(index);
248     // Is it among the original objects?
249
if(object == null)
250     {
251       // Try among the woken original objects!
252
object = wokenObjects.get(index);
253       // Is it among the sleeping original objects?
254
if(object == null)
255       {
256         try
257         {
258           object = new PdfIndirectObject(
259             file,
260             null,
261             xrefEntries[index]
262             );
263         }
264         catch(Exception JavaDoc e)
265         {throw new RuntimeException JavaDoc(e);}
266
267         // Now it's awake!
268
/*
269         NOTE: This operation allows to keep a consistant state across the whole session,
270         avoiding multiple incoherent instantiations of the same original indirect object.
271         */

272         wokenObjects.put(index,object);
273
274         // Early registration?
275
if(updateMode == UpdateModeEnum.Automatic)
276         {update(object); /* Force early registration. */}
277       }
278     }
279
280     return object;
281   }
282
283   public int indexOf(
284     Object JavaDoc object
285     )
286   {
287     // Is this indirect object associated to this file?
288
if(((PdfIndirectObject)object).getFile() != file)
289       return -1;
290
291     return ((PdfIndirectObject)object).getReference().getObjectNumber();
292   }
293
294   public int lastIndexOf(
295     Object JavaDoc object
296     )
297   {
298     /*
299       NOTE: By definition, there's a bijective relation between indirect objects
300       and their indices.
301     */

302     return indexOf(object);
303   }
304
305   public ListIterator JavaDoc<PdfIndirectObject> listIterator(
306     )
307   {throw new NotImplementedException();}
308
309   public ListIterator JavaDoc<PdfIndirectObject> listIterator(
310     int index
311     )
312   {throw new NotImplementedException();}
313
314   public PdfIndirectObject remove(
315     int index
316     )
317   {
318     /*
319       NOTE: Acrobat 6.0 and later (PDF 1.5+) DO NOT use the free list to recycle object numbers;
320       new objects are assigned new numbers [PDF:1.6:H.3:16].
321       According to such an implementation note, we simply mark the removed object as 'not-reusable'
322       newly-freed entry (generation 65535), neglecting both to add it to the linked list of free
323       entries and to increment by 1 its generation number.
324     */

325     return update(
326       new PdfIndirectObject(
327         file,
328         null,
329         new XRefEntry(
330           index,
331           65535, // Not reusable.
332
0,
333           XRefEntryUsageEnum.Free
334           )
335         )
336       );
337   }
338
339   /**
340     Sets an indirect object with the specified object number.
341     <h3>Contract</h3>
342     <ul>
343       <li>Preconditions:
344         <ol>
345           <li><code>index</code> value MUST be between 1 and (size() - 1); index 0
346           is reserved to the mandatory head of the linked list of free objects [PDF:1.6:3.4.3].</li>
347         </ol>
348       </li>
349       <li>Postconditions:<ol><li>(none).</li></ol></li>
350       <li>Invariants:<ol><li>(none).</li></ol></li>
351       <li>Side-effects:<ol><li>(none).</li></ol></li>
352     </ul>
353     <h3>Remarks</h3>
354     <p>This method is currently limited to <b>internal indirect
355     objects</b>: <i>use it to register modified internal indirect objects only</i>.
356     If you need to register alternative-type objects, consider the following
357     methods:</p>
358     <ul>
359       <li>to register an <b>external indirect object</b>, use
360       {@link #addExternal(PdfIndirectObject) addExternal(PdfIndirectObject)}.</li>
361       <li>to register an <b>internal data object</b>, use
362       {@link #add(PdfDataObject) add(PdfDataObject)}.</li>
363     </ul>
364     @param index Object number of the indirect object to set.
365     @param object Indirect object to set.
366     @return Replaced indirect object.
367   */

368   public PdfIndirectObject set(
369     int index,
370     PdfIndirectObject object
371     )
372   {throw new UnsupportedOperationException JavaDoc();}
373
374   public List JavaDoc<PdfIndirectObject> subList(
375     int fromIndex,
376     int toIndex
377     )
378   {throw new NotImplementedException();}
379
380   // <Collection>
381
/**
382     Registers an <b>external indirect object</b>.
383     <h3>Remarks</h3>
384     <p>External indirect objects come from alien PDF files. <i>This is a powerful
385     way to import the content of one file into another</i>.</p>
386     <p>Alternatives:<ul>
387     <li>To register and get an external indirect object, use
388     {@link #addExternal(PdfIndirectObject) addExternal(PdfIndirectObject)}.</li>
389     </ul></p>
390   */

391   public boolean add(
392     PdfIndirectObject object
393     )
394   {
395     boolean changed = (addExternal(object) != null);
396
397     return changed;
398   }
399
400   /**
401     Registers <b>external indirect objects</b>.
402     <h3>Remarks</h3>
403     <p>External indirect objects come from alien PDF files. <i>This is a powerful
404     way to import the content of one file into another</i>.</p>
405     <p>Alternatives:<ul>
406     <li>To register and get external indirect object, use
407     {@link #addAllExternal(PdfIndirectObject) addAllExternal(Collection<? extends PdfIndirectObject>)}.</li>
408     </ul></p>
409   */

410   public boolean addAll(
411     Collection JavaDoc<? extends PdfIndirectObject> objects
412     )
413   {
414     boolean changed = false;
415     for(PdfIndirectObject object : objects)
416     {
417       changed |= (addExternal(object) != null);
418     }
419
420     return changed;
421   }
422
423   public void clear(
424     )
425   {throw new UnsupportedOperationException JavaDoc();}
426
427   public boolean contains(
428     Object JavaDoc object
429     )
430   {throw new NotImplementedException();}
431
432   public boolean containsAll(
433     Collection JavaDoc<?> objects
434     )
435   {throw new NotImplementedException();}
436
437   public boolean equals(
438     Object JavaDoc object
439     )
440   {throw new NotImplementedException();}
441
442   public int hashCode(
443     )
444   {throw new NotImplementedException();}
445
446   public boolean isEmpty(
447     )
448   {
449     /*
450     NOTE: Semantics of the indirect objects collection imply that the collection is considered
451     empty in any case no in-use object is available.
452     */

453     for(PdfIndirectObject object : this)
454     {
455       if(object.isInUse())
456         return false;
457     }
458
459     return true;
460   }
461
462   public boolean remove(
463     Object JavaDoc object
464     )
465   {throw new NotImplementedException();}
466
467   public boolean removeAll(
468     Collection JavaDoc<?> objects
469     )
470   {throw new NotImplementedException();}
471
472   public boolean retainAll(
473     Collection JavaDoc<?> objects
474     )
475   {throw new UnsupportedOperationException JavaDoc();}
476
477   /**
478     Gets the number of entries available (both in-use and free) in the
479     collection.
480     @return The number of entries available in the collection.
481   */

482   public int size(
483     )
484   {return (lastObjectNumber + 1);}
485
486   public PdfIndirectObject[] toArray(
487     )
488   {throw new NotImplementedException();}
489
490   public <PdfIndirectObject> PdfIndirectObject[] toArray(
491     PdfIndirectObject[] objects
492     )
493   {throw new NotImplementedException();}
494
495   // <Iterable>
496
public Iterator JavaDoc<PdfIndirectObject> iterator(
497     )
498   {
499     return new Iterator JavaDoc<PdfIndirectObject>()
500     {
501       // <class>
502
// <dynamic>
503
// <fields>
504
/** Index of the next item. */
505       private int index = 0;
506       // </fields>
507

508       // <interface>
509
// <public>
510
// <Iterator>
511
public boolean hasNext(
512         )
513       {return (index < size());}
514
515       public PdfIndirectObject next(
516         )
517       {
518         if(!hasNext())
519           throw new NoSuchElementException JavaDoc();
520
521         return get(index++);
522       }
523
524       public void remove(
525         )
526       {throw new UnsupportedOperationException JavaDoc();}
527       // </Iterator>
528
// </public>
529
// </interface>
530
// </dynamic>
531
// </class>
532
};
533   }
534   // </Iterable>
535
// </Collection>
536
// </List>
537
// </public>
538

539   // <internal>
540
/**
541     <h3>Remarks</h3>
542     <p>For internal use only.</p>
543   */

544   public TreeMap JavaDoc<Integer JavaDoc,PdfIndirectObject> getModifiedObjects(
545     )
546   {return modifiedObjects;}
547
548   /**
549     <h3>Remarks</h3>
550     <p>For internal use only.</p>
551   */

552   public PdfIndirectObject update(
553     PdfIndirectObject object
554     )
555   {
556     int index = object.getReference().getObjectNumber();
557
558     // Get the old indirect object to be replaced!
559
PdfIndirectObject old = get(index);
560     if(old != object)
561     {old.dropFile(); /* Disconnect the old indirect object. */}
562
563     // Insert the new indirect object into the modified objects collection!
564
modifiedObjects.put(index,object);
565     // Remove old indirect object from cache!
566
wokenObjects.remove(index);
567     // Mark the new indirect object as modified!
568
object.dropOriginal();
569
570     return old;
571   }
572   // </internal>
573
// </interface>
574
// </dynamic>
575
// </class>
576
}
Popular Tags