diff src/org/dancres/blitz/mangler/MangledField.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/dancres/blitz/mangler/MangledField.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,147 @@
+package org.dancres.blitz.mangler;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.dancres.io.AnnotatingObjectOutputStream;
+import org.dancres.io.AnnotatingObjectInputStream;
+
+/**
+   Each field within an Entry is held in a MangledField.  We require the
+   field's name for indexing purposes.  We also use our own hashing
+   algorithm which is known not to "funnel" in the vast majority of cases.
+ */
+public class MangledField implements Serializable {
+    static final long serialVersionUID = -6256197142057463399L;
+
+    private String theName;
+    private byte[] theObjectBytes;
+    private byte[] theAnnotationBytes;
+    private int theHashCode;
+
+    MangledField(String aName) {
+        theName = aName;
+        theObjectBytes = new byte[0];
+        theAnnotationBytes = new byte[0];
+        theHashCode = 0;
+    }
+
+    MangledField(String aName, Object anObject)
+        throws IOException {
+        theName = aName;
+        mangle(anObject);
+    }
+
+    MangledField(String aName, byte[] anObject, byte[] aAnnotation, int aHash) {
+        theName = aName;
+        theObjectBytes = anObject;
+        theAnnotationBytes = aAnnotation;
+        theHashCode = aHash;
+    }
+
+    public int sizeOf() {
+        if (isNull())
+            return 0;
+        else
+            return theName.length() + theObjectBytes.length +
+                theAnnotationBytes.length + 4 + 4;
+    }
+
+    public Object unMangle(ClassLoader aDefault, boolean checkIntegrity)
+        throws IOException, ClassNotFoundException {
+
+        ByteArrayInputStream myObjStream =
+            new ByteArrayInputStream(theObjectBytes);
+        ByteArrayInputStream myAnnoStream =
+            new ByteArrayInputStream(theAnnotationBytes);
+
+        AnnotatingObjectInputStream myStream =
+            new AnnotatingObjectInputStream(aDefault, myObjStream,
+                                            myAnnoStream, checkIntegrity);
+
+        Object myResult = myStream.readObject();
+
+        myStream.close();
+
+        return myResult;
+    }
+  
+    public boolean isNull() {
+        // System.err.println("isNull: " + theName);
+        // System.err.println("OLength: " + theObjectBytes.length);
+        // System.err.println("ALength: " + theAnnotationBytes.length);
+        return (theObjectBytes.length == 0);
+    }
+
+    private void mangle(Object anObject) throws IOException {
+        ByteArrayOutputStream myObjectBytes = new ByteArrayOutputStream();
+        ByteArrayOutputStream myAnnotBytes = new ByteArrayOutputStream();
+        
+        AnnotatingObjectOutputStream myStream = 
+            new AnnotatingObjectOutputStream(myObjectBytes, myAnnotBytes);
+
+        myStream.writeObject(anObject);
+        myStream.close();
+
+        theObjectBytes = myObjectBytes.toByteArray();
+        theAnnotationBytes = myAnnotBytes.toByteArray();
+
+        theHashCode = buildHash(theObjectBytes);
+    }
+
+    /**
+       This algorithm is based on the "One at a time" hash published in
+       Dr Dobbs Journal '97 and authored by Bob Jenkins.  A copy of the
+       article can be found at
+       <a href="http://burtleburtle.net/bob/hash/doobs.html">
+       Burtleburtle.net</a>
+    */
+    private int buildHash(byte[] aBytes) {
+        int myHash = 0;
+
+        for (int i = 0; i < aBytes.length; i++) {
+            myHash += aBytes[i];
+            myHash += (myHash << 10);
+            myHash ^= (myHash >> 6);
+        }
+
+        myHash += (myHash << 3);
+        myHash ^= (myHash >> 11);
+        myHash += (myHash << 15);
+
+        return myHash;
+    }
+
+    public boolean matches(MangledField aField) {
+        if (aField.theHashCode == theHashCode) {
+            if (aField.theObjectBytes.length == theObjectBytes.length) {
+                for (int i = 0; i < theObjectBytes.length; i++) {
+                    if (aField.theObjectBytes[i] != theObjectBytes[i])
+                        return false;
+                }
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public String getName() {
+        return theName;
+    }
+
+    byte[] getContent() {
+        return theObjectBytes;
+    }
+
+    byte[] getAnnotations() {
+        return theAnnotationBytes;
+    }
+
+    public int hashCode() {
+        return theHashCode;
+    }
+}