13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/* 23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Copyright (C) 2014 Square, Inc. 33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * you may not use this file except in compliance with the License. 63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * You may obtain a copy of the License at 73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Unless required by applicable law or agreed to in writing, software 113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * See the License for the specific language governing permissions and 143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * limitations under the License. 153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage okio; 173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.IOException; 193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.zip.CRC32; 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport org.junit.Test; 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static okio.Util.UTF_8; 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertEquals; 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertFalse; 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertTrue; 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.fail; 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic class GzipSourceTest { 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzip() throws Exception { 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeader); 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertGzipped(gzipped); 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzip_withHCRC() throws Exception { 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller CRC32 hcrc = new CRC32(); 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ByteString gzipHeader = gzipHeaderWithFlags((byte) 0x02); 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller hcrc.update(gzipHeader.toByteArray()); 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeader); 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeShort(Util.reverseBytesShort((short) hcrc.getValue())); // little endian 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertGzipped(gzipped); 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzip_withExtra() throws Exception { 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeaderWithFlags((byte) 0x04)); 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeShort(Util.reverseBytesShort((short) 7)); // little endian extra length 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write("blubber".getBytes(UTF_8), 0, 7); 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertGzipped(gzipped); 593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzip_withName() throws Exception { 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeaderWithFlags((byte) 0x08)); 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write("foo.txt".getBytes(UTF_8), 0, 7); 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeByte(0); // zero-terminated 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertGzipped(gzipped); 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzip_withComment() throws Exception { 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeaderWithFlags((byte) 0x10)); 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write("rubbish".getBytes(UTF_8), 0, 7); 753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeByte(0); // zero-terminated 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertGzipped(gzipped); 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * For portability, it is a good idea to export the gzipped bytes and try running gzip. Ex. 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * {@code echo gzipped | base64 --decode | gzip -l -v} 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzip_withAll() throws Exception { 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeaderWithFlags((byte) 0x1c)); 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeShort(Util.reverseBytesShort((short) 7)); // little endian extra length 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write("blubber".getBytes(UTF_8), 0, 7); 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write("foo.txt".getBytes(UTF_8), 0, 7); 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeByte(0); // zero-terminated 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write("rubbish".getBytes(UTF_8), 0, 7); 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeByte(0); // zero-terminated 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertGzipped(gzipped); 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private void assertGzipped(OkBuffer gzipped) throws IOException { 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gunzipped = gunzip(gzipped); 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("It's a UNIX system! I know this!", gunzipped.readUtf8(gunzipped.size())); 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Note that you cannot test this with old versions of gzip, as they interpret flag bit 1 as 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * CONTINUATION, not HCRC. For example, this is the case with the default gzip on osx. 1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzipWhenHeaderCRCIncorrect() throws Exception { 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeaderWithFlags((byte) 0x02)); 1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeShort((short) 0); // wrong HCRC! 1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer); 1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gunzip(gzipped); 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IOException e) { 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("FHCRC: actual 0x0000261d != expected 0x00000000", e.getMessage()); 1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzipWhenCRCIncorrect() throws Exception { 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeader); 1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeInt(Util.reverseBytesInt(0x1234567)); // wrong CRC 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer.toByteArray(), 3, 4); 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gunzip(gzipped); 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IOException e) { 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("CRC: actual 0x37ad8f8d != expected 0x01234567", e.getMessage()); 1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzipWhenLengthIncorrect() throws Exception { 1393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzipped = new OkBuffer(); 1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipHeader); 1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(deflated); 1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.write(gzipTrailer.toByteArray(), 0, 4); 1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzipped.writeInt(Util.reverseBytesInt(0x123456)); // wrong length 1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gunzip(gzipped); 1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IOException e) { 1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("ISIZE: actual 0x00000020 != expected 0x00123456", e.getMessage()); 1503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzipExhaustsSource() throws Exception { 1543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzippedSource = new OkBuffer() 1553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .write(ByteString.decodeHex("1f8b08000000000000004b4c4a0600c241243503000000")); // 'abc' 1563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ExhaustableSource exhaustableSource = new ExhaustableSource(gzippedSource); 1583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller BufferedSource gunzippedSource = Okio.buffer(new GzipSource(exhaustableSource)); 1593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals('a', gunzippedSource.readByte()); 1613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals('b', gunzippedSource.readByte()); 1623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals('c', gunzippedSource.readByte()); 1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertFalse(exhaustableSource.exhausted); 1643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(-1, gunzippedSource.read(new OkBuffer(), 1)); 1653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertTrue(exhaustableSource.exhausted); 1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void gunzipThrowsIfSourceIsNotExhausted() throws Exception { 1693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer gzippedSource = new OkBuffer() 1703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .write(ByteString.decodeHex("1f8b08000000000000004b4c4a0600c241243503000000")); // 'abc' 1713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gzippedSource.writeByte('d'); // This byte shouldn't be here! 1723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller BufferedSource gunzippedSource = Okio.buffer(new GzipSource(gzippedSource)); 1743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals('a', gunzippedSource.readByte()); 1763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals('b', gunzippedSource.readByte()); 1773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals('c', gunzippedSource.readByte()); 1783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 1793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller gunzippedSource.readByte(); 1803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 1813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IOException expected) { 1823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private ByteString gzipHeaderWithFlags(byte flags) { 1863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller byte[] result = gzipHeader.toByteArray(); 1873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result[3] = flags; 1883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return ByteString.of(result); 1893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final ByteString gzipHeader = ByteString.decodeHex("1f8b0800000000000000"); 1923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Deflated "It's a UNIX system! I know this!" 1943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final ByteString deflated = ByteString.decodeHex( 1953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller "f32c512f56485408f5f38c5028ae2c2e49cd5554f054c8cecb2f5728c9c82c560400"); 1963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final ByteString gzipTrailer = ByteString.decodeHex("" 1983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller + "8d8fad37" // Checksum of deflated. 1993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller + "20000000" // 32 in little endian. 2003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ); 2013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private OkBuffer gunzip(OkBuffer gzipped) throws IOException { 2033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer result = new OkBuffer(); 2043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller GzipSource source = new GzipSource(gzipped); 2053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (source.read(result, Integer.MAX_VALUE) != -1) { 2063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 2083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** This source keeps track of whether its read have returned -1. */ 2113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static class ExhaustableSource implements Source { 2123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final Source source; 2133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private boolean exhausted; 2143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ExhaustableSource(Source source) { 2163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.source = source; 2173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public long read(OkBuffer sink, long byteCount) throws IOException { 2203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller long result = source.read(sink, byteCount); 2213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (result == -1) exhausted = true; 2223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 2233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public Source deadline(Deadline deadline) { 2263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.deadline(deadline); 2273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return this; 2283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void close() throws IOException { 2313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller source.close(); 2323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 235