1 /*
2  * Copyright (c) 2020, 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 package test.java.util.zip;
25 
26 import org.testng.Assert;
27 import org.testng.annotations.DataProvider;
28 import org.testng.annotations.Test;
29 
30 import java.nio.ByteBuffer;
31 import java.util.Arrays;
32 import java.util.zip.Deflater;
33 import java.util.zip.Inflater;
34 
35 import static java.nio.charset.StandardCharsets.UTF_8;
36 import static org.testng.Assert.assertThrows;
37 
38 /**
39  * @test
40  * @bug 8252739
41  * @summary Verify Deflater.setDictionary(dictionary, offset, length) uses the offset
42  * @run testng/othervm DeflaterDictionaryTests
43  */
44 public class DeflaterDictionaryTests {
45     // Output buffer size
46     private static final int RESULT_SIZE = 1024;
47     // Data to compress
48     private static final String SRC_DATA = "Welcome to the US Open;".repeat(6);
49     // Dictionary to be used
50     private static final String DICTIONARY = "US Open";
51     private static final int DICTIONARY_OFFSET = 1;
52     private static final int DICTIONARY_LENGTH = 3;
53 
54     /**
55      * DataProvider with offsets which should be valid for setDictionary
56      *
57      * @return valid offset values
58      */
59     @DataProvider(name = "validDictionaryOffsets")
validDictionaryOffsets()60     protected Object[][] validDictionaryOffsets() {
61         return new Object[][]{
62                 {0},
63                 {DICTIONARY_OFFSET},
64                 {DICTIONARY_LENGTH}
65         };
66     }
67 
68     /**
69      * DataProvider with  invalid offsets for setDictionary
70      *
71      * @return invalid offset values
72      */
73     @DataProvider(name = "invalidDictionaryOffsets")
invalidDictionaryOffsets()74     protected Object[][] invalidDictionaryOffsets() {
75         return new Object[][]{
76                 {-1},
77                 {DICTIONARY_LENGTH + 2},
78                 {DICTIONARY.length()}
79         };
80     }
81 
82     /**
83      * Validate that an offset can be used with Deflater::setDictionary
84      *
85      * @param dictionary_offset offset value to be used
86      * @throws Exception if an error occurs
87      */
88     @Test(dataProvider = "validDictionaryOffsets")
testByteArray(int dictionary_offset)89     public void testByteArray(int dictionary_offset) throws Exception {
90         byte[] input = SRC_DATA.getBytes(UTF_8);
91         byte[] output = new byte[RESULT_SIZE];
92         Deflater deflater = new Deflater();
93         Inflater inflater = new Inflater();
94         try {
95             // Compress the bytes
96             deflater.setDictionary(DICTIONARY.getBytes(UTF_8), dictionary_offset, DICTIONARY_LENGTH);
97             deflater.setInput(input);
98             deflater.finish();
99             int compressedDataLength = deflater.deflate(output, 0, output.length, Deflater.NO_FLUSH);
100             System.out.printf("Deflater::getTotalOut:%s, Deflater::getAdler: %s," +
101                             " compressed length: %s%n", deflater.getTotalOut(),
102                     deflater.getTotalOut(), compressedDataLength);
103             deflater.finished();
104 
105             // Decompress the bytes
106             inflater.setInput(output, 0, compressedDataLength);
107             byte[] result = new byte[RESULT_SIZE];
108             int resultLength = inflater.inflate(result);
109             if (inflater.needsDictionary()) {
110                 System.out.println("Specifying Dictionary");
111                 inflater.setDictionary(DICTIONARY.getBytes(UTF_8), dictionary_offset, DICTIONARY_LENGTH);
112                 resultLength = inflater.inflate(result);
113             } else {
114                 System.out.println("Did not need to use a Dictionary");
115             }
116             inflater.finished();
117             System.out.printf("Inflater::getAdler:%s, length: %s%n",
118                     inflater.getAdler(), resultLength);
119 
120             Assert.assertEquals(SRC_DATA.length(), resultLength);
121             Assert.assertEquals(input, Arrays.copyOf(result, resultLength));
122         } finally {
123             // Release Resources
124             deflater.end();
125             inflater.end();
126         }
127     }
128 
129     /**
130      * Validate that a ByteBuffer can be used with Deflater::setDictionary
131      *
132      * @throws Exception if an error occurs
133      */
134     @Test
testHeapByteBuffer()135     public void testHeapByteBuffer() throws Exception {
136         byte[] input = SRC_DATA.getBytes(UTF_8);
137         byte[] output = new byte[RESULT_SIZE];
138         ByteBuffer dictDef = ByteBuffer.wrap(DICTIONARY.getBytes(UTF_8), DICTIONARY_OFFSET, DICTIONARY_LENGTH);
139         ByteBuffer dictInf = ByteBuffer.wrap(DICTIONARY.getBytes(UTF_8), DICTIONARY_OFFSET, DICTIONARY_LENGTH);
140         Deflater deflater = new Deflater();
141         Inflater inflater = new Inflater();
142         try {
143             // Compress the bytes
144             deflater.setDictionary(dictDef);
145             deflater.setInput(input);
146             deflater.finish();
147             int compressedDataLength = deflater.deflate(output, 0, output.length, Deflater.NO_FLUSH);
148             System.out.printf("Deflater::getTotalOut:%s, Deflater::getAdler: %s," +
149                             " compressed length: %s%n", deflater.getTotalOut(),
150                     deflater.getTotalOut(), compressedDataLength);
151             deflater.finished();
152 
153             // Decompress the bytes
154             inflater.setInput(output, 0, compressedDataLength);
155             byte[] result = new byte[RESULT_SIZE];
156             int resultLength = inflater.inflate(result);
157             if (inflater.needsDictionary()) {
158                 System.out.println("Specifying Dictionary");
159                 inflater.setDictionary(dictInf);
160                 resultLength = inflater.inflate(result);
161             } else {
162                 System.out.println("Did not need to use a Dictionary");
163             }
164             inflater.finished();
165             System.out.printf("Inflater::getAdler:%s, length: %s%n",
166                     inflater.getAdler(), resultLength);
167 
168             Assert.assertEquals(SRC_DATA.length(), resultLength);
169             Assert.assertEquals(input, Arrays.copyOf(result, resultLength));
170         } finally {
171             // Release Resources
172             deflater.end();
173             inflater.end();
174         }
175     }
176 
177     /**
178      * Validate that ByteBuffer::allocateDirect can be used with Deflater::setDictionary
179      *
180      * @throws Exception if an error occurs
181      */
182     @Test
testByteBufferDirect()183     public void testByteBufferDirect() throws Exception {
184         byte[] input = SRC_DATA.getBytes(UTF_8);
185         byte[] output = new byte[RESULT_SIZE];
186         ByteBuffer dictDef = ByteBuffer.allocateDirect(DICTIONARY.length());
187         ByteBuffer dictInf = ByteBuffer.allocateDirect(DICTIONARY.length());
188         dictDef.put(DICTIONARY.getBytes(UTF_8));
189         dictInf.put(DICTIONARY.getBytes(UTF_8));
190         dictDef.position(DICTIONARY_OFFSET);
191         dictDef.limit(DICTIONARY_LENGTH);
192         dictInf.position(DICTIONARY_OFFSET);
193         dictInf.limit(DICTIONARY_LENGTH);
194         Deflater deflater = new Deflater();
195         Inflater inflater = new Inflater();
196         try {
197             // Compress the bytes
198             deflater.setDictionary(dictDef.slice());
199             deflater.setInput(input);
200             deflater.finish();
201             int compressedDataLength = deflater.deflate(output, 0, output.length, Deflater.NO_FLUSH);
202             System.out.printf("Deflater::getTotalOut:%s, Deflater::getAdler: %s," +
203                             " compressed length: %s%n", deflater.getTotalOut(),
204                     deflater.getTotalOut(), compressedDataLength);
205             deflater.finished();
206 
207             // Decompress the bytes
208             inflater.setInput(output, 0, compressedDataLength);
209             byte[] result = new byte[RESULT_SIZE];
210             int resultLength = inflater.inflate(result);
211             if (inflater.needsDictionary()) {
212                 System.out.println("Specifying Dictionary");
213                 inflater.setDictionary(dictInf.slice());
214                 resultLength = inflater.inflate(result);
215             } else {
216                 System.out.println("Did not need to use a Dictionary");
217             }
218             inflater.finished();
219             System.out.printf("Inflater::getAdler:%s, length: %s%n",
220                     inflater.getAdler(), resultLength);
221 
222             Assert.assertEquals(SRC_DATA.length(), resultLength);
223             Assert.assertEquals(input, Arrays.copyOf(result, resultLength));
224         } finally {
225             // Release Resources
226             deflater.end();
227             inflater.end();
228         }
229     }
230 
231     /**
232      * Validate that an invalid offset used with setDictionary will
233      * throw an Exception
234      *
235      * @param dictionary_offset offset value to be used
236      */
237     @Test(dataProvider = "invalidDictionaryOffsets")
testInvalidOffsets(int dictionary_offset)238     public void testInvalidOffsets(int dictionary_offset) {
239         byte[] dictionary = DICTIONARY.getBytes(UTF_8);
240 
241         Deflater deflater = new Deflater();
242         Inflater inflater = new Inflater();
243         try {
244             assertThrows(ArrayIndexOutOfBoundsException.class, () ->
245                     deflater.setDictionary(dictionary, dictionary_offset, DICTIONARY_LENGTH));
246             assertThrows(ArrayIndexOutOfBoundsException.class, () ->
247                     inflater.setDictionary(dictionary, dictionary_offset, DICTIONARY_LENGTH));
248         } finally {
249             // Release Resources
250             deflater.end();
251             inflater.end();
252         }
253     }
254 }