12d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes/*
22d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * Copyright (C) 2010 The Android Open Source Project
32d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *
42d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
52d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * you may not use this file except in compliance with the License.
62d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * You may obtain a copy of the License at
72d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *
82d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
92d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *
102d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * Unless required by applicable law or agreed to in writing, software
112d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
122d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * See the License for the specific language governing permissions and
142d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * limitations under the License.
152d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes */
162d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
172d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughespackage libcore.java.util.zip;
182d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
192d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesimport java.io.ByteArrayOutputStream;
202d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesimport java.util.zip.Adler32;
212d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesimport java.util.zip.Deflater;
222d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesimport java.util.zip.Inflater;
232d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesimport junit.framework.TestCase;
242d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
252d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughespublic class InflaterTest extends TestCase {
262d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    public void testDefaultDictionary() throws Exception {
272d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        assertRoundTrip(null);
282d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    }
292d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
302d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    public void testPresetCustomDictionary() throws Exception {
31aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        assertRoundTrip("dictionary".getBytes("UTF-8"));
322d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    }
332d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
342d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private static void assertRoundTrip(byte[] dictionary) throws Exception {
352d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // Construct a nice long input byte sequence.
362d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        String expected = makeString();
372d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        byte[] expectedBytes = expected.getBytes("UTF-8");
382d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
392d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // Compress the bytes, using the passed-in dictionary (or no dictionary).
402d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        byte[] deflatedBytes = deflate(expectedBytes, dictionary);
412d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
42aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        // Get ready to decompress deflatedBytes back to the original bytes ...
432d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        Inflater inflater = new Inflater();
442d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // We'll only supply the input a little bit at a time, so that zlib has to ask for more.
452d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        final int CHUNK_SIZE = 16;
462d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        int offset = 0;
472d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        inflater.setInput(deflatedBytes, offset, CHUNK_SIZE);
482d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        offset += CHUNK_SIZE;
492d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // If we used a dictionary to compress, check that we're asked for that same dictionary.
502d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        if (dictionary != null) {
512d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            // 1. there's no data available immediately...
522d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            assertEquals(0, inflater.inflate(new byte[8]));
532d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            // 2. ...because you need a dictionary.
542d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            assertTrue(inflater.needsDictionary());
552d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            // 3. ...and that dictionary has the same Adler32 as the dictionary we used.
562d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            assertEquals(adler32(dictionary), inflater.getAdler());
572d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            inflater.setDictionary(dictionary);
582d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        }
592d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // Do the actual decompression, now the dictionary's set up appropriately...
602d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // We use a tiny output buffer to ensure that we call inflate multiple times, and
612d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        // a tiny input buffer to ensure that zlib has to ask for more input.
622d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        ByteArrayOutputStream inflatedBytes = new ByteArrayOutputStream();
632d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        byte[] buf = new byte[8];
642d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        while (inflatedBytes.size() != expectedBytes.length) {
652d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            if (inflater.needsInput()) {
662d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                int nextChunkByteCount = Math.min(CHUNK_SIZE, deflatedBytes.length - offset);
672d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                inflater.setInput(deflatedBytes, offset, nextChunkByteCount);
682d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                offset += nextChunkByteCount;
692d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            } else {
702d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                int inflatedByteCount = inflater.inflate(buf);
712d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                if (inflatedByteCount > 0) {
722d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                    inflatedBytes.write(buf, 0, inflatedByteCount);
732d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes                }
742d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            }
752d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        }
762d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        inflater.end();
772d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
782d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        assertEquals(expected, new String(inflatedBytes.toByteArray(), "UTF-8"));
792d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    }
802d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
812d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private static String makeString() {
822d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        StringBuilder sb = new StringBuilder();
832d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        for (int i = 0; i < 1024; ++i) {
84aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes            // This is arbitrary but convenient in that it gives our string
85aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes            // an easily-recognizable beginning and end.
862d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            sb.append(i + 1024);
872d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        }
882d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        return sb.toString();
892d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    }
902d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
91b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson    /**
92b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson     * http://code.google.com/p/android/issues/detail?id=11755
93b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson     */
94b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson    public void testEmptyFileAndEmptyBuffer() throws Exception {
95b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson        byte[] emptyInput = deflate(new byte[0], null);
96b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson        Inflater inflater = new Inflater();
97b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson        inflater.setInput(emptyInput);
98b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson        assertFalse(inflater.finished());
99b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson        assertEquals(0, inflater.inflate(new byte[0], 0, 0));
100b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson        assertTrue(inflater.finished());
101b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson    }
102b9f4eb77cf7c5937fcd33d839c749900112874bdJesse Wilson
1032d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private static byte[] deflate(byte[] input, byte[] dictionary) {
1042d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        Deflater deflater = new Deflater();
1052d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        if (dictionary != null) {
1062d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            deflater.setDictionary(dictionary);
1072d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        }
1082d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        deflater.setInput(input);
1092d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        deflater.finish();
1102d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        ByteArrayOutputStream deflatedBytes = new ByteArrayOutputStream();
1112d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        byte[] buf = new byte[8];
1122d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        while (!deflater.finished()) {
1132d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            int byteCount = deflater.deflate(buf);
1142d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes            deflatedBytes.write(buf, 0, byteCount);
1152d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        }
1162d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        deflater.end();
1172d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        return deflatedBytes.toByteArray();
1182d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    }
1192d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
1202d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private static int adler32(byte[] bytes) {
1212d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        Adler32 adler32 = new Adler32();
1222d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        adler32.update(bytes);
1232d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        return (int) adler32.getValue();
1242d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    }
1252d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes}
126