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 volatile boolean finished;
32
33
34
35
36
37
38
39 @Deprecated
40 public JZlibDecoder() {
41 this(ZlibWrapper.ZLIB, 0);
42 }
43
44
45
46
47
48
49
50
51
52
53
54 public JZlibDecoder(int maxAllocation) {
55 this(ZlibWrapper.ZLIB, maxAllocation);
56 }
57
58
59
60
61
62
63
64 @Deprecated
65 public JZlibDecoder(ZlibWrapper wrapper) {
66 this(wrapper, 0);
67 }
68
69
70
71
72
73
74
75
76
77
78 public JZlibDecoder(ZlibWrapper wrapper, int maxAllocation) {
79 super(maxAllocation);
80
81 ObjectUtil.checkNotNull(wrapper, "wrapper");
82
83 int resultCode = z.init(ZlibUtil.convertWrapperType(wrapper));
84 if (resultCode != JZlib.Z_OK) {
85 ZlibUtil.fail(z, "initialization failure", resultCode);
86 }
87 }
88
89
90
91
92
93
94
95
96
97 @Deprecated
98 public JZlibDecoder(byte[] dictionary) {
99 this(dictionary, 0);
100 }
101
102
103
104
105
106
107
108
109
110
111
112
113 public JZlibDecoder(byte[] dictionary, int maxAllocation) {
114 super(maxAllocation);
115 this.dictionary = ObjectUtil.checkNotNull(dictionary, "dictionary");
116 int resultCode;
117 resultCode = z.inflateInit(JZlib.W_ZLIB);
118 if (resultCode != JZlib.Z_OK) {
119 ZlibUtil.fail(z, "initialization failure", resultCode);
120 }
121 }
122
123
124
125
126
127 @Override
128 public boolean isClosed() {
129 return finished;
130 }
131
132 @Override
133 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
134 if (finished) {
135
136 in.skipBytes(in.readableBytes());
137 return;
138 }
139
140 final int inputLength = in.readableBytes();
141 if (inputLength == 0) {
142 return;
143 }
144
145 try {
146
147 z.avail_in = inputLength;
148 if (in.hasArray()) {
149 z.next_in = in.array();
150 z.next_in_index = in.arrayOffset() + in.readerIndex();
151 } else {
152 byte[] array = new byte[inputLength];
153 in.getBytes(in.readerIndex(), array);
154 z.next_in = array;
155 z.next_in_index = 0;
156 }
157 final int oldNextInIndex = z.next_in_index;
158
159
160 ByteBuf decompressed = prepareDecompressBuffer(ctx, null, inputLength << 1);
161
162 try {
163 loop: for (;;) {
164 decompressed = prepareDecompressBuffer(ctx, decompressed, z.avail_in << 1);
165 z.avail_out = decompressed.writableBytes();
166 z.next_out = decompressed.array();
167 z.next_out_index = decompressed.arrayOffset() + decompressed.writerIndex();
168 int oldNextOutIndex = z.next_out_index;
169
170
171 int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
172 int outputLength = z.next_out_index - oldNextOutIndex;
173 if (outputLength > 0) {
174 decompressed.writerIndex(decompressed.writerIndex() + outputLength);
175 }
176
177 switch (resultCode) {
178 case JZlib.Z_NEED_DICT:
179 if (dictionary == null) {
180 ZlibUtil.fail(z, "decompression failure", resultCode);
181 } else {
182 resultCode = z.inflateSetDictionary(dictionary, dictionary.length);
183 if (resultCode != JZlib.Z_OK) {
184 ZlibUtil.fail(z, "failed to set the dictionary", resultCode);
185 }
186 }
187 break;
188 case JZlib.Z_STREAM_END:
189 finished = true;
190 z.inflateEnd();
191 break loop;
192 case JZlib.Z_OK:
193 break;
194 case JZlib.Z_BUF_ERROR:
195 if (z.avail_in <= 0) {
196 break loop;
197 }
198 break;
199 default:
200 ZlibUtil.fail(z, "decompression failure", resultCode);
201 }
202 }
203 } finally {
204 in.skipBytes(z.next_in_index - oldNextInIndex);
205 if (decompressed.isReadable()) {
206 out.add(decompressed);
207 } else {
208 decompressed.release();
209 }
210 }
211 } finally {
212
213
214
215
216 z.next_in = null;
217 z.next_out = null;
218 }
219 }
220
221 @Override
222 protected void decompressionBufferExhausted(ByteBuf buffer) {
223 finished = true;
224 }
225 }