Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / georges / form_dfn.cpp
blob82f4dc1db64511c8a20b0a5640c0e252bc8ca49c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdgeorges.h"
24 #include "nel/misc/i_xml.h"
25 #include "nel/misc/path.h"
27 #include "nel/georges/form_dfn.h"
28 #include "nel/georges/form_loader.h"
29 #include "nel/georges/form_elm.h"
31 #ifdef DEBUG_NEW
32 #define new DEBUG_NEW
33 #endif
35 using namespace NLMISC;
36 using namespace std;
38 #ifndef NL_OS_WINDOWS
39 #define stricmp strcasecmp
40 #endif
43 namespace NLGEORGES
46 // ***************************************************************************
48 void warning (bool exception, const char *format, ... );
50 // ***************************************************************************
52 void CFormDfn::addEntry( const std::string &name )
54 CEntry entry;
55 entry.setName( name.c_str() );
56 Entries.push_back( entry );
59 void CFormDfn::removeEntry( uint idx )
61 std::vector< CEntry >::iterator itr = Entries.begin() + idx;
62 Entries.erase( itr );
65 // ***************************************************************************
67 void CFormDfn::write (xmlDocPtr doc, const std::string &filename)
69 // Save filename
70 _Filename = CFile::getFilename (filename);
72 // Create the first node
73 xmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)"DFN", NULL);
74 xmlDocSetRootElement (doc, node);
76 // Write elements
77 uint parent;
78 for (parent=0; parent<Parents.size(); parent++)
80 // Parent name not empty ?
81 if (!Parents[parent].ParentFilename.empty ())
83 // Parent node
84 xmlNodePtr parentNode = xmlNewChild ( node, NULL, (const xmlChar*)"PARENT", NULL);
86 // Save parent
87 xmlSetProp (parentNode, (const xmlChar*)"Name", (const xmlChar*)Parents[parent].ParentFilename.c_str());
91 // Write elements
92 uint elm;
93 for (elm=0; elm<Entries.size(); elm++)
95 // Add a node
96 xmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)"ELEMENT", NULL);
97 xmlSetProp (elmPtr, (const xmlChar*)"Name", (const xmlChar*)Entries[elm].Name.c_str());
99 // What kind of element
100 switch (Entries[elm].TypeElement)
102 case UFormDfn::EntryType:
103 xmlSetProp (elmPtr, (const xmlChar*)"Type", (const xmlChar*)"Type");
104 xmlSetProp (elmPtr, (const xmlChar*)"Filename", (const xmlChar*)Entries[elm].Filename.c_str());
105 if ((!Entries[elm].FilenameExt.empty ()) && Entries[elm].FilenameExt != "*.*")
106 xmlSetProp (elmPtr, (const xmlChar*)"FilenameExt", (const xmlChar*)Entries[elm].FilenameExt.c_str());
107 break;
108 case UFormDfn::EntryDfn:
109 xmlSetProp (elmPtr, (const xmlChar*)"Type", (const xmlChar*)"Dfn");
110 xmlSetProp (elmPtr, (const xmlChar*)"Filename", (const xmlChar*)Entries[elm].Filename.c_str());
111 break;
112 case UFormDfn::EntryVirtualDfn:
113 xmlSetProp (elmPtr, (const xmlChar*)"Type", (const xmlChar*)"DfnPointer");
114 break;
117 // Is an array ?
118 if (Entries[elm].Array)
119 xmlSetProp (elmPtr, (const xmlChar*)"Array", (const xmlChar*)"true");
121 // Default value for type
122 if ((Entries[elm].TypeElement == UFormDfn::EntryType) && (!Entries[elm].Default.empty ()))
123 xmlSetProp (elmPtr, (const xmlChar*)"Default", (const xmlChar*)Entries[elm].Default.c_str ());
126 // Header
127 Header.write (node);
130 // ***************************************************************************
132 void CFormDfn::read (xmlNodePtr root, CFormLoader &loader, bool forceLoad, const std::string &filename)
134 // Save filename
135 _Filename = CFile::getFilename (filename);
137 // Check node name
138 if ( ((const char*)root->name == NULL) || (strcmp ((const char*)root->name, "DFN") != 0) )
140 // Throw exception
141 warning (true, "read", "XML Syntax error in block line %d, node (%s) should be DFN.", (sint)root->line, root->name);
144 // Count the parent
145 uint parentCount = CIXml::countChildren (root, "PARENT");
146 Parents.resize (parentCount);
148 // For each element entry
149 uint parentNumber = 0;
150 xmlNodePtr parent = CIXml::getFirstChildNode (root, "PARENT");
151 while (parentNumber<parentCount)
153 // Get the Parent
154 const char *parentFilename = (const char*)xmlGetProp (parent, (xmlChar*)"Name");
155 if (parentFilename)
157 Parents[parentNumber].ParentFilename = parentFilename;
159 // Delete the value
160 xmlFree ((void*)parentFilename);
162 // Load the parent
163 Parents[parentNumber].Parent = loader.loadFormDfn (Parents[parentNumber].ParentFilename.c_str (), forceLoad);
164 if ((Parents[parentNumber].Parent == NULL) && !forceLoad)
166 // Throw exception
167 warning (true, "read", "Can't load parent DFN file (%s).", Parents[parentNumber].ParentFilename.c_str ());
170 else
172 // Throw exception
173 warning (true, "read", "XML Syntax error in block (%s) line %d, aguments Name not found.",
174 parent->name, (sint)parent->line);
177 // Next parent
178 parent = CIXml::getNextChildNode (parent, "PARENT");
179 parentNumber++;
182 // Count the element children
183 uint childCount = CIXml::countChildren (root, "ELEMENT");
185 // Resize the element table
186 Entries.resize (childCount);
188 // For each element entry
189 uint childNumber = 0;
190 xmlNodePtr child = CIXml::getFirstChildNode (root, "ELEMENT");
191 while (childNumber<childCount)
193 // Checks
194 nlassert (child);
196 // Get the name
197 const char *value = (const char*)xmlGetProp (child, (xmlChar*)"Name");
198 if (value)
200 // Store the value
201 Entries[childNumber].Name = value;
203 // Delete the value
204 xmlFree ((void*)value);
206 // Reset
207 Entries[childNumber].Dfn = NULL;
208 Entries[childNumber].Type = NULL;
209 Entries[childNumber].Default.clear ();
211 const char *filename = (const char*)xmlGetProp (child, (xmlChar*)"Filename");
213 if ( filename )
215 Entries[childNumber].Filename = filename;
217 // Delete the value
218 xmlFree ((void*)filename);
220 else
222 Entries[childNumber].Filename.clear ();
225 const char *filenameExt = (const char*)xmlGetProp (child, (xmlChar*)"FilenameExt");
226 if ( filenameExt )
228 Entries[childNumber].FilenameExt = filenameExt;
230 // Delete the value
231 xmlFree ((void*)filenameExt);
233 else
235 Entries[childNumber].FilenameExt = "*.*";
238 // Read the type
239 const char *typeName = (const char*)xmlGetProp (child, (xmlChar*)"Type");
240 if (typeName)
242 bool type = false;
243 bool dfn = false;
244 if (stricmp (typeName, "Type") == 0)
246 Entries[childNumber].TypeElement = UFormDfn::EntryType;
247 type = true;
249 // Load the filename
250 if (!Entries[childNumber].Filename.empty ())
252 Entries[childNumber].Type = loader.loadType (Entries[childNumber].Filename.c_str ());
253 if ((Entries[childNumber].Type == NULL) && !forceLoad)
255 // Throw exception
256 warning (true, "read", "In XML block (%s) line %d, file not found %s.",
257 child->name, (sint)child->line, Entries[childNumber].Filename.c_str ());
260 // Read the default value
261 const char *defaultName = (const char*)xmlGetProp (child, (xmlChar*)"Default");
262 if (defaultName)
264 Entries[childNumber].Default = defaultName;
266 // Delete the value
267 xmlFree ((void*)defaultName);
270 else
272 // Throw exception
273 warning (true, "read", "XML In block (%s) line %d, no filename found for the .typ file.",
274 child->name, (sint)child->line);
277 else if (stricmp (typeName, "Dfn") == 0)
279 Entries[childNumber].TypeElement = UFormDfn::EntryDfn;
280 dfn = true;
282 // Load the filename
283 if (!Entries[childNumber].Filename.empty ())
285 // Load the filename
286 Entries[childNumber].Dfn = loader.loadFormDfn (Entries[childNumber].Filename.c_str (), forceLoad);
287 if ((Entries[childNumber].Dfn == NULL) && !forceLoad)
289 // Throw exception
290 warning (true, "read", "XML In block (%s) line %d, file not found %s.",
291 child->name, (sint)child->line, Entries[childNumber].Filename.c_str ());
294 else
296 // Throw exception
297 warning (true, "read", "XML In block (%s) line %d, no filename found for the .typ file.",
298 child->name, (sint)child->line);
301 else if (stricmp (typeName, "DfnPointer") == 0)
303 Entries[childNumber].TypeElement = UFormDfn::EntryVirtualDfn;
305 else
307 // Throw exception
308 warning (true, "read", "XML Syntax error in block (%s) line %d, element has not a valid type name attribut \"Type = %s\".",
309 child->name, (sint)child->line, typeName);
312 // Delete the value
313 xmlFree ((void*)typeName);
315 else
317 // Throw exception
318 warning (true, "read", "XML Syntax error in block (%s) line %d, element has no type name attribut \"Type = [Type][Dfn][DfnPointer]\".",
319 child->name, (sint)child->line);
322 // Get the array attrib
323 Entries[childNumber].Array = false;
324 const char* arrayFlag = (const char*)xmlGetProp (child, (xmlChar*)"Array");
325 if (arrayFlag)
327 Entries[childNumber].Array = (stricmp (arrayFlag, "true") == 0);
329 // Delete the value
330 xmlFree ((void*)arrayFlag);
333 else
335 // Throw exception
336 warning (true, "read", "XML Syntax error in block (%s) line %d, aguments Name not found.",
337 root->name, (sint)root->line);
340 // Next child
341 child = CIXml::getNextChildNode (child, "ELEMENT");
342 childNumber++;
345 // Read the header
346 Header.read (root);
349 // ***************************************************************************
351 uint CFormDfn::countParentDfn (uint32 round) const
353 // Checkout recursive calls
354 if (round > NLGEORGES_MAX_RECURSION)
356 // Turn around..
357 warning (false, "countParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
358 return 0;
361 uint count = 0;
362 uint i;
363 for (i=0; i<Parents.size (); i++)
365 count += Parents[i].Parent->countParentDfn (round+1);
367 return count+1;
370 // ***************************************************************************
372 void CFormDfn::getParentDfn (std::vector<CFormDfn*> &array, uint32 round)
374 // Checkout recursive calls
375 if (round > NLGEORGES_MAX_RECURSION)
377 // Turn around..
378 warning (false, "getParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
379 return;
382 //uint count = 0;
383 uint i;
384 for (i=0; i<Parents.size (); i++)
386 Parents[i].Parent->getParentDfn (array, round+1);
388 array.push_back (this);
391 // ***************************************************************************
393 void CFormDfn::getParentDfn (std::vector<const CFormDfn*> &array, uint32 round) const
395 // Checkout recursive calls
396 if (round > NLGEORGES_MAX_RECURSION)
398 // Turn around..
399 warning (false, "getParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
400 return;
403 //uint count = 0;
404 uint i;
405 for (i=0; i<Parents.size (); i++)
407 Parents[i].Parent->getParentDfn (array, round+1);
409 array.push_back (this);
412 // ***************************************************************************
414 uint CFormDfn::getNumParent () const
416 return (uint)Parents.size ();
419 // ***************************************************************************
421 CFormDfn *CFormDfn::getParent (uint parent) const
423 return Parents[parent].Parent;
426 // ***************************************************************************
428 const string& CFormDfn::getParentFilename (uint parent) const
430 return Parents[parent].ParentFilename;
433 // ***************************************************************************
435 uint CFormDfn::getNumEntry () const
437 return (uint)Entries.size();
440 // ***************************************************************************
442 void CFormDfn::setNumEntry (uint size)
444 Entries.resize (size);
447 // ***************************************************************************
449 const CFormDfn::CEntry &CFormDfn::getEntry (uint entry) const
451 return Entries[entry];
454 // ***************************************************************************
456 CFormDfn::CEntry &CFormDfn::getEntry (uint entry)
458 return Entries[entry];
461 // ***************************************************************************
463 void CFormDfn::setNumParent (uint size)
465 Parents.resize (size);
468 // ***************************************************************************
470 void CFormDfn::setParent (uint parent, CFormLoader &loader, const std::string &filename)
472 if (filename.empty())
473 Parents[parent].Parent = NULL;
474 else
475 Parents[parent].Parent = loader.loadFormDfn (filename, false);
476 Parents[parent].ParentFilename = filename;
479 // ***************************************************************************
481 void CFormDfn::CEntry::setType (CFormLoader &loader, const std::string &filename)
483 TypeElement = EntryType;
484 Dfn = NULL;
485 Filename = filename;
486 Type = loader.loadType (filename);
489 void CFormDfn::CEntry::setType( TEntryType type )
491 TypeElement = type;
494 // ***************************************************************************
496 void CFormDfn::CEntry::setDfn (CFormLoader &loader, const std::string &filename)
498 TypeElement = EntryDfn;
499 Filename = filename;
500 Type = NULL;
501 Dfn = loader.loadFormDfn (filename, false);
504 // ***************************************************************************
506 void CFormDfn::CEntry::setDfnPointer ()
508 TypeElement = EntryVirtualDfn;
509 Filename.clear();
510 Type = NULL;
511 Dfn = NULL;
514 // ***************************************************************************
516 const std::string &CFormDfn::CEntry::getName () const
518 return Name;
521 // ***************************************************************************
523 void CFormDfn::CEntry::setName (const std::string &name)
525 Name = name;
528 // ***************************************************************************
530 const std::string &CFormDfn::CEntry::getDefault () const
532 return Default;
535 // ***************************************************************************
537 void CFormDfn::CEntry::setDefault (const std::string &def)
539 Default = def;
542 // ***************************************************************************
544 void CFormDfn::CEntry::setArrayFlag (bool flag)
546 Array = flag;
549 // ***************************************************************************
551 bool CFormDfn::CEntry::getArrayFlag () const
553 return Array;
556 // ***************************************************************************
558 UFormDfn::TEntryType CFormDfn::CEntry::getType () const
560 return TypeElement;
563 // ***************************************************************************
565 const std::string &CFormDfn::CEntry::getFilename() const
567 return Filename;
570 // ***************************************************************************
572 void CFormDfn::CEntry::setFilename (const std::string &def)
574 Filename = def;
577 // ***************************************************************************
579 CType *CFormDfn::CEntry::getTypePtr ()
581 return Type;
584 // ***************************************************************************
586 CFormDfn *CFormDfn::CEntry::getDfnPtr ()
588 return Dfn;
591 // ***************************************************************************
593 const CType *CFormDfn::CEntry::getTypePtr () const
595 return Type;
598 // ***************************************************************************
600 const CFormDfn *CFormDfn::CEntry::getDfnPtr () const
602 return Dfn;
605 // ***************************************************************************
607 CFormDfn *CFormDfn::getSubDfn (uint index, uint &dfnIndex)
609 // Get the sub DFN
610 vector<CFormDfn*> parentDfn;
611 parentDfn.reserve (countParentDfn ());
612 getParentDfn (parentDfn);
614 // For each parent
615 uint dfn;
616 dfnIndex = index;
617 uint parentSize = (uint)parentDfn.size();
618 for (dfn=0; dfn<parentSize; dfn++)
620 // Good element ?
621 uint size = (uint)parentDfn[dfn]->Entries.size ();
622 if (dfnIndex<size)
623 return parentDfn[dfn];
624 dfnIndex -= size;
627 // Should be found..
628 nlstop;
629 return NULL;
632 // ***************************************************************************
634 const CFormDfn *CFormDfn::getSubDfn (uint index, uint &dfnIndex) const
636 // Get the sub DFN
637 vector<const CFormDfn*> parentDfn;
638 parentDfn.reserve (countParentDfn ());
639 getParentDfn (parentDfn);
641 // For each parent
642 uint dfn;
643 dfnIndex = index;
644 uint parentSize = (uint)parentDfn.size();
645 for (dfn=0; dfn<parentSize; dfn++)
647 // Good element ?
648 uint size = (uint)parentDfn[dfn]->Entries.size ();
649 if (dfnIndex<size)
650 return parentDfn[dfn];
651 dfnIndex -= size;
654 // Should be found..
655 nlstop;
656 return NULL;
659 // ***************************************************************************
661 bool CFormDfn::getEntryType (uint entry, TEntryType &type, bool &array) const
663 if (entry < Entries.size ())
665 type = Entries[entry].TypeElement;
666 array = Entries[entry].Array;
667 return true;
669 warning (false, "getEntryType", "Wrong entry ID.");
670 return false;
673 // ***************************************************************************
675 bool CFormDfn::getEntryFilename (uint entry, std::string& filename) const
677 if (entry < Entries.size ())
679 if (Entries[entry].TypeElement != EntryVirtualDfn)
681 filename = Entries[entry].Filename;
682 return true;
684 warning (false, "getEntryFilename", "The entry is a virtual DFN.");
685 return false;
687 warning (false, "getEntryFilename", "Wrong entry ID.");
688 return false;
691 // ***************************************************************************
693 bool CFormDfn::getEntryFilenameExt (uint entry, std::string& filename) const
695 if (entry < Entries.size ())
697 filename = Entries[entry].FilenameExt;
698 return true;
700 warning (false, "getEntryFilenameExt", "Wrong entry ID.");
701 return false;
704 // ***************************************************************************
706 bool CFormDfn::getEntryIndexByName (uint &entry, const std::string &name) const
708 uint entryIndex=0;
709 while (entryIndex<Entries.size ())
711 if (Entries[entryIndex].Name==name)
713 entry=entryIndex;
714 return true;
716 entryIndex++;
718 entry = std::numeric_limits<uint>::max();
719 return false;
722 // ***************************************************************************
724 bool CFormDfn::getEntryName (uint entry, std::string &name) const
726 if (entry < Entries.size ())
728 name = Entries[entry].Name;
729 return true;
731 warning (false, "getEntryName", "Wrong entry ID.");
732 return false;
735 // ***************************************************************************
737 bool CFormDfn::getEntryDfn (uint entry, UFormDfn **dfn)
739 if (entry < Entries.size ())
741 if (Entries[entry].TypeElement == EntryDfn)
743 *dfn = Entries[entry].Dfn;
744 return true;
746 else
747 warning (false, "getEntryDfn", "This entry is not a DFN.");
749 warning (false, "getEntryDfn", "Wrong entry ID.");
750 return false;
753 bool CFormDfn::getEntryByName (const std::string &name, CFormDfn::CEntry **entry)
755 int entryIndex=(int)Entries.size ()-1;
756 while (entryIndex>=0)
758 CEntry *entryPtr=&Entries[entryIndex];
759 if (entryPtr->getName()==name)
761 *entry=entryPtr;
762 return true;
764 entryIndex--;
766 *entry=NULL;
767 return false;
770 bool CFormDfn::getEntryDfnByName (const std::string &name, UFormDfn **dfn)
772 CFormDfn::CEntry *entry;
773 if (getEntryByName (name, &entry))
775 *dfn=entry->getDfnPtr();
776 return true;
778 *dfn=NULL;
779 return false;
782 bool CFormDfn::isAnArrayEntryByName (const std::string &name) const
784 CFormDfn::CEntry *entry;
785 if (const_cast<CFormDfn*>(this)->getEntryByName (name, &entry))
787 return entry->getArrayFlag();
789 return false;
792 // ***************************************************************************
794 bool CFormDfn::getEntryType (uint entry, UType **type)
796 if (entry < Entries.size ())
798 if (Entries[entry].TypeElement == EntryType)
800 *type = Entries[entry].Type;
801 return true;
803 else
804 warning (false, "getEntryType", "This entry is not a type.");
806 warning (false, "getEntryType", "Wrong entry ID.");
807 return false;
810 // ***************************************************************************
812 uint CFormDfn::getNumParents () const
814 return (uint)Parents.size ();
817 // ***************************************************************************
819 bool CFormDfn::getParent (uint parent, UFormDfn **parentRet)
821 if (parent < Parents.size ())
823 *parentRet = Parents[parent].Parent;
824 return true;
826 warning (false, "getParent", "Wrong parent ID.");
827 return false;
831 // ***************************************************************************
833 bool CFormDfn::getParentFilename (uint parent, std::string &filename) const
835 if (parent < Parents.size ())
837 filename = Parents[parent].ParentFilename;
838 return true;
840 warning (false, "getParentFilename", "Wrong parent ID.");
841 return false;
844 // ***************************************************************************
846 const std::string& CFormDfn::getComment () const
848 return Header.Comments;
851 // ***************************************************************************
853 const std::string &CFormDfn::CEntry::getFilenameExt() const
855 return FilenameExt;
858 // ***************************************************************************
860 void CFormDfn::CEntry::setFilenameExt (const std::string &ext)
862 FilenameExt = ext;
865 // ***************************************************************************
867 void CFormDfn::warning (bool exception, const std::string &function, const char *format, ... ) const
869 // Make a buffer string
870 va_list args;
871 va_start( args, format );
872 char buffer[1024];
873 vsnprintf( buffer, 1024, format, args );
874 va_end( args );
876 // Set the warning
877 NLGEORGES::warning (exception, "(CFormDfn::%s) in form DFN (%s) : %s", function.c_str(), _Filename.c_str (), buffer);
880 // ***************************************************************************
882 void CFormDfn::getDependencies (std::set<std::string> &dependencies) const
884 // Scan only if not already inserted
885 if (dependencies.insert (toLowerAscii(CFile::getFilename (_Filename))).second)
887 // Add parents
888 uint i;
889 for (i=0; i<Parents.size (); i++)
891 Parents[i].Parent->getDependencies (dependencies);
894 // Add entries
895 for (i=0; i<Entries.size (); i++)
897 if (Entries[i].getDfnPtr ())
898 Entries[i].getDfnPtr ()->getDependencies (dependencies);
899 if (Entries[i].getTypePtr ())
901 dependencies.insert (toLowerAscii(CFile::getFilename (Entries[i].getFilename())));
907 // ***************************************************************************
909 } // NLGEORGES