4343import static com .oracle .graal .python .builtins .PythonBuiltinClassType .ZlibCompress ;
4444import static com .oracle .graal .python .builtins .PythonBuiltinClassType .ZlibDecompress ;
4545import 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 ;
4648
49+ import java .util .zip .CRC32 ;
4750import java .util .zip .DataFormatException ;
4851import java .util .zip .Deflater ;
4952import java .util .zip .Inflater ;
5053
5154import com .oracle .graal .python .builtins .objects .bytes .PBytes ;
5255import com .oracle .graal .python .builtins .objects .object .PythonBuiltinObject ;
56+ import com .oracle .graal .python .nodes .PRaiseNode ;
5357import com .oracle .graal .python .runtime .NFIZlibSupport ;
5458import com .oracle .graal .python .runtime .object .PythonObjectFactory ;
59+ import com .oracle .graal .python .util .PythonUtils ;
5560import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
61+ import com .oracle .truffle .api .nodes .Node ;
5662import com .oracle .truffle .api .object .Shape ;
5763
5864public abstract class ZLibCompObject extends PythonBuiltinObject {
@@ -109,6 +115,7 @@ protected static class JavaZlibCompObject extends ZLibCompObject {
109115
110116 private byte [] inputData ; // helper for copy operation
111117 private boolean canCopy ; // to assist if copying is allowed
118+ private boolean readHeader ;
112119
113120 public JavaZlibCompObject (Object cls , Shape instanceShape , Object stream , int level , int wbits , int strategy , byte [] zdict ) {
114121 super (cls , instanceShape );
@@ -119,6 +126,7 @@ public JavaZlibCompObject(Object cls, Shape instanceShape, Object stream, int le
119126 this .strategy = strategy ;
120127 this .inputData = null ;
121128 this .canCopy = true ;
129+ this .readHeader = wbits >= 25 && wbits <= 31 ;
122130 }
123131
124132 public JavaZlibCompObject (Object cls , Shape instanceShape , Object stream , int wbits , byte [] zdict ) {
@@ -146,11 +154,17 @@ public void setDeflaterInput(byte[] data) {
146154 }
147155
148156 @ TruffleBoundary
149- public void setInflaterInput (byte [] data ) {
157+ public void setInflaterInput (byte [] data , Node node ) {
150158 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+ }
151165 canCopy = inputData == null ;
152- inputData = data ;
153- ((Inflater ) stream ).setInput (data );
166+ inputData = bytes ;
167+ ((Inflater ) stream ).setInput (bytes );
154168 }
155169
156170 @ TruffleBoundary
@@ -172,7 +186,7 @@ public ZLibCompObject copyCompressObj(PythonObjectFactory factory) {
172186 }
173187
174188 @ TruffleBoundary
175- public ZLibCompObject copyDecompressObj (PythonObjectFactory factory ) {
189+ public ZLibCompObject copyDecompressObj (PythonObjectFactory factory , Node node ) {
176190 assert canCopy ;
177191 boolean isRAW = wbits < 0 ;
178192 Inflater inflater = new Inflater (isRAW || wbits > (MAX_WBITS + 9 ));
@@ -182,7 +196,7 @@ public ZLibCompObject copyDecompressObj(PythonObjectFactory factory) {
182196 ZLibCompObject obj = factory .createJavaZLibCompObject (ZlibDecompress , inflater , wbits , zdict );
183197 if (inputData != null ) {
184198 try {
185- ((JavaZlibCompObject ) obj ).setInflaterInput (inputData );
199+ ((JavaZlibCompObject ) obj ).setInflaterInput (inputData , node );
186200 inflater .setInput (inputData );
187201 int n = inflater .inflate (new byte [ZLibModuleBuiltins .DEF_BUF_SIZE ]);
188202 if (!isRAW && n == 0 && inflater .needsDictionary () && zdict .length > 0 ) {
@@ -197,6 +211,74 @@ public ZLibCompObject copyDecompressObj(PythonObjectFactory factory) {
197211 obj .setUnusedData (getUnusedData ());
198212 return obj ;
199213 }
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+
200282 }
201283
202284 public boolean isInitialized () {
0 commit comments