text: /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
  *
   * Copyright (C) 2012 - 2016 - Scilab Enterprises
   *
   * This file is hereby licensed under the terms of the GNU GPL v2.0,
   * pursuant to article 5.3.4 of the CeCILL v.2.1.
   * This file was originally licensed under the terms of the CeCILL v2.1,
   * and continues to be available under such terms.
   * For more information, see the COPYING file which you should have received
   * along with this program.
  *
  */
  #include <fstream>
  #include "configvariable.hxx"
  #include "context.hxx"
  #include "loadlib.hxx"
  #include "macrofile.hxx"
  extern "C"
  {
  #include "FileExist.h"
  #include "sci_malloc.h"
  #include "os_string.h"
  #include "expandPathVariable.h"
  #include "fullpath.h"
  #include "PATH_MAX.h"
  #include "pathconvert.h"
  #include <libxml/xpath.h>
  #include <libxml/xmlreader.h>
  }
  
  #define DEFAULT_ENCODING "UTF-8"
  
  static char *GetXmlFileEncoding(std::string _filename);
  
  types::Library* loadlib(const std::wstring& _wstXML, int* err, bool _isFile, bool _bAddInContext)
  {
      types::Library* lib = NULL;
  
      wchar_t* pwstXML = pathconvertW(_wstXML.data(), (BOOL)FALSE, (BOOL)FALSE, AUTO_STYLE);
      wchar_t* pwstPathLib = expandPathVariableW(pwstXML);
  
      bool expanded = true;
      if (wcscmp(pwstPathLib, pwstXML) == 0)
      {
          expanded = false;
      }
  
      wchar_t* pwstTemp = get_full_pathW(pwstPathLib);
      FREE(pwstPathLib);
  
  
      std::wstring wstOriginalPath(pwstXML);
      FREE(pwstXML);
      std::wstring wstFile(pwstTemp);
      std::wstring wstPath(pwstTemp);
      FREE(pwstTemp);
  
      if (_isFile)
      {
          //remove / or \ at the end
          size_t pos = wstPath.find_last_of(L"/\\");
          wstPath = wstPath.substr(0, pos + 1);
          pos = wstOriginalPath.find_last_of(L"/\\");
          wstOriginalPath = wstOriginalPath.substr(0, pos + 1); //with ending /
      }
      else
      {
          if (wstFile.empty() == false && *wstFile.rbegin() != DIR_SEPARATORW[0])
          {
              wstFile += DIR_SEPARATORW;
          }
  
          wstFile += L"lib";
      }
  
      std::wstring libname;
      MacroInfoList lst;
      *err = parseLibFile(wstFile, lst, libname);
      if (*err)
      {
          return lib;
      }
  
      lib = new types::Library(expanded ? wstOriginalPath : wstPath);
  
      std::wstring stFilename(wstPath);
      if (stFilename.empty() == false && *stFilename.rbegin() != DIR_SEPARATORW[0])
      {
          stFilename += DIR_SEPARATORW;
      }
  
  
      for (const auto & macro : lst)
      {
          lib->add(macro.second.name, new types::MacroFile(macro.second.name, stFilename + macro.second.file, libname));
      }
  
  
      if (_bAddInContext)
      {
          symbol::Context* ctx = symbol::Context::getInstance();
          symbol::Symbol sym = symbol::Symbol(libname);
          if (ctx->isprotected(sym) == false)
          {
              ctx->put(sym, lib);
          }
          else
          {
              *err = 2;
              delete lib;
              lib = NULL;
          }
      }
  
      return lib;
  }
  
  int parseLibFile(const std::wstring& _wstXML, MacroInfoList& info, std::wstring& libname)
  {
      info.clear();
  
      char* pstFile = wide_string_to_UTF8(_wstXML.data());
  
      if (FileExist(pstFile) == FALSE)
      {
          FREE(pstFile);
          return 1;
      }
  
      std::string s(_wstXML.begin(), _wstXML.end());
      std::ifstream file(s);
      if (file)
      {
          const std::string XMLDecl("<?xml");
          std::string readXMLDecl;
          readXMLDecl.resize(XMLDecl.length(), ' ');//reserve space
          file.read(&*readXMLDecl.begin(), XMLDecl.length());
          if (XMLDecl != readXMLDecl)
          {
              FREE(pstFile);
              return 4;
          }
      }
  
      char *encoding = GetXmlFileEncoding(pstFile);
  
      /* Don't care about line return / empty line */
      xmlKeepBlanksDefault(0);
      /* check if the XML file has been encoded with utf8 (unicode) or not */
      if (stricmp("utf-8", encoding))
      {
          FREE(pstFile);
          free(encoding);
          return 3;
      }
  
      xmlDocPtr doc;
      xmlXPathContextPtr xpathCtxt = NULL;
      xmlXPathObjectPtr xpathObj = NULL;
      wchar_t* pstName = NULL;
      wchar_t* pstLibName = NULL;
      wchar_t* pstFileName = NULL;
      wchar_t* pstMd5 = NULL;
  
      free(encoding);
  
      doc = xmlParseFile(pstFile);
  
      if (doc == NULL)
      {
          FREE(pstFile);
          return 3;
      }
  
      FREE(pstFile);
  
      xpathCtxt = xmlXPathNewContext(doc);
      xpathObj = xmlXPathEval((const xmlChar*)"//scilablib", xpathCtxt);
      if (xpathObj && xpathObj->nodesetval->nodeMax)
      {
          xmlAttrPtr attrib = xpathObj->nodesetval->nodeTab[0]->properties;
          if (xmlStrEqual(attrib->name, (const xmlChar*)"name"))
          {
              /* we found the tag name */
              const char *str = (const char*)attrib->children->content;
              pstLibName = to_wide_string(str);
              libname = pstLibName;
              FREE(pstLibName);
              xmlXPathFreeObject(xpathObj);
          }
          else
          {
              if (xpathCtxt)
              {
                  xmlXPathFreeContext(xpathCtxt);
              }
              xmlXPathFreeObject(xpathObj);
              return 1;
          }
      }
  
      xpathObj = xmlXPathEval((const xmlChar*)"//scilablib/macro", xpathCtxt);
      if (xpathObj && xpathObj->nodesetval->nodeMax)
      {
          /* the Xpath has been understood and there are node */
          for (int i = 0; i < xpathObj->nodesetval->nodeNr; i++)
          {
              xmlAttrPtr attrib = xpathObj->nodesetval->nodeTab[i]->properties;
              /* Get the properties of <module>  */
              while (attrib != NULL)
              {
                  /* loop until when have read all the attributes */
                  if (xmlStrEqual(attrib->name, (const xmlChar*)"name"))
                  {
                      /* we found the tag name */
                      const char *str = (const char*)attrib->children->content;
                      if (pstName)
                      {
                          FREE(pstName);
                      }
                      pstName = to_wide_string(str);
                  }
                  else if (xmlStrEqual(attrib->name, (const xmlChar*)"file"))
                  {
                      /* we found the tag activate */
                      const char *str = (const char*)attrib->children->content;
                      if (pstFileName)
                      {
                          FREE(pstFileName);
                      }
                      pstFileName = to_wide_string(str);
                  }
                  else if (xmlStrEqual(attrib->name, (const xmlChar*)"md5"))
                  {
                      /* we found the tag activate */
                      const char *str = (const char*)attrib->children->content;
                      if (pstMd5)
                      {
                          FREE(pstMd5);
                      }
                      pstMd5 = to_wide_string(str);
                  }
                  attrib = attrib->next;
              }
  
              if (pstName && pstFileName && pstMd5)
              {
                  info[pstFileName] = MacroInfo(pstName, pstFileName, pstMd5);
              }
  
              if (pstName)
              {
                  FREE(pstName);
                  pstName = NULL;
              }
  
              if (pstFileName)
              {
                  FREE(pstFileName);
                  pstFileName = NULL;
              }
  
              if (pstMd5)
              {
                  FREE(pstMd5);
                  pstMd5 = NULL;
              }
          }
      }
  
      if (xpathObj)
      {
          xmlXPathFreeObject(xpathObj);
      }
      if (xpathCtxt)
      {
          xmlXPathFreeContext(xpathCtxt);
      }
  
      xmlFreeDoc(doc);
      return 0;
  }
  
  static char *GetXmlFileEncoding(std::string _filename)
  {
      char *encoding = NULL;
      xmlDocPtr doc = NULL;
  
      /* default */
      encoding = os_strdup(DEFAULT_ENCODING);
  
      doc = xmlParseFile(_filename.c_str());
      if (doc)
      {
          if (doc->encoding)
          {
              if (encoding)
              {
                  free(encoding);
                  encoding = NULL;
              }
              encoding = os_strdup((char*)doc->encoding);
          }
      }
  
      xmlFreeDoc(doc);
      return encoding;
  }
  