1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.compression;
17
18 import com.jcraft.jzlib.Inflater;
19 import com.jcraft.jzlib.JZlib;
20 import io.netty.buffer.ByteBuf;
21 import io.netty.buffer.ByteBufAllocator;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.util.internal.ObjectUtil;
24
25 import java.util.List;
26
27 public class JZlibDecoder extends ZlibDecoder {
28
29 private final Inflater z = new Inflater();
30 private byte[] dictionary;
31 private boolean needsRead;
32 private volatile boolean finished;
33
34
35
36
37
38
39
40 @Deprecated
41 public JZlibDecoder() {
42 this(ZlibWrapper.ZLIB, 0);
43 }
44
45
46
47
48
49
50
51
52
53
54
55 public JZlibDecoder(int maxAllocation) {
56 this(ZlibWrapper.ZLIB, maxAllocation);
57 }
58
59
60
61
62
63
64
65 @Deprecated
66 public JZlibDecoder(ZlibWrapper wrapper) {
67 this(wrapper, 0);
68 }
69
70
71
72
73
74
75
76
77
78
79 public JZlibDecoder(ZlibWrapper wrapper, int maxAllocation) {
80 super(maxAllocation);
81
82 ObjectUtil.checkNotNull(wrapper, "wrapper");
83
84 int resultCode = z.init(ZlibUtil.convertWrapperType(wrapper));
85 if (resultCode != JZlib.Z_OK) {
86 ZlibUtil.fail(z, "initialization failure", resultCode);
87 }
88 }
89
90
91
92
93
94
95
96
97
98 @Deprecated
99 public JZlibDecoder(byte[] dictionary) {
100 this(dictionary, 0);
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114 public JZlibDecoder(byte[] dictionary, int maxAllocation) {
115 super(maxAllocation);
116 this.dictionary = ObjectUtil.checkNotNull(dictionary, "dictionary");
117 int resultCode;
118 resultCode = z.inflateInit(JZlib.W_ZLIB);
119 if (resultCode != JZlib.Z_OK) {
120 ZlibUtil.fail(z, "initialization failure", resultCode);
121 }
122 }
123
124
125
126
127
128 @Override
129 public boolean isClosed() {
130 return finished;
131 }
132
133 @Override
134 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
135 needsRead = true;
136 if (finished) {
137
138 in.skipBytes(in.readableBytes());
139 return;
140 }
141
142 final int inputLength = in.readableBytes();
143 if (inputLength == 0) {
144 return;
145 }
146
147 try {
148
149 z.avail_in = inputLength;
150 if (in.hasArray()) {
151 z.next_in = in.array();
152 z.next_in_index = in.arrayOffset() + in.readerIndex();
153 } else {
154 byte[] array = new byte[inputLength];
155 in.getBytes(in.readerIndex(), array);
156 z.next_in = array;
157 z.next_in_index = 0;
158 }
159 final int oldNextInIndex = z.next_in_index;
160
161
162 ByteBuf decompressed = prepareDecompressBuffer(ctx, null, inputLength << 1);
163
164 try {
165 loop: for (;;) {
166 decompressed = prepareDecompressBuffer(ctx, decompressed, z.avail_in << 1);
167 z.avail_out = decompressed.writableBytes();
168 z.next_out = decompressed.array();
169 z.next_out_index = decompressed.arrayOffset() + decompressed.writerIndex();
170 int oldNextOutIndex = z.next_out_index;
171
172
173 int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
174 int outputLength = z.next_out_index - oldNextOutIndex;
175 if (outputLength > 0) {
176 decompressed.writerIndex(decompressed.writerIndex() + outputLength);
177 if (maxAllocation == 0) {
178
179
180 ByteBuf buffer = decompressed;
181 decompressed = null;
182 needsRead = false;
183 ctx.fireChannelRead(buffer);
184 }
185 }
186
187 switch (resultCode) {
188 case JZlib.Z_NEED_DICT:
189 if (dictionary == null) {
190 ZlibUtil.fail(z, "decompression failure", resultCode);
191 } else {
192 resultCode = z.inflateSetDictionary(dictionary, dictionary.length);
193 if (resultCode != JZlib.Z_OK) {
194 ZlibUtil.fail(z, "failed to set the dictionary", resultCode);
195 }
196 }
197 break;
198 case JZlib.Z_STREAM_END:
199 finished = true;
200 z.inflateEnd();
201 break loop;
202 case JZlib.Z_OK:
203 break;
204 case JZlib.Z_BUF_ERROR:
205 if (z.avail_in <= 0) {
206 break loop;
207 }
208 break;
209 default:
210 ZlibUtil.fail(z, "decompression failure", resultCode);
211 }
212 }
213 } finally {
214 in.skipBytes(z.next_in_index - oldNextInIndex);
215 if (decompressed != null) {
216 if (decompressed.isReadable()) {
217 needsRead = false;
218 ctx.fireChannelRead(decompressed);
219 } else {
220 decompressed.release();
221 }
222 }
223 }
224 } finally {
225
226
227
228
229 z.next_in = null;
230 z.next_out = null;
231 }
232 }
233
234 @Override
235 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
236
237 discardSomeReadBytes();
238
239 if (needsRead && !ctx.channel().config().isAutoRead()) {
240 ctx.read();
241 }
242 ctx.fireChannelReadComplete();
243 }
244
245 @Override
246 protected void decompressionBufferExhausted(ByteBuf buffer) {
247 finished = true;
248 }
249 }