From 7bcaf483ee720cbfbae40ac9df7af6eb28867f91 Mon Sep 17 00:00:00 2001
From: AraHaan <seandhunt_7@yahoo.com>
Date: Mon, 16 Oct 2017 15:35:01 -0400
Subject: [PATCH] Implement Binary Search from py2exe.

py2exe uses v0.0.3 modified to add binary search to load dll's (like pythonxx.dll) with a ton of exports.
---
 MemoryModule.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/MemoryModule.c b/MemoryModule.c
index cf38388..de5e08b 100644
--- a/MemoryModule.c
+++ b/MemoryModule.c
@@ -22,6 +22,12 @@
  * Portions created by Joachim Bauch are Copyright (C) 2004-2015
  * Joachim Bauch. All Rights Reserved.
  *
+ *
+ * THeller: Added binary search in MemoryGetProcAddress function
+ * (#define USE_BINARY_SEARCH to enable it).  This gives a very large
+ * speedup for libraries that exports lots of functions.
+ *
+ * These portions are Copyright (C) 2013 Thomas Heller.
  */
 
 #include <windows.h>
@@ -56,6 +62,15 @@
 
 #include "MemoryModule.h"
 
+#ifdef USE_BINARY_SEARCH
+
+struct NAME_TABLE {
+    LPCSTR name;
+    WORD idx;
+};
+
+#endif
+
 typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
 typedef int (WINAPI *ExeEntryProc)(void);
 
@@ -72,6 +87,10 @@ typedef struct {
     CustomLoadLibraryFunc loadLibrary;
     CustomGetProcAddressFunc getProcAddress;
     CustomFreeLibraryFunc freeLibrary;
+#ifdef USE_BINARY_SEARCH
+    struct NAME_TABLE *name_table;
+    int numEntries;
+#endif
     void *userdata;
     ExeEntryProc exeEntry;
     DWORD pageSize;
@@ -613,6 +632,9 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,
     result->getProcAddress = getProcAddress;
     result->freeLibrary = freeLibrary;
     result->userdata = userdata;
+#ifdef USE_BINARY_SEARCH
+    result->name_table = NULL;
+#endif
     result->pageSize = sysInfo.dwPageSize;
 
     if (!CheckSize(size, old_header->OptionalHeader.SizeOfHeaders)) {
@@ -688,6 +710,18 @@ HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,
     return NULL;
 }
 
+#ifdef USE_BINARY_SEARCH
+int _compare(const struct NAME_TABLE *p1, const struct NAME_TABLE *p2)
+{
+    return _stricmp(p1->name, p2->name);
+}
+
+int _find(LPCSTR *name, const struct NAME_TABLE *p)
+{
+    return _stricmp(*name, p->name);
+}
+#endif
+
 FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name)
 {
     unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase;
@@ -707,6 +741,45 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name)
         return NULL;
     }
 
+#ifdef USE_BINARY_SEARCH
+
+    // build name table and sort it by names
+    if (((PMEMORYMODULE)module)->name_table == NULL) {
+	struct NAME_TABLE *entry = (struct NAME_TABLE*)malloc(exports->NumberOfNames
+							      * sizeof(struct NAME_TABLE));
+	((PMEMORYMODULE)module)->name_table = entry;
+	if (entry == NULL) {
+	    ((PMEMORYMODULE)module)->numEntries = 0;
+	    SetLastError(ERROR_OUTOFMEMORY);
+	    return NULL;
+	}
+	((PMEMORYMODULE)module)->numEntries = exports->NumberOfNames;
+
+	nameRef = (DWORD *) (codeBase + exports->AddressOfNames);
+	ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals);
+	for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++) {
+	    entry->name = (const char *) (codeBase + (*nameRef));
+	    entry->idx = *ordinal;
+	    entry++;
+	}
+	entry = ((PMEMORYMODULE)module)->name_table;
+	qsort(entry, exports->NumberOfNames, sizeof(struct NAME_TABLE), _compare);
+    }
+
+    if (!IS_INTRESOURCE(name)) {
+	// search function name in list of exported names with binary search
+	if (((PMEMORYMODULE)module)->name_table) {
+	    struct NAME_TABLE *found;
+	    found = bsearch(&name,
+			    ((PMEMORYMODULE)module)->name_table,
+			    exports->NumberOfNames,
+			    sizeof(struct NAME_TABLE), _find);
+	    if (found)
+		idx = found->idx;
+	}
+    } else
+	idx = (int)name;
+#else
     if (HIWORD(name) == 0) {
         // load function by ordinal value
         if (LOWORD(name) < exports->Base) {
@@ -728,6 +801,7 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE module, LPCSTR name)
                 break;
             }
         }
+#endif    
 
         if (!found) {
             // exported symbol not found
@@ -759,6 +833,12 @@ void MemoryFreeLibrary(HMEMORYMODULE mod)
         (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0);
     }
 
+#ifdef USE_BINARY_SEARCH
+	if (module->name_table != NULL) {
+	    free(module->name_table);
+	}
+#endif
+
     if (module->modules != NULL) {
         // free previously opened libraries
         int i;