1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - 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 "VariableScope.hxx"
17 #include "XMLObject.hxx"
18 #include "XMLNodeList.hxx"
19 #include <iostream>
20 
21 namespace org_modules_xml
22 {
23 xmlFreeFunc VariableScope::XMLFreeFunc = 0;
24 std::map < void *, XMLObject * > VariableScope::mapLibXMLToXMLObject = std::map < void *, XMLObject * >();
25 std::map < void *, XMLNodeList * > VariableScope::mapLibXMLToXMLNodeList = std::map < void *, XMLNodeList * >();
26 std::map < const XMLObject *, std::map < const XMLObject *, bool>*> VariableScope::parentToChildren = std::map < const XMLObject *, std::map < const XMLObject *, bool>*>();
27 
VariableScope(int _initialSize)28 VariableScope::VariableScope(int _initialSize)
29 {
30     position = -1;
31     initialSize = _initialSize;
32     scope = new std::vector < XMLObject * >();
33     freePlaces = new std::stack < int >();
34     initXMLMemory();
35 }
36 
~VariableScope()37 VariableScope::~VariableScope()
38 {
39     for (unsigned int i = 0; i < scope->size(); i++)
40     {
41         if ((*scope)[i])
42         {
43             delete(*scope)[i];
44         }
45     }
46     delete scope;
47     delete freePlaces;
48 }
49 
50 /**
51  * To avoid unused place in the vector, we use a stack which contains the empty places.
52  */
getVariableId(const XMLObject & obj)53 int VariableScope::getVariableId(const XMLObject & obj)
54 {
55     int returnValue;
56     const XMLObject *parent = obj.getXMLObjectParent();
57 
58     if (freePlaces->size() != 0)
59     {
60         returnValue = freePlaces->top();
61         freePlaces->pop();
62         (*scope)[returnValue] = const_cast < XMLObject * >(&obj);
63     }
64     else
65     {
66         returnValue = (int)scope->size();
67         scope->push_back(const_cast < XMLObject * >(&obj));
68     }
69 
70     if (parent)
71     {
72         std::map < const XMLObject *, std::map < const XMLObject *, bool>*>::const_iterator it = parentToChildren.find(parent);
73 
74         if (it != parentToChildren.end())
75         {
76             std::map < const XMLObject *, bool>::iterator jt = it->second->find(&obj);
77             if (jt != it->second->end())
78             {
79                 jt->second = true;
80             }
81             else
82             {
83                 it->second->insert(std::pair<const XMLObject *, bool>(&obj, true));
84             }
85         }
86         else
87         {
88             std::map < const XMLObject *, bool> * map = new std::map < const XMLObject *, bool>();
89             map->insert(std::pair<const XMLObject *, bool>(&obj, true));
90             parentToChildren.insert(std::pair<const XMLObject *, std::map < const XMLObject *, bool>*>(parent, map));
91         }
92     }
93 
94     return returnValue;
95 }
96 
getVariableFromId(int id)97 XMLObject *VariableScope::getVariableFromId(int id)
98 {
99     if (id >= 0 && id < (int)scope->size())
100     {
101         return (*scope)[id];
102     }
103 
104     return 0;
105 }
106 
107 /**
108  * There are two motivations to register libxml pointers:
109  *   i) if a XMLObject is associated to a libxml node, then when this node will be removed
110  *      the XMLObject must be destroyed. This job is done in _xmlFreeFunc which is called
111  *      by libxml when a libxml node is freed.
112  *   ii) To avoid multiple instances of a XMLObject which wraps the same node, the function
113  *       getXMLObjectFromLibXMLPtr is used to know if a XMLObject already exists for the
114  *       libxml node.
115  */
registerPointers(void * libxml,XMLObject * obj)116 void VariableScope::registerPointers(void *libxml, XMLObject * obj)
117 {
118     if (libxml)
119     {
120         mapLibXMLToXMLObject[libxml] = obj;
121     }
122 }
123 
registerPointers(void * libxml,XMLNodeList * nodeList)124 void VariableScope::registerPointers(void *libxml, XMLNodeList * nodeList)
125 {
126     if (libxml)
127     {
128         mapLibXMLToXMLNodeList[libxml] = nodeList;
129     }
130 }
131 
unregisterPointer(void * libxml)132 void VariableScope::unregisterPointer(void *libxml)
133 {
134     if (libxml)
135     {
136         mapLibXMLToXMLObject.erase(libxml);
137     }
138 }
139 
unregisterNodeListPointer(void * libxml)140 void VariableScope::unregisterNodeListPointer(void *libxml)
141 {
142     if (libxml)
143     {
144         mapLibXMLToXMLNodeList.erase(libxml);
145     }
146 }
147 
getXMLObjectFromLibXMLPtr(void * libxml) const148 XMLObject *VariableScope::getXMLObjectFromLibXMLPtr(void *libxml) const
149 {
150     if (libxml)
151     {
152         std::map < void *, XMLObject * >::const_iterator it = mapLibXMLToXMLObject.find(libxml);
153         if (it != mapLibXMLToXMLObject.end())
154         {
155             return it->second;
156         }
157     }
158 
159     return 0;
160 }
161 
getXMLNodeListFromLibXMLPtr(void * libxml) const162 XMLNodeList *VariableScope::getXMLNodeListFromLibXMLPtr(void *libxml)const
163 {
164     if (libxml)
165     {
166         std::map < void *, XMLNodeList * >::const_iterator it = mapLibXMLToXMLNodeList.find(libxml);
167         if (it != mapLibXMLToXMLNodeList.end())
168         {
169             return it->second;
170         }
171     }
172 
173     return 0;
174 }
175 
removeId(int id)176 void VariableScope::removeId(int id)
177 {
178     if (id >= 0 && id < (int)scope->size() && (*scope)[id])
179     {
180         XMLObject * const child = (*scope)[id];
181         removeChildFromParent(child);
182         removeDependencies(child);
183         (*scope)[id] = 0;
184         freePlaces->push(id);
185     }
186 }
187 
removeDependencies(XMLObject * obj)188 void VariableScope::removeDependencies(XMLObject * obj)
189 {
190     std::map < const XMLObject *, std::map < const XMLObject *, bool>*>::const_iterator it = parentToChildren.find(obj);
191 
192     if (it != parentToChildren.end())
193     {
194         for (std::map < const XMLObject *, bool>::const_iterator i = it->second->begin(), e = it->second->end(); i != e; ++i)
195         {
196             const XMLObject *child = i->first;
197             if (child && i->second && getVariableFromId(child->getId()) == child)
198             {
199                 delete child;
200             }
201         }
202         delete it->second;
203 
204         parentToChildren.erase(obj);
205     }
206 }
207 
initXMLMemory()208 void VariableScope::initXMLMemory()
209 {
210     xmlFreeFunc freeFunc;
211     xmlMallocFunc mallocFunc;
212     xmlReallocFunc reallocFunc;
213     xmlStrdupFunc strdupFunc;
214 
215     xmlMemGet(&freeFunc, &mallocFunc, &reallocFunc, &strdupFunc);
216     freeFunc = getFreeFunc(freeFunc);
217     xmlMemSetup(freeFunc, mallocFunc, reallocFunc, strdupFunc);
218 }
219 
getFreeFunc(xmlFreeFunc freeFunc)220 xmlFreeFunc VariableScope::getFreeFunc(xmlFreeFunc freeFunc)
221 {
222     if (!XMLFreeFunc)
223     {
224         XMLFreeFunc = freeFunc;
225     }
226 
227     return &_xmlFreeFunc;
228 }
229 
_xmlFreeFunc(void * mem)230 void VariableScope::_xmlFreeFunc(void *mem)
231 {
232     std::map < void *, XMLObject * >::const_iterator it = mapLibXMLToXMLObject.find(mem);
233 
234     if (it != mapLibXMLToXMLObject.end())
235     {
236         delete it->second;
237 
238         mapLibXMLToXMLObject.erase(mem);
239     }
240 
241     std::map < void *, XMLNodeList * >::const_iterator itnl = mapLibXMLToXMLNodeList.find(mem);
242 
243     if (itnl != mapLibXMLToXMLNodeList.end())
244     {
245         delete itnl->second;
246 
247         mapLibXMLToXMLNodeList.erase(mem);
248     }
249 
250     XMLFreeFunc(mem);
251 }
252 
removeChildFromParent(const XMLObject * child)253 inline void VariableScope::removeChildFromParent(const XMLObject * child)
254 {
255     const XMLObject *parent = child->getXMLObjectParent();
256     std::map < const XMLObject *, std::map < const XMLObject *, bool>*>::iterator i = parentToChildren.find(parent);
257 
258     if (i != parentToChildren.end())
259     {
260         std::map < const XMLObject *, bool>::iterator j = i->second->find(child);
261         if (j != i->second->end())
262         {
263             j->second = false;
264         }
265     }
266 }
267 }
268