package me.ele.amigo.utils; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.zip.CRC32; /** * Tools to build a quick partial crc of files. */ public final class CrcUtils { static class CentralDirectory { long offset; long size; } /** * Size of reading buffers. */ private static final int BUFFER_SIZE = 0x4000; /** * Compute crc32 of the central directory of an apk. The central directory contains * the crc32 of each entries in the zip so the computed result is considered valid for the whole * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does * not either. */ public static String getCrc(File apk) { RandomAccessFile raf = null; try { raf = new RandomAccessFile(apk, "r"); CentralDirectory dir = findCentralDirectory(raf); return String.valueOf(computeCrcOfCentralDir(raf, dir)); } catch (IOException e) { throw new RuntimeException(e); } finally { try { if (raf != null) { raf.close(); } } catch (IOException e) { e.printStackTrace(); } } } /* Package visible for testing */ static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException { CentralDirectory dir = new CentralDirectory(); dir.size = Math.min(raf.length() >> 2, 10000); dir.offset = raf.length() >> 1; return dir; } /* Package visible for testing */ static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir) throws IOException { CRC32 crc = new CRC32(); long stillToRead = dir.size; raf.seek(dir.offset); int length = (int) Math.min(BUFFER_SIZE, stillToRead); byte[] buffer = new byte[BUFFER_SIZE]; length = raf.read(buffer, 0, length); while (length != -1) { crc.update(buffer, 0, length); stillToRead -= length; if (stillToRead == 0) { break; } length = (int) Math.min(BUFFER_SIZE, stillToRead); length = raf.read(buffer, 0, length); } return crc.getValue(); } }