1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012-2014 - Scilab Enterprises - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 #include <string>
17 
18 #include "XMLObject.hxx"
19 #include "XMLDocument.hxx"
20 #include "XMLAttr.hxx"
21 #include "XMLElement.hxx"
22 #include "XMLNodeList.hxx"
23 #include "VariableScope.hxx"
24 
25 namespace org_modules_xml
26 {
27 
XMLNodeList(const XMLDocument & _doc,xmlNode * _parent)28 XMLNodeList::XMLNodeList(const XMLDocument & _doc, xmlNode * _parent): XMLList(), doc(_doc)
29 {
30     parent = _parent;
31     size = getNodeListSize(parent->children);
32     prev = 1;
33     prevNode = parent->children;
34     scope->registerPointers(parent->children, this);
35     id = scope->getVariableId(*this);
36 }
37 
~XMLNodeList()38 XMLNodeList::~XMLNodeList()
39 {
40     scope->unregisterNodeListPointer(parent->children);
41     scope->removeId(id);
42 }
43 
getRealXMLPointer() const44 void *XMLNodeList::getRealXMLPointer() const
45 {
46     return static_cast < void *>(parent->children);
47 }
48 
getContentFromList() const49 const char **XMLNodeList::getContentFromList() const
50 {
51     const char **list = new const char *[size];
52     int i = 0;
53     for (xmlNode * cur = parent->children; cur; cur = cur->next, i++)
54     {
55         list[i] = (const char *)xmlNodeGetContent(cur);
56     }
57 
58     return list;
59 }
60 
getNameFromList() const61 const char **XMLNodeList::getNameFromList() const
62 {
63     const char **list = new const char *[size];
64     int i = 0;
65     for (xmlNode * cur = parent->children; cur; cur = cur->next, i++)
66     {
67         list[i] = cur->name ? (const char *)cur->name : "";
68     }
69 
70     return list;
71 }
72 
setAttributeValue(const char ** prefix,const char ** name,const char ** value,int lsize) const73 void XMLNodeList::setAttributeValue(const char **prefix, const char **name, const char **value, int lsize) const
74 {
75     for (xmlNode * cur = parent->children; cur; cur = cur->next)
76     {
77         XMLAttr::setAttributeValue(cur, prefix, name, value, lsize);
78     }
79 }
80 
setAttributeValue(const char ** name,const char ** value,int lsize) const81 void XMLNodeList::setAttributeValue(const char **name, const char **value, int lsize) const
82 {
83     for (xmlNode * cur = parent->children; cur; cur = cur->next)
84     {
85         XMLAttr::setAttributeValue(cur, name, value, lsize);
86     }
87 }
88 
remove() const89 void XMLNodeList::remove() const
90 {
91     xmlNode *cur = parent->children;
92 
93     while (cur != NULL)
94     {
95         xmlNode *nxt = cur->next;
96         xmlUnlinkNode(cur);
97         xmlFreeNode(cur);
98         cur = nxt;
99     }
100 }
101 
getXMLObjectParent() const102 const XMLObject *XMLNodeList::getXMLObjectParent() const
103 {
104     return &doc;
105 }
106 
dump() const107 const std::string XMLNodeList::dump() const
108 {
109     xmlBufferPtr buffer = xmlBufferCreate();
110     for (xmlNode * cur = parent->children; cur; cur = cur->next)
111     {
112         xmlNodeDump(buffer, doc.getRealDocument(), cur, 0, 1);
113         xmlBufferAdd(buffer, (xmlChar *) "\n", (int)strlen("\n"));
114     }
115     std::string str = std::string((const char *)buffer->content);
116 
117     xmlBufferFree(buffer);
118 
119     return str;
120 }
121 
getListElement(int index)122 const XMLObject *XMLNodeList::getListElement(int index)
123 {
124     xmlNode *n = getListNode(index);
125 
126     if (n)
127     {
128         XMLObject *obj = scope->getXMLObjectFromLibXMLPtr(n);
129 
130         if (obj)
131         {
132             return static_cast < XMLElement * >(obj);
133         }
134 
135         return new XMLElement(doc, n);
136     }
137 
138     return 0;
139 }
140 
removeElementAtPosition(int index)141 void XMLNodeList::removeElementAtPosition(int index)
142 {
143     if (size && index >= 1 && index <= size)
144     {
145         if (index == 1)
146         {
147             xmlNode *n = parent->children;
148 
149             scope->unregisterNodeListPointer(n);
150             xmlUnlinkNode(n);
151             xmlFreeNode(n);
152             size--;
153             if (size == 0)
154             {
155                 parent->children = 0;
156             }
157             prevNode = parent->children;
158             scope->registerPointers(parent->children, this);
159             prev = 1;
160         }
161         else
162         {
163             xmlNode *n = getListNode(index);
164 
165             if (n)
166             {
167                 xmlNode *next = n->next;
168 
169                 prevNode = prevNode->prev;
170                 prev--;
171                 xmlUnlinkNode(n);
172                 xmlFreeNode(n);
173                 prevNode->next = next;
174                 size--;
175             }
176         }
177     }
178 }
179 
setElementAtPosition(double index,const XMLElement & elem)180 void XMLNodeList::setElementAtPosition(double index, const XMLElement & elem)
181 {
182     if (size == 0)
183     {
184         insertAtEnd(elem);
185         prevNode = parent->children;
186         prev = 1;
187     }
188     else if (index < 1)
189     {
190         insertAtBeginning(elem);
191     }
192     else if (index > size)
193     {
194         insertAtEnd(elem);
195     }
196     else if ((int)index == index)
197     {
198         replaceAtIndex((int)index, elem);
199     }
200     else
201     {
202         insertAtIndex((int)index, elem);
203     }
204 }
205 
setElementAtPosition(double index,const XMLDocument & document)206 void XMLNodeList::setElementAtPosition(double index, const XMLDocument & document)
207 {
208     const XMLElement *e = document.getRoot();
209 
210     setElementAtPosition(index, *e);
211     delete e;
212 }
213 
setElementAtPosition(double index,const std::string & xmlCode)214 void XMLNodeList::setElementAtPosition(double index, const std::string & xmlCode)
215 {
216     std::string error;
217     XMLDocument document = XMLDocument(xmlCode, false, &error);
218 
219     if (error.empty())
220     {
221         setElementAtPosition(index, document);
222     }
223     else
224     {
225         xmlNode *n = xmlNewText((xmlChar *) xmlCode.c_str());
226 
227         setElementAtPosition(index, XMLElement(doc, n));
228     }
229 }
230 
setElementAtPosition(double index,const XMLNodeList & list)231 void XMLNodeList::setElementAtPosition(double index, const XMLNodeList & list)
232 {
233     if (list.getSize() && list.getRealNode() != parent)
234     {
235         xmlNode * node = 0;
236         xmlNode * snode = 0;
237         int pos = (int)index;
238 
239         if (index < 1)
240         {
241             pos = 1;
242         }
243         else if (index > size)
244         {
245             pos = size + 1;
246         }
247         else if ((int)index != index)
248         {
249             pos++;
250         }
251 
252         if (&list == this)
253         {
254             snode = node = xmlCopyNode(list.getRealNode(), 1);
255             for (xmlNode * cur = list.getRealNode()->next; cur; cur = cur->next)
256             {
257                 node->next = xmlCopyNode(cur, 1);
258                 node = node->next;
259             }
260             node = snode;
261         }
262         else
263         {
264             node = list.getRealNode();
265         }
266 
267         setElementAtPosition(index, XMLElement(doc, node));
268         for (xmlNode * cur = node->next; cur; cur = cur->next)
269         {
270             setElementAtPosition((double)(pos++) + 0.5, XMLElement(doc, cur));
271         }
272     }
273 }
274 
replaceAtIndex(int index,const XMLElement & elem)275 void XMLNodeList::replaceAtIndex(int index, const XMLElement & elem)
276 {
277     xmlNode *n = getListNode(index);
278 
279     if (n && n != elem.getRealNode())
280     {
281         if (index == 1)
282         {
283             scope->unregisterNodeListPointer(parent->children);
284         }
285         xmlNode *previous = n->prev;
286         xmlNode *next = n->next;
287         xmlNode *cpy = xmlCopyNode(elem.getRealNode(), 1);
288         xmlUnlinkNode(cpy);
289         xmlReplaceNode(n, cpy);
290         xmlFreeNode(n);
291         prevNode = cpy;
292         cpy->prev = previous;
293         cpy->next = next;
294         if (index == 1)
295         {
296             scope->registerPointers(parent->children, this);
297         }
298     }
299 }
300 
insertAtEnd(const XMLElement & elem)301 void XMLNodeList::insertAtEnd(const XMLElement & elem)
302 {
303     xmlNode *cpy = xmlCopyNode(elem.getRealNode(), 1);
304 
305     xmlUnlinkNode(cpy);
306     xmlAddChild(parent, cpy);
307     size++;
308 }
309 
insertAtBeginning(const XMLElement & elem)310 void XMLNodeList::insertAtBeginning(const XMLElement & elem)
311 {
312     xmlNode *cpy = xmlCopyNode(elem.getRealNode(), 1);
313 
314     xmlUnlinkNode(cpy);
315     scope->unregisterNodeListPointer(parent->children);
316     xmlAddPrevSibling(parent->children, cpy);
317     scope->registerPointers(parent->children, this);
318     size++;
319 }
320 
insertAtIndex(int index,const XMLElement & elem)321 void XMLNodeList::insertAtIndex(int index, const XMLElement & elem)
322 {
323     xmlNode *n = getListNode(index);
324 
325     if (n)
326     {
327         xmlNode *cpy = xmlCopyNode(elem.getRealNode(), 1);
328 
329         xmlUnlinkNode(cpy);
330         xmlAddNextSibling(n, cpy);
331         size++;
332     }
333 }
334 
getListNode(int index)335 xmlNode *XMLNodeList::getListNode(int index)
336 {
337     return XMLList::getListElement < xmlNode > (index, size, &prev, &prevNode);
338 }
339 
revalidateSize()340 void XMLNodeList::revalidateSize()
341 {
342     size = getNodeListSize(parent->children);
343     prevNode = parent->children;
344     prev = 1;
345 }
346 
getNodeListSize(xmlNode * node)347 int XMLNodeList::getNodeListSize(xmlNode * node)
348 {
349     int i = 0;
350 
351     for (xmlNode * n = node; n; n = n->next, i++)
352     {
353         ;
354     }
355 
356     return i;
357 }
358 }
359