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