43
43
import static com .oracle .graal .python .builtins .PythonBuiltinClassType .ZlibCompress ;
44
44
import static com .oracle .graal .python .builtins .PythonBuiltinClassType .ZlibDecompress ;
45
45
import static com .oracle .graal .python .builtins .modules .zlib .ZLibModuleBuiltins .MAX_WBITS ;
46
+ import static com .oracle .graal .python .builtins .objects .bytes .BytesUtils .mask ;
47
+ import static com .oracle .graal .python .runtime .exception .PythonErrorType .ZLibError ;
46
48
49
+ import java .util .zip .CRC32 ;
47
50
import java .util .zip .DataFormatException ;
48
51
import java .util .zip .Deflater ;
49
52
import java .util .zip .Inflater ;
50
53
51
54
import com .oracle .graal .python .builtins .objects .bytes .PBytes ;
52
55
import com .oracle .graal .python .builtins .objects .object .PythonBuiltinObject ;
56
+ import com .oracle .graal .python .nodes .PRaiseNode ;
53
57
import com .oracle .graal .python .runtime .NFIZlibSupport ;
54
58
import com .oracle .graal .python .runtime .object .PythonObjectFactory ;
59
+ import com .oracle .graal .python .util .PythonUtils ;
55
60
import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
61
+ import com .oracle .truffle .api .nodes .Node ;
56
62
import com .oracle .truffle .api .object .Shape ;
57
63
58
64
public abstract class ZLibCompObject extends PythonBuiltinObject {
@@ -109,6 +115,7 @@ protected static class JavaZlibCompObject extends ZLibCompObject {
109
115
110
116
private byte [] inputData ; // helper for copy operation
111
117
private boolean canCopy ; // to assist if copying is allowed
118
+ private boolean readHeader ;
112
119
113
120
public JavaZlibCompObject (Object cls , Shape instanceShape , Object stream , int level , int wbits , int strategy , byte [] zdict ) {
114
121
super (cls , instanceShape );
@@ -119,6 +126,7 @@ public JavaZlibCompObject(Object cls, Shape instanceShape, Object stream, int le
119
126
this .strategy = strategy ;
120
127
this .inputData = null ;
121
128
this .canCopy = true ;
129
+ this .readHeader = wbits >= 25 && wbits <= 31 ;
122
130
}
123
131
124
132
public JavaZlibCompObject (Object cls , Shape instanceShape , Object stream , int wbits , byte [] zdict ) {
@@ -146,11 +154,17 @@ public void setDeflaterInput(byte[] data) {
146
154
}
147
155
148
156
@ TruffleBoundary
149
- public void setInflaterInput (byte [] data ) {
157
+ public void setInflaterInput (byte [] data , Node node ) {
150
158
assert stream instanceof Inflater ;
159
+ byte [] bytes = data ;
160
+ if (readHeader ) {
161
+ readHeader = false ;
162
+ int h = gzipHeader (data , node );
163
+ bytes = PythonUtils .arrayCopyOfRange (bytes , h , data .length - h );
164
+ }
151
165
canCopy = inputData == null ;
152
- inputData = data ;
153
- ((Inflater ) stream ).setInput (data );
166
+ inputData = bytes ;
167
+ ((Inflater ) stream ).setInput (bytes );
154
168
}
155
169
156
170
@ TruffleBoundary
@@ -172,7 +186,7 @@ public ZLibCompObject copyCompressObj(PythonObjectFactory factory) {
172
186
}
173
187
174
188
@ TruffleBoundary
175
- public ZLibCompObject copyDecompressObj (PythonObjectFactory factory ) {
189
+ public ZLibCompObject copyDecompressObj (PythonObjectFactory factory , Node node ) {
176
190
assert canCopy ;
177
191
boolean isRAW = wbits < 0 ;
178
192
Inflater inflater = new Inflater (isRAW || wbits > (MAX_WBITS + 9 ));
@@ -182,7 +196,7 @@ public ZLibCompObject copyDecompressObj(PythonObjectFactory factory) {
182
196
ZLibCompObject obj = factory .createJavaZLibCompObject (ZlibDecompress , inflater , wbits , zdict );
183
197
if (inputData != null ) {
184
198
try {
185
- ((JavaZlibCompObject ) obj ).setInflaterInput (inputData );
199
+ ((JavaZlibCompObject ) obj ).setInflaterInput (inputData , node );
186
200
inflater .setInput (inputData );
187
201
int n = inflater .inflate (new byte [ZLibModuleBuiltins .DEF_BUF_SIZE ]);
188
202
if (!isRAW && n == 0 && inflater .needsDictionary () && zdict .length > 0 ) {
@@ -197,6 +211,74 @@ public ZLibCompObject copyDecompressObj(PythonObjectFactory factory) {
197
211
obj .setUnusedData (getUnusedData ());
198
212
return obj ;
199
213
}
214
+
215
+ public static final int GZIP_MAGIC = 0x8b1f ;
216
+ private static final int FHCRC = 2 ; // Header CRC
217
+ private static final int FEXTRA = 4 ; // Extra field
218
+ private static final int FNAME = 8 ; // File name
219
+ private static final int FCOMMENT = 16 ; // File comment
220
+
221
+ private static int getValue (byte b , CRC32 crc ) {
222
+ int v = mask (b );
223
+ crc .update (v );
224
+ return v ;
225
+ }
226
+
227
+ private static int readShort (byte [] bytes , int off , CRC32 crc ) {
228
+ return getValue (bytes [off + 1 ], crc ) << 8 | getValue (bytes [off ], crc );
229
+ }
230
+
231
+ // logic is from GZIPInputStream.readHeader()
232
+ @ TruffleBoundary
233
+ private static int gzipHeader (byte [] bytes , Node node ) {
234
+ CRC32 crc = new CRC32 ();
235
+ int idx = 0 ;
236
+ // Check header magic
237
+ if (readShort (bytes , idx , crc ) != GZIP_MAGIC ) {
238
+ throw PRaiseNode .raiseUncached (node , ZLibError , "Not in GZIP format" );
239
+ }
240
+ idx += 2 ;
241
+ // Check compression method
242
+ if (getValue (bytes [idx ++], crc ) != 8 ) {
243
+ throw PRaiseNode .raiseUncached (node , ZLibError , "Unsupported compression method" );
244
+ }
245
+ // Read flags
246
+ int flg = getValue (bytes [idx ++], crc );
247
+ // Skip MTIME, XFL, and OS fields
248
+ idx += 6 ;
249
+ int n = 2 + 2 + 6 ;
250
+ // Skip optional extra field
251
+ if ((flg & FEXTRA ) == FEXTRA ) {
252
+ int m = getValue (bytes [idx ++], crc );
253
+ idx += m ;
254
+ n += m + 2 ;
255
+ }
256
+ // Skip optional file name
257
+ if ((flg & FNAME ) == FNAME ) {
258
+ do {
259
+ n ++;
260
+ } while (getValue (bytes [idx ++], crc ) != 0 );
261
+ }
262
+ // Skip optional file comment
263
+ if ((flg & FCOMMENT ) == FCOMMENT ) {
264
+ do {
265
+ n ++;
266
+ } while (getValue (bytes [idx ++], crc ) != 0 );
267
+ }
268
+ // Check optional header CRC
269
+ crc .reset ();
270
+ if ((flg & FHCRC ) == FHCRC ) {
271
+ int v = (int ) crc .getValue () & 0xffff ;
272
+ if (readShort (bytes , idx , crc ) != v ) {
273
+ throw PRaiseNode .raiseUncached (node , ZLibError , "Corrupt GZIP header" );
274
+ }
275
+ idx += 2 ;
276
+ n += 2 ;
277
+ }
278
+ crc .reset ();
279
+ return idx ;
280
+ }
281
+
200
282
}
201
283
202
284
public boolean isInitialized () {
0 commit comments