aibika 1.3.12

Sign up to get free protection for your applications and to get access to all the features.
data/src/stub.c ADDED
@@ -0,0 +1,703 @@
1
+ /*
2
+ Single Executable Bundle Stub
3
+
4
+ This stub reads itself for embedded instructions to create directory
5
+ and files in a temporary directory, launching a program.
6
+ */
7
+
8
+ #include <windows.h>
9
+ #include <string.h>
10
+ #include <tchar.h>
11
+ #include <stdio.h>
12
+
13
+ const BYTE Signature[] = { 0x41, 0xb6, 0xba, 0x4e };
14
+
15
+ #define OP_END 0
16
+ #define OP_CREATE_DIRECTORY 1
17
+ #define OP_CREATE_FILE 2
18
+ #define OP_CREATE_PROCESS 3
19
+ #define OP_DECOMPRESS_LZMA 4
20
+ #define OP_SETENV 5
21
+ #define OP_POST_CREATE_PROCRESS 6
22
+ #define OP_ENABLE_DEBUG_MODE 7
23
+ #define OP_CREATE_INST_DIRECTORY 8
24
+ #define OP_MAX 9
25
+
26
+ BOOL ProcessImage(LPVOID p, DWORD size);
27
+ BOOL ProcessOpcodes(LPVOID* p);
28
+ void CreateAndWaitForProcess(LPTSTR ApplicationName, LPTSTR CommandLine);
29
+
30
+ BOOL OpEnd(LPVOID* p);
31
+ BOOL OpCreateFile(LPVOID* p);
32
+ BOOL OpCreateDirectory(LPVOID* p);
33
+ BOOL OpCreateProcess(LPVOID* p);
34
+ BOOL OpDecompressLzma(LPVOID* p);
35
+ BOOL OpSetEnv(LPVOID* p);
36
+ BOOL OpPostCreateProcess(LPVOID* p);
37
+ BOOL OpEnableDebugMode(LPVOID* p);
38
+ BOOL OpCreateInstDirectory(LPVOID* p);
39
+
40
+ #if WITH_LZMA
41
+ #include <LzmaDec.h>
42
+ #endif
43
+
44
+ typedef BOOL (*POpcodeHandler)(LPVOID*);
45
+
46
+ LPTSTR PostCreateProcess_ApplicationName = NULL;
47
+ LPTSTR PostCreateProcess_CommandLine = NULL;
48
+
49
+ DWORD ExitStatus = 0;
50
+ BOOL ExitCondition = FALSE;
51
+ BOOL DebugModeEnabled = FALSE;
52
+ BOOL DeleteInstDirEnabled = FALSE;
53
+ BOOL ChdirBeforeRunEnabled = TRUE;
54
+ TCHAR ImageFileName[MAX_PATH];
55
+
56
+ #if _CONSOLE
57
+ #define FATAL(...) { fprintf(stderr, "FATAL ERROR: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
58
+ #else
59
+ #define FATAL(...) { \
60
+ TCHAR TextBuffer[1024]; \
61
+ _sntprintf(TextBuffer, 1024, __VA_ARGS__); \
62
+ MessageBox(NULL, TextBuffer, _T("AIBIKA"), MB_OK | MB_ICONWARNING); \
63
+ }
64
+ #endif
65
+
66
+ #if _CONSOLE
67
+ #define DEBUG(...) { if (DebugModeEnabled) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } }
68
+ #else
69
+ #define DEBUG(...)
70
+ #endif
71
+
72
+ POpcodeHandler OpcodeHandlers[OP_MAX] =
73
+ {
74
+ &OpEnd,
75
+ &OpCreateDirectory,
76
+ &OpCreateFile,
77
+ &OpCreateProcess,
78
+ #if WITH_LZMA
79
+ &OpDecompressLzma,
80
+ #else
81
+ NULL,
82
+ #endif
83
+ &OpSetEnv,
84
+ &OpPostCreateProcess,
85
+ &OpEnableDebugMode,
86
+ &OpCreateInstDirectory,
87
+ };
88
+
89
+ TCHAR InstDir[MAX_PATH];
90
+
91
+ /** Decoder: Zero-terminated string */
92
+ LPTSTR GetString(LPVOID* p)
93
+ {
94
+ LPTSTR str = *p;
95
+ *p += lstrlen(str) + sizeof(TCHAR);
96
+ return str;
97
+ }
98
+
99
+ /** Decoder: 32 bit unsigned integer */
100
+ DWORD GetInteger(LPVOID* p)
101
+ {
102
+ DWORD dw = *(DWORD*)*p;
103
+ *p += 4;
104
+ return dw;
105
+ }
106
+
107
+ /**
108
+ Handler for console events.
109
+ */
110
+ BOOL WINAPI ConsoleHandleRoutine(DWORD dwCtrlType)
111
+ {
112
+ // Ignore all events. They will also be dispatched to the child procress (Ruby) which should
113
+ // exit quickly, allowing us to clean up.
114
+ return TRUE;
115
+ }
116
+
117
+ void FindExeDir(TCHAR* d)
118
+ {
119
+ strncpy(d, ImageFileName, MAX_PATH);
120
+ unsigned int i;
121
+ for (i = strlen(d)-1; i >= 0; --i)
122
+ {
123
+ if (i == 0 || d[i] == '\\')
124
+ {
125
+ d[i] = 0;
126
+ break;
127
+ }
128
+ }
129
+ }
130
+
131
+ BOOL DeleteRecursively(LPTSTR path)
132
+ {
133
+ TCHAR findPath[MAX_PATH];
134
+ DWORD pathLength;
135
+ WIN32_FIND_DATA findData;
136
+ HANDLE handle;
137
+ BOOL AnyFailed = FALSE;
138
+
139
+ lstrcpy(findPath, path);
140
+ pathLength = lstrlen(findPath);
141
+ if (pathLength > 1 && pathLength < MAX_PATH - 2) {
142
+ if (path[pathLength-1] == '\\')
143
+ lstrcat(findPath, "*");
144
+ else {
145
+ lstrcat(findPath, "\\*");
146
+ ++pathLength;
147
+ }
148
+ handle = FindFirstFile(findPath, &findData);
149
+ findPath[pathLength] = 0;
150
+ if (handle != INVALID_HANDLE_VALUE) {
151
+ do {
152
+ if (pathLength + lstrlen(findData.cFileName) < MAX_PATH) {
153
+ TCHAR subPath[MAX_PATH];
154
+ lstrcpy(subPath, findPath);
155
+ lstrcat(subPath, findData.cFileName);
156
+ if ((lstrcmp(findData.cFileName, ".") != 0) && (lstrcmp(findData.cFileName, "..") != 0)) {
157
+ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
158
+ if (!DeleteRecursively(subPath))
159
+ AnyFailed = TRUE;
160
+ } else {
161
+ if (!DeleteFile(subPath)) {
162
+ MoveFileEx(subPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
163
+ AnyFailed = TRUE;
164
+ }
165
+ }
166
+ }
167
+ } else {
168
+ AnyFailed = TRUE;
169
+ }
170
+ } while (FindNextFile(handle, &findData));
171
+ FindClose(handle);
172
+ }
173
+ } else {
174
+ AnyFailed = TRUE;
175
+ }
176
+ if (!RemoveDirectory(findPath)) {
177
+ MoveFileEx(findPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
178
+ AnyFailed = TRUE;
179
+ }
180
+ return AnyFailed;
181
+ }
182
+
183
+ void MarkForDeletion(LPTSTR path)
184
+ {
185
+ TCHAR marker[MAX_PATH];
186
+ lstrcpy(marker, path);
187
+ lstrcat(marker, ".aibika-delete-me");
188
+ HANDLE h = CreateFile(marker, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
189
+ CloseHandle(h);
190
+ }
191
+
192
+ void DeleteRecursivelyNowOrLater(LPTSTR path)
193
+ {
194
+ DEBUG("DeleteRecursivelyNowOrLater: %s", path);
195
+ if (!DeleteRecursively(path))
196
+ MarkForDeletion(path);
197
+ }
198
+
199
+ void DeleteOldFiles()
200
+ {
201
+ TCHAR path[MAX_PATH];
202
+ DWORD len = GetTempPath(MAX_PATH, path);
203
+ if (path[len-1] != '\\') {
204
+ lstrcat(path, "\\");
205
+ len += 1;
206
+ }
207
+ lstrcat(path, "*.aibika-delete-me");
208
+ WIN32_FIND_DATA findData;
209
+ HANDLE handle = FindFirstFile(path, &findData);
210
+ path[len] = 0;
211
+ if (handle == INVALID_HANDLE_VALUE)
212
+ return;
213
+ do {
214
+ TCHAR aibikaPath[MAX_PATH];
215
+ lstrcpy(aibikaPath, path);
216
+ lstrcat(aibikaPath, findData.cFileName);
217
+ DeleteFile(aibikaPath);
218
+ DWORD len = lstrlen(aibikaPath);
219
+ len -= lstrlen(".aibika-delete-me");
220
+ aibikaPath[len] = 0;
221
+ DeleteRecursivelyNowOrLater(aibikaPath);
222
+ } while (FindNextFile(handle, &findData));
223
+ FindClose(handle);
224
+ }
225
+
226
+ BOOL OpCreateInstDirectory(LPVOID* p)
227
+ {
228
+ DWORD DebugExtractMode = GetInteger(p);
229
+
230
+ DeleteInstDirEnabled = GetInteger(p);
231
+ ChdirBeforeRunEnabled = GetInteger(p);
232
+
233
+ /* Create an installation directory that will hold the extracted files */
234
+ TCHAR TempPath[MAX_PATH];
235
+ if (DebugExtractMode)
236
+ {
237
+ // In debug extraction mode, create the temp directory next to the exe
238
+ FindExeDir(TempPath);
239
+ if (strlen(TempPath) == 0)
240
+ {
241
+ FATAL("Unable to find directory containing exe");
242
+ return FALSE;
243
+ }
244
+ }
245
+ else
246
+ {
247
+ GetTempPath(MAX_PATH, TempPath);
248
+ }
249
+
250
+ UINT tempResult = GetTempFileName(TempPath, _T("aibikastub"), 0, InstDir);
251
+ if (tempResult == 0u)
252
+ {
253
+ FATAL("Failed to get temp file name.");
254
+ return FALSE;
255
+ }
256
+
257
+ DEBUG("Creating installation directory: '%s'", InstDir);
258
+
259
+ /* Attempt to delete the temp file created by GetTempFileName.
260
+ Ignore errors, i.e. if it doesn't exist. */
261
+ (void)DeleteFile(InstDir);
262
+
263
+ if (!CreateDirectory(InstDir, NULL))
264
+ {
265
+ FATAL("Failed to create installation directory.");
266
+ return FALSE;
267
+ }
268
+ return TRUE;
269
+ }
270
+
271
+ int CALLBACK _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
272
+ {
273
+ DeleteOldFiles();
274
+
275
+ /* Find name of image */
276
+ if (!GetModuleFileName(NULL, ImageFileName, MAX_PATH))
277
+ {
278
+ FATAL("Failed to get executable name (error %lu).", GetLastError());
279
+ return -1;
280
+ }
281
+
282
+
283
+ /* By default, assume the installation directory is wherever the EXE is */
284
+ FindExeDir(InstDir);
285
+
286
+ /* Set up environment */
287
+ SetEnvironmentVariable(_T("AIBIKA_EXECUTABLE"), ImageFileName);
288
+
289
+ SetConsoleCtrlHandler(&ConsoleHandleRoutine, TRUE);
290
+
291
+ /* Open the image (executable) */
292
+ HANDLE hImage = CreateFile(ImageFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
293
+ if (hImage == INVALID_HANDLE_VALUE)
294
+ {
295
+ FATAL("Failed to open executable (%s)", ImageFileName);
296
+ return -1;
297
+ }
298
+
299
+ /* Create a file mapping */
300
+ DWORD FileSize = GetFileSize(hImage, NULL);
301
+ HANDLE hMem = CreateFileMapping(hImage, NULL, PAGE_READONLY, 0, FileSize, NULL);
302
+ if (hMem == INVALID_HANDLE_VALUE)
303
+ {
304
+ FATAL("Failed to create file mapping (error %lu)", GetLastError());
305
+ CloseHandle(hImage);
306
+ return -1;
307
+ }
308
+
309
+ /* Map the image into memory */
310
+ LPVOID lpv = MapViewOfFile(hMem, FILE_MAP_READ, 0, 0, 0);
311
+ if (lpv == NULL)
312
+ {
313
+ FATAL("Failed to map view of executable into memory (error %lu).", GetLastError());
314
+ }
315
+ else
316
+ {
317
+ if (!ProcessImage(lpv, FileSize))
318
+ {
319
+ ExitStatus = -1;
320
+ }
321
+
322
+ if (!UnmapViewOfFile(lpv))
323
+ {
324
+ FATAL("Failed to unmap view of executable.");
325
+ }
326
+ }
327
+
328
+ if (!CloseHandle(hMem))
329
+ {
330
+ FATAL("Failed to close file mapping.");
331
+ }
332
+
333
+ if (!CloseHandle(hImage))
334
+ {
335
+ FATAL("Failed to close executable.");
336
+ }
337
+
338
+ if (ChdirBeforeRunEnabled)
339
+ {
340
+ DEBUG("Changing CWD to unpacked directory %s/src", InstDir);
341
+ SetCurrentDirectory(InstDir);
342
+ SetCurrentDirectory("./src");
343
+ }
344
+
345
+ if (PostCreateProcess_ApplicationName && PostCreateProcess_CommandLine)
346
+ {
347
+ DEBUG("**********");
348
+ DEBUG("Starting app in: %s", InstDir);
349
+ DEBUG("**********");
350
+ CreateAndWaitForProcess(PostCreateProcess_ApplicationName, PostCreateProcess_CommandLine);
351
+ }
352
+
353
+ if (DeleteInstDirEnabled)
354
+ {
355
+ DEBUG("Deleting temporary installation directory %s", InstDir);
356
+ TCHAR SystemDirectory[MAX_PATH];
357
+ if (GetSystemDirectory(SystemDirectory, MAX_PATH) > 0)
358
+ SetCurrentDirectory(SystemDirectory);
359
+ else
360
+ SetCurrentDirectory("C:\\");
361
+ DeleteRecursivelyNowOrLater(InstDir);
362
+ }
363
+
364
+ ExitProcess(ExitStatus);
365
+
366
+ /* Never gets here */
367
+ return 0;
368
+ }
369
+
370
+ /**
371
+ Process the image by checking the signature and locating the first
372
+ opcode.
373
+ */
374
+ BOOL ProcessImage(LPVOID ptr, DWORD size)
375
+ {
376
+ LPVOID pSig = ptr + size - 4;
377
+ if (memcmp(pSig, Signature, 4) == 0)
378
+ {
379
+ DEBUG("Good signature found.");
380
+ DWORD OpcodeOffset = *(DWORD*)(pSig - 4);
381
+ LPVOID pSeg = ptr + OpcodeOffset;
382
+ return ProcessOpcodes(&pSeg);
383
+ }
384
+ else
385
+ {
386
+ FATAL("Bad signature in executable.");
387
+ return FALSE;
388
+ }
389
+ }
390
+
391
+ /**
392
+ Process the opcodes in memory.
393
+ */
394
+ BOOL ProcessOpcodes(LPVOID* p)
395
+ {
396
+ while (!ExitCondition)
397
+ {
398
+ DWORD opcode = GetInteger(p);
399
+ if (opcode < OP_MAX)
400
+ {
401
+ if (!OpcodeHandlers[opcode](p))
402
+ {
403
+ return FALSE;
404
+ }
405
+ }
406
+ else
407
+ {
408
+ FATAL("Invalid opcode '%lu'.", opcode);
409
+ return FALSE;
410
+ }
411
+ }
412
+ return TRUE;
413
+ }
414
+
415
+ /**
416
+ Expands a specially formatted string, replacing | with the
417
+ temporary installation directory.
418
+ */
419
+ void ExpandPath(LPTSTR* out, LPTSTR str)
420
+ {
421
+ DWORD OutSize = lstrlen(str) + sizeof(TCHAR);
422
+ LPTSTR a = str;
423
+ while ((a = _tcschr(a, L'|')))
424
+ {
425
+ OutSize += lstrlen(InstDir) - sizeof(TCHAR);
426
+ a++;
427
+ }
428
+
429
+ *out = LocalAlloc(LMEM_FIXED, OutSize);
430
+
431
+ LPTSTR OutPtr = *out;
432
+ while ((a = _tcschr(str, L'|')))
433
+ {
434
+ int l = a - str;
435
+ if (l > 0)
436
+ {
437
+ memcpy(OutPtr, str, l);
438
+ OutPtr += l;
439
+ str += l;
440
+ }
441
+ str += sizeof(TCHAR);
442
+ lstrcpy(OutPtr, InstDir);
443
+ OutPtr += lstrlen(OutPtr);
444
+ }
445
+ lstrcpy(OutPtr, str);
446
+ }
447
+
448
+ /**
449
+ Finds the start of the first argument after the current one. Handles quoted arguments.
450
+ */
451
+ LPTSTR SkipArg(LPTSTR str)
452
+ {
453
+ if (*str == '"')
454
+ {
455
+ str++;
456
+ while (*str && *str != '"') { str++; }
457
+ if (*str == '"') { str++; }
458
+ }
459
+ else
460
+ {
461
+ while (*str && *str != ' ') { str++; }
462
+ }
463
+ while (*str && *str != ' ') { str++; }
464
+ return str;
465
+ }
466
+
467
+ /**
468
+ Create a file (OP_CREATE_FILE opcode handler)
469
+ */
470
+ BOOL OpCreateFile(LPVOID* p)
471
+ {
472
+ BOOL Result = TRUE;
473
+ LPTSTR FileName = GetString(p);
474
+ DWORD FileSize = GetInteger(p);
475
+ LPVOID Data = *p;
476
+ *p += FileSize;
477
+
478
+ TCHAR Fn[MAX_PATH];
479
+ lstrcpy(Fn, InstDir);
480
+ lstrcat(Fn, _T("\\"));
481
+ lstrcat(Fn, FileName);
482
+
483
+ DEBUG("CreateFile(%s, %lu)", Fn, FileSize);
484
+ HANDLE hFile = CreateFile(Fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
485
+ if (hFile != INVALID_HANDLE_VALUE)
486
+ {
487
+ DWORD BytesWritten;
488
+ if (!WriteFile(hFile, Data, FileSize, &BytesWritten, NULL))
489
+ {
490
+ FATAL("Write failure (%lu)", GetLastError());
491
+ Result = FALSE;
492
+ }
493
+ if (BytesWritten != FileSize)
494
+ {
495
+ FATAL("Write size failure");
496
+ Result = FALSE;
497
+ }
498
+ CloseHandle(hFile);
499
+ }
500
+ else
501
+ {
502
+ FATAL("Failed to create file '%s'", Fn);
503
+ Result = FALSE;
504
+ }
505
+
506
+ return Result;
507
+ }
508
+
509
+ /**
510
+ Create a directory (OP_CREATE_DIRECTORY opcode handler)
511
+ */
512
+ BOOL OpCreateDirectory(LPVOID* p)
513
+ {
514
+ LPTSTR DirectoryName = GetString(p);
515
+
516
+ TCHAR DirName[MAX_PATH];
517
+ lstrcpy(DirName, InstDir);
518
+ lstrcat(DirName, _T("\\"));
519
+ lstrcat(DirName, DirectoryName);
520
+
521
+ DEBUG("CreateDirectory(%s)", DirName);
522
+
523
+ if (!CreateDirectory(DirName, NULL))
524
+ {
525
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
526
+ {
527
+ DEBUG("Directory already exists");
528
+ }
529
+ else
530
+ {
531
+ FATAL("Failed to create directory '%s'.", DirName);
532
+ return FALSE;
533
+ }
534
+ }
535
+
536
+ return TRUE;
537
+ }
538
+
539
+ void GetCreateProcessInfo(LPVOID* p, LPTSTR* pApplicationName, LPTSTR* pCommandLine)
540
+ {
541
+ LPTSTR ImageName = GetString(p);
542
+ LPTSTR CmdLine = GetString(p);
543
+
544
+ ExpandPath(pApplicationName, ImageName);
545
+
546
+ LPTSTR ExpandedCommandLine;
547
+ ExpandPath(&ExpandedCommandLine, CmdLine);
548
+
549
+ LPTSTR MyCmdLine = GetCommandLine();
550
+ LPTSTR MyArgs = SkipArg(MyCmdLine);
551
+
552
+ *pCommandLine = LocalAlloc(LMEM_FIXED, lstrlen(ExpandedCommandLine) + sizeof(TCHAR) + lstrlen(MyArgs) + sizeof(TCHAR));
553
+ lstrcpy(*pCommandLine, ExpandedCommandLine);
554
+ lstrcat(*pCommandLine, _T(" "));
555
+ lstrcat(*pCommandLine, MyArgs);
556
+
557
+ LocalFree(ExpandedCommandLine);
558
+ }
559
+
560
+ /**
561
+ Create a new process and wait for it to complete (OP_CREATE_PROCESS
562
+ opcode handler)
563
+ */
564
+ BOOL OpCreateProcess(LPVOID* p)
565
+ {
566
+ LPTSTR ApplicationName;
567
+ LPTSTR CommandLine;
568
+ GetCreateProcessInfo(p, &ApplicationName, &CommandLine);
569
+ CreateAndWaitForProcess(ApplicationName, CommandLine);
570
+ LocalFree(ApplicationName);
571
+ LocalFree(CommandLine);
572
+ return TRUE;
573
+ }
574
+
575
+ void CreateAndWaitForProcess(LPTSTR ApplicationName, LPTSTR CommandLine)
576
+ {
577
+ PROCESS_INFORMATION ProcessInformation;
578
+ STARTUPINFO StartupInfo;
579
+ ZeroMemory(&StartupInfo, sizeof(StartupInfo));
580
+ StartupInfo.cb = sizeof(StartupInfo);
581
+ BOOL r = CreateProcess(ApplicationName, CommandLine, NULL, NULL,
582
+ TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation);
583
+
584
+ if (!r)
585
+ {
586
+ FATAL("Failed to create process (%s): %lu", ApplicationName, GetLastError());
587
+ return;
588
+ }
589
+
590
+ WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
591
+
592
+ if (!GetExitCodeProcess(ProcessInformation.hProcess, &ExitStatus))
593
+ {
594
+ FATAL("Failed to get exit status (error %lu).", GetLastError());
595
+ }
596
+
597
+ CloseHandle(ProcessInformation.hProcess);
598
+ CloseHandle(ProcessInformation.hThread);
599
+ }
600
+
601
+ /**
602
+ * Sets up a process to be created after all other opcodes have been processed. This can be used to create processes
603
+ * after the temporary files have all been created and memory has been freed.
604
+ */
605
+ BOOL OpPostCreateProcess(LPVOID* p)
606
+ {
607
+ DEBUG("PostCreateProcess");
608
+ if (PostCreateProcess_ApplicationName || PostCreateProcess_CommandLine)
609
+ {
610
+ return FALSE;
611
+ }
612
+ else
613
+ {
614
+ GetCreateProcessInfo(p, &PostCreateProcess_ApplicationName, &PostCreateProcess_CommandLine);
615
+ return TRUE;
616
+ }
617
+ }
618
+
619
+ BOOL OpEnableDebugMode(LPVOID* p)
620
+ {
621
+ DebugModeEnabled = TRUE;
622
+ DEBUG("Aibika stub running in debug mode");
623
+ return TRUE;
624
+ }
625
+
626
+ #if WITH_LZMA
627
+ void* SzAlloc(void* p, size_t size) { p = p; return LocalAlloc(LMEM_FIXED, size); }
628
+ void SzFree(void* p, void* address) { p = p; LocalFree(address); }
629
+ ISzAlloc alloc = { SzAlloc, SzFree };
630
+
631
+ #define LZMA_UNPACKSIZE_SIZE 8
632
+ #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNPACKSIZE_SIZE)
633
+
634
+ BOOL OpDecompressLzma(LPVOID* p)
635
+ {
636
+ BOOL Success = TRUE;
637
+
638
+ DWORD CompressedSize = GetInteger(p);
639
+ DEBUG("LzmaDecode(%ld)", CompressedSize);
640
+
641
+ Byte* src = (Byte*)*p;
642
+ *p += CompressedSize;
643
+
644
+ UInt64 unpackSize = 0;
645
+ int i;
646
+ for (i = 0; i < 8; i++)
647
+ {
648
+ unpackSize += (UInt64)src[LZMA_PROPS_SIZE + i] << (i * 8);
649
+ }
650
+
651
+ Byte* DecompressedData = LocalAlloc(LMEM_FIXED, unpackSize);
652
+
653
+ SizeT lzmaDecompressedSize = unpackSize;
654
+ SizeT inSizePure = CompressedSize - LZMA_HEADER_SIZE;
655
+ ELzmaStatus status;
656
+ SRes res = LzmaDecode(DecompressedData, &lzmaDecompressedSize, src + LZMA_HEADER_SIZE, &inSizePure,
657
+ src, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &alloc);
658
+ if (res != SZ_OK)
659
+ {
660
+ FATAL("LZMA decompression failed.");
661
+ Success = FALSE;
662
+ }
663
+ else
664
+ {
665
+ LPVOID decPtr = DecompressedData;
666
+ if (!ProcessOpcodes(&decPtr))
667
+ {
668
+ Success = FALSE;
669
+ }
670
+ }
671
+
672
+ LocalFree(DecompressedData);
673
+ return Success;
674
+ }
675
+ #endif
676
+
677
+ BOOL OpEnd(LPVOID* p)
678
+ {
679
+ ExitCondition = TRUE;
680
+ return TRUE;
681
+ }
682
+
683
+ BOOL OpSetEnv(LPVOID* p)
684
+ {
685
+ LPTSTR Name = GetString(p);
686
+ LPTSTR Value = GetString(p);
687
+ LPTSTR ExpandedValue;
688
+ ExpandPath(&ExpandedValue, Value);
689
+ DEBUG("SetEnv(%s, %s)", Name, ExpandedValue);
690
+
691
+ BOOL Result = FALSE;
692
+ if (!SetEnvironmentVariable(Name, ExpandedValue))
693
+ {
694
+ FATAL("Failed to set environment variable (error %lu).", GetLastError());
695
+ Result = FALSE;
696
+ }
697
+ else
698
+ {
699
+ Result = TRUE;
700
+ }
701
+ LocalFree(ExpandedValue);
702
+ return Result;
703
+ }
data/src/stub.rc ADDED
@@ -0,0 +1 @@
1
+ 101 ICON vit-ruby.ico
data/src/vit-ruby.ico ADDED
Binary file