diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 2a3db9b16..c090b8a9d 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -1908,6 +1908,14 @@ and are only documented here for completeness: The table used by ``dfhack.run_script()`` to give every script its own global environment, persistent between calls to the script. +* ``dfhack.internal.getPE()`` + + Returns the PE timestamp of the DF executable (only on Windows) + +* ``dfhack.internal.getMD5()`` + + Returns the MD5 of the DF executable (only on OS X and Linux) + * ``dfhack.internal.getAddress(name)`` Returns the global address ``name``, or *nil*. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index a3a9eb070..ba9591719 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2304,6 +2304,24 @@ static const LuaWrapper::FunctionReg dfhack_internal_module[] = { { NULL, NULL } }; +static int internal_getmd5(lua_State *L) +{ + auto p = Core::getInstance().p; + if (p->getDescriptor()->getOS() == OS_WINDOWS) + luaL_error(L, "process MD5 not available on Windows"); + lua_pushstring(L, p->getMD5().c_str()); + return 1; +} + +static int internal_getPE(lua_State *L) +{ + auto p = Core::getInstance().p; + if (p->getDescriptor()->getOS() != OS_WINDOWS) + luaL_error(L, "process PE timestamp not available on non-Windows"); + lua_pushinteger(L, p->getPE()); + return 1; +} + static int internal_getAddress(lua_State *L) { const char *name = luaL_checkstring(L, 1); @@ -2683,6 +2701,8 @@ static int internal_findScript(lua_State *L) } static const luaL_Reg dfhack_internal_funcs[] = { + { "getPE", internal_getPE }, + { "getMD5", internal_getmd5 }, { "getAddress", internal_getAddress }, { "setAddress", internal_setAddress }, { "getVTable", internal_getVTable }, diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index a485e196d..6f159e5fe 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -60,15 +60,16 @@ Process::Process(VersionInfoFactory * known_versions) identified = false; my_descriptor = 0; + my_pe = 0; md5wrapper md5; uint32_t length; uint8_t first_kb [1024]; memset(first_kb, 0, sizeof(first_kb)); // get hash of the running DF process - string hash = md5.getHashFromFile(real_path, length, (char *) first_kb); + my_md5 = md5.getHashFromFile(real_path, length, (char *) first_kb); // create linux process, add it to the vector - VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash); + VersionInfo * vinfo = known_versions->getVersionInfoByMD5(my_md5); if(vinfo) { my_descriptor = new VersionInfo(*vinfo); @@ -79,7 +80,7 @@ Process::Process(VersionInfoFactory * known_versions) char * wd = getcwd(NULL, 0); cerr << "Unable to retrieve version information.\n"; cerr << "File: " << real_path << endl; - cerr << "MD5: " << hash << endl; + cerr << "MD5: " << my_md5 << endl; cerr << "working dir: " << wd << endl; cerr << "length:" << length << endl; cerr << "1KB hexdump follows:" << endl; diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index 1b430e5a8..e4c647f7f 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -55,15 +55,16 @@ Process::Process(VersionInfoFactory * known_versions) identified = false; my_descriptor = 0; + my_pe = 0; md5wrapper md5; uint32_t length; uint8_t first_kb [1024]; memset(first_kb, 0, sizeof(first_kb)); // get hash of the running DF process - string hash = md5.getHashFromFile(exe_link_name, length, (char *) first_kb); + my_md5 = md5.getHashFromFile(exe_link_name, length, (char *) first_kb); // create linux process, add it to the vector - VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash); + VersionInfo * vinfo = known_versions->getVersionInfoByMD5(my_md5); if(vinfo) { my_descriptor = new VersionInfo(*vinfo); @@ -74,7 +75,7 @@ Process::Process(VersionInfoFactory * known_versions) char * wd = getcwd(NULL, 0); cerr << "Unable to retrieve version information.\n"; cerr << "File: " << exe_link_name << endl; - cerr << "MD5: " << hash << endl; + cerr << "MD5: " << my_md5 << endl; cerr << "working dir: " << wd << endl; cerr << "length:" << length << endl; cerr << "1KB hexdump follows:" << endl; diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index c923441e3..5474d7cfb 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -95,7 +95,8 @@ Process::Process(VersionInfoFactory * factory) { return; } - VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp); + my_pe = d->pe_header.FileHeader.TimeDateStamp; + VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(my_pe); if(vinfo) { identified = true; @@ -105,8 +106,7 @@ Process::Process(VersionInfoFactory * factory) } else { - fprintf(stderr, "Unable to retrieve version information.\nPE timestamp: 0x%x\n", - d->pe_header.FileHeader.TimeDateStamp); + fprintf(stderr, "Unable to retrieve version information.\nPE timestamp: 0x%x\n", my_pe); fflush(stderr); } } diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h index 80844ae5f..36100b400 100644 --- a/library/include/MemAccess.h +++ b/library/include/MemAccess.h @@ -287,6 +287,9 @@ namespace DFHack EXEC = 4 }; + uint32_t getPE() { return my_pe; } + std::string getMD5() { return my_md5; } + private: VersionInfo * my_descriptor; PlatformSpecific *d; @@ -294,6 +297,8 @@ namespace DFHack uint32_t my_pid; uint32_t base; std::map classNameCache; + uint32_t my_pe; + std::string my_md5; }; class DFHACK_EXPORT ClassNameCheck diff --git a/scripts/devel/export-dt-ini.lua b/scripts/devel/export-dt-ini.lua index 1d99b2d55..c75acd1dd 100644 --- a/scripts/devel/export-dt-ini.lua +++ b/scripts/devel/export-dt-ini.lua @@ -421,8 +421,13 @@ address('uniform_indiv_choice',df.squad_uniform_spec,'indiv_choice') local out = io.open('therapist.ini', 'w') out:write('[info]\n') --- TODO: add an api function to retrieve the checksum -out:write('checksum=<>\n') +if dfhack.getOSType() == 'windows' and dfhack.internal.getPE then + out:write(('checksum=0x%x\n'):format(dfhack.internal.getPE())) +elseif dfhack.getOSType() ~= 'windows' and dfhack.internal.getMD5 then + out:write(('checksum=0x%s\n'):format(dfhack.internal.getMD5():sub(1, 8))) +else + out:write('checksum=<>\n') +end out:write('version_name='..dfhack.getDFVersion()..'\n') out:write('complete='..(complete and 'true' or 'false')..'\n')