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.channel.ChannelHandlerContext;
22
23 import java.util.List;
24
25 public class JZlibDecoder extends ZlibDecoder {
26
27 private final Inflater z = new Inflater();
28 private byte[] dictionary;
29 private volatile boolean finished;
30
31
32
33
34
35
36 public JZlibDecoder() {
37 this(ZlibWrapper.ZLIB);
38 }
39
40
41
42
43
44
45 public JZlibDecoder(ZlibWrapper wrapper) {
46 if (wrapper == null) {
47 throw new NullPointerException("wrapper");
48 }
49
50 int resultCode = z.init(ZlibUtil.convertWrapperType(wrapper));
51 if (resultCode != JZlib.Z_OK) {
52 ZlibUtil.fail(z, "initialization failure", resultCode);
53 }
54 }
55
56
57
58
59
60
61
62
63 public JZlibDecoder(byte[] dictionary) {
64 if (dictionary == null) {
65 throw new NullPointerException("dictionary");
66 }
67 this.dictionary = dictionary;
68
69 int resultCode;
70 resultCode = z.inflateInit(JZlib.W_ZLIB);
71 if (resultCode != JZlib.Z_OK) {
72 ZlibUtil.fail(z, "initialization failure", resultCode);
73 }
74 }
75
76
77
78
79
80 @Override
81 public boolean isClosed() {
82 return finished;
83 }
84
85 @Override
86 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
87 if (finished) {
88
89 in.skipBytes(in.readableBytes());
90 return;
91 }
92
93 final int inputLength = in.readableBytes();
94 if (inputLength == 0) {
95 return;
96 }
97
98 try {
99
100 z.avail_in = inputLength;
101 if (in.hasArray()) {
102 z.next_in = in.array();
103 z.next_in_index = in.arrayOffset() + in.readerIndex();
104 } else {
105 byte[] array = new byte[inputLength];
106 in.getBytes(in.readerIndex(), array);
107 z.next_in = array;
108 z.next_in_index = 0;
109 }
110 final int oldNextInIndex = z.next_in_index;
111
112
113 ByteBuf decompressed = ctx.alloc().heapBuffer(inputLength << 1);
114
115 try {
116 loop: for (;;) {
117 decompressed.ensureWritable(z.avail_in << 1);
118 z.avail_out = decompressed.writableBytes();
119 z.next_out = decompressed.array();
120 z.next_out_index = decompressed.arrayOffset() + decompressed.writerIndex();
121 int oldNextOutIndex = z.next_out_index;
122
123
124 int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
125 int outputLength = z.next_out_index - oldNextOutIndex;
126 if (outputLength > 0) {
127 decompressed.writerIndex(decompressed.writerIndex() + outputLength);
128 }
129
130 switch (resultCode) {
131 case JZlib.Z_NEED_DICT:
132 if (dictionary == null) {
133 ZlibUtil.fail(z, "decompression failure", resultCode);
134 } else {
135 resultCode = z.inflateSetDictionary(dictionary, dictionary.length);
136 if (resultCode != JZlib.Z_OK) {
137 ZlibUtil.fail(z, "failed to set the dictionary", resultCode);
138 }
139 }
140 break;
141 case JZlib.Z_STREAM_END:
142 finished = true;
143 z.inflateEnd();
144 break loop;
145 case JZlib.Z_OK:
146 break;
147 case JZlib.Z_BUF_ERROR:
148 if (z.avail_in <= 0) {
149 break loop;
150 }
151 break;
152 default:
153 ZlibUtil.fail(z, "decompression failure", resultCode);
154 }
155 }
156 } finally {
157 in.skipBytes(z.next_in_index - oldNextInIndex);
158 if (decompressed.isReadable()) {
159 out.add(decompressed);
160 } else {
161 decompressed.release();
162 }
163 }
164 } finally {
165
166
167
168
169 z.next_in = null;
170 z.next_out = null;
171 }
172 }
173 }