Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / georges / form.cpp
blob63e4ee2eddef6a6594706735e94ec2455a576f06
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-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdgeorges.h"
22 #include "nel/misc/i_xml.h"
23 #include "nel/misc/o_xml.h"
24 #include "nel/misc/common.h"
25 #include "nel/misc/path.h"
27 #include "nel/georges/form.h"
28 #include "nel/georges/form_loader.h"
30 #ifdef DEBUG_NEW
31 #define new DEBUG_NEW
32 #endif
34 using namespace NLMISC;
36 namespace NLGEORGES
39 // ***************************************************************************
40 // Misc
41 // ***************************************************************************
43 void warning (bool exception, const char *format, ... )
45 // Make a buffer string
46 va_list args;
47 va_start( args, format );
48 char buffer[1024];
49 vsnprintf( buffer, 1024, format, args );
50 va_end( args );
52 // Set the warning
53 if (exception)
55 // Make an error message
56 char tmp[1024];
57 smprintf (tmp, 1024, "NeL::Georges %s", buffer);
58 throw EXmlParsingError (tmp);
60 else
62 nlwarning ("NeL::Georges %s", buffer);
66 // ***************************************************************************
67 // UForm
68 // ***************************************************************************
70 UForm::~UForm ()
74 // ***************************************************************************
76 UFormElm& CForm::getRootNode ()
78 return Elements;
81 // ***************************************************************************
83 const UFormElm& CForm::getRootNode () const
85 return Elements;
88 // ***************************************************************************
89 // CForm
90 // ***************************************************************************
92 CForm::CForm () : Elements (this, NULL, NULL, 0xffffffff)
94 uint i;
95 for (i=0; i<HeldElementCount; i++)
97 HeldElements[i] = new CFormElmStruct (this, NULL, NULL, 0xffffffff);
101 // ***************************************************************************
103 CForm::~CForm ()
105 uint i;
106 for (i=0; i<HeldElementCount; i++)
108 delete HeldElements[i];
112 // ***************************************************************************
114 void CForm::write (xmlDocPtr doc, const std::string &filename)
116 // Save the filename
117 if (!filename.empty())
118 _Filename = CFile::getFilename (filename);
120 // Create the first node
121 xmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)"FORM", NULL);
122 xmlDocSetRootElement (doc, node);
124 // List of parent
125 for (uint parent=0; parent<ParentList.size (); parent++)
127 // Parent name not empty ?
128 if (!(ParentList[parent].ParentFilename.empty()))
130 // Add a parent node
131 xmlNodePtr parentNode = xmlNewChild ( node, NULL, (const xmlChar*)"PARENT", NULL );
132 xmlSetProp (parentNode, (const xmlChar*)"Filename", (const xmlChar*)ParentList[parent].ParentFilename.c_str());
136 // Write elements
137 Elements.write (node, this, std::string(), true);
139 // Write held elements
140 uint i;
141 for (i=0; i<HeldElementCount; i++)
143 HeldElements[i]->write (node, this, std::string(), true);
146 // Header
147 Header.write (node);
150 // ***************************************************************************
152 void CForm::readParent (const char *parent, CFormLoader &loader)
154 // Load the parent
155 CForm *theParent = (CForm*)loader.loadForm (parent);
156 if (theParent != NULL)
158 // Set the parent
159 if (!insertParent (getParentCount (), parent, theParent))
161 // Make an error message
162 std::string parentName = parent;
164 // Delete the value
165 xmlFree ((void*)parent);
167 // Throw exception
168 warning (true, "readParent", "Can't set the parent FORM named (%s). Check if it is the same form or if it use a differnt formDfn.", parentName.c_str ());
171 else
173 // Make an error message
174 std::string parentName = parent;
176 // Delete the value
177 xmlFree ((void*)parent);
179 // Throw exception
180 warning (true, "readParent", "Can't load the parent FORM named (%s).", parentName.c_str ());
184 // ***************************************************************************
186 void CForm::read (xmlNodePtr node, CFormLoader &loader, CFormDfn *dfn, const std::string &filename)
188 // Save the filename
189 _Filename = CFile::getFilename (filename);
191 // Reset form
192 clean ();
194 // Save the dfn
195 _Dfn = dfn;
197 // Check node name
198 if ( ((const char*)node->name == NULL) || (strcmp ((const char*)node->name, "FORM") != 0) )
200 // Make an error message
201 warning (true, "read", "XML Syntax error in block line %d, node (%s) should be FORM.",
202 (sint)node->line, node->name);
205 // Get first struct node
206 xmlNodePtr child = CIXml::getFirstChildNode (node, "STRUCT");
207 if (child == NULL)
209 // Throw exception
210 warning (true, "read", "Syntax error in block line %d, node (%s) should have a STRUCT child node.",
211 (sint)node->line, node->name);
214 // Read the struct
215 Elements.read (child, loader, dfn, this);
217 // Get next struct node
218 child = CIXml::getNextChildNode (node, "STRUCT");
219 uint index = 0;
220 while ( (child != NULL) && (index < HeldElementCount))
222 HeldElements[index]->read (child, loader, dfn, this);
223 index++;
225 while (index < HeldElementCount)
227 // Build the Form
228 HeldElements[index]->build (dfn);
229 index++;
232 // Get the old parent parameter
233 const char *parent = (const char*)xmlGetProp (node, (xmlChar*)"Parent");
234 if (parent)
236 // Add a parent, xmlFree is done by readParent
237 readParent (parent, loader);
240 // Read the new parent nodes
241 uint parentCount = CIXml::countChildren (node, "PARENT");
243 // Reserve some parents
244 ParentList.reserve (ParentList.size () + parentCount);
246 // Enum children node
247 child = CIXml::getFirstChildNode (node, "PARENT");
248 while (child)
250 parent = (const char*)xmlGetProp (child, (xmlChar*)"Filename");
252 // Add a parent, xmlFree is done by readParent
253 readParent (parent, loader);
255 // Next node <PARENT>
256 child = CIXml::getNextChildNode (child, "PARENT");
259 // Read the header
260 Header.read (node);
263 // ***************************************************************************
265 const std::string &CForm::getComment () const
267 return Header.Comments;
270 // ***************************************************************************
272 void CForm::write (NLMISC::IStream &stream)
274 // Xml stream
275 COXml xmlStream;
276 xmlStream.init (&stream);
278 // Write the file
279 write (xmlStream.getDocument (), std::string());
282 // ***************************************************************************
284 bool CForm::insertParent (uint before, const std::string &filename, CForm *parent)
286 // Set or reset ?
287 nlassert (parent);
289 // Must have the same DFN
290 if (parent->Elements.FormDfn == Elements.FormDfn)
292 // Set members
293 std::vector<CParent>::iterator ite = ParentList.insert (ParentList.begin() + before, CParent());
294 ite->Parent = parent;
295 ite->ParentFilename = filename;
297 return true;
299 else
301 // Output an error
302 warning (false, "insertParent", "Can't insert parent form (%s) that has not the same DFN.", filename.c_str());
305 return false;
308 // ***************************************************************************
310 void CForm::removeParent (uint parent)
312 ParentList.erase (ParentList.begin() + parent);
315 // ***************************************************************************
317 CForm *CForm::getParent (uint parent) const
319 return ParentList[parent].Parent;
322 // ***************************************************************************
324 const std::string &CForm::getParentFilename (uint parent) const
326 return ParentList[parent].ParentFilename;
329 // ***************************************************************************
331 uint CForm::getParentCount () const
333 return (uint)ParentList.size ();
336 // ***************************************************************************
338 void CForm::clean ()
340 clearParents ();
343 // ***************************************************************************
345 void CForm::clearParents ()
347 ParentList.clear ();
350 // ***************************************************************************
352 const std::string &CForm::getFilename () const
354 return _Filename;
357 // ***************************************************************************
359 void CForm::warning (bool exception, const std::string &function, const char *format, ... ) const
361 // Make a buffer string
362 va_list args;
363 va_start( args, format );
364 char buffer[1024];
365 vsnprintf( buffer, 1024, format, args );
366 va_end( args );
368 // Set the warning
369 NLGEORGES::warning (exception, "(CForm::%s) in form (%s) : %s", function.c_str(), _Filename.c_str (), buffer);
372 // ***************************************************************************
374 void CForm::getDependencies (std::set<std::string> &dependencies) const
376 // Add me
377 if (dependencies.insert (toLowerAscii(CFile::getFilename (_Filename))).second)
379 // Add parents
380 uint i;
381 for (i=0; i<ParentList.size (); i++)
383 if (ParentList[i].Parent)
385 ParentList[i].Parent->getDependencies (dependencies);
389 // Add elements
390 Elements.getDependencies (dependencies);
394 // ***************************************************************************
396 uint CForm::getNumParent () const
398 return getParentCount();
401 // ***************************************************************************
403 UForm *CForm::getParentForm (uint parent) const
405 CForm *form = getParent (parent);
406 return form;
409 // ***************************************************************************
411 } // NLGEORGES