// NeL - MMORPG Framework
// 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 .
#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; parentname == 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 (parentNumbername, (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 (childNumbername, (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; icountParentDfn (round+1);
}
return count+1;
}
// ***************************************************************************
void CFormDfn::getParentDfn (std::vector &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; igetParentDfn (array, round+1);
}
array.push_back (this);
}
// ***************************************************************************
void CFormDfn::getParentDfn (std::vector &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; igetParentDfn (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 parentDfn;
parentDfn.reserve (countParentDfn ());
getParentDfn (parentDfn);
// For each parent
uint dfn;
dfnIndex = index;
uint parentSize = (uint)parentDfn.size();
for (dfn=0; dfnEntries.size ();
if (dfnIndex parentDfn;
parentDfn.reserve (countParentDfn ());
getParentDfn (parentDfn);
// For each parent
uint dfn;
dfnIndex = index;
uint parentSize = (uint)parentDfn.size();
for (dfn=0; dfnEntries.size ();
if (dfnIndex=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(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 &dependencies) const
{
// Scan only if not already inserted
if (dependencies.insert (toLower(CFile::getFilename (_Filename))).second)
{
// Add parents
uint i;
for (i=0; igetDependencies (dependencies);
}
// Add entries
for (i=0; igetDependencies (dependencies);
if (Entries[i].getTypePtr ())
{
dependencies.insert (toLower(CFile::getFilename (Entries[i].getFilename())));
}
}
}
}
// ***************************************************************************
} // NLGEORGES