Permalink
Browse files

Added Adler32 checksum.

Also, made previous() behave better in error cases (no partial object state update).
  • Loading branch information...
1 parent 809c0e8 commit 9543ccf3021e7b23196c9b3ffab7a02ff334432c @esstrifork esstrifork committed Jun 24, 2011
@@ -14,6 +14,7 @@
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;
+import java.util.zip.Adler32;
import java.io.OutputStream;
@@ -101,6 +102,15 @@ public static void writeBufferTo(ByteBuffer data, OutputStream out) throws IOExc
while (data.hasRemaining()) channel.write(data);
}
+ public static int computeAdler32(ByteBuffer data) {
+ return computeAdler32(DeltaZip.allToByteArray(data)); // Oh, the copying.
+ }
+ public static int computeAdler32(byte[] data) {
+ Adler32 acc = new Adler32();
+ acc.update(data);
+ return (int)acc.getValue();
+ }
+
//==================== Deflate / Inflate ====================
public static class Dictionary {
@@ -55,6 +55,7 @@ private static void insertCM(CompressionMethod[] table, CompressionMethod cm) {
private long current_pos, current_size;
private int current_method;
private byte[] current_version;
+ private int current_checksum;
private ByteBuffer exposed_current_version;
//==================== API ==========================================
@@ -152,31 +153,45 @@ protected void set_initial_position() throws IOException {
current_pos = access.getSize();
}
+ private static final int ENVELOPE_HEADER = 4 + 4; // Start-tag + checksum
+ private static final int ENVELOPE_TRAILER = 4; // End.tag
+ private static final int ENVELOPE_OVERHEAD = ENVELOPE_HEADER + ENVELOPE_TRAILER;
protected void goto_previous_position_and_compute_current_version() throws IOException {
- ByteBuffer tag_buf = access.pread(current_pos-4, 4);
+ ByteBuffer tag_buf = access.pread(current_pos-ENVELOPE_TRAILER, ENVELOPE_TRAILER);
int tag = tag_buf.getInt(0);
int size = tag &~ (-1 << 28);
int method = (tag >> 28) & 15;
// System.err.println("DB| tag="+tag+" -> "+method+":"+size);
- // Get start-tag plus data:
- long start_pos = current_pos-size-8;
- ByteBuffer data_buf = access.pread(start_pos, size+4);
+ // Read envelope header:
+ long start_pos = current_pos - size - ENVELOPE_OVERHEAD;
+ ByteBuffer data_buf = access.pread(start_pos, size + ENVELOPE_HEADER);
data_buf.rewind();
int start_tag = data_buf.getInt();
if (start_tag != tag) throw new IOException("Data error - tag mismatch @ "+start_pos+";"+current_pos);
-
- current_pos = start_pos;
- compute_current_version(method, data_buf);
+ int adler32 = data_buf.getInt();
+
+ // Unpack:
+ byte[] version = compute_current_version(method, data_buf, start_pos);
+
+ // Verify checksum:
+ int actual_adler32 = DZUtil.computeAdler32(version);
+ if (actual_adler32 != adler32)
+ throw new IOException("Data error - checksum mismatch @ "+start_pos+": stored is "+adler32+" but computed is "+actual_adler32);
+
+ // Commit:
+ this.current_pos = start_pos;
+ this.current_method = method;
+ this.current_version = version;
+ this.exposed_current_version = ByteBuffer.wrap(current_version).asReadOnlyBuffer();
+ this.current_checksum = actual_adler32;
}
- protected void compute_current_version(int method, ByteBuffer data_buf) throws IOException {
+ protected byte[] compute_current_version(int method, ByteBuffer data_buf, long pos) throws IOException {
CompressionMethod cm = COMPRESSION_METHODS[method];
- if (cm==null) throw new IOException("Invalid compression method: "+method+" @ "+current_pos);
+ if (cm==null) throw new IOException("Invalid compression method: "+method+" @ "+pos);
- current_method = method;
- current_version = cm.uncompress(data_buf, current_version, inflater);
- exposed_current_version = ByteBuffer.wrap(current_version).asReadOnlyBuffer();
+ return cm.uncompress(data_buf, current_version, inflater);
}
//====================
@@ -192,7 +207,11 @@ protected void pack_delta(ByteBuffer version, byte[] ref_version, ExtByteArrayOu
//====================
protected void pack_entry(ByteBuffer version, byte[] ref_version, CompressionMethod cm, ExtByteArrayOutputStream dst) {
+ int adler32 = DZUtil.computeAdler32(version);
+
int tag_blank = dst.insertBlank(4);
+ dst.writeBigEndianInteger(adler32, 4);
+
int size_before = dst.size();
try {
cm.compress(version.duplicate(), ref_version, dst);
@@ -25,20 +25,22 @@ public void test_read_known() throws Exception {
/** Chunked-deflate, no prefix/suffix. */
byte[] two_revs1 = {
(byte)0xCE, (byte)0xB4, 0x7A, 0x10,
- 64,0,0,7,0,0,4,(byte)243,
- 0,113,0,64,0,0,7,0,
- 0,0,13,72,101,108,108,111,
- 44,32,87,111,114,108,100,33,
+ 64,0,0,7, 0x05,(byte)0x8C,0x01,(byte)0xF5,
+ 0,0,4,(byte)243, 0,113,0,
+ 64,0,0,7,
+ 0,0,0,13, 0x1F,(byte)0x9E,0x04,0x6A,
+ 72,101,108,108,111, 44,32,87,111,114,108,100,33,
0,0,0,13};
/** Chunked-deflate, using prefix. */
byte[] two_revs2 = {
(byte)0xCE, (byte)0xB4, 0x7A, 0x10,
- 64,0,0,5,8,0,2,0,
- 4,64,0,0,5,0,0,0,
- 13,72,101,108,108,111,44,32,
- 87,111,114,108,100,33,0,0,
- 0,13};
+ 64,0,0,5, 0x05,(byte)0x8C,0x01,(byte)0xF5,
+ 8,0,2,0, 4,
+ 64,0,0,5,
+ 0,0,0,13, 0x1F,(byte)0x9E,0x04,0x6A,
+ 72,101,108,108,111,44,32,87,111,114,108,100,33,
+ 0,0,0,13};
ByteBuffer exp_rev1 = ByteBuffer.wrap("Hello, World!".getBytes("ISO-8859-1"));
ByteBuffer exp_rev2 = ByteBuffer.wrap("Hello".getBytes("ISO-8859-1"));

0 comments on commit 9543ccf

Please sign in to comment.