xref: /trunk/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx (revision 5e139d9fe42a654147771da4118aea6285c03168)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_plugin.hxx"
26 
27 #include "util.hxx"
28 
29 #include "osl/process.h"
30 #include "osl/security.hxx"
31 #include "osl/thread.hxx"
32 #include "osl/file.hxx"
33 #include "osl/module.hxx"
34 #include "rtl/byteseq.hxx"
35 #include "rtl/ustrbuf.hxx"
36 #include "rtl/instance.hxx"
37 #include "boost/scoped_array.hpp"
38 #include "com/sun/star/uno/Sequence.hxx"
39 #include <utility>
40 #include <algorithm>
41 #include <map>
42 
43 #if defined WNT
44 #if defined _MSC_VER
45 #pragma warning(push, 1)
46 #endif
47 #include <windows.h>
48 #if defined _MSC_VER
49 #pragma warning(pop)
50 #endif
51 #endif
52 #include <string.h>
53 
54 #include "sunjre.hxx"
55 #include "vendorlist.hxx"
56 #include "diagnostics.h"
57 using namespace rtl;
58 using namespace osl;
59 using namespace std;
60 
61 #define CHAR_POINTER(oustr) ::rtl::OUStringToOString(oustr,RTL_TEXTENCODING_UTF8).pData->buffer
62 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
63 #ifdef WNT
64 #define HKEY_SUN_JRE L"Software\\JavaSoft\\Java Runtime Environment"
65 #define HKEY_SUN_SDK L"Software\\JavaSoft\\Java Development Kit"
66 #endif
67 
68 #ifdef UNX
69 namespace {
70 char const *g_arJavaNames[] = {
71     "",
72     "j2re",
73     "j2se",
74     "j2sdk",
75     "jdk",
76     "jre",
77     "java",
78     "Home",
79     "IBMJava2-ppc-142"
80 };
81 /* These are directory names which could contain multiple java installations.
82  */
83 char const *g_arCollectDirs[] = {
84     "",
85     "j2re/",
86     "j2se/",
87     "j2sdk/",
88     "jdk/",
89     "jre/",
90     "java/",
91     "jvm/"
92 };
93 
94 struct JavaSearchPathEntry {
95     int searchImmediateContents; // More thorough, too slow for /usr/bin and /usr/lib
96     char const *path;
97 };
98 
99 /* These are directories in which a java installation is
100    looked for.
101 */
102 struct JavaSearchPathEntry g_arSearchPaths[] = {
103 #ifdef MACOSX
104     { 0, "" },
105     // Modern macOS JDK location (Oracle/Temurin/etc., both arm64 and x86_64
106     // install here). Each subdirectory is a JDK whose home is Contents/Home,
107     // so scan the immediate contents. A JDK of the wrong architecture (e.g. a
108     // Rosetta x86_64 JDK on Apple Silicon) is harmlessly skipped when its
109     // libjvm.dylib fails to load into the native-arch process.
110     { 1, "Library/Java/JavaVirtualMachines/" },
111     { 0, "Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin" },
112     { 0, "System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/" },
113 #else
114     { 0, "" },
115     { 1, "usr/" },
116     { 1, "usr/local/" },
117     { 0, "usr/local/IBMJava2-ppc-142" },
118     { 0, "usr/local/j2sdk1.3.1" },
119 #ifdef X86_64
120     { 0, "usr/lib64/" },
121 #endif
122     { 0, "usr/lib/" },
123     { 0, "usr/bin/" }
124 #endif
125 };
126 }
127 #endif //  UNX
128 
129 namespace jfw_plugin
130 {
131 extern VendorSupportMapEntry gVendorMap[];
132 
133 bool getSDKInfoFromRegistry(vector<OUString> & vecHome);
134 bool getJREInfoFromRegistry(vector<OUString>& vecJavaHome);
135 bool decodeOutput(const rtl::OString& s, rtl::OUString* out);
136 
137 
138 
139 namespace
140 {
getLibraryLocation()141     rtl::OUString getLibraryLocation()
142     {
143         rtl::OUString libraryFileUrl;
144         OSL_VERIFY(osl::Module::getUrlFromAddress((void *)(sal_IntPtr)getLibraryLocation, libraryFileUrl));
145         return getDirFromFile(libraryFileUrl);
146     }
147 
148     struct InitBootstrap
149     {
operator ()jfw_plugin::__anon1f015b3d0211::InitBootstrap150         rtl::Bootstrap * operator()(const OUString& sIni)
151         {
152             static rtl::Bootstrap aInstance(sIni);
153             return & aInstance;
154 
155         }
156    };
157 
158    struct InitBootstrapData
159    {
operator ()jfw_plugin::__anon1f015b3d0211::InitBootstrapData160        OUString const & operator()()
161        {
162            //  osl::Guard<osl::Mutex> g(osl::GetGlobalMutex());
163            static OUString sIni;
164             rtl::OUStringBuffer buf( 255);
165             buf.append( getLibraryLocation());
166             buf.appendAscii( SAL_CONFIGFILE("/sunjavaplugin") );
167             sIni = buf.makeStringAndClear();
168             JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin: "
169                              "Using configuration file \n") +  sIni);
170             return sIni;
171         }
172    };
173 }
174 
getBootstrap()175 rtl::Bootstrap * getBootstrap()
176 {
177     return rtl_Instance< rtl::Bootstrap, InitBootstrap,
178         ::osl::MutexGuard, ::osl::GetGlobalMutex,
179         OUString, InitBootstrapData >::create(
180             InitBootstrap(), ::osl::GetGlobalMutex(), InitBootstrapData());
181 }
182 
183 
184 
185 
186 class FileHandleGuard
187 {
188 public:
189     inline FileHandleGuard(oslFileHandle & rHandle) SAL_THROW(()):
190         m_rHandle(rHandle) {}
191 
192     inline ~FileHandleGuard() SAL_THROW(());
193 
getHandle()194     inline oslFileHandle & getHandle() SAL_THROW(()) { return m_rHandle; }
195 
196 private:
197     oslFileHandle & m_rHandle;
198 
199     FileHandleGuard(FileHandleGuard &); // not implemented
200     void operator =(FileHandleGuard); // not implemented
201 };
202 
~FileHandleGuard()203 inline FileHandleGuard::~FileHandleGuard() SAL_THROW(())
204 {
205     if (m_rHandle != 0)
206     {
207         if (osl_closeFile(m_rHandle) != osl_File_E_None)
208         {
209             OSL_ENSURE(false, "unexpected situation");
210         }
211     }
212 }
213 
214 
215 class FileHandleReader
216 {
217 public:
218     enum Result
219     {
220         RESULT_OK,
221         RESULT_EOF,
222         RESULT_ERROR
223     };
224 
225     inline FileHandleReader(oslFileHandle & rHandle) SAL_THROW(()):
226         m_aGuard(rHandle), m_nSize(0), m_nIndex(0), m_bLf(false) {}
227 
228     Result readLine(rtl::OString * pLine) SAL_THROW(());
229 
230 private:
231     enum { BUFFER_SIZE = 1024 };
232 
233     sal_Char m_aBuffer[BUFFER_SIZE];
234     FileHandleGuard m_aGuard;
235     int m_nSize;
236     int m_nIndex;
237     bool m_bLf;
238 };
239 
240 FileHandleReader::Result
readLine(rtl::OString * pLine)241 FileHandleReader::readLine(rtl::OString * pLine)
242     SAL_THROW(())
243 {
244     OSL_ENSURE(pLine, "specification violation");
245 
246     for (bool bEof = true;; bEof = false)
247     {
248         if (m_nIndex == m_nSize)
249         {
250             sal_uInt64 nRead = 0;
251             switch (osl_readFile(
252                         m_aGuard.getHandle(), m_aBuffer, sizeof(m_aBuffer), &nRead))
253             {
254             case osl_File_E_PIPE: //HACK! for windows
255                 nRead = 0;
256             case osl_File_E_None:
257                 if (nRead == 0)
258                 {
259                     m_bLf = false;
260                     return bEof ? RESULT_EOF : RESULT_OK;
261                 }
262                 m_nIndex = 0;
263                 m_nSize = static_cast< int >(nRead);
264                 break;
265             case osl_File_E_INTR:
266                 continue;
267 
268             default:
269                 return RESULT_ERROR;
270             }
271         }
272 
273         if (m_bLf && m_aBuffer[m_nIndex] == 0x0A)
274             ++m_nIndex;
275         m_bLf = false;
276 
277         int nStart = m_nIndex;
278         while (m_nIndex != m_nSize)
279             switch (m_aBuffer[m_nIndex++])
280             {
281             case 0x0D:
282                 m_bLf = true;
283             case 0x0A:
284                 *pLine += rtl::OString(m_aBuffer + nStart,
285                                        m_nIndex - 1 - nStart);
286                     //TODO! check for overflow, and not very efficient
287                 return RESULT_OK;
288             }
289 
290         *pLine += rtl::OString(m_aBuffer + nStart, m_nIndex - nStart);
291             //TODO! check for overflow, and not very efficient
292     }
293 }
294 
295 class AsynchReader: public Thread
296 {
297     size_t  m_nDataSize;
298     boost::scoped_array<sal_Char> m_arData;
299 
300     bool m_bError;
301     bool m_bDone;
302     FileHandleGuard m_aGuard;
303 
304     void SAL_CALL run();
305 public:
306 
307     AsynchReader(oslFileHandle & rHandle);
308 #if OSL_DEBUG_LEVEL >= 2
309     /** only call this function after this thread has finished.
310 
311         That is, call join on this instance and then call getData.
312 
313      */
314     OString getData();
315 #endif
316 };
317 
AsynchReader(oslFileHandle & rHandle)318 AsynchReader::AsynchReader(oslFileHandle & rHandle):
319     m_nDataSize(0), m_bError(false), m_bDone(false), m_aGuard(rHandle)
320 {
321 }
322 
323 #if OSL_DEBUG_LEVEL >= 2
getData()324 OString AsynchReader::getData()
325 {
326     OSL_ASSERT(isRunning() == sal_False );
327     return OString(m_arData.get(), m_nDataSize);
328 }
329 #endif
330 
run()331 void AsynchReader::run()
332 {
333     const sal_uInt64 BUFFER_SIZE = 4096;
334     sal_Char aBuffer[BUFFER_SIZE];
335     while (true)
336     {
337         sal_uInt64 nRead;
338         //the function blocks until something could be read or the pipe closed.
339         switch (osl_readFile(
340                     m_aGuard.getHandle(), aBuffer, BUFFER_SIZE, &nRead))
341         {
342         case osl_File_E_PIPE: //HACK! for windows
343             nRead = 0;
344         case osl_File_E_None:
345             break;
346         default:
347             m_bError = true;
348             return;
349         }
350 
351         if (nRead == 0)
352         {
353             m_bDone = true;
354             break;
355         }
356         else if (nRead <= BUFFER_SIZE)
357         {
358             //Save the data we have in m_arData into a temporary array
359             boost::scoped_array<sal_Char> arTmp( new sal_Char[m_nDataSize]);
360             memcpy(arTmp.get(), m_arData.get(), m_nDataSize);
361             //Enlarge m_arData to hold the newly read data
362             m_arData.reset(new sal_Char[(size_t)(m_nDataSize + nRead)]);
363             //Copy back the data that was already in m_arData
364             memcpy(m_arData.get(), arTmp.get(), m_nDataSize);
365             //Add the newly read data to m_arData
366             memcpy(m_arData.get() + m_nDataSize, aBuffer, (size_t) nRead);
367             m_nDataSize += (size_t) nRead;
368         }
369     }
370 }
371 
372 
getJavaProps(const OUString & exePath,std::vector<std::pair<rtl::OUString,rtl::OUString>> & props,bool * bProcessRun)373 bool getJavaProps(const OUString & exePath,
374                   std::vector<std::pair<rtl::OUString, rtl::OUString> >& props,
375                   bool * bProcessRun)
376 {
377     bool ret = false;
378 
379     OSL_ASSERT( exePath.getLength() > 0);
380     OUString usStartDir;
381     //We need to set the CLASSPATH in case the office is started from
382     //a different directory. The JREProperties.class is expected to reside
383     //next to the plugin.
384     rtl::OUString sThisLib;
385     if (osl_getModuleURLFromAddress((void *) (sal_IntPtr)& getJavaProps,
386                                     & sThisLib.pData) == sal_False)
387         return false;
388     sThisLib = getDirFromFile(sThisLib);
389     OUString sClassPath;
390     if (osl_getSystemPathFromFileURL(sThisLib.pData, & sClassPath.pData)
391         != osl_File_E_None)
392         return false;
393 
394     //check if we shall examine a Java for accessibility support
395     //If the bootstrap variable is "1" then we pass the argument
396     //"noaccessibility" to JREProperties.class. This will prevent
397     //that it calls   java.awt.Toolkit.getDefaultToolkit();
398     OUString sValue;
399     getBootstrap()->getFrom(OUSTR("JFW_PLUGIN_DO_NOT_CHECK_ACCESSIBILITY"), sValue);
400 
401     //prepare the arguments
402     sal_Int32 cArgs = 3;
403     OUString arg1 = OUString(RTL_CONSTASCII_USTRINGPARAM("-classpath"));// + sClassPath;
404     OUString arg2 = sClassPath;
405     OUString arg3(RTL_CONSTASCII_USTRINGPARAM("JREProperties"));
406     OUString arg4 = OUSTR("noaccessibility");
407     rtl_uString *args[4] = {arg1.pData, arg2.pData, arg3.pData};
408 
409     // Only add the fourth param if the bootstrap parameter is set.
410     if (sValue.equals(OUString::valueOf((sal_Int32) 1)))
411     {
412         args[3] = arg4.pData;
413         cArgs = 4;
414     }
415 
416     oslProcess javaProcess= 0;
417     oslFileHandle fileOut= 0;
418     oslFileHandle fileErr= 0;
419 
420     FileHandleReader stdoutReader(fileOut);
421     AsynchReader stderrReader(fileErr);
422 
423     JFW_TRACE2(OUSTR("\n[Java framework] Executing: ") + exePath + OUSTR(".\n"));
424     oslProcessError procErr =
425         osl_executeProcess_WithRedirectedIO( exePath.pData,//usExe.pData,
426                                              args,
427                                              cArgs,                 //sal_uInt32   nArguments,
428                                              osl_Process_HIDDEN, //oslProcessOption Options,
429                                              NULL, //oslSecurity Security,
430                                              usStartDir.pData,//usStartDir.pData,//usWorkDir.pData, //rtl_uString *strWorkDir,
431                                              NULL, //rtl_uString *strEnvironment[],
432                                              0, //  sal_uInt32   nEnvironmentVars,
433                                              &javaProcess, //oslProcess *pProcess,
434                                              NULL,//oslFileHandle *pChildInputWrite,
435                                              &fileOut,//oslFileHandle *pChildOutputRead,
436                                              &fileErr);//oslFileHandle *pChildErrorRead);
437 
438     if( procErr != osl_Process_E_None)
439     {
440         JFW_TRACE2("[Java framework] Execution failed. \n");
441         *bProcessRun = false;
442         return ret;
443     }
444     else
445     {
446         JFW_TRACE2("[Java framework] Java executed successfully.\n");
447         *bProcessRun = true;
448     }
449 
450     //Start asynchronous reading (different thread) of error stream
451     stderrReader.create();
452 
453     //Use this thread to read output stream
454     FileHandleReader::Result rs = FileHandleReader::RESULT_OK;
455     while (1)
456     {
457         OString aLine;
458         rs = stdoutReader.readLine( & aLine);
459         if (rs != FileHandleReader::RESULT_OK)
460             break;
461 //         JFW_TRACE2(OString("[Java framework] line:\" ")
462 //                + aLine + OString(" \".\n"));
463         OUString sLine;
464         if (!decodeOutput(aLine, &sLine))
465             continue;
466         JFW_TRACE2(OString("[Java framework]:\" ")
467                + OString( CHAR_POINTER(sLine)) + OString(" \".\n"));
468         sLine = sLine.trim();
469         if (sLine.getLength() == 0)
470             continue;
471         //The JREProperties class writes key value pairs, separated by '='
472         sal_Int32 index = sLine.indexOf('=', 0);
473         OSL_ASSERT(index != -1);
474         OUString sKey = sLine.copy(0, index);
475         OUString sVal = sLine.copy(index + 1);
476 
477         props.push_back(std::make_pair(sKey, sVal));
478     }
479 
480     if (rs != FileHandleReader::RESULT_ERROR && props.size()>0)
481         ret = true;
482 
483     //process error stream data
484     stderrReader.join();
485     JFW_TRACE2(OString("[Java framework]  Java wrote to stderr:\" ")
486                + stderrReader.getData() + OString(" \".\n"));
487 
488     TimeValue waitMax= {5 ,0};
489     procErr = osl_joinProcessWithTimeout(javaProcess, &waitMax);
490     OSL_ASSERT(procErr == osl_Process_E_None);
491     osl_freeProcessHandle(javaProcess);
492     return ret;
493 }
494 
495 /* converts the properties printed by JREProperties.class into
496     readable strings. The strings are encoded as integer values separated
497     by spaces.
498  */
decodeOutput(const rtl::OString & s,rtl::OUString * out)499 bool decodeOutput(const rtl::OString& s, rtl::OUString* out)
500 {
501     OSL_ASSERT(out != 0);
502     OUStringBuffer buff(512);
503     sal_Int32 nIndex = 0;
504     do
505     {
506         OString aToken = s.getToken( 0, ' ', nIndex );
507         if (aToken.getLength())
508         {
509             for (sal_Int32 i = 0; i < aToken.getLength(); ++i)
510             {
511                 if (aToken[i] < '0' || aToken[i] > '9')
512                     return false;
513             }
514             sal_Unicode value = (sal_Unicode)(aToken.toInt32());
515             buff.append(value);
516         }
517     } while (nIndex >= 0);
518 
519     *out = buff.makeStringAndClear();
520 //    JFW_TRACE2(*out);
521     return true;
522 }
523 
524 
525 #if defined WNT
createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase>> & vecInfos)526 void createJavaInfoFromWinReg(std::vector<rtl::Reference<VendorBase> > & vecInfos)
527 {
528         // Get Java s from registry
529     std::vector<OUString> vecJavaHome;
530     if(getSDKInfoFromRegistry(vecJavaHome))
531     {
532         // create impl objects
533         typedef std::vector<OUString>::iterator ItHome;
534         for(ItHome it_home= vecJavaHome.begin(); it_home != vecJavaHome.end();
535             it_home++)
536         {
537             getJREInfoByPath(*it_home, vecInfos);
538         }
539     }
540 
541     vecJavaHome.clear();
542     if(getJREInfoFromRegistry(vecJavaHome))
543     {
544         typedef std::vector<OUString>::iterator ItHome;
545         for(ItHome it_home= vecJavaHome.begin(); it_home != vecJavaHome.end();
546             it_home++)
547         {
548             getJREInfoByPath(*it_home, vecInfos);
549         }
550    }
551 }
552 
553 
getJavaInfoFromRegistry(const wchar_t * szRegKey,vector<OUString> & vecJavaHome)554 bool getJavaInfoFromRegistry(const wchar_t* szRegKey,
555                              vector<OUString>& vecJavaHome)
556 {
557     HKEY    hRoot;
558     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_ENUMERATE_SUB_KEYS, &hRoot)
559         == ERROR_SUCCESS)
560     {
561         DWORD dwIndex = 0;
562         const DWORD BUFFSIZE = 1024;
563         wchar_t bufVersion[BUFFSIZE];
564 //      char bufVersion[BUFFSIZE];
565         DWORD nNameLen = BUFFSIZE;
566         FILETIME fileTime;
567         nNameLen = sizeof(bufVersion);
568 
569         // Iterate over all subkeys of HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment
570         while (RegEnumKeyExW(hRoot, dwIndex, bufVersion, &nNameLen, NULL, NULL, NULL, &fileTime) != ERROR_NO_MORE_ITEMS)
571         {
572             HKEY    hKey;
573             // Open a Java Runtime Environment sub key, e.g. "1.4.0"
574             if (RegOpenKeyExW(hRoot, bufVersion, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
575             {
576                 DWORD   dwType;
577                 DWORD   dwTmpPathLen= 0;
578                 // Get the path to the JavaHome every JRE entry
579                 // Find out how long the string for JavaHome is and allocate memory to hold the path
580                 if( RegQueryValueExW(hKey, L"JavaHome", 0, &dwType, NULL, &dwTmpPathLen)== ERROR_SUCCESS)
581                 {
582                     char* szTmpPath= (char *) malloc( dwTmpPathLen);
583                     // Get the path for the runtime lib
584                     if(RegQueryValueExW(hKey, L"JavaHome", 0, &dwType, (unsigned char*) szTmpPath, &dwTmpPathLen) == ERROR_SUCCESS)
585                     {
586                         // There can be several version entries referring with the same JavaHome,e.g 1.4 and 1.4.1
587                         OUString usHome((sal_Unicode*) szTmpPath);
588                         // check if there is already an entry with the same JavaHomeruntime lib
589                         // if so, we use the one with the more accurate version
590                         bool bAppend= true;
591                         OUString usHomeUrl;
592                         if (osl_getFileURLFromSystemPath(usHome.pData, & usHomeUrl.pData) ==
593                             osl_File_E_None)
594                         {
595                             //iterate over the vector with java home strings
596                             typedef vector<OUString>::iterator ItHome;
597                             for(ItHome itHome= vecJavaHome.begin();
598                                 itHome != vecJavaHome.end(); itHome++)
599                             {
600                                 if(usHomeUrl.equals(*itHome))
601                                 {
602                                     bAppend= false;
603                                     break;
604                                 }
605                             }
606                             // Save the home dir
607                             if(bAppend)
608                             {
609                                 vecJavaHome.push_back(usHomeUrl);
610                             }
611                         }
612                     }
613                     free( szTmpPath);
614                     RegCloseKey(hKey);
615                 }
616             }
617             dwIndex ++;
618             nNameLen = BUFFSIZE;
619         }
620         RegCloseKey(hRoot);
621     }
622     return true;
623 }
624 
625 
626 
getSDKInfoFromRegistry(vector<OUString> & vecHome)627 bool getSDKInfoFromRegistry(vector<OUString> & vecHome)
628 {
629     return getJavaInfoFromRegistry(HKEY_SUN_SDK, vecHome);
630 }
631 
getJREInfoFromRegistry(vector<OUString> & vecJavaHome)632 bool getJREInfoFromRegistry(vector<OUString>& vecJavaHome)
633 {
634     return getJavaInfoFromRegistry(HKEY_SUN_JRE, vecJavaHome);
635 }
636 
637 #endif // WNT
638 
bubbleSortVersion(vector<rtl::Reference<VendorBase>> & vec)639 void bubbleSortVersion(vector<rtl::Reference<VendorBase> >& vec)
640 {
641     if(vec.size() == 0)
642         return;
643     int size= vec.size() - 1;
644     int cIter= 0;
645     // sort for version
646     for(int i= 0; i < size; i++)
647     {
648         for(int j= size; j > 0 + cIter; j--)
649         {
650             rtl::Reference<VendorBase>& cur= vec.at(j);
651             rtl::Reference<VendorBase>& next= vec.at(j-1);
652 
653             int nCmp = 0;
654             // comparing invalid SunVersion s is possible, they will be less than a
655             // valid version
656 
657             //check if version of current is recognized, by comparing it with itself
658             try
659             {
660                 cur->compareVersions(cur->getVersion());
661             }
662             catch (MalformedVersionException &)
663             {
664                 nCmp = -1; // current < next
665             }
666             //The version of cur is valid, now compare with the second version
667             if (nCmp == 0)
668             {
669                 try
670                 {
671                     nCmp = cur->compareVersions(next->getVersion());
672                 }
673                 catch (MalformedVersionException & )
674                 {
675                     //The second version is invalid, therefor it is regardes less.
676                     nCmp = 1;
677                 }
678             }
679             if(nCmp == 1) // cur > next
680             {
681                 rtl::Reference<VendorBase> less = next;
682                 vec.at(j-1)= cur;
683                 vec.at(j)= less;
684             }
685         }
686         cIter++;
687     }
688 }
689 
690 
getJREInfoFromBinPath(const rtl::OUString & path,vector<rtl::Reference<VendorBase>> & vecInfos)691 bool getJREInfoFromBinPath(
692     const rtl::OUString& path, vector<rtl::Reference<VendorBase> > & vecInfos)
693 {
694     // file:///c:/jre/bin
695     //map:       jre/bin/java.exe
696     bool ret = false;
697     vector<pair<OUString, OUString> > props;
698 
699     for ( sal_Int32 pos = 0;
700           gVendorMap[pos].sVendorName != NULL; ++pos )
701     {
702         vector<OUString> vecPaths;
703         getJavaExePaths_func pFunc = gVendorMap[pos].getJavaFunc;
704 
705         int size = 0;
706         char const* const* arExePaths = (*pFunc)(&size);
707         vecPaths = getVectorFromCharArray(arExePaths, size);
708 
709         //make sure argument path does not end with '/'
710         OUString sBinPath = path;
711         if (path.lastIndexOf('/') == (path.getLength() - 1))
712             sBinPath = path.copy(0, path.getLength() - 1);
713 
714         typedef vector<OUString>::const_iterator c_it;
715         for (c_it i = vecPaths.begin(); i != vecPaths.end(); i++)
716         {
717             //the map contains e.g. jre/bin/java.exe
718             //get the directory where the executable is contained
719             OUString sHome;
720             sal_Int32 index = i->lastIndexOf('/');
721             if (index == -1)
722             {
723                 //map contained only : "java.exe, then the argument
724                 //path is already the home directory
725                 sHome = sBinPath;
726             }
727             else
728             {
729                 // jre/bin/jre -> jre/bin
730                 OUString sMapPath(i->getStr(), index);
731                 index = sBinPath.lastIndexOf(sMapPath);
732                 if (index != -1
733                     && (index + sMapPath.getLength() == sBinPath.getLength())
734                     && sBinPath[index - 1] == '/')
735                 {
736                     sHome = OUString(sBinPath.getStr(), index - 1);
737                 }
738             }
739             if (sHome.getLength() > 0)
740             {
741                 ret = getJREInfoByPath(sHome, vecInfos);
742                 if (ret)
743                     break;
744             }
745         }
746         if (ret)
747             break;
748     }
749     return ret;
750 }
751 
getAllJREInfos()752 vector<Reference<VendorBase> > getAllJREInfos()
753 {
754     vector<Reference<VendorBase> > vecInfos;
755 
756 #if defined WNT
757     // Get Javas from the registry
758     createJavaInfoFromWinReg(vecInfos);
759 #endif // WNT
760 
761     createJavaInfoFromJavaHome(vecInfos);
762     //this function should be called after createJavaInfoDirScan.
763     //Otherwise in SDKs Java may be started twice
764     createJavaInfoFromPath(vecInfos);
765 
766 #ifdef UNX
767     createJavaInfoDirScan(vecInfos);
768 #endif
769 
770     bubbleSortVersion(vecInfos);
771     return vecInfos;
772 }
773 
774 
getVectorFromCharArray(char const * const * ar,int size)775 vector<OUString> getVectorFromCharArray(char const * const * ar, int size)
776 {
777     vector<OUString> vec;
778     for( int i = 0; i < size; i++)
779     {
780         OUString s(ar[i], strlen(ar[i]), RTL_TEXTENCODING_UTF8);
781         vec.push_back(s);
782     }
783     return vec;
784 }
getJREInfoByPath(const rtl::OUString & path,std::vector<rtl::Reference<VendorBase>> & vecInfos)785 bool getJREInfoByPath(const rtl::OUString& path,
786                       std::vector<rtl::Reference<VendorBase> > & vecInfos)
787 {
788     bool ret = false;
789 
790     rtl::Reference<VendorBase> aInfo = getJREInfoByPath(path);
791     if (aInfo.is())
792     {
793         ret = true;
794         vector<rtl::Reference<VendorBase> >::const_iterator it_impl= std::find_if(
795             vecInfos.begin(),vecInfos.end(), InfoFindSame(aInfo->getHome()));
796         if(it_impl == vecInfos.end())
797         {
798             vecInfos.push_back(aInfo);
799         }
800     }
801     return ret;
802 }
803 
804 /** Checks if the path is a directory. Links are resolved.
805     In case of an error the returned string has the length 0.
806     Otherwise the returned string is the "resolved" file URL.
807  */
resolveDirPath(const OUString & path)808 OUString resolveDirPath(const OUString & path)
809 {
810     OUString ret;
811     OUString sResolved;
812     //getAbsoluteFileURL also resolves links
813     if (File::getAbsoluteFileURL(
814             OUSTR("file:///"), path, sResolved) != File::E_None)
815         return OUString();
816 
817     //check if this is a valid path and if it is a directory
818     DirectoryItem item;
819     if (DirectoryItem::get(sResolved, item) == File::E_None)
820     {
821         FileStatus status(FileStatusMask_Type |
822                           FileStatusMask_LinkTargetURL |
823                           FileStatusMask_FileURL);
824 
825         if (item.getFileStatus(status) == File::E_None
826             && status.getFileType() == FileStatus::Directory)
827         {
828             ret = sResolved;
829         }
830     }
831     else
832         return OUString();
833     return ret;
834 }
835 /** Checks if the path is a file. If it is a link to a file than
836     it is resolved.
837  */
resolveFilePath(const OUString & path)838 OUString resolveFilePath(const OUString & path)
839 {
840     OUString ret;
841     OUString sResolved;
842 
843     if (File::getAbsoluteFileURL(
844             OUSTR("file:///"), path, sResolved) != File::E_None)
845         return OUString();
846 
847     //check if this is a valid path to a file or and if it is a link
848     DirectoryItem item;
849     if (DirectoryItem::get(sResolved, item) == File::E_None)
850     {
851         FileStatus status(FileStatusMask_Type |
852                           FileStatusMask_LinkTargetURL |
853                           FileStatusMask_FileURL);
854         if (item.getFileStatus(status) == File::E_None
855             && status.getFileType() == FileStatus::Regular)
856         {
857             ret = sResolved;
858         }
859     }
860     else
861         return OUString();
862 
863     return ret;
864 }
865 
getJREInfoByPath(const OUString & path)866 rtl::Reference<VendorBase> getJREInfoByPath(
867     const OUString& path)
868 {
869     rtl::Reference<VendorBase> ret;
870     static vector<OUString> vecBadPaths;
871 
872     static map<OUString, rtl::Reference<VendorBase> > mapJREs;
873     typedef map<OUString, rtl::Reference<VendorBase> >::const_iterator MapIt;
874     typedef map<OUString, rtl::Reference<VendorBase> > MAPJRE;
875     OUString sFilePath;
876     typedef vector<OUString>::const_iterator cit_path;
877     vector<pair<OUString, OUString> > props;
878 
879     OUString sResolvedDir = resolveDirPath(path);
880     // If this path is invalid then there is no chance to find a JRE here
881     if (sResolvedDir.getLength() == 0)
882         return 0;
883 
884     //check if the directory path is good, that is a JRE was already recognized.
885     //Then we need not detect it again
886     //For example, a sun JKD contains <jdk>/bin/java and <jdk>/jre/bin/java.
887     //When <jdk>/bin/java has been found then we need not find <jdk>/jre/bin/java.
888     //Otherwise we would execute java two times for evers JDK found.
889     MapIt entry2 = find_if(mapJREs.begin(), mapJREs.end(),
890                            SameOrSubDirJREMap(sResolvedDir));
891     if (entry2 != mapJREs.end())
892     {
893         JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin" SAL_DLLEXTENSION ": ")
894                    + OUSTR("JRE found again (detected before): ") + sResolvedDir
895                    + OUSTR(".\n"));
896         return entry2->second;
897     }
898 
899     for ( sal_Int32 pos = 0;
900           gVendorMap[pos].sVendorName != NULL; ++pos )
901     {
902         vector<OUString> vecPaths;
903         getJavaExePaths_func pFunc = gVendorMap[pos].getJavaFunc;
904 
905         int size = 0;
906         char const* const* arExePaths = (*pFunc)(&size);
907         vecPaths = getVectorFromCharArray(arExePaths, size);
908 
909         bool bBreak = false;
910         typedef vector<OUString>::const_iterator c_it;
911         for (c_it i = vecPaths.begin(); i != vecPaths.end(); i++)
912         {
913             //if the path is a link, then resolve it
914             //check if the executable exists at all
915 
916             //path can be only "file:///". Then do not append a '/'
917             //sizeof counts the terminating 0
918             OUString sFullPath;
919             if (path.getLength() == sizeof("file:///") - 1)
920                 sFullPath = sResolvedDir + (*i);
921             else
922                 sFullPath = sResolvedDir +
923                 OUString(RTL_CONSTASCII_USTRINGPARAM("/")) + (*i);
924 
925 
926             sFilePath = resolveFilePath(sFullPath);
927 
928             if (sFilePath.getLength() == 0)
929             {
930                 //The file path (to java exe) is not valid
931                 cit_path ifull = find(vecBadPaths.begin(), vecBadPaths.end(), sFullPath);
932                 if (ifull == vecBadPaths.end())
933                     vecBadPaths.push_back(sFullPath);
934                 continue;
935             }
936 
937             cit_path ifile = find(vecBadPaths.begin(), vecBadPaths.end(), sFilePath);
938             if (ifile != vecBadPaths.end())
939                 continue;
940 
941             MapIt entry =  mapJREs.find(sFilePath);
942             if (entry != mapJREs.end())
943             {
944                 JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin" SAL_DLLEXTENSION ": ")
945                    + OUSTR("JRE found again (detected before): ") + sFilePath
946                    + OUSTR(".\n"));
947 
948                 return entry->second;
949             }
950 
951             bool bProcessRun= false;
952             if (getJavaProps(sFilePath, props, & bProcessRun) == false)
953             {
954                 //The java executable could not be run or the system properties
955                 //could not be retrieved. We can assume that this java is corrupt.
956                 vecBadPaths.push_back(sFilePath);
957                 //If there was a java executable, that could be run but we did not get
958                 //the system properties, then we also assume that the whole Java installation
959                 //does not work. In a jdk there are two executables. One in jdk/bin and the other
960                 //in jdk/jre/bin. We do not search any further, because we assume that if one java
961                 //does not work then the other does not work as well. This saves us to run java
962                 //again which is quite costly.
963                 if (bProcessRun == true)
964                 {
965                     // 1.3.1 special treatment: jdk/bin/java and /jdk/jre/bin/java are links to
966                     //a script, named .java_wrapper. The script starts jdk/bin/sparc/native_threads/java
967                     //or jdk/jre/bin/sparc/native_threads/java. The script uses the name with which it was
968                     //invoked to build the path to the executable. It we start the script directy as .java_wrapper
969                     //then it tries to start a jdk/.../native_threads/.java_wrapper. Therefore the link, which
970                     //is named java, must be used to start the script.
971                     getJavaProps(sFullPath, props, & bProcessRun);
972                     // Either we found a working 1.3.1
973                     //Or the java is broken. In both cases we stop searchin under this "root" directory
974                     bBreak = true;
975                     break;
976                 }
977                 //sFilePath is no working java executable. We continue with another possible
978                 //path.
979                 else
980                 {
981                     continue;
982                 }
983             }
984             //sFilePath is a java and we could get the system properties. We proceed with this
985             //java.
986             else
987             {
988                 bBreak = true;
989                 break;
990             }
991         }
992         if (bBreak)
993             break;
994     }
995 
996     if (props.size() == 0)
997         return rtl::Reference<VendorBase>();
998 
999     //find java.vendor property
1000     typedef vector<pair<OUString, OUString> >::const_iterator c_ip;
1001     OUString sVendor(RTL_CONSTASCII_USTRINGPARAM("java.vendor"));
1002     OUString sVendorName;
1003 
1004     for (c_ip i = props.begin(); i != props.end(); i++)
1005     {
1006         if (sVendor.equals(i->first))
1007         {
1008             sVendorName = i->second;
1009             break;
1010         }
1011     }
1012 
1013     if (sVendorName.getLength() > 0)
1014     {
1015         //find the creator func for the respective vendor name
1016         for ( sal_Int32 c = 0;
1017               gVendorMap[c].sVendorName != NULL; ++c )
1018         {
1019             OUString sNameMap(gVendorMap[c].sVendorName, strlen(gVendorMap[c].sVendorName),
1020                               RTL_TEXTENCODING_ASCII_US);
1021             if (sNameMap.equals(sVendorName))
1022             {
1023                 ret = createInstance(gVendorMap[c].createFunc, props);
1024                 break;
1025             }
1026         }
1027         if ( !ret.is() )
1028         {
1029             // As of Java 8u222 the vendor name can be anything, so try the most generic one
1030             OUString genericVendorName(RTL_CONSTASCII_USTRINGPARAM("OpenJDK"));
1031             for ( sal_Int32 c = 0;
1032                   gVendorMap[c].sVendorName != NULL; ++c )
1033             {
1034                 OUString sNameMap(gVendorMap[c].sVendorName, strlen(gVendorMap[c].sVendorName),
1035                                   RTL_TEXTENCODING_ASCII_US);
1036                 if (sNameMap.equals(genericVendorName))
1037                 {
1038                     for (vector<pair<OUString, OUString> >::iterator i = props.begin(); i != props.end(); i++)
1039                     {
1040                         if (sVendor.equals(i->first))
1041                             i->second = genericVendorName;
1042                     }
1043                     ret = createInstance(gVendorMap[c].createFunc, props);
1044                     break;
1045                 }
1046             }
1047         }
1048     }
1049     if (ret.is() == false)
1050         vecBadPaths.push_back(sFilePath);
1051     else
1052     {
1053         JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin" SAL_DLLEXTENSION ": ")
1054                    + OUSTR("Found JRE: ") + sResolvedDir
1055                    + OUSTR(" \n at: ") + path + OUSTR(".\n"));
1056 
1057         mapJREs.insert(MAPJRE::value_type(sResolvedDir, ret));
1058         mapJREs.insert(MAPJRE::value_type(sFilePath, ret));
1059     }
1060 
1061     return ret;
1062 }
1063 
createInstance(createInstance_func pFunc,vector<pair<OUString,OUString>> properties)1064 Reference<VendorBase> createInstance(createInstance_func pFunc,
1065                                      vector<pair<OUString, OUString> > properties)
1066 {
1067 
1068     Reference<VendorBase> aBase = (*pFunc)();
1069     if (aBase.is())
1070     {
1071         if (aBase->initialize(properties) == false)
1072             aBase = 0;
1073     }
1074     return aBase;
1075 }
1076 
getDirFromFile(const OUString & usFilePath)1077 inline OUString getDirFromFile(const OUString& usFilePath)
1078 {
1079     sal_Int32 index= usFilePath.lastIndexOf('/');
1080     return OUString(usFilePath.getStr(), index);
1081 }
1082 
createJavaInfoFromPath(vector<rtl::Reference<VendorBase>> & vecInfos)1083 void createJavaInfoFromPath(vector<rtl::Reference<VendorBase> >& vecInfos)
1084 {
1085 // Get Java from PATH environment variable
1086     static OUString sCurDir(RTL_CONSTASCII_USTRINGPARAM("."));
1087     static OUString sParentDir(RTL_CONSTASCII_USTRINGPARAM(".."));
1088     char *szPath= getenv("PATH");
1089     if(szPath)
1090     {
1091         OUString usAllPath(szPath, strlen(szPath), osl_getThreadTextEncoding());
1092         sal_Int32 nIndex = 0;
1093         do
1094         {
1095             OUString usToken = usAllPath.getToken( 0, SAL_PATHSEPARATOR, nIndex );
1096             OUString usTokenUrl;
1097             if(File::getFileURLFromSystemPath(usToken, usTokenUrl) == File::E_None)
1098             {
1099                 if(usTokenUrl.getLength())
1100                 {
1101                     OUString usBin;
1102                     // "."
1103                     if(usTokenUrl.equals(sCurDir))
1104                     {
1105                         OUString usWorkDirUrl;
1106                         if(osl_Process_E_None == osl_getProcessWorkingDir(&usWorkDirUrl.pData))
1107                             usBin= usWorkDirUrl;
1108                     }
1109                     // ".."
1110                     else if(usTokenUrl.equals(sParentDir))
1111                     {
1112                         OUString usWorkDir;
1113                         if(osl_Process_E_None == osl_getProcessWorkingDir(&usWorkDir.pData))
1114                             usBin= getDirFromFile(usWorkDir);
1115                     }
1116                     else
1117                     {
1118                         usBin = usTokenUrl;
1119                     }
1120                     if(usBin.getLength())
1121                     {
1122                         getJREInfoFromBinPath(usBin, vecInfos);
1123                     }
1124                 }
1125             }
1126         }
1127         while ( nIndex >= 0 );
1128     }
1129 }
1130 
createJavaInfoFromJavaHome(vector<rtl::Reference<VendorBase>> & vecInfos)1131 void createJavaInfoFromJavaHome(vector<rtl::Reference<VendorBase> >& vecInfos)
1132 {
1133     // Get Java from JAVA_HOME environment
1134     char *szJavaHome= getenv("JAVA_HOME");
1135     if(szJavaHome)
1136     {
1137         OUString sHome(szJavaHome,strlen(szJavaHome),osl_getThreadTextEncoding());
1138         OUString sHomeUrl;
1139         if(File::getFileURLFromSystemPath(sHome, sHomeUrl) == File::E_None)
1140         {
1141             getJREInfoByPath(sHomeUrl, vecInfos);
1142         }
1143     }
1144 }
1145 
makeDriveLetterSame(OUString * fileURL)1146 bool makeDriveLetterSame(OUString * fileURL)
1147 {
1148     bool ret = false;
1149     DirectoryItem item;
1150     if (DirectoryItem::get(*fileURL, item) == File::E_None)
1151     {
1152         FileStatus status(FileStatusMask_FileURL);
1153         if (item.getFileStatus(status) == File::E_None)
1154         {
1155             *fileURL = status.getFileURL();
1156             ret = true;
1157         }
1158     }
1159     return ret;
1160 }
1161 
1162 #ifdef UNX
1163 #ifdef SOLARIS
1164 
createJavaInfoDirScan(vector<rtl::Reference<VendorBase>> & vecInfos)1165 void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos)
1166 {
1167     JFW_TRACE2(OUSTR("\n[Java framework] Checking \"/usr/jdk/latest\"\n"));
1168     getJREInfoByPath(OUSTR("file:////usr/jdk/latest"), vecInfos);
1169 }
1170 
1171 #else
createJavaInfoDirScan(vector<rtl::Reference<VendorBase>> & vecInfos)1172 void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos)
1173 {
1174     OUString excMessage = OUSTR("[Java framework] sunjavaplugin: "
1175                                 "Error in function createJavaInfoDirScan in util.cxx.");
1176     int cJavaNames= sizeof(g_arJavaNames) / sizeof(char*);
1177     boost::scoped_array<OUString> sarJavaNames(new OUString[cJavaNames]);
1178     OUString *arNames = sarJavaNames.get();
1179     for(int i= 0; i < cJavaNames; i++)
1180         arNames[i] = OUString(g_arJavaNames[i], strlen(g_arJavaNames[i]),
1181                               RTL_TEXTENCODING_UTF8);
1182 
1183     int cSearchPaths= sizeof(g_arSearchPaths) / sizeof(g_arSearchPaths[0]);
1184     boost::scoped_array<OUString> sarPathNames(new OUString[cSearchPaths]);
1185     OUString *arPaths = sarPathNames.get();
1186     for(int c = 0; c < cSearchPaths; c++)
1187         arPaths[c] = OUString(g_arSearchPaths[c].path, strlen(g_arSearchPaths[c].path),
1188                                RTL_TEXTENCODING_UTF8);
1189 
1190     int cCollectDirs = sizeof(g_arCollectDirs) / sizeof(char*);
1191     boost::scoped_array<OUString> sarCollectDirs(new OUString[cCollectDirs]);
1192     OUString *arCollectDirs = sarCollectDirs.get();
1193     for(int d = 0; d < cCollectDirs; d++)
1194         arCollectDirs[d] = OUString(g_arCollectDirs[d], strlen(g_arCollectDirs[d]),
1195                                RTL_TEXTENCODING_UTF8);
1196 
1197 
1198 
1199     OUString usFile(RTL_CONSTASCII_USTRINGPARAM("file:///"));
1200     for( int ii = 0; ii < cSearchPaths; ii ++)
1201     {
1202         OUString usDir1(usFile + arPaths[ii]);
1203         DirectoryItem item;
1204         if(DirectoryItem::get(usDir1, item) == File::E_None)
1205         {
1206             for(int j= 0; j < cCollectDirs; j++)
1207             {
1208                 OUString usDir2(usDir1 + arCollectDirs[j]);
1209                 // prevent that we scan the whole /usr/bin, /usr/lib, etc directories
1210                 if (g_arSearchPaths[ii].searchImmediateContents || arCollectDirs[j] != OUString())
1211                 {
1212                     //usr/java/xxx
1213                     //Examin every subdirectory
1214                     Directory aCollectionDir(usDir2);
1215 
1216                     Directory::RC openErr = aCollectionDir.open();
1217                     switch (openErr)
1218                     {
1219                     case File::E_None:
1220                         break;
1221                     case File::E_NOENT:
1222                     case File::E_NOTDIR:
1223                         continue;
1224                     case File::E_ACCES:
1225                         JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin: "
1226                                          "Could not read directory ") + usDir2 +
1227                                    OUSTR(" because of missing access rights."));
1228                         continue;
1229                     default:
1230                         JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin: "
1231                                          "Could not read directory ")
1232                                    + usDir2 + OUSTR(". Osl file error: ")
1233                                    + OUString::valueOf((sal_Int32) openErr));
1234                         continue;
1235                     }
1236 
1237                     DirectoryItem curIt;
1238                     File::RC errNext = File::E_None;
1239                     while( (errNext = aCollectionDir.getNextItem(curIt)) == File::E_None)
1240                     {
1241                         FileStatus aStatus(FileStatusMask_FileURL);
1242                         File::RC errStatus = File::E_None;
1243                         if ((errStatus = curIt.getFileStatus(aStatus)) != File::E_None)
1244                         {
1245                             JFW_TRACE2(excMessage + OUSTR("getFileStatus failed with error ")
1246                                 + OUString::valueOf((sal_Int32) errStatus));
1247                             continue;
1248                         }
1249                         JFW_TRACE2(OUSTR("[Java framework] sunjavaplugin: "
1250                                          "Checking if directory: ") + aStatus.getFileURL() +
1251                                    OUSTR(" is a Java. \n"));
1252 
1253                         getJREInfoByPath(aStatus.getFileURL(),vecInfos);
1254 #ifdef MACOSX
1255                         // On macOS a JDK bundle's home is at <bundle>/Contents/Home
1256                         // (e.g. under /Library/Java/JavaVirtualMachines/<jdk>/),
1257                         // not the bundle directory itself, so also probe there.
1258                         getJREInfoByPath(
1259                             aStatus.getFileURL() +
1260                             OUSTR("/Contents/Home"), vecInfos);
1261 #endif
1262                     }
1263 
1264                     JFW_ENSURE(errNext == File::E_None || errNext == File::E_NOENT,
1265                                 OUSTR("[Java framework] sunjavaplugin: "
1266                                       "Error while iterating over contens of ")
1267                                 + usDir2 + OUSTR(". Osl file error: ")
1268                                 + OUString::valueOf((sal_Int32) openErr));
1269                 }
1270             }
1271             for (int j= 0; j < cJavaNames; j++)
1272             {
1273                 //When we look directly into a dir like /usr/bin, /usr/lib, etc. then we only
1274                 //look for certain java directories, such as jre, jdk, etc. Whe do not want
1275                 //to examine the whole directory because of performance reasons.
1276 
1277                 //  usFile          arNames[j]
1278                 // <------>        <->
1279                 // file:///usr/lib/jvm
1280                 //         <------>
1281                 //          arPaths[ii] (usDir1)
1282                 //
1283                 OUString usDir3(usDir1 + arNames[j]);
1284 
1285                 DirectoryItem item3;
1286                 if(DirectoryItem::get(usDir3, item3) == File::E_None)
1287                 {
1288                     //remove trailing '/'
1289                     sal_Int32 islash = usDir3.lastIndexOf('/');
1290                     if (islash == usDir3.getLength() - 1
1291                         && (islash
1292                             > RTL_CONSTASCII_LENGTH("file://")))
1293                         usDir3 = usDir3.copy(0, islash);
1294                     getJREInfoByPath(usDir3,vecInfos);
1295                 }
1296             }
1297         }
1298     }
1299 }
1300 #endif // ifdef SOLARIS
1301 #endif // ifdef UNX
1302 }
1303