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.

424 lines
10 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/>.
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 "hsTypes.h"
#include "hsStlUtils.h"
#include "plSDL.h"
#include "../plFile/hsFiles.h"
#include "../plFile/plStreamSource.h"
#include "../pnNetCommon/pnNetCommon.h"
#include "../pnNetCommon/plNetApp.h"
static const int kTokenLen=256;
void plSDLParser::DebugMsg(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(char* fmt, va_list args) const
{
if (strlen(fmt)==nil)
return;
hsStatusMessage(xtl::formatv(fmt,args).c_str());
}
//
// parsing stateDesc
// read name, version
// return true to skip the next token read
//
bool plSDLParser::IParseStateDesc(const char* 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 = TRACKED_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, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
if (stream->GetToken(token, kTokenLen))
{
int v=atoi(token);
curDesc->SetVersion(v);
DebugMsg("\tVersion=%d", v);
}
}
else
{
hsAssert(false, xtl::format("Error parsing state desc, missing VERSION, fileName=%s",
fileName).c_str());
ok = false;
}
}
else
{
hsAssert(false, xtl::format("Error parsing state desc, fileName=%s", fileName).c_str());
ok = false;
}
if ( ok )
{
ok = ( plSDLMgr::GetInstance()->FindDescriptor(curDesc->GetName(), curDesc->GetVersion())==nil );
if ( !ok )
{
std::string err = xtl::format( "Found duplicate SDL descriptor for %s version %d.\nFailed to parse file: %s", 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 char* fileName, hsStream* stream, char token[], plStateDescriptor*& curDesc,
plVarDescriptor*& curVar) const
{
hsAssert(curDesc, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
if ( !curDesc )
return false;
bool skipNext=false;
std::string 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, xtl::format("can't find nested state desc reference %s, fileName=%s",
sdlName, fileName).c_str());
curVar = TRACKED_NEW plSDVarDescriptor(stateDesc);
}
else
curVar = TRACKED_NEW plSimpleVarDescriptor;
curDesc->AddVar(curVar);
bool ok=curVar->SetType(token);
hsAssert(ok, xtl::format("Variable 'type' syntax problem with .sdl file, type=%s, fileName=%s", token, fileName).c_str());
dbgStr = xtl::format("\tVAR Type=%s ", token).c_str();
//
// NAME (foo[1])
//
if (stream->GetToken(token, kTokenLen))
{
hsAssert(strstr(token, "[") && strstr(token, "]"), xtl::format("invalid var syntax, missing [x], fileName=%s",
fileName).c_str());
char* ptr = strtok( token, seps ); // skip [
hsAssert(curVar, xtl::format("Missing current var. Syntax problem with .sdl file, fileName=%s", 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 += xtl::format("Name=%s[%d]", curVar->GetName(), cnt).c_str();
}
//
// optional tokens: DEFAULT, INTERNAL
//
while (stream->GetToken(token, kTokenLen))
{
if (!strcmp(token, "DEFAULT"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
// read state var type
std::string 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.size())
{
curVar->SetDefault(defaultStr.c_str());
dbgStr += std::string(" DEFAULT=") + defaultStr;
}
}
else
if (!strcmp(token, "DISPLAYOPTION"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
dbgStr += std::string(" ") + token;
hsBool read=stream->GetToken(token, kTokenLen);
if (read)
{
std::string oldOptions=curVar->GetDisplayOptions();
if (oldOptions.size())
oldOptions += std::string(",");
oldOptions += token;
curVar->SetDisplayOptions(oldOptions.c_str());
dbgStr += std::string("=") + token;
if (!stricmp(token, "hidden"))
curVar->SetInternal(true);
}
else
{
hsAssert(false, xtl::format("missing displayOption string, fileName=%s", fileName).c_str());
}
}
else
if (!strcmp(token, "DEFAULTOPTION"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
dbgStr += std::string(" ") + token;
hsBool read=stream->GetToken(token, kTokenLen);
if (read)
{
dbgStr += std::string("=") + token;
if (!stricmp(token, "vault"))
curVar->SetAlwaysNew(true);
}
else
{
hsAssert(false, xtl::format("missing defaultOption string, fileName=%s", fileName).c_str());
}
}
#if 1 // delete me in May 2003
else
if (!strcmp(token, "INTERNAL"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
curVar->SetInternal(true);
dbgStr += std::string(" ") + token;
}
else
if (!strcmp(token, "PHASED"))
{
hsAssert(curVar, xtl::format("Syntax problem with .sdl file, fileName=%s", fileName).c_str());
curVar->SetAlwaysNew(true);
dbgStr += std::string(" ") + token;
}
#endif
else
{
skipNext=true;
break;
}
}
DebugMsg((char*)dbgStr.c_str());
return skipNext;
}
//
// create state descriptor from sdl file.
// return false on err.
//
bool plSDLParser::ILoadSDLFile(const char* fileName) const
{
DebugMsg("Parsing SDL file %s", fileName);
wchar_t* temp = hsStringToWString(fileName);
hsStream* stream = plStreamSource::GetInstance()->GetFile(temp);
delete [] temp;
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
{
std::string sdlDir = plSDLMgr::GetInstance()->GetSDLDir();
DebugMsg("SDL: Reading latest descriptors from directory %s", sdlDir.c_str());
wchar_t* temp = hsStringToWString(sdlDir.c_str());
std::wstring wSDLDir = temp;
delete [] temp;
// Get the names of all the sdl files
std::vector<std::wstring> files = plStreamSource::GetInstance()->GetListOfNames(wSDLDir, L".sdl");
bool ret=true;
int cnt=0;
for (int i = 0; i < files.size(); i++)
{
char* str = hsWStringToString(files[i].c_str());
if (!ILoadSDLFile(str))
{
plNetApp* netApp = plSDLMgr::GetInstance()->GetNetApp();
if (netApp)
netApp->ErrorMsg("Error loading SDL file %s", str);
else
hsStatusMessageF("Error loading SDL file %s", str);
ret=false;
}
else
cnt++;
delete [] str;
}
DebugMsg("Done reading SDL files");
if (!cnt)
ret=false;
return ret;
}
//
// reads sdl folder, creates descriptor list
//
bool plSDLParser::Parse() const
{
return IReadDescriptors();
}