/* * 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: */ #include #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; }