1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
package com.koushikdutta.async.http.filter;
import com.koushikdutta.async.*;
import com.koushikdutta.async.callback.DataCallback;
import com.koushikdutta.async.http.libcore.Memory;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.zip.CRC32;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
public class GZIPInputFilter extends InflaterInputFilter {
private static final int FCOMMENT = 16;
private static final int FEXTRA = 4;
private static final int FHCRC = 2;
private static final int FNAME = 8;
public GZIPInputFilter() {
super(new Inflater(true));
}
boolean mNeedsHeader = true;
protected CRC32 crc = new CRC32();
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
@Override
@SuppressWarnings("unused")
public void onDataAvailable(final DataEmitter emitter, ByteBufferList bb) {
if (mNeedsHeader) {
final PushParser parser = new PushParser(emitter);
parser.readBuffer(10, new TapCallback<byte[]>() {
int flags;
boolean hcrc;
public void tap(byte[] header) {
short magic = Memory.peekShort(header, 0, ByteOrder.LITTLE_ENDIAN);
if (magic != (short) GZIPInputStream.GZIP_MAGIC) {
report(new IOException(String.format("unknown format (magic number %x)", magic)));
emitter.setDataCallback(new NullDataCallback());
return;
}
flags = header[3];
hcrc = (flags & FHCRC) != 0;
if (hcrc) {
crc.update(header, 0, header.length);
}
if ((flags & FEXTRA) != 0) {
parser.readBuffer(2, new TapCallback<byte[]>() {
public void tap(byte[] header) {
if (hcrc) {
crc.update(header, 0, 2);
}
int length = Memory.peekShort(header, 0, ByteOrder.LITTLE_ENDIAN) & 0xffff;
parser.readBuffer(length, new TapCallback<byte[]>() {
public void tap(byte[] buf) {
if (hcrc) {
crc.update(buf, 0, buf.length);
}
next();
}
});
}
});
} else {
next();
}
}
private void next() {
PushParser parser = new PushParser(emitter);
DataCallback summer = new DataCallback() {
@Override
public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
if (hcrc) {
while (bb.size() > 0) {
ByteBuffer b = bb.remove();
crc.update(b.array(), b.arrayOffset() + b.position(), b.remaining());
ByteBufferList.reclaim(b);
}
}
}
};
if ((flags & FNAME) != 0) {
parser.until((byte)0, summer);
}
if ((flags & FCOMMENT) != 0) {
parser.until((byte)0, summer);
}
if (hcrc) {
parser.readBuffer(2, new TapCallback<byte[]>() {
public void tap(byte[] header) {
short crc16 = Memory.peekShort(header, 0, ByteOrder.LITTLE_ENDIAN);
if ((short) crc.getValue() != crc16) {
report(new IOException("CRC mismatch"));
return;
}
crc.reset();
mNeedsHeader = false;
setDataEmitter(emitter);
// emitter.setDataCallback(GZIPInputFilter.this);
}
});
}
else {
mNeedsHeader = false;
setDataEmitter(emitter);
}
}
});
}
else {
super.onDataAvailable(emitter, bb);
}
}
}
|