KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > etymon > pjx > XrefTable


1 /*
2   Copyright (C) Etymon Systems, Inc. <http://www.etymon.com/>
3 */

4
5 package com.etymon.pjx;
6
7 import java.io.*;
8 import java.util.*;
9
10 /**
11    Represents the PDF cross-reference table and associated trailer
12    dictionary. This class is immutable.
13    @author Nassib Nassar
14 */

15 public class XrefTable {
16
17     /**
18        The array of generation values.
19      */

20     protected int[] _generation;
21     
22     /**
23        The array of index values. Each value represents either a
24            byte offset (if in-use) or the next free object number (if
25            free).
26      */

27     protected long[] _index;
28
29     /**
30        The array of sorted index values. This contains only
31        in-use entries, to be used for binary searching and
32        locating the offset of the next object in the file.
33      */

34     protected long[] _index_sorted;
35
36     /**
37        The list of startxref values associated with this
38        cross-reference table.
39      */

40     protected List _startxrefs;
41     
42     /**
43        The trailer dictionary associated with this cross-reference
44        table.
45      */

46     protected PdfDictionary _trailer;
47     
48     /**
49        The array of usage values. Each values is ENTRY_FREE,
50        ENTRY_IN_USE, or ENTRY_UNDEFINED.
51      */

52     protected byte[] _usage;
53
54     /**
55        This indicates that an entry is free.
56      */

57         public static final byte ENTRY_FREE = 1;
58         
59     /**
60        This indicates that an entry is in-use.
61      */

62         public static final byte ENTRY_IN_USE = 2;
63         
64     /**
65        This indicates that an entry is undefined.
66      */

67     public static final byte ENTRY_UNDEFINED = 0; // do not change
68

69     /**
70        A protected constructor intended to be called only from
71        {@link #wrap(long[], int[], byte[], PdfDictionary)
72        wrap(long[], int[], byte[], PdfDictionary)}.
73      */

74     protected XrefTable() {
75     }
76     
77     /**
78        Constructs a cross-reference table from a set of arrays and
79        a trailer dictionary.
80        @param index the array of index values. Each value
81            represents either a byte offset (if in-use) or the next
82            free object number (if free).
83        @param generation the array of generation values.
84        @param usage the array of usage values. Each value is
85        {@link #ENTRY_FREE ENTRY_FREE}, {@link #ENTRY_IN_USE
86        ENTRY_IN_USE}, or {@link #ENTRY_UNDEFINED ENTRY_UNDEFINED}.
87        @param trailerDictionary the trailer dictionary.
88        @throws PdfFormatException
89      */

90     public XrefTable(long[] index, int[] generation, byte[] usage,
91              PdfDictionary trailerDictionary) throws PdfFormatException {
92
93         if ( (index.length != generation.length) &&
94              (index.length != usage.length) ) {
95             throw new PdfFormatException("Xref arrays are not the same length.");
96         }
97         _index = new long[index.length];
98         _generation = new int[generation.length];
99         _usage = new byte[usage.length];
100         System.arraycopy(index, 0, _index, 0, index.length);
101         System.arraycopy(generation, 0, _generation, 0, generation.length);
102         System.arraycopy(usage, 0, _usage, 0, usage.length);
103         _startxrefs = new ArrayList();
104         createSortedIndexArray();
105         
106         _trailer = trailerDictionary;
107     }
108
109     /**
110        Returns a shallow copy of this instance.
111        @return a clone of this instance.
112      */

113     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
114         return super.clone();
115     }
116
117     protected void createSortedIndexArray() {
118
119         // determine number of entries that are in use
120
int size = 0;
121         for (int x = 0; x < _usage.length; x++) {
122             if (_usage[x] == ENTRY_IN_USE) {
123                 size++;
124             }
125         }
126
127         _index_sorted = new long[size + _startxrefs.size()];
128         int y = 0;
129         // add index values
130
for (int x = 0; x < _usage.length; x++) {
131             if (_usage[x] == ENTRY_IN_USE) {
132                 _index_sorted[y++] = _index[x];
133             }
134         }
135         // add startxref values
136
for (Iterator p = _startxrefs.iterator(); p.hasNext(); ) {
137             _index_sorted[y++] = ((Long JavaDoc)p.next()).longValue();
138         }
139         
140         Arrays.sort(_index_sorted);
141         
142     }
143
144     /**
145        Returns an offset estimated to be relatively close to the
146        end of the object (specified by object number). The offset
147        will be no earlier than the end of the object.
148        @param n the specified object number.
149        @return the index value, or -1 if the specified object
150        number corresponds to the last object in the document. If
151        the object number does not correspond to an in-use entry,
152        then -1 is returned.
153      */

154     public long estimateObjectEnd(int n) {
155
156         if (_usage[n] != ENTRY_IN_USE) {
157             return -1;
158         }
159
160         long start = _index[n];
161         
162         int x = Arrays.binarySearch(_index_sorted, start);
163
164         while ( (x < _index_sorted.length) && (_index_sorted[x] == start) ) {
165             x++;
166         }
167         
168         if (x < _index_sorted.length) {
169             return _index_sorted[x];
170         } else {
171             return -1;
172         }
173         
174     }
175     
176     /**
177        Returns the generation value for a specified object.
178        @param n the object number.
179        @return the generation value.
180      */

181     public int getGeneration(int n) {
182         return _generation[n];
183     }
184
185     /**
186        Returns the array of generation values. The calling method
187        must not modify this array unless it guarantees that this
188        object exists in no other thread, in order to comply with
189        the immutability requirement of this class.
190        @return the array of generation values.
191      */

192     public int[] getGenerationArray() {
193         int[] a = new int[_generation.length];
194         System.arraycopy(_generation, 0, a, 0, _generation.length);
195         return a;
196     }
197
198     /**
199        Returns the index value for a specified object.
200        @param n the object number.
201        @return the index value.
202      */

203     public long getIndex(int n) {
204         return _index[n];
205     }
206
207     /**
208        Returns the array of index values. The calling method must
209        not modify this array unless it guarantees that this object
210        exists in no other thread, in order to comply with the
211        immutability requirement of this class.
212        @return the array of index values.
213      */

214     public long[] getIndexArray() {
215         long[] a = new long[_index.length];
216         System.arraycopy(_index, 0, a, 0, _index.length);
217         return a;
218     }
219
220     /**
221        Returns the list of startxref values associated with this
222        cross-reference table. The calling method must not modify
223        this list unless it guarantees that this object exists in
224        no other thread, in order to comply with the immutability
225        requirement of this class.
226        @return the list of startxref values (as
227            <code>Long</code> objects.
228     */

229     protected List getStartxrefList() {
230         return _startxrefs;
231     }
232
233     /**
234        Returns the trailer dictionary associated with this
235        cross-reference table.
236        @return the trailer dictionary.
237     */

238     public PdfDictionary getTrailerDictionary() {
239         return _trailer;
240     }
241
242     /**
243        Returns the usage value for a specified object.
244        @param n the object number.
245        @return the usage value.
246      */

247     public byte getUsage(int n) {
248         return _usage[n];
249     }
250
251     /**
252        Returns the array of usage values. The calling method must
253        not modify this array unless it guarantees that this object
254        exists in no other thread, in order to comply with the
255        immutability requirement of this class.
256        @return the array of usage values.
257      */

258     public byte[] getUsageArray() {
259         byte[] a = new byte[_usage.length];
260         System.arraycopy(_usage, 0, a, 0, _usage.length);
261         return a;
262     }
263
264     /**
265        Returns the number of entries in this cross-reference
266        table.
267        @return the number of entries.
268      */

269     public int size() {
270         return _usage.length;
271     }
272     
273     /**
274        Returns the cross-reference table, associated trailer
275        dictionary, and a complete PDF trailer as a string in PDF
276        format.
277        @return the PDF string.
278      */

279     public String JavaDoc toString() {
280         ByteArrayOutputStream baos = new ByteArrayOutputStream();
281         try {
282             PdfWriter w = new PdfWriter(baos);
283             writePdf(w, 0);
284             w.close();
285             baos.close();
286         }
287         catch (IOException e) {
288             return null;
289         }
290         return baos.toString();
291     }
292
293     /**
294        Returns the array of generation values. The calling method
295        must ensure that the array is never externally modified, in
296        order to meet the immutability requirement of this class.
297        @return the array of generation values.
298      */

299     protected int[] unwrapGenerationArray() {
300         return _generation;
301     }
302
303     /**
304        Returns the array of index values. The calling method must
305        ensure that the array is never externally modified, in
306        order to meet the immutability requirement of this class.
307        @return the array of index values.
308      */

309     protected long[] unwrapIndexArray() {
310         return _index;
311     }
312
313     /**
314        Returns the array of usage values. The calling method must
315        ensure that the array is never externally modified, in
316        order to meet the immutability requirement of this class.
317        @return the array of usage values.
318     */

319     protected byte[] unwrapUsageArray() {
320         return _usage;
321     }
322     
323     /**
324        A factory for fast construction of this class. The
325        constructed object will be a wrapper around the specified
326        objects. The calling method must ensure that the arrays
327        are never externally modified, in order to meet the
328        immutability requirement of this class. It must also
329        ensure that all three arrays have the same length. It is
330        also the calling method's responsibility to call {@link
331        #createSortedIndexArray() createSortedIndexArray()} before
332        the instance will be used.
333        @param index the array of index values.
334        @param generation the array of generation values.
335        @param usage the array of usage values.
336        @param trailerDictionary the trailer dictionary.
337        @return the constructed object.
338      */

339     protected static XrefTable wrap(long[] index, int[] generation, byte[] usage, PdfDictionary trailerDictionary) {
340         XrefTable xt = new XrefTable();
341         xt._index = index;
342         xt._generation = generation;
343         xt._usage = usage;
344         xt._trailer = trailerDictionary;
345         xt._startxrefs = new ArrayList();
346         return xt;
347     }
348     
349     /**
350        Writes the cross-reference table, associated trailer
351        dictionary, and a complete PDF trailer in PDF format.
352        Before writing the cross-reference table, the free entries
353        are combined into a linked list as required by the PDF
354        specification.
355        @param w the <code>PdfWriter</code> to write to.
356        @param startxref the byte offset within the output file
357        where the cross-reference table begins.
358        @return the number of bytes written by this method.
359        @throws IOException
360      */

361     protected int writePdf(PdfWriter w, long startxref) throws IOException {
362
363         xrefGenerateFreeList();
364         
365         DataOutputStream dos = w.getDataOutputStream();
366         
367         String JavaDoc s, t;
368         
369         dos.writeBytes("xref\n");
370         int count = 5;
371         
372         int x, xx;
373         x = 0;
374         while (x < size()) {
375             
376             if (_usage[x] != ENTRY_UNDEFINED) {
377                 
378                 xx = x + 1;
379                 while ( (xx < size()) && (_usage[xx] != ENTRY_UNDEFINED) ) {
380                     xx++;
381                 }
382                 
383                 s = Integer.toString(x);
384                 dos.writeBytes(s);
385                 dos.write(' ');
386                 t = Integer.toString(xx - x);
387                 dos.writeBytes(t);
388                 dos.write('\n');
389                 count += s.length() + t.length() + 2;
390                 
391                 while (x < xx) {
392                     // write index
393
s = Long.toString(_index[x]);
394                     int y = s.length();
395                     for (int z = y; z < 10; z++) {
396                         dos.write('0');
397                     }
398                     dos.writeBytes(s);
399                     dos.write(' ');
400                     // write generation
401
s = Integer.toString(_generation[x]);
402                     y = s.length();
403                     for (int z = y; z < 5; z++) {
404                         dos.write('0');
405                     }
406                     dos.writeBytes(s);
407                     dos.write(' ');
408                     if (_usage[x] == ENTRY_IN_USE) {
409                         dos.write('n');
410                     } else {
411                         dos.write('f');
412                     }
413                     dos.writeBytes(" \n");
414                     count += 20;
415                     x++;
416                 }
417             }
418             x++;
419         }
420         
421         dos.writeBytes("trailer\n");
422         count += 8;
423
424         count += _trailer.writePdf(w, false);
425         
426         s = "\nstartxref\n" + Long.toString(startxref) + "\n%%EOF\n";
427         dos.writeBytes(s);
428         return count + s.length();
429     }
430
431     /**
432        Combines the free elements of this cross-reference table
433        into a linked list as required by the PDF specification.
434      */

435     protected void xrefGenerateFreeList() {
436         int lastFree = 0;
437         long[] index = _index;
438         byte[] usage = _usage;
439         for (int x = usage.length - 1; x >= 0; x--) {
440             if (usage[x] == ENTRY_FREE) {
441                 index[x] = lastFree;
442                 lastFree = x;
443             }
444         }
445     }
446     
447 }
448
Popular Tags