1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 7110149 8184306 6341887 27 * @summary Test basic deflater & inflater functionality 28 * @key randomness 29 */ 30 31 import java.io.*; 32 import java.nio.*; 33 import java.util.*; 34 import java.util.zip.*; 35 36 import static java.nio.charset.StandardCharsets.UTF_8; 37 38 public class DeInflate { 39 40 private static Random rnd = new Random(); 41 42 checkStream(Deflater def, byte[] in, int len, byte[] out1, byte[] out2, boolean nowrap)43 static void checkStream(Deflater def, byte[] in, int len, 44 byte[] out1, byte[] out2, boolean nowrap) 45 throws Throwable 46 { 47 Arrays.fill(out1, (byte)0); 48 Arrays.fill(out2, (byte)0); 49 50 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 51 try (DeflaterOutputStream defos = new DeflaterOutputStream(baos, def)) { 52 defos.write(in, 0, len); 53 } 54 out1 = baos.toByteArray(); 55 int m = out1.length; 56 57 Inflater inf = new Inflater(nowrap); 58 inf.setInput(out1, 0, m); 59 int n = inf.inflate(out2); 60 61 if (n != len || 62 !Arrays.equals(Arrays.copyOf(in, len), Arrays.copyOf(out2, len)) || 63 inf.inflate(out2) != 0) { 64 System.out.printf("m=%d, n=%d, len=%d, eq=%b%n", 65 m, n, len, Arrays.equals(in, out2)); 66 throw new RuntimeException("De/inflater failed:" + def); 67 } 68 } 69 checkByteBuffer(Deflater def, Inflater inf, ByteBuffer in, ByteBuffer out1, ByteBuffer out2, byte[] expected, int len, byte[] result, boolean out1ReadOnlyWhenInflate)70 static void checkByteBuffer(Deflater def, Inflater inf, 71 ByteBuffer in, ByteBuffer out1, ByteBuffer out2, 72 byte[] expected, int len, byte[] result, 73 boolean out1ReadOnlyWhenInflate) 74 throws Throwable { 75 def.reset(); 76 inf.reset(); 77 78 def.setInput(in); 79 def.finish(); 80 int m = def.deflate(out1); 81 82 out1.flip(); 83 if (out1ReadOnlyWhenInflate) 84 out1 = out1.asReadOnlyBuffer(); 85 inf.setInput(out1); 86 int n = inf.inflate(out2); 87 88 out2.flip(); 89 out2.get(result, 0, n); 90 91 if (n != len || out2.position() != len || 92 !Arrays.equals(Arrays.copyOf(expected, len), Arrays.copyOf(result, len)) || 93 inf.inflate(result) != 0) { 94 throw new RuntimeException("De/inflater(buffer) failed:" + def); 95 } 96 } 97 checkByteBufferReadonly(Deflater def, Inflater inf, ByteBuffer in, ByteBuffer out1, ByteBuffer out2)98 static void checkByteBufferReadonly(Deflater def, Inflater inf, 99 ByteBuffer in, ByteBuffer out1, ByteBuffer out2) 100 throws Throwable { 101 def.reset(); 102 inf.reset(); 103 def.setInput(in); 104 def.finish(); 105 int m = -1; 106 if (!out2.isReadOnly()) 107 out2 = out2.asReadOnlyBuffer(); 108 try { 109 m = def.deflate(out2); 110 throw new RuntimeException("deflater: ReadOnlyBufferException: failed"); 111 } catch (ReadOnlyBufferException robe) {} 112 m = def.deflate(out1); 113 out1.flip(); 114 inf.setInput(out1); 115 try { 116 inf.inflate(out2); 117 throw new RuntimeException("inflater: ReadOnlyBufferException: failed"); 118 } catch (ReadOnlyBufferException robe) {} 119 } 120 check(Deflater def, byte[] in, int len, byte[] out1, byte[] out2, boolean nowrap)121 static void check(Deflater def, byte[] in, int len, 122 byte[] out1, byte[] out2, boolean nowrap) 123 throws Throwable 124 { 125 Arrays.fill(out1, (byte)0); 126 Arrays.fill(out2, (byte)0); 127 128 def.setInput(in, 0, len); 129 def.finish(); 130 int m = def.deflate(out1); 131 132 Inflater inf = new Inflater(nowrap); 133 inf.setInput(out1, 0, m); 134 int n = inf.inflate(out2); 135 136 if (n != len || 137 !Arrays.equals(Arrays.copyOf(in, len), Arrays.copyOf(out2, len)) || 138 inf.inflate(out2) != 0) { 139 System.out.printf("m=%d, n=%d, len=%d, eq=%b%n", 140 m, n, len, Arrays.equals(in, out2)); 141 throw new RuntimeException("De/inflater failed:" + def); 142 } 143 144 // readable 145 Arrays.fill(out1, (byte)0); 146 Arrays.fill(out2, (byte)0); 147 ByteBuffer bbIn = ByteBuffer.wrap(in, 0, len); 148 ByteBuffer bbOut1 = ByteBuffer.wrap(out1); 149 ByteBuffer bbOut2 = ByteBuffer.wrap(out2); 150 checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false); 151 checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2); 152 153 // readonly in 154 Arrays.fill(out1, (byte)0); 155 Arrays.fill(out2, (byte)0); 156 bbIn = ByteBuffer.wrap(in, 0, len).asReadOnlyBuffer(); 157 bbOut1 = ByteBuffer.wrap(out1); 158 bbOut2 = ByteBuffer.wrap(out2); 159 checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false); 160 checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2); 161 162 // readonly out1 when inflate 163 Arrays.fill(out1, (byte)0); 164 Arrays.fill(out2, (byte)0); 165 bbIn = ByteBuffer.wrap(in, 0, len); 166 bbOut1 = ByteBuffer.wrap(out1); 167 bbOut2 = ByteBuffer.wrap(out2); 168 checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, true); 169 checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2); 170 171 // direct 172 bbIn = ByteBuffer.allocateDirect(in.length); 173 bbIn.put(in, 0, n).flip(); 174 bbOut1 = ByteBuffer.allocateDirect(out1.length); 175 bbOut2 = ByteBuffer.allocateDirect(out2.length); 176 checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false); 177 checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2); 178 } 179 checkDict(Deflater def, Inflater inf, byte[] src, byte[] dstDef, byte[] dstInf, ByteBuffer dictDef, ByteBuffer dictInf)180 static void checkDict(Deflater def, Inflater inf, byte[] src, 181 byte[] dstDef, byte[] dstInf, 182 ByteBuffer dictDef, ByteBuffer dictInf) throws Throwable { 183 def.reset(); 184 inf.reset(); 185 186 def.setDictionary(dictDef); 187 def.setInput(src); 188 def.finish(); 189 int n = def.deflate(dstDef); 190 191 inf.setInput(dstDef, 0, n); 192 n = inf.inflate(dstInf); 193 if (n != 0 || !inf.needsDictionary()) { 194 throw new RuntimeException("checkDict failed: need dict to continue"); 195 } 196 inf.setDictionary(dictInf); 197 n = inf.inflate(dstInf); 198 // System.out.println("result: " + new String(dstInf, 0, n)); 199 if (n != src.length || !Arrays.equals(Arrays.copyOf(dstInf, n), src)) { 200 throw new RuntimeException("checkDict failed: inflate result"); 201 } 202 } 203 checkDict(int level, int strategy)204 static void checkDict(int level, int strategy) throws Throwable { 205 206 Deflater def = newDeflater(level, strategy, false, new byte[0]); 207 Inflater inf = new Inflater(); 208 209 byte[] src = "hello world, hello world, hello sherman".getBytes(); 210 byte[] dict = "hello".getBytes(); 211 212 byte[] dstDef = new byte[1024]; 213 byte[] dstInf = new byte[1024]; 214 215 def.setDictionary(dict); 216 def.setInput(src); 217 def.finish(); 218 int n = def.deflate(dstDef); 219 220 inf.setInput(dstDef, 0, n); 221 n = inf.inflate(dstInf); 222 if (n != 0 || !inf.needsDictionary()) { 223 throw new RuntimeException("checkDict failed: need dict to continue"); 224 } 225 inf.setDictionary(dict); 226 n = inf.inflate(dstInf); 227 //System.out.println("result: " + new String(dstInf, 0, n)); 228 if (n != src.length || !Arrays.equals(Arrays.copyOf(dstInf, n), src)) { 229 throw new RuntimeException("checkDict failed: inflate result"); 230 } 231 232 ByteBuffer dictDef = ByteBuffer.wrap(dict); 233 ByteBuffer dictInf = ByteBuffer.wrap(dict); 234 checkDict(def, inf, src, dstDef, dstInf, dictDef, dictInf); 235 236 dictDef = ByteBuffer.allocateDirect(dict.length); 237 dictInf = ByteBuffer.allocateDirect(dict.length); 238 dictDef.put(dict).flip(); 239 dictInf.put(dict).flip(); 240 checkDict(def, inf, src, dstDef, dstInf, dictDef, dictInf); 241 242 def.end(); 243 inf.end(); 244 } 245 newDeflater(int level, int strategy, boolean dowrap, byte[] tmp)246 private static Deflater newDeflater(int level, int strategy, boolean dowrap, byte[] tmp) { 247 Deflater def = new Deflater(level, dowrap); 248 if (strategy != Deflater.DEFAULT_STRATEGY) { 249 def.setStrategy(strategy); 250 // The first invocation after setLevel/Strategy() 251 // with a different level/stragety returns 0, if 252 // there is no need to flush out anything for the 253 // previous setting/"data", this is tricky and 254 // appears un-documented. 255 def.deflate(tmp); 256 } 257 return def; 258 } 259 resetDeflater(Deflater def, int level, int strategy)260 private static Deflater resetDeflater(Deflater def, int level, int strategy) { 261 def.setLevel(level); 262 def.setStrategy(strategy); 263 def.reset(); 264 return def; 265 } 266 main(String[] args)267 public static void main(String[] args) throws Throwable { 268 269 byte[] dataIn = new byte[1024 * 512]; 270 rnd.nextBytes(dataIn); 271 byte[] dataOut1 = new byte[dataIn.length + 1024]; 272 byte[] dataOut2 = new byte[dataIn.length]; 273 274 Deflater defNotWrap = new Deflater(Deflater.DEFAULT_COMPRESSION, false); 275 Deflater defWrap = new Deflater(Deflater.DEFAULT_COMPRESSION, true); 276 277 for (int level = Deflater.DEFAULT_COMPRESSION; 278 level <= Deflater.BEST_COMPRESSION; level++) { 279 for (int strategy = Deflater.DEFAULT_STRATEGY; 280 strategy <= Deflater.HUFFMAN_ONLY; strategy++) { 281 for (boolean dowrap : new boolean[] { false, true }) { 282 System.out.println("level:" + level + 283 ", strategy: " + strategy + 284 ", dowrap: " + dowrap); 285 for (int i = 0; i < 5; i++) { 286 int len = (i == 0)? dataIn.length 287 : new Random().nextInt(dataIn.length); 288 // use a new deflater 289 Deflater def = newDeflater(level, strategy, dowrap, dataOut2); 290 check(def, dataIn, len, dataOut1, dataOut2, dowrap); 291 def.end(); 292 293 // reuse the deflater (with reset) and test on stream, which 294 // uses a "smaller" buffer (smaller than the overall data) 295 def = resetDeflater(dowrap ? defWrap : defNotWrap, level, strategy); 296 checkStream(def, dataIn, len, dataOut1, dataOut2, dowrap); 297 } 298 } 299 // test setDictionary() 300 checkDict(level, strategy); 301 } 302 } 303 } 304 } 305