1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <cassert>
24 #include <memory>
25 
26 #include <elements.hxx>
27 #include <osl/mutex.hxx>
28 #include <osl/file.hxx>
29 #include <fwkutil.hxx>
30 #include <fwkbase.hxx>
31 #include "framework.hxx"
32 #include <libxmlutil.hxx>
33 #include <algorithm>
34 #include <libxml/parser.h>
35 #include <libxml/xpath.h>
36 #include <libxml/xpathInternals.h>
37 #include <boost/optional.hpp>
38 #include <string.h>
39 
40 // For backwards compatibility, the nFeatures and nRequirements flag words are
41 // read/written as potentially signed hexadecimal numbers (though that has no
42 // practical relevance given that each has only one flag with value 0x01
43 // defined).
44 
45 using namespace osl;
46 namespace jfw
47 {
48 
getElement(OString const & docPath,xmlChar const * pathExpression)49 static OString getElement(OString const & docPath,
50                         xmlChar const * pathExpression)
51 {
52     //Prepare the xml document and context
53     OSL_ASSERT(!docPath.isEmpty());
54     jfw::CXmlDocPtr doc(xmlParseFile(docPath.getStr()));
55     if (doc == nullptr)
56         throw FrameworkException(
57             JFW_E_ERROR,
58             "[Java framework] Error in function getElement (elements.cxx)");
59 
60     jfw::CXPathContextPtr context(xmlXPathNewContext(doc));
61     if (xmlXPathRegisterNs(context, reinterpret_cast<xmlChar const *>("jf"),
62         reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)) == -1)
63         throw FrameworkException(
64             JFW_E_ERROR,
65             "[Java framework] Error in function getElement (elements.cxx)");
66 
67     CXPathObjectPtr pathObj = xmlXPathEvalExpression(pathExpression, context);
68     OString sValue;
69     if (xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
70     {
71         throw FrameworkException(
72             JFW_E_ERROR,
73             "[Java framework] Error in function getElement (elements.cxx)");
74     }
75     sValue = reinterpret_cast<sal_Char*>(pathObj->nodesetval->nodeTab[0]->content);
76     return sValue;
77 }
78 
getElementUpdated()79 OString getElementUpdated()
80 {
81     return getElement(jfw::getVendorSettingsPath(),
82                       reinterpret_cast<xmlChar const *>("/jf:javaSelection/jf:updated/text()"));
83 }
84 
createSettingsStructure(xmlDoc * document,bool * bNeedsSave)85 void createSettingsStructure(xmlDoc * document, bool * bNeedsSave)
86 {
87     OString sExcMsg("[Java framework] Error in function createSettingsStructure "
88                          "(elements.cxx).");
89     xmlNode * root = xmlDocGetRootElement(document);
90     if (root == nullptr)
91         throw FrameworkException(JFW_E_ERROR, sExcMsg);
92     bool bFound = false;
93     xmlNode * cur = root->children;
94     while (cur != nullptr)
95     {
96         if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("enabled")) == 0)
97         {
98             bFound = true;
99             break;
100         }
101         cur = cur->next;
102     }
103     if (bFound)
104     {
105         *bNeedsSave = false;
106         return;
107     }
108     //We will modify this document
109     *bNeedsSave = true;
110     // Now we create the child elements ------------------
111     //Get xsi:nil namespace
112     xmlNs* nsXsi = xmlSearchNsByHref(
113         document, root, reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
114 
115     //<enabled xsi:nil="true"
116     xmlNode  * nodeEn = xmlNewTextChild(
117         root, nullptr, reinterpret_cast<xmlChar const *>("enabled"), reinterpret_cast<xmlChar const *>(""));
118     if (nodeEn == nullptr)
119         throw FrameworkException(JFW_E_ERROR, sExcMsg);
120     xmlSetNsProp(nodeEn, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
121     //add a new line
122     xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
123     xmlAddChild(root, nodeCrLf);
124 
125     //<userClassPath xsi:nil="true">
126     xmlNode  * nodeUs = xmlNewTextChild(
127         root, nullptr, reinterpret_cast<xmlChar const *>("userClassPath"), reinterpret_cast<xmlChar const *>(""));
128     if (nodeUs == nullptr)
129         throw FrameworkException(JFW_E_ERROR, sExcMsg);
130     xmlSetNsProp(nodeUs, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
131     //add a new line
132     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
133     xmlAddChild(root, nodeCrLf);
134 
135     //<vmParameters xsi:nil="true">
136     xmlNode  * nodeVm = xmlNewTextChild(
137         root, nullptr, reinterpret_cast<xmlChar const *>("vmParameters"), reinterpret_cast<xmlChar const *>(""));
138     if (nodeVm == nullptr)
139         throw FrameworkException(JFW_E_ERROR, sExcMsg);
140     xmlSetNsProp(nodeVm, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
141     //add a new line
142     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
143     xmlAddChild(root, nodeCrLf);
144 
145     //<jreLocations xsi:nil="true">
146     xmlNode  * nodeJre = xmlNewTextChild(
147         root, nullptr, reinterpret_cast<xmlChar const *>("jreLocations"), reinterpret_cast<xmlChar const *>(""));
148     if (nodeJre == nullptr)
149         throw FrameworkException(JFW_E_ERROR, sExcMsg);
150     xmlSetNsProp(nodeJre, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
151     //add a new line
152     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
153     xmlAddChild(root, nodeCrLf);
154 
155     //<javaInfo xsi:nil="true">
156     xmlNode  * nodeJava = xmlNewTextChild(
157         root, nullptr, reinterpret_cast<xmlChar const *>("javaInfo"), reinterpret_cast<xmlChar const *>(""));
158     if (nodeJava == nullptr)
159         throw FrameworkException(JFW_E_ERROR, sExcMsg);
160     xmlSetNsProp(nodeJava, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
161     //add a new line
162     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
163     xmlAddChild(root, nodeCrLf);
164 }
165 
NodeJava(Layer layer)166 NodeJava::NodeJava(Layer layer):
167     m_layer(layer)
168 {
169     //This class reads and write to files which should only be done in
170     //application mode
171     if (getMode() == JFW_MODE_DIRECT)
172         throw FrameworkException(
173             JFW_E_DIRECT_MODE,
174             "[Java framework] Trying to access settings files in direct mode.");
175 }
176 
177 
load()178 void NodeJava::load()
179 {
180     const OString sExcMsg("[Java framework] Error in function NodeJava::load"
181                              "(elements.cxx).");
182     if (SHARED == m_layer)
183     {
184         //we do not support yet to write into the shared installation
185 
186         //check if shared settings exist at all.
187         OUString sURL(BootParams::getSharedData());
188         jfw::FileStatus s = sURL.isEmpty()
189             ? FILE_DOES_NOT_EXIST : checkFileURL(sURL);
190         if (s == FILE_INVALID)
191             throw FrameworkException(
192                 JFW_E_ERROR,
193                 "[Java framework] Invalid file for shared Java settings.");
194         else if (s == FILE_DOES_NOT_EXIST)
195             //Writing shared data is not supported yet.
196             return;
197     }
198     else if (USER == m_layer)
199     {
200         if (!prepareSettingsDocument())
201         {
202             SAL_INFO("jfw.level1", "no path to load user settings document from");
203             return;
204         }
205     }
206     else
207     {
208         OSL_FAIL("[Java framework] Unknown enum used.");
209     }
210 
211 
212     //Read the user elements
213     OString sSettingsPath = getSettingsPath();
214     //There must not be a share settings file
215     CXmlDocPtr docUser(xmlParseFile(sSettingsPath.getStr()));
216     if (docUser == nullptr)
217         throw FrameworkException(JFW_E_ERROR, sExcMsg);
218 
219     xmlNode * cur = xmlDocGetRootElement(docUser);
220     if (cur == nullptr || cur->children == nullptr)
221         throw FrameworkException(JFW_E_ERROR, sExcMsg);
222 
223     CXmlCharPtr sNil;
224     cur = cur->children;
225     while (cur != nullptr)
226     {
227         if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("enabled")) == 0)
228         {
229             //only overwrite share settings if xsi:nil="false"
230             sNil = xmlGetNsProp(
231                 cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
232             if (sNil == nullptr)
233                 throw FrameworkException(JFW_E_ERROR, sExcMsg);
234             if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
235             {
236                 CXmlCharPtr sEnabled( xmlNodeListGetString(
237                     docUser, cur->children, 1));
238                 if (xmlStrcmp(sEnabled, reinterpret_cast<xmlChar const *>("true")) == 0)
239                     m_enabled = boost::optional<sal_Bool>(true);
240                 else if (xmlStrcmp(sEnabled, reinterpret_cast<xmlChar const *>("false")) == 0)
241                     m_enabled = boost::optional<sal_Bool>(false);
242             }
243         }
244         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("userClassPath")) == 0)
245         {
246             sNil = xmlGetNsProp(
247                 cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
248             if (sNil == nullptr)
249                 throw FrameworkException(JFW_E_ERROR, sExcMsg);
250             if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
251             {
252                 CXmlCharPtr sUser(xmlNodeListGetString(
253                     docUser, cur->children, 1));
254                 m_userClassPath = boost::optional<OUString>(OUString(sUser));
255             }
256         }
257         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("javaInfo")) == 0)
258         {
259             sNil = xmlGetNsProp(
260                 cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
261             if (sNil == nullptr)
262                 throw FrameworkException(JFW_E_ERROR, sExcMsg);
263 
264             if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
265             {
266                 if (! m_javaInfo)
267                     m_javaInfo = boost::optional<CNodeJavaInfo>(CNodeJavaInfo());
268                 m_javaInfo->loadFromNode(docUser, cur);
269             }
270         }
271         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vmParameters")) == 0)
272         {
273             sNil = xmlGetNsProp(
274                 cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
275             if (sNil == nullptr)
276                 throw FrameworkException(JFW_E_ERROR, sExcMsg);
277             if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
278             {
279                 if ( ! m_vmParameters)
280                     m_vmParameters = boost::optional<std::vector<OUString> >(
281                         std::vector<OUString> ());
282 
283                 xmlNode * pOpt = cur->children;
284                 while (pOpt != nullptr)
285                 {
286                     if (xmlStrcmp(pOpt->name, reinterpret_cast<xmlChar const *>("param")) == 0)
287                     {
288                         CXmlCharPtr sOpt = xmlNodeListGetString(
289                             docUser, pOpt->children, 1);
290                         m_vmParameters->push_back(sOpt);
291                     }
292                     pOpt = pOpt->next;
293                 }
294             }
295         }
296         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("jreLocations")) == 0)
297         {
298             sNil = xmlGetNsProp(
299                 cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
300             if (sNil == nullptr)
301                 throw FrameworkException(JFW_E_ERROR, sExcMsg);
302             if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
303             {
304                 if (! m_JRELocations)
305                     m_JRELocations = boost::optional<std::vector<OUString> >(
306                         std::vector<OUString>());
307 
308                 xmlNode * pLoc = cur->children;
309                 while (pLoc != nullptr)
310                 {
311                     if (xmlStrcmp(pLoc->name, reinterpret_cast<xmlChar const *>("location")) == 0)
312                     {
313                         CXmlCharPtr sLoc = xmlNodeListGetString(
314                             docUser, pLoc->children, 1);
315                         m_JRELocations->push_back(sLoc);
316                     }
317                     pLoc = pLoc->next;
318                 }
319             }
320         }
321         cur = cur->next;
322     }
323 }
324 
getSettingsPath() const325 OString NodeJava::getSettingsPath() const
326 {
327     OString ret;
328     switch (m_layer)
329     {
330     case USER: ret = getUserSettingsPath(); break;
331     case SHARED: ret = getSharedSettingsPath(); break;
332     default:
333         OSL_FAIL("[Java framework] NodeJava::getSettingsPath()");
334     }
335     return ret;
336 }
337 
getSettingsURL() const338 OUString NodeJava::getSettingsURL() const
339 {
340     OUString ret;
341     switch (m_layer)
342     {
343     case USER: ret = BootParams::getUserData(); break;
344     case SHARED: ret = BootParams::getSharedData(); break;
345     default:
346         OSL_FAIL("[Java framework] NodeJava::getSettingsURL()");
347     }
348     return ret;
349 }
350 
prepareSettingsDocument() const351 bool NodeJava::prepareSettingsDocument() const
352 {
353     OString sExcMsg(
354         "[Java framework] Error in function prepareSettingsDocument"
355         " (elements.cxx).");
356     if (!createSettingsDocument())
357     {
358         return false;
359     }
360     OString sSettings = getSettingsPath();
361     CXmlDocPtr doc(xmlParseFile(sSettings.getStr()));
362     if (!doc)
363         throw FrameworkException(JFW_E_ERROR, sExcMsg);
364 
365     bool bNeedsSave = false;
366     createSettingsStructure(doc, & bNeedsSave);
367     if (bNeedsSave)
368     {
369         if (xmlSaveFormatFileEnc(
370                 sSettings.getStr(), doc,"UTF-8", 1) == -1)
371             throw FrameworkException(JFW_E_ERROR, sExcMsg);
372     }
373     return true;
374 }
375 
write() const376 void NodeJava::write() const
377 {
378     OString sExcMsg("[Java framework] Error in function NodeJava::writeSettings "
379                          "(elements.cxx).");
380     CXmlDocPtr docUser;
381     CXPathContextPtr contextUser;
382     CXPathObjectPtr pathObj;
383 
384     if (!prepareSettingsDocument())
385     {
386         SAL_INFO("jfw.level1", "no path to write settings document to");
387         return;
388     }
389 
390     //Read the user elements
391     OString sSettingsPath = getSettingsPath();
392     docUser = xmlParseFile(sSettingsPath.getStr());
393     if (docUser == nullptr)
394         throw FrameworkException(JFW_E_ERROR, sExcMsg);
395     contextUser = xmlXPathNewContext(docUser);
396     if (xmlXPathRegisterNs(contextUser, reinterpret_cast<xmlChar const *>("jf"),
397         reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)) == -1)
398         throw FrameworkException(JFW_E_ERROR, sExcMsg);
399 
400     xmlNode * root = xmlDocGetRootElement(docUser);
401     //Get xsi:nil namespace
402     xmlNs* nsXsi = xmlSearchNsByHref(docUser,
403                              root,
404                              reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
405 
406     //set the <enabled> element
407     //The element must exist
408     if (m_enabled)
409     {
410         pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:enabled"),
411                                          contextUser);
412         if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
413             throw FrameworkException(JFW_E_ERROR, sExcMsg);
414 
415         xmlNode * nodeEnabled = pathObj->nodesetval->nodeTab[0];
416         xmlSetNsProp(nodeEnabled,
417                      nsXsi,
418                      reinterpret_cast<xmlChar const *>("nil"),
419                      reinterpret_cast<xmlChar const *>("false"));
420 
421         if (m_enabled == boost::optional<sal_Bool>(true))
422             xmlNodeSetContent(nodeEnabled,reinterpret_cast<xmlChar const *>("true"));
423         else
424             xmlNodeSetContent(nodeEnabled,reinterpret_cast<xmlChar const *>("false"));
425     }
426 
427     //set the <userClassPath> element
428     //The element must exist
429     if (m_userClassPath)
430     {
431         pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:userClassPath"),
432                                          contextUser);
433         if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
434             throw FrameworkException(JFW_E_ERROR, sExcMsg);
435 
436         xmlNode * nodeEnabled = pathObj->nodesetval->nodeTab[0];
437         xmlSetNsProp(nodeEnabled, nsXsi, reinterpret_cast<xmlChar const *>("nil"),reinterpret_cast<xmlChar const *>("false"));
438         xmlNodeSetContent(nodeEnabled,static_cast<xmlChar*>(CXmlCharPtr(*m_userClassPath)));
439     }
440 
441     //set <javaInfo> element
442     if (m_javaInfo)
443     {
444         pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:javaInfo"),
445                                                 contextUser);
446         if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
447             throw FrameworkException(JFW_E_ERROR, sExcMsg);
448         m_javaInfo->writeToNode(
449             docUser, pathObj->nodesetval->nodeTab[0]);
450     }
451 
452     //set <vmParameters> element
453     if (m_vmParameters)
454     {
455         pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:vmParameters"),
456                                          contextUser);
457         if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
458             throw FrameworkException(JFW_E_ERROR, sExcMsg);
459         xmlNode* vmParameters = pathObj->nodesetval->nodeTab[0];
460         //set xsi:nil = false;
461         xmlSetNsProp(vmParameters, nsXsi,reinterpret_cast<xmlChar const *>("nil"),
462                      reinterpret_cast<xmlChar const *>("false"));
463 
464         //remove option elements
465         xmlNode* cur = vmParameters->children;
466         while (cur != nullptr)
467         {
468             xmlNode* lastNode = cur;
469             cur = cur->next;
470             xmlUnlinkNode(lastNode);
471             xmlFreeNode(lastNode);
472         }
473         //add a new line after <vmParameters>
474         if (!m_vmParameters->empty())
475         {
476             xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
477             xmlAddChild(vmParameters, nodeCrLf);
478         }
479 
480         for (auto const & vmParameter : *m_vmParameters)
481         {
482             xmlNewTextChild(vmParameters, nullptr, reinterpret_cast<xmlChar const *>("param"),
483                             CXmlCharPtr(vmParameter));
484             //add a new line
485             xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
486             xmlAddChild(vmParameters, nodeCrLf);
487         }
488     }
489 
490     //set <jreLocations> element
491     if (m_JRELocations)
492     {
493         pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:jreLocations"),
494                                          contextUser);
495         if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
496             throw FrameworkException(JFW_E_ERROR, sExcMsg);
497         xmlNode* jreLocationsNode = pathObj->nodesetval->nodeTab[0];
498         //set xsi:nil = false;
499         xmlSetNsProp(jreLocationsNode, nsXsi,reinterpret_cast<xmlChar const *>("nil"),
500                      reinterpret_cast<xmlChar const *>("false"));
501 
502         //remove option elements
503         xmlNode* cur = jreLocationsNode->children;
504         while (cur != nullptr)
505         {
506             xmlNode* lastNode = cur;
507             cur = cur->next;
508             xmlUnlinkNode(lastNode);
509             xmlFreeNode(lastNode);
510         }
511         //add a new line after <vmParameters>
512         if (!m_JRELocations->empty())
513         {
514             xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
515             xmlAddChild(jreLocationsNode, nodeCrLf);
516         }
517 
518         for (auto const & JRELocation : *m_JRELocations)
519         {
520             xmlNewTextChild(jreLocationsNode, nullptr, reinterpret_cast<xmlChar const *>("location"),
521                             CXmlCharPtr(JRELocation));
522             //add a new line
523             xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
524             xmlAddChild(jreLocationsNode, nodeCrLf);
525         }
526     }
527 
528     if (xmlSaveFormatFile(sSettingsPath.getStr(), docUser, 1) == -1)
529         throw FrameworkException(JFW_E_ERROR, sExcMsg);
530 }
531 
setEnabled(bool bEnabled)532 void NodeJava::setEnabled(bool bEnabled)
533 {
534     m_enabled =  boost::optional<sal_Bool>(bEnabled);
535 }
536 
537 
setUserClassPath(const OUString & sClassPath)538 void NodeJava::setUserClassPath(const OUString & sClassPath)
539 {
540     m_userClassPath = boost::optional<OUString>(sClassPath);
541 }
542 
setJavaInfo(const JavaInfo * pInfo,bool bAutoSelect)543 void NodeJava::setJavaInfo(const JavaInfo * pInfo, bool bAutoSelect)
544 {
545     if (!m_javaInfo)
546         m_javaInfo = boost::optional<CNodeJavaInfo>(CNodeJavaInfo());
547     m_javaInfo->bAutoSelect = bAutoSelect;
548     m_javaInfo->bNil = false;
549 
550     if (pInfo != nullptr)
551     {
552         m_javaInfo->m_bEmptyNode = false;
553         m_javaInfo->sVendor = pInfo->sVendor;
554         m_javaInfo->sLocation = pInfo->sLocation;
555         m_javaInfo->sVersion = pInfo->sVersion;
556         m_javaInfo->nFeatures = pInfo->nFeatures;
557         m_javaInfo->nRequirements = pInfo->nRequirements;
558         m_javaInfo->arVendorData = pInfo->arVendorData;
559     }
560     else
561     {
562         m_javaInfo->m_bEmptyNode = true;
563         m_javaInfo->sVendor.clear();
564         m_javaInfo->sLocation.clear();
565         m_javaInfo->sVersion.clear();
566         m_javaInfo->nFeatures = 0;
567         m_javaInfo->nRequirements = 0;
568         m_javaInfo->arVendorData = rtl::ByteSequence();
569     }
570 }
571 
setVmParameters(std::vector<OUString> const & arOptions)572 void NodeJava::setVmParameters(std::vector<OUString> const & arOptions)
573 {
574     m_vmParameters = boost::optional<std::vector<OUString> >(arOptions);
575 }
576 
addJRELocation(OUString const & sLocation)577 void NodeJava::addJRELocation(OUString const & sLocation)
578 {
579     if (!m_JRELocations)
580         m_JRELocations = boost::optional<std::vector<OUString> >(
581             std::vector<OUString> ());
582      //only add the path if not already present
583     std::vector<OUString>::const_iterator it =
584         std::find(m_JRELocations->begin(), m_JRELocations->end(), sLocation);
585     if (it == m_JRELocations->end())
586         m_JRELocations->push_back(sLocation);
587 }
588 
checkSettingsFileStatus(OUString const & sURL)589 jfw::FileStatus NodeJava::checkSettingsFileStatus(OUString const & sURL)
590 {
591     jfw::FileStatus ret = FILE_DOES_NOT_EXIST;
592 
593     //check the file time
594     ::osl::DirectoryItem item;
595     File::RC rc = ::osl::DirectoryItem::get(sURL, item);
596     if (File::E_None == rc)
597     {
598         ::osl::FileStatus stat(osl_FileStatus_Mask_Validate);
599         File::RC rc_stat = item.getFileStatus(stat);
600         if (File::E_None == rc_stat)
601         {
602             ret = FILE_OK;
603         }
604         else if (File::E_NOENT == rc_stat)
605         {
606             ret = FILE_DOES_NOT_EXIST;
607         }
608         else
609         {
610             ret = FILE_INVALID;
611         }
612     }
613     else if(File::E_NOENT == rc)
614     {
615         ret = FILE_DOES_NOT_EXIST;
616     }
617     else
618     {
619         ret = FILE_INVALID;
620     }
621     return ret;
622 }
623 
createSettingsDocument() const624 bool NodeJava::createSettingsDocument() const
625 {
626     const OUString sURL = getSettingsURL();
627     if (sURL.isEmpty())
628     {
629         return false;
630     }
631     //make sure there is a user directory
632     OString sExcMsg("[Java framework] Error in function createSettingsDocument "
633                          "(elements.cxx).");
634     // check if javasettings.xml already exist
635     if (FILE_OK == checkSettingsFileStatus(sURL))
636         return true;
637 
638     //make sure that the directories are created in case they do not exist
639     FileBase::RC rcFile = Directory::createPath(getDirFromFile(sURL));
640     if (rcFile != FileBase::E_EXIST && rcFile != FileBase::E_None)
641         throw FrameworkException(JFW_E_ERROR, sExcMsg);
642 
643     //javasettings.xml does not exist yet
644     CXmlDocPtr doc(xmlNewDoc(reinterpret_cast<xmlChar const *>("1.0")));
645     if (! doc)
646         throw FrameworkException(JFW_E_ERROR, sExcMsg);
647 
648     //Create the root element and name spaces
649     xmlNodePtr root =   xmlNewDocNode(
650         doc, nullptr, reinterpret_cast<xmlChar const *>("java"), reinterpret_cast<xmlChar const *>("\n"));
651 
652     if (root == nullptr)
653         throw FrameworkException(JFW_E_ERROR, sExcMsg);
654 
655     if (xmlNewNs(root, reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK),nullptr) == nullptr)
656         throw FrameworkException(JFW_E_ERROR, sExcMsg);
657     if (xmlNewNs(root,reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE),reinterpret_cast<xmlChar const *>("xsi")) == nullptr)
658         throw FrameworkException(JFW_E_ERROR, sExcMsg);
659     xmlDocSetRootElement(doc,  root);
660 
661     //Create a comment
662     xmlNodePtr com = xmlNewComment(
663         reinterpret_cast<xmlChar const *>("This is a generated file. Do not alter this file!"));
664     if (com == nullptr)
665         throw FrameworkException(JFW_E_ERROR, sExcMsg);
666 
667     if (xmlAddPrevSibling(root, com) == nullptr)
668         throw FrameworkException(JFW_E_ERROR, sExcMsg);
669 
670     const OString path = getSettingsPath();
671     if (xmlSaveFormatFileEnc(path.getStr(), doc,"UTF-8", 1) == -1)
672          throw FrameworkException(JFW_E_ERROR, sExcMsg);
673     return true;
674 }
675 
676 
CNodeJavaInfo()677 CNodeJavaInfo::CNodeJavaInfo() :
678     m_bEmptyNode(false), bNil(true), bAutoSelect(true),
679     nFeatures(0), nRequirements(0)
680 {
681 }
682 
loadFromNode(xmlDoc * pDoc,xmlNode * pJavaInfo)683 void CNodeJavaInfo::loadFromNode(xmlDoc * pDoc, xmlNode * pJavaInfo)
684 {
685     OString sExcMsg("[Java framework] Error in function NodeJavaInfo::loadFromNode "
686                          "(elements.cxx).");
687 
688     OSL_ASSERT(pJavaInfo && pDoc);
689     if (pJavaInfo->children == nullptr)
690         return;
691     //Get the xsi:nil attribute;
692     CXmlCharPtr sNil = xmlGetNsProp(
693         pJavaInfo, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
694     if ( ! sNil)
695         throw FrameworkException(JFW_E_ERROR, sExcMsg);
696 
697     if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("true")) == 0)
698         bNil = true;
699     else if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
700         bNil = false;
701     else
702         throw FrameworkException(JFW_E_ERROR, sExcMsg);
703     if (bNil)
704         return;
705 
706     //Get javaInfo@manuallySelected attribute
707     CXmlCharPtr sAutoSelect = xmlGetProp(
708         pJavaInfo, reinterpret_cast<xmlChar const *>("autoSelect"));
709     if ( ! sAutoSelect)
710         throw FrameworkException(JFW_E_ERROR, sExcMsg);
711 
712     if (xmlStrcmp(sAutoSelect, reinterpret_cast<xmlChar const *>("true")) == 0)
713         bAutoSelect = true;
714     else if (xmlStrcmp(sAutoSelect, reinterpret_cast<xmlChar const *>("false")) == 0)
715         bAutoSelect = false;
716     else
717         throw FrameworkException(JFW_E_ERROR, sExcMsg);
718 
719     xmlNode * cur = pJavaInfo->children;
720 
721     while (cur != nullptr)
722     {
723         if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vendor")) == 0)
724         {
725             CXmlCharPtr xmlVendor = xmlNodeListGetString(
726                 pDoc, cur->children, 1);
727             if (! xmlVendor)
728                 return;
729             sVendor = xmlVendor;
730         }
731         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("location")) == 0)
732         {
733             CXmlCharPtr xmlLocation = xmlNodeListGetString(
734                 pDoc, cur->children, 1);
735             sLocation = xmlLocation;
736         }
737         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("version")) == 0)
738         {
739             CXmlCharPtr xmlVersion = xmlNodeListGetString(
740                 pDoc, cur->children, 1);
741             sVersion = xmlVersion;
742         }
743         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("features"))== 0)
744         {
745             CXmlCharPtr xmlFeatures = xmlNodeListGetString(
746                     pDoc, cur->children, 1);
747             OUString sFeatures = xmlFeatures;
748             nFeatures = sFeatures.toInt64(16);
749         }
750         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("requirements")) == 0)
751         {
752             CXmlCharPtr xmlRequire = xmlNodeListGetString(
753                 pDoc, cur->children, 1);
754             OUString sRequire = xmlRequire;
755             nRequirements = sRequire.toInt64(16);
756 #ifdef MACOSX
757             //javaldx is not used anymore in the mac build. In case the Java
758             //corresponding to the saved settings does not exist anymore the
759             //javavm services will look for an existing Java after creation of
760             //the JVM failed. See stoc/source/javavm/javavm.cxx. Only if
761             //nRequirements does not have the flag JFW_REQUIRE_NEEDRESTART the
762             //jvm of the new selected JRE will be started. Old settings (before
763             //OOo 3.3) still contain the flag which can be safely ignored.
764             nRequirements &= ~JFW_REQUIRE_NEEDRESTART;
765 #endif
766         }
767         else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vendorData")) == 0)
768         {
769             CXmlCharPtr xmlData = xmlNodeListGetString(
770                 pDoc, cur->children, 1);
771             xmlChar* _data = static_cast<xmlChar*>(xmlData);
772             if (_data)
773             {
774                 rtl::ByteSequence seq(reinterpret_cast<sal_Int8*>(_data), strlen(reinterpret_cast<char*>(_data)));
775                 arVendorData = decodeBase16(seq);
776             }
777         }
778         cur = cur->next;
779     }
780 
781     if (sVendor.isEmpty())
782         m_bEmptyNode = true;
783     //Get the javainfo attributes
784     CXmlCharPtr sVendorUpdate = xmlGetProp(pJavaInfo,
785                                reinterpret_cast<xmlChar const *>("vendorUpdate"));
786     if ( ! sVendorUpdate)
787         throw FrameworkException(JFW_E_ERROR, sExcMsg);
788     sAttrVendorUpdate = sVendorUpdate;
789 }
790 
791 
writeToNode(xmlDoc * pDoc,xmlNode * pJavaInfoNode) const792 void CNodeJavaInfo::writeToNode(xmlDoc* pDoc,
793                                 xmlNode* pJavaInfoNode) const
794 
795 {
796     OSL_ASSERT(pJavaInfoNode && pDoc);
797     //write the attribute vendorSettings
798 
799     //javaInfo@vendorUpdate
800     //creates the attribute if necessary
801     OString sUpdated = getElementUpdated();
802 
803     xmlSetProp(pJavaInfoNode, reinterpret_cast<xmlChar const *>("vendorUpdate"),
804                reinterpret_cast<xmlChar const *>(sUpdated.getStr()));
805 
806     //javaInfo@autoSelect
807     xmlSetProp(pJavaInfoNode, reinterpret_cast<xmlChar const *>("autoSelect"),
808                reinterpret_cast<xmlChar const *>(bAutoSelect ? "true" : "false"));
809 
810     //Set xsi:nil in javaInfo element to false
811     //the xmlNs pointer must not be destroyed
812     xmlNs* nsXsi = xmlSearchNsByHref(pDoc,
813                              pJavaInfoNode,
814                              reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
815 
816     xmlSetNsProp(pJavaInfoNode,
817                  nsXsi,
818                  reinterpret_cast<xmlChar const *>("nil"),
819                  reinterpret_cast<xmlChar const *>("false"));
820 
821     //Delete the children of JavaInfo
822     xmlNode* cur = pJavaInfoNode->children;
823     while (cur != nullptr)
824     {
825         xmlNode* lastNode = cur;
826         cur = cur->next;
827         xmlUnlinkNode(lastNode);
828         xmlFreeNode(lastNode);
829     }
830 
831     //If the JavaInfo was set with an empty value,
832     //then we are done.
833     if (m_bEmptyNode)
834         return;
835 
836     //add a new line after <javaInfo>
837     xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
838     xmlAddChild(pJavaInfoNode, nodeCrLf);
839 
840     //Create the vendor element
841     xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("vendor"),
842                     CXmlCharPtr(sVendor));
843     //add a new line for better readability
844     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
845     xmlAddChild(pJavaInfoNode, nodeCrLf);
846 
847     //Create the location element
848     xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("location"),
849                     CXmlCharPtr(sLocation));
850     //add a new line for better readability
851     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
852     xmlAddChild(pJavaInfoNode, nodeCrLf);
853 
854     //Create the version element
855     xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("version"),
856                     CXmlCharPtr(sVersion));
857     //add a new line for better readability
858     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
859     xmlAddChild(pJavaInfoNode, nodeCrLf);
860 
861     //Create the features element
862     OUString sFeatures = OUString::number(
863         nFeatures, 16);
864     xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("features"),
865                     CXmlCharPtr(sFeatures));
866     //add a new line for better readability
867     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
868     xmlAddChild(pJavaInfoNode, nodeCrLf);
869 
870 
871     //Create the requirements element
872     OUString sRequirements = OUString::number(
873          nRequirements, 16);
874     xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("requirements"),
875                     CXmlCharPtr(sRequirements));
876     //add a new line for better readability
877     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
878     xmlAddChild(pJavaInfoNode, nodeCrLf);
879 
880 
881     //Create the features element
882     rtl::ByteSequence data = encodeBase16(arVendorData);
883     xmlNode* dataNode = xmlNewChild(pJavaInfoNode, nullptr,
884                                     reinterpret_cast<xmlChar const *>("vendorData"),
885                                     reinterpret_cast<xmlChar const *>(""));
886     xmlNodeSetContentLen(dataNode,
887                          reinterpret_cast<xmlChar*>(data.getArray()), data.getLength());
888     //add a new line for better readability
889     nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
890     xmlAddChild(pJavaInfoNode, nodeCrLf);
891 }
892 
makeJavaInfo() const893 std::unique_ptr<JavaInfo> CNodeJavaInfo::makeJavaInfo() const
894 {
895     if (bNil || m_bEmptyNode)
896         return std::unique_ptr<JavaInfo>();
897     return std::unique_ptr<JavaInfo>(
898         new JavaInfo{
899             sVendor, sLocation, sVersion, nFeatures, nRequirements,
900             arVendorData});
901 }
902 
903 
MergedSettings()904 MergedSettings::MergedSettings():
905     m_bEnabled(false),
906     m_sClassPath(),
907     m_vmParams(),
908     m_JRELocations(),
909     m_javaInfo()
910 {
911     NodeJava settings(NodeJava::USER);
912     settings.load();
913     NodeJava sharedSettings(NodeJava::SHARED);
914     sharedSettings.load();
915     merge(sharedSettings, settings);
916 }
917 
~MergedSettings()918 MergedSettings::~MergedSettings()
919 {
920 }
921 
merge(const NodeJava & share,const NodeJava & user)922 void MergedSettings::merge(const NodeJava & share, const NodeJava & user)
923 {
924     if (user.getEnabled())
925         m_bEnabled = * user.getEnabled();
926     else if (share.getEnabled())
927         m_bEnabled = * share.getEnabled();
928     else
929         m_bEnabled = true;
930 
931     if (user.getUserClassPath())
932         m_sClassPath = * user.getUserClassPath();
933     else if (share.getUserClassPath())
934         m_sClassPath = * share.getUserClassPath();
935 
936     if (user.getJavaInfo())
937         m_javaInfo = * user.getJavaInfo();
938     else if (share.getJavaInfo())
939         m_javaInfo = * share.getJavaInfo();
940 
941     if (user.getVmParameters())
942         m_vmParams = * user.getVmParameters();
943     else if (share.getVmParameters())
944          m_vmParams = * share.getVmParameters();
945 
946     if (user.getJRELocations())
947         m_JRELocations = * user.getJRELocations();
948     else if (share.getJRELocations())
949         m_JRELocations = * share.getJRELocations();
950 }
951 
952 
getVmParametersUtf8() const953 ::std::vector< OString> MergedSettings::getVmParametersUtf8() const
954 {
955     ::std::vector< OString> ret;
956     for (auto const & vmParam : m_vmParams)
957     {
958         ret.push_back( OUStringToOString(vmParam, RTL_TEXTENCODING_UTF8));
959     }
960     return ret;
961 }
962 
963 
createJavaInfo() const964 std::unique_ptr<JavaInfo> MergedSettings::createJavaInfo() const
965 {
966     return m_javaInfo.makeJavaInfo();
967 }
968 #ifdef _WIN32
getJavaInfoAttrAutoSelect() const969 bool MergedSettings::getJavaInfoAttrAutoSelect() const
970 {
971     return m_javaInfo.bAutoSelect;
972 }
973 #endif
getVmParametersArray(std::vector<OUString> * parParams) const974 void MergedSettings::getVmParametersArray(std::vector<OUString> * parParams)
975     const
976 {
977     assert(parParams != nullptr);
978     osl::MutexGuard guard(FwkMutex::get());
979 
980     *parParams = m_vmParams;
981 }
982 
983 }
984 
985 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
986