mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-03 01:22:19 +00:00
8114309e89
* use static_assert directly. Raze is C++17, no need for that macro shit. * removed CONSTEXPR - I seriously fail to see the use here, many of the functions marked as CONSTEXPR cannot possibly even be constant evaluated so the declaration makes no sense. Removed most of these and replaced the valid ones with the official constexpr keyword. * got rid of EDUKE_PREDICT_FALSE - this makes zero sense in script parsing code, at best it will save a few microseconds. Clean code wins. * replaced Blrintf with xs_CRoundToInt. Shitty name is shitty name, even if derived from POSIX. * replaced Bstr*casecmp with str*icmp. As these get defined in the CMake project based on actual compiler checks they are preferable here. * removed lots of other stuff that is not needed with a minimum compiler requirement of C++17.
963 lines
25 KiB
C++
963 lines
25 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
|
|
This file is part of NBlood.
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
#include "compat.h"
|
|
#include "common_game.h"
|
|
#include "misc.h"
|
|
#include "globals.h"
|
|
#include "sound.h"
|
|
#include "filesystem.h"
|
|
|
|
BEGIN_BLD_NS
|
|
|
|
// I don't think we still need these.
|
|
#define DICT_LOAD 0
|
|
#define DICT_LOCK 0
|
|
|
|
#define kMaxCmdLineDefines 5
|
|
#define kMaxDefines 1000
|
|
#define kMaxParseLevels 5
|
|
static int nCmdDefines = 0;
|
|
static int nDefines = 0;
|
|
|
|
static int gParseLevel = 0;
|
|
int dword_44CE0[kMaxParseLevels] = { 0, 0, 0, 0, 0 };
|
|
|
|
// FIXME
|
|
unsigned int nBytes = 0;
|
|
char buffer[1024];
|
|
int scriptValue = 0;
|
|
|
|
char scriptBuffer[256];
|
|
|
|
struct define_t
|
|
{
|
|
FString _text;
|
|
int _value;
|
|
};
|
|
|
|
define_t gCmdDefines[kMaxCmdLineDefines];
|
|
|
|
void addMemoryResource(char *fileName, char flags, int ID);
|
|
|
|
struct tag_t {
|
|
const char *_value;
|
|
uint8_t _index;
|
|
};
|
|
|
|
enum eTags
|
|
{
|
|
kTag0,
|
|
kTagEnd,
|
|
kTagString,
|
|
kTagConstant,
|
|
kTag4, // string constant?
|
|
kTagComma,
|
|
kTagSemiColon,
|
|
kTagColon,
|
|
kTagEquals,
|
|
kTagHash,
|
|
kTagComment,
|
|
kTagInclude,
|
|
kTagResource,
|
|
kTagAs,
|
|
kTagPreload,
|
|
kTagPrelock,
|
|
kTagData,
|
|
kTagLoad,
|
|
kTagEmit,
|
|
kTagIfDef,
|
|
kTagEndif,
|
|
kTagElse
|
|
};
|
|
|
|
tag_t tags[] =
|
|
{
|
|
{ ",", kTagComma },
|
|
{ ";", kTagSemiColon },
|
|
{ ":", kTagColon },
|
|
{ "=", kTagEquals },
|
|
{ "#", kTagHash },
|
|
{ "//", kTagComment },
|
|
{ "INCLUDE", kTagInclude },
|
|
{ "RESOURCE", kTagResource },
|
|
{ "AS", kTagAs },
|
|
{ "PRELOAD", kTagPreload },
|
|
{ "PRELOCK", kTagPrelock },
|
|
{ "DATA", kTagData },
|
|
{ "LOAD", kTagLoad },
|
|
{ "EMIT", kTagEmit },
|
|
{ "%ifdef", kTagIfDef },
|
|
{ "%endif", kTagEndif },
|
|
{ "%else", kTagElse }
|
|
};
|
|
|
|
const int kTagCount = sizeof(tags) / sizeof(tag_t);
|
|
|
|
int qsort_compar(const void *a, const void *b)
|
|
{
|
|
return stricmp((const char*)a, (const char*)b);
|
|
}
|
|
|
|
void SortTags()
|
|
{
|
|
qsort(tags, kTagCount, sizeof(tag_t), qsort_compar);
|
|
}
|
|
|
|
void AddCmdDefine(char *text, int value)
|
|
{
|
|
dassert(nCmdDefines < kMaxCmdLineDefines);
|
|
|
|
gCmdDefines[nCmdDefines]._text = text;
|
|
gCmdDefines[nCmdDefines]._value = value;
|
|
|
|
nCmdDefines++;
|
|
}
|
|
|
|
static void SplitPath(const char *pzPath, char *pzDirectory, char *pzFile, char *pzType)
|
|
{
|
|
int const nLength = strlen(pzPath);
|
|
const char *pDirectory = pzPath+nLength;
|
|
const char *pDot = NULL;
|
|
for (int i = nLength-1; i >= 0; i--)
|
|
{
|
|
if (pzPath[i] == '/' || pzPath[i] == '\\')
|
|
{
|
|
strncpy(pzDirectory, pzPath, i);
|
|
pzDirectory[i] = 0;
|
|
if (!pDot)
|
|
{
|
|
strcpy(pzFile, pzPath+i+1);
|
|
strcpy(pzType, "");
|
|
}
|
|
else
|
|
{
|
|
strncpy(pzFile, pzPath+i+1, pDot-(pzPath+i+1));
|
|
pzFile[pDot-(pzPath+i+1)] = 0;
|
|
strcpy(pzType, pDot+1);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if (pzPath[i] == '.')
|
|
{
|
|
pDot = pzPath+i;
|
|
}
|
|
}
|
|
strcpy(pzDirectory, "/");
|
|
if (!pDot)
|
|
{
|
|
strcpy(pzFile, pzPath);
|
|
strcpy(pzType, "");
|
|
}
|
|
else
|
|
{
|
|
strncpy(pzFile, pzPath, pDot-pzPath);
|
|
pzFile[pDot-pzPath] = 0;
|
|
strcpy(pzType, pDot+1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 174 bytes
|
|
struct RFS
|
|
{
|
|
private:
|
|
TArray<char> buffer;
|
|
char *_ptr; // [0]
|
|
char _curChar; // [4]
|
|
char *_pUnknown2; // [5] - some sort of pointer into _ptr?
|
|
char *_pStartLine; // [9]
|
|
char *_pEnd; // [13]
|
|
char *_pMark; // [17]
|
|
char _unknown6; // [21]
|
|
int _unknown7; // [22]
|
|
int _curLine; // [26]
|
|
char _fileName[BMAX_PATH]; // [30]
|
|
|
|
public:
|
|
int Open(int lumpnum);
|
|
void Close();
|
|
void Increment();
|
|
void SkipBeyondValue(char value);
|
|
uint8_t GetNextTag();
|
|
void ScriptError(const char *message);
|
|
void SetMark();
|
|
void UnsetMark();
|
|
};
|
|
|
|
int RFS::Open(int lumpnum)
|
|
{
|
|
auto hFile = fileSystem.OpenFileReader(lumpnum);
|
|
if (!hFile.isOpen()) {
|
|
Printf("BARF: Error opening file %d", lumpnum);
|
|
return 1;
|
|
}
|
|
|
|
int fileSize = hFile.GetLength();
|
|
buffer.Resize(fileSize);
|
|
_ptr = buffer.Data();
|
|
if (_ptr == NULL) {
|
|
Printf("BARF: Not enough memory to read %d", lumpnum);
|
|
return 1;
|
|
}
|
|
|
|
hFile.Read(_ptr, fileSize);
|
|
|
|
_curLine = 0;
|
|
_pUnknown2 = _ptr;
|
|
_curChar = '\n';
|
|
_pEnd = &_ptr[fileSize - 1];
|
|
|
|
return 0;
|
|
}
|
|
|
|
void RFS::Close()
|
|
{
|
|
}
|
|
|
|
void RFS::Increment()
|
|
{
|
|
if (_curChar == '\n') {
|
|
_curLine++;
|
|
_pStartLine = _pUnknown2;
|
|
}
|
|
|
|
if (_pUnknown2 >= _pEnd) {
|
|
_curChar = 0;
|
|
}
|
|
else {
|
|
_curChar = *_pUnknown2; // grabs the next char
|
|
_pUnknown2++; // increment pointer into char data
|
|
}
|
|
}
|
|
|
|
void RFS::SkipBeyondValue(char nVal)
|
|
{
|
|
while (_curChar && _curChar != nVal) {
|
|
Increment();
|
|
}
|
|
}
|
|
|
|
void RFS::SetMark()
|
|
{
|
|
_pMark = _pUnknown2;
|
|
_unknown6 = _curChar;
|
|
_unknown7 = _curLine;
|
|
}
|
|
|
|
// inverse of the above function
|
|
void RFS::UnsetMark()
|
|
{
|
|
_pUnknown2 = _pMark;
|
|
_curChar = _unknown6;
|
|
_curLine = _unknown7;
|
|
}
|
|
|
|
void RFS::ScriptError(const char *message)
|
|
{
|
|
// TODO
|
|
TArray<char> msg;
|
|
|
|
char *p = _pStartLine;
|
|
while (*p != '\n')
|
|
{
|
|
if (isprint(*p))
|
|
msg.Push(*p);
|
|
else
|
|
msg.Push(' ');
|
|
p++;
|
|
}
|
|
|
|
msg.Push('\n');
|
|
|
|
p = _pStartLine;
|
|
|
|
while (p < _pMark)
|
|
{
|
|
msg.Push(' ');
|
|
p++;
|
|
}
|
|
|
|
msg.Push('^');
|
|
msg.Push(0);
|
|
|
|
Printf("Error in %s line %d: %s\n\n%s", _fileName, _curLine, message, msg.Data());
|
|
}
|
|
|
|
uint8_t RFS::GetNextTag()
|
|
{
|
|
// skip any space characters
|
|
do {
|
|
Increment();
|
|
} while (isspace(_curChar));
|
|
|
|
if (_curChar == '\0') {
|
|
return kTagEnd;
|
|
}
|
|
|
|
SetMark();
|
|
|
|
// Path A
|
|
if (_curChar == '"')
|
|
{
|
|
Increment();
|
|
|
|
int i = 0;
|
|
|
|
// section 1
|
|
while (1) {
|
|
|
|
if (_curChar == '\0' || _curChar == '"') {
|
|
scriptBuffer[i] = '\0';
|
|
return kTagString;
|
|
}
|
|
|
|
if (i == 256) {
|
|
ScriptError("String exceeds maximum string length");
|
|
break;
|
|
}
|
|
|
|
scriptBuffer[i] = _curChar;
|
|
i++;
|
|
Increment();
|
|
}
|
|
|
|
// section 2
|
|
while (1)
|
|
{
|
|
if (_curChar == '\0' || _curChar == '"') {
|
|
return kTag0;
|
|
}
|
|
|
|
Increment();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
scriptValue = 0;
|
|
bool isNegative = false; // or 'isSigned' ?
|
|
|
|
// is it a negative number?
|
|
if (_curChar == '-')
|
|
{
|
|
Increment();
|
|
|
|
isNegative = true;
|
|
|
|
if (!isdigit(_curChar)) {
|
|
UnsetMark();
|
|
}
|
|
}
|
|
|
|
if (isdigit(_curChar))
|
|
{
|
|
// left path
|
|
if (_curChar == '0')
|
|
{
|
|
Increment();
|
|
|
|
// handle a hex value
|
|
if (toupper(_curChar) == 'X')
|
|
{
|
|
// orange loop
|
|
while (1)
|
|
{
|
|
Increment();
|
|
if (!isxdigit(_curChar)) { // isxdigit() checks for a hex value
|
|
break;
|
|
}
|
|
|
|
// hex version of atoi?
|
|
scriptValue *= 16;
|
|
if (!isdigit(_curChar)) {
|
|
scriptValue += toupper(_curChar) - 55;
|
|
}
|
|
else {
|
|
scriptValue += _curChar - '0';
|
|
}
|
|
|
|
SetMark();
|
|
}
|
|
|
|
UnsetMark();
|
|
if (isNegative) {
|
|
scriptValue = -scriptValue;
|
|
}
|
|
|
|
return kTagConstant;
|
|
}
|
|
|
|
UnsetMark();
|
|
}
|
|
|
|
// the loop
|
|
while (isdigit(_curChar))
|
|
{
|
|
// atoi implementation
|
|
scriptValue = scriptValue * 10 + _curChar - '0';
|
|
SetMark();
|
|
Increment();
|
|
}
|
|
|
|
UnsetMark();
|
|
if (isNegative) {
|
|
scriptValue = -scriptValue;
|
|
}
|
|
|
|
return kTagConstant;
|
|
}
|
|
else
|
|
{
|
|
// BLUEISH PATH
|
|
int ebp = 0; // v11
|
|
int i = 0;
|
|
|
|
// blue loop #1
|
|
while (1)
|
|
{
|
|
scriptBuffer[ebp] = _curChar;
|
|
ebp++;
|
|
int eax = -1;
|
|
|
|
// blue loop #2
|
|
for (i = 0; i < kTagCount; i++)
|
|
{
|
|
//if (eax >= 0) {
|
|
if (eax == 0) {
|
|
break;
|
|
}
|
|
|
|
// eax = strnicmp(tags[i]._value, scriptBuffer, ebp);
|
|
eax = strnicmp(scriptBuffer, tags[i]._value, ebp);
|
|
|
|
//if (eax >= 0) {
|
|
if (eax == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (eax > 0 || i == kTagCount) {
|
|
break;
|
|
}
|
|
|
|
if (eax == 0 && strlen(tags[i]._value) == ebp)
|
|
{
|
|
scriptBuffer[ebp] = 0;
|
|
return tags[i]._index;
|
|
}
|
|
|
|
Increment();
|
|
}
|
|
|
|
UnsetMark();
|
|
|
|
i = 0;
|
|
|
|
while (isalnum(_curChar))
|
|
{
|
|
scriptBuffer[i] = _curChar;
|
|
SetMark();
|
|
i++;
|
|
Increment();
|
|
}
|
|
|
|
UnsetMark();
|
|
scriptBuffer[i] = 0;
|
|
return kTag4;
|
|
}
|
|
}
|
|
|
|
// qAssert(1==0); // TODO - what to return here
|
|
}
|
|
|
|
void ParseScript(int lumpnum)
|
|
{
|
|
char text[256];
|
|
char char256_1[256];
|
|
char char256_2[256];
|
|
char fileName[BMAX_PATH];
|
|
char inp[BMAX_PATH];
|
|
//char zScriptDirectory[BMAX_PATH], zTemp1[BMAX_PATH], zTemp2[BMAX_PATH];
|
|
|
|
//SplitPath(scriptFileName, zScriptDirectory, zTemp1, zTemp2);
|
|
|
|
RFS rfs;
|
|
|
|
// AddExtension(name, ".RFS");
|
|
if (rfs.Open(lumpnum))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gParseLevel = 0;
|
|
dword_44CE0[0] = 0;
|
|
|
|
bool parsing = true;
|
|
|
|
while (parsing)
|
|
{
|
|
// START LOOP. to be fixed later
|
|
START:
|
|
|
|
uint8_t tag = rfs.GetNextTag();
|
|
|
|
switch (tag)
|
|
{
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
case kTagEnd:
|
|
{
|
|
parsing = false;
|
|
break;
|
|
}
|
|
case kTagComment:
|
|
{
|
|
// skip to next line
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
case kTagEmit: // minty/light green colour
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTag4)
|
|
{
|
|
rfs.ScriptError("Symbol name expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
strcpy(char256_2, scriptBuffer);
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTagEquals)
|
|
{
|
|
rfs.ScriptError("Missing '='");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTagConstant)
|
|
{
|
|
rfs.ScriptError("Constant expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//AddDefine(char256_2, scriptValue);
|
|
rfs.SkipBeyondValue('\n');
|
|
}
|
|
}
|
|
}
|
|
case kTagResource: // really light blue..
|
|
{
|
|
if (kTagString != rfs.GetNextTag()) {
|
|
rfs.ScriptError("String constant exected");
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
|
|
strcpy(inp, scriptBuffer);
|
|
char nFlags = 0;
|
|
int ID = 0;
|
|
bool isDefine = false;
|
|
|
|
tag = rfs.GetNextTag();
|
|
if (tag == kTagAs)
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag == kTag4)
|
|
{
|
|
strcpy(text, scriptBuffer);
|
|
|
|
if (rfs.GetNextTag() != kTagEquals)
|
|
{
|
|
rfs.ScriptError("Missing '='");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
|
|
isDefine = true;
|
|
tag = rfs.GetNextTag();
|
|
}
|
|
|
|
if (tag != kTagConstant)
|
|
{
|
|
rfs.ScriptError("Constant expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
|
|
if (isDefine) {
|
|
//AddDefine(text, scriptValue);
|
|
}
|
|
|
|
ID = scriptValue;
|
|
tag = rfs.GetNextTag();
|
|
}
|
|
|
|
//if (!bNoEncrypt) {
|
|
// nFlags |= kResFlagIsEncrypted;
|
|
//}
|
|
|
|
while (tag == kTagComma)
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
|
|
if (tag == kTagPreload) {
|
|
nFlags |= DICT_LOAD;
|
|
}
|
|
else if (tag == kTagPrelock) {
|
|
nFlags |= DICT_LOCK;
|
|
}
|
|
else {
|
|
rfs.ScriptError("Unrecognized flag");
|
|
rfs.SkipBeyondValue(';');
|
|
goto START; // FIXME
|
|
}
|
|
|
|
tag = rfs.GetNextTag();
|
|
}
|
|
|
|
if (tag != kTagSemiColon)
|
|
{
|
|
rfs.ScriptError("';' expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
|
|
if (dword_44CE0[gParseLevel] == 0)
|
|
{
|
|
// In the RFS files I have seen the outermost directory is not part of what goes into the file system.
|
|
auto inp1 = strchr(inp, '\\');
|
|
if (!inp1 || !fileSystem.CreatePathlessCopy(inp1 + 1, ID, nFlags))
|
|
{
|
|
// I'll activate this when I find evidence that it is needed. Otherwise the risk of picking up unwanted data is too high.
|
|
//fileSystem.CreatePathlessCopy(inp, ID, nFlags);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case kTagIfDef: // purplish colour
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTag4)
|
|
{
|
|
rfs.ScriptError("Parameter error in ifdef");
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
rfs.SetMark();
|
|
strcpy(char256_1, scriptBuffer);
|
|
|
|
bool bGotDefine = false;
|
|
|
|
// check if this was defined via command prompt arguments
|
|
for (int i = 0; i < nCmdDefines; i++)
|
|
{
|
|
if (stricmp(gCmdDefines[i]._text, char256_1) == 0) { // string is equivalent
|
|
bGotDefine = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// loc_11FC3:
|
|
gParseLevel++;
|
|
dassert(gParseLevel < kMaxParseLevels);
|
|
|
|
if (bGotDefine) {
|
|
dword_44CE0[gParseLevel] = dword_44CE0[gParseLevel - 1];
|
|
}
|
|
else {
|
|
dword_44CE0[gParseLevel] = 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case kTagElse: // pinky colour
|
|
{
|
|
if (gParseLevel)
|
|
{
|
|
// loc_12066:
|
|
if (dword_44CE0[gParseLevel - 1] == 0) {
|
|
if (dword_44CE0[gParseLevel] == 0) {
|
|
dword_44CE0[gParseLevel] = 1;
|
|
}
|
|
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
rfs.ScriptError("Unexpected else");
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case kTagEndif: // poo coloured
|
|
{
|
|
if (gParseLevel) {
|
|
gParseLevel--;
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
rfs.ScriptError("Unexpected Endif");
|
|
rfs.SkipBeyondValue('\n');
|
|
break;
|
|
}
|
|
}
|
|
case kTagHash: // gold colour
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag == kTagInclude)
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTagString)
|
|
{
|
|
rfs.ScriptError("String constant exected");
|
|
// why no SkipBeyondValue?
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// too dangerous if we want to cumulatively collect all RFS files
|
|
//fileSystem.Rehash();
|
|
//ParseScript(scriptBuffer);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case kTagData: // eg: data "AMB1.SFX" as 1: 80, 0x10000, 0x0, 1, -1, "amb1";
|
|
{
|
|
// green coloured section
|
|
if (rfs.GetNextTag() != kTagString) {
|
|
rfs.ScriptError("String constant expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
|
|
// eg strcpy(fileName, "AMB1.SFX");
|
|
strcpy(fileName, scriptBuffer);
|
|
|
|
char nFlags = 0;
|
|
int ID = 0;
|
|
|
|
bool isDefine = false;
|
|
|
|
tag = rfs.GetNextTag();
|
|
|
|
// process an ID section
|
|
if (tag == kTagAs)
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag == kTag4)
|
|
{
|
|
strcpy(fileName, scriptBuffer);
|
|
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTagEquals) {
|
|
rfs.ScriptError("Missing '='");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
|
|
isDefine = true;
|
|
tag = rfs.GetNextTag();
|
|
}
|
|
|
|
if (tag != kTagConstant)
|
|
{
|
|
rfs.ScriptError("Constant Expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
else {
|
|
//if (isDefine) {
|
|
// AddDefine(fileName, scriptValue);
|
|
//}
|
|
|
|
ID = scriptValue;
|
|
tag = rfs.GetNextTag();
|
|
}
|
|
}
|
|
|
|
if (tag == kTagComma)
|
|
{
|
|
// process all sections on this line that are comma separated
|
|
while (1)
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
if (tag == kTagPreload)
|
|
{
|
|
nFlags |= DICT_LOAD;
|
|
tag = rfs.GetNextTag();
|
|
|
|
if (tag == kTagComma) {
|
|
continue;
|
|
}
|
|
}
|
|
else if (tag == kTagPrelock)
|
|
{
|
|
nFlags |= DICT_LOCK;
|
|
tag = rfs.GetNextTag();
|
|
|
|
if (tag == kTagComma) {
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rfs.ScriptError("Unrecognized flag");
|
|
rfs.SkipBeyondValue(';');
|
|
goto START; // FIXME
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_12471:
|
|
if (tag != kTagColon) // marked orange in IDA
|
|
{
|
|
while (1)
|
|
{
|
|
if (tag == kTagPreload)
|
|
{
|
|
nFlags |= DICT_LOAD;
|
|
tag = rfs.GetNextTag();
|
|
|
|
if (tag == kTagColon) {
|
|
break;
|
|
}
|
|
}
|
|
else if (tag == kTagPrelock)
|
|
{
|
|
nFlags |= DICT_LOCK;
|
|
tag = rfs.GetNextTag();
|
|
|
|
if (tag == kTagColon) {
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
rfs.ScriptError("':' expected");
|
|
rfs.SkipBeyondValue(';');
|
|
goto START; // FIXME
|
|
}
|
|
}
|
|
}
|
|
|
|
nBytes = 0;
|
|
|
|
// yellow loop
|
|
while (1)
|
|
{
|
|
tag = rfs.GetNextTag();
|
|
|
|
switch (tag)
|
|
{
|
|
case kTagString:
|
|
{
|
|
memcpy(&buffer[nBytes], scriptBuffer, strlen(scriptBuffer) + 1);
|
|
nBytes += strlen(scriptBuffer) + 1;
|
|
break;
|
|
}
|
|
case kTagConstant:
|
|
{
|
|
memcpy(&buffer[nBytes], &scriptValue, sizeof(scriptValue));
|
|
nBytes += sizeof(scriptValue);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
rfs.ScriptError("Constant expected");
|
|
rfs.SkipBeyondValue(';');
|
|
goto START; // FIXME
|
|
}
|
|
}
|
|
|
|
tag = rfs.GetNextTag();
|
|
if (tag != kTagComma) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tag != kTagSemiColon) {
|
|
rfs.ScriptError("Semicolon expected");
|
|
rfs.SkipBeyondValue(';');
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (dword_44CE0[gParseLevel] == 0) {
|
|
addMemoryResource(fileName, nFlags, ID);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//CreateHeader();
|
|
rfs.Close();
|
|
}
|
|
|
|
void addMemoryResource(char* filePath, char flags, int ID)
|
|
{
|
|
char zDirectory[BMAX_PATH];
|
|
char zFilename[BMAX_PATH];
|
|
char zType[BMAX_PATH];
|
|
|
|
SplitPath(filePath, zDirectory, zFilename, zType);
|
|
|
|
fileSystem.AddFromBuffer(zFilename, zType, buffer, nBytes, ID, flags);
|
|
}
|
|
|
|
|
|
void ReadAllRFS()
|
|
{
|
|
bool found = false;
|
|
auto numf = fileSystem.GetNumEntries();
|
|
for (int i = 0; i < numf; i++)
|
|
{
|
|
auto rl = fileSystem.GetResourceType(i);
|
|
if (!stricmp(rl, "RFS"))
|
|
{
|
|
ParseScript(i);
|
|
found = true;
|
|
}
|
|
}
|
|
if (found) fileSystem.InitHashChains();
|
|
}
|
|
END_BLD_NS
|