bug 13981: fix string corruption in error cases
[scilab.git] / scilab / modules / io / src / cpp / loadlib.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
4 *
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution.  The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13 #include "configvariable.hxx"
14 #include "context.hxx"
15 #include "loadlib.hxx"
16 #include "macrofile.hxx"
17
18 extern "C"
19 {
20 #include "FileExist.h"
21 #include "sci_malloc.h"
22 #include "os_string.h"
23 #include "expandPathVariable.h"
24 #include "PATH_MAX.h"
25 #include <libxml/xpath.h>
26 #include <libxml/xmlreader.h>
27 }
28
29 #define DEFAULT_ENCODING "UTF-8"
30
31 static char *GetXmlFileEncoding(std::string _filename);
32
33 types::Library* loadlib(const std::wstring& _wstXML, int* err, bool _isFile, bool _bAddInContext)
34 {
35     types::Library* lib = NULL;
36
37     wchar_t* pwstPathLib = expandPathVariableW((wchar_t*)_wstXML.c_str());
38
39     std::wstring wstOriginalPath(_wstXML);
40     std::wstring wstFile(pwstPathLib);
41     std::wstring wstPath(pwstPathLib);
42     FREE(pwstPathLib);
43
44     if (_isFile)
45     {
46         size_t pos = wstPath.find_last_of(L"/\\");
47         wstPath = wstPath.substr(0, pos);
48         pos = wstOriginalPath.find_last_of(L"/\\");
49         wstOriginalPath = wstOriginalPath.substr(0, pos + 1); //with ending /
50     }
51     else
52     {
53         if (wstFile.empty() == false && *wstFile.rbegin() != DIR_SEPARATORW[0])
54         {
55             wstFile += DIR_SEPARATORW;
56         }
57
58         wstFile += L"lib";
59     }
60
61     char* pstFile = wide_string_to_UTF8(wstFile.c_str());
62
63     if (FileExist(pstFile) == FALSE)
64     {
65         *err = 1;
66         FREE(pstFile);
67         return NULL;
68     }
69
70     char *encoding = GetXmlFileEncoding(pstFile);
71
72     /* Don't care about line return / empty line */
73     xmlKeepBlanksDefault(0);
74     /* check if the XML file has been encoded with utf8 (unicode) or not */
75     if (stricmp("utf-8", encoding))
76     {
77         *err = 1;
78         FREE(pstFile);
79         free(encoding);
80         return NULL;
81     }
82
83     xmlDocPtr doc;
84     xmlXPathContextPtr xpathCtxt    = NULL;
85     xmlXPathObjectPtr xpathObj      = NULL;
86     wchar_t* pstName                = NULL;
87     wchar_t* pstLibName             = NULL;
88     wchar_t* pstFileName            = NULL;
89
90     free(encoding);
91
92     doc = xmlParseFile(pstFile);
93
94     if (doc == NULL)
95     {
96         *err = 1;
97         //std::cout << "Error: Could not parse file " << pstFile << std::endl;
98         FREE(pstFile);
99         return NULL;
100     }
101
102     FREE(pstFile);
103
104     lib = new types::Library(wstOriginalPath);
105
106     xpathCtxt = xmlXPathNewContext(doc);
107     xpathObj = xmlXPathEval((const xmlChar*)"//scilablib", xpathCtxt);
108     if (xpathObj && xpathObj->nodesetval->nodeMax)
109     {
110         xmlAttrPtr attrib = xpathObj->nodesetval->nodeTab[0]->properties;
111         if (xmlStrEqual (attrib->name, (const xmlChar*)"name"))
112         {
113             /* we found the tag name */
114             const char *str = (const char*)attrib->children->content;
115             pstLibName = to_wide_string(str);
116             xmlXPathFreeObject(xpathObj);
117         }
118         else
119         {
120             if (xpathCtxt)
121             {
122                 xmlXPathFreeContext(xpathCtxt);
123             }
124             xmlXPathFreeObject(xpathObj);
125             delete lib;
126             return NULL;
127         }
128     }
129
130     xpathObj = xmlXPathEval((const xmlChar*)"//scilablib/macro", xpathCtxt);
131     if (xpathObj && xpathObj->nodesetval->nodeMax)
132     {
133         /* the Xpath has been understood and there are node */
134         for (int i = 0 ; i < xpathObj->nodesetval->nodeNr ; i++)
135         {
136             xmlAttrPtr attrib = xpathObj->nodesetval->nodeTab[i]->properties;
137             /* Get the properties of <module>  */
138             while (attrib != NULL)
139             {
140                 /* loop until when have read all the attributes */
141                 if (xmlStrEqual (attrib->name, (const xmlChar*)"name"))
142                 {
143                     /* we found the tag name */
144                     const char *str = (const char*)attrib->children->content;
145                     pstName = to_wide_string(str);
146                 }
147                 else if (xmlStrEqual(attrib->name, (const xmlChar*)"file"))
148                 {
149                     /* we found the tag activate */
150                     const char *str = (const char*)attrib->children->content;
151                     pstFileName = to_wide_string(str);
152                 }
153                 attrib = attrib->next;
154             }
155
156             if (pstName && pstFileName)
157             {
158                 std::wstring stFilename(wstPath);
159                 if (stFilename.empty() == false && *stFilename.rbegin() != DIR_SEPARATORW[0])
160                 {
161                     stFilename += DIR_SEPARATORW;
162                 }
163
164                 stFilename += pstFileName;
165                 lib->add(pstName, new types::MacroFile(pstName, stFilename, pstLibName));
166             }
167
168             if (pstName)
169             {
170                 FREE(pstName);
171                 pstName = NULL;
172             }
173
174             if (pstFileName)
175             {
176                 FREE(pstFileName);
177                 pstFileName = NULL;
178             }
179         }
180     }
181
182     if (xpathObj)
183     {
184         xmlXPathFreeObject(xpathObj);
185     }
186     if (xpathCtxt)
187     {
188         xmlXPathFreeContext(xpathCtxt);
189     }
190
191     if (_bAddInContext)
192     {
193         symbol::Context* ctx = symbol::Context::getInstance();
194         symbol::Symbol sym = symbol::Symbol(pstLibName);
195         if (ctx->isprotected(sym) == false)
196         {
197             ctx->put(symbol::Symbol(pstLibName), lib);
198         }
199         else
200         {
201             *err = 2;
202             delete lib;
203             lib = NULL;
204         }
205     }
206
207     xmlFreeDoc(doc);
208     FREE(pstLibName);
209     return lib;
210 }
211
212 static char *GetXmlFileEncoding(std::string _filename)
213 {
214     char *encoding = NULL;
215     xmlDocPtr doc = NULL;
216
217     /* default */
218     encoding = os_strdup(DEFAULT_ENCODING);
219
220     doc = xmlParseFile(_filename.c_str());
221     if (doc)
222     {
223         if (doc->encoding)
224         {
225             if (encoding)
226             {
227                 free(encoding);
228                 encoding = NULL;
229             }
230             encoding = os_strdup((char*)doc->encoding);
231         }
232     }
233
234     xmlFreeDoc(doc);
235     return encoding;
236 }