You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
442 lines
13 KiB
442 lines
13 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
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, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#include "HeadSpin.h" |
|
#include "plSDL.h" |
|
#include "plFile/plStreamSource.h" |
|
#include "pnNetCommon/pnNetCommon.h" |
|
#include "pnNetCommon/plNetApp.h" |
|
|
|
static const int kTokenLen=256; |
|
|
|
void plSDLParser::DebugMsg(const plString& msg) const |
|
{ |
|
return; |
|
plNetApp* netApp = plSDLMgr::GetInstance()->GetNetApp(); |
|
|
|
if (netApp) |
|
hsLogEntry(netApp->DebugMsg(msg)); |
|
else |
|
hsStatusMessage(msg.c_str()); |
|
} |
|
|
|
void plSDLParser::DebugMsg(const char* fmt, ...) const |
|
{ |
|
return; |
|
plNetApp* netApp = plSDLMgr::GetInstance()->GetNetApp(); |
|
|
|
va_list args; |
|
va_start(args, fmt); |
|
|
|
if (netApp) |
|
{ |
|
hsLogEntry(netApp->DebugMsgV(fmt, args)); |
|
} |
|
else |
|
DebugMsgV(fmt, args); |
|
va_end(args); |
|
} |
|
|
|
void plSDLParser::DebugMsgV(const char* fmt, va_list args) const |
|
{ |
|
if (strlen(fmt) == 0) |
|
return; |
|
hsStatusMessage(plString::IFormat(fmt,args).c_str()); |
|
} |
|
|
|
// |
|
// parsing stateDesc |
|
// read name, version |
|
// return true to skip the next token read |
|
// |
|
bool plSDLParser::IParseStateDesc(const plFileName& fileName, hsStream* stream, char token[], |
|
plStateDescriptor*& curDesc) const |
|
{ |
|
plSDL::DescriptorList* descList = &plSDLMgr::GetInstance()->fDescriptors; |
|
|
|
bool ok = true; |
|
|
|
// |
|
// NAME |
|
// |
|
// curDesc=plSDLMgr::GetInstance()->FindDescriptor(token, plSDL::kLatestVersion); |
|
// if (!curDesc) |
|
{ |
|
curDesc = new plStateDescriptor; |
|
curDesc->SetName(token); |
|
|
|
DebugMsg("SDL: DESC name=%s", token); |
|
} |
|
|
|
// |
|
// { |
|
// |
|
stream->GetToken(token, kTokenLen); // skip '{' |
|
|
|
// |
|
// VERSION |
|
// |
|
if (stream->GetToken(token, kTokenLen)) |
|
{ |
|
if (!strcmp(token, "VERSION")) |
|
{ |
|
// read desc version |
|
hsAssert(curDesc, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
if (stream->GetToken(token, kTokenLen)) |
|
{ |
|
int v=atoi(token); |
|
curDesc->SetVersion(v); |
|
DebugMsg("\tVersion=%d", v); |
|
} |
|
} |
|
else |
|
{ |
|
hsAssert(false, plFormat("Error parsing state desc, missing VERSION, fileName={}", fileName).c_str()); |
|
ok = false; |
|
} |
|
} |
|
else |
|
{ |
|
hsAssert(false, plFormat("Error parsing state desc, fileName={}", fileName).c_str()); |
|
ok = false; |
|
} |
|
|
|
if ( ok ) |
|
{ |
|
ok = ( plSDLMgr::GetInstance()->FindDescriptor(curDesc->GetName(), curDesc->GetVersion())==nil ); |
|
if ( !ok ) |
|
{ |
|
plString err = plFormat("Found duplicate SDL descriptor for {} version {}.\nFailed to parse file: {}", |
|
curDesc->GetName(), curDesc->GetVersion(), fileName); |
|
plNetApp::StaticErrorMsg( err.c_str() ); |
|
hsAssert( false, err.c_str() ); |
|
} |
|
} |
|
|
|
if ( ok ) |
|
{ |
|
descList->push_back(curDesc); |
|
} |
|
else |
|
{ |
|
delete curDesc; |
|
curDesc = nil; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// |
|
// Parse a variable descriptor. |
|
// read type, name, count [default] |
|
// return true to skip the next token read |
|
// |
|
bool plSDLParser::IParseVarDesc(const plFileName& fileName, hsStream* stream, char token[], |
|
plStateDescriptor*& curDesc, plVarDescriptor*& curVar) const |
|
{ |
|
hsAssert(curDesc, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
if ( !curDesc ) |
|
return false; |
|
|
|
bool skipNext=false; |
|
plString dbgStr; |
|
static char seps[] = "( ,)[]"; |
|
// read type, name, cnt, [default] |
|
|
|
// |
|
// TYPE |
|
// create new state var, make current |
|
// |
|
if (*token == '$') |
|
{ |
|
// nested sdls |
|
char* sdlName = token+1; |
|
plStateDescriptor* stateDesc = plSDLMgr::GetInstance()->FindDescriptor(sdlName, plSDL::kLatestVersion); |
|
hsAssert(stateDesc, plFormat("can't find nested state desc reference {}, fileName={}", |
|
sdlName, fileName).c_str()); |
|
curVar = new plSDVarDescriptor(stateDesc); |
|
} |
|
else |
|
curVar = new plSimpleVarDescriptor; |
|
|
|
curDesc->AddVar(curVar); |
|
bool ok=curVar->SetType(token); |
|
hsAssert(ok, plFormat("Variable 'type' syntax problem with .sdl file, type={}, fileName={}", |
|
token, fileName).c_str()); |
|
dbgStr = plFormat("\tVAR Type={} ", token); |
|
|
|
// |
|
// NAME (foo[1]) |
|
// |
|
if (stream->GetToken(token, kTokenLen)) |
|
{ |
|
hsAssert(strstr(token, "[") != nullptr && strstr(token, "]") != nullptr, |
|
plFormat("invalid var syntax, missing [x], fileName={}", fileName).c_str()); |
|
char* ptr = strtok( token, seps ); // skip [ |
|
|
|
hsAssert(curVar, plFormat("Missing current var. Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
curVar->SetName(token); |
|
// |
|
// COUNT |
|
// |
|
char* cntTok=strtok(nil, seps); // kill ] |
|
int cnt = cntTok ? atoi(cntTok) : 0; |
|
curVar->SetCount(cnt); |
|
if (cnt==0) |
|
curVar->SetVariableLength(true); |
|
dbgStr += plFormat("Name={}[{}]", curVar->GetName(), cnt); |
|
} |
|
|
|
// |
|
// optional tokens: DEFAULT, INTERNAL |
|
// |
|
while (stream->GetToken(token, kTokenLen)) |
|
{ |
|
if (!strcmp(token, "DEFAULT")) |
|
{ |
|
hsAssert(curVar, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
// read state var type |
|
|
|
plString defaultStr; |
|
plSimpleVarDescriptor* sVar=(plSimpleVarDescriptor*)curVar; |
|
if (sVar) |
|
{ |
|
int i; |
|
for(i=0;i<sVar->GetAtomicCount();i++) |
|
{ |
|
if (stream->GetToken(token, kTokenLen)) |
|
{ |
|
defaultStr += token; |
|
if (i!=sVar->GetAtomicCount()-1) |
|
defaultStr += ","; |
|
} |
|
} |
|
} |
|
if (!defaultStr.IsEmpty()) |
|
{ |
|
curVar->SetDefault(defaultStr); |
|
dbgStr += " DEFAULT=" + defaultStr; |
|
} |
|
} |
|
else |
|
if (!strcmp(token, "DISPLAYOPTION")) |
|
{ |
|
hsAssert(curVar, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
dbgStr += plString(" ") + token; |
|
|
|
bool read=stream->GetToken(token, kTokenLen); |
|
if (read) |
|
{ |
|
plString oldOptions=curVar->GetDisplayOptions(); |
|
if (!oldOptions.IsEmpty()) |
|
oldOptions += ","; |
|
oldOptions += token; |
|
curVar->SetDisplayOptions(oldOptions); |
|
dbgStr += plString("=") + token; |
|
if (!stricmp(token, "hidden")) |
|
curVar->SetInternal(true); |
|
} |
|
else |
|
{ |
|
hsAssert(false, plFormat("missing displayOption string, fileName={}", fileName).c_str()); |
|
} |
|
} |
|
else |
|
if (!strcmp(token, "DEFAULTOPTION")) |
|
{ |
|
hsAssert(curVar, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
dbgStr += plString(" ") + token; |
|
|
|
bool read=stream->GetToken(token, kTokenLen); |
|
if (read) |
|
{ |
|
dbgStr += plString("=") + token; |
|
if (!stricmp(token, "vault")) |
|
curVar->SetAlwaysNew(true); |
|
} |
|
else |
|
{ |
|
hsAssert(false, plFormat("missing defaultOption string, fileName={}", fileName).c_str()); |
|
} |
|
} |
|
|
|
#if 1 // delete me in May 2003 |
|
else |
|
if (!strcmp(token, "INTERNAL")) |
|
{ |
|
hsAssert(curVar, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
curVar->SetInternal(true); |
|
dbgStr += plString(" ") + token; |
|
} |
|
else |
|
if (!strcmp(token, "PHASED")) |
|
{ |
|
hsAssert(curVar, plFormat("Syntax problem with .sdl file, fileName={}", fileName).c_str()); |
|
curVar->SetAlwaysNew(true); |
|
dbgStr += plString(" ") + token; |
|
} |
|
#endif |
|
else |
|
{ |
|
skipNext=true; |
|
break; |
|
} |
|
} |
|
|
|
DebugMsg(dbgStr.c_str()); |
|
|
|
return skipNext; |
|
} |
|
|
|
// |
|
// create state descriptor from sdl file. |
|
// return false on err. |
|
// |
|
bool plSDLParser::ILoadSDLFile(const plFileName& fileName) const |
|
{ |
|
DebugMsg("Parsing SDL file %s", fileName.AsString().c_str()); |
|
|
|
hsStream* stream = plStreamSource::GetInstance()->GetFile(fileName); |
|
if (!stream) |
|
return false; |
|
|
|
stream->Rewind(); |
|
|
|
plVarDescriptor* curVar=nil; |
|
plStateDescriptor* curDesc=nil; |
|
char token[kTokenLen]; |
|
bool parsingStateDesc=false; |
|
bool skip=false; |
|
while (1) |
|
{ |
|
if (!skip) |
|
{ |
|
if (!stream->GetToken(token, kTokenLen)) |
|
break; |
|
} |
|
skip=false; |
|
|
|
if (!strcmp(token, "VAR")) |
|
{ |
|
parsingStateDesc=false; |
|
curVar=nil; // start fresh |
|
continue; |
|
} |
|
|
|
if (!strcmp(token, "STATEDESC")) |
|
{ |
|
parsingStateDesc=true; |
|
curDesc=nil; // start fresh |
|
continue; |
|
} |
|
|
|
if (!strcmp(token, "}")) |
|
{ |
|
if ( curDesc ) |
|
curDesc->SetFilename( fileName ); |
|
parsingStateDesc=false; |
|
continue; |
|
} |
|
|
|
if (parsingStateDesc) |
|
{ |
|
skip=IParseStateDesc(fileName, stream, token, curDesc); |
|
if ( !curDesc ) |
|
break; // failed to parse state desc |
|
} |
|
else |
|
{ |
|
skip=IParseVarDesc(fileName, stream, token, curDesc, curVar); |
|
} |
|
} |
|
|
|
// If the very last char is a } without a \n, then it won't be handled above for some reason, so we have to catch it here. |
|
if ( curDesc ) |
|
curDesc->SetFilename( fileName ); |
|
|
|
// do not close or delete the stream, we do not own it |
|
return true; |
|
} |
|
|
|
// |
|
// load all .sdl files in sdl directory, and create descriptors for each. |
|
// return false on error |
|
// |
|
bool plSDLParser::IReadDescriptors() const |
|
{ |
|
plFileName sdlDir = plSDLMgr::GetInstance()->GetSDLDir(); |
|
DebugMsg("SDL: Reading latest descriptors from directory %s", sdlDir.AsString().c_str()); |
|
|
|
// Get the names of all the sdl files |
|
std::vector<plFileName> files = plStreamSource::GetInstance()->GetListOfNames(sdlDir, "sdl"); |
|
|
|
bool ret=true; |
|
int cnt=0; |
|
for (int i = 0; i < files.size(); i++) |
|
{ |
|
if (!ILoadSDLFile(files[i])) |
|
{ |
|
plNetApp* netApp = plSDLMgr::GetInstance()->GetNetApp(); |
|
if (netApp) |
|
netApp->ErrorMsg("Error loading SDL file %s", files[i].AsString().c_str()); |
|
else |
|
hsStatusMessageF("Error loading SDL file %s", files[i].AsString().c_str()); |
|
ret=false; |
|
} |
|
else |
|
cnt++; |
|
} |
|
DebugMsg("Done reading SDL files"); |
|
|
|
if (!cnt) |
|
ret=false; |
|
|
|
return ret; |
|
} |
|
|
|
|
|
// |
|
// reads sdl folder, creates descriptor list |
|
// |
|
bool plSDLParser::Parse() const |
|
{ |
|
return IReadDescriptors(); |
|
}
|
|
|