ocran 1.3.18 → 1.4.0

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.txt +306 -292
  3. data/LICENSE.txt +22 -22
  4. data/README.md +549 -533
  5. data/exe/ocran +5 -5
  6. data/ext/extconf.rb +15 -0
  7. data/lib/ocran/build_constants.rb +16 -16
  8. data/lib/ocran/build_facade.rb +17 -17
  9. data/lib/ocran/build_helper.rb +110 -105
  10. data/lib/ocran/command_output.rb +22 -22
  11. data/lib/ocran/dir_builder.rb +162 -0
  12. data/lib/ocran/direction.rb +623 -458
  13. data/lib/ocran/file_path_set.rb +69 -69
  14. data/lib/ocran/gem_spec_queryable.rb +172 -172
  15. data/lib/ocran/host_config_helper.rb +57 -44
  16. data/lib/ocran/inno_setup_script_builder.rb +111 -111
  17. data/lib/ocran/launcher_batch_builder.rb +85 -85
  18. data/lib/ocran/library_detector.rb +61 -61
  19. data/lib/ocran/library_detector_posix.rb +55 -0
  20. data/lib/ocran/option.rb +323 -273
  21. data/lib/ocran/refine_pathname.rb +104 -104
  22. data/lib/ocran/runner.rb +115 -105
  23. data/lib/ocran/runtime_environment.rb +46 -46
  24. data/lib/ocran/stub_builder.rb +298 -264
  25. data/lib/ocran/version.rb +5 -5
  26. data/lib/ocran/windows_command_escaping.rb +15 -15
  27. data/lib/ocran.rb +7 -7
  28. data/share/ocran/lzma.exe +0 -0
  29. data/src/Makefile +75 -0
  30. data/src/edicon.c +161 -0
  31. data/src/error.c +100 -0
  32. data/src/error.h +66 -0
  33. data/src/inst_dir.c +334 -0
  34. data/src/inst_dir.h +157 -0
  35. data/src/lzma/7zTypes.h +529 -0
  36. data/src/lzma/Compiler.h +43 -0
  37. data/src/lzma/LzmaDec.c +1363 -0
  38. data/src/lzma/LzmaDec.h +236 -0
  39. data/src/lzma/Precomp.h +10 -0
  40. data/src/script_info.c +246 -0
  41. data/src/script_info.h +7 -0
  42. data/src/stub.c +133 -0
  43. data/src/stub.manifest +29 -0
  44. data/src/stub.rc +3 -0
  45. data/src/system_utils.c +1002 -0
  46. data/src/system_utils.h +209 -0
  47. data/src/system_utils_posix.c +500 -0
  48. data/src/unpack.c +574 -0
  49. data/src/unpack.h +85 -0
  50. data/src/vit-ruby.ico +0 -0
  51. metadata +52 -16
  52. data/share/ocran/edicon.exe +0 -0
  53. data/share/ocran/stub.exe +0 -0
  54. data/share/ocran/stubw.exe +0 -0
data/src/unpack.c ADDED
@@ -0,0 +1,574 @@
1
+ #include <stdbool.h>
2
+ #include <stddef.h>
3
+ #include <stdint.h>
4
+ #include <string.h>
5
+ #include <stdlib.h>
6
+ #ifdef _WIN32
7
+ #include <windows.h>
8
+ #endif
9
+ #include "error.h"
10
+ #include "system_utils.h"
11
+ #include "inst_dir.h"
12
+ #include "script_info.h"
13
+ #include "unpack.h"
14
+
15
+ #if WITH_LZMA
16
+ #include <LzmaDec.h>
17
+ #endif
18
+
19
+ typedef uint32_t SizeType;
20
+
21
+ static inline size_t get_size(const void *p)
22
+ {
23
+ const uint8_t *b = p;
24
+ return (size_t)b[0]
25
+ | ((size_t)b[1] << 8)
26
+ | ((size_t)b[2] << 16)
27
+ | ((size_t)b[3] << 24);
28
+ }
29
+
30
+ typedef struct {
31
+ const uint8_t *begin;
32
+ const uint8_t *end;
33
+ const uint8_t *cur;
34
+ } UnpackReader;
35
+
36
+ static bool read_bytes(UnpackReader *reader, size_t size, const uint8_t **ptr)
37
+ {
38
+ size_t avail = (size_t)(reader->end - reader->cur);
39
+ if (size > avail) {
40
+ DEBUG("failed to read requested data bytes");
41
+ return false;
42
+ }
43
+
44
+ *ptr = reader->cur;
45
+ reader->cur += size;
46
+ return true;
47
+ }
48
+
49
+ static bool read_integer(UnpackReader *reader, size_t *size);
50
+
51
+ static bool read_string(UnpackReader *reader, const char **str)
52
+ {
53
+ size_t len;
54
+ if (!read_integer(reader, &len)) {
55
+ DEBUG("failed to read string size");
56
+ return false;
57
+ }
58
+
59
+ if (len == 0) {
60
+ DEBUG("string size is zero");
61
+ return false;
62
+ }
63
+
64
+ const uint8_t *bytes;
65
+ if (!read_bytes(reader, len, &bytes)) {
66
+ DEBUG("failed to read string data");
67
+ return false;
68
+ }
69
+
70
+ if (bytes[len - 1] != '\0') {
71
+ DEBUG("string is not null-terminated");
72
+ return false;
73
+ }
74
+
75
+ *str = (const char *)bytes;
76
+ return true;
77
+ }
78
+
79
+ static bool read_integer(UnpackReader *reader, size_t *size)
80
+ {
81
+ const uint8_t *b;
82
+ if (!read_bytes(reader, sizeof(SizeType), &b)) {
83
+ DEBUG("failed to read integer value");
84
+ return false;
85
+ }
86
+
87
+ *size = get_size(b);
88
+ return true;
89
+ }
90
+
91
+ static bool read_opcode(UnpackReader *reader, Opcode *opcode)
92
+ {
93
+ const uint8_t *b;
94
+ if (!read_bytes(reader, 1, &b)) {
95
+ DEBUG("failed to read opcode");
96
+ return false;
97
+ }
98
+
99
+ *opcode = (Opcode)b[0];
100
+ return true;
101
+ }
102
+
103
+ static bool process_opcode(UnpackReader *reader, Opcode opcode)
104
+ {
105
+ const char *name, *value;
106
+ const uint8_t *bytes;
107
+ size_t size;
108
+
109
+ switch (opcode) {
110
+ case OP_CREATE_DIRECTORY: {
111
+ if (!read_string(reader, &name)) {
112
+ return false;
113
+ }
114
+ DEBUG("OP_CREATE_DIRECTORY: path='%s'", name);
115
+ return CreateDirectoryUnderInstDir(name);
116
+ }
117
+
118
+ case OP_CREATE_FILE: {
119
+ if (!read_string(reader, &name)) {
120
+ return false;
121
+ }
122
+ if (!read_integer(reader, &size)) {
123
+ return false;
124
+ }
125
+ if (!read_bytes(reader, size, &bytes)) {
126
+ return false;
127
+ }
128
+ const void *data = bytes;
129
+ DEBUG("OP_CREATE_FILE: path='%s' (%zu bytes)", name, size);
130
+ return ExportFileToInstDir(name, data, size);
131
+ }
132
+
133
+ case OP_SETENV: {
134
+ if (!read_string(reader, &name)) {
135
+ return false;
136
+ }
137
+ if (!read_string(reader, &value)) {
138
+ return false;
139
+ }
140
+ DEBUG("OP_SETENV: name='%s', value='%s'", name, value);
141
+ return SetEnvWithInstDir(name, value);
142
+ }
143
+
144
+ case OP_SET_SCRIPT: {
145
+ if (!read_integer(reader, &size)) {
146
+ return false;
147
+ }
148
+ if (!read_bytes(reader, size, &bytes)) {
149
+ return false;
150
+ }
151
+ const char *args = (const char *)bytes;
152
+ DEBUG("OP_SET_SCRIPT");
153
+ return SetScriptInfo(args, size);
154
+ }
155
+
156
+ case OP_CREATE_SYMLINK: {
157
+ if (!read_string(reader, &name)) {
158
+ return false;
159
+ }
160
+ if (!read_string(reader, &value)) {
161
+ return false;
162
+ }
163
+ DEBUG("OP_CREATE_SYMLINK: link='%s', target='%s'", name, value);
164
+ #ifndef _WIN32
165
+ return CreateSymlinkUnderInstDir(name, value);
166
+ #else
167
+ DEBUG("OP_CREATE_SYMLINK: skipped on Windows");
168
+ return true;
169
+ #endif
170
+ }
171
+
172
+ default: {
173
+ DEBUG("Invalid opcode: %d", opcode);
174
+ return false;
175
+ }
176
+ }
177
+
178
+ /* Unreachable: every case returns earlier */
179
+ return false;
180
+ }
181
+
182
+ static bool process_opcodes(const void *data, size_t data_size)
183
+ {
184
+ UnpackReader reader = {
185
+ .begin = (const uint8_t *)data,
186
+ .cur = (const uint8_t *)data,
187
+ .end = (const uint8_t *)data + data_size
188
+ };
189
+ Opcode opcode;
190
+
191
+ while (reader.cur < reader.end) {
192
+ if (!read_opcode(&reader, &opcode)) {
193
+ return false;
194
+ }
195
+ if (!process_opcode(&reader, opcode)) {
196
+ return false;
197
+ }
198
+ }
199
+ return true;
200
+ }
201
+
202
+ #if WITH_LZMA
203
+ #define LZMA_UNPACKSIZE_SIZE 8
204
+ #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNPACKSIZE_SIZE)
205
+ #define LZMA_SIZET_MAX ((SizeT)-1)
206
+
207
+ void *SzAlloc(const ISzAlloc *p, size_t size) { p = p; return malloc(size); }
208
+ void SzFree(const ISzAlloc *p, void *address) { p = p; free(address); }
209
+ ISzAlloc alloc = { SzAlloc, SzFree };
210
+
211
+ static bool decompress_lzma(void *dest, unsigned long long dest_size,
212
+ const void *src, size_t src_size)
213
+ {
214
+ SizeT decompressed_size = (SizeT)dest_size;
215
+ SizeT inSizePure = src_size - LZMA_HEADER_SIZE;
216
+ ELzmaStatus status;
217
+
218
+ SRes res = LzmaDecode((Byte *)dest, &decompressed_size,
219
+ (Byte *)src + LZMA_HEADER_SIZE, &inSizePure,
220
+ (Byte *)src, LZMA_PROPS_SIZE,
221
+ LZMA_FINISH_END, &status, &alloc);
222
+
223
+ if (res != SZ_OK || status != LZMA_STATUS_FINISHED_WITH_MARK) {
224
+ APP_ERROR("LZMA decompression error: %d, status: %d", res, status);
225
+ return false;
226
+ }
227
+ return true;
228
+ }
229
+
230
+ static unsigned long long parse_lzma_unpack_size(const void *data)
231
+ {
232
+ const Byte *size_bytes = (const Byte *)data + LZMA_PROPS_SIZE;
233
+ unsigned long long size64 = 0;
234
+ for (int i = 0; i < LZMA_UNPACKSIZE_SIZE; i++) {
235
+ size64 |= (unsigned long long)size_bytes[i] << (i * 8);
236
+ }
237
+ return size64;
238
+ }
239
+ #endif
240
+
241
+ static void *DecompressLzmaData(const void *data, size_t data_size,
242
+ size_t *decompressed_size)
243
+ {
244
+ #if WITH_LZMA
245
+ if (data_size < LZMA_HEADER_SIZE) {
246
+ APP_ERROR("LZMA header is truncated");
247
+ return NULL;
248
+ }
249
+
250
+ unsigned long long unpack_size = parse_lzma_unpack_size(data);
251
+
252
+ DEBUG("Parsed LZMA decompressed size: %llu bytes", unpack_size);
253
+
254
+ if (unpack_size > (unsigned long long)LZMA_SIZET_MAX) {
255
+ APP_ERROR("Decompression size exceeds LZMA SizeT limit");
256
+ return NULL;
257
+ }
258
+
259
+ if (unpack_size > (unsigned long long)SIZE_MAX) {
260
+ APP_ERROR("Size too large to fit in size_t");
261
+ return NULL;
262
+ }
263
+
264
+ void *unpack_data = malloc(unpack_size);
265
+ if (!unpack_data) {
266
+ APP_ERROR("Memory allocation failed during decompression");
267
+ return NULL;
268
+ }
269
+
270
+ if (!decompress_lzma(unpack_data, unpack_size, data, data_size)) {
271
+ APP_ERROR("LZMA decompression failed");
272
+ free(unpack_data);
273
+ return NULL;
274
+ }
275
+
276
+ *decompressed_size = unpack_size;
277
+ return unpack_data;
278
+ #else
279
+ APP_ERROR("Does not support LZMA");
280
+ return NULL;
281
+ #endif
282
+ }
283
+
284
+ const uint8_t Signature[] = { 0x41, 0xb6, 0xba, 0x4e };
285
+
286
+ /** Manages digital signatures **/
287
+
288
+ /* see https://en.wikipedia.org/wiki/Portable_Executable for explanation of these header fields */
289
+ #define SECURITY_ENTRY(header) ((header)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY])
290
+
291
+ #ifdef _WIN32
292
+ /* The NTHeader is another name for the PE header. It is the 'modern' executable header
293
+ as opposed to the DOS_HEADER which exists for legacy reasons */
294
+ static PIMAGE_NT_HEADERS retrieveNTHeader(const void *ptr) {
295
+ PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)ptr;
296
+
297
+ /* e_lfanew is an RVA (relative virtual address, i.e offset) to the NTHeader
298
+ to get a usable pointer we add the RVA to the base address */
299
+ return (PIMAGE_NT_HEADERS)((DWORD_PTR)dosHeader + (DWORD)dosHeader->e_lfanew);
300
+ }
301
+
302
+ /* Check whether there's an embedded digital signature */
303
+ static bool isDigitallySigned(const void *ptr, size_t buffer_size) {
304
+ PIMAGE_NT_HEADERS ntHeader = retrieveNTHeader(ptr);
305
+ DWORD securityAddr = SECURITY_ENTRY(ntHeader).VirtualAddress;
306
+ DWORD securitySize = SECURITY_ENTRY(ntHeader).Size;
307
+
308
+ /* A valid digital signature must have non-zero size and the address must be within the file bounds */
309
+ if (securitySize == 0) {
310
+ return false;
311
+ }
312
+
313
+ /* Check if the security entry points to a valid location within the file */
314
+ if (securityAddr == 0 || securityAddr >= buffer_size) {
315
+ return false;
316
+ }
317
+
318
+ /* Check if the entire security entry fits within the file */
319
+ if (securityAddr + securitySize > buffer_size) {
320
+ return false;
321
+ }
322
+
323
+ return true;
324
+ }
325
+ #endif
326
+
327
+ static const void *find_signature(const void *buffer, size_t buffer_size)
328
+ {
329
+ #ifdef _WIN32
330
+ // Check if the executable is digitally signed
331
+ if (!isDigitallySigned(buffer, buffer_size)) {
332
+ // No digital signature, use the original logic
333
+ const void *sig = (const uint8_t *)buffer + buffer_size - sizeof(Signature);
334
+ if (memcmp(sig, Signature, sizeof(Signature))) {
335
+ return NULL;
336
+ }
337
+ return sig;
338
+ }
339
+ else {
340
+ // Executable is digitally signed
341
+ PIMAGE_NT_HEADERS ntHeader = retrieveNTHeader(buffer);
342
+ DWORD securityAddr = SECURITY_ENTRY(ntHeader).VirtualAddress;
343
+
344
+ if (securityAddr == 0 || securityAddr > buffer_size) {
345
+ DEBUG("Invalid security address: %lu", (unsigned long)securityAddr);
346
+ return NULL;
347
+ }
348
+
349
+ DWORD offset = securityAddr - 1;
350
+ const char *searchPtr = (const char *)buffer;
351
+
352
+ /* There is unfortunately a 'buffer' of null bytes between the
353
+ ocraSignature and the digital signature. This buffer appears to be random
354
+ in size, so the only way we can account for it is to search backwards
355
+ for the first non-null byte.
356
+ NOTE: this means that the hard-coded Ocra signature cannot end with a null byte.
357
+ */
358
+ while(offset > sizeof(Signature) && !searchPtr[offset])
359
+ offset--;
360
+
361
+ /* -3 because we're already at the first byte and we need to go back 4 bytes */
362
+ if (offset < sizeof(Signature)) {
363
+ DEBUG("Signature search went out of bounds");
364
+ return NULL;
365
+ }
366
+
367
+ const void *sig = (const void *)&searchPtr[offset - 3];
368
+
369
+ if (memcmp(sig, Signature, sizeof(Signature))) {
370
+ DEBUG("Signature mismatch in signed executable");
371
+ return NULL;
372
+ }
373
+ return sig;
374
+ }
375
+ #else
376
+ // POSIX: no PE headers, just check the end of the file
377
+ if (buffer_size < sizeof(Signature)) {
378
+ return NULL;
379
+ }
380
+
381
+ const void *sig = (const uint8_t *)buffer + buffer_size - sizeof(Signature);
382
+ if (memcmp(sig, Signature, sizeof(Signature)) != 0) {
383
+ return NULL;
384
+ }
385
+
386
+ return sig;
387
+ #endif
388
+ }
389
+
390
+ typedef uint8_t OperationModesType;
391
+
392
+ OperationModes get_operation_modes(const void **p)
393
+ {
394
+ const OperationModesType *q = (const OperationModesType *)*p;
395
+ *p = q + 1;
396
+ return (OperationModes)*q;
397
+ }
398
+
399
+ typedef SizeType OffsetType;
400
+
401
+ size_t get_offset(const void *p)
402
+ {
403
+ return get_size(p);
404
+ }
405
+
406
+ struct UnpackContext {
407
+ MemoryMap *map;
408
+ OperationModes modes;
409
+ const void *data;
410
+ size_t data_size;
411
+ };
412
+
413
+ UnpackContext *OpenPackFile(const char *self_path)
414
+ {
415
+ UnpackContext *context = NULL;
416
+
417
+ if (!self_path || !*self_path) {
418
+ APP_ERROR("self_path is NULL or empty");
419
+
420
+ goto cleanup;
421
+ }
422
+
423
+ context = calloc(1, sizeof(UnpackContext)) ;
424
+ if (!context) {
425
+ APP_ERROR("Memory allocation failed for context");
426
+
427
+ goto cleanup;
428
+ }
429
+
430
+ context->map = CreateMemoryMap(self_path);
431
+ if (!context->map) {
432
+ APP_ERROR("Failed to map the executable file");
433
+
434
+ goto cleanup;
435
+ }
436
+ const void *map_base = GetMemoryMapBase(context->map);
437
+ size_t map_size = GetMemoryMapSize(context->map);
438
+
439
+ /* Locate the end of the packed data */
440
+ if (map_size < sizeof(Signature)) {
441
+ APP_ERROR("Too small to contain signature");
442
+
443
+ goto cleanup;
444
+ }
445
+ const void *signature = find_signature(map_base, map_size);
446
+ if (!signature) {
447
+ APP_ERROR("Signature not found");
448
+
449
+ goto cleanup;
450
+ }
451
+ if ((size_t)((const uint8_t *)signature - (const uint8_t *)map_base)
452
+ < sizeof(OffsetType)) {
453
+ APP_ERROR("Signature too close to buffer start");
454
+
455
+ goto cleanup;
456
+ }
457
+ const void *tail = signature;
458
+
459
+ /* Determine the start of the packed data */
460
+ tail = (const uint8_t *)tail - sizeof(OffsetType);
461
+ size_t offset = get_offset(tail);
462
+ if (offset > map_size - sizeof(OperationModesType)) {
463
+ APP_ERROR("Offset out of range");
464
+
465
+ goto cleanup;
466
+ }
467
+ const void *head = (const uint8_t *)map_base + offset;
468
+
469
+ /* Verify that the header fits immediately before the offset */
470
+ if (head > tail
471
+ || (size_t)((const uint8_t *)tail - (const uint8_t *)head)
472
+ < sizeof(OperationModesType)) {
473
+ APP_ERROR("Not enough space for header before offset");
474
+
475
+ goto cleanup;
476
+ }
477
+ context->modes = get_operation_modes(&head);
478
+ context->data = head;
479
+ context->data_size = (const uint8_t *)tail - (const uint8_t *)head;
480
+
481
+ DEBUG(
482
+ "OpenPackFile: offset=%zu, modes= %u, data_size=%zu",
483
+ offset, (unsigned)context->modes, context->data_size
484
+ );
485
+ return context;
486
+
487
+ cleanup:
488
+ if (context) {
489
+ ClosePackFile(context);
490
+ }
491
+ return NULL;
492
+ }
493
+
494
+ bool ClosePackFile(UnpackContext *context)
495
+ {
496
+ if (context) {
497
+ if (context->map) {
498
+ DestroyMemoryMap(context->map);
499
+ }
500
+ free(context);
501
+ }
502
+ return true;
503
+ }
504
+
505
+ OperationModes GetOperationModes(const UnpackContext *context)
506
+ {
507
+ if (!context) {
508
+ APP_ERROR("context is NULL");
509
+
510
+ return 0;
511
+ }
512
+ return context->modes;
513
+ }
514
+
515
+ static inline bool IsMode(OperationModes modes, OperationModes mask) {
516
+ return (modes & mask) == mask;
517
+ }
518
+
519
+ bool IsDebugMode(OperationModes modes) {
520
+ return IsMode(modes, DEBUG_MODE);
521
+ }
522
+
523
+ bool IsExtractToExeDir(OperationModes modes) {
524
+ return IsMode(modes, EXTRACT_TO_EXE_DIR);
525
+ }
526
+
527
+ bool IsAutoCleanInstDir(OperationModes modes) {
528
+ return IsMode(modes, AUTO_CLEAN_INST_DIR);
529
+ }
530
+
531
+ bool IsChdirBeforeScript(OperationModes modes) {
532
+ return IsMode(modes, CHDIR_BEFORE_SCRIPT);
533
+ }
534
+
535
+ bool IsDataCompressed(OperationModes modes) {
536
+ return IsMode(modes, DATA_COMPRESSED);
537
+ }
538
+
539
+ bool ProcessImage(const UnpackContext *context)
540
+ {
541
+ if (!context) {
542
+ APP_ERROR("context is NULL");
543
+ return false;
544
+ }
545
+
546
+ DEBUG("Data segment size: %zu bytes", context->data_size);
547
+
548
+ bool compressed = IsDataCompressed(context->modes);
549
+ void *data;
550
+ size_t data_size;
551
+
552
+ if (compressed) {
553
+ data = DecompressLzmaData(
554
+ context->data,
555
+ context->data_size,
556
+ &data_size
557
+ );
558
+ if (!data) {
559
+ APP_ERROR("LZMA decompression failed");
560
+ return false;
561
+ }
562
+ DEBUG("LZMA decompressed %zu bytes", data_size);
563
+ } else {
564
+ data = (void *)context->data;
565
+ data_size = context->data_size;
566
+ }
567
+
568
+ bool ok = process_opcodes(data, data_size);
569
+
570
+ if (compressed) {
571
+ free(data);
572
+ }
573
+ return ok;
574
+ }
data/src/unpack.h ADDED
@@ -0,0 +1,85 @@
1
+ #include <stdbool.h>
2
+
3
+ typedef enum {
4
+ OP_CREATE_DIRECTORY = 1,
5
+ OP_CREATE_FILE = 2,
6
+ OP_SETENV = 3,
7
+ OP_SET_SCRIPT = 4,
8
+ OP_CREATE_SYMLINK = 5,
9
+ } Opcode;
10
+
11
+ /**
12
+ * OperationModes defines a set of flags used to control various aspects of the
13
+ * program's behavior during runtime. These flags enable or disable specific
14
+ * features and functionalities, allowing for a more flexible and customizable
15
+ * execution based on the needs of the user or the environment.
16
+ *
17
+ * The flags managed by OperationModes include, but are not limited to:
18
+ *
19
+ * - DEBUG_MODE: Activates verbose debugging information to assist in
20
+ * development or troubleshooting.
21
+ *
22
+ * - EXTRACT_TO_EXE_DIR: Directs the program to unpack data in the same
23
+ * directory as the executable.
24
+ *
25
+ * - AUTO_CLEAN_INST_DIR: Enables automatic cleanup of the extraction
26
+ * directory upon program termination.
27
+ *
28
+ * - CHDIR_BEFORE_SCRIPT: Changes the current directory to the script's
29
+ * location before its execution.
30
+ *
31
+ * - DATA_COMPRESSED: Indicates that the data to be processed is compressed and
32
+ * requires decompression.
33
+ *
34
+ * By adjusting these flags, developers and users can tailor the program's
35
+ * execution to suit specific scenarios, enhancing both usability and
36
+ * efficiency.
37
+ */
38
+ typedef enum {
39
+ /**
40
+ * Enable debug information display. Output various execution information to
41
+ * stderr.
42
+ */
43
+ DEBUG_MODE = 0x01,
44
+
45
+ /**
46
+ * Sets the extraction directory to the executable directory.
47
+ * Data will be unpacked in the same location as the executable file.
48
+ */
49
+ EXTRACT_TO_EXE_DIR = 0x02,
50
+
51
+ /**
52
+ * Enable automatic deletion of the extraction directory at the end of the
53
+ * application. Cleanup the extracted data upon program termination.
54
+ */
55
+ AUTO_CLEAN_INST_DIR = 0x04,
56
+
57
+ /**
58
+ * Change the current directory to the location of the script before
59
+ * executing the script. This allows file operations relative to that
60
+ * directory.
61
+ */
62
+ CHDIR_BEFORE_SCRIPT = 0x08,
63
+
64
+ /**
65
+ * Indicates that the data to be extracted is compressed. Decompression is
66
+ * required before using the data.
67
+ */
68
+ DATA_COMPRESSED = 0x10,
69
+ } OperationModes;
70
+
71
+ bool IsDebugMode(OperationModes modes);
72
+ bool IsExtractToExeDir(OperationModes modes);
73
+ bool IsAutoCleanInstDir(OperationModes modes);
74
+ bool IsChdirBeforeScript(OperationModes modes);
75
+ bool IsDataCompressed(OperationModes modes);
76
+
77
+ typedef struct UnpackContext UnpackContext;
78
+
79
+ UnpackContext *OpenPackFile(const char *self_path);
80
+
81
+ bool ClosePackFile(UnpackContext *context);
82
+
83
+ OperationModes GetOperationModes(const UnpackContext *context);
84
+
85
+ bool ProcessImage(const UnpackContext *context);
data/src/vit-ruby.ico ADDED
Binary file