1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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>
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"
35 using namespace NLMISC
;
39 #define stricmp strcasecmp
46 // ***************************************************************************
48 void warning (bool exception
, const char *format
, ... );
50 // ***************************************************************************
52 void CFormDfn::addEntry( const std::string
&name
)
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
;
65 // ***************************************************************************
67 void CFormDfn::write (xmlDocPtr doc
, const std::string
&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
);
78 for (parent
=0; parent
<Parents
.size(); parent
++)
80 // Parent name not empty ?
81 if (!Parents
[parent
].ParentFilename
.empty ())
84 xmlNodePtr parentNode
= xmlNewChild ( node
, NULL
, (const xmlChar
*)"PARENT", NULL
);
87 xmlSetProp (parentNode
, (const xmlChar
*)"Name", (const xmlChar
*)Parents
[parent
].ParentFilename
.c_str());
93 for (elm
=0; elm
<Entries
.size(); elm
++)
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());
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());
112 case UFormDfn::EntryVirtualDfn
:
113 xmlSetProp (elmPtr
, (const xmlChar
*)"Type", (const xmlChar
*)"DfnPointer");
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 ());
130 // ***************************************************************************
132 void CFormDfn::read (xmlNodePtr root
, CFormLoader
&loader
, bool forceLoad
, const std::string
&filename
)
135 _Filename
= CFile::getFilename (filename
);
138 if ( ((const char*)root
->name
== NULL
) || (strcmp ((const char*)root
->name
, "DFN") != 0) )
141 warning (true, "read", "XML Syntax error in block line %d, node (%s) should be DFN.", (sint
)root
->line
, root
->name
);
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
)
154 const char *parentFilename
= (const char*)xmlGetProp (parent
, (xmlChar
*)"Name");
157 Parents
[parentNumber
].ParentFilename
= parentFilename
;
160 xmlFree ((void*)parentFilename
);
163 Parents
[parentNumber
].Parent
= loader
.loadFormDfn (Parents
[parentNumber
].ParentFilename
.c_str (), forceLoad
);
164 if ((Parents
[parentNumber
].Parent
== NULL
) && !forceLoad
)
167 warning (true, "read", "Can't load parent DFN file (%s).", Parents
[parentNumber
].ParentFilename
.c_str ());
173 warning (true, "read", "XML Syntax error in block (%s) line %d, aguments Name not found.",
174 parent
->name
, (sint
)parent
->line
);
178 parent
= CIXml::getNextChildNode (parent
, "PARENT");
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
)
197 const char *value
= (const char*)xmlGetProp (child
, (xmlChar
*)"Name");
201 Entries
[childNumber
].Name
= value
;
204 xmlFree ((void*)value
);
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");
215 Entries
[childNumber
].Filename
= filename
;
218 xmlFree ((void*)filename
);
222 Entries
[childNumber
].Filename
.clear ();
225 const char *filenameExt
= (const char*)xmlGetProp (child
, (xmlChar
*)"FilenameExt");
228 Entries
[childNumber
].FilenameExt
= filenameExt
;
231 xmlFree ((void*)filenameExt
);
235 Entries
[childNumber
].FilenameExt
= "*.*";
239 const char *typeName
= (const char*)xmlGetProp (child
, (xmlChar
*)"Type");
244 if (stricmp (typeName
, "Type") == 0)
246 Entries
[childNumber
].TypeElement
= UFormDfn::EntryType
;
250 if (!Entries
[childNumber
].Filename
.empty ())
252 Entries
[childNumber
].Type
= loader
.loadType (Entries
[childNumber
].Filename
.c_str ());
253 if ((Entries
[childNumber
].Type
== NULL
) && !forceLoad
)
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");
264 Entries
[childNumber
].Default
= defaultName
;
267 xmlFree ((void*)defaultName
);
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
;
283 if (!Entries
[childNumber
].Filename
.empty ())
286 Entries
[childNumber
].Dfn
= loader
.loadFormDfn (Entries
[childNumber
].Filename
.c_str (), forceLoad
);
287 if ((Entries
[childNumber
].Dfn
== NULL
) && !forceLoad
)
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 ());
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
;
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
);
313 xmlFree ((void*)typeName
);
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");
327 Entries
[childNumber
].Array
= (stricmp (arrayFlag
, "true") == 0);
330 xmlFree ((void*)arrayFlag
);
336 warning (true, "read", "XML Syntax error in block (%s) line %d, aguments Name not found.",
337 root
->name
, (sint
)root
->line
);
341 child
= CIXml::getNextChildNode (child
, "ELEMENT");
349 // ***************************************************************************
351 uint
CFormDfn::countParentDfn (uint32 round
) const
353 // Checkout recursive calls
354 if (round
> NLGEORGES_MAX_RECURSION
)
357 warning (false, "countParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
363 for (i
=0; i
<Parents
.size (); i
++)
365 count
+= Parents
[i
].Parent
->countParentDfn (round
+1);
370 // ***************************************************************************
372 void CFormDfn::getParentDfn (std::vector
<CFormDfn
*> &array
, uint32 round
)
374 // Checkout recursive calls
375 if (round
> NLGEORGES_MAX_RECURSION
)
378 warning (false, "getParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
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
)
399 warning (false, "getParentDfn", "Recursive call on the same DFN, look for loop inheritances.");
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
;
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
;
486 Type
= loader
.loadType (filename
);
489 void CFormDfn::CEntry::setType( TEntryType type
)
494 // ***************************************************************************
496 void CFormDfn::CEntry::setDfn (CFormLoader
&loader
, const std::string
&filename
)
498 TypeElement
= EntryDfn
;
501 Dfn
= loader
.loadFormDfn (filename
, false);
504 // ***************************************************************************
506 void CFormDfn::CEntry::setDfnPointer ()
508 TypeElement
= EntryVirtualDfn
;
514 // ***************************************************************************
516 const std::string
&CFormDfn::CEntry::getName () const
521 // ***************************************************************************
523 void CFormDfn::CEntry::setName (const std::string
&name
)
528 // ***************************************************************************
530 const std::string
&CFormDfn::CEntry::getDefault () const
535 // ***************************************************************************
537 void CFormDfn::CEntry::setDefault (const std::string
&def
)
542 // ***************************************************************************
544 void CFormDfn::CEntry::setArrayFlag (bool flag
)
549 // ***************************************************************************
551 bool CFormDfn::CEntry::getArrayFlag () const
556 // ***************************************************************************
558 UFormDfn::TEntryType
CFormDfn::CEntry::getType () const
563 // ***************************************************************************
565 const std::string
&CFormDfn::CEntry::getFilename() const
570 // ***************************************************************************
572 void CFormDfn::CEntry::setFilename (const std::string
&def
)
577 // ***************************************************************************
579 CType
*CFormDfn::CEntry::getTypePtr ()
584 // ***************************************************************************
586 CFormDfn
*CFormDfn::CEntry::getDfnPtr ()
591 // ***************************************************************************
593 const CType
*CFormDfn::CEntry::getTypePtr () const
598 // ***************************************************************************
600 const CFormDfn
*CFormDfn::CEntry::getDfnPtr () const
605 // ***************************************************************************
607 CFormDfn
*CFormDfn::getSubDfn (uint index
, uint
&dfnIndex
)
610 vector
<CFormDfn
*> parentDfn
;
611 parentDfn
.reserve (countParentDfn ());
612 getParentDfn (parentDfn
);
617 uint parentSize
= (uint
)parentDfn
.size();
618 for (dfn
=0; dfn
<parentSize
; dfn
++)
621 uint size
= (uint
)parentDfn
[dfn
]->Entries
.size ();
623 return parentDfn
[dfn
];
632 // ***************************************************************************
634 const CFormDfn
*CFormDfn::getSubDfn (uint index
, uint
&dfnIndex
) const
637 vector
<const CFormDfn
*> parentDfn
;
638 parentDfn
.reserve (countParentDfn ());
639 getParentDfn (parentDfn
);
644 uint parentSize
= (uint
)parentDfn
.size();
645 for (dfn
=0; dfn
<parentSize
; dfn
++)
648 uint size
= (uint
)parentDfn
[dfn
]->Entries
.size ();
650 return parentDfn
[dfn
];
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
;
669 warning (false, "getEntryType", "Wrong entry ID.");
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
;
684 warning (false, "getEntryFilename", "The entry is a virtual DFN.");
687 warning (false, "getEntryFilename", "Wrong entry ID.");
691 // ***************************************************************************
693 bool CFormDfn::getEntryFilenameExt (uint entry
, std::string
& filename
) const
695 if (entry
< Entries
.size ())
697 filename
= Entries
[entry
].FilenameExt
;
700 warning (false, "getEntryFilenameExt", "Wrong entry ID.");
704 // ***************************************************************************
706 bool CFormDfn::getEntryIndexByName (uint
&entry
, const std::string
&name
) const
709 while (entryIndex
<Entries
.size ())
711 if (Entries
[entryIndex
].Name
==name
)
718 entry
= std::numeric_limits
<uint
>::max();
722 // ***************************************************************************
724 bool CFormDfn::getEntryName (uint entry
, std::string
&name
) const
726 if (entry
< Entries
.size ())
728 name
= Entries
[entry
].Name
;
731 warning (false, "getEntryName", "Wrong entry ID.");
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
;
747 warning (false, "getEntryDfn", "This entry is not a DFN.");
749 warning (false, "getEntryDfn", "Wrong entry ID.");
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
)
770 bool CFormDfn::getEntryDfnByName (const std::string
&name
, UFormDfn
**dfn
)
772 CFormDfn::CEntry
*entry
;
773 if (getEntryByName (name
, &entry
))
775 *dfn
=entry
->getDfnPtr();
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();
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
;
804 warning (false, "getEntryType", "This entry is not a type.");
806 warning (false, "getEntryType", "Wrong entry ID.");
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
;
826 warning (false, "getParent", "Wrong parent ID.");
831 // ***************************************************************************
833 bool CFormDfn::getParentFilename (uint parent
, std::string
&filename
) const
835 if (parent
< Parents
.size ())
837 filename
= Parents
[parent
].ParentFilename
;
840 warning (false, "getParentFilename", "Wrong parent ID.");
844 // ***************************************************************************
846 const std::string
& CFormDfn::getComment () const
848 return Header
.Comments
;
851 // ***************************************************************************
853 const std::string
&CFormDfn::CEntry::getFilenameExt() const
858 // ***************************************************************************
860 void CFormDfn::CEntry::setFilenameExt (const std::string
&ext
)
865 // ***************************************************************************
867 void CFormDfn::warning (bool exception
, const std::string
&function
, const char *format
, ... ) const
869 // Make a buffer string
871 va_start( args
, format
);
873 vsnprintf( buffer
, 1024, format
, args
);
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
)
889 for (i
=0; i
<Parents
.size (); i
++)
891 Parents
[i
].Parent
->getDependencies (dependencies
);
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 // ***************************************************************************