aibika 1.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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