RFS parser wip

# Conflicts:
#	.gitignore
#	platform/Windows/nblood.vcxproj.filters
This commit is contained in:
nukeykt 2019-09-19 15:06:11 +09:00 committed by Christoph Oelckers
parent 9be59caef8
commit b13bdf50be
9 changed files with 1106 additions and 16 deletions

View File

@ -778,6 +778,7 @@ blood_game_objs := \
aizomba.cpp \
aizombf.cpp \
asound.cpp \
barf.cpp \
callback.cpp \
choke.cpp \
common.cpp \

View File

@ -195,6 +195,7 @@
<ClCompile Include="..\..\source\blood\src\aizomba.cpp" />
<ClCompile Include="..\..\source\blood\src\aizombf.cpp" />
<ClCompile Include="..\..\source\blood\src\asound.cpp" />
<ClCompile Include="..\..\source\blood\src\barf.cpp" />
<ClCompile Include="..\..\source\blood\src\blood.cpp" />
<ClCompile Include="..\..\source\blood\src\callback.cpp" />
<ClCompile Include="..\..\source\blood\src\choke.cpp" />
@ -299,6 +300,7 @@
<ClInclude Include="..\..\source\blood\src\aizomba.h" />
<ClInclude Include="..\..\source\blood\src\aizombf.h" />
<ClInclude Include="..\..\source\blood\src\asound.h" />
<ClInclude Include="..\..\source\blood\src\barf.h" />
<ClInclude Include="..\..\source\blood\src\blood.h" />
<ClInclude Include="..\..\source\blood\src\callback.h" />
<ClInclude Include="..\..\source\blood\src\choke.h" />

View File

@ -228,6 +228,9 @@
<ClCompile Include="..\..\source\blood\src\aiunicult.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\barf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\source\blood\rsrc\gameres.rc">
@ -457,5 +460,8 @@
<ClInclude Include="..\..\source\blood\src\aiunicult.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\barf.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

952
source/blood/src/barf.cpp Normal file
View File

@ -0,0 +1,952 @@
//-------------------------------------------------------------------------
/*
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 "compat.h"
#ifdef WITHKPLIB
#include "kplib.h"
#endif
#include "common_game.h"
#include "resource.h"
#include "misc.h"
#include "globals.h"
#include "sound.h"
static Resource gBarfRes;
#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
{
char *_text;
int _value;
};
define_t gCmdDefines[kMaxCmdLineDefines];
void sub_11DF0(char *pzScriptDir, char *fileName, char flags, int ID);
void sub_11C10(char *pzScriptDir, 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 = (char*)Resource::Alloc(strlen(text) + 1);
strcpy(gCmdDefines[nCmdDefines]._text, text);
gCmdDefines[nCmdDefines]._value = value;
nCmdDefines++;
}
// 174 bytes
struct RFS
{
private:
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:
void Open(const char *fileName);
void Close();
void Increment();
void SkipBeyondValue(char value);
uint8_t GetNextTag();
void ScriptError(const char *message);
void SetMark();
void UnsetMark();
};
void RFS::Open(const char *fileName)
{
strcpy(_fileName, fileName);
int hFile = open(_fileName, O_BINARY);
if (hFile == -1) {
ThrowError("Error opening file %s", _fileName);
}
int fileSize = filelength(hFile);
_ptr = (char*)Resource::Alloc(fileSize);
if (_ptr == NULL) {
ThrowError("Not enough memory to read %s", _fileName);
}
read(hFile, _ptr, fileSize);
close(hFile);
_curLine = 0;
_pUnknown2 = _ptr;
_curChar = '\n';
_pEnd = &_ptr[fileSize - 1];
}
void RFS::Close()
{
if (_ptr) {
/* BUG - the original code called nfree but this should be a Resource::Free()
_nfree(_ptr);
*/
Resource::Free(_ptr);
}
}
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
char *p = _pStartLine;
while (*p != '\n')
{
if (isprint(*p))
putchar(*p);
else
putchar(' ');
p++;
}
putchar('\n');
p = _pStartLine;
while (p < _pMark)
{
putchar(' ');
p++;
}
puts("^");
initprintf("Error in %s line %d: %s\n\n", _fileName, _curLine, message);
}
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(char *scriptFileName)
{
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");
rfs.Open(scriptFileName);
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;
nFlags |= DICT_ID;
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) {
sub_11C10(zScriptDirectory, inp, nFlags, ID);
}
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
{
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);
//}
nFlags |= DICT_ID;
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) {
sub_11DF0(zScriptDirectory, fileName, nFlags, ID);
}
}
break;
}
}
}
//CreateHeader();
rfs.Close();
}
void sub_11C10(char *pzScriptDir, char *fileName, char flags, int ID)
{
char zDirectory[BMAX_PATH];
char zFilename[BMAX_PATH];
char zType[BMAX_PATH];
BDIR* dirr;
struct Bdirent* dirent;
dirr = Bopendir("./");
if (dirr)
{
while (dirent = Breaddir(dirr))
{
if (!Bwildmatch(dirent->name, fileName))
continue;
SplitPath(dirent->name, zDirectory, zFilename, zType);
if (!Bstrcasecmp(zType, "RAW") || !Bstrcasecmp(zType, "SFX") || !Bstrcasecmp(zType, "MID") || !Bstrcasecmp(zType, "TMB"))
gSoundRes.AddExternalResource(zFilename, zType, ID, flags, dirent->name);
else
gSysRes.AddExternalResource(zFilename, zType, ID, flags, dirent->name);
}
Bclosedir(dirr);
}
dirr = Bopendir(pzScriptDir);
if (dirr)
{
while (dirent = Breaddir(dirr))
{
if (!Bwildmatch(dirent->name, fileName))
continue;
SplitPath(dirent->name, zDirectory, zFilename, zType);
if (!Bstrcasecmp(zType, "RAW") || !Bstrcasecmp(zType, "SFX") || !Bstrcasecmp(zType, "MID") || !Bstrcasecmp(zType, "TMB"))
gSoundRes.AddExternalResource(zFilename, zType, ID, flags, dirent->name);
else
gSysRes.AddExternalResource(zFilename, zType, ID, flags, dirent->name);
}
Bclosedir(dirr);
}
}
void sub_11DF0(char* pzScriptDir, char *filePath, char flags, int ID)
{
char zDirectory[BMAX_PATH];
char zFilename[BMAX_PATH];
char zType[BMAX_PATH];
char zFilePath[BMAX_PATH];
buildvfs_fd handle;
ConcatPath(pzScriptDir, filePath, zFilePath);
handle = kopen4loadfrommod(zFilePath, 0);
if (handle == buildvfs_fd_invalid)
{
Bstrcpy(zFilePath, filePath);
handle = kopen4loadfrommod(zFilePath, 0);
if (handle == buildvfs_fd_invalid)
return;
}
kclose(handle);
SplitPath(zFilePath, zDirectory, zFilename, zType);
if (!Bstrcasecmp(zType, "RAW") || !Bstrcasecmp(zType, "SFX") || !Bstrcasecmp(zType, "MID") || !Bstrcasecmp(zType, "TMB"))
gSoundRes.AddExternalResource(zFilename, zType, ID, flags, zFilePath);
else
gSysRes.AddExternalResource(zFilename, zType, ID, flags, zFilePath);
}

24
source/blood/src/barf.h Normal file
View File

@ -0,0 +1,24 @@
//-------------------------------------------------------------------------
/*
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.
*/
//-------------------------------------------------------------------------
#pragma once

View File

@ -131,11 +131,80 @@ void ChangeExtension(char *pzFile, const char *pzExt)
_splitpath(pzFile, drive, dir, filename, NULL);
_makepath(pzFile, drive, dir, filename, pzExt);
#else
char *pDot = strrchr(pzFile, '.');
if (!pDot)
pDot = pzFile + strlen(pzFile);
else
*pDot = 0;
strcat(pDot, pzExt);
int const nLength = Bstrlen(pzFile);
char * pDot = pzFile+nLength;
for (int i = nLength-1; i >= 0; i--)
{
if (pzFile[i] == '/' || pzFile[i] == '\\')
break;
if (pzFile[i] == '.')
{
pDot = pzFile+i;
break;
}
}
*pDot = '\0';
Bstrcat(pDot, pzExt);
#endif
}
void SplitPath(const char *pzPath, char *pzDirectory, char *pzFile, char *pzType)
{
int const nLength = Bstrlen(pzFile);
const char *pDirectory = pzFile+nLength;
const char *pDot = NULL;
for (int i = nLength-1; i >= 0; i--)
{
if (pzFile[i] == '/' || pzFile[i] == '\\')
{
Bstrncpy(pzDirectory, pzPath, i);
pzDirectory[i] = 0;
if (!pDot)
{
Bstrcpy(pzFile, pzPath+i+1);
Bstrcpy(pzType, "");
}
else
{
Bstrncpy(pzFile, pzPath+i+1, pDot-(pzPath+i+1));
Bstrcpy(pzType, pDot+1);
}
return;
}
else if (pzFile[i] == '.')
{
pDot = pzFile+i;
}
}
Bstrcpy(pzDirectory, "/");
if (!pDot)
{
Bstrcpy(pzFile, pzPath);
Bstrcpy(pzType, "");
}
else
{
Bstrncpy(pzFile, pzPath, pDot-pzPath);
Bstrcpy(pzType, pDot+1);
}
}
void ConcatPath(const char *pzPath1, const char *pzPath2, char *pzConcatPath)
{
int n1 = Bstrlen(pzPath1), n2 = Bstrlen(pzPath2);
int i = n1, j = 0;
while (i > 0 && (pzPath1[i-1] == '/' || pzPath1[i-1] == '\\'))
{
i--;
}
while (j < n2 && (pzPath2[j] == '/' || pzPath1[j] == '\\'))
{
j++;
}
Bstrncpy(pzConcatPath, pzPath1, i);
pzConcatPath[i] = 0;
Bstrcpy(pzConcatPath, pzPath2+j);
}

View File

@ -30,3 +30,5 @@ unsigned int qrand(void);
int wrand(void);
void wsrand(int);
void ChangeExtension(char *pzFile, const char *pzExt);
void SplitPath(const char *pzPath, char *pzDirectory, char *pzFile, char *pzType);
void ConcatPath(const char* pzPath1, const char* pzPath2, char* pzConcatPath);

View File

@ -68,6 +68,8 @@ Resource::~Resource(void)
Free(dict[i].type);
if (dict[i].name)
Free(dict[i].name);
if (dict[i].path)
Free(dict[i].path);
}
Free(dict);
dict = NULL;
@ -149,6 +151,7 @@ void Resource::Init(const char *filename)
dict[i].name = (char*)Alloc(nNameLength+1);
strncpy(dict[i].type, tdict[i].type, min(3, nTypeLength));
strncpy(dict[i].name, tdict[i].name, min(8, nNameLength));
dict[i].path = NULL;
dict[i].type[nTypeLength] = 0;
dict[i].name[nNameLength] = 0;
dict[i].id = B_LITTLE32(tdict[i].id);
@ -362,14 +365,20 @@ void Resource::Grow(void)
Reindex();
}
void Resource::AddExternalResource(const char *name, const char *type, int id)
void Resource::AddExternalResource(const char *name, const char *type, int id, int flags, const char *pzDirectory)
{
char name2[BMAX_PATH], type2[BMAX_PATH], filename[BMAX_PATH*2];
//if (strlen(name) > 8 || strlen(type) > 3) return;
char name2[BMAX_PATH], type2[BMAX_PATH], filename[BMAX_PATH], path[BMAX_PATH];
if (Bstrlen(type) > 0)
Bsprintf(filename, "%s.%s", name, type);
Bsnprintf(filename, BMAX_PATH-1, "%s.%s", name, type);
else
Bsprintf(filename, "%s", name);
Bsnprintf(filename, BMAX_PATH-1, "%s", name);
if (pzDirectory)
Bsnprintf(path, BMAX_PATH-1, "%s/%s", pzDirectory, filename);
else
Bstrncpy(path, filename, BMAX_PATH-1);
int fhandle = kopen4loadfrommod(filename, 0);
if (fhandle == -1)
return;
@ -404,17 +413,25 @@ void Resource::AddExternalResource(const char *name, const char *type, int id)
Free(node->name);
node->name = NULL;
}
if (node->path)
{
Free(node->path);
node->path = NULL;
}
int nTypeLength = strlen(type2);
int nNameLength = strlen(name2);
int nPathLength = strlen(path);
node->type = (char*)Alloc(nTypeLength+1);
node->name = (char*)Alloc(nNameLength+1);
node->path = (char*)Alloc(nPathLength+1);
strcpy(node->type, type2);
strcpy(node->name, name2);
strcpy(node->path, path);
}
node->size = size;
node->flags |= DICT_EXTERNAL;
node->flags |= DICT_EXTERNAL | flags;
Flush(node);
if (id != -1)
if (id >= 0)
{
index = Probe(id, type2);
dassert(index != NULL);
@ -439,15 +456,23 @@ void Resource::AddExternalResource(const char *name, const char *type, int id)
Free(node->name);
node->name = NULL;
}
if (node->path)
{
Free(node->path);
node->path = NULL;
}
int nTypeLength = strlen(type2);
int nNameLength = strlen(name2);
int nPathLength = strlen(path);
node->type = (char*)Alloc(nTypeLength+1);
node->name = (char*)Alloc(nNameLength+1);
node->path = (char*)Alloc(nPathLength+1);
strcpy(node->type, type2);
strcpy(node->name, name2);
strcpy(node->path, path);
node->id = id;
node->size = size;
node->flags |= DICT_EXTERNAL;
node->flags |= DICT_EXTERNAL | flags;
Flush(node);
}
}
@ -550,7 +575,10 @@ void Resource::Read(DICTNODE *n, void *p)
dassert(n != NULL);
if (n->flags & DICT_EXTERNAL)
{
sprintf(filename, "%s.%s", n->name, n->type);
if (n->path)
Bstrncpy(filename, n->path, BMAX_PATH-1);
else
Bsnprintf(filename, MAX_PATH-1, "%s.%s", n->name, n->type);
int fhandle = kopen4loadfrommod(filename, 0);
if (fhandle == -1 || (uint32_t)kread(fhandle, p, n->size) != n->size)
{
@ -814,6 +842,11 @@ void Resource::RemoveNode(DICTNODE* pNode)
Free(pNode->type);
pNode->type = NULL;
}
if (pNode->path)
{
Free(pNode->path);
pNode->path = NULL;
}
*pNode = dict[--count];
Bmemset(&dict[count], 0, sizeof(DICTNODE));
if (pNode->ptr && !pNode->lockCount)

View File

@ -76,6 +76,7 @@ struct DICTNODE : CACHENODE
//char name[8];
char *type;
char *name;
char *path;
unsigned int id;
};
@ -92,7 +93,7 @@ public:
DICTNODE **Probe(unsigned int id, const char *type);
void Reindex(void);
void Grow(void);
void AddExternalResource(const char *name, const char *type, int id = -1);
void AddExternalResource(const char *name, const char *type, int id = 0, int flags = 0, const char* pzDirectory = NULL);
static void *Alloc(int nSize);
static void Free(void *p);
DICTNODE *Lookup(const char *name, const char *type);