Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-1-2-2013-Decompilation
Path: blob/main/RSDKv4/Reader.cpp
817 views
1
#include "RetroEngine.hpp"
2
#include <string>
3
4
RSDKContainer rsdkContainer;
5
6
char fileName[0x100];
7
byte fileBuffer[0x2000];
8
int fileSize = 0;
9
int vFileSize = 0;
10
int readPos = 0;
11
int readSize = 0;
12
int bufferPosition = 0;
13
int virtualFileOffset = 0;
14
bool useEncryption = false;
15
byte packID = 0;
16
byte eStringPosA;
17
byte eStringPosB;
18
byte eStringNo;
19
byte eNybbleSwap;
20
byte encryptionStringA[0x10];
21
byte encryptionStringB[0x10];
22
23
FileIO *cFileHandle = nullptr;
24
25
bool CheckRSDKFile(const char *filePath)
26
{
27
FileInfo info;
28
29
char filePathBuffer[0x100];
30
#if RETRO_PLATFORM == RETRO_OSX
31
char pathBuf[0x100];
32
sprintf(pathBuf, "%s/%s", gamePath, filePath);
33
sprintf(filePathBuffer, "%s", pathBuf);
34
#else
35
sprintf(filePathBuffer, "%s", filePath);
36
#endif
37
38
cFileHandle = fOpen(filePathBuffer, "rb");
39
if (cFileHandle) {
40
byte signature[6] = { 'R', 'S', 'D', 'K', 'v', 'B' };
41
byte buf = 0;
42
for (int i = 0; i < 6; ++i) {
43
fRead(&buf, 1, 1, cFileHandle);
44
if (buf != signature[i])
45
return false;
46
}
47
48
Engine.usingDataFile = true;
49
#if !RETRO_USE_ORIGINAL_CODE
50
Engine.usingDataFile_Config = true;
51
#endif
52
53
StrCopy(rsdkContainer.packNames[rsdkContainer.packCount], filePathBuffer);
54
55
byte b[4];
56
fRead(&b, 2, 1, cFileHandle);
57
ushort fileCount = (b[1] << 8) | (b[0] << 0);
58
for (int f = 0; f < fileCount; ++f) {
59
for (int y = 0; y < 4; ++y) {
60
fRead(b, 1, 4, cFileHandle);
61
rsdkContainer.files[f].hash[y] = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0);
62
}
63
64
fRead(b, 4, 1, cFileHandle);
65
rsdkContainer.files[f].offset = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0);
66
fRead(b, 4, 1, cFileHandle);
67
rsdkContainer.files[f].filesize = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0);
68
69
rsdkContainer.files[f].encrypted = (rsdkContainer.files[f].filesize & 0x80000000);
70
rsdkContainer.files[f].filesize &= 0x7FFFFFFF;
71
72
rsdkContainer.files[f].packID = rsdkContainer.packCount;
73
74
rsdkContainer.fileCount++;
75
}
76
77
fClose(cFileHandle);
78
cFileHandle = NULL;
79
if (LoadFile("Bytecode/GlobalCode.bin", &info)) {
80
Engine.usingBytecode = true;
81
CloseFile();
82
}
83
PrintLog("loaded datapack '%s'", filePathBuffer);
84
85
rsdkContainer.packCount++;
86
return true;
87
}
88
else {
89
Engine.usingDataFile = false;
90
#if !RETRO_USE_ORIGINAL_CODE
91
Engine.usingDataFile_Config = false;
92
#endif
93
cFileHandle = NULL;
94
95
if (LoadFile("Bytecode/GlobalCode.bin", &info)) {
96
Engine.usingBytecode = true;
97
CloseFile();
98
}
99
PrintLog("Couldn't load datapack '%s'", filePathBuffer);
100
return false;
101
}
102
}
103
104
#if !RETRO_USE_ORIGINAL_CODE
105
int CheckFileInfo(const char *filepath)
106
{
107
char pathBuf[0x100];
108
StrCopy(pathBuf, filepath);
109
uint hash[4];
110
int len = StrLength(pathBuf);
111
GenerateMD5FromString(pathBuf, len, &hash[0], &hash[1], &hash[2], &hash[3]);
112
113
for (int f = 0; f < rsdkContainer.fileCount; ++f) {
114
RSDKFileInfo *file = &rsdkContainer.files[f];
115
116
bool match = true;
117
for (int h = 0; h < 4; ++h) {
118
if (hash[h] != file->hash[h]) {
119
match = false;
120
break;
121
}
122
}
123
if (!match)
124
continue;
125
126
return f;
127
}
128
return -1;
129
}
130
131
inline bool ends_with(std::string const &value, std::string const &ending)
132
{
133
if (ending.size() > value.size())
134
return false;
135
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
136
}
137
#endif
138
139
bool LoadFile(const char *filePath, FileInfo *fileInfo)
140
{
141
MEM_ZEROP(fileInfo);
142
143
if (cFileHandle)
144
fClose(cFileHandle);
145
146
char filePathBuf[0x100];
147
StrCopy(filePathBuf, filePath);
148
bool forceFolder = false;
149
#if RETRO_USE_MOD_LOADER
150
// Fixes ".ani" ".Ani" bug and any other case differences
151
char pathLower[0x100];
152
memset(pathLower, 0, sizeof(char) * 0x100);
153
for (int c = 0; c < strlen(filePathBuf); ++c) {
154
pathLower[c] = tolower(filePathBuf[c]);
155
}
156
157
bool addPath = true;
158
int m = activeMod != -1 ? activeMod : 0;
159
for (; m < modList.size(); ++m) {
160
if (modList[m].active) {
161
std::map<std::string, std::string>::const_iterator iter = modList[m].fileMap.find(pathLower);
162
if (iter != modList[m].fileMap.cend()) {
163
StrCopy(filePathBuf, iter->second.c_str());
164
forceFolder = true;
165
addPath = false;
166
break;
167
}
168
}
169
if (activeMod != -1)
170
break;
171
}
172
173
if (forceUseScripts && !forceFolder) {
174
if (std::string(filePathBuf).rfind("Data/Scripts/", 0) == 0 && ends_with(std::string(filePathBuf), "txt")) {
175
// is a script, since those dont exist normally, load them from "scripts/"
176
forceFolder = true;
177
Engine.usingDataFile = false;
178
addPath = true;
179
std::string fStr = std::string(filePathBuf);
180
fStr.erase(fStr.begin(), fStr.begin() + 5); // remove "Data/"
181
StrCopy(filePathBuf, fStr.c_str());
182
}
183
}
184
#endif
185
186
#if RETRO_PLATFORM == RETRO_OSX || RETRO_PLATFORM == RETRO_ANDROID
187
#if RETRO_USE_MOD_LOADER
188
if (addPath) {
189
#else
190
if (true) {
191
#endif
192
char pathBuf[0x100];
193
sprintf(pathBuf, "%s/%s", gamePath, filePathBuf);
194
sprintf(filePathBuf, "%s", pathBuf);
195
}
196
#endif
197
198
cFileHandle = NULL;
199
#if !RETRO_USE_ORIGINAL_CODE
200
StringLowerCase(fileInfo->fileName, filePath);
201
StrCopy(fileName, fileInfo->fileName);
202
203
int fileIndex = CheckFileInfo(fileName);
204
if (fileIndex != -1 && !forceFolder) {
205
RSDKFileInfo *file = &rsdkContainer.files[fileIndex];
206
packID = file->packID;
207
cFileHandle = fOpen(rsdkContainer.packNames[file->packID], "rb");
208
if (cFileHandle) {
209
fSeek(cFileHandle, 0, SEEK_END);
210
fileSize = (int)fTell(cFileHandle);
211
212
vFileSize = file->filesize;
213
virtualFileOffset = file->offset;
214
readPos = file->offset;
215
readSize = 0;
216
bufferPosition = 0;
217
fSeek(cFileHandle, virtualFileOffset, SEEK_SET);
218
219
useEncryption = file->encrypted;
220
memset(fileInfo->encryptionStringA, 0, 0x10 * sizeof(byte));
221
memset(fileInfo->encryptionStringB, 0, 0x10 * sizeof(byte));
222
if (useEncryption) {
223
GenerateELoadKeys(vFileSize, (vFileSize >> 1) + 1);
224
eStringNo = (vFileSize & 0x1FC) >> 2;
225
eStringPosA = 0;
226
eStringPosB = 8;
227
eNybbleSwap = 0;
228
memcpy(fileInfo->encryptionStringA, encryptionStringA, 0x10 * sizeof(byte));
229
memcpy(fileInfo->encryptionStringB, encryptionStringB, 0x10 * sizeof(byte));
230
}
231
232
fileInfo->readPos = readPos;
233
fileInfo->fileSize = fileSize;
234
fileInfo->vfileSize = vFileSize;
235
fileInfo->virtualFileOffset = virtualFileOffset;
236
fileInfo->eStringNo = eStringNo;
237
fileInfo->eStringPosB = eStringPosB;
238
fileInfo->eStringPosA = eStringPosA;
239
fileInfo->eNybbleSwap = eNybbleSwap;
240
fileInfo->bufferPosition = bufferPosition;
241
fileInfo->useEncryption = useEncryption;
242
fileInfo->packID = packID;
243
fileInfo->usingDataPack = true;
244
PrintLog("Loaded Data File '%s'", filePath);
245
246
Engine.usingDataFile = true;
247
248
return true;
249
}
250
#else
251
if (Engine.usingDataFile) {
252
StringLowerCase(fileInfo->fileName, filePath);
253
StrCopy(fileName, fileInfo->fileName);
254
uint hash[4];
255
int len = StrLength(fileInfo->fileName);
256
GenerateMD5FromString(fileInfo->fileName, len, &hash[0], &hash[1], &hash[2], &hash[3]);
257
258
for (int f = 0; f < rsdkContainer.fileCount; ++f) {
259
RSDKFileInfo *file = &rsdkContainer.files[f];
260
261
bool match = true;
262
for (int h = 0; h < 4; ++h) {
263
if (hash[h] != file->hash[h]) {
264
match = false;
265
break;
266
}
267
}
268
if (!match)
269
continue;
270
271
packID = file->packID;
272
cFileHandle = fOpen(rsdkContainer.packNames[file->packID], "rb");
273
if (cFileHandle) {
274
fSeek(cFileHandle, 0, SEEK_END);
275
fileSize = (int)fTell(cFileHandle);
276
277
vFileSize = file->filesize;
278
virtualFileOffset = file->offset;
279
readPos = file->offset;
280
readSize = 0;
281
bufferPosition = 0;
282
fSeek(cFileHandle, virtualFileOffset, SEEK_SET);
283
284
useEncryption = file->encrypted;
285
memset(fileInfo->encryptionStringA, 0, 0x10 * sizeof(byte));
286
memset(fileInfo->encryptionStringB, 0, 0x10 * sizeof(byte));
287
if (useEncryption) {
288
GenerateELoadKeys(vFileSize, (vFileSize >> 1) + 1);
289
eStringNo = (vFileSize & 0x1FC) >> 2;
290
eStringPosA = 0;
291
eStringPosB = 8;
292
eNybbleSwap = 0;
293
memcpy(fileInfo->encryptionStringA, encryptionStringA, 0x10 * sizeof(byte));
294
memcpy(fileInfo->encryptionStringB, encryptionStringB, 0x10 * sizeof(byte));
295
}
296
297
fileInfo->readPos = readPos;
298
fileInfo->fileSize = fileSize;
299
fileInfo->vfileSize = vFileSize;
300
fileInfo->virtualFileOffset = virtualFileOffset;
301
fileInfo->eStringNo = eStringNo;
302
fileInfo->eStringPosB = eStringPosB;
303
fileInfo->eStringPosA = eStringPosA;
304
fileInfo->eNybbleSwap = eNybbleSwap;
305
fileInfo->bufferPosition = bufferPosition;
306
fileInfo->useEncryption = useEncryption;
307
fileInfo->packID = packID;
308
fileInfo->usingDataPack = true;
309
PrintLog("Loaded Data File '%s'", filePath);
310
311
return true;
312
}
313
else {
314
break;
315
}
316
}
317
#endif
318
PrintLog("Couldn't load file '%s'", filePath);
319
return false;
320
}
321
else {
322
StrCopy(fileInfo->fileName, filePathBuf);
323
StrCopy(fileName, fileInfo->fileName);
324
325
cFileHandle = fOpen(fileInfo->fileName, "rb");
326
if (!cFileHandle) {
327
PrintLog("Couldn't load file '%s'", filePath);
328
return false;
329
}
330
virtualFileOffset = 0;
331
fSeek(cFileHandle, 0, SEEK_END);
332
fileInfo->fileSize = (int)fTell(cFileHandle);
333
fileSize = fileInfo->vfileSize = fileInfo->fileSize;
334
fSeek(cFileHandle, 0, SEEK_SET);
335
readPos = 0;
336
fileInfo->readPos = readPos;
337
packID = fileInfo->packID = -1;
338
fileInfo->usingDataPack = false;
339
bufferPosition = 0;
340
readSize = 0;
341
useEncryption = false;
342
343
#if !RETRO_USE_ORIGINAL_CODE
344
Engine.usingDataFile = false;
345
#endif
346
347
PrintLog("Loaded File '%s'", filePath);
348
return true;
349
}
350
}
351
352
void GenerateELoadKeys(uint key1, uint key2)
353
{
354
char buffer[0x20];
355
uint hash[0x4];
356
357
// StringA
358
ConvertIntegerToString(buffer, key1);
359
int len = StrLength(buffer);
360
GenerateMD5FromString(buffer, len, &hash[0], &hash[1], &hash[2], &hash[3]);
361
362
#if !RETRO_USE_ORIGINAL_CODE
363
for (int i = 0; i < 4; ++i)
364
for (int j = 0; j < 4; ++j) encryptionStringA[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;
365
#else
366
for (int y = 0; y < 0x10; y += 4) {
367
encryptionStringA[y + 3] = hash[y + 0];
368
encryptionStringA[y + 2] = hash[y + 1];
369
encryptionStringA[y + 1] = hash[y + 2];
370
encryptionStringA[y + 0] = hash[y + 3];
371
}
372
#endif
373
374
// StringB
375
ConvertIntegerToString(buffer, key2);
376
len = StrLength(buffer);
377
GenerateMD5FromString(buffer, len, &hash[0], &hash[1], &hash[2], &hash[3]);
378
379
#if !RETRO_USE_ORIGINAL_CODE
380
for (int i = 0; i < 4; ++i)
381
for (int j = 0; j < 4; ++j) encryptionStringB[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;
382
#else
383
for (int y = 0; y < 0x10; y += 4) {
384
encryptionStringB[y + 3] = hash[y + 0];
385
encryptionStringB[y + 2] = hash[y + 1];
386
encryptionStringB[y + 1] = hash[y + 2];
387
encryptionStringB[y + 0] = hash[y + 3];
388
}
389
#endif
390
}
391
392
const uint ENC_KEY_2 = 0x24924925;
393
const uint ENC_KEY_1 = 0xAAAAAAAB;
394
int mulUnsignedHigh(uint arg1, int arg2) { return (int)(((unsigned long long)arg1 * (unsigned long long)arg2) >> 32); }
395
396
void FileRead(void *dest, int size)
397
{
398
byte *data = (byte *)dest;
399
memset(data, 0, size);
400
401
if (readPos <= fileSize) {
402
if (useEncryption) {
403
while (size > 0) {
404
if (bufferPosition == readSize)
405
FillFileBuffer();
406
407
*data = encryptionStringB[eStringPosB] ^ eStringNo ^ fileBuffer[bufferPosition++];
408
if (eNybbleSwap)
409
*data = ((*data << 4) + (*data >> 4)) & 0xFF;
410
*data ^= encryptionStringA[eStringPosA];
411
412
++eStringPosA;
413
++eStringPosB;
414
if (eStringPosA <= 0x0F) {
415
if (eStringPosB > 0x0C) {
416
eStringPosB = 0;
417
eNybbleSwap ^= 0x01;
418
}
419
}
420
else if (eStringPosB <= 0x08) {
421
eStringPosA = 0;
422
eNybbleSwap ^= 0x01;
423
}
424
else {
425
eStringNo += 2;
426
eStringNo &= 0x7F;
427
428
if (eNybbleSwap != 0) {
429
int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);
430
int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);
431
eNybbleSwap = 0;
432
433
int temp1 = key2 + (eStringNo - key2) / 2;
434
int temp2 = key1 / 8 * 3;
435
436
eStringPosA = eStringNo - temp1 / 4 * 7;
437
eStringPosB = eStringNo - temp2 * 4 + 2;
438
}
439
else {
440
int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);
441
int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);
442
eNybbleSwap = 1;
443
444
int temp1 = key2 + (eStringNo - key2) / 2;
445
int temp2 = key1 / 8 * 3;
446
447
eStringPosB = eStringNo - temp1 / 4 * 7;
448
eStringPosA = eStringNo - temp2 * 4 + 3;
449
}
450
}
451
452
++data;
453
--size;
454
}
455
}
456
else {
457
while (size > 0) {
458
if (bufferPosition == readSize)
459
FillFileBuffer();
460
461
*data++ = fileBuffer[bufferPosition++];
462
size--;
463
}
464
}
465
}
466
}
467
468
void FileSkip(int count)
469
{
470
if (readPos <= fileSize) {
471
if (useEncryption) {
472
while (count > 0) {
473
if (bufferPosition == readSize)
474
FillFileBuffer();
475
bufferPosition++;
476
477
++eStringPosA;
478
++eStringPosB;
479
if (eStringPosA <= 0x0F) {
480
if (eStringPosB > 0x0C) {
481
eStringPosB = 0;
482
eNybbleSwap ^= 0x01;
483
}
484
}
485
else if (eStringPosB <= 0x08) {
486
eStringPosA = 0;
487
eNybbleSwap ^= 0x01;
488
}
489
else {
490
eStringNo += 2;
491
eStringNo &= 0x7F;
492
493
if (eNybbleSwap != 0) {
494
int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);
495
int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);
496
eNybbleSwap = 0;
497
498
int temp1 = key2 + (eStringNo - key2) / 2;
499
int temp2 = key1 / 8 * 3;
500
501
eStringPosA = eStringNo - temp1 / 4 * 7;
502
eStringPosB = eStringNo - temp2 * 4 + 2;
503
}
504
else {
505
int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);
506
int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);
507
eNybbleSwap = 1;
508
509
int temp1 = key2 + (eStringNo - key2) / 2;
510
int temp2 = key1 / 8 * 3;
511
512
eStringPosB = eStringNo - temp1 / 4 * 7;
513
eStringPosA = eStringNo - temp2 * 4 + 3;
514
}
515
}
516
517
--count;
518
}
519
}
520
else {
521
while (count > 0) {
522
if (bufferPosition == readSize)
523
FillFileBuffer();
524
bufferPosition++;
525
count--;
526
}
527
}
528
}
529
}
530
531
void GetFileInfo(FileInfo *fileInfo)
532
{
533
StrCopy(fileInfo->fileName, fileName);
534
fileInfo->bufferPosition = bufferPosition;
535
fileInfo->readPos = readPos - readSize;
536
fileInfo->fileSize = fileSize;
537
fileInfo->vfileSize = vFileSize;
538
fileInfo->virtualFileOffset = virtualFileOffset;
539
fileInfo->eStringPosA = eStringPosA;
540
fileInfo->eStringPosB = eStringPosB;
541
fileInfo->eStringNo = eStringNo;
542
fileInfo->eNybbleSwap = eNybbleSwap;
543
fileInfo->useEncryption = useEncryption;
544
fileInfo->packID = packID;
545
fileInfo->usingDataPack = Engine.usingDataFile;
546
memcpy(encryptionStringA, fileInfo->encryptionStringA, 0x10 * sizeof(byte));
547
memcpy(encryptionStringB, fileInfo->encryptionStringB, 0x10 * sizeof(byte));
548
}
549
550
void SetFileInfo(FileInfo *fileInfo)
551
{
552
#if !RETRO_USE_ORIGINAL_CODE
553
if (fileInfo->usingDataPack) {
554
#else
555
if (Engine.usingDataFile) {
556
#endif
557
cFileHandle = fOpen(rsdkContainer.packNames[fileInfo->packID], "rb");
558
if (cFileHandle) {
559
virtualFileOffset = fileInfo->virtualFileOffset;
560
vFileSize = fileInfo->vfileSize;
561
fSeek(cFileHandle, 0, SEEK_END);
562
fileSize = (int)fTell(cFileHandle);
563
readPos = fileInfo->readPos;
564
fSeek(cFileHandle, readPos, SEEK_SET);
565
FillFileBuffer();
566
bufferPosition = fileInfo->bufferPosition;
567
eStringPosA = fileInfo->eStringPosA;
568
eStringPosB = fileInfo->eStringPosB;
569
eStringNo = fileInfo->eStringNo;
570
eNybbleSwap = fileInfo->eNybbleSwap;
571
useEncryption = fileInfo->useEncryption;
572
packID = fileInfo->packID;
573
Engine.usingDataFile = fileInfo->usingDataPack;
574
575
if (useEncryption) {
576
GenerateELoadKeys(vFileSize, (vFileSize >> 1) + 1);
577
}
578
}
579
}
580
else {
581
StrCopy(fileName, fileInfo->fileName);
582
cFileHandle = fOpen(fileInfo->fileName, "rb");
583
virtualFileOffset = 0;
584
fileSize = fileInfo->fileSize;
585
readPos = fileInfo->readPos;
586
fSeek(cFileHandle, readPos, SEEK_SET);
587
FillFileBuffer();
588
bufferPosition = fileInfo->bufferPosition;
589
eStringPosA = 0;
590
eStringPosB = 0;
591
eStringNo = 0;
592
eNybbleSwap = 0;
593
useEncryption = fileInfo->useEncryption;
594
packID = fileInfo->packID;
595
Engine.usingDataFile = fileInfo->usingDataPack;
596
}
597
}
598
599
size_t GetFilePosition()
600
{
601
if (Engine.usingDataFile)
602
return bufferPosition + readPos - readSize - virtualFileOffset;
603
else
604
return bufferPosition + readPos - readSize;
605
}
606
607
void SetFilePosition(int newPos)
608
{
609
if (useEncryption) {
610
readPos = virtualFileOffset + newPos;
611
eStringNo = (vFileSize & 0x1FC) >> 2;
612
eStringPosA = 0;
613
eStringPosB = 8;
614
eNybbleSwap = false;
615
while (newPos) {
616
++eStringPosA;
617
++eStringPosB;
618
if (eStringPosA <= 0x0F) {
619
if (eStringPosB > 0x0C) {
620
eStringPosB = 0;
621
eNybbleSwap ^= 0x01;
622
}
623
}
624
else if (eStringPosB <= 0x08) {
625
eStringPosA = 0;
626
eNybbleSwap ^= 0x01;
627
}
628
else {
629
eStringNo += 2;
630
eStringNo &= 0x7F;
631
632
if (eNybbleSwap != 0) {
633
int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);
634
int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);
635
eNybbleSwap = 0;
636
637
int temp1 = key2 + (eStringNo - key2) / 2;
638
int temp2 = key1 / 8 * 3;
639
640
eStringPosA = eStringNo - temp1 / 4 * 7;
641
eStringPosB = eStringNo - temp2 * 4 + 2;
642
}
643
else {
644
int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);
645
int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);
646
eNybbleSwap = 1;
647
648
int temp1 = key2 + (eStringNo - key2) / 2;
649
int temp2 = key1 / 8 * 3;
650
651
eStringPosB = eStringNo - temp1 / 4 * 7;
652
eStringPosA = eStringNo - temp2 * 4 + 3;
653
}
654
}
655
--newPos;
656
}
657
}
658
else {
659
if (Engine.usingDataFile)
660
readPos = virtualFileOffset + newPos;
661
else
662
readPos = newPos;
663
}
664
fSeek(cFileHandle, readPos, SEEK_SET);
665
FillFileBuffer();
666
}
667
668
bool ReachedEndOfFile()
669
{
670
if (Engine.usingDataFile)
671
return bufferPosition + readPos - readSize - virtualFileOffset >= vFileSize;
672
else
673
return bufferPosition + readPos - readSize >= fileSize;
674
}
675
676