KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > etymon > pj > object > PjStream


1 package com.etymon.pj.object;
2
3 import java.io.*;
4 import java.util.*;
5 import java.util.zip.*;
6 import com.etymon.pj.*;
7 import com.etymon.pj.exception.*;
8
9 /**
10    A representation of the PDF stream type.
11    @author Nassib Nassar
12 */

13 public class PjStream
14     extends PjObject {
15
16     /**
17        Creates a stream as a wrapper around a byte array.
18        @param s the byte array to use for this stream.
19     */

20     public PjStream(byte[] s) {
21         _d = new PjStreamDictionary();
22         _s = s;
23     }
24
25     /**
26        Creates a stream as a wrapper around a PjStreamDictionary and
27        byte array.
28        @param d the dictionary to use for this stream.
29        @param s the byte array to use for this stream.
30     */

31     public PjStream(PjStreamDictionary d, byte[] s) {
32         _d = d;
33         _s = s;
34     }
35
36     /**
37        Returns the PjStreamDictionary used in the representation of this
38        stream.
39        @return the PjStreamDictionary used in the representation of this
40        stream.
41     */

42     public PjStreamDictionary getStreamDictionary() {
43         return _d;
44     }
45     
46     /**
47        Returns the byte array used in the representation of this
48        stream.
49        @return the byte array used in the representation of this
50        stream.
51     */

52     public byte[] getBuffer() {
53         return _s;
54     }
55
56     /**
57        Decompresses this stream if it is compressed with the Flate
58        algorithm.
59        @return a cloned, uncompressed version of this stream; or
60        this stream if it is not marked as being compressed with
61        Flate.
62        @exception InvalidPdfObjectException if an invalid object
63        type is encountered.
64     */

65     public PjStream flateDecompress() throws InvalidPdfObjectException {
66         // first check if the FlateDecode filter is turned on;
67
// if not, return this (we don't need to decompress).
68
// if so, turn off the filter in the new dictionary
69
Hashtable ht = _d.getHashtable();
70         Object JavaDoc obj = ht.get(PjName.FILTER);
71         if (obj == null) {
72             return this;
73         }
74         if ( (obj instanceof PjName) || (obj instanceof PjArray) ) {
75             PjStreamDictionary newPjd = null;
76             Hashtable newHt;
77             if (obj instanceof PjName) {
78                 PjName pjn = (PjName)obj;
79                 if ( ! pjn.equals(PjName.FLATEDECODE) ) {
80                     return this;
81                 } else {
82                     // remove the element from the cloned dictionary
83
try {
84                         newPjd = (PjStreamDictionary)(_d.clone());
85                     }
86                     catch (CloneNotSupportedException JavaDoc e) {
87                         throw new InvalidPdfObjectException(e.getMessage());
88                     }
89                     newHt = newPjd.getHashtable();
90                     newHt.remove(PjName.FILTER);
91                 }
92             }
93             else if (obj instanceof PjArray) {
94                 PjArray pja = (PjArray)obj;
95                 Vector v = pja.getVector();
96                 int x;
97                 if ( (x = v.indexOf(PjName.FLATEDECODE)) == -1) {
98                     return this;
99                 } else {
100                     // remove the element from the cloned dictionary
101
try {
102                         newPjd = (PjStreamDictionary)(_d.clone());
103                     }
104                     catch (CloneNotSupportedException JavaDoc e) {
105                         throw new InvalidPdfObjectException(e.getMessage());
106                     }
107                     newHt = newPjd.getHashtable();
108                     pja = (PjArray)(newHt.get(PjName.FILTER));
109                     v = pja.getVector();
110                     v.removeElementAt(x);
111                 }
112             }
113             // do the decompression
114
InflaterInputStream in = new InflaterInputStream(new ByteArrayInputStream(_s));
115             ByteArrayOutputStream out = new ByteArrayOutputStream();
116             int length;
117             byte[] buffer = new byte[PjConst.FLATE_BUFFER_SIZE];
118             try {
119                 while ((length = in.read(buffer, 0, buffer.length)) != -1) {
120                     out.write(buffer, 0, length);
121                 }
122                 out.close();
123                 in.close();
124             }
125             catch (IOException e) {
126                 // not sure what would cause this exception in this case
127
return this;
128             }
129             return new PjStream(newPjd, out.toByteArray());
130         } else {
131             throw new InvalidPdfObjectException("Stream filter is not a name or array.");
132         }
133     }
134
135     /**
136        Compress this stream with the Flate algorithm if it is not
137        already compressed.
138        @return a cloned, compressed version of this stream; or
139        this stream if it is already compressed.
140        @exception InvalidPdfObjectException if an invalid object
141        type is encountered.
142     */

143     public PjStream flateCompress() throws InvalidPdfObjectException {
144         // first check if any compression filters are turned on;
145
// if so, return this (we don't need to compress).
146
// if not, turn on the FlateDecode filter in the new dictionary
147
Hashtable ht = _d.getHashtable();
148         Object JavaDoc filter = ht.get(PjName.FILTER);
149         if (filter != null) {
150             if ( ( ! (filter instanceof PjName) ) && ( ! (filter instanceof PjArray) ) ) {
151                 throw new InvalidPdfObjectException("Stream filter is not a name or array.");
152             }
153             // get or create a vector with the list of filters
154
Vector v = null;
155             if (filter instanceof PjName) {
156                 v = new Vector();
157                 v.addElement(filter);
158             }
159             else if (filter instanceof PjArray) {
160                 v = ((PjArray)filter).getVector();
161             }
162             // see if any of the filters are compression filters
163
PjName name;
164             Enumeration m = v.elements();
165             Object JavaDoc obj;
166             while (m.hasMoreElements()) {
167                 obj = m.nextElement();
168                 if ( ! (obj instanceof PjName) ) {
169                     throw new InvalidPdfObjectException(
170                         "Stream filter array contins an object that is not a name.");
171                 }
172                 name = (PjName)obj;
173                 if ( (name.equals(PjName.LZWDECODE)) ||
174                      (name.equals(PjName.RUNLENGTHDECODE)) ||
175                      (name.equals(PjName.CCITTFAXDECODE)) ||
176                      (name.equals(PjName.DCTDECODE)) ||
177                      (name.equals(PjName.FLATEDECODE)) ) {
178                     return this;
179                 }
180             }
181         }
182         // ok, clone the dictionary and add the FlateDecode filter
183
PjStreamDictionary newPjd;
184         try {
185             newPjd = (PjStreamDictionary)(_d.clone());
186         }
187         catch (CloneNotSupportedException JavaDoc e) {
188             throw new InvalidPdfObjectException(e.getMessage());
189         }
190         Hashtable newHt = newPjd.getHashtable();
191         if (filter == null) {
192             newHt.put(PjName.FILTER, PjName.FLATEDECODE);
193         } else {
194             if (filter instanceof PjArray) {
195                 Vector v = ((PjArray)filter).getVector();
196                 v.addElement(PjName.FLATEDECODE);
197             } else {
198                 // filter must be a name, so make it into an array
199
Vector v = new Vector();
200                 v.addElement(filter);
201                 v.addElement(PjName.FLATEDECODE);
202                 newHt.put(PjName.FILTER, new PjArray(v));
203             }
204         }
205         // do the compression
206
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
207         DeflaterOutputStream out = new DeflaterOutputStream(byteArrayOut);
208         ByteArrayInputStream in = new ByteArrayInputStream(_s);
209         int length;
210         byte[] buffer = new byte[PjConst.FLATE_BUFFER_SIZE];
211         try {
212             while ((length = in.read(buffer, 0, buffer.length)) != -1) {
213                 out.write(buffer, 0, length);
214             }
215             out.close();
216             in.close();
217         }
218         catch (IOException e) {
219             // not sure what would cause this exception in this case
220
return this;
221         }
222         return new PjStream(newPjd, byteArrayOut.toByteArray());
223     }
224     
225     /**
226        Sets the Length field in the stream dictionary to
227        accurately reflect the length of the stream. It is not
228        normally necessary to call this method, because it gets
229        called implicitly by methods that output the object in PDF
230        format.
231     */

232     public void setLength() {
233         _d.getHashtable().put(new PjName("Length"),
234                       new PjNumber(_s.length));
235     }
236
237     /**
238        Writes this PDF stream to a stream in PDF format.
239        @param os the stream to write to.
240        @return the number of bytes written.
241        @exception IOException if an I/O error occurs.
242     */

243     public long writePdf(OutputStream os) throws IOException {
244         setLength();
245         long z = _d.writePdf(os);
246         z = z + writeln(os, "");
247         z = z + write(os, "stream\n");
248         z = z + write(os, _s);
249         z = z + write(os, "endstream");
250         return z;
251     }
252
253     /**
254        Returns a deep copy of this object.
255        @return a deep copy of this object.
256        @exception CloneNotSupportedException if the instance can not be cloned.
257     */

258     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
259         return new PjStream((PjStreamDictionary)(_d.clone()), (byte[])(_s.clone()));
260     }
261     
262     /**
263        Renumbers object references within this object. This
264        method calls itself recursively to comprehensively renumber
265        all objects contained within this object.
266        @param map the table of object number mappings. Each
267        object number is looked up by key in the hash table, and
268        the associated value is assigned as the new object number.
269        The map hash table should consist of PjNumber keys and
270        PjReference values.
271     */

272     public void renumber(Hashtable map) {
273         _d.renumber(map);
274     }
275
276     /**
277        Decode this stream if it is compressed with the Ascii85
278        algorithm.
279        @return a cloned, unencoded version of this stream; or
280        this stream if it is not marked as being compressed with
281        Ascii85.
282        @exception InvalidPdfObjectException if an invalid object
283        type is encountered.
284     */

285     public PjStream ascii85Decode() throws InvalidPdfObjectException {
286         // first check if the Ascii85Decode filter is turned on;
287
// if not, return this (we don't need to decompress).
288
// if so, turn off the filter in the new dictionary
289
Hashtable ht = _d.getHashtable();
290         Object JavaDoc obj = ht.get(PjName.FILTER);
291         if (obj == null) {
292             return this;
293         }
294         if ( (obj instanceof PjName) || (obj instanceof PjArray) ) {
295             PjStreamDictionary newPjd = null;
296             Hashtable newHt;
297             if (obj instanceof PjName) {
298                 PjName pjn = (PjName)obj;
299                 if ( ! pjn.equals(PjName.ASCII85DECODE) ) {
300                     return this;
301                 } else {
302                     // remove the element from the cloned dictionary
303
try {
304                         newPjd = (PjStreamDictionary)(_d.clone());
305                     }
306                     catch (CloneNotSupportedException JavaDoc e) {
307                         throw new InvalidPdfObjectException(e.getMessage());
308                     }
309                     newHt = newPjd.getHashtable();
310                     newHt.remove(PjName.FILTER);
311                 }
312             }
313             else if (obj instanceof PjArray) {
314                 PjArray pja = (PjArray)obj;
315                 Vector v = pja.getVector();
316                 int x;
317                 if ( (x=v.indexOf(PjName.ASCII85DECODE))==-1) {
318                     return this;
319                 } else {
320                     // remove the element from the cloned dictionary
321
try {
322                         newPjd = (PjStreamDictionary)(_d.clone());
323                     }
324                     catch (CloneNotSupportedException JavaDoc e) {
325                         throw new InvalidPdfObjectException(e.getMessage());
326                     }
327                     newHt = newPjd.getHashtable();
328                     pja = (PjArray)(newHt.get(PjName.FILTER));
329                     v = pja.getVector();
330                     v.removeElementAt(x);
331                 }
332             }
333             // do the decoding
334
// the raw data resides in _s.
335
byte [] decodedBuf = ascii85Decode(_s);
336             if(decodedBuf == null)
337                 return this;
338             return new PjStream(newPjd, decodedBuf);
339         } else {
340             throw new InvalidPdfObjectException("Stream filter is not a name or array.");
341         }
342     }
343
344     protected PjStreamDictionary _d;
345     protected byte[] _s;
346     
347     static long bytesToLong(byte [] b, int offset, int len) {
348         long val = 0, exp = 0;
349         for(int i=offset+len-1;i >= offset;i--) {
350             for(int j=7;j >= 0;j--) {
351                 byte mask = (byte)(128 >> j);
352                 if((b[i] & mask) == mask) {
353                     val += Math.pow(2, exp);
354                 }
355                 exp++;
356             }
357         }
358         return val;
359     }
360
361     static char [] ascii85EncodeWord(long word) {
362         long v1, v2, v3, v4, v5;
363         long p4 = (long)Math.pow(85,4);
364         long p3 = (long)Math.pow(85,3);
365         long p2 = (long)Math.pow(85,2);
366         v1 = word/p4;
367         word = word - (v1*p4);
368         v2 = word/p3;
369         word = word - (v2*p3);
370         v3 = word/p2;
371         word = word - (v3*p2);
372         v4 = word/85;
373         word = word - (v4*85);
374         v5 = word;
375         char [] c = new char[5];
376         c[0] = (char)(v1 + '!');
377         c[1] = (char)(v2 + '!');
378         c[2] = (char)(v3 + '!');
379         c[3] = (char)(v4 + '!');
380         c[4] = (char)(v5 + '!');
381
382         return c;
383     }
384
385     public static byte[] ascii85Encode(byte [] src) {
386         ByteArrayOutputStream out = new ByteArrayOutputStream();
387         try {
388             int groupCount = src.length/4;
389             int extraCount = src.length%4;
390             int i;
391             for(i=0;i<groupCount;i++) {
392                 long word = bytesToLong(src, i*4, 4);
393                 if(word == 0) {
394                     out.write('z');
395                     continue;
396                 }
397                 char [] c = ascii85EncodeWord(word);
398                 out.write(c[0]);
399                 out.write(c[1]);
400                 out.write(c[2]);
401                 out.write(c[3]);
402                 out.write(c[4]);
403             }
404             if(extraCount > 0) {
405                 byte [] buf = new byte[4];
406                 if(extraCount == 1) {
407                     buf[3] = src[i*4];
408                     buf[2] = 0;
409                     buf[1] = 0;
410                     buf[0] = 0;
411                 } else if(extraCount ==2 ) {
412                     buf[3] = src[i*4+1];
413                     buf[2] = src[i*4];
414                     buf[1] = 0;
415                     buf[0] = 0;
416                 } else {
417                     buf[3] = src[i*4+2];
418                     buf[2] = src[i*4+1];
419                     buf[1] = src[i*4];
420                     buf[0] = 0;
421                 }
422                 long word = bytesToLong(buf, 0, 4);
423                 char [] c = ascii85EncodeWord(word);
424                 for(i=5-(extraCount+1);i<5;i++) {
425                     out.write(c[i]);
426                 }
427             }
428             out.write('~');
429             out.write('>');
430             out.close();
431         } catch(IOException e) {
432             System.out.println(e);
433         }
434         return out.toByteArray();
435     }
436
437     static long toWord(byte [] b, int offset, int sigDigits) {
438         long v1, v2, v3, v4, v5;
439         long p4 = (long)Math.pow(85,4);
440         long p3 = (long)Math.pow(85,3);
441         long p2 = (long)Math.pow(85,2);
442         v1 = (b[offset]-'!') * p4;
443         v2 = (b[offset+1]-'!') * p3;
444         v3 = (b[offset+2]-'!') * p2;
445         v4 = (b[offset+3]-'!') * 85;
446         v5 = (b[offset+4]-'!');
447         if(sigDigits == 5)
448             return v1 + v2 + v3 + v4 + v5;
449         else if (sigDigits == 4)
450             return v2 + v3 + v4 + v5;
451         else if (sigDigits == 3)
452             return v3 + v4 + v5;
453         else if (sigDigits == 2)
454             return v4 + v5;
455         else return v5;
456     }
457
458     public static byte[] ascii85Decode(byte [] src) {
459         ByteArrayOutputStream out = new ByteArrayOutputStream();
460         try {
461             int ptr = 0;
462             int len = src.length - 2; // ignore end of
463
// data marker
464

465             for(;;) {
466                 if(((len - ptr) < 5)&&(src[ptr] != 'z')) {
467                     break;
468                 }
469                 long word = 0;
470                 if(src[ptr] == 'z') {
471                     ptr++;
472                 } else {
473                     word = toWord(src, ptr, 5);
474                     ptr+=5;
475                 }
476                 byte b4 = (byte)(word & 255);
477                 byte b3 = (byte)((word>>>8) & 255);
478                 byte b2 = (byte)((word>>>16) & 255);
479                 byte b1 = (byte)((word>>>24) & 255);
480                 out.write(b1);
481                 out.write(b2);
482                 out.write(b3);
483                 out.write(b4);
484             }
485             if((len-ptr) > 0) {
486                 // We have extra bytes
487
int count = len-ptr;
488                 // The acutal number of binary bytes is 1 less
489
// than count
490
byte [] buf = new byte[5];
491
492                 int pad = 5-count;
493                 int j = 0;
494                 for(int i=0;i<5;i++) {
495                     if(i<pad) {
496                         buf[j++] = 0;
497                     } else {
498                         buf[j++] = src[ptr];
499                         ptr++;
500                     }
501                 }
502                 long word = toWord(buf, 0, count);
503                 byte b4 = (byte)(word & 255);
504                 byte b3 = (byte)((word>>>8) & 255);
505                 byte b2 = (byte)((word>>>16) & 255);
506                 byte b1 = (byte)((word>>>24) & 255);
507                 count -= 1;
508                 if(count == 1) {
509                     out.write(b4);
510                 } else if(count == 2) {
511                     out.write(b3);
512                     out.write(b4);
513                 } else if(count == 3) {
514                     out.write(b2);
515                     out.write(b3);
516                     out.write(b4);
517                 }
518             }
519             out.close();
520         } catch(IOException e) {
521             System.out.println(e);
522         }
523         return out.toByteArray();
524     }
525 }
526
Popular Tags