| 1710 | |
| 1711 | === Groovy === |
| 1712 | {{{ |
| 1713 | import java.nio.ByteBuffer |
| 1714 | import java.nio.ByteOrder |
| 1715 | import java.nio.channels.FileChannel |
| 1716 | import java.nio.channels.FileChannel.MapMode |
| 1717 | |
| 1718 | class OpenSubtitlesHasher { |
| 1719 | |
| 1720 | def static HASH_CHUNK_SIZE = 64 * 1024 |
| 1721 | |
| 1722 | def static computeHash(file) { |
| 1723 | def size = file.length() |
| 1724 | def chunkSizeForFile = Math.min(HASH_CHUNK_SIZE, size) |
| 1725 | |
| 1726 | def fileChannel = new FileInputStream(file).getChannel() |
| 1727 | |
| 1728 | try { |
| 1729 | def head = computeHashForChunk(fileChannel.map(MapMode.READ_ONLY, 0, chunkSizeForFile)) |
| 1730 | def tail = computeHashForChunk(fileChannel.map(MapMode.READ_ONLY, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile)) |
| 1731 | |
| 1732 | return String.format("%016x", size + head + tail) |
| 1733 | } finally { |
| 1734 | fileChannel.close() |
| 1735 | } |
| 1736 | } |
| 1737 | |
| 1738 | |
| 1739 | def static computeHash(stream, length){ |
| 1740 | def chunkSizeForFile = (int) Math.min(HASH_CHUNK_SIZE, length) |
| 1741 | |
| 1742 | def chunkBytes = new byte[(int) Math.min(2 * HASH_CHUNK_SIZE, length)] |
| 1743 | |
| 1744 | def dis = new DataInputStream(stream) |
| 1745 | |
| 1746 | dis.readFully(chunkBytes, 0, chunkSizeForFile) |
| 1747 | |
| 1748 | def position = chunkSizeForFile |
| 1749 | def tailChunkPosition = length - chunkSizeForFile |
| 1750 | |
| 1751 | while (position < tailChunkPosition && (position += dis.skip(tailChunkPosition - position)) >= 0) |
| 1752 | |
| 1753 | dis.readFully(chunkBytes, chunkSizeForFile, chunkBytes.length - chunkSizeForFile) |
| 1754 | |
| 1755 | def head = computeHashForChunk(ByteBuffer.wrap(chunkBytes, 0, chunkSizeForFile)) |
| 1756 | def tail = computeHashForChunk(ByteBuffer.wrap(chunkBytes, chunkBytes.length - chunkSizeForFile, chunkSizeForFile)) |
| 1757 | |
| 1758 | return String.format("%016x", length + head + tail) |
| 1759 | } |
| 1760 | |
| 1761 | def static computeHashForChunk(buffer) { |
| 1762 | def longBuffer = buffer.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer() |
| 1763 | def hash = 0 |
| 1764 | |
| 1765 | while (longBuffer.hasRemaining()) { |
| 1766 | hash += longBuffer.get() |
| 1767 | } |
| 1768 | |
| 1769 | return hash |
| 1770 | } |
| 1771 | } |
| 1772 | }}} |