R3EXS 1.0.2 → 1.0.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +260 -260
- data/README_EN.md +260 -260
- data/bin/R3EXS +6 -4
- data/ext/rgss3a_rvdata2/rgss3a_rvdata2.c +616 -565
- data/lib/R3EXS/RGSS3.rb +1456 -1456
- data/lib/R3EXS/RGSS3_R3EXS.rb +95 -95
- data/lib/R3EXS/ast.rb +7 -7
- data/lib/R3EXS/error.rb +17 -0
- data/lib/R3EXS/extract_strings.rb +79 -79
- data/lib/R3EXS/json_rvdata2.rb +104 -104
- data/lib/R3EXS/utils.rb +970 -970
- data/lib/R3EXS/version.rb +1 -1
- metadata +2 -2
@@ -1,565 +1,616 @@
|
|
1
|
-
#include "ruby.h"
|
2
|
-
|
3
|
-
#ifdef _WIN32
|
4
|
-
wchar_t* wchar_arr = NULL;
|
5
|
-
unsigned short wchar_arr_size = 0;
|
6
|
-
|
7
|
-
/*
|
8
|
-
* 将指定长度的 UTF-8 字符串转换为 wchar 字符串
|
9
|
-
* wchar 字符串会被存储在 wchar_arr 中
|
10
|
-
* 同时更新 wchar_arr_size
|
11
|
-
*
|
12
|
-
* @param utf8char UTF-8 字符串
|
13
|
-
* @param n 字符串长度
|
14
|
-
* @return 0 成功,-1 失败
|
15
|
-
*/
|
16
|
-
int utf8towc(const char* utf8char, size_t n)
|
17
|
-
{
|
18
|
-
// 计算转换为 wchar 所需的缓冲区大小,包括结尾的 '\0'
|
19
|
-
int wc_size = MultiByteToWideChar(CP_UTF8, 0, utf8char, n, NULL, 0) + 1;
|
20
|
-
if (wc_size ==
|
21
|
-
{
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
*
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
*
|
133
|
-
*
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
switch (r)
|
146
|
-
{
|
147
|
-
case 1 : *data_p ^= (magickey & MASK_KEY_1); break;
|
148
|
-
case 2 : *data_p ^= (magickey & MASK_KEY_2); break;
|
149
|
-
case 3 : *data_p ^= (magickey & MASK_KEY_3); break;
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
/*
|
154
|
-
*
|
155
|
-
*
|
156
|
-
* @param
|
157
|
-
* @
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
*
|
166
|
-
*
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
*
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
*
|
246
|
-
*
|
247
|
-
* @
|
248
|
-
* @return [void]
|
249
|
-
*/
|
250
|
-
|
251
|
-
{
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
free(
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
#
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
#
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
#
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
}
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
#
|
401
|
-
|
402
|
-
|
403
|
-
#endif
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
unsigned
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
{
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
#
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
#
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
1
|
+
#include "ruby.h"
|
2
|
+
|
3
|
+
#ifdef _WIN32
|
4
|
+
wchar_t* wchar_arr = NULL;
|
5
|
+
unsigned short wchar_arr_size = 0;
|
6
|
+
|
7
|
+
/*
|
8
|
+
* 将指定长度的 UTF-8 字符串转换为 wchar 字符串
|
9
|
+
* wchar 字符串会被存储在 wchar_arr 中
|
10
|
+
* 同时更新 wchar_arr_size
|
11
|
+
*
|
12
|
+
* @param utf8char UTF-8 字符串
|
13
|
+
* @param n 字符串长度
|
14
|
+
* @return 0 成功,-1 失败
|
15
|
+
*/
|
16
|
+
int utf8towc(const char* utf8char, size_t n)
|
17
|
+
{
|
18
|
+
// 计算转换为 wchar 所需的缓冲区大小,包括结尾的 '\0'
|
19
|
+
int wc_size = MultiByteToWideChar(CP_UTF8, 0, utf8char, n, NULL, 0) + 1;
|
20
|
+
if (wc_size == 1) // 转换失败
|
21
|
+
{
|
22
|
+
if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION)
|
23
|
+
{
|
24
|
+
errno = EILSEQ;
|
25
|
+
return -1;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
if (wc_size > wchar_arr_size)
|
29
|
+
{
|
30
|
+
wchar_t* wchar_arr_new = (wchar_t*)realloc(wchar_arr, sizeof(wchar_t) * wc_size);
|
31
|
+
if (!wchar_arr_new)
|
32
|
+
{
|
33
|
+
errno = ENOMEM;
|
34
|
+
return -1;
|
35
|
+
}
|
36
|
+
wchar_arr = wchar_arr_new;
|
37
|
+
wchar_arr_size = wc_size;
|
38
|
+
}
|
39
|
+
|
40
|
+
// 执行从 UTF-8 到 wchar 的转换
|
41
|
+
MultiByteToWideChar(CP_UTF8, 0, utf8char, n, wchar_arr, wchar_arr_size);
|
42
|
+
// 添加结尾的 '\0'
|
43
|
+
wchar_arr[wc_size - 1] = L'\0';
|
44
|
+
return 0;
|
45
|
+
}
|
46
|
+
|
47
|
+
/*
|
48
|
+
* 处理 utf8towc 错误
|
49
|
+
*
|
50
|
+
* @return [void]
|
51
|
+
*/
|
52
|
+
void utf8towc_error_handler(void)
|
53
|
+
{
|
54
|
+
rb_sys_fail("Failed to convert UTF-8 to wchar");
|
55
|
+
}
|
56
|
+
#endif
|
57
|
+
|
58
|
+
#ifdef __linux__
|
59
|
+
char* char_arr = NULL;
|
60
|
+
unsigned short char_arr_size = 0;
|
61
|
+
|
62
|
+
/*
|
63
|
+
* 将指定长度的 UTF-8 字符串 转换为 char 字符串
|
64
|
+
* char 字符串会被存储在 char_arr 中
|
65
|
+
* 同时更新 char_arr_size
|
66
|
+
*
|
67
|
+
* @param utf8char UTF-8 字符串
|
68
|
+
* @param n 字符串长度
|
69
|
+
* @return 0 成功,-1 失败
|
70
|
+
*/
|
71
|
+
int utf8tomb(const char* utf8char, size_t n)
|
72
|
+
{
|
73
|
+
// 计算转换为 char 所需的缓冲区大小,包括结尾的 '\0'
|
74
|
+
int mb_size = n + 1;
|
75
|
+
if (mb_size > char_arr_size)
|
76
|
+
{
|
77
|
+
char* char_arr_new = (char*)realloc(char_arr, sizeof(char) * mb_size);
|
78
|
+
if (!char_arr_new)
|
79
|
+
{
|
80
|
+
errno = ENOMEM;
|
81
|
+
return -1;
|
82
|
+
}
|
83
|
+
char_arr = char_arr_new;
|
84
|
+
char_arr_size = mb_size;
|
85
|
+
}
|
86
|
+
memcpy(char_arr, utf8char, n);
|
87
|
+
char_arr[mb_size - 1] = '\0';
|
88
|
+
return 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
/*
|
92
|
+
* 处理 utf8tomb 错误
|
93
|
+
*
|
94
|
+
* @return [void]
|
95
|
+
*/
|
96
|
+
void utf8tomb_error_handler(void)
|
97
|
+
{
|
98
|
+
rb_sys_fail("Failed to convert UTF-8 to char");
|
99
|
+
}
|
100
|
+
#endif
|
101
|
+
|
102
|
+
VALUE R3EXS = Qnil;
|
103
|
+
|
104
|
+
ID r3exs_RGSS3AFileError_id;
|
105
|
+
ID r3exs_File_id;
|
106
|
+
ID r3exs_FileUtils_id;
|
107
|
+
ID r3exs_Dir_id;
|
108
|
+
ID r3exs_new_id;
|
109
|
+
ID r3exs_join_id;
|
110
|
+
ID r3exs_dirname_id;
|
111
|
+
ID r3exs_exist_id;
|
112
|
+
ID r3exs_mkdir_p_id;
|
113
|
+
|
114
|
+
VALUE r3exs_RGSS3AFileError_class;
|
115
|
+
VALUE r3exs_File_module;
|
116
|
+
VALUE r3exs_FileUtils_module;
|
117
|
+
VALUE r3exs_Dir_module;
|
118
|
+
|
119
|
+
#define MOD_4_MASK 0b11
|
120
|
+
#define MASK_KEY_1 0x000000FF
|
121
|
+
#define MASK_KEY_2 0x0000FFFF
|
122
|
+
#define MASK_KEY_3 0x00FFFFFF
|
123
|
+
|
124
|
+
// 解码文件类型
|
125
|
+
enum RGSSAD_DECRYPT_TYPE
|
126
|
+
{
|
127
|
+
RGSSAD,
|
128
|
+
Fux2Pack2
|
129
|
+
};
|
130
|
+
|
131
|
+
/*
|
132
|
+
* 解码文件名
|
133
|
+
*
|
134
|
+
* @param data 文件名指针
|
135
|
+
* @param n 文件名长度
|
136
|
+
* @param magickey 解密密钥
|
137
|
+
* @return [void]
|
138
|
+
*/
|
139
|
+
void decrypt_file_name(unsigned char* data, size_t n, unsigned int magickey)
|
140
|
+
{
|
141
|
+
size_t q = n >> 2;
|
142
|
+
char r = n & MOD_4_MASK;
|
143
|
+
unsigned int* data_p = (unsigned int*)data;
|
144
|
+
for (; data_p < (unsigned int*)(data + q * 4); ++data_p) *data_p ^= magickey;
|
145
|
+
switch (r)
|
146
|
+
{
|
147
|
+
case 1 : *data_p ^= (magickey & MASK_KEY_1); break;
|
148
|
+
case 2 : *data_p ^= (magickey & MASK_KEY_2); break;
|
149
|
+
case 3 : *data_p ^= (magickey & MASK_KEY_3); break;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
/*
|
154
|
+
* 解码数据段
|
155
|
+
*
|
156
|
+
* @param data 数据段指针
|
157
|
+
* @param n 数据段长度
|
158
|
+
* @param magickey 解密密钥
|
159
|
+
* @return [void]
|
160
|
+
*/
|
161
|
+
void decrypt_file_data(unsigned char* data, size_t n, unsigned int magickey)
|
162
|
+
{
|
163
|
+
size_t q = n >> 2;
|
164
|
+
char r = n & MOD_4_MASK;
|
165
|
+
unsigned int* data_p = (unsigned int*)data;
|
166
|
+
for (; data_p < (unsigned int*)(data + q * 4); ++data_p)
|
167
|
+
{
|
168
|
+
*data_p ^= magickey;
|
169
|
+
magickey = magickey * 7 + 3;
|
170
|
+
}
|
171
|
+
switch (r)
|
172
|
+
{
|
173
|
+
case 1 : *data_p ^= (magickey & MASK_KEY_1); break;
|
174
|
+
case 2 : *data_p ^= (magickey & MASK_KEY_2); break;
|
175
|
+
case 3 : *data_p ^= (magickey & MASK_KEY_3); break;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
/*
|
180
|
+
* 处理 mkdir 错误
|
181
|
+
*
|
182
|
+
* @param dir 目录
|
183
|
+
* @return [void]
|
184
|
+
*/
|
185
|
+
void mkdir_error_handler(const char* dir)
|
186
|
+
{
|
187
|
+
rb_sys_fail(dir);
|
188
|
+
}
|
189
|
+
|
190
|
+
/*
|
191
|
+
* 处理 malloc 错误
|
192
|
+
*
|
193
|
+
* @return [void]
|
194
|
+
*/
|
195
|
+
void malloc_error_handler(void)
|
196
|
+
{
|
197
|
+
rb_sys_fail("Failed to allocate memory");
|
198
|
+
}
|
199
|
+
|
200
|
+
/*
|
201
|
+
* 处理 fopen 错误
|
202
|
+
*
|
203
|
+
* @param path 文件路径
|
204
|
+
* @return [void]
|
205
|
+
*/
|
206
|
+
void fopen_error_handler(const char* path)
|
207
|
+
{
|
208
|
+
rb_sys_fail(path);
|
209
|
+
}
|
210
|
+
|
211
|
+
/*
|
212
|
+
* 处理 fseek 错误
|
213
|
+
*
|
214
|
+
* @param path 文件路径
|
215
|
+
* @return [void]
|
216
|
+
*/
|
217
|
+
void fseek_error_handler(const char* path)
|
218
|
+
{
|
219
|
+
rb_sys_fail(path);
|
220
|
+
}
|
221
|
+
|
222
|
+
/*
|
223
|
+
* 处理 ftell 错误
|
224
|
+
*
|
225
|
+
* @param path 文件路径
|
226
|
+
* @return [void]
|
227
|
+
*/
|
228
|
+
void ftell_error_handler(const char* path)
|
229
|
+
{
|
230
|
+
rb_sys_fail(path);
|
231
|
+
}
|
232
|
+
|
233
|
+
/*
|
234
|
+
* 处理 fread 错误
|
235
|
+
*
|
236
|
+
* @param path 文件路径
|
237
|
+
* @return [void]
|
238
|
+
*/
|
239
|
+
void fread_error_handler(const char* path)
|
240
|
+
{
|
241
|
+
rb_sys_fail(path);
|
242
|
+
}
|
243
|
+
|
244
|
+
/*
|
245
|
+
* 处理 fwrite 错误
|
246
|
+
*
|
247
|
+
* @param path 文件路径
|
248
|
+
* @return [void]
|
249
|
+
*/
|
250
|
+
void fwrite_error_handler(const char* path)
|
251
|
+
{
|
252
|
+
rb_sys_fail(path);
|
253
|
+
}
|
254
|
+
|
255
|
+
/*
|
256
|
+
* 处理 fclose 错误
|
257
|
+
*
|
258
|
+
* @param path 文件路径
|
259
|
+
* @return [void]
|
260
|
+
*/
|
261
|
+
void fclose_error_handler(const char* path)
|
262
|
+
{
|
263
|
+
rb_sys_fail(path);
|
264
|
+
}
|
265
|
+
|
266
|
+
/*
|
267
|
+
* 解码 Game.rgss3a 文件中的 rvdata2 数据
|
268
|
+
*
|
269
|
+
* @param target_path Game.rgss3a 文件路径
|
270
|
+
* @param output_dir 输出目录
|
271
|
+
* @param verbose 是否输出详细信息
|
272
|
+
* @raise [RGSS3AFileError] 未知的 RGSS3A 文件加密类型
|
273
|
+
* @raise [SystemCallError] 系统调用失败
|
274
|
+
* @return [void]
|
275
|
+
*/
|
276
|
+
VALUE r3exs_rgss3a_rvdata2(VALUE self, VALUE target_path, VALUE output_dir, VALUE verbose)
|
277
|
+
{
|
278
|
+
bool verbose_bool = RTEST(verbose);
|
279
|
+
// 首先将 Ruby 的 VALUE 转换为 C 的字符串
|
280
|
+
char* target_path_C = StringValueCStr(target_path);
|
281
|
+
char* output_dir_C = StringValueCStr(output_dir);
|
282
|
+
|
283
|
+
// 创建 output_dir
|
284
|
+
#ifdef _WIN32
|
285
|
+
if (utf8towc(output_dir_C, strlen(output_dir_C)) == -1)
|
286
|
+
{
|
287
|
+
free(wchar_arr);
|
288
|
+
utf8towc_error_handler();
|
289
|
+
}
|
290
|
+
if (_wmkdir(wchar_arr) == -1 && errno != EEXIST)
|
291
|
+
{
|
292
|
+
free(wchar_arr);
|
293
|
+
mkdir_error_handler(output_dir_C);
|
294
|
+
}
|
295
|
+
#endif
|
296
|
+
#ifdef __linux__
|
297
|
+
if (mkdir(output_dir_C, 0755) == -1 && errno != EEXIST)
|
298
|
+
{
|
299
|
+
free(char_arr);
|
300
|
+
mkdir_error_handler(output_dir_C);
|
301
|
+
}
|
302
|
+
#endif
|
303
|
+
|
304
|
+
// 打开文件
|
305
|
+
#ifdef _WIN32
|
306
|
+
if (utf8towc(target_path_C, strlen(target_path_C)) == -1)
|
307
|
+
{
|
308
|
+
free(wchar_arr);
|
309
|
+
utf8towc_error_handler();
|
310
|
+
}
|
311
|
+
FILE* Rgss3a_file = _wfopen(wchar_arr, L"rb");
|
312
|
+
if (!Rgss3a_file)
|
313
|
+
{
|
314
|
+
free(wchar_arr);
|
315
|
+
fopen_error_handler(target_path_C);
|
316
|
+
}
|
317
|
+
#endif
|
318
|
+
#ifdef __linux__
|
319
|
+
FILE* Rgss3a_file = fopen(target_path_C, "rb");
|
320
|
+
if (!Rgss3a_file)
|
321
|
+
{
|
322
|
+
free(char_arr);
|
323
|
+
fopen_error_handler(target_path_C);
|
324
|
+
}
|
325
|
+
#endif
|
326
|
+
|
327
|
+
// 获取文件大小
|
328
|
+
if (fseek(Rgss3a_file, 0, SEEK_END) == -1)
|
329
|
+
{
|
330
|
+
#ifdef _WIN32
|
331
|
+
free(wchar_arr);
|
332
|
+
#endif
|
333
|
+
#ifdef __linux__
|
334
|
+
free(char_arr);
|
335
|
+
#endif
|
336
|
+
if (fclose(Rgss3a_file) == EOF)
|
337
|
+
fclose_error_handler(target_path_C);
|
338
|
+
fseek_error_handler(target_path_C);
|
339
|
+
}
|
340
|
+
long int Rgss3a_file_size = ftell(Rgss3a_file);
|
341
|
+
if (Rgss3a_file_size == -1)
|
342
|
+
{
|
343
|
+
#ifdef _WIN32
|
344
|
+
free(wchar_arr);
|
345
|
+
#endif
|
346
|
+
#ifdef __linux__
|
347
|
+
free(char_arr);
|
348
|
+
#endif
|
349
|
+
if (fclose(Rgss3a_file) == EOF)
|
350
|
+
fclose_error_handler(target_path_C);
|
351
|
+
ftell_error_handler(target_path_C);
|
352
|
+
}
|
353
|
+
if (fseek(Rgss3a_file, 0, SEEK_SET) == -1)
|
354
|
+
{
|
355
|
+
#ifdef _WIN32
|
356
|
+
free(wchar_arr);
|
357
|
+
#endif
|
358
|
+
#ifdef __linux__
|
359
|
+
free(char_arr);
|
360
|
+
#endif
|
361
|
+
if (fclose(Rgss3a_file) == EOF)
|
362
|
+
fclose_error_handler(target_path_C);
|
363
|
+
fseek_error_handler(target_path_C);
|
364
|
+
}
|
365
|
+
|
366
|
+
// 分配内存
|
367
|
+
unsigned char* Rgss3a_data = (unsigned char*)malloc(sizeof(unsigned char) * Rgss3a_file_size);
|
368
|
+
if (!Rgss3a_data)
|
369
|
+
{
|
370
|
+
#ifdef _WIN32
|
371
|
+
free(wchar_arr);
|
372
|
+
#endif
|
373
|
+
#ifdef __linux__
|
374
|
+
free(char_arr);
|
375
|
+
#endif
|
376
|
+
if (fclose(Rgss3a_file) == EOF)
|
377
|
+
fclose_error_handler(target_path_C);
|
378
|
+
malloc_error_handler();
|
379
|
+
}
|
380
|
+
|
381
|
+
// 把整个文件读到内存中
|
382
|
+
size_t result = fread(Rgss3a_data, sizeof(unsigned char), Rgss3a_file_size, Rgss3a_file);
|
383
|
+
if (result < Rgss3a_file_size)
|
384
|
+
{
|
385
|
+
#ifdef _WIN32
|
386
|
+
free(wchar_arr);
|
387
|
+
#endif
|
388
|
+
#ifdef __linux__
|
389
|
+
free(char_arr);
|
390
|
+
#endif
|
391
|
+
free(Rgss3a_data);
|
392
|
+
if (fclose(Rgss3a_file) == EOF)
|
393
|
+
fclose_error_handler(target_path_C);
|
394
|
+
fread_error_handler(target_path_C);
|
395
|
+
}
|
396
|
+
|
397
|
+
// 关闭文件
|
398
|
+
if (fclose(Rgss3a_file) == EOF)
|
399
|
+
fclose_error_handler(target_path_C);
|
400
|
+
#ifdef _WIN32
|
401
|
+
if (verbose_bool)
|
402
|
+
printf("\e[2K\e[32mReaded \e[0m%ls\n", wchar_arr);
|
403
|
+
#endif
|
404
|
+
#ifdef __linux__
|
405
|
+
if (verbose_bool)
|
406
|
+
printf("\e[2K\e[32mReaded \e[0m%s\n", target_path_C);
|
407
|
+
#endif
|
408
|
+
|
409
|
+
// 设置文件指针索引
|
410
|
+
unsigned char* Rgss3a_p = Rgss3a_data;
|
411
|
+
|
412
|
+
// 判断加密类型
|
413
|
+
enum RGSSAD_DECRYPT_TYPE decrypt_type;
|
414
|
+
if (memcmp(Rgss3a_p, "RGSSAD\x00\x03", 8) == 0)
|
415
|
+
{
|
416
|
+
decrypt_type = RGSSAD;
|
417
|
+
}
|
418
|
+
else if (memcmp(Rgss3a_p, "Fux2Pack", 8) == 0)
|
419
|
+
{
|
420
|
+
decrypt_type = Fux2Pack2;
|
421
|
+
}
|
422
|
+
else
|
423
|
+
{
|
424
|
+
#ifdef _WIN32
|
425
|
+
free(wchar_arr);
|
426
|
+
#endif
|
427
|
+
#ifdef __linux__
|
428
|
+
free(char_arr);
|
429
|
+
#endif
|
430
|
+
// 不支持的 RGSS3A 加密格式
|
431
|
+
free(Rgss3a_data);
|
432
|
+
VALUE error_message = rb_sprintf("Unknown RGSS3A file decrypted type: %+" PRIsVALUE, target_path);
|
433
|
+
VALUE exception = rb_funcall(r3exs_RGSS3AFileError_class, r3exs_new_id, 1, error_message);
|
434
|
+
rb_exc_raise(exception);
|
435
|
+
}
|
436
|
+
|
437
|
+
// 读取 MagicKey
|
438
|
+
Rgss3a_p += 8;
|
439
|
+
unsigned int magickey;
|
440
|
+
switch (decrypt_type)
|
441
|
+
{
|
442
|
+
case RGSSAD :
|
443
|
+
magickey = *(unsigned int*)Rgss3a_p * 9 + 3;
|
444
|
+
break;
|
445
|
+
case Fux2Pack2 :
|
446
|
+
magickey = *(unsigned int*)Rgss3a_p;
|
447
|
+
break;
|
448
|
+
}
|
449
|
+
Rgss3a_p += 4;
|
450
|
+
|
451
|
+
while (1)
|
452
|
+
{
|
453
|
+
// 读取数据段偏移量
|
454
|
+
unsigned int data_offset = *(unsigned int*)Rgss3a_p ^ magickey;
|
455
|
+
if (data_offset == 0) break;
|
456
|
+
Rgss3a_p += 4;
|
457
|
+
|
458
|
+
// 读取数据段长度
|
459
|
+
unsigned int data_size = *(unsigned int*)Rgss3a_p ^ magickey;
|
460
|
+
Rgss3a_p += 4;
|
461
|
+
|
462
|
+
// 读取数据段 magicKey
|
463
|
+
unsigned int data_magickey = *(unsigned int*)Rgss3a_p ^ magickey;
|
464
|
+
Rgss3a_p += 4;
|
465
|
+
|
466
|
+
// 读取文件名长度
|
467
|
+
unsigned int filename_size = *(unsigned int*)Rgss3a_p ^ magickey;
|
468
|
+
Rgss3a_p += 4;
|
469
|
+
|
470
|
+
// 解码文件名
|
471
|
+
if (verbose_bool)
|
472
|
+
printf("\e[34mDecrypting DataName...\r");
|
473
|
+
decrypt_file_name(Rgss3a_p, filename_size, magickey);
|
474
|
+
|
475
|
+
// 将文件名中的 '\\' 替换为 '/'
|
476
|
+
for (unsigned int i = 0; i < filename_size; ++i)
|
477
|
+
{
|
478
|
+
if (Rgss3a_p[i] == '\\')
|
479
|
+
Rgss3a_p[i] = '/';
|
480
|
+
}
|
481
|
+
|
482
|
+
// 读取文件名
|
483
|
+
#ifdef _WIN32
|
484
|
+
if (utf8towc((char*)Rgss3a_p, filename_size) == -1)
|
485
|
+
{
|
486
|
+
free(wchar_arr);
|
487
|
+
free(Rgss3a_data);
|
488
|
+
utf8towc_error_handler();
|
489
|
+
}
|
490
|
+
#endif
|
491
|
+
#ifdef __linux__
|
492
|
+
if (utf8tomb((char*)Rgss3a_p, filename_size) == -1)
|
493
|
+
{
|
494
|
+
free(char_arr);
|
495
|
+
free(Rgss3a_data);
|
496
|
+
utf8tomb_error_handler();
|
497
|
+
}
|
498
|
+
#endif
|
499
|
+
|
500
|
+
// 解码数据段
|
501
|
+
#ifdef _WIN32
|
502
|
+
if (verbose_bool)
|
503
|
+
printf("\e[2K\e[32mDecrypting \e[0m%ls \e[0mOffset: \e[35m%u \e[0mSize: \e[35m%u \e[0mMagicKey: \e[35m%u\e[0m...\r", wchar_arr, data_offset, data_size, data_magickey);
|
504
|
+
#endif
|
505
|
+
#ifdef __linux__
|
506
|
+
if (verbose_bool)
|
507
|
+
printf("\e[2K\e[32mDecrypting \e[0m%s \e[0mOffset: \e[35m%u \e[0mSize: \e[35m%u \e[0mMagicKey: \e[35m%u\e[0m...\r", char_arr, data_offset, data_size, data_magickey);
|
508
|
+
#endif
|
509
|
+
decrypt_file_data(Rgss3a_data + data_offset, data_size, data_magickey);
|
510
|
+
#ifdef _WIN32
|
511
|
+
if (verbose_bool)
|
512
|
+
printf("\e[2K\e[32mDecrypted \e[0m%ls \e[0mOffset: \e[35m%u \e[0mSize: \e[35m%u \e[0mMagicKey: \e[35m%u\e[0m\n", wchar_arr, data_offset, data_size, data_magickey);
|
513
|
+
#endif
|
514
|
+
#ifdef __linux__
|
515
|
+
if (verbose_bool)
|
516
|
+
printf("\e[2K\e[32mDecrypted \e[0m%s \e[0mOffset: \e[35m%u \e[0mSize: \e[35m%u \e[0mMagicKey: \e[35m%u\e[0m\n", char_arr, data_offset, data_size, data_magickey);
|
517
|
+
#endif
|
518
|
+
|
519
|
+
// 写入解密后的数据到文件
|
520
|
+
// 先将 output_dir 和文件名拼接得到 output_full_path
|
521
|
+
// 再通过 File.dirname(output_full_path) 获得 output_full_dir
|
522
|
+
// 最后通过 FileUtils.mkdir_p(output_full_dir) 递归创建目录
|
523
|
+
VALUE output_full_path = rb_funcall(r3exs_File_module, r3exs_join_id, 2, output_dir, rb_utf8_str_new(Rgss3a_p, filename_size));
|
524
|
+
VALUE output_full_dir = rb_funcall(r3exs_File_module, r3exs_dirname_id, 1, output_full_path);
|
525
|
+
char* output_full_path_C = StringValueCStr(output_full_path);
|
526
|
+
// 创建目录
|
527
|
+
rb_funcall(r3exs_FileUtils_module, r3exs_mkdir_p_id, 1, output_full_dir);
|
528
|
+
|
529
|
+
#ifdef _WIN32
|
530
|
+
utf8towc(output_full_path_C, strlen(output_full_path_C));
|
531
|
+
if (verbose_bool)
|
532
|
+
printf("\e[34mWriting \e[0m%ls...\r", wchar_arr);
|
533
|
+
FILE* output_file = _wfopen(wchar_arr, L"wb");
|
534
|
+
if (!output_file)
|
535
|
+
{
|
536
|
+
free(wchar_arr);
|
537
|
+
free(Rgss3a_data);
|
538
|
+
fopen_error_handler(output_full_path_C);
|
539
|
+
}
|
540
|
+
#endif
|
541
|
+
#ifdef __linux__
|
542
|
+
if (verbose_bool)
|
543
|
+
printf("\e[34mWriting \e[0m%s...\r", output_full_path_C);
|
544
|
+
FILE* output_file = fopen(output_full_path_C, "wb");
|
545
|
+
if (!output_file)
|
546
|
+
{
|
547
|
+
free(char_arr);
|
548
|
+
free(Rgss3a_data);
|
549
|
+
fopen_error_handler(output_full_path_C);
|
550
|
+
}
|
551
|
+
#endif
|
552
|
+
// 写入文件
|
553
|
+
result = fwrite(Rgss3a_data + data_offset, sizeof(unsigned char), data_size, output_file);
|
554
|
+
if (result < data_size)
|
555
|
+
{
|
556
|
+
#ifdef _WIN32
|
557
|
+
free(wchar_arr);
|
558
|
+
#endif
|
559
|
+
#ifdef __linux__
|
560
|
+
free(char_arr);
|
561
|
+
#endif
|
562
|
+
free(Rgss3a_data);
|
563
|
+
if (fclose(output_file) == EOF)
|
564
|
+
fclose_error_handler(output_full_path_C);
|
565
|
+
fwrite_error_handler(output_full_path_C);
|
566
|
+
}
|
567
|
+
if (fclose(output_file) == EOF)
|
568
|
+
fclose_error_handler(output_full_path_C);
|
569
|
+
#ifdef _WIN32
|
570
|
+
if (verbose_bool)
|
571
|
+
printf("\e[2K\e[32mWrited \e[0m%ls\n", wchar_arr);
|
572
|
+
#endif
|
573
|
+
#ifdef __linux__
|
574
|
+
if (verbose_bool)
|
575
|
+
printf("\e[2K\e[32mWrited \e[0m%s\n", output_full_path_C);
|
576
|
+
#endif
|
577
|
+
Rgss3a_p += filename_size;
|
578
|
+
}
|
579
|
+
|
580
|
+
#ifdef _WIN32
|
581
|
+
free(wchar_arr);
|
582
|
+
#endif
|
583
|
+
#ifdef __linux__
|
584
|
+
free(char_arr);
|
585
|
+
#endif
|
586
|
+
free(Rgss3a_data);
|
587
|
+
return Qnil;
|
588
|
+
}
|
589
|
+
|
590
|
+
/*
|
591
|
+
* 初始化 R3EXS 模块方法 rgss3a_rvdata2
|
592
|
+
*
|
593
|
+
* @return [void]
|
594
|
+
*/
|
595
|
+
void Init_rgss3a_rvdata2()
|
596
|
+
{
|
597
|
+
// 定义 R3EXS 模块
|
598
|
+
R3EXS = rb_define_module("R3EXS");
|
599
|
+
// 定义 ID
|
600
|
+
r3exs_RGSS3AFileError_id = rb_intern("RGSS3AFileError");
|
601
|
+
r3exs_File_id = rb_intern("File");
|
602
|
+
r3exs_FileUtils_id = rb_intern("FileUtils");
|
603
|
+
r3exs_Dir_id = rb_intern("Dir");
|
604
|
+
r3exs_join_id = rb_intern("join");
|
605
|
+
r3exs_dirname_id = rb_intern("dirname");
|
606
|
+
r3exs_exist_id = rb_intern("exist?");
|
607
|
+
r3exs_mkdir_p_id = rb_intern("mkdir_p");
|
608
|
+
|
609
|
+
// 定义模块和类
|
610
|
+
r3exs_RGSS3AFileError_class = rb_const_get(R3EXS, r3exs_RGSS3AFileError_id);
|
611
|
+
r3exs_File_module = rb_const_get(rb_cObject, r3exs_File_id);
|
612
|
+
r3exs_FileUtils_module = rb_const_get(rb_cObject, r3exs_FileUtils_id);
|
613
|
+
r3exs_Dir_module = rb_const_get(rb_cObject, r3exs_Dir_id);
|
614
|
+
// 定义 rgss3a_rvdata2 方法
|
615
|
+
rb_define_singleton_method(R3EXS, "rgss3a_rvdata2", r3exs_rgss3a_rvdata2, 3);
|
616
|
+
}
|