1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.util.zip.CRC32;
18 import java.util.Random;
19 import java.nio.ByteBuffer;
20 
21 /**
22  * The ART compiler can use intrinsics for the java.util.zip.CRC32 methods:
23  *   private native static int update(int crc, int b)
24  *   private native static int updateBytes(int crc, byte[] b, int off, int len)
25  *
26  * As the methods are private it is not possible to check the use of intrinsics
27  * for them directly.
28  * The tests check that correct checksums are produced.
29  */
30 public class Main {
Main()31   public Main() {
32   }
33 
CRC32Byte(int value)34   public static long CRC32Byte(int value) {
35     CRC32 crc32 = new CRC32();
36     crc32.update(value);
37     return crc32.getValue();
38   }
39 
CRC32BytesUsingUpdateInt(int... values)40   public static long CRC32BytesUsingUpdateInt(int... values) {
41     CRC32 crc32 = new CRC32();
42     for (int value : values) {
43       crc32.update(value);
44     }
45     return crc32.getValue();
46   }
47 
assertEqual(long expected, long actual)48   public static void assertEqual(long expected, long actual) {
49     if (expected != actual) {
50       throw new Error("Expected: " + expected + ", found: " + actual);
51     }
52   }
53 
assertEqual(boolean expected, boolean actual)54   private static void assertEqual(boolean expected, boolean actual) {
55     if (expected != actual) {
56       throw new Error("Expected: " + expected + ", found: " + actual);
57     }
58   }
59 
TestCRC32Update()60   private static void TestCRC32Update() {
61     // public void update(int b)
62     //
63     // Tests for checksums of the byte 0x0
64     // Check that only the low eight bits of the argument are used.
65     assertEqual(0xD202EF8DL, CRC32Byte(0x0));
66     assertEqual(0xD202EF8DL, CRC32Byte(0x0100));
67     assertEqual(0xD202EF8DL, CRC32Byte(0x010000));
68     assertEqual(0xD202EF8DL, CRC32Byte(0x01000000));
69     assertEqual(0xD202EF8DL, CRC32Byte(0xff00));
70     assertEqual(0xD202EF8DL, CRC32Byte(0xffff00));
71     assertEqual(0xD202EF8DL, CRC32Byte(0xffffff00));
72     assertEqual(0xD202EF8DL, CRC32Byte(0x1200));
73     assertEqual(0xD202EF8DL, CRC32Byte(0x123400));
74     assertEqual(0xD202EF8DL, CRC32Byte(0x12345600));
75     assertEqual(0xD202EF8DL, CRC32Byte(Integer.MIN_VALUE));
76 
77     // Tests for checksums of the byte 0x1
78     // Check that only the low eight bits of the argument are used.
79     assertEqual(0xA505DF1BL, CRC32Byte(0x1));
80     assertEqual(0xA505DF1BL, CRC32Byte(0x0101));
81     assertEqual(0xA505DF1BL, CRC32Byte(0x010001));
82     assertEqual(0xA505DF1BL, CRC32Byte(0x01000001));
83     assertEqual(0xA505DF1BL, CRC32Byte(0xff01));
84     assertEqual(0xA505DF1BL, CRC32Byte(0xffff01));
85     assertEqual(0xA505DF1BL, CRC32Byte(0xffffff01));
86     assertEqual(0xA505DF1BL, CRC32Byte(0x1201));
87     assertEqual(0xA505DF1BL, CRC32Byte(0x123401));
88     assertEqual(0xA505DF1BL, CRC32Byte(0x12345601));
89 
90     // Tests for checksums of the byte 0x0f
91     // Check that only the low eight bits of the argument are used.
92     assertEqual(0x42BDF21CL, CRC32Byte(0x0f));
93     assertEqual(0x42BDF21CL, CRC32Byte(0x010f));
94     assertEqual(0x42BDF21CL, CRC32Byte(0x01000f));
95     assertEqual(0x42BDF21CL, CRC32Byte(0x0100000f));
96     assertEqual(0x42BDF21CL, CRC32Byte(0xff0f));
97     assertEqual(0x42BDF21CL, CRC32Byte(0xffff0f));
98     assertEqual(0x42BDF21CL, CRC32Byte(0xffffff0f));
99     assertEqual(0x42BDF21CL, CRC32Byte(0x120f));
100     assertEqual(0x42BDF21CL, CRC32Byte(0x12340f));
101     assertEqual(0x42BDF21CL, CRC32Byte(0x1234560f));
102 
103     // Tests for checksums of the byte 0xff
104     // Check that only the low eight bits of the argument are used.
105     assertEqual(0xFF000000L, CRC32Byte(0x00ff));
106     assertEqual(0xFF000000L, CRC32Byte(0x01ff));
107     assertEqual(0xFF000000L, CRC32Byte(0x0100ff));
108     assertEqual(0xFF000000L, CRC32Byte(0x010000ff));
109     assertEqual(0xFF000000L, CRC32Byte(0x0000ffff));
110     assertEqual(0xFF000000L, CRC32Byte(0x00ffffff));
111     assertEqual(0xFF000000L, CRC32Byte(0xffffffff));
112     assertEqual(0xFF000000L, CRC32Byte(0x12ff));
113     assertEqual(0xFF000000L, CRC32Byte(0x1234ff));
114     assertEqual(0xFF000000L, CRC32Byte(0x123456ff));
115     assertEqual(0xFF000000L, CRC32Byte(Integer.MAX_VALUE));
116 
117     // Tests for sequences
118     // Check that only the low eight bits of the values are used.
119     assertEqual(0xFF41D912L, CRC32BytesUsingUpdateInt(0, 0, 0));
120     assertEqual(0xFF41D912L,
121                 CRC32BytesUsingUpdateInt(0x0100, 0x010000, 0x01000000));
122     assertEqual(0xFF41D912L,
123                 CRC32BytesUsingUpdateInt(0xff00, 0xffff00, 0xffffff00));
124     assertEqual(0xFF41D912L,
125                 CRC32BytesUsingUpdateInt(0x1200, 0x123400, 0x12345600));
126 
127     assertEqual(0x909FB2F2L, CRC32BytesUsingUpdateInt(1, 1, 1));
128     assertEqual(0x909FB2F2L,
129                 CRC32BytesUsingUpdateInt(0x0101, 0x010001, 0x01000001));
130     assertEqual(0x909FB2F2L,
131                 CRC32BytesUsingUpdateInt(0xff01, 0xffff01, 0xffffff01));
132     assertEqual(0x909FB2F2L,
133                 CRC32BytesUsingUpdateInt(0x1201, 0x123401, 0x12345601));
134 
135     assertEqual(0xE33A9F71L, CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f));
136     assertEqual(0xE33A9F71L,
137                 CRC32BytesUsingUpdateInt(0x010f, 0x01000f, 0x0100000f));
138     assertEqual(0xE33A9F71L,
139                 CRC32BytesUsingUpdateInt(0xff0f, 0xffff0f, 0xffffff0f));
140     assertEqual(0xE33A9F71L,
141                 CRC32BytesUsingUpdateInt(0x120f, 0x12340f, 0x1234560f));
142 
143     assertEqual(0xFFFFFF00L, CRC32BytesUsingUpdateInt(0x0ff, 0x0ff, 0x0ff));
144     assertEqual(0xFFFFFF00L,
145                 CRC32BytesUsingUpdateInt(0x01ff, 0x0100ff, 0x010000ff));
146     assertEqual(0xFFFFFF00L,
147                 CRC32BytesUsingUpdateInt(0x00ffff, 0x00ffffff, 0xffffffff));
148     assertEqual(0xFFFFFF00L,
149                 CRC32BytesUsingUpdateInt(0x12ff, 0x1234ff, 0x123456ff));
150 
151     assertEqual(0xB6CC4292L, CRC32BytesUsingUpdateInt(0x01, 0x02));
152 
153     assertEqual(0xB2DE047CL,
154                 CRC32BytesUsingUpdateInt(0x0, -1, Integer.MIN_VALUE, Integer.MAX_VALUE));
155   }
156 
CRC32ByteArray(byte[] bytes, int off, int len)157   private static long CRC32ByteArray(byte[] bytes, int off, int len) {
158     CRC32 crc32 = new CRC32();
159     crc32.update(bytes, off, len);
160     return crc32.getValue();
161   }
162 
163   // This is used to test we generate correct code for constant offsets.
164   // In this case the offset is 0.
CRC32ByteArray(byte[] bytes)165   private static long CRC32ByteArray(byte[] bytes) {
166     CRC32 crc32 = new CRC32();
167     crc32.update(bytes);
168     return crc32.getValue();
169   }
170 
CRC32ByteAndByteArray(int value, byte[] bytes)171   private static long CRC32ByteAndByteArray(int value, byte[] bytes) {
172     CRC32 crc32 = new CRC32();
173     crc32.update(value);
174     crc32.update(bytes);
175     return crc32.getValue();
176   }
177 
CRC32ByteArrayAndByte(byte[] bytes, int value)178   private static long CRC32ByteArrayAndByte(byte[] bytes, int value) {
179     CRC32 crc32 = new CRC32();
180     crc32.update(bytes);
181     crc32.update(value);
182     return crc32.getValue();
183   }
184 
CRC32ByteArrayThrowsAIOOBE(byte[] bytes, int off, int len)185   private static boolean CRC32ByteArrayThrowsAIOOBE(byte[] bytes, int off, int len) {
186     try {
187       CRC32 crc32 = new CRC32();
188       crc32.update(bytes, off, len);
189     } catch (ArrayIndexOutOfBoundsException ex) {
190       return true;
191     }
192     return false;
193   }
194 
CRC32ByteArrayThrowsNPE()195   private static boolean CRC32ByteArrayThrowsNPE() {
196     try {
197       CRC32 crc32 = new CRC32();
198       crc32.update(null, 0, 0);
199       return false;
200     } catch (NullPointerException e) {}
201 
202     try {
203       CRC32 crc32 = new CRC32();
204       crc32.update(null, 1, 2);
205       return false;
206     } catch (NullPointerException e) {}
207 
208     try {
209       CRC32 crc32 = new CRC32();
210       crc32.update((byte[])null);
211       return false;
212     } catch (NullPointerException e) {}
213 
214     return true;
215   }
216 
CRC32BytesUsingUpdateInt(byte[] bytes, int off, int len)217   private static long CRC32BytesUsingUpdateInt(byte[] bytes, int off, int len) {
218     CRC32 crc32 = new CRC32();
219     while (len-- > 0) {
220       crc32.update(bytes[off++]);
221     }
222     return crc32.getValue();
223   }
224 
TestCRC32UpdateBytes()225   private static void TestCRC32UpdateBytes() {
226     assertEqual(0L, CRC32ByteArray(new byte[] {}));
227     assertEqual(0L, CRC32ByteArray(new byte[] {}, 0, 0));
228     assertEqual(0L, CRC32ByteArray(new byte[] {0}, 0, 0));
229     assertEqual(0L, CRC32ByteArray(new byte[] {0}, 1, 0));
230     assertEqual(0L, CRC32ByteArray(new byte[] {0, 0}, 1, 0));
231 
232     assertEqual(true, CRC32ByteArrayThrowsNPE());
233     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, -1, 0));
234     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0}, -1, 1));
235     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0}, 0, -1));
236     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 0, -1));
237     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 1, 0));
238     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, -1, 1));
239     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 1, -1));
240     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 0, 1));
241     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 0, 10));
242     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0}, 0, 10));
243     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 10, 10));
244     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0, 0, 0, 0}, 2, 3));
245     assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0, 0, 0, 0}, 3, 2));
246 
247     assertEqual(CRC32Byte(0), CRC32ByteArray(new byte[] {0}));
248     assertEqual(CRC32Byte(0), CRC32ByteArray(new byte[] {0}, 0, 1));
249     assertEqual(CRC32Byte(1), CRC32ByteArray(new byte[] {1}));
250     assertEqual(CRC32Byte(1), CRC32ByteArray(new byte[] {1}, 0, 1));
251     assertEqual(CRC32Byte(0x0f), CRC32ByteArray(new byte[] {0x0f}));
252     assertEqual(CRC32Byte(0x0f), CRC32ByteArray(new byte[] {0x0f}, 0, 1));
253     assertEqual(CRC32Byte(0xff), CRC32ByteArray(new byte[] {-1}));
254     assertEqual(CRC32Byte(0xff), CRC32ByteArray(new byte[] {-1}, 0, 1));
255     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
256                 CRC32ByteArray(new byte[] {0, 0, 0}));
257     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
258                 CRC32ByteArray(new byte[] {0, 0, 0}, 0, 3));
259     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
260                 CRC32ByteArray(new byte[] {1, 1, 1}));
261     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
262                 CRC32ByteArray(new byte[] {1, 1, 1}, 0, 3));
263     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
264                 CRC32ByteArray(new byte[] {0x0f, 0x0f, 0x0f}));
265     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
266                 CRC32ByteArray(new byte[] {0x0f, 0x0f, 0x0f}, 0, 3));
267     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
268                 CRC32ByteArray(new byte[] {-1, -1, -1}));
269     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
270                 CRC32ByteArray(new byte[] {-1, -1, -1}, 0, 3));
271     assertEqual(CRC32BytesUsingUpdateInt(1, 2),
272                 CRC32ByteArray(new byte[] {1, 2}));
273     assertEqual(CRC32BytesUsingUpdateInt(1, 2),
274                 CRC32ByteArray(new byte[] {1, 2}, 0, 2));
275     assertEqual(
276         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
277         CRC32ByteArray(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}));
278     assertEqual(
279         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
280         CRC32ByteArray(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}, 0, 4));
281 
282     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
283                 CRC32ByteAndByteArray(0, new byte[] {0, 0}));
284     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
285                 CRC32ByteAndByteArray(1, new byte[] {1, 1}));
286     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
287                 CRC32ByteAndByteArray(0x0f, new byte[] {0x0f, 0x0f}));
288     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
289                 CRC32ByteAndByteArray(-1, new byte[] {-1, -1}));
290     assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3),
291                 CRC32ByteAndByteArray(1, new byte[] {2, 3}));
292     assertEqual(
293         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
294         CRC32ByteAndByteArray(0, new byte[] {-1, Byte.MIN_VALUE, Byte.MAX_VALUE}));
295 
296     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
297                 CRC32ByteArrayAndByte(new byte[] {0, 0}, 0));
298     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
299                 CRC32ByteArrayAndByte(new byte[] {1, 1}, 1));
300     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
301                 CRC32ByteArrayAndByte(new byte[] {0x0f, 0x0f}, 0x0f));
302     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
303                 CRC32ByteArrayAndByte(new byte[] {-1, -1}, -1));
304     assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3),
305                 CRC32ByteArrayAndByte(new byte[] {1, 2}, 3));
306     assertEqual(
307         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
308         CRC32ByteArrayAndByte(new byte[] {0, -1, Byte.MIN_VALUE}, Byte.MAX_VALUE));
309 
310     byte[] bytes = new byte[128 * 1024];
311     Random rnd = new Random(0);
312     rnd.nextBytes(bytes);
313 
314     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, bytes.length),
315                 CRC32ByteArray(bytes));
316     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, 8 * 1024),
317                 CRC32ByteArray(bytes, 0, 8 * 1024));
318 
319     int off = rnd.nextInt(bytes.length / 2);
320     for (int len = 0; len <= 16; ++len) {
321       assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
322                   CRC32ByteArray(bytes, off, len));
323     }
324 
325     // Check there are no issues with unaligned accesses.
326     for (int o = 1; o < 8; ++o) {
327       for (int l = 0; l <= 16; ++l) {
328         assertEqual(CRC32BytesUsingUpdateInt(bytes, o, l),
329                     CRC32ByteArray(bytes, o, l));
330       }
331     }
332 
333     int len = bytes.length / 2;
334     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len - 1),
335                 CRC32ByteArray(bytes, 0, len - 1));
336     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len),
337                 CRC32ByteArray(bytes, 0, len));
338     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len + 1),
339                 CRC32ByteArray(bytes, 0, len + 1));
340 
341     len = rnd.nextInt(bytes.length + 1);
342     off = rnd.nextInt(bytes.length - len);
343     assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
344                 CRC32ByteArray(bytes, off, len));
345   }
346 
CRC32ByteBuffer(byte[] bytes, int off, int len)347   private static long CRC32ByteBuffer(byte[] bytes, int off, int len) {
348     ByteBuffer buf = ByteBuffer.wrap(bytes, 0, off + len);
349     buf.position(off);
350     CRC32 crc32 = new CRC32();
351     crc32.update(buf);
352     return crc32.getValue();
353   }
354 
TestCRC32UpdateByteBuffer()355   private static void TestCRC32UpdateByteBuffer() {
356     assertEqual(0L, CRC32ByteBuffer(new byte[] {}, 0, 0));
357     assertEqual(0L, CRC32ByteBuffer(new byte[] {0}, 0, 0));
358     assertEqual(0L, CRC32ByteBuffer(new byte[] {0}, 1, 0));
359     assertEqual(0L, CRC32ByteBuffer(new byte[] {0, 0}, 1, 0));
360 
361     assertEqual(CRC32Byte(0), CRC32ByteBuffer(new byte[] {0}, 0, 1));
362     assertEqual(CRC32Byte(1), CRC32ByteBuffer(new byte[] {1}, 0, 1));
363     assertEqual(CRC32Byte(0x0f), CRC32ByteBuffer(new byte[] {0x0f}, 0, 1));
364     assertEqual(CRC32Byte(0xff), CRC32ByteBuffer(new byte[] {-1}, 0, 1));
365     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
366                 CRC32ByteBuffer(new byte[] {0, 0, 0}, 0, 3));
367     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
368                 CRC32ByteBuffer(new byte[] {1, 1, 1}, 0, 3));
369     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
370                 CRC32ByteBuffer(new byte[] {0x0f, 0x0f, 0x0f}, 0, 3));
371     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
372                 CRC32ByteBuffer(new byte[] {-1, -1, -1}, 0, 3));
373     assertEqual(CRC32BytesUsingUpdateInt(1, 2),
374                 CRC32ByteBuffer(new byte[] {1, 2}, 0, 2));
375     assertEqual(
376         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
377         CRC32ByteBuffer(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}, 0, 4));
378 
379     byte[] bytes = new byte[128 * 1024];
380     Random rnd = new Random(0);
381     rnd.nextBytes(bytes);
382 
383     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, 8 * 1024),
384                 CRC32ByteBuffer(bytes, 0, 8 * 1024));
385 
386     int off = rnd.nextInt(bytes.length / 2);
387     for (int len = 0; len <= 16; ++len) {
388       assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
389                   CRC32ByteBuffer(bytes, off, len));
390     }
391 
392     // Check there are no issues with unaligned accesses.
393     for (int o = 1; o < 8; ++o) {
394       for (int l = 0; l <= 16; ++l) {
395         assertEqual(CRC32BytesUsingUpdateInt(bytes, o, l),
396                     CRC32ByteBuffer(bytes, o, l));
397       }
398     }
399 
400     int len = bytes.length / 2;
401     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len - 1),
402                 CRC32ByteBuffer(bytes, 0, len - 1));
403     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len),
404                 CRC32ByteBuffer(bytes, 0, len));
405     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len + 1),
406                 CRC32ByteBuffer(bytes, 0, len + 1));
407 
408     len = rnd.nextInt(bytes.length + 1);
409     off = rnd.nextInt(bytes.length - len);
410     assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
411                 CRC32ByteBuffer(bytes, off, len));
412   }
413 
CRC32DirectByteBuffer(byte[] bytes, int off, int len)414   private static long CRC32DirectByteBuffer(byte[] bytes, int off, int len) {
415     final int total_len = off + len;
416     ByteBuffer buf = ByteBuffer.allocateDirect(total_len).put(bytes, 0, total_len);
417     buf.position(off);
418     CRC32 crc32 = new CRC32();
419     crc32.update(buf);
420     return crc32.getValue();
421   }
422 
CRC32ByteAndDirectByteBuffer(int value, byte[] bytes)423   private static long CRC32ByteAndDirectByteBuffer(int value, byte[] bytes) {
424     ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length).put(bytes);
425     buf.position(0);
426     CRC32 crc32 = new CRC32();
427     crc32.update(value);
428     crc32.update(buf);
429     return crc32.getValue();
430   }
431 
CRC32DirectByteBufferAndByte(byte[] bytes, int value)432   private static long CRC32DirectByteBufferAndByte(byte[] bytes, int value) {
433     ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length).put(bytes);
434     buf.position(0);
435     CRC32 crc32 = new CRC32();
436     crc32.update(buf);
437     crc32.update(value);
438     return crc32.getValue();
439   }
440 
TestCRC32UpdateDirectByteBuffer()441   private static void TestCRC32UpdateDirectByteBuffer() {
442     assertEqual(0L, CRC32DirectByteBuffer(new byte[] {}, 0, 0));
443     assertEqual(0L, CRC32DirectByteBuffer(new byte[] {0}, 0, 0));
444     assertEqual(0L, CRC32DirectByteBuffer(new byte[] {0}, 1, 0));
445     assertEqual(0L, CRC32DirectByteBuffer(new byte[] {0, 0}, 1, 0));
446 
447     assertEqual(CRC32Byte(0), CRC32DirectByteBuffer(new byte[] {0}, 0, 1));
448     assertEqual(CRC32Byte(1), CRC32DirectByteBuffer(new byte[] {1}, 0, 1));
449     assertEqual(CRC32Byte(0x0f), CRC32DirectByteBuffer(new byte[] {0x0f}, 0, 1));
450     assertEqual(CRC32Byte(0xff), CRC32DirectByteBuffer(new byte[] {-1}, 0, 1));
451     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
452                 CRC32DirectByteBuffer(new byte[] {0, 0, 0}, 0, 3));
453     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
454                 CRC32DirectByteBuffer(new byte[] {1, 1, 1}, 0, 3));
455     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
456                 CRC32DirectByteBuffer(new byte[] {0x0f, 0x0f, 0x0f}, 0, 3));
457     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
458                 CRC32DirectByteBuffer(new byte[] {-1, -1, -1}, 0, 3));
459     assertEqual(CRC32BytesUsingUpdateInt(1, 2),
460                 CRC32DirectByteBuffer(new byte[] {1, 2}, 0, 2));
461     assertEqual(
462         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
463         CRC32DirectByteBuffer(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}, 0, 4));
464 
465     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
466                 CRC32ByteAndDirectByteBuffer(0, new byte[] {0, 0}));
467     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
468                 CRC32ByteAndDirectByteBuffer(1, new byte[] {1, 1}));
469     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
470                 CRC32ByteAndDirectByteBuffer(0x0f, new byte[] {0x0f, 0x0f}));
471     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
472                 CRC32ByteAndDirectByteBuffer(-1, new byte[] {-1, -1}));
473     assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3),
474                 CRC32ByteAndDirectByteBuffer(1, new byte[] {2, 3}));
475     assertEqual(
476         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
477         CRC32ByteAndDirectByteBuffer(0, new byte[] {-1, Byte.MIN_VALUE, Byte.MAX_VALUE}));
478 
479     assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
480                 CRC32DirectByteBufferAndByte(new byte[] {0, 0}, 0));
481     assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
482                 CRC32DirectByteBufferAndByte(new byte[] {1, 1}, 1));
483     assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
484                 CRC32DirectByteBufferAndByte(new byte[] {0x0f, 0x0f}, 0x0f));
485     assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
486                 CRC32DirectByteBufferAndByte(new byte[] {-1, -1}, -1));
487     assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3),
488                 CRC32DirectByteBufferAndByte(new byte[] {1, 2}, 3));
489     assertEqual(
490         CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
491         CRC32DirectByteBufferAndByte(new byte[] {0, -1, Byte.MIN_VALUE}, Byte.MAX_VALUE));
492 
493     byte[] bytes = new byte[128 * 1024];
494     Random rnd = new Random(0);
495     rnd.nextBytes(bytes);
496 
497     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, bytes.length),
498                 CRC32DirectByteBuffer(bytes, 0, bytes.length));
499     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, 8 * 1024),
500                 CRC32DirectByteBuffer(bytes, 0, 8 * 1024));
501 
502     int off = rnd.nextInt(bytes.length / 2);
503     for (int len = 0; len <= 16; ++len) {
504       assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
505                   CRC32DirectByteBuffer(bytes, off, len));
506     }
507 
508     // Check there are no issues with unaligned accesses.
509     for (int o = 1; o < 8; ++o) {
510       for (int l = 0; l <= 16; ++l) {
511         assertEqual(CRC32BytesUsingUpdateInt(bytes, o, l),
512                     CRC32DirectByteBuffer(bytes, o, l));
513       }
514     }
515 
516     int len = bytes.length / 2;
517     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len - 1),
518                 CRC32DirectByteBuffer(bytes, 0, len - 1));
519     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len),
520                 CRC32DirectByteBuffer(bytes, 0, len));
521     assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len + 1),
522                 CRC32DirectByteBuffer(bytes, 0, len + 1));
523 
524     len = rnd.nextInt(bytes.length + 1);
525     off = rnd.nextInt(bytes.length - len);
526     assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
527                 CRC32DirectByteBuffer(bytes, off, len));
528   }
529 
main(String args[])530   public static void main(String args[]) {
531     TestCRC32Update();
532     TestCRC32UpdateBytes();
533     TestCRC32UpdateByteBuffer();
534     TestCRC32UpdateDirectByteBuffer();
535   }
536 }
537