9a9b9923522f06da44992c318ed2855b277e0948
[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         //remove / or \ at the end
47         size_t pos = wstPath.find_last_of(L"/\\");
48         wstPath = wstPath.substr(0, pos);
49         pos = wstOriginalPath.find_last_of(L"/\\");
50         wstOriginalPath = wstOriginalPath.substr(0, pos + 1); //with ending /
51     }
52     else
53     {
54         if (wstFile.empty() == false && *wstFile.rbegin() != DIR_SEPARATORW[0])
55         {
56             wstFile += DIR_SEPARATORW;
57         }
58
59         wstFile += L"lib";
60     }
61
62
63     std::wstring libname;
64     MacroInfoList lst;
65     *err = parseLibFile(wstFile, lst, libname);
66     if (*err)
67     {
68         return lib;
69     }
70
71     lib = new types::Library(wstOriginalPath);
72
73     std::wstring stFilename(wstPath);
74     if (stFilename.empty() == false && *stFilename.rbegin() != DIR_SEPARATORW[0])
75     {
76         stFilename += DIR_SEPARATORW;
77     }
78
79
80     for (const auto& macro : lst)
81     {
82         lib->add(macro.second.name, new types::MacroFile(macro.second.name, stFilename + macro.second.file, libname));
83     }
84
85
86     if (_bAddInContext)
87     {
88         symbol::Context* ctx = symbol::Context::getInstance();
89         symbol::Symbol sym = symbol::Symbol(libname);
90         if (ctx->isprotected(sym) == false)
91         {
92             ctx->put(sym, lib);
93         }
94         else
95         {
96             *err = 2;
97             delete lib;
98             lib = NULL;
99         }
100     }
101
102     return lib;
103 }
104
105 int parseLibFile(const std::wstring& _wstXML, MacroInfoList& info, std::wstring& libname)
106 {
107     info.clear();
108
109     char* pstFile = wide_string_to_UTF8(_wstXML.data());
110
111     if (FileExist(pstFile) == FALSE)
112     {
113         FREE(pstFile);
114         return 1;
115     }
116
117     char *encoding = GetXmlFileEncoding(pstFile);
118
119     /* Don't care about line return / empty line */
120     xmlKeepBlanksDefault(0);
121     /* check if the XML file has been encoded with utf8 (unicode) or not */
122     if (stricmp("utf-8", encoding))
123     {
124         FREE(pstFile);
125         free(encoding);
126         return NULL;
127     }
128
129     xmlDocPtr doc;
130     xmlXPathContextPtr xpathCtxt = NULL;
131     xmlXPathObjectPtr xpathObj = NULL;
132     wchar_t* pstName = NULL;
133     wchar_t* pstLibName = NULL;
134     wchar_t* pstFileName = NULL;
135     wchar_t* pstMd5 = NULL;
136
137     free(encoding);
138
139     doc = xmlParseFile(pstFile);
140
141     if (doc == NULL)
142     {
143         FREE(pstFile);
144         return 1;
145     }
146
147     FREE(pstFile);
148
149     xpathCtxt = xmlXPathNewContext(doc);
150     xpathObj = xmlXPathEval((const xmlChar*)"//scilablib", xpathCtxt);
151     if (xpathObj && xpathObj->nodesetval->nodeMax)
152     {
153         xmlAttrPtr attrib = xpathObj->nodesetval->nodeTab[0]->properties;
154         if (xmlStrEqual(attrib->name, (const xmlChar*)"name"))
155         {
156             /* we found the tag name */
157             const char *str = (const char*)attrib->children->content;
158             pstLibName = to_wide_string(str);
159             libname = pstLibName;
160             FREE(pstLibName);
161             xmlXPathFreeObject(xpathObj);
162         }
163         else
164         {
165             if (xpathCtxt)
166             {
167                 xmlXPathFreeContext(xpathCtxt);
168             }
169             xmlXPathFreeObject(xpathObj);
170             return 1;
171         }
172     }
173
174     xpathObj = xmlXPathEval((const xmlChar*)"//scilablib/macro", xpathCtxt);
175     if (xpathObj && xpathObj->nodesetval->nodeMax)
176     {
177         /* the Xpath has been understood and there are node */
178         for (int i = 0; i < xpathObj->nodesetval->nodeNr; i++)
179         {
180             xmlAttrPtr attrib = xpathObj->nodesetval->nodeTab[i]->properties;
181             /* Get the properties of <module>  */
182             while (attrib != NULL)
183             {
184                 /* loop until when have read all the attributes */
185                 if (xmlStrEqual(attrib->name, (const xmlChar*)"name"))
186                 {
187                     /* we found the tag name */
188                     const char *str = (const char*)attrib->children->content;
189                     pstName = to_wide_string(str);
190                 }
191                 else if (xmlStrEqual(attrib->name, (const xmlChar*)"file"))
192                 {
193                     /* we found the tag activate */
194                     const char *str = (const char*)attrib->children->content;
195                     pstFileName = to_wide_string(str);
196                 }
197                 else if (xmlStrEqual(attrib->name, (const xmlChar*)"md5"))
198                 {
199                     /* we found the tag activate */
200                     const char *str = (const char*)attrib->children->content;
201                     pstMd5 = to_wide_string(str);
202                 }
203                 attrib = attrib->next;
204             }
205
206             if (pstName && pstFileName && pstMd5)
207             {
208                 info[pstFileName] = MacroInfo(pstName, pstFileName, pstMd5);
209             }
210
211             if (pstName)
212             {
213                 FREE(pstName);
214                 pstName = NULL;
215             }
216
217             if (pstFileName)
218             {
219                 FREE(pstFileName);
220                 pstFileName = NULL;
221             }
222
223             if (pstMd5)
224             {
225                 FREE(pstMd5);
226                 pstMd5 = NULL;
227             }
228         }
229     }
230
231     if (xpathObj)
232     {
233         xmlXPathFreeObject(xpathObj);
234     }
235     if (xpathCtxt)
236     {
237         xmlXPathFreeContext(xpathCtxt);
238     }
239
240     xmlFreeDoc(doc);
241     return 0;
242 }
243
244 static char *GetXmlFileEncoding(std::string _filename)
245 {
246     char *encoding = NULL;
247     xmlDocPtr doc = NULL;
248
249     /* default */
250     encoding = os_strdup(DEFAULT_ENCODING);
251
252     doc = xmlParseFile(_filename.c_str());
253     if (doc)
254     {
255         if (doc->encoding)
256         {
257             if (encoding)
258             {
259                 free(encoding);
260                 encoding = NULL;
261             }
262             encoding = os_strdup((char*)doc->encoding);
263         }
264     }
265
266     xmlFreeDoc(doc);
267     return encoding;
268 }