summaryrefslogtreecommitdiff
path: root/win32/common/droplet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'win32/common/droplet.cpp')
-rw-r--r--win32/common/droplet.cpp226
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;
+}
+