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