/*==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 . 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;iGetAtomicCount();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 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(); }