diff --git a/API-CHANGES.txt b/API-CHANGES.txt
index a7e27b061071642596307752afebaefae6e7bf86..02329e843cb78a0ba18e12877f78a24023f1d942 100644
--- a/API-CHANGES.txt
+++ b/API-CHANGES.txt
@@ -1,9 +1,8 @@
 Changes to make once we are ready to do a backwards incompatible change.
 - TSK_SERVICE_ACCOUNT to TSK_ACCOUNT
 - HashDB to use new TSK_BASE_HASHDB enum instead of its own ENUM
-- Java SleuthkitCase.addArtifactType shoudl return different if artifact already exists or getArtifactId should....
-- Java SleuthkitCase.findFilesWhere should return AbstractFile liek findFiles
+- Java SleuthkitCase.addArtifactType should return different if artifact already exists or getArtifactId should....
+- Java SleuthkitCase.findFilesWhere should return AbstractFile like findFiles
 - getUniquePath() should not throw exception. 
 - findFilesInImage should return an enum like TskDB methods differentiating if any data was found or not.
-- remove addImageInfo in db_Sqlite that does not take MD5, and/oor make it take IMG_INFO as argument
-
+- remove addImageInfo in db_Sqlite that does not take MD5, and/or make it take IMG_INFO as argument
\ No newline at end of file
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
index 58047852fcf26eb79a8a5e75c0b44ba506a8a395..11f431e9ccb1f4100ee8f90ceee33ec355f8a172 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
@@ -26,7 +26,7 @@ using std::stringstream;
 using std::for_each;
 
 static TSK_HDB_INFO * m_NSRLDb = NULL;
-static std::vector<TSK_HDB_INFO *> m_knownbads;
+static std::vector<TSK_HDB_INFO *> m_hashDbs;
 
 /*
 * JNI file handle structure encapsulates both
@@ -274,7 +274,7 @@ JNIEXPORT jint JNICALL
     TSK_TCHAR pathT[1024];
     toTCHAR(env, pathT, 1024, pathJ);
 
-    TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_IDXONLY;
+    TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_TRY;
     TSK_HDB_INFO * tempdb = tsk_hdb_open(pathT, flags);
 
     if(tempdb == NULL)
@@ -302,7 +302,7 @@ JNIEXPORT jint JNICALL
     TSK_TCHAR pathT[1024];
     toTCHAR(env, pathT, 1024, pathJ);
 
-    TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_IDXONLY;
+    TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_TRY;
     TSK_HDB_INFO * temp = tsk_hdb_open(pathT, flags);
 
     if(temp == NULL)
@@ -311,19 +311,143 @@ JNIEXPORT jint JNICALL
         return -1;
     }
 
-    m_knownbads.push_back(temp);
+    m_hashDbs.push_back(temp);
     
-    return m_knownbads.size();
+    return m_hashDbs.size();
 }
 
 /*
- * Get the name of the database pointed to by path
+ * Create a new hash db.
  * @param env pointer to java environment this was called from
  * @param obj the java object this was called from
  * @param pathJ the path to the database
+ * @return a handle for the database
+ */
+JNIEXPORT jint JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_newDbKnownBadNat(JNIEnv * env,
+    jclass obj, jstring pathJ)
+{
+    TSK_TCHAR pathT[1024];
+    toTCHAR(env, pathT, 1024, pathJ);
+
+    TSK_HDB_INFO * temp = tsk_hdb_new(pathT);
+
+    if(temp == NULL)
+    {
+        setThrowTskCoreError(env);
+        return -1;
+    }
+
+    m_hashDbs.push_back(temp);
+    
+    return m_hashDbs.size();
+}
+
+/*
+ * Add entry to hash db.
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param filenameJ Name of the file that was hashed (can be empty)
+ * @param hashMd5J Text of MD5 hash (can be empty)
+ * @param hashSha1J Text of SHA1 hash (can be empty)
+ * @param hashSha256J Text of SHA256 hash (can be empty)
+ * @param dbHandle Which DB.
+ * @return 1 on error and 0 on success
+ */
+JNIEXPORT jint JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_addStrDbKnownBadNat(JNIEnv * env,
+    jclass obj, jstring filenameJ, jstring hashMd5J, jstring hashSha1J, jstring hashSha256J, jint dbHandle)
+{
+    int8_t retval = 0;
+
+    if((size_t) dbHandle > m_hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        retval = 1;
+    } else {
+        jboolean isCopy;
+        const char *md5 = (const char *) env->GetStringUTFChars(hashMd5J, &isCopy);
+        const char *sha1 = (const char *) env->GetStringUTFChars(hashSha1J, &isCopy);
+        const char *sha256 = (const char *) env->GetStringUTFChars(hashSha256J, &isCopy);
+   
+        TSK_TCHAR filenameT[1024];
+        toTCHAR(env, filenameT, 1024, filenameJ);
+
+        TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1);
+
+        if(db != NULL) {
+            retval = tsk_hdb_add_str(db, filenameT, md5, sha1, sha256);
+
+            if (retval == 1) {
+                setThrowTskCoreError(env);
+            }
+        }
+
+        env->ReleaseStringUTFChars(hashMd5J, (const char *) md5);
+        env->ReleaseStringUTFChars(hashSha1J, (const char *) sha1);
+        env->ReleaseStringUTFChars(hashSha256J, (const char *) sha256);
+    }
+
+    return retval;
+}
+
+/*
+ * Get updateable state.
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param dbHandle Which DB.
+ * @return true if db can be updated
+ */
+JNIEXPORT jboolean JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_isUpdateableDbKnownBadNat(JNIEnv * env,
+    jclass obj, jint dbHandle)
+{
+    bool retval = false;
+
+    if((size_t) dbHandle > m_hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+    } else {
+        TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1);
+
+        if(db != NULL) {
+            retval = (db->idx_info->updateable == 1) ? true : false;
+        }
+    }
+    return retval;
+}
+
+/*
+ * Test for index only (no original Db file) legacy (IDX format).
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param dbHandle Which DB.
+ * @return true if index only AND is legacy
+ */
+JNIEXPORT jboolean JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_isIdxOnlyHashDbNat(JNIEnv * env,
+    jclass obj, jint dbHandle)
+{
+    bool retval = false;
+
+    if((size_t) dbHandle > m_hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+    } else {
+        TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1);
+
+        if(db != NULL) {
+            retval = (tsk_hdb_is_idxonly(db) == 1) ? true : false;
+        }
+    }
+    return retval;
+}
+
+/*
+ * Get the name of the database pointed to by path
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param pathJ the path to the database (expects the actual database path, not an index path)
  */
 JNIEXPORT jstring JNICALL
-    Java_org_sleuthkit_datamodel_SleuthkitJNI_getDbName(JNIEnv * env,
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_getDbNameByPath(JNIEnv * env,
     jclass obj, jstring pathJ) {
 
     TSK_HDB_OPEN_ENUM flags;
@@ -350,6 +474,30 @@ JNIEXPORT jstring JNICALL
     return jname;
 }
 
+/*
+ * Get the name of the database pointed to by path
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param dbHandle Which DB.
+ */
+JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getDbName
+  (JNIEnv * env, jclass obj, jint dbHandle)
+{
+    if((size_t) dbHandle > m_hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return env->NewStringUTF("-1");
+    } else {
+        TSK_HDB_INFO * temp = m_hashDbs.at(dbHandle-1);
+        if (temp == NULL) {
+            setThrowTskCoreError(env, "Error: database object is null");
+            return env->NewStringUTF("-1");
+        }
+
+
+        jstring jname = env->NewStringUTF(temp->db_name);
+        return jname;
+    }
+}
 
 JNIEXPORT void JNICALL
     Java_org_sleuthkit_datamodel_SleuthkitJNI_closeDbLookupsNat(JNIEnv * env,
@@ -360,9 +508,9 @@ JNIEXPORT void JNICALL
         m_NSRLDb = NULL;
     }
 
-    for_each(m_knownbads.begin(), m_knownbads.end(), tsk_hdb_close);
+    for_each(m_hashDbs.begin(), m_hashDbs.end(), tsk_hdb_close);
    
-    m_knownbads.clear();
+    m_hashDbs.clear();
 }
 
 /*
@@ -402,7 +550,7 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_nsrlDbLookup
 JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_knownBadDbLookup
 (JNIEnv * env, jclass obj, jstring hash, jint dbHandle){
 
-    if((size_t) dbHandle > m_knownbads.size()) {
+    if((size_t) dbHandle > m_hashDbs.size()) {
         setThrowTskCoreError(env, "Invalid database handle");
         return -1;
     }
@@ -415,7 +563,7 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_knownBadDbLooku
 
     
 
-    TSK_HDB_INFO * db = m_knownbads.at(dbHandle-1);
+    TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1);
 
     if(db != NULL) {
         int8_t retval = tsk_hdb_lookup_str(db, md5, TSK_HDB_FLAG_QUICK, NULL, NULL);
@@ -1349,7 +1497,7 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_startVerboseLoggingNat
  * @param dbPathJ path for the database
  */
 JNIEXPORT void JNICALL
-Java_org_sleuthkit_datamodel_SleuthkitJNI_createLookupIndexNat (JNIEnv * env,
+Java_org_sleuthkit_datamodel_SleuthkitJNI_createLookupIndexByPathNat (JNIEnv * env,
     jclass obj, jstring dbPathJ)
 {
     TSK_TCHAR dbPathT[1024];
@@ -1384,13 +1532,56 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_createLookupIndexNat (JNIEnv * env,
     tsk_hdb_close(temp);
 }
 
+/*
+ * Create an index for the given database
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param dbHandle handle for the database
+ */
+JNIEXPORT void JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_createLookupIndexNat (JNIEnv * env,
+    jclass obj, jint dbHandle)
+{
+    if((size_t) dbHandle > m_hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return;
+    } else {
+        TSK_HDB_INFO * temp = m_hashDbs.at(dbHandle-1);
+        if (temp == NULL) {
+            setThrowTskCoreError(env, "Error: database object is null");
+            return;
+        }
+
+        TSK_TCHAR dbType[1024];
+
+        if(temp->db_type == TSK_HDB_DBTYPE_MD5SUM_ID) {
+            TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_MD5SUM_STR);
+        }
+        else if(temp->db_type == TSK_HDB_DBTYPE_HK_ID) {
+            TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_HK_STR);
+        }
+        else if(temp->db_type == TSK_HDB_DBTYPE_ENCASE_ID) {
+            TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_ENCASE_STR);
+        }
+        else {
+            TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_NSRL_MD5_STR);
+        }
+
+        if (tsk_hdb_makeindex(temp, dbType)) {
+            setThrowTskCoreError(env, "Error creating index");
+        }
+
+        return;
+    }
+}
+
 /*
  * Check if an index exists for the given database path.
  * @param env pointer to java environment this was called from
  * @param obj the java object this was called from
  * @param dbPathJ path for the database
  */
-JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_lookupIndexExistsNat
+JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_lookupIndexExistsByPathNat
   (JNIEnv * env, jclass obj, jstring dbPathJ) {
 
     TSK_TCHAR dbPathT[1024];
@@ -1408,6 +1599,30 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_lookupIndex
     return (jboolean) retval == 1;
 }
 
+/*
+ * Check if an index exists for the given database.
+ * @param env pointer to java environment this was called from
+ * @param obj the java object this was called from
+ * @param dbHandle handle for the database
+ */
+JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_lookupIndexExistsNat
+  (JNIEnv * env, jclass obj, jint dbHandle) {
+
+    if((size_t) dbHandle > m_hashDbs.size()) {
+        setThrowTskCoreError(env, "Invalid database handle");
+        return (jboolean) false;
+    } else {
+        TSK_HDB_INFO * temp = m_hashDbs.at(dbHandle-1);
+        if (temp == NULL) {
+            return (jboolean) false;
+        }
+
+        uint8_t retval = tsk_hdb_hasindex(temp, TSK_HDB_HTYPE_MD5_ID);
+
+        return (jboolean) retval == 1;
+    }
+}
+
 /*
  * Get the size of the index for the database at the given path
  * @param env pointer to java environment this was called from
@@ -1428,7 +1643,7 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getIndexSizeNat
     }
 
     if(tsk_hdb_hasindex(temp, TSK_HDB_HTYPE_MD5_ID)) {
-        return (jint) ((temp->idx_size - temp->idx_off) / (temp->idx_llen));
+        return (jint) ((temp->idx_info->idx_struct.idx_binsrch->idx_size - temp->idx_info->idx_struct.idx_binsrch->idx_off) / (temp->idx_info->idx_struct.idx_binsrch->idx_llen));
     }
 
 
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h
index a61672bec3e934a9e5071fdc4a676e8388f79220..47261d57c71ad71f21d4c2fd2500a9cea62d9f55 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.h
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.h
@@ -65,14 +65,58 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_setDbNSRLNat
 JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_addDbKnownBadNat
   (JNIEnv *, jclass, jstring);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    newDbKnownBadNat
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_newDbKnownBadNat(JNIEnv * env,
+    jclass obj, jstring pathJ);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    addStrDbKnownBadNat
+ * Signature: 
+ */
+JNIEXPORT jint JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_addStrDbKnownBadNat(JNIEnv * env,
+    jclass obj, jstring filenameJ, jstring hashMd5J, jstring hashSha1J, jstring hashSha256J, jint dbHandle);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    isUpdateableDbKnownBadNat
+ * Signature: 
+ */
+JNIEXPORT jboolean JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_isUpdateableDbKnownBadNat(JNIEnv * env,
+    jclass obj, jint dbHandle);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    isIdxOnlyHashDbNat
+ * Signature: 
+ */
+JNIEXPORT jboolean JNICALL
+    Java_org_sleuthkit_datamodel_SleuthkitJNI_isIdxOnlyHashDbNat(JNIEnv * env,
+    jclass obj, jint dbHandle);
+
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    getDbName
  * Signature: (Ljava/lang/String;)Ljava/lang/String;
  */
-JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getDbName
+JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getDbNameByPath
   (JNIEnv *, jclass, jstring);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getHashDbName
+ * Signature: 
+ */
+JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getDbName
+  (JNIEnv *, jclass, jint dbHandle);
+
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    closeDbLookupsNat
@@ -259,19 +303,35 @@ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_closeFileNat
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
- * Method:    createLookupIndexNat
+ * Method:    createLookupIndexByPathNat
  * Signature: (Ljava/lang/String;)V
  */
+JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_createLookupIndexByPathNat
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    createLookupIndexNat
+ * Signature: 
+ */
 JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_createLookupIndexNat
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    lookupIndexExistsByPathNat
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_lookupIndexExistsByPathNat
   (JNIEnv *, jclass, jstring);
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    lookupIndexExistsNat
- * Signature: (Ljava/lang/String;)Z
+ * Signature: 
  */
 JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_lookupIndexExistsNat
-  (JNIEnv *, jclass, jstring);
+  (JNIEnv *, jclass, jint);
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index d0604c15532b0466298c232742875fad3779cb43..1ca4fe825b2dc6c6005b6760a8bd609764e2ba30 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -653,6 +653,9 @@ public AddImageProcess makeAddImageProcess(String timezone, boolean processUnall
 	 * @param path The path to the database
 	 * @return a handle for that database
 	 */
+	// BC: This is called by IngestModule
+	// Use jni.openNSRLDatabase instead
+	@Deprecated
 	public int setNSRLDatabase(String path) throws TskCoreException {
 		return this.caseHandle.setNSRLDatabase(path);
 	}
@@ -663,6 +666,8 @@ public int setNSRLDatabase(String path) throws TskCoreException {
 	 * @param path The path to the database
 	 * @return a handle for that database
 	 */
+	// use jni.openHashDatabase instead
+	@Deprecated
 	public int addKnownBadDatabase(String path) throws TskCoreException {
 		return this.caseHandle.addKnownBadDatabase(path);
 	}
@@ -673,6 +678,8 @@ public int addKnownBadDatabase(String path) throws TskCoreException {
 	 * @throws TskCoreException exception thrown if a critical error occurs
 	 * within tsk core
 	 */
+	// use jni.closeHashDatabases instead
+	@Deprecated
 	public void clearLookupDatabases() throws TskCoreException {
 		this.caseHandle.clearLookupDatabases();
 	}
@@ -4937,6 +4944,7 @@ void setMd5Hash(AbstractFile file, String md5Hash) throws TskCoreException {
 	 * @throws TskCoreException thrown if a critical error occurred within tsk
 	 * core
 	 */
+	@Deprecated
 	public TskData.FileKnown nsrlLookupMd5(String md5Hash) throws TskCoreException {
 		return SleuthkitJNI.nsrlHashLookup(md5Hash);
 	}
@@ -4950,6 +4958,7 @@ public TskData.FileKnown nsrlLookupMd5(String md5Hash) throws TskCoreException {
 	 * @throws TskCoreException thrown if a critical error occurred within tsk
 	 * core
 	 */
+	@Deprecated
 	public TskData.FileKnown knownBadLookupMd5(String md5Hash, int dbHandle) throws TskCoreException {
 		return SleuthkitJNI.knownBadHashLookup(md5Hash, dbHandle);
 	}
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
index 2d75ca64b1d27b8f81a40fdd461f3854154e284f..d0e6853ae2c8d1d4fefd3bcdff6428ebd70db897 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
@@ -54,7 +54,15 @@ public class SleuthkitJNI {
 
 	private static native int addDbKnownBadNat(String hashDbPath) throws TskCoreException;
 
-	private static native String getDbName(String hashDbPath) throws TskCoreException;
+    private static native int newDbKnownBadNat(String hashDbPath) throws TskCoreException;
+    
+    private static native int addStrDbKnownBadNat(String filename, String hashMd5, String hashSha1, String hashSha256, int dbHandle) throws TskCoreException;
+
+    private static native boolean isUpdateableDbKnownBadNat(int dbHandle);
+    
+	private static native String getDbNameByPath(String hashDbPath) throws TskCoreException;
+
+    private static native String getDbName(int dbHandle) throws TskCoreException;
 
 	private static native void closeDbLookupsNat() throws TskCoreException;
 
@@ -107,10 +115,16 @@ public class SleuthkitJNI {
 	private static native void closeFileNat(long fileHandle);
 
 	//hash-lookup database functions
-	private static native void createLookupIndexNat(String dbPath) throws TskCoreException;
+	private static native void createLookupIndexByPathNat(String dbPath) throws TskCoreException;
+    
+    private static native void createLookupIndexNat(int dbHandle) throws TskCoreException;
 
-	private static native boolean lookupIndexExistsNat(String dbPath) throws TskCoreException;
+	private static native boolean lookupIndexExistsByPathNat(String dbPath) throws TskCoreException;
+    
+    private static native boolean lookupIndexExistsNat(int dbHandle) throws TskCoreException;
 
+    private static native boolean isIdxOnlyHashDbNat(int dbHandle) throws TskCoreException;
+    
 	//util functions
 	private static native long findDeviceSizeNat(String devicePath) throws TskCoreException;
 
@@ -150,12 +164,16 @@ void free() throws TskCoreException {
 			SleuthkitJNI.closeCaseDbNat(caseDbPointer);
 		}
 
+		
+		/******************** Hash Database Methods ***********************/
 		/**
-		 * Clear currently set lookup databases within TSK
+		 * Close the currently open lookup databases 
 		 *
 		 * @throws TskCoreException exception thrown if critical error occurs
 		 * within TSK
 		 */
+		// use jni.closeHashDatabases() instead
+		@Deprecated
 		void clearLookupDatabases() throws TskCoreException {
 			closeDbLookupsNat();
 		}
@@ -166,20 +184,27 @@ void clearLookupDatabases() throws TskCoreException {
 		 * @param path The path to the database
 		 * @return a handle for that database
 		 */
+		// BC: Called by SleuthkitCase, which is called by IngestModule
+		// use jni.openNSRLDatabase() instead
+		@Deprecated
 		int setNSRLDatabase(String path) throws TskCoreException {
 			return setDbNSRLNat(path);
 		}
+		
 
 		/**
-		 * Add the known bad database
+		 * Open a hash bad database
 		 *
 		 * @param path The path to the database
 		 * @return a handle for that database
 		 */
+		// use jni.openHashDatabase() instead
+		@Deprecated
 		int addKnownBadDatabase(String path) throws TskCoreException {
 			return addDbKnownBadNat(path);
 		}
-
+		
+		
 		/**
 		 * Start the process of adding a disk image to the case
 		 *
@@ -574,16 +599,31 @@ public static void closeFile(long fileHandle) {
 		closeFileNat(fileHandle);
 	}
 
+	
+	/****************************** Hash database methods *****************/
 	/**
 	 * Create an index for the given database path.
 	 *
 	 * @param dbPath The path to the database
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Called by HashDb.
+	// use createLookupIndexForHashDatabase instead
+	@Deprecated    
 	public static void createLookupIndex(String dbPath) throws TskCoreException {
-		createLookupIndexNat(dbPath);
+		createLookupIndexByPathNat(dbPath);
 	}
 
+	/**
+	 * Create an index for the given database path.
+	 *
+	 * @param dbPath The path to the database
+	 * @throws TskCoreException if a critical error occurs within TSK core
+	 */
+	public static void createLookupIndexForHashDatabase(int dbHandle) throws TskCoreException {
+		createLookupIndexNat(dbHandle);
+	}    
+    
 	/**
 	 * Check if an index exists for the given database path.
 	 *
@@ -591,10 +631,25 @@ public static void createLookupIndex(String dbPath) throws TskCoreException {
 	 * @return true if index exists
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Called by HashDB
+	// use lookupIndexForHashDatabaseExists instead
+	@Deprecated        
 	public static boolean lookupIndexExists(String dbPath) throws TskCoreException {
-		return lookupIndexExistsNat(dbPath);
+		return lookupIndexExistsByPathNat(dbPath);
 	}
 
+    
+	/**
+	 * Check if an index exists for the given database path.
+	 *
+	 * @param dbPath
+	 * @return true if index exists
+	 * @throws TskCoreException if a critical error occurs within TSK core
+	 */
+	public static boolean hashDatabaseHasLookupIndex(int dbHandle) throws TskCoreException {
+		return lookupIndexExistsNat(dbHandle);
+	}    
+    
 	/**
 	 * Set the NSRL database
 	 *
@@ -602,31 +657,83 @@ public static boolean lookupIndexExists(String dbPath) throws TskCoreException {
 	 * @return a handle for that database
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Does not appear to be called. HashDBINgestModule calls SleuthkitCase.setNSRLDatabase, which calls the version of this in CaseHandle
+	// use openNSRLDatabase instead
+	@Deprecated
 	public static int setNSRLDatabase(String path) throws TskCoreException {
+		return openNSRLDatabase(path);
+	}
+	
+	public static int openNSRLDatabase(String path) throws TskCoreException {
 		return setDbNSRLNat(path);
 	}
+	
 
 	/**
-	 * Add the known bad database
+	 * Opens a hash database.  Supports the various formats that TSK supports
 	 *
 	 * @param path The path to the database
 	 * @return a handle for that database
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Does not appear to be called.  HashDBIngestModule calls SleuthkitCase.addKnownBad, which calls the version in CaseHandle
+	// use openHashDatabase instead
+	@Deprecated
 	public static int addKnownBadDatabase(String path) throws TskCoreException {
+		return openHashDatabase(path);
+	}
+	
+	public static int openHashDatabase(String path) throws TskCoreException {
 		return addDbKnownBadNat(path);
 	}
+	
+	
+	/**
+	 * Creates a hash database.  Will be of the default TSK hash database type.
+	 *
+	 * @param path The path to the database
+	 * @return a handle for that database
+	 * @throws TskCoreException if a critical error occurs within TSK core
+	 */
+	public static int createHashDatabase(String path) throws TskCoreException {		
+		return newDbKnownBadNat(path);
+	}
 
+	/**
+	 * Close the currently open lookup databases 
+	 *
+	 * @throws TskCoreException exception thrown if critical error occurs
+	 * within TSK
+	 */
+	public static void closeHashDatabases() throws TskCoreException {
+		closeDbLookupsNat();
+	}
+	
 	/**
 	 * Get the name of the database
 	 *
 	 * @param path The path to the database
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Used by HasDBAddDatabaseDialog an HashDBXML
+    //use getHashDatabaseName instead
+    @Deprecated
 	public static String getDatabaseName(String path) throws TskCoreException {
-		return getDbName(path);
+		return getDbNameByPath(path);
 	}
 
+	
+	/**
+	 * Get the name of the database
+	 *
+	 * @param dbHandle previously opened hash db handle
+	 * @throws TskCoreException if a critical error occurs within TSK core
+	 */
+	public static String getHashDatabaseName(int dbHandle) throws TskCoreException {
+		return getDbName(dbHandle);
+	}
+    
+    
 	/**
 	 * Look up the given hash in the NSRL database
 	 *
@@ -634,7 +741,14 @@ public static String getDatabaseName(String path) throws TskCoreException {
 	 * @return the status of the hash in the NSRL
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Called by SleuthkitCase -> Deprecated
+	// use lookupNSRLDatabase instead
+	@Deprecated
 	public static TskData.FileKnown nsrlHashLookup(String hash) throws TskCoreException {
+		return lookupInNSRLDatabase(hash);
+	}
+	
+	public static TskData.FileKnown lookupInNSRLDatabase(String hash) throws TskCoreException {
 		return TskData.FileKnown.valueOf((byte) nsrlDbLookup(hash));
 	}
 
@@ -646,10 +760,39 @@ public static TskData.FileKnown nsrlHashLookup(String hash) throws TskCoreExcept
 	 * @return the status of the hash in the known bad database
 	 * @throws TskCoreException if a critical error occurs within TSK core
 	 */
+	// BC: Called by SleuthkitCase -> Deprecated
+	// use lookupInHashDatabase instead
+	@Deprecated
 	public static TskData.FileKnown knownBadHashLookup(String hash, int dbHandle) throws TskCoreException {
+		return lookupInHashDatabase(hash, dbHandle);
+	}
+	
+	public static TskData.FileKnown lookupInHashDatabase(String hash, int dbHandle) throws TskCoreException {
 		return TskData.FileKnown.valueOf((byte) knownBadDbLookup(hash, dbHandle));
 	}
+	
+	/**
+	 * Adds a hash value to a hash database. 
+	 * @param filename Name of file (can be null)
+	 * @param md5 Text of MD5 hash (can be null)
+	 * @param sha1 Text of SHA1 hash (can be null)
+	 * @param sha256 Text of SHA256 hash (can be null)
+	 * @param dbHandle Handle to DB
+	 * @throws TskCoreException 
+	 */
+	public static void addToHashDatabase(String filename, String md5, String sha1, String sha256, int dbHandle) throws TskCoreException {
+		addStrDbKnownBadNat(filename, md5, sha1, sha256, dbHandle);
+	}
 
+    
+	public static boolean isUpdateableHashDatabase(int dbHandle) throws TskCoreException {
+		return isUpdateableDbKnownBadNat(dbHandle);
+	}    
+    
+    public static boolean hashDatabaseHasLegacyLookupIndexOnly(int dbHandle) throws TskCoreException {
+        return isIdxOnlyHashDbNat(dbHandle);
+    }
+    
 	/**
 	 * Get the size of the index of the given database
 	 *
@@ -657,6 +800,8 @@ public static TskData.FileKnown knownBadHashLookup(String hash, int dbHandle) th
 	 * @return the size of the index or -1 if it doesn't exist
 	 * @throws TskCoreException
 	 */
+	// BC: Does not appear to be used at all -> SHould probably go away.
+	@Deprecated
 	public static int getIndexSize(String path) throws TskCoreException {
 		return getIndexSizeNat(path);
 	}
diff --git a/tools/hashtools/hfind.cpp b/tools/hashtools/hfind.cpp
index 0486c25b5f8b33cb456047d136017d77cae4d767..5614a269c83edbc8d15c08a29a6815c701030b8c 100644
--- a/tools/hashtools/hfind.cpp
+++ b/tools/hashtools/hfind.cpp
@@ -22,13 +22,15 @@ usage()
 {
     TFPRINTF(stderr,
              _TSK_T
-             ("usage: %s [-eqV] [-f lookup_file] [-i db_type] db_file [hashes]\n"),
+             ("usage: %s [-eqVa] [-c db_name] [-f lookup_file] [-i db_type] db_file [hashes]\n"),
              progname);
     tsk_fprintf(stderr,
                 "\t-e: Extended mode - where values other than just the name are printed\n");
     tsk_fprintf(stderr,
                 "\t-q: Quick mode - where a 1 is printed if it is found, else 0\n");
     tsk_fprintf(stderr, "\t-V: Print version to STDOUT\n");
+    tsk_fprintf(stderr, "\t-c db_name: Create blank index with the given name.\n");
+    tsk_fprintf(stderr, "\t-a: Add given hashes to the database.\n");
     tsk_fprintf(stderr,
                 "\t-f lookup_file: File with one hash per line to lookup\n");
     tsk_fprintf(stderr,
@@ -73,7 +75,9 @@ main(int argc, char ** argv1)
     unsigned int flags = 0;
     TSK_HDB_INFO *hdb_info;
     TSK_TCHAR **argv;
-    
+    bool create = false;
+    bool addHash = false;
+
 #ifdef TSK_WIN32
     // On Windows, get the wide arguments (mingw doesn't support wmain)
     argv = CommandLineToArgvW(GetCommandLineW(), &argc);
@@ -88,7 +92,7 @@ main(int argc, char ** argv1)
     progname = argv[0];
     setlocale(LC_ALL, "");
 
-    while ((ch = GETOPT(argc, argv, _TSK_T("ef:i:qV"))) > 0) {
+    while ((ch = GETOPT(argc, argv, _TSK_T("cef:i:aqV"))) > 0) {
         switch (ch) {
         case _TSK_T('e'):
             flags |= TSK_HDB_FLAG_EXT;
@@ -102,6 +106,14 @@ main(int argc, char ** argv1)
             idx_type = OPTARG;
             break;
 
+        case _TSK_T('c'):
+            create = true;
+            break;
+
+        case _TSK_T('a'):
+            addHash = true;
+            break;
+
         case _TSK_T('q'):
             flags |= TSK_HDB_FLAG_QUICK;
             break;
@@ -123,9 +135,26 @@ main(int argc, char ** argv1)
 
     db_file = argv[OPTIND++];
 
-    if ((hdb_info = tsk_hdb_open(db_file, TSK_HDB_OPEN_NONE)) == NULL) {
-        tsk_error_print(stderr);
-        return 1;
+    // Make a new database (creates an index from scratch)
+    if (create) {
+        if ((hdb_info = tsk_hdb_new(db_file)) == NULL) {
+            tsk_error_print(stderr);
+            return 1;
+        } else {
+            printf("New index %"PRIttocTSK" created.\n", db_file);
+            return 0;
+        }
+    } else {
+        // Open an existing database
+        TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_NONE;
+        if(addHash) {
+            flags = TSK_HDB_OPEN_IDXONLY;
+        }
+
+        if ((hdb_info = tsk_hdb_open(db_file, flags)) == NULL) {
+            tsk_error_print(stderr);
+            return 1;
+        }
     }
 
     /* What mode are we going to run in 
@@ -191,19 +220,33 @@ main(int argc, char ** argv1)
             }
             htmp[i] = '\0';
 
-            /* Perform lookup */
-            retval =
-                tsk_hdb_lookup_str(hdb_info, (const char *)htmp, 
-                        (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL);
-            if (retval == -1) {
-                tsk_error_print(stderr);
-                return 1;
-            }
-            if (flags & TSK_HDB_FLAG_QUICK) {
-                printf("%d\n", retval);
-            }
-            else if (retval == 0) {
-                print_notfound(htmp);
+            if (addHash) {
+                // Write a new hash to the database/index, if it's updateable
+                //@todo support sha1 and sha2-256
+                retval = tsk_hdb_add_str(hdb_info, NULL, (const char *)htmp, NULL, NULL);
+                if (retval == 1) {
+                    printf("There was an error adding the hash.\n");
+                    tsk_error_print(stderr);
+                    return 1;
+                } else if (retval == -1) {
+                    printf("Database is not updateable.\n");
+                } else if (retval == 0) {
+                    printf("Hash %s added.\n", htmp);
+                }
+            } else {
+                /* Perform lookup */
+                retval = tsk_hdb_lookup_str(hdb_info, (const char *)htmp, 
+                         (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL);
+                if (retval == -1) {
+                    tsk_error_print(stderr);
+                    return 1;
+                }
+                if (flags & TSK_HDB_FLAG_QUICK) {
+                    printf("%d\n", retval);
+                }
+                else if (retval == 0) {
+                    print_notfound(htmp);
+                }
             }
             OPTIND++;
         }
diff --git a/tsk/hashdb/Makefile.am b/tsk/hashdb/Makefile.am
index 7a1c074edfaca419310822544286298b7ac93333..7ab062132f0d2d6c5b11d30e513387ae0db6bb78 100644
--- a/tsk/hashdb/Makefile.am
+++ b/tsk/hashdb/Makefile.am
@@ -2,11 +2,13 @@ AM_CPPFLAGS = -I../.. -I$(srcdir)/../.. -Wall
 EXTRA_DIST = .indent.pro
 
 noinst_LTLIBRARIES = libtskhashdb.la
-libtskhashdb_la_SOURCES = tm_lookup.c md5sum_index.c nsrl_index.c \
-    hk_index.c idxonly_index.c encase_index.c tsk_hashdb_i.h
+libtskhashdb_la_SOURCES = binsrch_index.c sqlite_index.cpp \
+    tm_lookup.cpp md5sum.c nsrl.c \
+    hdb_open.cpp hdb_index.cpp \
+    hashkeeper.c idxonly.c encase.c tsk_hashdb_i.h
 
 indent:
-	indent *.c *.h
+	indent *.cpp *.c *.h
 
 clean-local:
 	-rm -f *.c~ *.h~
diff --git a/tsk/hashdb/binsrch_index.c b/tsk/hashdb/binsrch_index.c
new file mode 100644
index 0000000000000000000000000000000000000000..24f618037f20c0bc07458114120207f79d23071e
--- /dev/null
+++ b/tsk/hashdb/binsrch_index.c
@@ -0,0 +1,700 @@
+
+/*
+ * The Sleuth Kit
+ *
+ * Brian Carrier [carrier <at> sleuthkit [dot] org]
+ * Copyright (c) 2003-2011 Brian Carrier.  All rights reserved
+ *
+ *
+ * This software is distributed under the Common Public License 1.0
+ *
+ */
+
+#include "tsk_hashdb_i.h"
+
+/**
+ * \file binsrch_index.c
+ * Contains functions for creating the original binary search / ASCII index
+ * and looking up values in it. 
+ */
+
+/** Initialize the TSK hash DB index file. This creates the intermediate file,
+ * which will have entries added to it.  This file must be sorted before the 
+ * process is finished.
+ *
+ * @param hdb_info Hash database state structure
+ * @param htype String of index type to create
+ *
+ * @return 1 on error and 0 on success
+ *
+ */
+    uint8_t
+binsrch_initialize(TSK_HDB_INFO * hdb_info, TSK_TCHAR * htype)
+{
+    // Creating plain text indices is unsupported
+    tsk_error_reset();
+    tsk_error_set_errno(TSK_ERR_HDB_UNSUPTYPE);
+    tsk_error_set_errstr("binsrch_initialize: Creating plain text indices is unsupported.");
+    return 1;
+}
+
+/**
+ * Add a string entry to the intermediate index file.
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue String of hash value to add
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+    uint8_t
+binsrch_addentry(TSK_HDB_INFO * hdb_info, char *hvalue,
+        TSK_OFF_T offset)
+{
+    // Creating plain text indices is unsupported
+    tsk_error_reset();
+    tsk_error_set_errno(TSK_ERR_HDB_UNSUPTYPE);
+    tsk_error_set_errstr("binsrch_addentry: Creating plain text indices is unsupported.");
+    return 1;
+}
+
+/**
+ * Add a binary entry to the intermediate index file.
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue Array of integers of hash value to add
+ * @param hlen Number of bytes in hvalue
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+    uint8_t
+binsrch_addentry_bin(TSK_HDB_INFO * hdb_info, unsigned char *hvalue, int hlen,
+        TSK_OFF_T offset)
+{
+    // Creating plain text indices is unsupported
+    tsk_error_reset();
+    tsk_error_set_errno(TSK_ERR_HDB_UNSUPTYPE);
+    tsk_error_set_errstr("binsrch_addentry_bin: Creating plain text indices is unsupported.");
+    return 1;
+}
+
+/**
+ * Finalize index creation process by sorting the index and removing the
+ * intermediate temp file.
+ *
+ * @param hdb_info Hash database state info structure.
+ * @return 1 on error and 0 on success
+ */
+    uint8_t
+binsrch_finalize(TSK_HDB_INFO * hdb_info)
+{
+    // Creating plain text indices is unsupported
+    tsk_error_reset();
+    tsk_error_set_errno(TSK_ERR_HDB_UNSUPTYPE);
+    tsk_error_set_errstr("binsrch_finalize: Creating plain text indices is unsupported.");
+    return 1;
+}
+
+
+/** \internal
+ * Setup the internal variables to read an index. This
+ * opens the index and sets the needed size information.
+ *
+ * @param hdb_info Hash database to analyze
+ * @param hash The hash type that was used to make the index.
+ *
+ * @return 1 on error and 0 on success
+ */
+    uint8_t
+binsrch_open(TSK_HDB_INFO * hdb_info, TSK_IDX_INFO * idx_info, uint8_t htype)
+{
+    char head[TSK_HDB_MAXLEN];
+    char head2[TSK_HDB_MAXLEN];
+    char *ptr;
+
+
+    if ((idx_info->idx_struct.idx_binsrch =
+                (TSK_IDX_BINSRCH *) tsk_malloc
+                (sizeof(TSK_IDX_BINSRCH))) == NULL) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                "binsrch_open: Malloc error");
+        return 1;
+    }
+
+    if ((htype != TSK_HDB_HTYPE_MD5_ID)
+            && (htype != TSK_HDB_HTYPE_SHA1_ID)) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                "binsrch_open: Invalid hash type : %d", htype);
+        return 1;
+    }
+
+    idx_info->idx_struct.idx_binsrch->idx_llen = TSK_HDB_IDX_LEN(htype);
+
+    /* Verify the index exists, get its size, and open it */
+#ifdef TSK_WIN32
+    {
+        HANDLE hWin;
+        DWORD szLow, szHi;
+
+        if (-1 == GetFileAttributes(idx_info->idx_fname)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+            tsk_error_set_errstr(
+                    "binsrch_open: Error finding index file: %"PRIttocTSK,
+                    idx_info->idx_fname);
+            return 1;
+        }
+
+        if ((hWin = CreateFile(idx_info->idx_fname, GENERIC_READ,
+                        FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) ==
+                INVALID_HANDLE_VALUE) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+            tsk_error_set_errstr(
+                    "binsrch_open: Error opening index file: %"PRIttocTSK,
+                    idx_info->idx_fname);
+            return 1;
+        }
+        idx_info->idx_struct.idx_binsrch->hIdx =
+            _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r");
+        if (idx_info->idx_struct.idx_binsrch->hIdx == NULL) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+            tsk_error_set_errstr(
+                    "binsrch_open: Error converting Windows handle to C handle");
+            return 1;
+        }
+
+        szLow = GetFileSize(hWin, &szHi);
+        if (szLow == 0xffffffff) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+            tsk_error_set_errstr(
+                    "binsrch_open: Error getting size of index file: %"PRIttocTSK" - %d",
+                    idx_info->idx_fname, (int)GetLastError());
+            return 1;
+        }
+        idx_info->idx_struct.idx_binsrch->idx_size = szLow | ((uint64_t) szHi << 32);
+    }
+
+#else
+    {
+        struct stat sb;
+        if (stat(idx_info->idx_fname, &sb) < 0) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+            tsk_error_set_errstr(
+                    "binsrch_open: Error finding index file: %s",
+                    idx_info->idx_fname);
+            return 1;
+        }
+        idx_info->idx_struct.idx_binsrch->idx_size = sb.st_size;
+
+        if (NULL == (idx_info->idx_struct.idx_binsrch->hIdx = fopen(idx_info->idx_fname, "r"))) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+            tsk_error_set_errstr(
+                    "binsrch_open: Error opening index file: %s",
+                    idx_info->idx_fname);
+            return 1;
+        }
+    }
+#endif
+
+
+    /* Do some testing on the first line */
+    if (NULL == fgets(head, TSK_HDB_MAXLEN, idx_info->idx_struct.idx_binsrch->hIdx)) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+        tsk_error_set_errstr(
+                 "hdb_setupindex: Header line of index file");
+        return 1;
+    }
+
+    if (strncmp(head, TSK_HDB_IDX_HEAD_TYPE_STR, strlen(TSK_HDB_IDX_HEAD_TYPE_STR))
+        != 0) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+        tsk_error_set_errstr(
+                 "hdb_setupindex: Invalid index file: Missing header line");
+        return 1;
+    }
+
+    /* Do some testing on the second line */
+    if (NULL == fgets(head2, TSK_HDB_MAXLEN, idx_info->idx_struct.idx_binsrch->hIdx)) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+        tsk_error_set_errstr(
+                 "hdb_setupindex: Error reading line 2 of index file");
+        return 1;
+    }
+
+    /* Set the offset to the start of the index entries */
+    if (strncmp(head2, TSK_HDB_IDX_HEAD_NAME_STR, strlen(TSK_HDB_IDX_HEAD_NAME_STR))
+        != 0) {
+        idx_info->idx_struct.idx_binsrch->idx_off = (uint16_t) (strlen(head));
+    } else {
+        idx_info->idx_struct.idx_binsrch->idx_off = (uint16_t) (strlen(head) + strlen(head2));
+    }
+
+
+    /* Skip the space */
+    ptr = &head[strlen(TSK_HDB_IDX_HEAD_TYPE_STR) + 1];
+
+    ptr[strlen(ptr) - 1] = '\0';
+    if ((ptr[strlen(ptr) - 1] == 10) || (ptr[strlen(ptr) - 1] == 13)) {
+        ptr[strlen(ptr) - 1] = '\0';
+        idx_info->idx_struct.idx_binsrch->idx_llen++;   // make the expected index length longer to account for different cr/nl/etc.
+    }
+
+    /* Verify the header value in the index */
+    if (strcmp(ptr, TSK_HDB_DBTYPE_NSRL_STR) == 0) {
+        if ((hdb_info->db_type != TSK_HDB_DBTYPE_NSRL_ID) &&
+            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+            tsk_error_set_errstr(
+                     "hdb_indexsetup: DB detected as %s, index type has NSRL",
+                     ptr);
+            return 1;
+        }
+    }
+    else if (strcmp(ptr, TSK_HDB_DBTYPE_MD5SUM_STR) == 0) {
+        if ((hdb_info->db_type != TSK_HDB_DBTYPE_MD5SUM_ID) &&
+            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+            tsk_error_set_errstr(
+                     "hdb_indexsetup: DB detected as %s, index type has MD5SUM",
+                     ptr);
+            return 1;
+        }
+    }
+    else if (strcmp(ptr, TSK_HDB_DBTYPE_HK_STR) == 0) {
+        if ((hdb_info->db_type != TSK_HDB_DBTYPE_HK_ID) &&
+            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+            tsk_error_set_errstr(
+                     "hdb_indexsetup: DB detected as %s, index type has hashkeeper",
+                     ptr);
+            return 1;
+        }
+    }
+    else if (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+        tsk_error_set_errstr(
+                 "hdb_setupindex: Unknown Database Type in index header: %s",
+                 ptr);
+        return 1;
+    }
+
+    /* Do some sanity checking */
+    if (((idx_info->idx_struct.idx_binsrch->idx_size - idx_info->idx_struct.idx_binsrch->idx_off) % idx_info->idx_struct.idx_binsrch->idx_llen) !=
+        0) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
+        tsk_error_set_errstr(
+                 "hdb_setupindex: Error, size of index file is not a multiple of row size");
+        return 1;
+    }
+
+    /* allocate a buffer for a row */
+    if ((idx_info->idx_struct.idx_binsrch->idx_lbuf = tsk_malloc(idx_info->idx_struct.idx_binsrch->idx_llen + 1)) == NULL) {
+        return 1;
+    }
+
+    return 0;
+}
+
+
+
+/**
+ * \ingroup hashdblib
+ * Search the index for a text/ASCII hash value
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash Hash value to search for (NULL terminated string)
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+int8_t
+binsrch_lookup_str(TSK_HDB_INFO * hdb_info, const char *hash,
+                   TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action,
+                   void *ptr)
+{
+    TSK_OFF_T poffset;
+    TSK_OFF_T up;               // Offset of the first byte past the upper limit that we are looking in
+    TSK_OFF_T low;              // offset of the first byte of the lower limit that we are looking in
+    int cmp;
+    uint8_t wasFound = 0;
+    size_t i;
+    uint8_t htype;
+
+
+    /* Sanity checks on the hash input */
+    if (strlen(hash) == TSK_HDB_HTYPE_MD5_LEN) {
+        htype = TSK_HDB_HTYPE_MD5_ID;
+    }
+    else if (strlen(hash) == TSK_HDB_HTYPE_SHA1_LEN) {
+        htype = TSK_HDB_HTYPE_SHA1_ID;
+    }
+    else {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                 "hdb_lookup: Invalid hash length: %s", hash);
+        return -1;
+    }
+
+    for (i = 0; i < strlen(hash); i++) {
+        if (isxdigit((int) hash[i]) == 0) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr(
+                     "hdb_lookup: Invalid hash value (hex only): %s",
+                     hash);
+            return -1;
+        }
+    }
+
+    /* Sanity check */
+    if (hdb_info->hash_len != strlen(hash)) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                 "hdb_lookup: Hash passed is different size than expected (%d vs %Zd)",
+                 hdb_info->hash_len, strlen(hash));
+        return -1;
+    }
+
+
+    low = hdb_info->idx_info->idx_struct.idx_binsrch->idx_off;
+    up = hdb_info->idx_info->idx_struct.idx_binsrch->idx_size;
+
+    poffset = 0;
+
+    // We have to lock access to idx_info->idx_struct.idx_binsrch->idx_lbuf, but since we're in a loop,
+    // I'm assuming one lock up front is better than many inside.
+    tsk_take_lock(&hdb_info->lock);
+
+    while (1) {
+        TSK_OFF_T offset;
+
+        /* If top and bottom are the same, it's not there */
+        if (up == low) {
+            tsk_release_lock(&hdb_info->lock);
+            return 0;
+        }
+
+        /* Get the middle of the windows that we are looking at */
+        offset = rounddown(((up - low) / 2), hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen);
+
+        /* Sanity Check */
+        if ((offset % hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen) != 0) {
+            tsk_release_lock(&hdb_info->lock);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
+            tsk_error_set_errstr(
+                     "hdb_lookup: Error, new offset is not a multiple of the line length");
+            return -1;
+        }
+
+        /* The middle offset is relative to the low offset, so add them */
+        offset += low;
+
+        /* If we didn't move, then it's not there */
+        if (poffset == offset) {
+            tsk_release_lock(&hdb_info->lock);
+            return 0;
+        }
+
+        /* Seek to the offset and read it */
+        if (0 != fseeko(hdb_info->idx_info->idx_struct.idx_binsrch->hIdx, offset, SEEK_SET)) {
+            tsk_release_lock(&hdb_info->lock);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+            tsk_error_set_errstr(
+                     "hdb_lookup: Error seeking in search: %" PRIuOFF,
+                     offset);
+            return -1;
+        }
+
+        if (NULL ==
+            fgets(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf, (int) hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen + 1,
+                  hdb_info->idx_info->idx_struct.idx_binsrch->hIdx)) {
+            if (feof(hdb_info->idx_info->idx_struct.idx_binsrch->hIdx)) {
+                tsk_release_lock(&hdb_info->lock);
+                return 0;
+            }
+            tsk_release_lock(&hdb_info->lock);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+            tsk_error_set_errstr(
+                     "Error reading index file: %lu",
+                     (unsigned long) offset);
+            return -1;
+        }
+
+        /* Sanity Check */
+        if ((strlen(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf) < hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen) ||
+            (hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len] != '|')) {
+            tsk_release_lock(&hdb_info->lock);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
+            tsk_error_set_errstr(
+                     "Invalid line in index file: %lu (%s)",
+                     (unsigned long) (offset / hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen),
+                     hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf);
+            return -1;
+        }
+
+        /* Set the delimter to NULL so we can treat the hash as a string */
+        hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len] = '\0';
+        cmp = strcasecmp(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf, hash);
+
+        /* The one we just read is too small, so set the new lower bound
+         * at the start of the next row */
+        if (cmp < 0) {
+            low = offset + hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen;
+        }
+
+        /* The one we just read is too big, so set the upper bound at this
+         * entry */
+        else if (cmp > 0) {
+            up = offset;
+        }
+
+        /* We found it */
+        else {
+            wasFound = 1;
+
+            if ((flags & TSK_HDB_FLAG_QUICK)
+                || (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)) {
+                tsk_release_lock(&hdb_info->lock);
+                return 1;
+            }
+            else {
+                TSK_OFF_T tmpoff, db_off;
+
+#ifdef TSK_WIN32
+                db_off =
+                    _atoi64(&hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len + 1]);
+#else
+                db_off =
+                    strtoull(&hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len + 1],
+                             NULL, 10);
+#endif
+
+                /* Print the one that we found first */
+                if (hdb_info->
+                    getentry(hdb_info, hash, db_off, flags, action, ptr)) {
+                    tsk_release_lock(&hdb_info->lock);
+                    tsk_error_set_errstr2( "hdb_lookup");
+                    return -1;
+                }
+
+
+                /* there could be additional entries both before and after
+                 * this entry - but we can restrict ourselves to the up
+                 * and low bounds from our previous hunting 
+                 */
+
+                tmpoff = offset - hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen;
+                while (tmpoff >= low) {
+
+                    /* Break if we are at the header */
+                    if (tmpoff <= 0)
+                        break;
+
+                    if (0 != fseeko(hdb_info->idx_info->idx_struct.idx_binsrch->hIdx, tmpoff, SEEK_SET)) {
+                        tsk_release_lock(&hdb_info->lock);
+                        tsk_error_reset();
+                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+                        tsk_error_set_errstr(
+                                 "hdb_lookup: Error seeking for prev entries: %"
+                                 PRIuOFF, tmpoff);
+                        return -1;
+                    }
+
+                    if (NULL ==
+                        fgets(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf,
+                              (int) hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen + 1,
+                              hdb_info->idx_info->idx_struct.idx_binsrch->hIdx)) {
+                        tsk_release_lock(&hdb_info->lock);
+                        tsk_error_reset();
+                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+                        tsk_error_set_errstr(
+                                 "Error reading index file (prev): %lu",
+                                 (unsigned long) tmpoff);
+                        return -1;
+                    }
+                    else if (strlen(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf) <
+                             hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen) {
+                        tsk_release_lock(&hdb_info->lock);
+                        tsk_error_reset();
+                        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
+                        tsk_error_set_errstr(
+                                 "Invalid index file line (prev): %lu",
+                                 (unsigned long) tmpoff);
+                        return -1;
+                    }
+
+                    hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len] = '\0';
+                    if (strcasecmp(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf, hash) != 0) {
+                        break;
+                    }
+
+#ifdef TSK_WIN32
+                    db_off =
+                        _atoi64(&hdb_info->
+                                idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len + 1]);
+#else
+
+                    db_off =
+                        strtoull(&hdb_info->
+                                 idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len + 1], NULL,
+                                 10);
+#endif
+                    if (hdb_info->
+                        getentry(hdb_info, hash, db_off, flags, action,
+                                 ptr)) {
+                        tsk_release_lock(&hdb_info->lock);
+                        return -1;
+                    }
+                    tmpoff -= hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen;
+                }
+
+                /* next entries */
+                tmpoff = offset + hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen;
+                while (tmpoff < up) {
+
+                    if (0 != fseeko(hdb_info->idx_info->idx_struct.idx_binsrch->hIdx, tmpoff, SEEK_SET)) {
+                        tsk_release_lock(&hdb_info->lock);
+                        tsk_error_reset();
+                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+                        tsk_error_set_errstr(
+                                 "hdb_lookup: Error seeking for next entries: %"
+                                 PRIuOFF, tmpoff);
+                        return -1;
+                    }
+
+                    if (NULL ==
+                        fgets(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf,
+                              (int) hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen + 1,
+                              hdb_info->idx_info->idx_struct.idx_binsrch->hIdx)) {
+                        if (feof(hdb_info->idx_info->idx_struct.idx_binsrch->hIdx))
+                            break;
+                        tsk_release_lock(&hdb_info->lock);
+                        tsk_error_reset();
+                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
+                        tsk_error_set_errstr(
+                                 "Error reading index file (next): %lu",
+                                 (unsigned long) tmpoff);
+                        return -1;
+                    }
+                    else if (strlen(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf) <
+                             hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen) {
+                        tsk_release_lock(&hdb_info->lock);
+                        tsk_error_reset();
+                        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
+                        tsk_error_set_errstr(
+                                 "Invalid index file line (next): %lu",
+                                 (unsigned long) tmpoff);
+                        return -1;
+                    }
+
+                    hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len] = '\0';
+                    if (strcasecmp(hdb_info->idx_info->idx_struct.idx_binsrch->idx_lbuf, hash) != 0) {
+                        break;
+                    }
+#ifdef TSK_WIN32
+                    db_off =
+                        _atoi64(&hdb_info->
+                                idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len + 1]);
+#else
+                    db_off =
+                        strtoull(&hdb_info->
+                                 idx_info->idx_struct.idx_binsrch->idx_lbuf[hdb_info->hash_len + 1], NULL,
+                                 10);
+#endif
+                    if (hdb_info->
+                        getentry(hdb_info, hash, db_off, flags, action,
+                                 ptr)) {
+                        tsk_release_lock(&hdb_info->lock);
+                        return -1;
+                    }
+
+                    tmpoff += hdb_info->idx_info->idx_struct.idx_binsrch->idx_llen;
+                }
+            }
+            break;
+        }
+        poffset = offset;
+    }
+    tsk_release_lock(&hdb_info->lock);
+
+    return wasFound;
+}
+
+/**
+ * \ingroup hashdblib
+ * Search the index for the given hash value given (in binary form).
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash Array with binary hash value to search for
+ * @param len Number of bytes in binary hash value
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+int8_t
+binsrch_lookup_raw(TSK_HDB_INFO * hdb_info, uint8_t * hash, uint8_t len,
+                   TSK_HDB_FLAG_ENUM flags,
+                   TSK_HDB_LOOKUP_FN action, void *ptr)
+{
+    char hashbuf[TSK_HDB_HTYPE_SHA1_LEN + 1];
+    int i;
+    static const char hex[] = "0123456789abcdef";
+
+    if (2 * len > TSK_HDB_HTYPE_SHA1_LEN) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                 "tsk_hdb_lookup_raw: hash value too long\n");
+        return -1;
+    }
+
+    for (i = 0; i < len; i++) {
+        hashbuf[2 * i] = hex[(hash[i] >> 4) & 0xf];
+        hashbuf[2 * i + 1] = hex[hash[i] & 0xf];
+    }
+    hashbuf[2 * len] = '\0';
+
+    return tsk_hdb_lookup_str(hdb_info, hashbuf, flags, action, ptr);
+}
+
+int8_t
+binsrch_get_properties(TSK_HDB_INFO * hdb_info)
+{
+    // Always false
+    hdb_info->idx_info->updateable = 0;
+    return 0;
+}
+
+void
+binsrch_close(TSK_IDX_INFO * idx_info)
+{
+    //Nothing to do here...
+}
diff --git a/tsk/hashdb/encase_index.c b/tsk/hashdb/encase.c
similarity index 100%
rename from tsk/hashdb/encase_index.c
rename to tsk/hashdb/encase.c
diff --git a/tsk/hashdb/hk_index.c b/tsk/hashdb/hashkeeper.c
similarity index 99%
rename from tsk/hashdb/hk_index.c
rename to tsk/hashdb/hashkeeper.c
index 4fc284e5c461d415f7b97a556118fbc5caf492b7..c7776b6b9bda726ed0d9117844fadd1e968a70e2 100644
--- a/tsk/hashdb/hk_index.c
+++ b/tsk/hashdb/hashkeeper.c
@@ -401,7 +401,7 @@ hk_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset,
         }
 
         if (NULL ==
-            fgets(hdb_info->idx_lbuf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
+            fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
             if (feof(hdb_info->hDb)) {
                 break;
             }
diff --git a/tsk/hashdb/hdb_index.cpp b/tsk/hashdb/hdb_index.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b96c2a33ffa9c0c2d058640df35635faef378e69
--- /dev/null
+++ b/tsk/hashdb/hdb_index.cpp
@@ -0,0 +1,702 @@
+/*
+ * The Sleuth Kit
+ *
+ * Brian Carrier [carrier <at> sleuthkit [dot] org]
+ * Copyright (c) 2003-2013 Brian Carrier.  All rights reserved
+ *
+ *
+ * This software is distributed under the Common Public License 1.0
+ */
+
+#include "tsk_hashdb_i.h"
+
+
+/**
+ * \file hdb_index.cpp
+ * Contains the code to make indexes for databases.
+ */
+
+
+/**
+ * Open a file and return a handle to it.
+ */
+static FILE *
+tsk_idx_open_file(TSK_TCHAR *idx_fname)
+{
+    if (idx_fname == NULL) {
+        return NULL;
+    }
+
+    FILE * idx = NULL;
+
+#ifdef TSK_WIN32
+    {
+        HANDLE hWin;
+        //DWORD szLow, szHi;
+
+        if (-1 == GetFileAttributes(idx_fname)) {
+            //tsk_release_lock(&idx_info->lock);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+            tsk_error_set_errstr(
+                    "tsk_idx_open_file: Error finding index file: %"PRIttocTSK,
+                    idx_fname);
+            return NULL;
+        }
+
+        if ((hWin = CreateFile(idx_fname, GENERIC_READ,
+                        FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) ==
+                INVALID_HANDLE_VALUE) {
+            //tsk_release_lock(&idx_info->lock);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+            tsk_error_set_errstr(
+                    "tsk_idx_open_file: Error opening index file: %"PRIttocTSK,
+                    idx_fname);
+            return NULL;
+        }
+
+        idx = _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r");
+    }
+#else
+    {
+        idx = fopen(idx_fname, "r");
+    }
+#endif
+
+    return idx;
+}
+
+
+static void
+tsk_idx_close_file(FILE * idx)
+{
+    if (idx == NULL) {
+        return;
+    }
+
+    // fclose should work on all platforms:
+    if (fclose(idx) != 0) {
+        tsk_error_set_errstr2("tsk_idx_close_file: Error closing index file object.");
+    }
+}
+
+/**
+ * Update the hash type. New indices can handle multiple hash types, so hash
+ * type is now dependent on what the client is doing (e.g. lookup md5).
+ * @return 1 on error, 0 on success
+ */
+static int
+hdb_update_htype(TSK_HDB_INFO * hdb_info, uint8_t htype)
+{
+    /* Get hash type specific information */
+    switch (htype) {
+        case TSK_HDB_HTYPE_MD5_ID:
+            hdb_info->hash_type = static_cast<TSK_HDB_HTYPE_ENUM>(htype);
+            hdb_info->hash_len = TSK_HDB_HTYPE_MD5_LEN;
+            break;
+        case TSK_HDB_HTYPE_SHA1_ID:
+            hdb_info->hash_type = static_cast<TSK_HDB_HTYPE_ENUM>(htype);
+            hdb_info->hash_len = TSK_HDB_HTYPE_SHA1_LEN;
+            break;
+        default:
+            return 1;
+    }
+    return 0;
+}
+
+/**
+ * Open an index for the given hash db
+ * We only create kdb (SQLite) files, but can open old indexes.
+ * @return NULL on error, TSK_IDX_INFO instance on success
+ */
+// @@@ htype should be enum
+static TSK_IDX_INFO *
+tsk_idx_open(TSK_HDB_INFO * hdb_info, uint8_t htype, uint8_t create)
+{
+    TSK_IDX_INFO * idx_info;
+    size_t flen;
+    const int header_size = 16;
+    char header[header_size];
+    FILE * idx = NULL;
+
+    if (hdb_info->idx_info != NULL) {
+        return hdb_info->idx_info;
+    }
+
+    if ((idx_info =
+         (TSK_IDX_INFO *) tsk_malloc(sizeof(TSK_IDX_INFO))) == NULL) {
+        return NULL;
+    }
+
+    hdb_info->idx_info = idx_info;
+
+    /* Make the name for the index file */
+    flen = TSTRLEN(hdb_info->db_fname) + 32;
+    idx_info->idx_fname =
+        (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR));
+    if (idx_info->idx_fname == NULL) {
+        free(idx_info);
+        // @@@ ERROR INFO NEEDED
+        return NULL;
+    }
+
+    if (hdb_update_htype(hdb_info, htype) == 1) {
+        free(idx_info);
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+        tsk_error_set_errstr(
+            "tsk_idx_open: Unknown hash type: %d\n",
+            (int)htype);
+        return NULL;
+    }
+
+    // Verify the new SQLite index exists, get its size, and open it for header reading
+    
+    // Set SQLite index filename
+
+    // Do not auto-add .kdb extension if we are creating a blank kdb file.
+    bool newBlank = (create == 1) && (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID);
+    
+    // Check if it already has a .kdb extension
+    TSK_TCHAR * c;
+    c = TSTRRCHR(hdb_info->db_fname, _TSK_T('.'));    
+    if (newBlank || ((c != NULL) && (TSTRLEN(c) >= 4)
+        && (TSTRCMP(c, _TSK_T(".kdb")) == 0))) {
+
+        TSTRNCPY(idx_info->idx_fname, hdb_info->db_fname, TSTRLEN(hdb_info->db_fname));
+    } else {
+        TSNPRINTF(idx_info->idx_fname, flen,
+            _TSK_T("%s.kdb"), hdb_info->db_fname);
+    }
+    
+    if (((idx = tsk_idx_open_file(idx_info->idx_fname)) == NULL) && (create == 0)) {
+
+        // Try opening an old format index file
+
+        // Clear index filename
+        free(idx_info->idx_fname);
+        idx_info->idx_fname = (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR));
+        if (idx_info->idx_fname == NULL) {
+            free(idx_info);
+            // @@@ ERROR INFO NEEDED
+            return NULL;
+        }
+
+        // Check if it already has an .idx extension
+        TSK_TCHAR * c;
+        c = TSTRRCHR(hdb_info->db_fname, _TSK_T('.'));    
+        if ((c != NULL) && (TSTRLEN(c) >= 4)
+            && (TSTRCMP(c, _TSK_T(".idx")) == 0)) {
+
+            // Use given db filename as the index filename
+            TSTRNCPY(idx_info->idx_fname, hdb_info->db_fname, TSTRLEN(hdb_info->db_fname));
+        } else {
+            // Change the filename to the old format
+            switch (htype) {
+                case TSK_HDB_HTYPE_MD5_ID:
+                    TSNPRINTF(idx_info->idx_fname, flen,
+                              _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"),
+                              hdb_info->db_fname, TSK_HDB_HTYPE_MD5_STR);
+                    break;
+                case TSK_HDB_HTYPE_SHA1_ID:
+                    TSNPRINTF(idx_info->idx_fname, flen,
+                              _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"),
+                              hdb_info->db_fname, TSK_HDB_HTYPE_SHA1_STR);
+                    break;
+            }
+        }
+
+        idx = tsk_idx_open_file(idx_info->idx_fname);
+
+        if (!idx) {
+            free(idx_info);
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+            tsk_error_set_errstr( "tsk_idx_open: Error opening index file");
+            return NULL;
+        }
+        
+        if (1 != fread(header, header_size, 1, idx)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+            tsk_error_set_errstr(
+                "tsk_idx_open: Error reading header: %"PRIttocTSK,
+                idx_info->idx_fname);
+            return NULL;
+        }
+        else if (strncmp(header,
+                           IDX_BINSRCH_HEADER,
+                           strlen(IDX_BINSRCH_HEADER)) == 0) {
+            idx_info->index_type = TSK_HDB_ITYPE_BINSRCH;
+            idx_info->open = binsrch_open;
+            idx_info->close = binsrch_close;
+            idx_info->initialize = binsrch_initialize;
+            idx_info->addentry = binsrch_addentry;
+            idx_info->addentry_bin = binsrch_addentry_bin;
+            idx_info->finalize = binsrch_finalize;
+            idx_info->lookup_str = binsrch_lookup_str;
+            idx_info->lookup_raw = binsrch_lookup_raw;
+            idx_info->get_properties = binsrch_get_properties;
+        }
+        else {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+            tsk_error_set_errstr(
+                "tsk_idx_open: Unrecognized header format: %"PRIttocTSK,
+                idx_info->idx_fname);
+            free(idx_info);
+            return NULL;
+        }
+    }
+    // kdb extension
+    else {
+        if (idx) {
+            if (1 != fread(header, header_size, 1, idx)) {
+                ///@todo should this actually be an error?
+                idx_info->index_type = TSK_HDB_ITYPE_SQLITE_V1;
+            }
+            else if (strncmp(header,
+                        IDX_SQLITE_V1_HEADER,
+                        strlen(IDX_SQLITE_V1_HEADER)) == 0) {
+                idx_info->index_type = TSK_HDB_ITYPE_SQLITE_V1;
+            }
+            else {
+                tsk_error_reset();
+                tsk_error_set_errno(TSK_ERR_HDB_MISSING);
+                tsk_error_set_errstr(
+                        "tsk_idx_open: Unrecognized header format: %"PRIttocTSK,
+                        idx_info->idx_fname);
+                tsk_idx_close_file(idx);
+                free(idx_info);                
+                return NULL;
+            }
+        }
+
+        idx_info->open = sqlite_v1_open;
+        idx_info->close = sqlite_v1_close;
+        idx_info->initialize = sqlite_v1_initialize;
+        idx_info->addentry = sqlite_v1_addentry;
+        idx_info->addentry_bin = sqlite_v1_addentry_bin;
+        idx_info->finalize = sqlite_v1_finalize;
+        idx_info->lookup_str = sqlite_v1_lookup_str;
+        idx_info->lookup_raw = sqlite_v1_lookup_raw;
+        idx_info->get_properties = sqlite_v1_get_properties;
+    }
+
+    tsk_idx_close_file(idx);
+
+    // Open
+    if (idx_info->open(hdb_info, idx_info, htype) == 0) {
+        if (create == 1) {
+            idx_info->updateable = 1;
+        } else {
+            idx_info->get_properties(hdb_info);
+        }
+
+        return idx_info;
+    }
+
+    tsk_error_reset();
+    tsk_error_set_errno(TSK_ERR_HDB_ARG);
+    tsk_error_set_errstr(
+             "Error setting up idx_info struct: %d\n", htype);
+    free(idx_info);
+    return NULL;
+}
+
+
+/**
+ * Ensures that the index is already opened or can be opened. 
+ * @param hdb_info Database handle
+ * @param htype TSK_HDB_HTYPE_ENUM value
+ * @param 
+ * @return 0 if already set up or if setup successful, 1 otherwise
+ */
+uint8_t
+hdb_setupindex(TSK_HDB_INFO * hdb_info, uint8_t htype, uint8_t create)
+{
+    // Lock for lazy load of idx_info and lazy alloc of idx_lbuf.
+    tsk_take_lock(&hdb_info->lock);
+
+    // already opened
+    if (hdb_info->idx_info != NULL) {
+        // update htype
+        hdb_update_htype(hdb_info, htype);
+
+        tsk_release_lock(&hdb_info->lock);
+        return 0;
+    }
+
+    hdb_info->idx_info = tsk_idx_open(hdb_info, htype, create);
+
+    if (hdb_info->idx_info != NULL) {
+        tsk_release_lock(&hdb_info->lock);
+        return 0;
+    }
+
+    tsk_release_lock(&hdb_info->lock);
+    return 1;
+}
+
+
+/** 
+ * Creates and initialize a new TSK hash DB index file.
+ *
+ * @param hdb_info Hash database state structure
+ * @param a_dbtype String of index type to create
+ *
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+tsk_hdb_idxinitialize(TSK_HDB_INFO * hdb_info, TSK_TCHAR * a_dbtype)
+{
+    char dbtmp[32];
+    int i;
+    uint8_t create = 1; //create new file if it doesn't already exist
+
+    /* Use the string of the index/hash type to figure out some
+     * settings */
+
+    // convert to char -- cheating way to deal with WCHARs..
+    for (i = 0; i < 31 && a_dbtype[i] != '\0'; i++) {
+        dbtmp[i] = (char) a_dbtype[i];
+    }
+    dbtmp[i] = '\0';
+
+    // MD5 index for NSRL file
+    if (strcmp(dbtmp, TSK_HDB_DBTYPE_NSRL_MD5_STR) == 0) {
+
+        if (hdb_info->db_type != TSK_HDB_DBTYPE_NSRL_ID) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr(
+                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
+                     hdb_info->db_type, TSK_HDB_DBTYPE_NSRL_ID);
+            return 1;
+        }
+        hdb_info->hash_type = TSK_HDB_HTYPE_MD5_ID;
+    }
+    // SHA1 index for NSRL file
+    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_NSRL_SHA1_STR) == 0) {
+        if (hdb_info->db_type != TSK_HDB_DBTYPE_NSRL_ID) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr(
+                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
+                     hdb_info->db_type, TSK_HDB_DBTYPE_NSRL_ID);
+            return 1;
+        }
+        hdb_info->hash_type = TSK_HDB_HTYPE_SHA1_ID;
+    }
+    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_MD5SUM_STR) == 0) {
+        if ((hdb_info->db_type != TSK_HDB_DBTYPE_MD5SUM_ID) && (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr(
+                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
+                     hdb_info->db_type, TSK_HDB_DBTYPE_MD5SUM_ID);
+            return 1;
+        }
+        hdb_info->hash_type = TSK_HDB_HTYPE_MD5_ID;
+    }
+    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_HK_STR) == 0) {
+        if (hdb_info->db_type != TSK_HDB_DBTYPE_HK_ID) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr(
+                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
+                     hdb_info->db_type, TSK_HDB_DBTYPE_HK_ID);
+            return 1;
+        }
+        hdb_info->hash_type = TSK_HDB_HTYPE_MD5_ID;
+    }
+    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_ENCASE_STR) == 0) {
+        if (hdb_info->db_type != TSK_HDB_DBTYPE_ENCASE_ID) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr(
+                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
+                     hdb_info->db_type, TSK_HDB_DBTYPE_ENCASE_ID);
+            return 1;
+        }
+        hdb_info->hash_type = TSK_HDB_HTYPE_MD5_ID;
+    }
+    else {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                 "hdb_idxinitialize: Unknown database type request: %s",
+                 dbtmp);
+        return 1;
+    }
+
+    /* Setup the internal hash information */
+    if (hdb_setupindex(hdb_info, hdb_info->hash_type, create)) {
+        return 1;
+    }
+
+    /* Call db-specific initialize function */
+	return hdb_info->idx_info->initialize(hdb_info, a_dbtype);
+}
+
+/**
+ * Add a string hash entry to the index
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue String of hash value to add
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+tsk_hdb_idxaddentry(TSK_HDB_INFO * hdb_info, char *hvalue,
+                    TSK_OFF_T offset)
+{
+    return hdb_info->idx_info->addentry(hdb_info, hvalue, offset);
+}
+
+/**
+ * Add a binary hash entry to the index
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue Array of integers of hash value to add
+ * @param hlen Number of bytes in hvalue
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+tsk_hdb_idxaddentry_bin(TSK_HDB_INFO * hdb_info, unsigned char *hvalue, int hlen,
+                    TSK_OFF_T offset)
+{
+    return hdb_info->idx_info->addentry_bin(hdb_info, hvalue, hlen, offset);
+}
+
+/**
+ * Finalize index creation process.
+ *
+ * @param hdb_info Hash database state info structure.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+tsk_hdb_idxfinalize(TSK_HDB_INFO * hdb_info)
+{
+    return hdb_info->idx_info->finalize(hdb_info);
+}
+
+
+
+/**
+ * \ingroup hashdblib
+ * Determine if the open hash database has an index.
+ *
+ * @param hdb_info Hash database to consider
+ * @param htype Hash type that index should be of
+ *
+ * @return 1 if index exists and 0 if not
+ */
+uint8_t
+tsk_hdb_hasindex(TSK_HDB_INFO * hdb_info, uint8_t htype)
+{
+    /* Check if the index is already open, and 
+     * try to open it if not */
+    if (hdb_setupindex(hdb_info, htype, 0) == 0) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * \ingroup hashdblib
+ * Test for index only (legacy)
+ * Assumes that the db was opened using the TSK_HDB_OPEN_TRY option.
+ *
+ * @param hdb_info Hash database to consider
+ *
+ * @return 1 if there is only a legacy index AND no db, 0 otherwise
+ */
+uint8_t
+tsk_hdb_is_idxonly(TSK_HDB_INFO * hdb_info)
+{
+    if (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID) {
+        return (hdb_info->idx_info->index_type == TSK_HDB_ITYPE_BINSRCH) ? 1 : 0;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * \ingroup hashdblib
+ * Close an open hash index
+ *
+ * @param idx_info index to close
+ */
+void tsk_idx_close(TSK_IDX_INFO * idx_info)
+{
+    if (idx_info->idx_fname) {
+        free(idx_info->idx_fname);
+    }
+
+    idx_info->close(idx_info);
+}
+
+
+/**
+ * \ingroup hashdblib
+ * Create an index for an open hash database.
+ * @param a_hdb_info Open hash database to index
+ * @param a_type Text of hash database type
+ * @returns 1 on error
+ */
+uint8_t
+tsk_hdb_makeindex(TSK_HDB_INFO * a_hdb_info, TSK_TCHAR * a_type)
+{
+    return a_hdb_info->makeindex(a_hdb_info, a_type);
+}
+
+/**
+ * \ingroup hashdblib
+ * Create an empty index.
+ * @param db_file Filename. For a new index from scratch, the db name == idx name.
+ * @returns NULL on error
+ */
+TSK_HDB_INFO *
+tsk_hdb_new(TSK_TCHAR * db_file)
+{
+    TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_IDXONLY;
+    TSK_HDB_INFO * hdb_info = tsk_hdb_open(db_file, flags);
+    if (hdb_info != NULL) {
+        TSK_TCHAR * dbtype = NULL; //ignored for IDX only
+        if (hdb_info->makeindex(hdb_info, dbtype) != 0) {
+            tsk_hdb_close(hdb_info);
+            hdb_info = NULL;
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_CREATE);
+            tsk_error_set_errstr("tsk_hdb_new: making new index failed");
+        } else {
+            if (tsk_hdb_idxfinalize(hdb_info) != 0) {
+                tsk_hdb_close(hdb_info);
+                hdb_info = NULL;
+                tsk_error_reset();
+                tsk_error_set_errno(TSK_ERR_HDB_WRITE);
+                tsk_error_set_errstr("tsk_hdb_new: finalizing new index failed");
+            }
+        }    
+    }
+    return hdb_info;
+}
+
+/**
+ * \ingroup hashdblib
+ * Add a binary hash entry to the index
+ *
+ * @param hdb_info the hash database object
+ * @param filename Name of the file that was hashed (can be null)
+ * @param md5 Text of MD5 hash (can be null)
+ * @param sha1 Text of SHA1 hash (can be null)
+ * @param sha256 Text of SHA256 hash (can be null)
+ * @return 1 on error, 0 on success, -1 if not updateable
+ */
+int8_t
+tsk_hdb_add_str(TSK_HDB_INFO * hdb_info, 
+                const TSK_TCHAR * filename, 
+                const char * md5, 
+                const char * sha1, 
+                const char * sha256)
+{
+    if(hdb_info == NULL) {
+        tsk_error_set_errstr2("tsk_hdb_add_str: null hdb_info");
+        return 1;
+    } else {
+        uint8_t htype = TSK_HDB_HTYPE_MD5_ID;
+        if (hdb_setupindex(hdb_info, htype, 0)) {
+            return 1;
+        }
+
+        if(hdb_info->idx_info->updateable == 1) {
+            ///@todo also allow use of other htypes
+            char * hvalue = (char *)md5;
+
+            // @todo Could set up a polymorphic mechanism like with finalize() but
+            // we know it's going to be sqlite in this function.
+            if (sqlite_v1_begin(hdb_info) == 1) {
+                tsk_error_set_errstr2("tsk_hdb_add_str: sqlite_v1_begin failed");
+                return 1;
+            }
+
+            // Attempt to add a new row to the hash index
+            TSK_OFF_T offset = 0; //not needed since there might not be an original DB
+            if (tsk_hdb_idxaddentry(hdb_info, hvalue, offset) != 0) {
+                tsk_error_reset();
+                tsk_error_set_errno(TSK_ERR_HDB_WRITE);
+                tsk_error_set_errstr("tsk_hdb_add_str: adding entry failed");
+                return 1;            
+            } else {
+                // Close the index
+                if (tsk_hdb_idxfinalize(hdb_info) != 0) {
+                    tsk_error_reset();
+                    tsk_error_set_errno(TSK_ERR_HDB_WRITE);
+                    tsk_error_set_errstr("tsk_hdb_add_str: finalizing index failed");
+                    return 1;
+                }  
+                return 0;
+            }
+        } else {
+            return -1;
+        }
+    }
+}
+
+/**
+ * Set db_name to the name of the database file
+ *
+ * @param hdb_info the hash database object
+ */
+void
+tsk_hdb_name_from_path(TSK_HDB_INFO * hdb_info)
+{
+#ifdef TSK_WIN32
+    const char PATH_CHAR = '\\';
+#else
+    const char PATH_CHAR = '/';
+#endif
+    TSK_TCHAR * begin;
+    TSK_TCHAR * end;
+    int i;
+
+    hdb_info->db_name[0] = '\0';
+
+    begin = TSTRRCHR(hdb_info->db_fname, PATH_CHAR);
+#ifdef TSK_WIN32
+    // cygwin can have forward slashes, so try that too on Windows
+    if (!begin) {
+        begin = TSTRRCHR(hdb_info->db_fname, '/');
+    }
+#endif
+
+    if (!begin) {
+        begin = hdb_info->db_fname;
+    }
+    else {
+        // unlikely since this means that the dbname is "/"
+        if (TSTRLEN(begin) == 1)
+            return;
+        else
+            begin++;
+    }
+
+    // end points to the byte after the last one we want to use
+    if ((TSTRLEN(hdb_info->db_fname) > 4) && (TSTRICMP(&hdb_info->db_fname[TSTRLEN(hdb_info->db_fname)-4], _TSK_T(".idx")) == 0)) 
+        end = &hdb_info->db_fname[TSTRLEN(hdb_info->db_fname)-4];
+    else
+        end = begin + TSTRLEN(begin);
+        
+
+    // @@@ TODO: Use TskUTF16_to_UTF8 to properly convert for Windows
+    for(i = 0; i < (end-begin); i++)
+    {
+        hdb_info->db_name[i] = (char) begin[i];
+    }
+
+    hdb_info->db_name[i] = '\0';
+}
diff --git a/tsk/hashdb/hdb_open.cpp b/tsk/hashdb/hdb_open.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7c86ae748cab6acd9e5989abc96e0cc6bf92fb1c
--- /dev/null
+++ b/tsk/hashdb/hdb_open.cpp
@@ -0,0 +1,232 @@
+/*
+ * The Sleuth Kit
+ *
+ * Brian Carrier [carrier <at> sleuthkit [dot] org]
+ * Copyright (c) 2003-2013 Brian Carrier.  All rights reserved
+ *
+ *
+ * This software is distributed under the Common Public License 1.0
+ */
+
+#include "tsk_hashdb_i.h"
+
+
+/**
+ * \file hdb_open.c
+ * Contains the generic hash database creation and lookup code.
+ */
+
+
+
+/**
+ * \ingroup hashdblib
+ * Open an existing hash database. 
+ *
+ * @param db_file Path to database (even if only an index exists, in which case db path should still be listed).
+ * @param flags Flags for opening the database.  
+ *
+ * @return Pointer to hash database state structure or NULL on error
+ */
+TSK_HDB_INFO *
+tsk_hdb_open(TSK_TCHAR * db_file, TSK_HDB_OPEN_ENUM flags)
+{
+    TSK_HDB_INFO *hdb_info;
+    size_t flen;
+    FILE *hDb;
+    uint8_t dbtype = 0;
+
+    if (flags == TSK_HDB_OPEN_TRY) {
+        TSK_HDB_OPEN_ENUM tryflag = TSK_HDB_OPEN_NONE;
+
+        if ((hdb_info = tsk_hdb_open(db_file, tryflag)) != NULL) {
+            // success (and there is a src db file existent)
+            return hdb_info;
+        } else {
+            // if null then maybe it's IDX only
+            flags = TSK_HDB_OPEN_IDXONLY;
+            // continue this function in IDXONLY mode
+        }
+    }
+
+    if ((flags & TSK_HDB_OPEN_IDXONLY) == 0) {
+        /* Open the database file */
+#ifdef TSK_WIN32
+        {
+            HANDLE hWin;
+
+            if ((hWin = CreateFile(db_file, GENERIC_READ,
+                                   FILE_SHARE_READ, 0, OPEN_EXISTING, 0,
+                                   0)) == INVALID_HANDLE_VALUE) {
+                tsk_error_reset();
+                tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+                tsk_error_set_errstr(
+                         "hdb_open: Error opening database file: %S",
+                         db_file);
+                return NULL;
+            }
+            hDb =
+                _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r");
+            if (hDb == NULL) {
+                tsk_error_reset();
+                tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+                tsk_error_set_errstr(
+                         "hdb_open: Error converting Windows handle to C handle");
+                return NULL;
+            }
+        }
+#else
+        if (NULL == (hDb = fopen(db_file, "r"))) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
+            tsk_error_set_errstr(
+                     "hdb_open: Error opening database file: %s", db_file);
+            return NULL;
+        }
+#endif
+
+        /* Try to figure out what type of DB it is */
+        if (sqlite3_test(hDb)) {
+            dbtype = TSK_HDB_DBTYPE_IDXONLY_ID;
+            fclose(hDb);
+            hDb = NULL;
+
+        } else {
+            if (nsrl_test(hDb)) {
+                dbtype = TSK_HDB_DBTYPE_NSRL_ID;
+            }
+            if (md5sum_test(hDb)) {
+                if (dbtype != 0) {
+                    tsk_error_reset();
+                    tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+                    tsk_error_set_errstr(
+                             "hdb_open: Error determining DB type (MD5sum)");
+                    return NULL;
+                }
+                dbtype = TSK_HDB_DBTYPE_MD5SUM_ID;
+            }
+            if (encase_test(hDb)) {
+                if (dbtype != 0) {
+                    tsk_error_reset();
+                    tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+                    tsk_error_set_errstr(
+                             "hdb_open: Error determining DB type (EnCase)");
+                    return NULL;
+                }
+                dbtype = TSK_HDB_DBTYPE_ENCASE_ID;
+            }
+            if (hk_test(hDb)) {
+                if (dbtype != 0) {
+                    tsk_error_reset();
+                    tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+                    tsk_error_set_errstr(
+                             "hdb_open: Error determining DB type (HK)");
+                    return NULL;
+                }
+                dbtype = TSK_HDB_DBTYPE_HK_ID;
+            }
+            if (dbtype == 0) {
+                tsk_error_reset();
+                tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
+                tsk_error_set_errstr(
+                         "hdb_open: Error determining DB type");
+                return NULL;
+            }
+            fseeko(hDb, 0, SEEK_SET);
+        }
+    }
+    else {
+        dbtype = TSK_HDB_DBTYPE_IDXONLY_ID;
+        hDb = NULL;
+    }
+
+    if ((hdb_info =
+         (TSK_HDB_INFO *) tsk_malloc(sizeof(TSK_HDB_INFO))) == NULL)
+        return NULL;
+
+    hdb_info->hDb = hDb;
+
+    /* Copy the database name into the structure */
+    flen = TSTRLEN(db_file) + 8;        // + 32;
+
+    hdb_info->db_fname =
+        (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR));
+    if (hdb_info->db_fname == NULL) {
+        free(hdb_info);
+        return NULL;
+    }
+
+    TSTRNCPY(hdb_info->db_fname, db_file, flen);
+    
+    hdb_info->hash_type = static_cast<TSK_HDB_HTYPE_ENUM>(0);
+    hdb_info->hash_len = 0;
+    hdb_info->idx_info = NULL;
+
+    // Initialize mutex (or critical section) obj
+    tsk_init_lock(&hdb_info->lock);
+
+    /* Get database specific information */
+    hdb_info->db_type = static_cast<TSK_HDB_DBTYPE_ENUM>(dbtype);
+    switch (dbtype) {
+        case TSK_HDB_DBTYPE_NSRL_ID:
+            nsrl_name(hdb_info);
+            hdb_info->getentry = nsrl_getentry;
+            hdb_info->makeindex = nsrl_makeindex;
+            break;
+
+        case TSK_HDB_DBTYPE_MD5SUM_ID:
+            md5sum_name(hdb_info);
+            hdb_info->getentry = md5sum_getentry;
+            hdb_info->makeindex = md5sum_makeindex;
+            break;
+
+        case TSK_HDB_DBTYPE_ENCASE_ID:
+            encase_name(hdb_info);
+            hdb_info->getentry = encase_getentry;
+            hdb_info->makeindex = encase_makeindex;
+            break;
+
+        case TSK_HDB_DBTYPE_HK_ID:
+            hk_name(hdb_info);
+            hdb_info->getentry = hk_getentry;
+            hdb_info->makeindex = hk_makeindex;
+            break;
+
+        case TSK_HDB_DBTYPE_IDXONLY_ID:
+            idxonly_name(hdb_info);
+            hdb_info->getentry = idxonly_getentry;
+            hdb_info->makeindex = idxonly_makeindex;
+            break;
+
+        default:
+            free(hdb_info);
+            return NULL;
+    }
+
+    return hdb_info;
+}
+
+
+
+/**
+ * \ingroup hashdblib
+ * Close an open hash database.
+ *
+ * @param hdb_info database to close
+ */
+void
+tsk_hdb_close(TSK_HDB_INFO * hdb_info)
+{
+    if (hdb_info->db_fname)
+        free(hdb_info->db_fname);
+
+    if (hdb_info->hDb)
+        fclose(hdb_info->hDb);
+
+    if (hdb_info->idx_info) {
+        tsk_idx_close(hdb_info->idx_info);
+    }
+
+    tsk_deinit_lock(&hdb_info->lock);
+
+    free(hdb_info);
+}
diff --git a/tsk/hashdb/idxonly_index.c b/tsk/hashdb/idxonly.c
similarity index 54%
rename from tsk/hashdb/idxonly_index.c
rename to tsk/hashdb/idxonly.c
index a6c4713f8218b5d04b050962ff6c003d07ed2fc9..3c3dff904e2e304ac57d7cd6b4d4bf89eb8b1cf0 100644
--- a/tsk/hashdb/idxonly_index.c
+++ b/tsk/hashdb/idxonly.c
@@ -29,6 +29,8 @@ idxonly_name(TSK_HDB_INFO * hdb_info)
     char *bufptr = buf;
     size_t i = 0;
     memset(hdb_info->db_name, '\0', TSK_HDB_NAME_MAXLEN);
+
+    //Calling tsk_hdb_hasindex() has the side effect to set up the index structure (if the index exist)
     if(tsk_hdb_hasindex(hdb_info, TSK_HDB_HTYPE_MD5_ID) == 0) {
         if (tsk_verbose)
             fprintf(stderr,
@@ -36,46 +38,64 @@ idxonly_name(TSK_HDB_INFO * hdb_info)
         tsk_hdb_name_from_path(hdb_info);
         return;
     }
-    hFile = hdb_info->hIdx;
-    fseeko(hFile, 0, 0);
-    if(NULL == fgets(buf, TSK_HDB_NAME_MAXLEN, hFile) ||
-        NULL == fgets(buf, TSK_HDB_NAME_MAXLEN, hFile) ||
-        strncmp(buf,
-                TSK_HDB_IDX_HEAD_NAME_STR,
-                strlen(TSK_HDB_IDX_HEAD_NAME_STR)) != 0) {
-        if (tsk_verbose)
-            fprintf(stderr,
-                "Failed to read name from index; using file name instead");
+
+    // Get the DB name. Alternatively, we could query the index for Hashset Name.
+    if (hdb_info->idx_info->index_type == TSK_HDB_ITYPE_SQLITE_V1) {
         tsk_hdb_name_from_path(hdb_info);
         return;
-    }
-    bufptr = strchr(buf, '|');
-    bufptr++;
-    while(bufptr[i] != '\r' && bufptr[i] != '\n' && i < strlen(bufptr))
-    {
-        hdb_info->db_name[i] = bufptr[i];
-        i++;
+    } else {
+        // Get name from legacy (bin search text) index
+        hFile = hdb_info->idx_info->idx_struct.idx_binsrch->hIdx;
+        fseeko(hFile, 0, 0);
+        if(NULL == fgets(buf, TSK_HDB_NAME_MAXLEN, hFile) ||
+            NULL == fgets(buf, TSK_HDB_NAME_MAXLEN, hFile) ||
+            strncmp(buf,
+                    TSK_HDB_IDX_HEAD_NAME_STR,
+                    strlen(TSK_HDB_IDX_HEAD_NAME_STR)) != 0) {
+            if (tsk_verbose)
+                fprintf(stderr,
+                    "Failed to read name from index; using file name instead");
+            tsk_hdb_name_from_path(hdb_info);
+            return;
+        }
+        bufptr = strchr(buf, '|');
+        bufptr++;
+        while(bufptr[i] != '\r' && bufptr[i] != '\n' && i < strlen(bufptr))
+        {
+            hdb_info->db_name[i] = bufptr[i];
+            i++;
+        }
     }
 }
 
 
 /**
- * This function should process the database to create a sorted index of it,
- * but in this case we do not have a database, so just make an error...
+ * This function creates an empty
  *
  * @param hdb_info Hash database to make index of.
- * @param dbtype Type of hash database 
+ * @param dbtype Type of hash database. Ignored for IDX only.
  *
  * @return 1 on error and 0 on success.
  */
 uint8_t
 idxonly_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype)
 {
-    tsk_error_reset();
-    tsk_error_set_errno(TSK_ERR_HDB_ARG);
-    tsk_error_set_errstr(
-             "idxonly_makeindex: Make index not supported when INDEX ONLY option is used");
-    return 1;
+    //tsk_error_reset();
+    //tsk_error_set_errno(TSK_ERR_HDB_ARG);
+    //tsk_error_set_errstr(
+    //         "idxonly_makeindex: Make index not supported when INDEX ONLY option is used");
+
+    ///@temporary until we exorcise all the htype conditionals out
+    TSK_TCHAR dbtype_default[1024];
+    TSNPRINTF(dbtype_default, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_MD5SUM_STR);
+
+    /* Initialize the TSK index file */
+    if (tsk_hdb_idxinitialize(hdb_info, dbtype_default)) {
+        tsk_error_set_errstr2( "idxonly_makeindex");
+        return 1;
+    }
+
+    return 0;
 }
 
 
@@ -103,4 +123,4 @@ idxonly_getentry(TSK_HDB_INFO * hdb_info, const char *hash,
     tsk_error_set_errstr(
              "idxonly_getentry: Not supported when INDEX ONLY option is used");
     return 1;
-}
\ No newline at end of file
+}
diff --git a/tsk/hashdb/md5sum_index.c b/tsk/hashdb/md5sum.c
similarity index 100%
rename from tsk/hashdb/md5sum_index.c
rename to tsk/hashdb/md5sum.c
diff --git a/tsk/hashdb/nsrl_index.c b/tsk/hashdb/nsrl.c
similarity index 100%
rename from tsk/hashdb/nsrl_index.c
rename to tsk/hashdb/nsrl.c
diff --git a/tsk/hashdb/sqlite_index.cpp b/tsk/hashdb/sqlite_index.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5316e76e7dce084fee646166c37c9024e3386f3
--- /dev/null
+++ b/tsk/hashdb/sqlite_index.cpp
@@ -0,0 +1,757 @@
+
+/*
+ * The Sleuth Kit
+ *
+ * Brian Carrier [carrier <at> sleuthkit [dot] org]
+ * Copyright (c) 2003-2011 Brian Carrier.  All rights reserved
+ *
+ *
+ * This software is distributed under the Common Public License 1.0
+ *
+ */
+
+#include "tsk_hashdb_i.h"
+
+/**
+ * \file sqlite_index.c
+ * Contains functions for creating a SQLite format hash index
+ */
+
+/**
+ * Static sqlite statements, prepared initially and bound before each use
+ */
+static sqlite3_stmt *m_stmt = NULL;
+static bool need_SQL_index = false;
+
+/**
+ * Prototypes 
+ */
+//int8_t sqlite_v1_get_properties(TSK_HDB_INFO * hdb_info);
+uint8_t sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen, TSK_OFF_T offset);
+uint8_t addentry_text(TSK_HDB_INFO * hdb_info, char* hvalue, TSK_OFF_T offset);
+int8_t  lookup_text(TSK_HDB_INFO * hdb_info, const char* hvalue, TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action, void *ptr);
+
+static int attempt(int resultCode, int expectedResultCode,
+		const char *errfmt, sqlite3 * sqlite)
+{
+	if (resultCode != expectedResultCode) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr(errfmt, sqlite3_errmsg(sqlite), resultCode);
+		return 1;
+	}
+	return 0;
+}
+
+static int attempt_exec(const char *sql, int (*callback) (void *, int, char **, char **),
+						void *callback_arg, const char *errfmt, sqlite3 * sqlite)
+{
+	char * errmsg;
+
+	if(sqlite3_exec(sqlite, sql, callback, callback_arg, &errmsg) != SQLITE_OK) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr(errfmt, errmsg);
+		sqlite3_free(errmsg);
+		return 1;
+	}
+	return 0;
+}
+
+static int attempt_exec_nocallback(const char *sql, const char *errfmt, sqlite3 * sqlite)
+{
+	return attempt_exec(sql, NULL, NULL, errfmt, sqlite);
+}
+
+static int finalize_stmt(sqlite3_stmt * stmt)
+{
+	if (sqlite3_finalize(stmt) != SQLITE_OK) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Error finalizing SQL statement\n");
+        tsk_error_print(stderr);
+		return 1;
+	}
+	return 0;
+}
+
+static int prepare_stmt(const char *sql, sqlite3_stmt ** ppStmt, sqlite3 * sqlite)
+{
+    ///@todo possible performance increase by using strlen(sql)+1 instead of -1
+	if (sqlite3_prepare_v2(sqlite, sql, -1, ppStmt, NULL) != SQLITE_OK) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Error preparing SQL statement: %s\n", sql);
+        tsk_error_print(stderr);
+		return 1;
+	}
+	return 0;
+}
+
+static uint8_t tsk_hdb_begin_transaction(TSK_IDX_INFO * idx_info) {
+	return attempt_exec_nocallback("BEGIN", "Error beginning transaction %s\n", idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+}
+
+static uint8_t tsk_hdb_commit_transaction(TSK_IDX_INFO * idx_info) {
+	return attempt_exec_nocallback("COMMIT", "Error committing transaction %s\n", idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+}
+
+/** Init prepared statements. Call before adding to the database. Call finalize() when done.
+ *
+ * @param hdb_info Hash database state structure
+ *
+ * @return 1 on error and 0 on success
+ *
+ */
+uint8_t
+sqlite_v1_begin(TSK_HDB_INFO * hdb_info)
+{
+	char * insertStmt;
+
+	if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) {
+		insertStmt = "INSERT INTO hashes (md5, database_offset) VALUES (?, ?)";
+	} else if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
+		insertStmt = "INSERT INTO hashes (sha1, database_offset) VALUES (?, ?)";
+	} else {
+        return 1;
+    }
+
+	prepare_stmt(insertStmt, &m_stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+
+	if (tsk_hdb_begin_transaction(hdb_info->idx_info)) {
+		return 1;
+	} else {
+        return 0;
+    }
+}
+
+/** Initialize the TSK hash DB index file by creating tables, etc..
+ *
+ * @param hdb_info Hash database state structure
+ * @param htype String of index type to create
+ *
+ * @return 1 on error and 0 on success
+ *
+ */
+uint8_t
+sqlite_v1_initialize(TSK_HDB_INFO * hdb_info, TSK_TCHAR * htype)
+{
+	char stmt[1024];
+
+	if (attempt_exec_nocallback("PRAGMA synchronous = OFF;",
+		"Error setting PRAGMA synchronous: %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+			return 1;
+	}
+
+	if (attempt_exec_nocallback
+		("CREATE TABLE properties (name TEXT, value TEXT);",
+		"Error creating properties table %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+			return 1;
+	}
+
+	snprintf(stmt, 1024,
+		"INSERT INTO properties (name, value) VALUES ('%s', '%s');",
+		IDX_SCHEMA_VER, IDX_VERSION_NUM);
+	if (attempt_exec_nocallback(stmt, "Error adding schema info to properties: %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+		return 1;
+	}
+
+	snprintf(stmt, 1024,
+		"INSERT INTO properties (name, value) VALUES ('%s', '%s');",
+		IDX_HASHSET_NAME, hdb_info->db_name);
+	if (attempt_exec_nocallback(stmt, "Error adding name to properties: %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+		return 1;
+	}
+
+	snprintf(stmt, 1024,
+		"INSERT INTO properties (name, value) VALUES ('%s', '%s');",
+		IDX_HASHSET_UPDATEABLE, (hdb_info->idx_info->updateable == 1) ? "true" : "false");
+	if (attempt_exec_nocallback(stmt, "Error adding updateable to properties: %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+		return 1;
+	}
+
+#ifdef IDX_SQLITE_STORE_TEXT
+	if (attempt_exec_nocallback
+		("CREATE TABLE hashes (id INTEGER PRIMARY KEY AUTOINCREMENT, md5 TEXT UNIQUE, sha1 TEXT, sha2_256 TEXT, database_offset INTEGER);",
+		"Error creating hashes table %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+			return 1;
+	}
+#else
+	if (attempt_exec_nocallback
+		("CREATE TABLE hashes (id INTEGER PRIMARY KEY AUTOINCREMENT, md5 BINARY(16) UNIQUE, sha1 BINARY(20), sha2_256 BINARY(32), database_offset INTEGER);",
+		"Error creating hashes table %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+			return 1;
+	}
+#endif
+
+    // The names table enables the user to optionally map one or many names to each hash.
+    // "name" should be the filename without the path.
+	if (attempt_exec_nocallback
+		("CREATE TABLE names (name TEXT, hash_id INTEGER);",
+		"Error creating names table %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+			return 1;
+	}
+
+    need_SQL_index = true;
+
+	return sqlite_v1_begin(hdb_info);
+}
+
+/**
+ * Add a string representation of a hash value to the index.
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue String of hash value to add
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+sqlite_v1_addentry(TSK_HDB_INFO * hdb_info, char* hvalue,
+                    TSK_OFF_T offset)
+{
+	if (strlen(hvalue) != hdb_info->hash_len) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Hash length doesn't match index type: %s\n", hvalue);
+        tsk_error_print(stderr);
+		return 1;
+	}
+
+#ifdef IDX_SQLITE_STORE_TEXT
+    uint8_t ret = addentry_text(hdb_info, hvalue, offset);
+#else
+	const size_t len = (hdb_info->hash_len)/2;
+    uint8_t* hash = (uint8_t*) tsk_malloc(len+1);
+    
+	size_t count;
+
+    // We use an intermediate short to be compatible with Microsoft's implementation of the scanf family format
+    short unsigned int binval;
+    for (count = 0; count < len; count++) {
+		int r = sscanf(hvalue, "%2hx", &binval);
+        hash[count] = (uint8_t) binval;
+		hvalue += 2 * sizeof(char);
+	}
+    uint8_t ret = sqlite_v1_addentry_bin(hdb_info, hash, len, offset);
+
+    delete [] hash;
+#endif
+
+	return ret;
+}
+
+/**
+ * Add a binary representation of a hash value into the index.
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue Array of integers of hash value to add
+ * @param hlen Number of bytes in hvalue
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen,
+                    TSK_OFF_T offset)
+{
+    if (attempt(sqlite3_bind_blob(m_stmt, 1, hvalue, hlen, SQLITE_TRANSIENT),
+		SQLITE_OK,
+		"Error binding binary blob: %s\n",
+		hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ||
+		attempt(sqlite3_bind_int64(m_stmt, 2, offset),
+		SQLITE_OK,
+		"Error binding entry offset: %s\n",
+		hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ) {
+        return 1;
+    }
+
+    // Don't report error on constraint -- we just will silently not add that duplicate hash
+	int r = sqlite3_step(m_stmt);
+    if ((r != SQLITE_DONE) && (r != SQLITE_CONSTRAINT) ) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Error stepping: %s\n", sqlite3_errmsg( hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite), r);
+        return 1;
+    }
+
+	r = sqlite3_reset(m_stmt);
+    if ((r != SQLITE_OK) && (r != SQLITE_CONSTRAINT) ) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Error resetting: %s\n", sqlite3_errmsg( hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite), r);
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * Add a text representation of a hash value into the index.
+ *
+ * @param hdb_info Hash database state info
+ * @param hvalue String of hash value to add
+ * @param hlen Number of bytes in hvalue
+ * @param offset Byte offset of hash entry in original database.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+addentry_text(TSK_HDB_INFO * hdb_info, char* hvalue, TSK_OFF_T offset)
+{
+    if (attempt(sqlite3_bind_text(m_stmt, 1, hvalue, strlen(hvalue), SQLITE_TRANSIENT),
+		SQLITE_OK,
+		"Error binding text: %s\n",
+		hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ||
+		attempt(sqlite3_bind_int64(m_stmt, 2, offset),
+		    SQLITE_OK,
+		    "Error binding entry offset: %s\n",
+		    hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ) {
+        return 1;
+    }
+
+    // Don't report error on constraint -- we just will silently not add that duplicate hash
+	int r = sqlite3_step(m_stmt);
+    if ((r != SQLITE_DONE) && (r != SQLITE_CONSTRAINT) ) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Error stepping: %s\n", sqlite3_errmsg( hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite), r);
+        return 1;
+    }
+
+	r = sqlite3_reset(m_stmt);
+    if ((r != SQLITE_OK) && (r != SQLITE_CONSTRAINT) ) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Error resetting: %s\n", sqlite3_errmsg( hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite), r);
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * Finalize index creation process
+ *
+ * @param hdb_info Hash database state info structure.
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+sqlite_v1_finalize(TSK_HDB_INFO * hdb_info)
+{
+	if (tsk_hdb_commit_transaction(hdb_info->idx_info)) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_AUTO_DB);
+		tsk_error_set_errstr("Failed to commit transaction\n");
+        tsk_error_print(stderr);
+		return 1;
+	}
+	
+    // We create the indexes at the end in order to make adding the initial batch of data (e.g. indexing an NSRL db)
+    // faster. Updates after indexing can be slower since the index has to update as well.
+    if (need_SQL_index) {
+        need_SQL_index = false;
+	    return attempt_exec_nocallback
+		    ("CREATE INDEX md5_index ON hashes(md5);",
+		    "Error creating md5_index on md5: %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) ||
+		    attempt_exec_nocallback
+		    ("CREATE INDEX sha1_index ON hashes(sha1);",
+		    "Error creating sha1_index on sha1: %s\n", hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+    } else {
+        return 0;
+    }
+}
+
+/** \internal
+ * Setup the internal variables to read an index or database. This
+ * opens the index and sets the needed size information.
+ *
+ * @param hdb_info Hash database to analyze
+ * @param htype The hash type that was used to make the index.
+ *
+ * @return 1 on error and 0 on success
+ */
+uint8_t
+sqlite_v1_open(TSK_HDB_INFO * hdb_info, TSK_IDX_INFO * idx_info, uint8_t htype)
+{
+    sqlite3 * sqlite = NULL;
+
+    if ((idx_info->idx_struct.idx_sqlite_v1 =
+                (TSK_IDX_SQLITE_V1 *) tsk_malloc
+                (sizeof(TSK_IDX_SQLITE_V1))) == NULL) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                 "sqlite_v1_open: Malloc error");
+        return 1;
+    }
+
+
+    if ((htype != TSK_HDB_HTYPE_MD5_ID)
+        && (htype != TSK_HDB_HTYPE_SHA1_ID)
+        && (htype != TSK_HDB_HTYPE_SHA2_256_ID)) {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                 "hdb_setupindex: Invalid hash type : %d", htype);
+        return 1;
+    }
+
+#ifdef TSK_WIN32
+    {
+        if (attempt(sqlite3_open16(idx_info->idx_fname, &sqlite),
+                    SQLITE_OK,
+                    "Can't open index: %s\n", sqlite)) {
+            sqlite3_close(sqlite);
+            return 1;
+        }
+    }
+#else
+    {
+        if (attempt(sqlite3_open(idx_info->idx_fname, &sqlite),
+                    SQLITE_OK,
+                    "Can't open index: %s\n", sqlite)) {
+            sqlite3_close(sqlite);
+            return 1;
+        }
+    }
+#endif
+
+	sqlite3_extended_result_codes(sqlite, 1);
+
+    idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite = sqlite;
+
+    return 0;
+}
+
+
+
+
+
+/**
+ * \ingroup hashdblib
+ * Search the index for a text/ASCII hash value
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash Hash value to search for (NULL terminated string)
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+int8_t
+sqlite_v1_lookup_str(TSK_HDB_INFO * hdb_info, const char* hvalue,
+                   TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action,
+                   void *ptr)
+{
+    int8_t ret = 0;
+
+#ifdef IDX_SQLITE_STORE_TEXT
+    ret = lookup_text(hdb_info, hvalue, flags, action, ptr);
+#else
+	const size_t len = strlen(hvalue)/2;
+	uint8_t * hashBlob = (uint8_t *) tsk_malloc(len+1);
+	const char * pos = hvalue;
+	size_t count = 0;
+
+	for(count = 0; count < len; count++) {
+		sscanf(pos, "%2hx", (short unsigned int *) &(hashBlob[count]));
+		pos += 2 * sizeof(char);
+	}
+
+    ret = sqlite_v1_lookup_raw(hdb_info, hashBlob, len, flags, action, ptr);
+#endif
+
+    if ((ret == 1) && (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)
+        && !(flags & TSK_HDB_FLAG_QUICK) && (action != NULL)) {
+        //name is blank because we don't have a name in this case
+        ///@todo query the names table for associations
+        char * name = "";
+        action(hdb_info, hvalue, name, ptr);
+    }
+
+	return ret;		
+}
+
+/**
+ * \ingroup hashdblib
+ * Search the index for the given hash value given (in binary form).
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash Array with binary hash value to search for
+ * @param len Number of bytes in binary hash value
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+int8_t
+sqlite_v1_lookup_raw(TSK_HDB_INFO * hdb_info, uint8_t * hvalue, uint8_t len,
+                   TSK_HDB_FLAG_ENUM flags,
+                   TSK_HDB_LOOKUP_FN action, void *ptr)
+{
+	char hashbuf[TSK_HDB_HTYPE_SHA1_LEN + 1];
+	int8_t ret = 0;
+    int i;
+	static const char hex[] = "0123456789abcdef";
+	TSK_OFF_T offset;
+    char * selectStmt;
+    sqlite3_stmt* stmt = NULL;
+
+    tsk_take_lock(&hdb_info->lock);
+
+	/* Sanity check */
+	if ((hdb_info->hash_len)/2 != len) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_HDB_ARG);
+		tsk_error_set_errstr("hdb_lookup: Hash passed is different size than expected: %d vs %d",
+			hdb_info->hash_len, (len * 2));
+		ret = -1;
+	} else {
+
+    	if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) {
+            selectStmt = "SELECT md5,database_offset from hashes where md5=? limit 1";
+        } else if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
+            selectStmt = "SELECT sha1,database_offset from hashes where sha1=? limit 1";
+        } else {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr("Unknown hash type: %d\n", hdb_info->hash_type);
+            ret = -1;
+        }
+
+        if (ret != -1) {
+            prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+        
+	        if (attempt(sqlite3_bind_blob(stmt, 1, hvalue, len, free),
+		        SQLITE_OK,
+		        "Error binding binary blob: %s\n",
+		        hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
+			    ret = -1;
+	        } else {
+                // Found a match
+	            if (sqlite3_step(stmt) == SQLITE_ROW) {
+		            if ((flags & TSK_HDB_FLAG_QUICK)
+			            || (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)) {
+				        
+                        // There is just an index, so no other info to get
+                        ///@todo Look up a name in the sqlite db
+                        ret = 1;
+		            } else {
+                        // Use offset to get more info
+			            for (i = 0; i < len; i++) {
+				            hashbuf[2 * i] = hex[(hvalue[i] >> 4) & 0xf];
+				            hashbuf[2 * i + 1] = hex[hvalue[i] & 0xf];
+			            }
+			            hashbuf[2 * len] = '\0';
+
+			            offset = sqlite3_column_int64(stmt, 1);
+
+			            if (hdb_info->getentry(hdb_info, hashbuf, offset, flags, action, ptr)) {
+				            tsk_error_set_errstr2("hdb_lookup");
+				            ret = -1;
+			            } else {
+			                ret = 1;
+                        }
+		            }
+                }
+            }
+        
+	        sqlite3_reset(stmt);
+    
+            if (stmt) {
+                finalize_stmt(stmt);
+            }
+        }
+    }
+
+    tsk_release_lock(&hdb_info->lock);
+
+	return ret;
+}
+
+
+/**
+ * \ingroup hashdblib
+ * Search the index for the given hash value given (in string form).
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash String hash value to search for
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+///@todo refactor so as not to duplicate code with sqlite_v1_lookup_raw()
+int8_t
+lookup_text(TSK_HDB_INFO * hdb_info, const char* hvalue, TSK_HDB_FLAG_ENUM flags,
+                   TSK_HDB_LOOKUP_FN action, void *ptr)
+{
+	int8_t ret = 0;
+	TSK_OFF_T offset;
+    char selectStmt[1024];
+    sqlite3_stmt* stmt = NULL;
+    int len = strlen(hvalue);
+
+    tsk_take_lock(&hdb_info->lock);
+
+	/* Sanity check */
+	if (hdb_info->hash_len != len) {
+		tsk_error_reset();
+		tsk_error_set_errno(TSK_ERR_HDB_ARG);
+		tsk_error_set_errstr("hdb_lookup: Hash passed is different size than expected: %d vs %d",
+			hdb_info->hash_len, len);
+		ret = -1;
+	} else {
+    	if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) {
+            snprintf(selectStmt, 1024,
+		        "SELECT md5,database_offset from hashes where md5='%s' limit 1",
+                hvalue);
+        } else if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
+            snprintf(selectStmt, 1024,
+		        "SELECT sha1,database_offset from hashes where sha1='%s' limit 1",
+                hvalue);
+        } else {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_HDB_ARG);
+            tsk_error_set_errstr("Unknown hash type: %d\n", hdb_info->hash_type);
+            ret = -1;
+        }
+
+        if (ret != -1) {
+            prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+        
+            // Found a match
+	        if (sqlite3_step(stmt) == SQLITE_ROW) {
+		        if ((flags & TSK_HDB_FLAG_QUICK)
+			        || (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)) {
+				        
+                    // There is just an index, so no other info to get
+                    ///@todo Look up a name in the sqlite db
+                    ret = 1;
+		        } else {
+                    // Use offset to get more info
+			        offset = sqlite3_column_int64(stmt, 1);
+
+			        if (hdb_info->getentry(hdb_info, hvalue, offset, flags, action, ptr)) {
+				        tsk_error_set_errstr2("hdb_lookup");
+				        ret = -1;
+			        } else {
+			            ret = 1;
+                    }
+		        }
+            }
+                   
+	        sqlite3_reset(stmt);
+    
+            if (stmt) {
+                finalize_stmt(stmt);
+            }
+        }
+    }
+
+    tsk_release_lock(&hdb_info->lock);
+
+	return ret;
+}
+
+
+/**
+ * \ingroup hashdblib
+ * Sets the updateable flag in the hdb_info argument based on querying the index props table.
+ *
+ * @param hdb_info Open hash database (with index)
+ * @return -1 on error, 0 on success.
+ */
+int8_t
+sqlite_v1_get_properties(TSK_HDB_INFO * hdb_info)
+{
+    int8_t ret = 0;
+	sqlite3_stmt* stmt = NULL;
+    char selectStmt[1024];
+
+    tsk_take_lock(&hdb_info->lock);
+    
+    snprintf(selectStmt, 1024, "SELECT value from properties where name='%s'", IDX_HASHSET_UPDATEABLE);
+    prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+
+	if (sqlite3_step(stmt) == SQLITE_ROW) {
+		const char* value = (const char *)sqlite3_column_text(stmt, 0);
+
+        if (value == NULL) {
+            tsk_error_set_errstr2("sqlite_v1_get_properties: null value");
+            ret = -1;
+        } else {
+            // Set the updateable flag
+            if (strcmp(value, "true") == 0) {
+                hdb_info->idx_info->updateable = 1;
+            }
+        }
+	} else {
+        tsk_error_set_errstr2("sqlite_v1_get_properties");
+        ret = -1;
+    }
+
+	sqlite3_reset(stmt);
+    
+    if (stmt) {
+        finalize_stmt(stmt);
+    }
+
+
+    ///@todo load db name property as well?
+
+    tsk_release_lock(&hdb_info->lock);
+
+	return ret;
+}
+
+/*
+ * Close the sqlite index handle
+ * @param idx_info the index to close
+ */
+void
+sqlite_v1_close(TSK_IDX_INFO * idx_info)
+{
+    if (m_stmt) {
+        finalize_stmt(m_stmt);
+    }
+
+    m_stmt = NULL;
+
+    if (idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite) {
+        sqlite3_close(idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
+    }
+}
+
+/**
+ * Test the file to see if it is an sqlite database (== index only)
+ *
+ * @param hFile File handle to hash database
+ *
+ * @return 1 if sqlite and 0 if not
+ */
+uint8_t
+sqlite3_test(FILE * hFile)
+{
+    const int header_size = 16;
+    char header[header_size];
+
+    if (hFile) {
+        if (1 != fread(header, header_size, 1, hFile)) {
+            ///@todo should this actually be an error?
+            return 0;
+        }
+        else if (strncmp(header,
+                IDX_SQLITE_V1_HEADER,
+                strlen(IDX_SQLITE_V1_HEADER)) == 0) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/tsk/hashdb/tm_lookup.c b/tsk/hashdb/tm_lookup.c
deleted file mode 100644
index 9a60263bb517277f70e0b35e4a9f54cee60a21b8..0000000000000000000000000000000000000000
--- a/tsk/hashdb/tm_lookup.c
+++ /dev/null
@@ -1,1353 +0,0 @@
-/*
- * The Sleuth Kit
- *
- * Brian Carrier [carrier <at> sleuthkit [dot] org]
- * Copyright (c) 2003-2011 Brian Carrier.  All rights reserved
- *
- *
- * This software is distributed under the Common Public License 1.0
- */
-
-#include "tsk_hashdb_i.h"
-
-/**
- * \file tm_lookup.c
- * Contains the generic hash database creation and lookup code.
- */
-
-
-
-/**
- * Setup the hash-type specific information (such as length, index entry
- * sizes, index name etc.) in the HDB_INFO structure.
- *
- * @param hdb_info Structure to fill in.
- * @param htype Hash type being used
- * @return 1 on error and 0 on success
- */
-static uint8_t
-hdb_setuphash(TSK_HDB_INFO * hdb_info, uint8_t htype)
-{
-    size_t flen;
-
-    if (hdb_info->hash_type != 0) {
-        return 0;
-    }
-
-    /* Make the name for the index file */
-    flen = TSTRLEN(hdb_info->db_fname) + 32;
-    hdb_info->idx_fname =
-        (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR));
-    if (hdb_info->idx_fname == NULL) {
-        return 1;
-    }
-
-    /* Get hash type specific information */
-    switch (htype) {
-    case TSK_HDB_HTYPE_MD5_ID:
-        hdb_info->hash_type = htype;
-        hdb_info->hash_len = TSK_HDB_HTYPE_MD5_LEN;
-        hdb_info->idx_llen = TSK_HDB_IDX_LEN(htype);
-        TSNPRINTF(hdb_info->idx_fname, flen,
-                  _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"),
-                  hdb_info->db_fname, TSK_HDB_HTYPE_MD5_STR);
-        return 0;
-    case TSK_HDB_HTYPE_SHA1_ID:
-        hdb_info->hash_type = htype;
-        hdb_info->hash_len = TSK_HDB_HTYPE_SHA1_LEN;
-        hdb_info->idx_llen = TSK_HDB_IDX_LEN(htype);
-        TSNPRINTF(hdb_info->idx_fname, flen,
-                  _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"),
-                  hdb_info->db_fname, TSK_HDB_HTYPE_SHA1_STR);
-        return 0;
-    }
-
-    tsk_error_reset();
-    tsk_error_set_errno(TSK_ERR_HDB_ARG);
-    tsk_error_set_errstr(
-             "hdb_setuphash: Invalid hash type as argument: %d", htype);
-    return 1;
-}
-
-
-/** Initialize the TSK hash DB index file. This creates the intermediate file,
- * which will have entries added to it.  This file must be sorted before the 
- * process is finished.
- *
- * @param hdb_info Hash database state structure
- * @param htype String of index type to create
- *
- * @return 1 on error and 0 on success
- *
- */
-uint8_t
-tsk_hdb_idxinitialize(TSK_HDB_INFO * hdb_info, TSK_TCHAR * htype)
-{
-    size_t flen;
-    char dbtmp[32];
-    int i;
-
-
-    /* Use the string of the index/hash type to figure out some
-     * settings */
-
-    // convert to char -- cheating way to deal with WCHARs..
-    for (i = 0; i < 31 && htype[i] != '\0'; i++) {
-        dbtmp[i] = (char) htype[i];
-    }
-    dbtmp[i] = '\0';
-
-    if (strcmp(dbtmp, TSK_HDB_DBTYPE_NSRL_MD5_STR) == 0) {
-
-        if (hdb_info->db_type != TSK_HDB_DBTYPE_NSRL_ID) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_ARG);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
-                     hdb_info->db_type, TSK_HDB_DBTYPE_NSRL_ID);
-            return 1;
-        }
-        hdb_setuphash(hdb_info, TSK_HDB_HTYPE_MD5_ID);
-    }
-    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_NSRL_SHA1_STR) == 0) {
-        if (hdb_info->db_type != TSK_HDB_DBTYPE_NSRL_ID) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_ARG);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
-                     hdb_info->db_type, TSK_HDB_DBTYPE_NSRL_ID);
-            return 1;
-        }
-        hdb_setuphash(hdb_info, TSK_HDB_HTYPE_SHA1_ID);
-    }
-    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_MD5SUM_STR) == 0) {
-        if (hdb_info->db_type != TSK_HDB_DBTYPE_MD5SUM_ID) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_ARG);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
-                     hdb_info->db_type, TSK_HDB_DBTYPE_MD5SUM_ID);
-            return 1;
-        }
-        hdb_setuphash(hdb_info, TSK_HDB_HTYPE_MD5_ID);
-    }
-    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_HK_STR) == 0) {
-        if (hdb_info->db_type != TSK_HDB_DBTYPE_HK_ID) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_ARG);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
-                     hdb_info->db_type, TSK_HDB_DBTYPE_HK_ID);
-            return 1;
-        }
-        hdb_setuphash(hdb_info, TSK_HDB_HTYPE_MD5_ID);
-    }
-    else if (strcmp(dbtmp, TSK_HDB_DBTYPE_ENCASE_STR) == 0) {
-        if (hdb_info->db_type != TSK_HDB_DBTYPE_ENCASE_ID) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_ARG);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: database detected as: %d index creation as: %d",
-                     hdb_info->db_type, TSK_HDB_DBTYPE_ENCASE_ID);
-            return 1;
-        }
-        hdb_setuphash(hdb_info, TSK_HDB_HTYPE_MD5_ID);
-    }
-    else {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_ARG);
-        tsk_error_set_errstr(
-                 "hdb_idxinitialize: Unknown database type request: %s",
-                 dbtmp);
-        return 1;
-    }
-
-    /* Setup the internal hash information */
-    if (hdb_setuphash(hdb_info, hdb_info->hash_type)) {
-        return 1;
-    }
-
-    /* Make the name for the unsorted intermediate index file */
-    flen = TSTRLEN(hdb_info->db_fname) + 32;
-    hdb_info->uns_fname =
-        (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR));
-    if (hdb_info->uns_fname == NULL) {
-        return 1;
-    }
-    TSNPRINTF(hdb_info->uns_fname, flen,
-              _TSK_T("%s-%") PRIcTSK _TSK_T("-ns.idx"), hdb_info->db_fname,
-              TSK_HDB_HTYPE_STR(hdb_info->hash_type));
-
-
-    /* Create temp unsorted file of offsets */
-#ifdef TSK_WIN32
-    {
-        HANDLE hWin;
-
-        if ((hWin = CreateFile(hdb_info->uns_fname, GENERIC_WRITE,
-                               0, 0, CREATE_ALWAYS, 0, 0)) ==
-            INVALID_HANDLE_VALUE) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_CREATE);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: %"PRIttocTSK" GetFileSize: %d",
-                     hdb_info->uns_fname, (int)GetLastError());
-            return 1;
-        }
-
-        hdb_info->hIdxTmp =
-            _fdopen(_open_osfhandle((intptr_t) hWin, _O_WRONLY), "wb");
-        if (hdb_info->hIdxTmp == NULL) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-            tsk_error_set_errstr(
-                     "hdb_idxinitialize: Error converting Windows handle to C handle");
-            free(hdb_info);
-            return 1;
-        }
-    }
-#else
-    if (NULL == (hdb_info->hIdxTmp = fopen(hdb_info->uns_fname, "w"))) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_CREATE);
-        tsk_error_set_errstr(
-                 "Error creating temp index file: %s",
-                 hdb_info->uns_fname);
-        return 1;
-    }
-#endif
-
-    /* Print the header */
-    fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_NAME_STR,
-        hdb_info->db_name);
-    switch (hdb_info->db_type) {
-    case TSK_HDB_DBTYPE_NSRL_ID:
-       fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR,
-            TSK_HDB_DBTYPE_NSRL_STR);
-        break;
-    case TSK_HDB_DBTYPE_MD5SUM_ID:
-        fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR,
-            TSK_HDB_DBTYPE_MD5SUM_STR);
-        break;
-    case TSK_HDB_DBTYPE_HK_ID:
-        fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR,
-            TSK_HDB_DBTYPE_HK_STR);
-        break;
-    case TSK_HDB_DBTYPE_ENCASE_ID:
-        fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR,
-            TSK_HDB_DBTYPE_ENCASE_STR);
-        break;
-        /* Used to stop warning messages about missing enum value */
-    case TSK_HDB_DBTYPE_IDXONLY_ID:
-    default:
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_CREATE);
-        tsk_error_set_errstr("idxinit: Invalid db type\n");
-        return 1;
-    }
-
-    return 0;
-}
-
-/**
- * Add a string entry to the intermediate index file.
- *
- * @param hdb_info Hash database state info
- * @param hvalue String of hash value to add
- * @param offset Byte offset of hash entry in original database.
- * @return 1 on error and 0 on success
- */
-uint8_t
-tsk_hdb_idxaddentry(TSK_HDB_INFO * hdb_info, char *hvalue,
-                    TSK_OFF_T offset)
-{
-    int i;
-    // make the hashes all upper case
-    for (i = 0; hvalue[i] != '\0'; i++) {
-        if (islower((int) hvalue[i]))
-            fprintf(hdb_info->hIdxTmp, "%c", toupper((int) hvalue[i]));
-        else
-            fprintf(hdb_info->hIdxTmp, "%c", hvalue[i]);
-    }
-
-    /* Print the entry to the unsorted index file */
-    fprintf(hdb_info->hIdxTmp, "|%.16llu\n", (unsigned long long) offset);
-
-    return 0;
-}
-
-/**
- * Add a binary entry to the intermediate index file.
- *
- * @param hdb_info Hash database state info
- * @param hvalue Array of integers of hash value to add
- * @param hlen Number of bytes in hvalue
- * @param offset Byte offset of hash entry in original database.
- * @return 1 on error and 0 on success
- */
-uint8_t
-tsk_hdb_idxaddentry_bin(TSK_HDB_INFO * hdb_info, unsigned char *hvalue, int hlen,
-                    TSK_OFF_T offset)
-{
-    int i;
-    for (i = 0; i < hlen; i++) {
-        fprintf(hdb_info->hIdxTmp, "%02X", hvalue[i]);
-    }
-
-    /* Print the entry to the unsorted index file */
-    fprintf(hdb_info->hIdxTmp, "|%.16llu\n", (unsigned long long) offset);
-
-    return 0;
-}
-
-/**
- * Finalize index creation process by sorting the index and removing the
- * intermediate temp file.
- *
- * @param hdb_info Hash database state info structure.
- * @return 1 on error and 0 on success
- */
-uint8_t
-tsk_hdb_idxfinalize(TSK_HDB_INFO * hdb_info)
-{
-#ifdef TSK_WIN32
-    wchar_t buf[TSK_HDB_MAXLEN];
-    /// @@ Expand this to be SYSTEM_ROOT -- GetWindowsDirectory()
-    wchar_t *sys32 = _TSK_T("C:\\WINDOWS\\System32\\sort.exe");
-    DWORD stat;
-    STARTUPINFO myStartInfo;
-    PROCESS_INFORMATION pinfo;
-
-    /* Close the unsorted file */
-    fclose(hdb_info->hIdxTmp);
-    hdb_info->hIdxTmp = NULL;
-
-    /* Close the existing index if it is open */
-    if (hdb_info->hIdx) {
-        fclose(hdb_info->hIdx);
-        hdb_info->hIdx = NULL;
-    }
-
-    if (tsk_verbose)
-        tsk_fprintf(stderr, "hdb_idxfinalize: Sorting index\n");
-
-    stat = GetFileAttributes(sys32);
-    if ((stat != -1) && ((stat & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
-        TSNPRINTF(buf, TSK_HDB_MAXLEN, _TSK_T("%s /o \"%s\" \"%s\""),
-                  sys32, hdb_info->idx_fname, hdb_info->uns_fname);
-    }
-    else {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_MISSING);
-        tsk_error_set_errstr("Cannot find sort executable");
-        return 1;
-    }
-
-    GetStartupInfo(&myStartInfo);
-
-    if (FALSE ==
-        CreateProcess(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL,
-                      &myStartInfo, &pinfo)) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_PROC);
-        tsk_error_set_errstr(
-                 "Error starting sorting index file using %S", buf);
-        return 1;
-    }
-
-    if (WAIT_FAILED == WaitForSingleObject(pinfo.hProcess, INFINITE)) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_PROC);
-        tsk_error_set_errstr(
-                 "Error (waiting) sorting index file using %S", buf);
-        return 1;
-    }
-
-    if (FALSE == DeleteFile(hdb_info->uns_fname)) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_DELETE);
-        tsk_error_set_errstr(
-                 "Error deleting temp file: %d", (int)GetLastError());
-        return 1;
-    }
-#else
-    char buf[TSK_HDB_MAXLEN];
-    char *root = "/bin/sort";
-    char *usr = "/usr/bin/sort";
-    char *local = "/usr/local/bin/sort";
-    struct stat stats;
-
-    if (tsk_verbose)
-        tsk_fprintf(stderr, "hdb_idxfinalize: Sorting index\n");
-
-    /* Close the unsorted file */
-    fclose(hdb_info->hIdxTmp);
-    hdb_info->hIdxTmp = NULL;
-
-    /* Close the existing index if it is open */
-    if (hdb_info->hIdx) {
-        fclose(hdb_info->hIdx);
-        hdb_info->hIdx = NULL;
-    }
-
-    if (0 == stat(local, &stats)) {
-        snprintf(buf, TSK_HDB_MAXLEN, "%s -o %s %s", local,
-                 hdb_info->idx_fname, hdb_info->uns_fname);
-    }
-    else if (0 == stat(usr, &stats)) {
-        snprintf(buf, TSK_HDB_MAXLEN, "%s -o \"%s\" \"%s\"",
-                 usr, hdb_info->idx_fname, hdb_info->uns_fname);
-    }
-    else if (0 == stat(root, &stats)) {
-        snprintf(buf, TSK_HDB_MAXLEN, "%s -o \"%s\" \"%s\"",
-                 root, hdb_info->idx_fname, hdb_info->uns_fname);
-    }
-    else {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_MISSING);
-        tsk_error_set_errstr("Cannot find sort executable");
-        return 1;
-    }
-
-    if (0 != system(buf)) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_PROC);
-        tsk_error_set_errstr(
-                 "Error sorting index file using %s", buf);
-        return 1;
-    }
-
-    unlink(hdb_info->uns_fname);
-#endif
-
-    return 0;
-}
-
-
-/** \internal
- * Setup the internal variables to read an index. This
- * opens the index and sets the needed size information.
- *
- * @param hdb_info Hash database to analyze
- * @param hash The hash type that was used to make the index.
- *
- * @return 1 on error and 0 on success
- */
-static uint8_t
-hdb_setupindex(TSK_HDB_INFO * hdb_info, uint8_t htype)
-{
-    char head[TSK_HDB_MAXLEN];
-    char head2[TSK_HDB_MAXLEN];
-    char *ptr;
- 
-    // Lock for lazy load of hIdx and lazy alloc of idx_lbuf.
-    tsk_take_lock(&hdb_info->lock);
-
-    if (hdb_info->hIdx != NULL) {
-        tsk_release_lock(&hdb_info->lock);
-        return 0;
-    }
-
-    if ((htype != TSK_HDB_HTYPE_MD5_ID)
-        && (htype != TSK_HDB_HTYPE_SHA1_ID)) {
-        tsk_release_lock(&hdb_info->lock);
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_ARG);
-        tsk_error_set_errstr(
-                 "hdb_setupindex: Invalid hash type : %d", htype);
-        return 1;
-    }
-
-    if (hdb_setuphash(hdb_info, htype)) {
-        tsk_release_lock(&hdb_info->lock);
-        return 1;
-    }
-
-    /* Verify the index exists, get its size, and open it */
-#ifdef TSK_WIN32
-    {
-        HANDLE hWin;
-        DWORD szLow, szHi;
-
-        if (-1 == GetFileAttributes(hdb_info->idx_fname)) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
-            tsk_error_set_errstr(
-                     "hdb_setupindex: Error finding index file: %"PRIttocTSK,
-                     hdb_info->idx_fname);
-            return 1;
-        }
-
-        if ((hWin = CreateFile(hdb_info->idx_fname, GENERIC_READ,
-                               FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) ==
-            INVALID_HANDLE_VALUE) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-            tsk_error_set_errstr(
-                     "hdb_setupindex: Error opening index file: %"PRIttocTSK,
-                     hdb_info->idx_fname);
-            return 1;
-        }
-        hdb_info->hIdx =
-            _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r");
-        if (hdb_info->hIdx == NULL) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-            tsk_error_set_errstr(
-                     "hdb_setupindex: Error converting Windows handle to C handle");
-            return 1;
-        }
-
-        szLow = GetFileSize(hWin, &szHi);
-        if (szLow == 0xffffffff) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-            tsk_error_set_errstr(
-                     "hdb_setupindex: Error getting size of index file: %"PRIttocTSK" - %d",
-                     hdb_info->idx_fname, (int)GetLastError());
-            return 1;
-        }
-        hdb_info->idx_size = szLow | ((uint64_t) szHi << 32);
-    }
-
-#else
-    {
-        struct stat sb;
-        if (stat(hdb_info->idx_fname, &sb) < 0) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_MISSING);
-            tsk_error_set_errstr(
-                     "hdb_setupindex: Error finding index file: %s",
-                     hdb_info->idx_fname);
-            return 1;
-        }
-        hdb_info->idx_size = sb.st_size;
-
-        if (NULL == (hdb_info->hIdx = fopen(hdb_info->idx_fname, "r"))) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-            tsk_error_set_errstr(
-                     "hdb_setupindex: Error opening index file: %s",
-                     hdb_info->idx_fname);
-            return 1;
-        }
-    }
-#endif
-
-    /* Do some testing on the first line */
-    if (NULL == fgets(head, TSK_HDB_MAXLEN, hdb_info->hIdx)) {
-        tsk_release_lock(&hdb_info->lock);
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-        tsk_error_set_errstr(
-                 "hdb_setupindex: Header line of index file");
-        return 1;
-    }
-
-    if (strncmp(head, TSK_HDB_IDX_HEAD_TYPE_STR, strlen(TSK_HDB_IDX_HEAD_TYPE_STR))
-        != 0) {
-        tsk_release_lock(&hdb_info->lock);
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-        tsk_error_set_errstr(
-                 "hdb_setupindex: Invalid index file: Missing header line");
-        return 1;
-    }
-
-    /* Do some testing on the second line */
-    if (NULL == fgets(head2, TSK_HDB_MAXLEN, hdb_info->hIdx)) {
-        tsk_release_lock(&hdb_info->lock);
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-        tsk_error_set_errstr(
-                 "hdb_setupindex: Error reading line 2 of index file");
-        return 1;
-    }
-
-    /* Set the offset to the start of the index entries */
-    if (strncmp(head2, TSK_HDB_IDX_HEAD_NAME_STR, strlen(TSK_HDB_IDX_HEAD_NAME_STR))
-        != 0) {
-        hdb_info->idx_off = (uint16_t) (strlen(head));
-    } else {
-        hdb_info->idx_off = (uint16_t) (strlen(head) + strlen(head2));
-    }
-
-
-    /* Skip the space */
-    ptr = &head[strlen(TSK_HDB_IDX_HEAD_TYPE_STR) + 1];
-
-    ptr[strlen(ptr) - 1] = '\0';
-    if ((ptr[strlen(ptr) - 1] == 10) || (ptr[strlen(ptr) - 1] == 13)) {
-        ptr[strlen(ptr) - 1] = '\0';
-        hdb_info->idx_llen++;   // make the expected index length longer to account for different cr/nl/etc.
-    }
-
-    /* Verify the header value in the index */
-    if (strcmp(ptr, TSK_HDB_DBTYPE_NSRL_STR) == 0) {
-        if ((hdb_info->db_type != TSK_HDB_DBTYPE_NSRL_ID) &&
-            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-            tsk_error_set_errstr(
-                     "hdb_indexsetup: DB detected as %s, index type has NSRL",
-                     ptr);
-            return 1;
-        }
-    }
-    else if (strcmp(ptr, TSK_HDB_DBTYPE_MD5SUM_STR) == 0) {
-        if ((hdb_info->db_type != TSK_HDB_DBTYPE_MD5SUM_ID) &&
-            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-            tsk_error_set_errstr(
-                     "hdb_indexsetup: DB detected as %s, index type has MD5SUM",
-                     ptr);
-            return 1;
-        }
-    }
-    else if (strcmp(ptr, TSK_HDB_DBTYPE_HK_STR) == 0) {
-        if ((hdb_info->db_type != TSK_HDB_DBTYPE_HK_ID) &&
-            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-            tsk_error_set_errstr(
-                     "hdb_indexsetup: DB detected as %s, index type has hashkeeper",
-                     ptr);
-            return 1;
-        }
-    }
-    else if (strcmp(ptr, TSK_HDB_DBTYPE_ENCASE_STR) == 0) {
-        if ((hdb_info->db_type != TSK_HDB_DBTYPE_ENCASE_ID) &&
-            (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-            tsk_error_set_errstr(
-                     "hdb_indexsetup: DB detected as %s, index type has EnCase",
-                     ptr);
-            return 1;
-        }
-    }
-    else if (hdb_info->db_type != TSK_HDB_DBTYPE_IDXONLY_ID) {
-        tsk_release_lock(&hdb_info->lock);
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-        tsk_error_set_errstr(
-                 "hdb_setupindex: Unknown Database Type in index header: %s",
-                 ptr);
-        return 1;
-    }
-
-    /* Do some sanity checking */
-    if (((hdb_info->idx_size - hdb_info->idx_off) % hdb_info->idx_llen) !=
-        0) {
-        tsk_release_lock(&hdb_info->lock);
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
-        tsk_error_set_errstr(
-                 "hdb_setupindex: Error, size of index file is not a multiple of row size");
-        return 1;
-    }
-
-    /* allocate a buffer for a row */
-    if ((hdb_info->idx_lbuf = tsk_malloc(hdb_info->idx_llen + 1)) == NULL) {
-        tsk_release_lock(&hdb_info->lock);
-        return 1;
-    }
-
-    tsk_release_lock(&hdb_info->lock);
-
-    return 0;
-}
-
-
-
-
-
-
-
-
-/**
- * \ingroup hashdblib
- * Search the index for a text/ASCII hash value
- *
- * @param hdb_info Open hash database (with index)
- * @param hash Hash value to search for (NULL terminated string)
- * @param flags Flags to use in lookup
- * @param action Callback function to call for each hash db entry 
- * (not called if QUICK flag is given)
- * @param ptr Pointer to data to pass to each callback
- *
- * @return -1 on error, 0 if hash value not found, and 1 if value was found.
- */
-int8_t
-tsk_hdb_lookup_str(TSK_HDB_INFO * hdb_info, const char *hash,
-                   TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action,
-                   void *ptr)
-{
-    TSK_OFF_T poffset;
-    TSK_OFF_T up;               // Offset of the first byte past the upper limit that we are looking in
-    TSK_OFF_T low;              // offset of the first byte of the lower limit that we are looking in
-    int cmp;
-    uint8_t wasFound = 0;
-    size_t i;
-    uint8_t htype;
-
-
-    /* Sanity checks on the hash input */
-    if (strlen(hash) == TSK_HDB_HTYPE_MD5_LEN) {
-        htype = TSK_HDB_HTYPE_MD5_ID;
-    }
-    else if (strlen(hash) == TSK_HDB_HTYPE_SHA1_LEN) {
-        htype = TSK_HDB_HTYPE_SHA1_ID;
-    }
-    else {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_ARG);
-        tsk_error_set_errstr(
-                 "hdb_lookup: Invalid hash length: %s", hash);
-        return -1;
-    }
-
-    for (i = 0; i < strlen(hash); i++) {
-        if (isxdigit((int) hash[i]) == 0) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_ARG);
-            tsk_error_set_errstr(
-                     "hdb_lookup: Invalid hash value (hex only): %s",
-                     hash);
-            return -1;
-        }
-    }
-
-    if (hdb_setupindex(hdb_info, htype))
-        return -1;
-
-
-    /* Sanity check */
-    if (hdb_info->hash_len != strlen(hash)) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_ARG);
-        tsk_error_set_errstr(
-                 "hdb_lookup: Hash passed is different size than expected (%d vs %Zd)",
-                 hdb_info->hash_len, strlen(hash));
-        return -1;
-    }
-
-
-    low = hdb_info->idx_off;
-    up = hdb_info->idx_size;
-
-    poffset = 0;
-
-    // We have to lock access to idx_lbuf, but since we're in a loop,
-    // I'm assuming one lock up front is better than many inside.
-    tsk_take_lock(&hdb_info->lock);
-
-    while (1) {
-        TSK_OFF_T offset;
-
-        /* If top and bottom are the same, it's not there */
-        if (up == low) {
-            tsk_release_lock(&hdb_info->lock);
-            return 0;
-        }
-
-        /* Get the middle of the windows that we are looking at */
-        offset = rounddown(((up - low) / 2), hdb_info->idx_llen);
-
-        /* Sanity Check */
-        if ((offset % hdb_info->idx_llen) != 0) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
-            tsk_error_set_errstr(
-                     "hdb_lookup: Error, new offset is not a multiple of the line length");
-            return -1;
-        }
-
-        /* The middle offset is relative to the low offset, so add them */
-        offset += low;
-
-        /* If we didn't move, then it's not there */
-        if (poffset == offset) {
-            tsk_release_lock(&hdb_info->lock);
-            return 0;
-        }
-
-        /* Seek to the offset and read it */
-        if (0 != fseeko(hdb_info->hIdx, offset, SEEK_SET)) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-            tsk_error_set_errstr(
-                     "hdb_lookup: Error seeking in search: %" PRIuOFF,
-                     offset);
-            return -1;
-        }
-
-        if (NULL ==
-            fgets(hdb_info->idx_lbuf, (int) hdb_info->idx_llen + 1,
-                  hdb_info->hIdx)) {
-            if (feof(hdb_info->hIdx)) {
-                tsk_release_lock(&hdb_info->lock);
-                return 0;
-            }
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-            tsk_error_set_errstr(
-                     "Error reading index file: %lu",
-                     (unsigned long) offset);
-            return -1;
-        }
-
-        /* Sanity Check */
-        if ((strlen(hdb_info->idx_lbuf) < hdb_info->idx_llen) ||
-            (hdb_info->idx_lbuf[hdb_info->hash_len] != '|')) {
-            tsk_release_lock(&hdb_info->lock);
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
-            tsk_error_set_errstr(
-                     "Invalid line in index file: %lu (%s)",
-                     (unsigned long) (offset / hdb_info->idx_llen),
-                     hdb_info->idx_lbuf);
-            return -1;
-        }
-
-        /* Set the delimter to NULL so we can treat the hash as a string */
-        hdb_info->idx_lbuf[hdb_info->hash_len] = '\0';
-        cmp = strcasecmp(hdb_info->idx_lbuf, hash);
-
-        /* The one we just read is too small, so set the new lower bound
-         * at the start of the next row */
-        if (cmp < 0) {
-            low = offset + hdb_info->idx_llen;
-        }
-
-        /* The one we just read is too big, so set the upper bound at this
-         * entry */
-        else if (cmp > 0) {
-            up = offset;
-        }
-
-        /* We found it */
-        else {
-            wasFound = 1;
-
-            if ((flags & TSK_HDB_FLAG_QUICK)
-                || (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)) {
-                tsk_release_lock(&hdb_info->lock);
-                return 1;
-            }
-            else {
-                TSK_OFF_T tmpoff, db_off;
-
-#ifdef TSK_WIN32
-                db_off =
-                    _atoi64(&hdb_info->idx_lbuf[hdb_info->hash_len + 1]);
-#else
-                db_off =
-                    strtoull(&hdb_info->idx_lbuf[hdb_info->hash_len + 1],
-                             NULL, 10);
-#endif
-
-                /* Print the one that we found first */
-                if (hdb_info->
-                    getentry(hdb_info, hash, db_off, flags, action, ptr)) {
-                    tsk_release_lock(&hdb_info->lock);
-                    tsk_error_set_errstr2( "hdb_lookup");
-                    return -1;
-                }
-
-
-                /* there could be additional entries both before and after
-                 * this entry - but we can restrict ourselves to the up
-                 * and low bounds from our previous hunting 
-                 */
-
-                tmpoff = offset - hdb_info->idx_llen;
-                while (tmpoff >= low) {
-
-                    /* Break if we are at the header */
-                    if (tmpoff <= 0)
-                        break;
-
-                    if (0 != fseeko(hdb_info->hIdx, tmpoff, SEEK_SET)) {
-                        tsk_release_lock(&hdb_info->lock);
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-                        tsk_error_set_errstr(
-                                 "hdb_lookup: Error seeking for prev entries: %"
-                                 PRIuOFF, tmpoff);
-                        return -1;
-                    }
-
-                    if (NULL ==
-                        fgets(hdb_info->idx_lbuf,
-                              (int) hdb_info->idx_llen + 1,
-                              hdb_info->hIdx)) {
-                        tsk_release_lock(&hdb_info->lock);
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-                        tsk_error_set_errstr(
-                                 "Error reading index file (prev): %lu",
-                                 (unsigned long) tmpoff);
-                        return -1;
-                    }
-                    else if (strlen(hdb_info->idx_lbuf) <
-                             hdb_info->idx_llen) {
-                        tsk_release_lock(&hdb_info->lock);
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
-                        tsk_error_set_errstr(
-                                 "Invalid index file line (prev): %lu",
-                                 (unsigned long) tmpoff);
-                        return -1;
-                    }
-
-                    hdb_info->idx_lbuf[hdb_info->hash_len] = '\0';
-                    if (strcasecmp(hdb_info->idx_lbuf, hash) != 0) {
-                        break;
-                    }
-
-#ifdef TSK_WIN32
-                    db_off =
-                        _atoi64(&hdb_info->
-                                idx_lbuf[hdb_info->hash_len + 1]);
-#else
-
-                    db_off =
-                        strtoull(&hdb_info->
-                                 idx_lbuf[hdb_info->hash_len + 1], NULL,
-                                 10);
-#endif
-                    if (hdb_info->
-                        getentry(hdb_info, hash, db_off, flags, action,
-                                 ptr)) {
-                        tsk_release_lock(&hdb_info->lock);
-                        return -1;
-                    }
-                    tmpoff -= hdb_info->idx_llen;
-                }
-
-                /* next entries */
-                tmpoff = offset + hdb_info->idx_llen;
-                while (tmpoff < up) {
-
-                    if (0 != fseeko(hdb_info->hIdx, tmpoff, SEEK_SET)) {
-                        tsk_release_lock(&hdb_info->lock);
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-                        tsk_error_set_errstr(
-                                 "hdb_lookup: Error seeking for next entries: %"
-                                 PRIuOFF, tmpoff);
-                        return -1;
-                    }
-
-                    if (NULL ==
-                        fgets(hdb_info->idx_lbuf,
-                              (int) hdb_info->idx_llen + 1,
-                              hdb_info->hIdx)) {
-                        if (feof(hdb_info->hIdx))
-                            break;
-                        tsk_release_lock(&hdb_info->lock);
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_HDB_READIDX);
-                        tsk_error_set_errstr(
-                                 "Error reading index file (next): %lu",
-                                 (unsigned long) tmpoff);
-                        return -1;
-                    }
-                    else if (strlen(hdb_info->idx_lbuf) <
-                             hdb_info->idx_llen) {
-                        tsk_release_lock(&hdb_info->lock);
-                        tsk_error_reset();
-                        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
-                        tsk_error_set_errstr(
-                                 "Invalid index file line (next): %lu",
-                                 (unsigned long) tmpoff);
-                        return -1;
-                    }
-
-                    hdb_info->idx_lbuf[hdb_info->hash_len] = '\0';
-                    if (strcasecmp(hdb_info->idx_lbuf, hash) != 0) {
-                        break;
-                    }
-#ifdef TSK_WIN32
-                    db_off =
-                        _atoi64(&hdb_info->
-                                idx_lbuf[hdb_info->hash_len + 1]);
-#else
-                    db_off =
-                        strtoull(&hdb_info->
-                                 idx_lbuf[hdb_info->hash_len + 1], NULL,
-                                 10);
-#endif
-                    if (hdb_info->
-                        getentry(hdb_info, hash, db_off, flags, action,
-                                 ptr)) {
-                        tsk_release_lock(&hdb_info->lock);
-                        return -1;
-                    }
-
-                    tmpoff += hdb_info->idx_llen;
-                }
-            }
-            break;
-        }
-        poffset = offset;
-    }
-    tsk_release_lock(&hdb_info->lock);
-
-    return wasFound;
-}
-
-/**
- * \ingroup hashdblib
- * Search the index for the given hash value given (in binary form).
- *
- * @param hdb_info Open hash database (with index)
- * @param hash Array with binary hash value to search for
- * @param len Number of bytes in binary hash value
- * @param flags Flags to use in lookup
- * @param action Callback function to call for each hash db entry 
- * (not called if QUICK flag is given)
- * @param ptr Pointer to data to pass to each callback
- *
- * @return -1 on error, 0 if hash value not found, and 1 if value was found.
- */
-int8_t
-tsk_hdb_lookup_raw(TSK_HDB_INFO * hdb_info, uint8_t * hash, uint8_t len,
-                   TSK_HDB_FLAG_ENUM flags,
-                   TSK_HDB_LOOKUP_FN action, void *ptr)
-{
-    char hashbuf[TSK_HDB_HTYPE_SHA1_LEN + 1];
-    int i;
-    static const char hex[] = "0123456789abcdef";
-
-    if (2 * len > TSK_HDB_HTYPE_SHA1_LEN) {
-        tsk_error_reset();
-        tsk_error_set_errno(TSK_ERR_HDB_ARG);
-        tsk_error_set_errstr(
-                 "tsk_hdb_lookup_raw: hash value too long\n");
-        return -1;
-    }
-
-    for (i = 0; i < len; i++) {
-        hashbuf[2 * i] = hex[(hash[i] >> 4) & 0xf];
-        hashbuf[2 * i + 1] = hex[hash[i] & 0xf];
-    }
-    hashbuf[2 * len] = '\0';
-
-    return tsk_hdb_lookup_str(hdb_info, hashbuf, flags, action, ptr);
-}
-
-/**
- * \ingroup hashdblib
- * Determine if the open hash database has an index.
- *
- * @param hdb_info Hash database to consider
- * @param htype Hash type that index should be of
- *
- * @return 1 if index exists and 0 if not
- */
-uint8_t
-tsk_hdb_hasindex(TSK_HDB_INFO * hdb_info, uint8_t htype)
-{
-    /* Check if the index is already open, and 
-     * try to open it if not */
-    if (hdb_setupindex(hdb_info, htype))
-        return 0;
-    else
-        return 1;
-}
-
-
-
-/**
- * \ingroup hashdblib
- * Open a hash database. 
- *
- * @param db_file Path to database (even if only an index exists).
- * @param flags Flags for opening the database.  
- *
- * @return Poiner to hash database state structure or NULL on error
- */
-TSK_HDB_INFO *
-tsk_hdb_open(TSK_TCHAR * db_file, TSK_HDB_OPEN_ENUM flags)
-{
-    TSK_HDB_INFO *hdb_info;
-    size_t flen;
-    FILE *hDb;
-    uint8_t dbtype = 0;
-
-    if ((flags & TSK_HDB_OPEN_IDXONLY) == 0) {
-        /* Open the database file */
-#ifdef TSK_WIN32
-        {
-            HANDLE hWin;
-
-            if ((hWin = CreateFile(db_file, GENERIC_READ,
-                                   FILE_SHARE_READ, 0, OPEN_EXISTING, 0,
-                                   0)) == INVALID_HANDLE_VALUE) {
-                tsk_error_reset();
-                tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-                tsk_error_set_errstr(
-                         "hdb_open: Error opening database file: %S",
-                         db_file);
-                return NULL;
-            }
-            hDb =
-                _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r");
-            if (hDb == NULL) {
-                tsk_error_reset();
-                tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-                tsk_error_set_errstr(
-                         "hdb_open: Error converting Windows handle to C handle");
-                return NULL;
-            }
-        }
-#else
-        if (NULL == (hDb = fopen(db_file, "r"))) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_OPEN);
-            tsk_error_set_errstr(
-                     "hdb_open: Error opening database file: %s", db_file);
-            return NULL;
-        }
-#endif
-
-        /* Try to figure out what type of DB it is */
-        if (nsrl_test(hDb)) {
-            dbtype = TSK_HDB_DBTYPE_NSRL_ID;
-        }
-        if (md5sum_test(hDb)) {
-            if (dbtype != 0) {
-                tsk_error_reset();
-                tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-                tsk_error_set_errstr(
-                         "hdb_open: Error determining DB type (MD5sum)");
-                return NULL;
-            }
-            dbtype = TSK_HDB_DBTYPE_MD5SUM_ID;
-        }
-        if (encase_test(hDb)) {
-            if (dbtype != 0) {
-                tsk_error_reset();
-                tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-                tsk_error_set_errstr(
-                         "hdb_open: Error determining DB type (EnCase)");
-                return NULL;
-            }
-            dbtype = TSK_HDB_DBTYPE_ENCASE_ID;
-        }
-        if (hk_test(hDb)) {
-            if (dbtype != 0) {
-                tsk_error_reset();
-                tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-                tsk_error_set_errstr(
-                         "hdb_open: Error determining DB type (HK)");
-                return NULL;
-            }
-            dbtype = TSK_HDB_DBTYPE_HK_ID;
-        }
-        if (dbtype == 0) {
-            tsk_error_reset();
-            tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
-            tsk_error_set_errstr(
-                     "hdb_open: Error determining DB type");
-            return NULL;
-        }
-        fseeko(hDb, 0, SEEK_SET);
-    }
-    else {
-        dbtype = TSK_HDB_DBTYPE_IDXONLY_ID;
-        hDb = NULL;
-    }
-
-    if ((hdb_info =
-         (TSK_HDB_INFO *) tsk_malloc(sizeof(TSK_HDB_INFO))) == NULL)
-        return NULL;
-
-    hdb_info->hDb = hDb;
-
-    /* Copy the database name into the structure */
-    flen = TSTRLEN(db_file) + 8;        // + 32;
-
-    hdb_info->db_fname =
-        (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR));
-    if (hdb_info->db_fname == NULL) {
-        free(hdb_info);
-        return NULL;
-    }
-    TSTRNCPY(hdb_info->db_fname, db_file, flen);
-
-    
-    hdb_info->hash_type = 0;
-    hdb_info->hash_len = 0;
-    hdb_info->idx_fname = NULL;
-
-    hdb_info->uns_fname = NULL;
-    hdb_info->hIdxTmp = NULL;
-    hdb_info->hIdx = NULL;
-
-    hdb_info->idx_size = 0;
-    hdb_info->idx_off = 0;
-
-    hdb_info->idx_lbuf = NULL;
-
-    tsk_init_lock(&hdb_info->lock);
-
-    /* Get database specific information */
-    hdb_info->db_type = dbtype;
-    switch (dbtype) {
-    case TSK_HDB_DBTYPE_NSRL_ID:
-        nsrl_name(hdb_info);
-        hdb_info->getentry = nsrl_getentry;
-        hdb_info->makeindex = nsrl_makeindex;
-        break;
-
-    case TSK_HDB_DBTYPE_MD5SUM_ID:
-        md5sum_name(hdb_info);
-        hdb_info->getentry = md5sum_getentry;
-        hdb_info->makeindex = md5sum_makeindex;
-        break;
-
-    case TSK_HDB_DBTYPE_ENCASE_ID:
-        encase_name(hdb_info);
-        hdb_info->getentry = encase_getentry;
-        hdb_info->makeindex = encase_makeindex;
-        break;
-
-    case TSK_HDB_DBTYPE_HK_ID:
-        hk_name(hdb_info);
-        hdb_info->getentry = hk_getentry;
-        hdb_info->makeindex = hk_makeindex;
-        break;
-
-    case TSK_HDB_DBTYPE_IDXONLY_ID:
-        idxonly_name(hdb_info);
-        hdb_info->getentry = idxonly_getentry;
-        hdb_info->makeindex = idxonly_makeindex;
-        break;
-
-    default:
-        return NULL;
-    }
-
-
-    return hdb_info;
-}
-
-/**
- * \ingroup hashdblib
- * Close an open hash database.
- *
- * @param hdb_info database to close
- */
-void
-tsk_hdb_close(TSK_HDB_INFO * hdb_info)
-{
-    if (hdb_info->hIdx)
-        fclose(hdb_info->hIdx);
-
-    if (hdb_info->hIdxTmp)
-        fclose(hdb_info->hIdxTmp);
-    // @@@ Could delete temp file too...
-
-    if (hdb_info->idx_lbuf != NULL)
-        free(hdb_info->idx_lbuf);
-
-    if (hdb_info->db_fname)
-        free(hdb_info->db_fname);
-
-    if (hdb_info->uns_fname)
-        free(hdb_info->uns_fname);
-
-    if (hdb_info->idx_fname)
-        free(hdb_info->idx_fname);
-
-    if (hdb_info->hDb)
-        fclose(hdb_info->hDb);
-
-    tsk_deinit_lock(&hdb_info->lock);
-
-    free(hdb_info);
-}
-
-/**
- * \ingroup hashdblib
- * Create an index for an open hash database.
- * @param a_hdb_info Open hash database to index
- * @param a_type Text of hash database type
- * @returns 1 on error
- */
-uint8_t
-tsk_hdb_makeindex(TSK_HDB_INFO * a_hdb_info, TSK_TCHAR * a_type)
-{
-    return a_hdb_info->makeindex(a_hdb_info, a_type);
-}
-
-/**
- * Set db_name to the name of the database file
- *
- * @param hdb_info the hash database object
- */
-void
-tsk_hdb_name_from_path(TSK_HDB_INFO * hdb_info)
-{
-#ifdef TSK_WIN32
-    const char PATH_CHAR = '\\';
-#else
-    const char PATH_CHAR = '/';
-#endif
-    TSK_TCHAR * begin;
-    TSK_TCHAR * end;
-    int i;
-
-    hdb_info->db_name[0] = '\0';
-
-    begin = TSTRRCHR(hdb_info->db_fname, PATH_CHAR);
-#ifdef TSK_WIN32
-    // cygwin can have forward slashes, so try that too on Windows
-    if (!begin) {
-        begin = TSTRRCHR(hdb_info->db_fname, '/');
-    }
-#endif
-
-    if (!begin) {
-        begin = hdb_info->db_fname;
-    }
-    else {
-        // unlikely since this means that the dbname is "/"
-        if (TSTRLEN(begin) == 1)
-            return;
-        else
-            begin++;
-    }
-
-    // end points to the byte after the last one we want to use
-    if ((TSTRLEN(hdb_info->db_fname) > 4) && (TSTRICMP(&hdb_info->db_fname[TSTRLEN(hdb_info->db_fname)-4], _TSK_T(".idx")) == 0)) 
-        end = &hdb_info->db_fname[TSTRLEN(hdb_info->db_fname)-4];
-    else
-        end = begin + TSTRLEN(begin);
-        
-
-    // @@@ TODO: Use TskUTF16_to_UTF8 to properly convert for Windows
-    for(i = 0; i < (end-begin); i++)
-    {
-        hdb_info->db_name[i] = (char) begin[i];
-    }
-
-    hdb_info->db_name[i] = '\0';
-}
diff --git a/tsk/hashdb/tm_lookup.cpp b/tsk/hashdb/tm_lookup.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cc663b0b60e641961a21ee65ca504e51582e887d
--- /dev/null
+++ b/tsk/hashdb/tm_lookup.cpp
@@ -0,0 +1,104 @@
+/*
+ * The Sleuth Kit
+ *
+ * Brian Carrier [carrier <at> sleuthkit [dot] org]
+ * Copyright (c) 2003-2013 Brian Carrier.  All rights reserved
+ *
+ *
+ * This software is distributed under the Common Public License 1.0
+ */
+
+#include "tsk_hashdb_i.h"
+
+
+/**
+ * \file tm_lookup.cpp
+ * Contains the generic hash database lookup code.
+ */
+
+
+
+/**
+ * \ingroup hashdblib
+ * Search the index for a text/ASCII hash value
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash Hash value to search for (NULL terminated string)
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+int8_t
+tsk_hdb_lookup_str(TSK_HDB_INFO * hdb_info, const char *hash,
+                   TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action,
+                   void *ptr)
+{
+    uint8_t htype;
+
+    /* Sanity checks on the hash input */
+    if (strlen(hash) == TSK_HDB_HTYPE_MD5_LEN) {
+        htype = TSK_HDB_HTYPE_MD5_ID;
+    }
+    else if (strlen(hash) == TSK_HDB_HTYPE_SHA1_LEN) {
+        htype = TSK_HDB_HTYPE_SHA1_ID;
+    }
+    else {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                "hdb_lookup_str: Invalid hash length: %s", hash);
+        return -1;
+    }
+
+    if (hdb_setupindex(hdb_info, htype, 0)) {
+        return -1;
+    }
+
+    return hdb_info->idx_info->lookup_str(hdb_info, hash, flags, action, ptr);
+}
+
+/**
+ * \ingroup hashdblib
+ * Search the index for the given hash value given (in binary form).
+ *
+ * @param hdb_info Open hash database (with index)
+ * @param hash Array with binary hash value to search for
+ * @param len Number of bytes in binary hash value
+ * @param flags Flags to use in lookup
+ * @param action Callback function to call for each hash db entry 
+ * (not called if QUICK flag is given)
+ * @param ptr Pointer to data to pass to each callback
+ *
+ * @return -1 on error, 0 if hash value not found, and 1 if value was found.
+ */
+int8_t
+tsk_hdb_lookup_raw(TSK_HDB_INFO * hdb_info, uint8_t * hash, uint8_t len,
+                   TSK_HDB_FLAG_ENUM flags,
+                   TSK_HDB_LOOKUP_FN action, void *ptr)
+{
+    uint8_t htype;
+
+    /* Sanity checks on the hash input */
+    if (len/2 == TSK_HDB_HTYPE_MD5_LEN) {
+        htype = TSK_HDB_HTYPE_MD5_ID;
+    }
+    else if (len/2 == TSK_HDB_HTYPE_SHA1_LEN) {
+        htype = TSK_HDB_HTYPE_SHA1_ID;
+    }
+    else {
+        tsk_error_reset();
+        tsk_error_set_errno(TSK_ERR_HDB_ARG);
+        tsk_error_set_errstr(
+                "hdb_lookup_raw: Invalid hash length: %s", hash);
+        return -1;
+    }
+
+    if (hdb_setupindex(hdb_info, htype, 0)) {
+        return -1;
+    }
+
+	return hdb_info->idx_info->lookup_raw(hdb_info, hash, len, flags, action, ptr);
+}
diff --git a/tsk/hashdb/tsk_hashdb.h b/tsk/hashdb/tsk_hashdb.h
index 66f01a47f80dd509b9f25837d203990f4e34be8b..e3059edd117909d9ed6492a7d3974900d2e00756 100644
--- a/tsk/hashdb/tsk_hashdb.h
+++ b/tsk/hashdb/tsk_hashdb.h
@@ -17,6 +17,8 @@
  * \defgroup hashdblib_cpp C++ Hash Database Classes
 */
 
+#include "tsk/auto/sqlite3.h"
+
 #ifndef _TSK_HDB_H
 #define _TSK_HDB_H
 
@@ -43,12 +45,15 @@ extern "C" {
         TSK_HDB_HTYPE_INVALID_ID = 0,   ///< Invalid algorithm signals error.
         TSK_HDB_HTYPE_MD5_ID = 1,       ///< MD5 Algorithm
         TSK_HDB_HTYPE_SHA1_ID = 2,      ///< SHA1 Algorithm
+        TSK_HDB_HTYPE_SHA2_256_ID = 4,  ///< SHA2-256 (aka SHA-256) Algorithm
     };
     typedef enum TSK_HDB_HTYPE_ENUM TSK_HDB_HTYPE_ENUM;
 
 #define TSK_HDB_HTYPE_MD5_STR	"md5"   ///< String name for MD5 algorithm
 #define TSK_HDB_HTYPE_SHA1_STR	"sha1"  ///< String name for SHA1 algorithm
+#define TSK_HDB_HTYPE_SHA2_256_STR	"sha2_256"  ///< String name for SHA256 algorithm
 
+#define TSK_HDB_HTYPE_SHA2_256_LEN 64   ///< Length of SHA256 hash
 #define TSK_HDB_HTYPE_SHA1_LEN 40       ///< Length of SHA1 hash
 #define TSK_HDB_HTYPE_MD5_LEN 32        ///< Length of MD5 hash
 #define TSK_HDB_HTYPE_CRC32_LEN 8       ///< Length of CRC hash
@@ -59,16 +64,27 @@ extern "C" {
     */
 #define TSK_HDB_HTYPE_STR(x) \
     ( ((x) & TSK_HDB_HTYPE_MD5_ID) ? (TSK_HDB_HTYPE_MD5_STR) : ( \
-    ( ((x) & TSK_HDB_HTYPE_SHA1_ID) ? TSK_HDB_HTYPE_SHA1_STR : "") ) )
+    ( ((x) & TSK_HDB_HTYPE_SHA1_ID) ? (TSK_HDB_HTYPE_SHA1_STR) : ( \
+    ( ((x) & TSK_HDB_HTYPE_SHA2_256_ID) ? TSK_HDB_HTYPE_SHA2_256_STR : "") ) ) ) )
 
     /**
     * Return the length of a hash, given its ID
     */
 #define TSK_HDB_HTYPE_LEN(x) \
     ( ((x) & TSK_HDB_HTYPE_MD5_ID) ? (TSK_HDB_HTYPE_MD5_LEN) : ( \
-    ( ((x) & TSK_HDB_HTYPE_SHA1_ID) ? TSK_HDB_HTYPE_SHA1_LEN : 0) ) )
+    ( ((x) & TSK_HDB_HTYPE_SHA1_ID) ? (TSK_HDB_HTYPE_SHA1_LEN) : ( \
+    ( ((x) & TSK_HDB_HTYPE_SHA2_256_ID) ? TSK_HDB_HTYPE_SHA2_256_LEN : 0) ) ) ) )
+
 
 
+    /**
+    * Hash Index types
+    */
+    enum TSK_HDB_ITYPE_ENUM {
+        TSK_HDB_ITYPE_BINSRCH = 1,     ///< Original binary search text format
+        TSK_HDB_ITYPE_SQLITE_V1 = 2    ///< Sqlite database format
+    };
+    typedef enum TSK_HDB_ITYPE_ENUM TSK_HDB_ITYPE_ENUM;
 
     /**
     * Hash Database types
@@ -85,12 +101,12 @@ extern "C" {
 
 
     /* String versions of DB types */
-#define TSK_HDB_DBTYPE_NSRL_STR		        "nsrl"  ///< NSRL String name
-#define TSK_HDB_DBTYPE_NSRL_MD5_STR		"nsrl-md5"      ///< NSRL md5 string name
-#define TSK_HDB_DBTYPE_NSRL_SHA1_STR		"nsrl-sha1"     ///< NSRL SHA1 string name
-#define TSK_HDB_DBTYPE_MD5SUM_STR		"md5sum"        ///< md5sum db string n ame
-#define TSK_HDB_DBTYPE_HK_STR			"hk"    ///< hash keeper string name
-#define TSK_HDB_DBTYPE_ENCASE_STR			"encase"    ///< encase string name
+#define TSK_HDB_DBTYPE_NSRL_STR		        "nsrl"  ///< NSRL database 
+#define TSK_HDB_DBTYPE_NSRL_MD5_STR		"nsrl-md5"      ///< NSRL database with MD5 index
+#define TSK_HDB_DBTYPE_NSRL_SHA1_STR		"nsrl-sha1"     ///< NSRL database with SHA1 index
+#define TSK_HDB_DBTYPE_MD5SUM_STR		"md5sum"        ///< md5sum database
+#define TSK_HDB_DBTYPE_HK_STR			"hk"    ///< hash keeper index
+#define TSK_HDB_DBTYPE_ENCASE_STR			"encase"    ///< encase index
     /// List of supported data base types
 #define TSK_HDB_DBTYPE_SUPPORT_STR		"nsrl-md5, nsrl-sha1, md5sum, encase, hk"
 
@@ -98,12 +114,63 @@ extern "C" {
 
 
     typedef struct TSK_HDB_INFO TSK_HDB_INFO;
+    typedef struct TSK_IDX_INFO TSK_IDX_INFO;
 
     typedef TSK_WALK_RET_ENUM(*TSK_HDB_LOOKUP_FN) (TSK_HDB_INFO *,
         const char *hash,
         const char *name,
         void *);
 
+    /**
+     * Holds information about a sqlite index
+     */
+    struct TSK_IDX_SQLITE_V1 {
+		sqlite3 *hIdx_sqlite;	///< Sqlite DB if index is using sqlite schema
+    };
+    typedef struct TSK_IDX_SQLITE_V1 TSK_IDX_SQLITE_V1;
+
+    /**
+     * Holds information about a plain text / binary search index
+     */
+    struct TSK_IDX_BINSRCH {
+        FILE *hIdx;             ///< File handle to index (only open during lookups)
+        FILE *hIdxTmp;          ///< File handle to temp (unsorted) index file (only open during index creation)
+        TSK_TCHAR *uns_fname;   ///< Name of unsorted index file
+
+        TSK_OFF_T idx_size;     ///< Size of index file
+        uint16_t idx_off;       ///< Offset in index file to first index entry
+        size_t idx_llen;        ///< Length of each line in index
+        char *idx_lbuf;         ///< Buffer to hold a line from the index  (r/w shared - lock) 
+    };
+    typedef struct TSK_IDX_BINSRCH TSK_IDX_BINSRCH;
+
+    /**
+     * Holds information about a hash index. Created by idx_open.
+     */
+    struct TSK_IDX_INFO {
+        TSK_HDB_ITYPE_ENUM index_type;   ///< Type of index
+        TSK_TCHAR *idx_fname;   ///< Name of index file
+        uint8_t   updateable;   ///< Allow new entries to be added?
+
+        union {
+            TSK_IDX_SQLITE_V1 * idx_sqlite_v1;
+            TSK_IDX_BINSRCH * idx_binsrch;
+        }idx_struct;
+
+        uint8_t(*open) (TSK_HDB_INFO *, TSK_IDX_INFO *, uint8_t);
+        uint8_t(*initialize) (TSK_HDB_INFO *, TSK_TCHAR *);
+        uint8_t(*addentry) (TSK_HDB_INFO *, char *, TSK_OFF_T);
+        uint8_t(*addentry_bin) (TSK_HDB_INFO *, unsigned char *, int, TSK_OFF_T);
+        uint8_t(*finalize) (TSK_HDB_INFO *);
+        int8_t(*lookup_str) (TSK_HDB_INFO *, const char *, TSK_HDB_FLAG_ENUM,
+                TSK_HDB_LOOKUP_FN, void *);
+        int8_t(*lookup_raw) (TSK_HDB_INFO *, uint8_t *, uint8_t,
+                TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
+        int8_t(*get_properties) (TSK_HDB_INFO *);        
+        void(*close) (TSK_IDX_INFO *);
+
+    };
+
     /**
     * Holds information about an open hash database. Created by 
     * hdb_open and used for making an index and looking up values.
@@ -114,25 +181,16 @@ extern "C" {
 
         TSK_TCHAR *db_fname;    ///< Name of the database file
 
-        TSK_TCHAR *uns_fname;   ///< Name of unsorted index file
-
         FILE *hDb;              ///< File handle to database (always open)
-        FILE *hIdxTmp;          ///< File handle to temp (unsorted) index file (only open during index creation)
-        FILE *hIdx;             ///< File handle to index (only open during lookups) 
-
-        TSK_OFF_T idx_size;     ///< Size of index file
-        uint16_t idx_off;       ///< Offset in index file to first index entry
-        size_t idx_llen;        ///< Length of each line in index
-
-        /* lock protects idx_lbuf and lazy loading of hIdx */
-        tsk_lock_t lock;        ///< Lock for lazy loading and idx_lbuf
-        char *idx_lbuf;         ///< Buffer to hold a line from the index  (r/w shared - lock) 
-        TSK_TCHAR *idx_fname;   ///< Name of index file
 
         TSK_HDB_HTYPE_ENUM hash_type;   ///< Type of hash used in index
         uint16_t hash_len;      ///< Length of hash
 
         TSK_HDB_DBTYPE_ENUM db_type;    ///< Type of database
+        TSK_IDX_INFO * idx_info;  ///< The index for the hdb info
+
+        /* lock protects idx_lbuf and lazy loading of idx_info */
+        tsk_lock_t lock;        ///< Lock for lazy loading and idx_lbuf
 
         uint8_t(*getentry) (TSK_HDB_INFO *, const char *, TSK_OFF_T, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);    ///< \internal Database-specific function to find entry at a given offset
         uint8_t(*makeindex) (TSK_HDB_INFO *, TSK_TCHAR *);     ///< \internal Database-specific function to make index
@@ -143,25 +201,36 @@ extern "C" {
     */
     enum TSK_HDB_OPEN_ENUM {
         TSK_HDB_OPEN_NONE = 0,  ///< No special flags
-        TSK_HDB_OPEN_IDXONLY = (0x1 << 0)       ///< Open only the index -- do not look for the original DB
+        TSK_HDB_OPEN_IDXONLY = (0x1 << 0),       ///< Open only the index -- do not look for the original DB
+        TSK_HDB_OPEN_TRY = (0x1 << 1)           ///< Try to open original db. If that fails, try TSK_HDB_OPEN_IDXONLY.
     };
     typedef enum TSK_HDB_OPEN_ENUM TSK_HDB_OPEN_ENUM;
 
-
+    /* Functions */
     extern TSK_HDB_INFO *tsk_hdb_open(TSK_TCHAR * db_file,
         TSK_HDB_OPEN_ENUM flags);
+
     extern void tsk_hdb_close(TSK_HDB_INFO * hdb);
 
     extern uint8_t tsk_hdb_hasindex(TSK_HDB_INFO *, uint8_t htype);
+
+    extern uint8_t tsk_hdb_is_idxonly(TSK_HDB_INFO *);
+
     extern uint8_t tsk_hdb_makeindex(TSK_HDB_INFO *, TSK_TCHAR *);
 
+    extern TSK_HDB_INFO * tsk_hdb_new(TSK_TCHAR * db_file);
+
+    extern int8_t tsk_hdb_add_str(TSK_HDB_INFO * hdb_info, 
+                        const TSK_TCHAR * filename, 
+                        const char * md5, 
+                        const char * sha1, 
+                        const char * sha256);
 
-    /* Functions */
     extern int8_t tsk_hdb_lookup_str(TSK_HDB_INFO *, const char *,
         TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN,
         void *);
 
-    extern int8_t tsk_hdb_lookup_raw(TSK_HDB_INFO *, uint8_t * hash,
+    extern int8_t tsk_hdb_lookup_raw(TSK_HDB_INFO * hdb_info, uint8_t * hash,
         uint8_t len, TSK_HDB_FLAG_ENUM,
         TSK_HDB_LOOKUP_FN, void *);
 
diff --git a/tsk/hashdb/tsk_hashdb_i.h b/tsk/hashdb/tsk_hashdb_i.h
index b6066f03d27be1175c9ece9d801350f5d9ff0d56..fc838eb80b39b7a41ad7a1cabccadea831153148 100644
--- a/tsk/hashdb/tsk_hashdb_i.h
+++ b/tsk/hashdb/tsk_hashdb_i.h
@@ -57,7 +57,22 @@ extern "C" {
 #define TSK_HDB_IDX_HEAD_TYPE_STR	"00000000000000000000000000000000000000000"
 #define TSK_HDB_IDX_HEAD_NAME_STR	"00000000000000000000000000000000000000001"
 
+/**
+ * Properties for the sqlite hash database index
+ */
+#define IDX_SCHEMA_VER "Index Schema Version"
+#define IDX_VERSION_NUM "1"
+#define IDX_HASHSET_NAME "Hashset Name"
+#define IDX_HASHSET_UPDATEABLE "Updateable"
+#define IDX_BINSRCH_HEADER "0000000000000000"
+#define IDX_SQLITE_V1_HEADER "SQLite format 3"
+// Warning: changing the hash storage type changes the Db schema
+#define IDX_SQLITE_STORE_TEXT
 
+    extern uint8_t
+        hdb_setupindex(TSK_HDB_INFO * hdb_info, uint8_t htype, uint8_t create);
+
+    extern void tsk_idx_close(TSK_IDX_INFO * idx_info);
 
     extern uint8_t tsk_hdb_idxinitialize(TSK_HDB_INFO *,
                                          TSK_TCHAR * dbname);
@@ -105,6 +120,34 @@ extern "C" {
     extern uint8_t idxonly_getentry(TSK_HDB_INFO *, const char *,
                                     TSK_OFF_T, TSK_HDB_FLAG_ENUM,
                                     TSK_HDB_LOOKUP_FN, void *);
+
+    extern uint8_t binsrch_open(TSK_HDB_INFO *, TSK_IDX_INFO *, uint8_t);
+    extern void binsrch_close(TSK_IDX_INFO *);
+    extern uint8_t binsrch_initialize(TSK_HDB_INFO *, TSK_TCHAR *);
+    extern uint8_t binsrch_addentry(TSK_HDB_INFO *, char *, TSK_OFF_T);
+    extern uint8_t binsrch_addentry_bin(TSK_HDB_INFO *,
+            unsigned char *, int, TSK_OFF_T);
+    extern uint8_t binsrch_finalize(TSK_HDB_INFO *);
+    extern int8_t binsrch_lookup_str(TSK_HDB_INFO *, const char *,
+                                    TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
+    extern int8_t binsrch_lookup_raw(TSK_HDB_INFO *, uint8_t *, uint8_t,
+                                    TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
+    extern int8_t binsrch_get_properties(TSK_HDB_INFO * hdb_info);
+
+    extern uint8_t sqlite_v1_open(TSK_HDB_INFO *, TSK_IDX_INFO *, uint8_t);
+    extern void sqlite_v1_close(TSK_IDX_INFO *);
+    extern uint8_t sqlite_v1_initialize(TSK_HDB_INFO *, TSK_TCHAR *);
+    extern uint8_t sqlite_v1_begin(TSK_HDB_INFO *);
+    extern uint8_t sqlite_v1_addentry(TSK_HDB_INFO *, char *, TSK_OFF_T);
+    extern uint8_t sqlite_v1_addentry_bin(TSK_HDB_INFO *,
+            unsigned char *, int, TSK_OFF_T);
+    extern uint8_t sqlite_v1_finalize(TSK_HDB_INFO *);
+    extern int8_t sqlite_v1_lookup_str(TSK_HDB_INFO *, const char *,
+                                    TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
+    extern int8_t sqlite_v1_lookup_raw(TSK_HDB_INFO *, uint8_t *, uint8_t,
+                                    TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *);
+    extern int8_t sqlite_v1_get_properties(TSK_HDB_INFO * hdb_info);
+    extern uint8_t sqlite3_test(FILE *);
 #ifdef __cplusplus
 }
 #endif
diff --git a/win32/libtsk/libtsk.vcxproj b/win32/libtsk/libtsk.vcxproj
index cb68eefb5219718f2c80ad4ae426e2570b253417..8daa257d6473f02ba90d66307d34b43c37a33114 100755
--- a/win32/libtsk/libtsk.vcxproj
+++ b/win32/libtsk/libtsk.vcxproj
@@ -273,12 +273,16 @@ copy "$(LIBEWF_HOME)\msvscpp\x64\release\zlib.dll" "$(OutDir)"
     <ClCompile Include="..\..\tsk\base\tsk_unicode.c" />
     <ClCompile Include="..\..\tsk\base\tsk_version.c" />
     <ClCompile Include="..\..\tsk\base\XGetopt.c" />
-    <ClCompile Include="..\..\tsk\hashdb\encase_index.c" />
-    <ClCompile Include="..\..\tsk\hashdb\hk_index.c" />
-    <ClCompile Include="..\..\tsk\hashdb\idxonly_index.c" />
-    <ClCompile Include="..\..\tsk\hashdb\md5sum_index.c" />
-    <ClCompile Include="..\..\tsk\hashdb\nsrl_index.c" />
-    <ClCompile Include="..\..\tsk\hashdb\tm_lookup.c" />
+    <ClCompile Include="..\..\tsk\hashdb\encase.c" />
+    <ClCompile Include="..\..\tsk\hashdb\hashkeeper.c" />
+    <ClCompile Include="..\..\tsk\hashdb\idxonly.c" />
+    <ClCompile Include="..\..\tsk\hashdb\md5sum.c" />
+    <ClCompile Include="..\..\tsk\hashdb\nsrl.c" />
+    <ClCompile Include="..\..\tsk\hashdb\hdb_open.cpp" />
+    <ClCompile Include="..\..\tsk\hashdb\hdb_index.cpp" />
+    <ClCompile Include="..\..\tsk\hashdb\sqlite_index.cpp" />
+    <ClCompile Include="..\..\tsk\hashdb\binsrch_index.c" />
+    <ClCompile Include="..\..\tsk\hashdb\tm_lookup.cpp" />
     <ClCompile Include="..\..\tsk\img\aff.c" />
     <ClCompile Include="..\..\tsk\img\ewf.c" />
     <ClCompile Include="..\..\tsk\img\img_io.c" />
@@ -323,4 +327,4 @@ copy "$(LIBEWF_HOME)\msvscpp\x64\release\zlib.dll" "$(OutDir)"
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/win32/libtsk/libtsk.vcxproj.filters b/win32/libtsk/libtsk.vcxproj.filters
index c64d1b2ea867bc4d6cdfb87547c007517ea6f2f0..247cfc9b145ed6f3648847cc121f6426d0ada3c3 100755
--- a/win32/libtsk/libtsk.vcxproj.filters
+++ b/win32/libtsk/libtsk.vcxproj.filters
@@ -222,24 +222,6 @@
     <ClCompile Include="..\..\tsk\base\XGetopt.c">
       <Filter>base</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\tsk\hashdb\encase_index.c">
-      <Filter>hash</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\tsk\hashdb\hk_index.c">
-      <Filter>hash</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\tsk\hashdb\idxonly_index.c">
-      <Filter>hash</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\tsk\hashdb\md5sum_index.c">
-      <Filter>hash</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\tsk\hashdb\nsrl_index.c">
-      <Filter>hash</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\tsk\hashdb\tm_lookup.c">
-      <Filter>hash</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\tsk\img\aff.c">
       <Filter>img</Filter>
     </ClCompile>
@@ -271,6 +253,36 @@
       <Filter>fs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\tsk\fs\yaffs.cpp" />
+    <ClCompile Include="..\..\tsk\hashdb\tm_lookup.cpp">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\sqlite_index.cpp">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\binsrch_index.c">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\hashkeeper.c">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\encase.c">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\hdb_index.cpp">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\hdb_open.cpp">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\idxonly.c">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\md5sum.c">
+      <Filter>hash</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tsk\hashdb\nsrl.c">
+      <Filter>hash</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\tsk\vs\tsk_bsd.h">