diff options
Diffstat (limited to 'win32/common/droplet.cpp')
-rw-r--r-- | win32/common/droplet.cpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/win32/common/droplet.cpp b/win32/common/droplet.cpp new file mode 100644 index 0000000..e796f49 --- /dev/null +++ b/win32/common/droplet.cpp @@ -0,0 +1,226 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +#include <stdafx.h> +#include "lib/rep.h" +#include "common/binfile.h" +#include "common/repfile.h" +#include "Droplet.h" + +// (Con|De)struction: -------------------------------------------- + +Droplet::Droplet() +{ + m_keepBackups = false; + memset(&m_ctx, 0, sizeof(m_ctx)); +} + +Droplet::~Droplet() +{ + repFree(&m_ctx); +} + + +// All error handling jumps to 'cleanup' where wrapping up loose +// ends is done +#define RETURN(v) { ret = v; goto cleanup; } + + +// save: --------------------------------------------------- +// Saves a droplet to a file. The file must already exist +// and must be an executable + +bool Droplet::save(LPCTSTR fileName) +{ + HANDLE update = NULL; + void* data = NULL; + BFILE h = NULL; + bool ret = true; + + { + if(!m_ctx.script.ops) + RETURN(false); + + // Make the rep binfile + bfval val; + BFILE h = bfStartMem(NULL, 0, BF_REALLOC); + if(!h) RETURN(false); + + // Write out the headers + repfWriteHeader(h); + + // Write to it now + if(m_ctx.block != 0) + bfWriteInt(h, REPVAL_BUFSIZE, m_ctx.block); + + bfWriteInt(h, DROPVAL_BACKUPS, m_keepBackups ? 1 : 0); + + // Write the script out + val.id = REPVAL_SCRIPT; + val.len = m_ctx.script.len; + val.type = BINTYPE_DATA; + bfWriteValue(h, &val, m_ctx.script.ops); + + if(!m_title.empty()) + bfWriteString(h, DROPVAL_TITLE, m_title.c_str()); + + // Done + bfWriteEnd(h); + if(bfError(h)) RETURN(false); + + size_t len = bfCount(h); + data = bfInternal(h); + bfClose(h); + h = NULL; + + // Now actually modify the EXE + update = BeginUpdateResource(fileName, FALSE); + if(!update) RETURN(false); + + if(!UpdateResource(update, DROP_RESOURCE_TYPE, DROP_RESOURCE_ID, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), data, len) + || !EndUpdateResource(update, FALSE)) + RETURN(false); + + update = NULL; + } + +cleanup: + while(data) + { + free(data); + + if(h == NULL) + break; + + data = bfInternal(h); + bfClose(h); + h = NULL; + } + + if(update) + EndUpdateResource(update, TRUE); + + return true; +} + + +// load: --------------------------------------------------------------- +// Load a droplet from a file + +bool Droplet::load(LPCTSTR fileName) +{ + HMODULE module = LoadLibrary(fileName); + if(!module) + return false; + + bool ret = load(GetModuleHandle(fileName)); + + FreeLibrary(module); + + return ret; +} + + +// load: --------------------------------------------------------------- +// Load a droplet from a loaded module + +bool Droplet::load(HMODULE module) +{ + bool ret = true; + BFILE h = NULL; + + { + // In case we're called twice + repFree(&m_ctx); + + // Load the resource + HRSRC hRsrc = FindResourceEx(module, DROP_RESOURCE_TYPE, DROP_RESOURCE_ID, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); + if(!hRsrc) RETURN(false); + + HGLOBAL hGlobal = LoadResource(module, hRsrc); + if(!hGlobal) RETURN(false); + + void* data = LockResource(hGlobal); + if(!data) RETURN(false); + + ::SetLastError(0); + + // And now read it + h = bfStartMem(data, SizeofResource(module, hRsrc), 0); + if(!h) RETURN(false); + + // Check the format + if(!repfReadHeader(h)) + RETURN(false); + + bfval val; + + while(bfReadValueInfo(h, &val)) + { + switch(val.id) + { + case REPVAL_BUFSIZE: + bfReadValueData(h, &val, &(m_ctx.block)); + continue; + + case DROPVAL_BACKUPS: + { + long value; + bfReadValueData(h, &val, &value); + m_keepBackups = value == 0 ? false : true; + } + continue; + + case REPVAL_SCRIPT: + { + // Script must have some length + if(val.len == 0) + RETURN(false); + + m_ctx.script.ops = (byte*)malloc(val.len); + if(!m_ctx.script.ops) + RETURN(false); + + bfReadValueData(h, &val, m_ctx.script.ops); + m_ctx.script.len = val.len; + } + continue; + + case DROPVAL_TITLE: + { + bfReadValueData(h, &val, m_title.get_buffer(val.len)); + m_title.release_buffer(); + } + continue; + + } + + bfSkipValueData(h, &val); + } + } + +cleanup: + if(h) + bfClose(h); + + return ret; +} + |