1 /* Copyright 2016 Google Inc. All Rights Reserved. 2 3 Distributed under MIT license. 4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 */ 6 7 package org.brotli.integration; 8 9 import java.io.ByteArrayOutputStream; 10 import java.io.IOException; 11 import java.io.InputStream; 12 import java.math.BigInteger; 13 import java.util.ArrayList; 14 import java.util.List; 15 import java.util.zip.ZipEntry; 16 import java.util.zip.ZipInputStream; 17 18 /** 19 * Utilities to work test files bundles in zip archive. 20 */ 21 public class BundleHelper { BundleHelper()22 private BundleHelper() { } 23 listEntries(InputStream input)24 public static List<String> listEntries(InputStream input) throws IOException { 25 List<String> result = new ArrayList<String>(); 26 ZipInputStream zis = new ZipInputStream(input); 27 ZipEntry entry; 28 try { 29 while ((entry = zis.getNextEntry()) != null) { 30 if (!entry.isDirectory()) { 31 result.add(entry.getName()); 32 } 33 zis.closeEntry(); 34 } 35 } finally { 36 zis.close(); 37 } 38 return result; 39 } 40 readStream(InputStream input)41 public static byte[] readStream(InputStream input) throws IOException { 42 ByteArrayOutputStream result = new ByteArrayOutputStream(); 43 byte[] buffer = new byte[65536]; 44 int bytesRead; 45 while ((bytesRead = input.read(buffer)) != -1) { 46 result.write(buffer, 0, bytesRead); 47 } 48 return result.toByteArray(); 49 } 50 readEntry(InputStream input, String entryName)51 public static byte[] readEntry(InputStream input, String entryName) throws IOException { 52 ZipInputStream zis = new ZipInputStream(input); 53 ZipEntry entry; 54 try { 55 while ((entry = zis.getNextEntry()) != null) { 56 if (entry.getName().equals(entryName)) { 57 byte[] result = readStream(zis); 58 zis.closeEntry(); 59 return result; 60 } 61 zis.closeEntry(); 62 } 63 } finally { 64 zis.close(); 65 } 66 /* entry not found */ 67 return null; 68 } 69 70 /** ECMA CRC64 polynomial. */ 71 private static final long CRC_64_POLY = 72 new BigInteger("C96C5795D7870F42", 16).longValue(); 73 74 /** 75 * Rolls CRC64 calculation. 76 * 77 * <p> {@code CRC64(data) = -1 ^ updateCrc64((... updateCrc64(-1, firstBlock), ...), lastBlock);} 78 * <p> This simple and reliable checksum is chosen to make is easy to calculate the same value 79 * across the variety of languages (C++, Java, Go, ...). 80 */ updateCrc64(long crc, byte[] data, int offset, int length)81 public static long updateCrc64(long crc, byte[] data, int offset, int length) { 82 for (int i = offset; i < offset + length; ++i) { 83 long c = (crc ^ (long) (data[i] & 0xFF)) & 0xFF; 84 for (int k = 0; k < 8; k++) { 85 c = ((c & 1) == 1) ? CRC_64_POLY ^ (c >>> 1) : c >>> 1; 86 } 87 crc = c ^ (crc >>> 8); 88 } 89 return crc; 90 } 91 92 /** 93 * Calculates CRC64 of stream contents. 94 */ fingerprintStream(InputStream input)95 public static long fingerprintStream(InputStream input) throws IOException { 96 byte[] buffer = new byte[65536]; 97 long crc = -1; 98 while (true) { 99 int len = input.read(buffer); 100 if (len <= 0) { 101 break; 102 } 103 crc = updateCrc64(crc, buffer, 0, len); 104 } 105 return ~crc; 106 } 107 getExpectedFingerprint(String entryName)108 public static long getExpectedFingerprint(String entryName) { 109 int dotIndex = entryName.indexOf('.'); 110 String entryCrcString = (dotIndex == -1) ? entryName : entryName.substring(0, dotIndex); 111 return new BigInteger(entryCrcString, 16).longValue(); 112 } 113 } 114