1 /*
   2  * Copyright (c) 2011, 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 6571338
  27  * @summary Inflater should not require a buffer to the inflate() methods
  28  * larger than 1 byte.
  29  * @key randomness
  30  */
  31 
  32 import java.io.*;
  33 import java.nio.*;
  34 import java.util.*;
  35 import java.util.zip.*;
  36 
  37 public class InflaterBufferSize {
  38     private static final int DATA_LEN = 1024 *64;
  39     private static byte[] data;
  40 
  41     // If true, print extra info.
  42     private static final boolean debug = System.getProperty("debug") != null;
  43 
  44     private static void debug(String s) {
  45         if (debug) System.out.println(s);
  46     }
  47 
  48     private static void createData() {
  49         ByteBuffer bb = ByteBuffer.allocate(8);
  50         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  51         for (int i = 0; i < DATA_LEN; i++) {
  52             bb.putDouble(0, Math.random());
  53             baos.write(bb.array(), 0, 8);
  54         }
  55         data = baos.toByteArray();
  56     }
  57 
  58     private static byte[] grow(byte[] a, int capacity) {
  59         while (a.length < capacity) {
  60             byte[] a2 = new byte[a.length * 2];
  61             System.arraycopy(a, 0, a2, 0, a.length);
  62             a = a2;
  63         }
  64         return a;
  65     }
  66 
  67     private static byte[] trim(byte[] a, int length) {
  68         byte[] res = new byte[length];
  69         System.arraycopy(a, 0, res, 0, length);
  70         return res;
  71     }
  72 
  73     private static byte[] deflate(byte[] in, int level) throws Throwable {
  74         final Deflater flater = new Deflater(level);
  75         flater.setInput(in);
  76         flater.finish();
  77         final byte[] smallBuffer = new byte[32];
  78         byte[] flated = new byte[32];
  79         int count = 0;
  80         int n;
  81         while ((n = flater.deflate(smallBuffer)) > 0) {
  82             flated = grow(flated, count + n);
  83             System.arraycopy(smallBuffer, 0, flated, count, n);
  84             count += n;
  85         }
  86         return trim(flated, count);
  87     }
  88 
  89     private static byte[] inflate(byte[] in) throws Throwable {
  90         final Inflater flater = new Inflater();
  91         flater.setInput(in);
  92         // This is the buffer of interest.  It should be possible to use any
  93         // non-zero size.
  94         final byte[] smallBuffer = new byte[1];
  95         byte[] flated = new byte[32];
  96         int count = 0;
  97         int n;
  98         while ((n = flater.inflate(smallBuffer)) > 0) {
  99             flated = grow(flated, count + n);
 100             System.arraycopy(smallBuffer, 0, flated, count, n);
 101             count += n;
 102         }
 103         return trim(flated, count);
 104     }
 105 
 106     public static void realMain(String[] args) throws Throwable {
 107         byte deflated[], inflated[];
 108 
 109         int level = -1;
 110         if (args.length > 0) {
 111           level = Integer.parseInt(args[0]);
 112         }
 113         debug("Using level " + level);
 114 
 115         if (args.length > 1) {
 116             FileInputStream fis = new FileInputStream(args[1]);
 117             int len = fis.available();
 118             data = new byte[len];
 119             check(fis.read(data, 0, len) == len, "Did not read complete file");
 120             debug("Original data from " + args[1]);
 121             fis.close();
 122         } else {
 123             createData();
 124             debug("Original data from random byte array");
 125         }
 126         debug("Original data length: " + data.length + " bytes");
 127 
 128         debug("");
 129         deflated = deflate(data, level);
 130         debug("Deflated data length: " + deflated.length + " bytes");
 131 
 132         inflated = inflate(deflated);
 133         debug("Inflated data length: "+ inflated.length + " bytes" );
 134 
 135         if (!check(Arrays.equals(data, inflated),
 136                    "Inflated and deflated arrays do not match")) {
 137             OutputStream os = new BufferedOutputStream(new FileOutputStream("deflated.zip"));
 138             try {
 139                 os.write(deflated);
 140             } finally {
 141                 os.close();
 142             }
 143         }
 144     }
 145 
 146     //--------------------- Infrastructure ---------------------------
 147     static volatile int passed = 0, failed = 0;
 148     static void pass() {passed++;}
 149     static void pass(String msg) {System.out.println(msg); passed++;}
 150     static void fail() {failed++; Thread.dumpStack();}
 151     static void fail(String msg) {System.out.println(msg); fail();}
 152     static void unexpected(Throwable t) {failed++; t.printStackTrace();}
 153     static void unexpected(Throwable t, String msg) {
 154         System.out.println(msg); failed++; t.printStackTrace();}
 155     static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
 156     static boolean check(boolean cond, String msg) {if (cond) pass(); else fail(msg); return cond;}
 157     static void equal(Object x, Object y) {
 158         if (x == null ? y == null : x.equals(y)) pass();
 159         else fail(x + " not equal to " + y);}
 160     public static void main(String[] args) throws Throwable {
 161         try {realMain(args);} catch (Throwable t) {unexpected(t);}
 162         System.out.println("\nPassed = " + passed + " failed = " + failed);
 163         if (failed > 0) throw new AssertionError("Some tests failed");}
 164 }