KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > zlib > ZlibModule


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Charles Reich
28  */

29
30 package com.caucho.quercus.lib.zlib;
31
32 import com.caucho.quercus.QuercusModuleException;
33 import com.caucho.quercus.annotation.NotNull;
34 import com.caucho.quercus.annotation.Optional;
35 import com.caucho.quercus.annotation.ReturnNullAsFalse;
36 import com.caucho.quercus.env.*;
37 import com.caucho.quercus.lib.file.BinaryInput;
38 import com.caucho.quercus.lib.file.BinaryOutput;
39 import com.caucho.quercus.lib.file.BinaryStream;
40 import com.caucho.quercus.lib.file.FileModule;
41 import com.caucho.quercus.module.AbstractQuercusModule;
42 import com.caucho.util.L10N;
43 import com.caucho.vfs.StreamImplOutputStream;
44 import com.caucho.vfs.TempBuffer;
45 import com.caucho.vfs.TempStream;
46 import com.caucho.vfs.WriteStream;
47
48 import java.io.IOException JavaDoc;
49 import java.io.InputStream JavaDoc;
50 import java.util.logging.Level JavaDoc;
51 import java.util.logging.Logger JavaDoc;
52 import java.util.zip.Adler32 JavaDoc;
53 import java.util.zip.Deflater JavaDoc;
54 import java.util.zip.Inflater JavaDoc;
55 import java.util.zip.InflaterInputStream JavaDoc;
56
57 /**
58  * PHP Zlib
59  */

60 public class ZlibModule extends AbstractQuercusModule {
61   private static final Logger JavaDoc log
62     = Logger.getLogger(ZlibModule.class.getName());
63   private static final L10N L = new L10N(ZlibModule.class);
64
65   public static final int FORCE_GZIP = 0x1;
66   public static final int FORCE_DEFLATE = 0x2;
67
68   public String JavaDoc []getLoadedExtensions()
69   {
70     return new String JavaDoc[] { "zlib" };
71   }
72
73   /**
74    *
75    * @param env
76    * @param fileName
77    * @param mode
78    * @param useIncludePath always on
79    * @return Zlib
80    */

81   @ReturnNullAsFalse
82   public static BinaryStream gzopen(Env env,
83                   String JavaDoc fileName,
84                   String JavaDoc mode,
85                   @Optional("false") boolean useIncludePath)
86   {
87     String JavaDoc filemode = getFileMode(mode);
88     int compressionLevel = getCompressionLevel(mode);
89     int compressionStrategy = getCompressionStrategy(mode);
90
91     Object JavaDoc val = FileModule.fopen(env, fileName, mode, useIncludePath, null);
92
93     if (val == null)
94       return null;
95
96     try {
97       int ch = filemode.charAt(0);
98
99       if (ch == 'r') {
100         BinaryInput is = (BinaryInput) val;
101         return new ZlibInputStream(is);
102       }
103       else if (ch == 'w') {
104         return new ZlibOutputStream(((BinaryOutput) val).getOutputStream(),
105                     compressionLevel,
106                     compressionStrategy);
107       }
108       else if (ch == 'a') {
109         return new ZlibOutputStream(((BinaryOutput) val).getOutputStream(),
110                     compressionLevel,
111                     compressionStrategy);
112       }
113       else if (ch == 'x') {
114         return new ZlibOutputStream(((BinaryOutput) val).getOutputStream(),
115                     compressionLevel,
116                     compressionStrategy);
117       }
118     }
119     catch (IOException JavaDoc e) {
120       log.log(Level.FINE, e.getMessage(), e);
121       env.warning(L.l(e.getMessage()));
122     }
123
124     return null;
125   }
126
127   /**
128    *
129    * @param env
130    * @param fileName
131    * @param useIncludePath
132    * @return array of uncompressed lines from fileName
133    */

134   @ReturnNullAsFalse
135   public static ArrayValue gzfile(Env env,
136                   String JavaDoc fileName,
137                   @Optional boolean useIncludePath)
138   {
139     BinaryInput is = (BinaryInput) gzopen(env, fileName, "r", useIncludePath);
140
141     if (is == null)
142       return null;
143
144     try {
145       ArrayValue result = new ArrayValueImpl();
146
147       StringValue line;
148       while ((line = is.readLine(Integer.MAX_VALUE)) != null &&
149          line.length() > 0)
150     result.put(line);
151
152       return result;
153     } catch (IOException JavaDoc e) {
154       throw new QuercusModuleException(e);
155     } finally {
156       is.close();
157     }
158   }
159
160   /**
161    * outputs uncompressed bytes directly to browser, writes a warning message
162    * if an error has occured
163    * Note: PHP5 is supposed to print an error message but it doesn't do it
164    *
165    * @param env
166    * @param fileName
167    * @param useIncludePath
168    * @return number of bytes read from file, or FALSE if an error occurred
169    */

170   public static Value readgzfile(Env env,
171                  String JavaDoc fileName,
172                  @Optional boolean useIncludePath)
173   {
174     BinaryInput is = (BinaryInput) gzopen(env, fileName, "r", useIncludePath);
175
176     if (is == null)
177       return BooleanValue.FALSE;
178
179     try {
180       return LongValue.create(env.getOut().writeStream(is.getInputStream()));
181     } catch (IOException JavaDoc e) {
182       throw new QuercusModuleException(e);
183     } finally {
184       is.close();
185     }
186   }
187
188   /**
189    * Writes a string to the gzip stream.
190    */

191   public static int gzwrite(@NotNull BinaryOutput os,
192                 InputStream JavaDoc is,
193                 @Optional("0x7fffffff") int length)
194   {
195     if (os == null)
196       return 0;
197
198     try {
199       return os.write(is, length);
200     } catch (IOException JavaDoc e) {
201       throw new QuercusModuleException(e);
202     }
203   }
204
205   /**
206    *
207    * @param env
208    * @param zp
209    * @param s
210    * @param length
211    * @return alias of gzwrite
212    */

213   public int gzputs(Env env,
214                     @NotNull BinaryOutput os,
215                     InputStream JavaDoc is,
216                     @Optional("0x7ffffff") int length)
217   {
218     if (os == null)
219       return 0;
220
221     try {
222       return os.write(is, length);
223     } catch (IOException JavaDoc e) {
224       throw new QuercusModuleException(e);
225     }
226   }
227
228   /**
229    * Closes the stream.
230    */

231   public boolean gzclose(@NotNull BinaryStream os)
232   {
233     if (os == null)
234       return false;
235     
236     os.close();
237
238     return true;
239   }
240
241   /**
242    * Returns true if the GZip stream is ended.
243    */

244   public boolean gzeof(@NotNull BinaryStream binaryStream)
245   {
246     if (binaryStream == null)
247       return true;
248
249     return binaryStream.isEOF();
250   }
251
252   /**
253    * Reads a character from the stream.
254    */

255   public static Value gzgetc(@NotNull BinaryInput is)
256   {
257     if (is == null)
258       return BooleanValue.FALSE;
259
260     try {
261       int ch = is.read();
262
263       if (ch < 0)
264         return BooleanValue.FALSE;
265       else
266         return new BinaryBuilderValue(new byte[] { (byte) ch });
267     } catch (IOException JavaDoc e) {
268       throw new QuercusModuleException(e);
269     }
270   }
271
272   /**
273    * Reads a chunk of data from the gzip stream.
274    */

275   @ReturnNullAsFalse
276   public BinaryValue gzread(@NotNull BinaryInput is, int length)
277   {
278     if (is == null)
279       return null;
280
281     try {
282       return is.read(length);
283     } catch (IOException JavaDoc e) {
284       throw new QuercusModuleException(e);
285     }
286   }
287
288   /**
289    * Reads a line from the input stream.
290    */

291   public static Value gzgets(Env env,
292                   @NotNull BinaryInput is,
293                   int length)
294   {
295     return FileModule.fgets(env, is, length);
296   }
297
298   /**
299    * Reads a line from the zip stream, stripping tags.
300    */

301   public static Value gzgetss(Env env,
302                   @NotNull BinaryInput is,
303                   int length,
304                   @Optional String JavaDoc allowedTags)
305   {
306     return FileModule.fgetss(env, is, length, allowedTags);
307   }
308
309   /**
310    * Rewinds the stream to the very beginning
311    */

312   public boolean gzrewind(@NotNull BinaryStream binaryStream)
313   {
314     if (binaryStream == null)
315       return false;
316
317     return binaryStream.setPosition(0);
318   }
319
320   /**
321    * Set stream position to the offset
322    * @param offset absolute position to set stream to
323    * @return 0 upon success, else -1 for error
324    */

325   public int gzseek(@NotNull BinaryStream binaryStream, long offset)
326   {
327     if (binaryStream == null)
328       return -1;
329     if (binaryStream.setPosition(offset) == false)
330       return -1;
331     if (binaryStream.getPosition() != offset)
332       return -1;
333
334     return 0;
335   }
336
337   /**
338    * Gets the current position in the stream
339    * @return the position in the stream, or FALSE for error
340    */

341   public Value gztell(@NotNull BinaryStream binaryStream)
342   {
343     if (binaryStream == null)
344       return BooleanValue.FALSE;
345     return new LongValue(binaryStream.getPosition());
346   }
347
348   /**
349    * Prints out the remaining data in the stream to stdout
350    */

351   public Value gzpassthru(Env env, @NotNull BinaryInput is)
352   {
353     WriteStream out = env.getOut();
354     TempBuffer tempBuf = TempBuffer.allocate();
355     byte[] buffer = tempBuf.getBuffer();
356
357     int length = 0;
358     try {
359       int sublen = is.read(buffer, 0, buffer.length);
360       while (sublen > 0) {
361         out.write(buffer, 0, sublen);
362         length += sublen;
363         sublen = is.read(buffer, 0, buffer.length);
364       }
365
366       return new LongValue(length);
367
368     } catch (IOException JavaDoc e) {
369       log.log(Level.FINE, e.toString(), e);
370
371       return BooleanValue.FALSE;
372
373     } finally {
374       TempBuffer.free(tempBuf);
375     }
376   }
377
378   /**
379    * Returns the encoding type both allowed by the server
380    * and supported by the user's browser.
381    */

382   public Value zlib_get_coding_type(Env env)
383   {
384     String JavaDoc ini = env.getIniString("zlib.output_compression");
385
386     if (ini == null || ini == "")
387       return BooleanValue.FALSE;
388
389     //zlib_get_coding_type can also be an integer > 0
390
if (! ini.equalsIgnoreCase("on")) {
391       int ch = ini.charAt(0);
392
393       if (ch < '0' || ch > '9')
394         return BooleanValue.FALSE;
395     }
396
397     ServerArrayValue sav = new ServerArrayValue(env);
398     Value val = sav.get(new StringValueImpl("HTTP_ACCEPT_ENCODING"));
399
400     if (!val.isset())
401       return BooleanValue.FALSE;
402
403     String JavaDoc s = val.toString();
404     if (s.contains("gzip"))
405       return new StringValueImpl("gzip");
406     else if(s.contains("deflate"))
407       return new StringValueImpl("deflate");
408     else
409       return BooleanValue.FALSE;
410   }
411
412   /**
413    * compresses data using zlib
414    *
415    * @param data
416    * @param level (default is Deflater.DEFAULT_COMPRESSION)
417    * @return compressed string
418    */

419   public Value gzcompress(InputStream JavaDoc data,
420                           @Optional("6") int level)
421   {
422     TempBuffer tempBuf = TempBuffer.allocate();
423     byte []buffer = tempBuf.getBuffer();
424
425     try {
426       Deflater JavaDoc deflater = new Deflater JavaDoc(level, true);
427       Adler32 JavaDoc crc = new Adler32 JavaDoc();
428
429       boolean isFinished = false;
430       TempStream out = new TempStream();
431
432       buffer[0] = (byte) 0x78;
433
434       if (level <= 1)
435         buffer[1] = (byte) 0x01;
436       else if (level < 6)
437         buffer[1] = (byte) 0x5e;
438       else if (level == 6)
439         buffer[1] = (byte) 0x9c;
440       else
441         buffer[1] = (byte) 0xda;
442
443       out.write(buffer, 0, 2, false);
444
445       int len;
446       while (! isFinished) {
447         while (! isFinished && deflater.needsInput()) {
448           len = data.read(buffer, 0, buffer.length);
449
450           if (len > 0) {
451             crc.update(buffer, 0, len);
452             deflater.setInput(buffer, 0, len);
453           }
454           else {
455             isFinished = true;
456             deflater.finish();
457           }
458         }
459
460         while ((len = deflater.deflate(buffer, 0, buffer.length)) > 0) {
461           out.write(buffer, 0, len, false);
462         }
463       }
464
465       long value = crc.getValue();
466     
467       buffer[0] = (byte) (value >> 24);
468       buffer[1] = (byte) (value >> 16);
469       buffer[2] = (byte) (value >> 8);
470       buffer[3] = (byte) (value >> 0);
471
472       out.write(buffer, 0, 4, true);
473
474       return new TempBufferStringValue(out.getHead());
475     } catch (Exception JavaDoc e) {
476       throw QuercusModuleException.create(e);
477     } finally {
478       TempBuffer.free(tempBuf);
479     }
480   }
481
482   /**
483    *
484    * @param data
485    * @param length (maximum length of string returned)
486    * @return uncompressed string
487    */

488   public Value gzuncompress(InputStream JavaDoc is,
489                             @Optional("0") long length)
490   {
491     TempBuffer tempBuf = TempBuffer.allocate();
492     byte []buffer = tempBuf.getBuffer();
493
494     try {
495       if (length == 0)
496         length = Long.MAX_VALUE;
497
498       InflaterInputStream JavaDoc in = new InflaterInputStream JavaDoc(is);
499       TempStream out = new TempStream();
500
501
502
503       int len;
504       while ((len = in.read(buffer, 0, buffer.length)) >= 0) {
505         out.write(buffer, 0, len, false);
506       }
507
508       in.close();
509
510       return new TempBufferStringValue(out.getHead());
511     } catch (Exception JavaDoc e) {
512       throw QuercusModuleException.create(e);
513     } finally {
514       TempBuffer.free(tempBuf);
515     }
516   }
517
518   private int _dbg;
519   
520   /**
521    *
522    * @param level
523    * @return compressed using DEFLATE algorithm
524    */

525   public Value gzdeflate(InputStream JavaDoc data,
526                          @Optional("6") int level)
527   {
528     TempBuffer tempBuf = TempBuffer.allocate();
529     byte []buffer = tempBuf.getBuffer();
530
531     try {
532       Deflater JavaDoc deflater = new Deflater JavaDoc(level, true);
533
534       boolean isFinished = false;
535       TempStream out = new TempStream();
536
537       int len;
538       while (! isFinished) {
539         if (! isFinished && deflater.needsInput()) {
540           len = data.read(buffer, 0, buffer.length);
541
542           if (len > 0)
543             deflater.setInput(buffer, 0, len);
544           else {
545             isFinished = true;
546             deflater.finish();
547           }
548         }
549
550         while ((len = deflater.deflate(buffer, 0, buffer.length)) > 0) {
551           out.write(buffer, 0, len, false);
552         }
553       }
554       deflater.end();
555
556       return new TempBufferStringValue(out.getHead());
557
558     } catch (Exception JavaDoc e) {
559       throw QuercusModuleException.create(e);
560     } finally {
561       TempBuffer.free(tempBuf);
562     }
563   }
564
565   /**
566    * @param data compressed using Deflate algorithm
567    * @param length (maximum length of string returned)
568    *
569    * @return uncompressed string
570    */

571   public Value gzinflate(Env env,
572                          InputStream JavaDoc data,
573                          @Optional("0") long length)
574   {
575     TempBuffer tempBuf = TempBuffer.allocate();
576     byte []buffer = tempBuf.getBuffer();
577
578     try {
579       Inflater JavaDoc inflater = new Inflater JavaDoc(true);
580
581       boolean isFinished = false;
582       TempStream out = new TempStream();
583
584       int len;
585       while (! isFinished) {
586         if (! isFinished && inflater.needsInput()) {
587           len = data.read(buffer, 0, buffer.length);
588
589           if (len > 0) {
590             inflater.setInput(buffer, 0, len);
591       }
592           else
593             isFinished = true;
594         }
595
596         while ((len = inflater.inflate(buffer, 0, buffer.length)) > 0) {
597           out.write(buffer, 0, len, false);
598         }
599       }
600
601       inflater.end();
602
603       return new TempBufferStringValue(out.getHead());
604     } catch (Exception JavaDoc e) {
605       env.warning(e);
606       return BooleanValue.FALSE;
607     } finally {
608       TempBuffer.free(tempBuf);
609     }
610   }
611
612   /**
613    *
614    * Compresses data using the Deflate algorithm, output is
615    * compatible with gzwrite's output
616    *
617    * @param data compressed with the Deflate algorithm
618    * @param level Deflate compresion level [0-9]
619    * @param encodingMode CRC32 trailer is not written if encoding mode
620    * is FORCE_DEFLATE, default is to write CRC32
621    * @return StringValue with gzip header and trailer
622    */

623   public Value gzencode(InputStream JavaDoc is,
624                         @Optional("6") int level,
625                         @Optional("1") int encodingMode)
626   {
627     TempBuffer tempBuf = TempBuffer.allocate();
628     byte[] buffer = tempBuf.getBuffer();
629
630     TempStream ts = new TempStream();
631     StreamImplOutputStream out = new StreamImplOutputStream(ts);
632
633     try {
634       ZlibOutputStream gzOut;
635
636       gzOut = new ZlibOutputStream(out, level,
637                Deflater.DEFAULT_STRATEGY,
638                encodingMode);
639
640       int len;
641       while ((len = is.read(buffer, 0, buffer.length)) > 0) {
642         gzOut.write(buffer, 0, len);
643       }
644       gzOut.close();
645       return new TempBufferStringValue(ts.getHead());
646
647     } catch(IOException JavaDoc e) {
648       throw QuercusModuleException.create(e);
649     } finally {
650       TempBuffer.free(tempBuf);
651     }
652   }
653
654   /**
655    * Helper function to retrieve the filemode closest to the end
656    * Note: PHP5 unexpectedly fails when 'x' is the mode.
657    *
658    * XXX todo: toss a warning if '+' is found
659    * (gzip cannot be open for both reading and writing at the same time)
660    *
661    */

662   private static String JavaDoc getFileMode(String JavaDoc input)
663   {
664     String JavaDoc modifier = "";
665     String JavaDoc filemode = input.substring(0, 1);
666
667     for (int i = 1; i < input.length(); i++ )
668     {
669       char ch = input.charAt(i);
670       switch (ch) {
671         case 'r':
672           filemode = "r";
673           break;
674         case 'w':
675           filemode = "w";
676           break;
677         case 'a':
678           filemode = "a";
679           break;
680         case 'b':
681           modifier = "b";
682           break;
683         case 't':
684           modifier = "t";
685           break;
686       }
687     }
688     return filemode + modifier;
689   }
690
691   /**
692    * Helper function to retrieve the compression level
693    * - finds the compression level nearest to the end and returns that
694    */

695   private static int getCompressionLevel(String JavaDoc input)
696   {
697     for (int i = input.length() - 1; i >= 0; i--) {
698       char ch = input.charAt(i);
699       
700       if (ch >= '0' && ch <= '9')
701         return ch - '0';
702     }
703     
704     return Deflater.DEFAULT_COMPRESSION;
705   }
706
707   /**
708    * Helper function to retrieve the compression strategy.
709    * - finds the compression strategy nearest to the end and returns that
710    */

711   private static int getCompressionStrategy(String JavaDoc input)
712   {
713     for (int i = input.length() - 1; i >= 0; i--) {
714       char ch = input.charAt(i);
715       
716       switch (ch) {
717       case 'f':
718         return Deflater.FILTERED;
719     
720       case 'h':
721         return Deflater.HUFFMAN_ONLY;
722       }
723     }
724     
725     return Deflater.DEFAULT_STRATEGY;
726   }
727 }
728
Popular Tags