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