KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > filter > support > Zlib


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  */

20 package org.apache.mina.filter.support;
21
22 import java.io.IOException JavaDoc;
23
24 import org.apache.mina.common.ByteBuffer;
25
26 import com.jcraft.jzlib.JZlib;
27 import com.jcraft.jzlib.ZStream;
28
29 /**
30  * A helper class for interfacing with the JZlib library. This class acts both
31  * as a compressor and decompressor, but only as one at a time. The only
32  * flush method supported is <tt>Z_SYNC_FLUSH</tt> also known as <tt>Z_PARTIAL_FLUSH</tt>
33  *
34  * @author The Apache Directory Project (mina-dev@directory.apache.org)
35  * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $
36  */

37 public class Zlib {
38     public static final int COMPRESSION_MAX = JZlib.Z_BEST_COMPRESSION;
39
40     public static final int COMPRESSION_MIN = JZlib.Z_BEST_SPEED;
41
42     public static final int COMPRESSION_NONE = JZlib.Z_NO_COMPRESSION;
43
44     public static final int COMPRESSION_DEFAULT = JZlib.Z_DEFAULT_COMPRESSION;
45
46     public static final int MODE_DEFLATER = 1;
47
48     public static final int MODE_INFLATER = 2;
49
50     private int compressionLevel;
51
52     private ZStream zStream = null;
53
54     private int mode = -1;
55
56     /**
57      * @param compressionLevel the level of compression that should be used
58      * @param mode the mode in which the instance will operate. Can be either
59      * of <tt>MODE_DEFLATER</tt> or <tt>MODE_INFLATER</tt>
60      */

61     public Zlib(int compressionLevel, int mode) {
62         switch (compressionLevel) {
63         case COMPRESSION_MAX:
64         case COMPRESSION_MIN:
65         case COMPRESSION_NONE:
66         case COMPRESSION_DEFAULT:
67             this.compressionLevel = compressionLevel;
68             break;
69         default:
70             throw new IllegalArgumentException JavaDoc(
71                     "invalid compression level specified");
72         }
73
74         // create a new instance of ZStream. This will be done only once.
75
zStream = new ZStream();
76
77         switch (mode) {
78         case MODE_DEFLATER:
79             zStream.deflateInit(this.compressionLevel);
80             break;
81         case MODE_INFLATER:
82             zStream.inflateInit();
83             break;
84         default:
85             throw new IllegalArgumentException JavaDoc("invalid mode specified");
86         }
87         this.mode = mode;
88     }
89
90     /**
91      * @param inBuffer the {@link ByteBuffer} to be decompressed. The contents
92      * of the buffer are transferred into a local byte array and the buffer is
93      * flipped and returned intact.
94      * @return the decompressed data. If not passed to the MINA methods that
95      * release the buffer automatically, the buffer has to be manually released
96      * @throws IOException if the decompression of the data failed for some reason.
97      */

98     public ByteBuffer inflate(ByteBuffer inBuffer) throws IOException JavaDoc {
99         if (mode == MODE_DEFLATER) {
100             throw new IllegalStateException JavaDoc("not initialized as INFLATER");
101         }
102
103         byte[] inBytes = new byte[inBuffer.limit()];
104         inBuffer.get(inBytes).flip();
105
106         byte[] outBytes = new byte[inBytes.length * 2];
107         ByteBuffer outBuffer = ByteBuffer.allocate(outBytes.length);
108         outBuffer.setAutoExpand(true);
109
110         zStream.next_in = inBytes;
111         zStream.next_in_index = 0;
112         zStream.avail_in = inBytes.length;
113         zStream.next_out = outBytes;
114         zStream.next_out_index = 0;
115         zStream.avail_out = outBytes.length;
116         int retval = 0;
117
118         do {
119             retval = zStream.inflate(JZlib.Z_SYNC_FLUSH);
120             switch (retval) {
121             case JZlib.Z_OK:
122                 // completed decompression, lets copy data and get out
123
case JZlib.Z_BUF_ERROR:
124                 // need more space for output. store current output and get more
125
outBuffer.put(outBytes, 0, zStream.next_out_index);
126                 zStream.next_out_index = 0;
127                 zStream.avail_out = outBytes.length;
128                 break;
129             default:
130                 // unknown error
131
outBuffer.release();
132                 outBuffer = null;
133                 if (zStream.msg == null)
134                     throw new IOException JavaDoc("Unknown error. Error code : "
135                             + retval);
136                 else
137                     throw new IOException JavaDoc("Unknown error. Error code : "
138                             + retval + " and message : " + zStream.msg);
139             }
140         } while (zStream.avail_in > 0);
141
142         return outBuffer.flip();
143     }
144
145     /**
146      * @param inBuffer the buffer to be compressed. The contents are transferred
147      * into a local byte array and the buffer is flipped and returned intact.
148      * @return the buffer with the compressed data. If not passed to any of the
149      * MINA methods that automatically release the buffer, the buffer has to be
150      * released manually.
151      * @throws IOException if the compression of teh buffer failed for some reason
152      */

153     public ByteBuffer deflate(ByteBuffer inBuffer) throws IOException JavaDoc {
154         if (mode == MODE_INFLATER) {
155             throw new IllegalStateException JavaDoc("not initialized as DEFLATER");
156         }
157
158         byte[] inBytes = new byte[inBuffer.limit()];
159         inBuffer.get(inBytes).flip();
160
161         // according to spec, destination buffer should be 0.1% larger
162
// than source length plus 12 bytes. We add a single byte to safeguard
163
// against rounds that round down to the smaller value
164
int outLen = (int) Math.round(inBytes.length * 1.001) + 1 + 12;
165         byte[] outBytes = new byte[outLen];
166
167         zStream.next_in = inBytes;
168         zStream.next_in_index = 0;
169         zStream.avail_in = inBytes.length;
170         zStream.next_out = outBytes;
171         zStream.next_out_index = 0;
172         zStream.avail_out = outBytes.length;
173
174         int retval = zStream.deflate(JZlib.Z_SYNC_FLUSH);
175         if (retval != JZlib.Z_OK) {
176             outBytes = null;
177             inBytes = null;
178             throw new IOException JavaDoc("Compression failed with return value : "
179                     + retval);
180         }
181
182         ByteBuffer outBuf = ByteBuffer
183                 .wrap(outBytes, 0, zStream.next_out_index);
184
185         return outBuf;
186     }
187
188     /**
189      * Cleans up the resources used by the compression library.
190      */

191     public void cleanUp() {
192         if (zStream != null)
193             zStream.free();
194     }
195 }
196
Popular Tags