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