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