2019-09-19 06:06:11 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2019-09-19 06:06:11 +00:00
|
|
|
#include "compat.h"
|
2020-12-09 14:56:32 +00:00
|
|
|
#include "blood.h"
|
2020-04-11 21:54:33 +00:00
|
|
|
#include "filesystem.h"
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2020-04-11 21:54:33 +00:00
|
|
|
// I don't think we still need these.
|
2020-10-11 10:18:25 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
DICT_LOAD = 0,
|
|
|
|
DICT_LOCK = 0,
|
|
|
|
|
|
|
|
kMaxCmdLineDefines = 5,
|
|
|
|
kMaxDefines = 1000,
|
|
|
|
kMaxParseLevels = 5
|
|
|
|
};
|
2019-09-19 06:06:11 +00:00
|
|
|
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
|
|
|
|
{
|
2019-10-31 19:17:49 +00:00
|
|
|
FString _text;
|
2019-09-19 06:06:11 +00:00
|
|
|
int _value;
|
|
|
|
};
|
|
|
|
|
|
|
|
define_t gCmdDefines[kMaxCmdLineDefines];
|
|
|
|
|
2019-11-02 09:20:32 +00:00
|
|
|
void addMemoryResource(char *fileName, char flags, int ID);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2020-09-04 19:24:48 +00:00
|
|
|
return stricmp((const char*)a, (const char*)b);
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SortTags()
|
|
|
|
{
|
|
|
|
qsort(tags, kTagCount, sizeof(tag_t), qsort_compar);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddCmdDefine(char *text, int value)
|
|
|
|
{
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(nCmdDefines < kMaxCmdLineDefines);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2019-10-31 19:17:49 +00:00
|
|
|
gCmdDefines[nCmdDefines]._text = text;
|
2019-09-19 06:06:11 +00:00
|
|
|
gCmdDefines[nCmdDefines]._value = value;
|
|
|
|
|
|
|
|
nCmdDefines++;
|
|
|
|
}
|
|
|
|
|
2020-09-01 17:49:05 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-09-19 06:06:11 +00:00
|
|
|
// 174 bytes
|
|
|
|
struct RFS
|
|
|
|
{
|
|
|
|
private:
|
2019-10-31 19:17:49 +00:00
|
|
|
TArray<char> buffer;
|
2019-09-19 06:06:11 +00:00
|
|
|
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:
|
2020-01-22 20:09:45 +00:00
|
|
|
int Open(int lumpnum);
|
2019-09-19 06:06:11 +00:00
|
|
|
void Close();
|
|
|
|
void Increment();
|
|
|
|
void SkipBeyondValue(char value);
|
|
|
|
uint8_t GetNextTag();
|
|
|
|
void ScriptError(const char *message);
|
|
|
|
void SetMark();
|
|
|
|
void UnsetMark();
|
|
|
|
};
|
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
int RFS::Open(int lumpnum)
|
2019-09-19 06:06:11 +00:00
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
auto hFile = fileSystem.OpenFileReader(lumpnum);
|
2019-10-21 15:16:08 +00:00
|
|
|
if (!hFile.isOpen()) {
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("BARF: Error opening file %d", lumpnum);
|
2019-09-22 08:16:16 +00:00
|
|
|
return 1;
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 15:16:08 +00:00
|
|
|
int fileSize = hFile.GetLength();
|
2019-10-31 19:17:49 +00:00
|
|
|
buffer.Resize(fileSize);
|
|
|
|
_ptr = buffer.Data();
|
2019-09-19 06:06:11 +00:00
|
|
|
if (_ptr == NULL) {
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("BARF: Not enough memory to read %d", lumpnum);
|
2019-09-22 08:16:16 +00:00
|
|
|
return 1;
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 15:16:08 +00:00
|
|
|
hFile.Read(_ptr, fileSize);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
_curLine = 0;
|
|
|
|
_pUnknown2 = _ptr;
|
|
|
|
_curChar = '\n';
|
|
|
|
_pEnd = &_ptr[fileSize - 1];
|
2019-09-22 08:16:16 +00:00
|
|
|
|
|
|
|
return 0;
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-01-22 20:09:45 +00:00
|
|
|
TArray<char> msg;
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
char *p = _pStartLine;
|
|
|
|
while (*p != '\n')
|
|
|
|
{
|
|
|
|
if (isprint(*p))
|
2020-01-22 20:09:45 +00:00
|
|
|
msg.Push(*p);
|
2019-09-19 06:06:11 +00:00
|
|
|
else
|
2020-01-22 20:09:45 +00:00
|
|
|
msg.Push(' ');
|
2019-09-19 06:06:11 +00:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
msg.Push('\n');
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
p = _pStartLine;
|
|
|
|
|
|
|
|
while (p < _pMark)
|
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
msg.Push(' ');
|
2019-09-19 06:06:11 +00:00
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
msg.Push('^');
|
|
|
|
msg.Push(0);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("Error in %s line %d: %s\n\n%s", _fileName, _curLine, message, msg.Data());
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-09-20 06:52:29 +00:00
|
|
|
bool isNegative = false; // or 'isSigned' ?
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
// is it a negative number?
|
|
|
|
if (_curChar == '-')
|
|
|
|
{
|
|
|
|
Increment();
|
|
|
|
|
2019-09-20 06:52:29 +00:00
|
|
|
isNegative = true;
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
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);
|
2020-09-04 19:24:48 +00:00
|
|
|
eax = strnicmp(scriptBuffer, tags[i]._value, ebp);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
//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
|
|
|
|
}
|
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
void ParseScript(int lumpnum)
|
2019-09-19 06:06:11 +00:00
|
|
|
{
|
|
|
|
char text[256];
|
|
|
|
char char256_1[256];
|
|
|
|
char char256_2[256];
|
|
|
|
char fileName[BMAX_PATH];
|
|
|
|
char inp[BMAX_PATH];
|
2020-01-22 20:09:45 +00:00
|
|
|
//char zScriptDirectory[BMAX_PATH], zTemp1[BMAX_PATH], zTemp2[BMAX_PATH];
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
//SplitPath(scriptFileName, zScriptDirectory, zTemp1, zTemp2);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
RFS rfs;
|
|
|
|
|
|
|
|
// AddExtension(name, ".RFS");
|
2020-01-22 20:09:45 +00:00
|
|
|
if (rfs.Open(lumpnum))
|
2019-09-22 08:16:16 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
gParseLevel = 0;
|
|
|
|
dword_44CE0[0] = 0;
|
|
|
|
|
2019-09-20 06:52:29 +00:00
|
|
|
bool parsing = true;
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
while (parsing)
|
|
|
|
{
|
|
|
|
// START LOOP. to be fixed later
|
|
|
|
START:
|
|
|
|
|
|
|
|
uint8_t tag = rfs.GetNextTag();
|
|
|
|
|
|
|
|
switch (tag)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case kTagEnd:
|
|
|
|
{
|
2019-09-22 08:16:16 +00:00
|
|
|
parsing = false;
|
2019-09-19 06:06:11 +00:00
|
|
|
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;
|
2019-09-20 06:52:29 +00:00
|
|
|
bool isDefine = false;
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-09-20 06:52:29 +00:00
|
|
|
isDefine = true;
|
2019-09-19 06:06:11 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-02 09:20:32 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-09-20 06:52:29 +00:00
|
|
|
bool bGotDefine = false;
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
// check if this was defined via command prompt arguments
|
|
|
|
for (int i = 0; i < nCmdDefines; i++)
|
|
|
|
{
|
2020-09-04 19:24:48 +00:00
|
|
|
if (stricmp(gCmdDefines[i]._text, char256_1) == 0) { // string is equivalent
|
2019-09-20 06:52:29 +00:00
|
|
|
bGotDefine = true;
|
2019-09-19 06:06:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// loc_11FC3:
|
|
|
|
gParseLevel++;
|
2020-10-11 10:38:17 +00:00
|
|
|
assert(gParseLevel < kMaxParseLevels);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
// too dangerous if we want to cumulatively collect all RFS files
|
|
|
|
//fileSystem.Rehash();
|
|
|
|
//ParseScript(scriptBuffer);
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2019-09-20 06:52:29 +00:00
|
|
|
bool isDefine = false;
|
2019-09-19 06:06:11 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-09-20 06:52:29 +00:00
|
|
|
isDefine = true;
|
2019-09-19 06:06:11 +00:00
|
|
|
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
|
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (tag == kTagPreload)
|
2019-09-19 06:06:11 +00:00
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
nFlags |= DICT_LOAD;
|
|
|
|
tag = rfs.GetNextTag();
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
if (tag == kTagColon) {
|
|
|
|
break;
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
2020-01-22 20:09:45 +00:00
|
|
|
}
|
|
|
|
else if (tag == kTagPrelock)
|
|
|
|
{
|
|
|
|
nFlags |= DICT_LOCK;
|
|
|
|
tag = rfs.GetNextTag();
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
if (tag == kTagColon) {
|
|
|
|
break;
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-22 20:09:45 +00:00
|
|
|
else {
|
|
|
|
rfs.ScriptError("':' expected");
|
|
|
|
rfs.SkipBeyondValue(';');
|
|
|
|
goto START; // FIXME
|
|
|
|
}
|
|
|
|
}
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nBytes = 0;
|
|
|
|
|
|
|
|
// yellow loop
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
tag = rfs.GetNextTag();
|
|
|
|
|
|
|
|
switch (tag)
|
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
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
|
|
|
|
}
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tag = rfs.GetNextTag();
|
|
|
|
if (tag != kTagComma) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tag != kTagSemiColon) {
|
|
|
|
rfs.ScriptError("Semicolon expected");
|
|
|
|
rfs.SkipBeyondValue(';');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dword_44CE0[gParseLevel] == 0) {
|
2019-11-02 09:20:32 +00:00
|
|
|
addMemoryResource(fileName, nFlags, ID);
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//CreateHeader();
|
|
|
|
rfs.Close();
|
|
|
|
}
|
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
void addMemoryResource(char* filePath, char flags, int ID)
|
2019-09-19 06:06:11 +00:00
|
|
|
{
|
2020-01-22 20:09:45 +00:00
|
|
|
char zDirectory[BMAX_PATH];
|
2019-09-19 06:06:11 +00:00
|
|
|
char zFilename[BMAX_PATH];
|
|
|
|
char zType[BMAX_PATH];
|
|
|
|
|
2019-09-22 08:16:16 +00:00
|
|
|
SplitPath(filePath, zDirectory, zFilename, zType);
|
2019-09-19 06:06:11 +00:00
|
|
|
|
2019-11-02 09:20:32 +00:00
|
|
|
fileSystem.AddFromBuffer(zFilename, zType, buffer, nBytes, ID, flags);
|
2019-09-19 06:06:11 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 20:09:45 +00:00
|
|
|
|
|
|
|
void ReadAllRFS()
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
auto numf = fileSystem.GetNumEntries();
|
|
|
|
for (int i = 0; i < numf; i++)
|
|
|
|
{
|
|
|
|
auto rl = fileSystem.GetResourceType(i);
|
2020-04-11 21:54:33 +00:00
|
|
|
if (!stricmp(rl, "RFS"))
|
2020-01-22 20:09:45 +00:00
|
|
|
{
|
|
|
|
ParseScript(i);
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
2020-04-11 21:54:33 +00:00
|
|
|
if (found) fileSystem.InitHashChains();
|
2020-01-22 20:09:45 +00:00
|
|
|
}
|
2019-09-22 06:39:22 +00:00
|
|
|
END_BLD_NS
|