khanat-opennel-code/code/nel/src/georges/form_dfn.cpp
2010-08-20 13:27:17 +02:00

881 lines
23 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdgeorges.h"
#include "nel/misc/i_xml.h"
#include "nel/misc/path.h"
#include "form_dfn.h"
#include "form_loader.h"
#include "form_elm.h"
using namespace NLMISC;
using namespace std;
#ifndef NL_OS_WINDOWS
#define stricmp strcasecmp
#endif
namespace NLGEORGES
{
// ***************************************************************************
void warning (bool exception, const char *format, ... );
// ***************************************************************************
void CFormDfn::write (xmlDocPtr doc, const char *filename, bool georges4CVS)
{
// Save filename
_Filename = CFile::getFilename (filename);
// Create the first node
xmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)"DFN", NULL);
xmlDocSetRootElement (doc, node);
// Write elements
uint parent;
for (parent=0; parent<Parents.size(); parent++)
{
// Parent name not empty ?
if (!Parents[parent].ParentFilename.empty ())
{
// Parent node
xmlNodePtr parentNode = xmlNewChild ( node, NULL, (const xmlChar*)"PARENT", NULL);
// Save parent
xmlSetProp (parentNode, (const xmlChar*)"Name", (const xmlChar*)Parents[parent].ParentFilename.c_str());
}
}
// Write elements
uint elm;
for (elm=0; elm<Entries.size(); elm++)
{
// Add a node
xmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)"ELEMENT", NULL);
xmlSetProp (elmPtr, (const xmlChar*)"Name", (const xmlChar*)Entries[elm].Name.c_str());
// What kind of element
switch (Entries[elm].TypeElement)
{
case UFormDfn::EntryType:
xmlSetProp (elmPtr, (const xmlChar*)"Type", (const xmlChar*)"Type");
xmlSetProp (elmPtr, (const xmlChar*)"Filename", (const xmlChar*)Entries[elm].Filename.c_str());
if ((!Entries[elm].FilenameExt.empty ()) && Entries[elm].FilenameExt != "*.*")
xmlSetProp (elmPtr, (const xmlChar*)"FilenameExt", (const xmlChar*)Entries[elm].FilenameExt.c_str());
break;
case UFormDfn::EntryDfn:
xmlSetProp (elmPtr, (const xmlChar*)"Type", (const xmlChar*)"Dfn");
xmlSetProp (elmPtr, (const xmlChar*)"Filename", (const xmlChar*)Entries[elm].Filename.c_str());
break;
case UFormDfn::EntryVirtualDfn:
xmlSetProp (elmPtr, (const xmlChar*)"Type", (const xmlChar*)"DfnPointer");
break;
}
// Is an array ?
if (Entries[elm].Array)
xmlSetProp (elmPtr, (const xmlChar*)"Array", (const xmlChar*)"true");
// Default value for type
if ((Entries[elm].TypeElement == UFormDfn::EntryType) && (!Entries[elm].Default.empty ()))
xmlSetProp (elmPtr, (const xmlChar*)"Default", (const xmlChar*)Entries[elm].Default.c_str ());
}
// Header
Header.write (node, georges4CVS);
}
// ***************************************************************************
void CFormDfn::read (xmlNodePtr root, CFormLoader &loader, bool forceLoad, const char *filename)
{
// Save filename
_Filename = CFile::getFilename (filename);
// Check node name
if ( ((const char*)root->name == NULL) || (strcmp ((const char*)root->name, "DFN") != 0) )
{
// Throw exception
warning (true, "read", "XML Syntax error in block line %d, node (%s) should be DFN.", (ptrdiff_t)root->content, root->name);
}
// Count the parent
uint parentCount = CIXml::countChildren (root, "PARENT");
Parents.resize (parentCount);
// For each element entry
uint parentNumber = 0;
xmlNodePtr parent = CIXml::getFirstChildNode (root, "PARENT");
while (parentNumber<parentCount)
{
// Get the Parent
const char *parentFilename = (const char*)xmlGetProp (parent, (xmlChar*)"Name");
if (parentFilename)
{
Parents[parentNumber].ParentFilename = parentFilename;
// Delete the value
xmlFree ((void*)parentFilename);
// Load the parent
Parents[parentNumber].Parent = loader.loadFormDfn (Parents[parentNumber].ParentFilename.c_str (), forceLoad);
if ((Parents[parentNumber].Parent == NULL) && !forceLoad)
{
// Throw exception
warning (true, "read", "Can't load parent DFN file (%s).", Parents[parentNumber].ParentFilename.c_str ());
}
}
else
{
// Throw exception
warning (true, "read", "XML Syntax error in block (%s) line %d, aguments Name not found.",
parent->name, (ptrdiff_t)parent->content);
}
// Next parent
parent = CIXml::getNextChildNode (parent, "PARENT");
parentNumber++;
}
// Count the element children
uint childCount = CIXml::countChildren (root, "ELEMENT");
// Resize the element table
Entries.resize (childCount);
// For each element entry
uint childNumber = 0;
xmlNodePtr child = CIXml::getFirstChildNode (root, "ELEMENT");
while (childNumber<childCount)
{
// Checks
nlassert (child);
// Get the name
const char *value = (const char*)xmlGetProp (child, (xmlChar*)"Name");
if (value)
{
// Store the value
Entries[childNumber].Name = value;
// Delete the value
xmlFree ((void*)value);
// Reset
Entries[childNumber].Dfn = NULL;
Entries[childNumber].Type = NULL;
Entries[childNumber].Default.clear ();
const char *filename = (const char*)xmlGetProp (child, (xmlChar*)"Filename");
if ( filename )
{
Entries[childNumber].Filename = filename;
// Delete the value
xmlFree ((void*)filename);
}
else
{
Entries[childNumber].Filename.clear ();
}
const char *filenameExt = (const char*)xmlGetProp (child, (xmlChar*)"FilenameExt");
if ( filenameExt )
{
Entries[childNumber].FilenameExt = filenameExt;
// Delete the value
xmlFree ((void*)filenameExt);
}
else
{
Entries[childNumber].FilenameExt = "*.*";
}
// Read the type
const char *typeName = (const char*)xmlGetProp (child, (xmlChar*)"Type");
if (typeName)
{
bool type = false;
bool dfn = false;
if (stricmp (typeName, "Type") == 0)
{
Entries[childNumber].TypeElement = UFormDfn::EntryType;
type = true;
// Load the filename
if (!Entries[childNumber].Filename.empty ())
{
Entries[childNumber].Type = loader.loadType (Entries[childNumber].Filename.c_str ());
if ((Entries[childNumber].Type == NULL) && !forceLoad)
{
// Throw exception
warning (true, "read", "In XML block (%s) line %d, file not found %s.",
child->name, (ptrdiff_t)child->content, Entries[childNumber].Filename.c_str ());
}
// Read the default value
const char *defaultName = (const char*)xmlGetProp (child, (xmlChar*)"Default");
if (defaultName)
{
Entries[childNumber].Default = defaultName;
// Delete the value
xmlFree ((void*)defaultName);
}
}
else
{
// Throw exception
warning (true, "read", "XML In block (%s) line %d, no filename found for the .typ file.",
child->name, (ptrdiff_t)child->content, Entries[childNumber].Filename.c_str ());
}
}
else if (stricmp (typeName, "Dfn") == 0)
{
Entries[childNumber].TypeElement = UFormDfn::EntryDfn;
dfn = true;
// Load the filename
if (!Entries[childNumber].Filename.empty ())
{
// Load the filename
Entries[childNumber].Dfn = loader.loadFormDfn (Entries[childNumber].Filename.c_str (), forceLoad);
if ((Entries[childNumber].Dfn == NULL) && !forceLoad)
{
// Throw exception
warning (true, "read", "XML In block (%s) line %d, file not found %s.",
child->name, (ptrdiff_t)child->content, Entries[childNumber].Filename.c_str ());
}
}
else
{
// Throw exception
warning (true, "read", "XML In block (%s) line %d, no filename found for the .typ file.",
child->name, (ptrdiff_t)child->content, Entries[childNumber].Filename.c_str ());
}
}
else if (stricmp (typeName, "DfnPointer") == 0)
{
Entries[childNumber].TypeElement = UFormDfn::EntryVirtualDfn;
}
else
{
// Throw exception
warning (true, "read", "XML Syntax error in block (%s) line %d, element has not a valid type name attribut \"Type = %s\".",
child->name, (ptrdiff_t)child->content, typeName);
}
// Delete the value
xmlFree ((void*)typeName);
}
else
{
// Throw exception
warning (true, "read", "XML Syntax error in block (%s) line %d, element has no type name attribut \"Type = [Type][Dfn][DfnPointer]\".",
child->name, (ptrdiff_t)child->content);
}
// Get the array attrib
Entries[childNumber].Array = false;
const char* arrayFlag = (const char*)xmlGetProp (child, (xmlChar*)"Array");
if (arrayFlag)
{
Entries[childNumber].Array = (stricmp (arrayFlag, "true") == 0);
// Delete the value
xmlFree ((void*)arrayFlag);
}
}
else
{
// Throw exception
warning (true, "read", "XML Syntax error in block (%s) line %d, aguments Name not found.",
root->name, (ptrdiff_t)root->content);
}
// Next child
child = CIXml::getNextChildNode (child, "ELEMENT");
childNumber++;
}
// Read the header
Header.read (root);
}
// ***************************************************************************
uint CFormDfn::countParentDfn (uint32 round) const
{
// Checkout recursive calls
if (round > NLGEORGES_MAX_RECURSION)
{
// Turn around..
warning (false, "countParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
return 0;
}
uint count = 0;
uint i;
for (i=0; i<Parents.size (); i++)
{
count += Parents[i].Parent->countParentDfn (round+1);
}
return count+1;
}
// ***************************************************************************
void CFormDfn::getParentDfn (std::vector<CFormDfn*> &array, uint32 round)
{
// Checkout recursive calls
if (round > NLGEORGES_MAX_RECURSION)
{
// Turn around..
warning (false, "getParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
return;
}
//uint count = 0;
uint i;
for (i=0; i<Parents.size (); i++)
{
Parents[i].Parent->getParentDfn (array, round+1);
}
array.push_back (this);
}
// ***************************************************************************
void CFormDfn::getParentDfn (std::vector<const CFormDfn*> &array, uint32 round) const
{
// Checkout recursive calls
if (round > NLGEORGES_MAX_RECURSION)
{
// Turn around..
warning (false, "getParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
return;
}
//uint count = 0;
uint i;
for (i=0; i<Parents.size (); i++)
{
Parents[i].Parent->getParentDfn (array, round+1);
}
array.push_back (this);
}
// ***************************************************************************
uint CFormDfn::getNumParent () const
{
return (uint)Parents.size ();
}
// ***************************************************************************
CFormDfn *CFormDfn::getParent (uint parent) const
{
return Parents[parent].Parent;
}
// ***************************************************************************
const string& CFormDfn::getParentFilename (uint parent) const
{
return Parents[parent].ParentFilename;
}
// ***************************************************************************
uint CFormDfn::getNumEntry () const
{
return (uint)Entries.size();
}
// ***************************************************************************
void CFormDfn::setNumEntry (uint size)
{
Entries.resize (size);
}
// ***************************************************************************
const CFormDfn::CEntry &CFormDfn::getEntry (uint entry) const
{
return Entries[entry];
}
// ***************************************************************************
CFormDfn::CEntry &CFormDfn::getEntry (uint entry)
{
return Entries[entry];
}
// ***************************************************************************
void CFormDfn::setNumParent (uint size)
{
Parents.resize (size);
}
// ***************************************************************************
void CFormDfn::setParent (uint parent, CFormLoader &loader, const char *filename)
{
if (strcmp (filename, "")==0)
Parents[parent].Parent = NULL;
else
Parents[parent].Parent = loader.loadFormDfn (filename, false);
Parents[parent].ParentFilename = filename;
}
// ***************************************************************************
void CFormDfn::CEntry::setType (CFormLoader &loader, const char *filename)
{
TypeElement = EntryType;
Dfn = NULL;
Filename = filename;
Type = loader.loadType (filename);
}
// ***************************************************************************
void CFormDfn::CEntry::setDfn (CFormLoader &loader, const char *filename)
{
TypeElement = EntryDfn;
Filename = filename;
Type = NULL;
Dfn = loader.loadFormDfn (filename, false);
}
// ***************************************************************************
void CFormDfn::CEntry::setDfnPointer ()
{
TypeElement = EntryVirtualDfn;
Filename = "";
Type = NULL;
Dfn = NULL;
}
// ***************************************************************************
const std::string &CFormDfn::CEntry::getName () const
{
return Name;
}
// ***************************************************************************
void CFormDfn::CEntry::setName (const char *name)
{
Name = name;
}
// ***************************************************************************
const std::string &CFormDfn::CEntry::getDefault () const
{
return Default;
}
// ***************************************************************************
void CFormDfn::CEntry::setDefault (const char *def)
{
Default = def;
}
// ***************************************************************************
void CFormDfn::CEntry::setArrayFlag (bool flag)
{
Array = flag;
}
// ***************************************************************************
bool CFormDfn::CEntry::getArrayFlag () const
{
return Array;
}
// ***************************************************************************
UFormDfn::TEntryType CFormDfn::CEntry::getType () const
{
return TypeElement;
}
// ***************************************************************************
const std::string &CFormDfn::CEntry::getFilename() const
{
return Filename;
}
// ***************************************************************************
void CFormDfn::CEntry::setFilename (const char *def)
{
Filename = def;
}
// ***************************************************************************
CType *CFormDfn::CEntry::getTypePtr ()
{
return Type;
}
// ***************************************************************************
CFormDfn *CFormDfn::CEntry::getDfnPtr ()
{
return Dfn;
}
// ***************************************************************************
const CType *CFormDfn::CEntry::getTypePtr () const
{
return Type;
}
// ***************************************************************************
const CFormDfn *CFormDfn::CEntry::getDfnPtr () const
{
return Dfn;
}
// ***************************************************************************
CFormDfn *CFormDfn::getSubDfn (uint index, uint &dfnIndex)
{
// Get the sub DFN
vector<CFormDfn*> parentDfn;
parentDfn.reserve (countParentDfn ());
getParentDfn (parentDfn);
// For each parent
uint dfn;
dfnIndex = index;
uint parentSize = (uint)parentDfn.size();
for (dfn=0; dfn<parentSize; dfn++)
{
// Good element ?
uint size = (uint)parentDfn[dfn]->Entries.size ();
if (dfnIndex<size)
return parentDfn[dfn];
dfnIndex -= size;
}
// Should be found..
nlstop;
return NULL;
}
// ***************************************************************************
const CFormDfn *CFormDfn::getSubDfn (uint index, uint &dfnIndex) const
{
// Get the sub DFN
vector<const CFormDfn*> parentDfn;
parentDfn.reserve (countParentDfn ());
getParentDfn (parentDfn);
// For each parent
uint dfn;
dfnIndex = index;
uint parentSize = (uint)parentDfn.size();
for (dfn=0; dfn<parentSize; dfn++)
{
// Good element ?
uint size = (uint)parentDfn[dfn]->Entries.size ();
if (dfnIndex<size)
return parentDfn[dfn];
dfnIndex -= size;
}
// Should be found..
nlstop;
return NULL;
}
// ***************************************************************************
bool CFormDfn::getEntryType (uint entry, TEntryType &type, bool &array) const
{
if (entry < Entries.size ())
{
type = Entries[entry].TypeElement;
array = Entries[entry].Array;
return true;
}
warning (false, "getEntryType", "Wrong entry ID.");
return false;
}
// ***************************************************************************
bool CFormDfn::getEntryFilename (uint entry, std::string& filename) const
{
if (entry < Entries.size ())
{
if (Entries[entry].TypeElement != EntryVirtualDfn)
{
filename = Entries[entry].Filename;
return true;
}
warning (false, "getEntryFilename", "The entry is a virtual DFN.");
return false;
}
warning (false, "getEntryFilename", "Wrong entry ID.");
return false;
}
// ***************************************************************************
bool CFormDfn::getEntryFilenameExt (uint entry, std::string& filename) const
{
if (entry < Entries.size ())
{
filename = Entries[entry].FilenameExt;
return true;
}
warning (false, "getEntryFilenameExt", "Wrong entry ID.");
return false;
}
// ***************************************************************************
bool CFormDfn::getEntryIndexByName (uint &entry, const std::string &name) const
{
uint entryIndex=0;
while (entryIndex<Entries.size ())
{
if (Entries[entryIndex].Name==name)
{
entry=entryIndex;
return true;
}
entryIndex++;
}
entry=~0;
return false;
}
// ***************************************************************************
bool CFormDfn::getEntryName (uint entry, std::string &name) const
{
if (entry < Entries.size ())
{
name = Entries[entry].Name;
return true;
}
warning (false, "getEntryName", "Wrong entry ID.");
return false;
}
// ***************************************************************************
bool CFormDfn::getEntryDfn (uint entry, UFormDfn **dfn)
{
if (entry < Entries.size ())
{
if (Entries[entry].TypeElement == EntryDfn)
{
*dfn = Entries[entry].Dfn;
return true;
}
else
warning (false, "getEntryDfn", "This entry is not a DFN.");
}
warning (false, "getEntryDfn", "Wrong entry ID.");
return false;
}
bool CFormDfn::getEntryByName (const std::string &name, CFormDfn::CEntry **entry)
{
int entryIndex=(int)Entries.size ()-1;
while (entryIndex>=0)
{
CEntry *entryPtr=&Entries[entryIndex];
if (entryPtr->getName()==name)
{
*entry=entryPtr;
return true;
}
entryIndex--;
}
*entry=NULL;
return false;
}
bool CFormDfn::getEntryDfnByName (const std::string &name, UFormDfn **dfn)
{
CFormDfn::CEntry *entry;
if (getEntryByName (name, &entry))
{
*dfn=entry->getDfnPtr();
return true;
}
*dfn=NULL;
return false;
}
bool CFormDfn::isAnArrayEntryByName (const std::string &name) const
{
CFormDfn::CEntry *entry;
if (const_cast<CFormDfn*>(this)->getEntryByName (name, &entry))
{
return entry->getArrayFlag();
}
return false;
}
// ***************************************************************************
bool CFormDfn::getEntryType (uint entry, UType **type)
{
if (entry < Entries.size ())
{
if (Entries[entry].TypeElement == EntryType)
{
*type = Entries[entry].Type;
return true;
}
else
warning (false, "getEntryType", "This entry is not a type.");
}
warning (false, "getEntryType", "Wrong entry ID.");
return false;
}
// ***************************************************************************
uint CFormDfn::getNumParents () const
{
return (uint)Parents.size ();
}
// ***************************************************************************
bool CFormDfn::getParent (uint parent, UFormDfn **parentRet)
{
if (parent < Parents.size ())
{
*parentRet = Parents[parent].Parent;
return true;
}
warning (false, "getParent", "Wrong parent ID.");
return false;
}
// ***************************************************************************
bool CFormDfn::getParentFilename (uint parent, std::string &filename) const
{
if (parent < Parents.size ())
{
filename = Parents[parent].ParentFilename;
return true;
}
warning (false, "getParentFilename", "Wrong parent ID.");
return false;
}
// ***************************************************************************
const std::string& CFormDfn::getComment () const
{
return Header.Comments;
}
// ***************************************************************************
const std::string &CFormDfn::CEntry::getFilenameExt() const
{
return FilenameExt;
}
// ***************************************************************************
void CFormDfn::CEntry::setFilenameExt (const char *ext)
{
FilenameExt = ext;
}
// ***************************************************************************
void CFormDfn::warning (bool exception, const char *function, const char *format, ... ) const
{
// Make a buffer string
va_list args;
va_start( args, format );
char buffer[1024];
vsnprintf( buffer, 1024, format, args );
va_end( args );
// Set the warning
NLGEORGES::warning (exception, "(CFormDfn::%s) in form DFN (%s) : %s", function, _Filename.c_str (), buffer);
}
// ***************************************************************************
void CFormDfn::getDependencies (std::set<std::string> &dependencies) const
{
// Scan only if not already inserted
if (dependencies.insert (toLower(CFile::getFilename (_Filename))).second)
{
// Add parents
uint i;
for (i=0; i<Parents.size (); i++)
{
Parents[i].Parent->getDependencies (dependencies);
}
// Add entries
for (i=0; i<Entries.size (); i++)
{
if (Entries[i].getDfnPtr ())
Entries[i].getDfnPtr ()->getDependencies (dependencies);
if (Entries[i].getTypePtr ())
{
dependencies.insert (toLower(CFile::getFilename (Entries[i].getFilename())));
}
}
}
}
// ***************************************************************************
} // NLGEORGES