Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "boost/scoped_array.hpp"
21 : #include "rtl/ustring.hxx"
22 : #include "rtl/bootstrap.hxx"
23 : #include "osl/thread.hxx"
24 : #include "osl/file.hxx"
25 : #include "jvmfwk/framework.h"
26 : #include "vendorplugin.hxx"
27 : #include <cassert>
28 : #include <vector>
29 : #include <functional>
30 : #include <algorithm>
31 : #include "framework.hxx"
32 : #include "fwkutil.hxx"
33 : #include "elements.hxx"
34 : #include "fwkbase.hxx"
35 :
36 : namespace {
37 :
38 : static bool g_bEnabledSwitchedOn = false;
39 :
40 : static JavaVM * g_pJavaVM = NULL;
41 :
42 0 : bool areEqualJavaInfo(
43 : JavaInfo const * pInfoA,JavaInfo const * pInfoB)
44 : {
45 0 : return jfw_areEqualJavaInfo(pInfoA, pInfoB);
46 : }
47 :
48 : }
49 :
50 0 : javaFrameworkError SAL_CALL jfw_findAllJREs(JavaInfo ***pparInfo, sal_Int32 *pSize)
51 : {
52 0 : javaFrameworkError retVal = JFW_E_NONE;
53 : try
54 : {
55 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
56 0 : javaFrameworkError errcode = JFW_E_NONE;
57 0 : if (pparInfo == NULL || pSize == NULL)
58 0 : return JFW_E_INVALID_ARG;
59 :
60 0 : jfw::VendorSettings aVendorSettings;
61 : std::vector<OUString> vecVendors =
62 0 : aVendorSettings.getSupportedVendors();
63 : //Add the JavaInfos found by jfw_plugin_getAllJavaInfos to the vector
64 : //Make sure that the contents are destroyed if this
65 : //function returns with an error
66 0 : std::vector<jfw::CJavaInfo> vecInfo;
67 : //Add the JavaInfos found by jfw_plugin_getJavaInfoByPath to this vector
68 : //Make sure that the contents are destroyed if this
69 : //function returns with an error
70 0 : std::vector<jfw::CJavaInfo> vecInfoManual;
71 : typedef std::vector<jfw::CJavaInfo>::iterator it_info;
72 : //get the list of paths to jre locations which have been
73 : //added manually
74 0 : const jfw::MergedSettings settings;
75 : const std::vector<OUString>& vecJRELocations =
76 0 : settings.getJRELocations();
77 : //Use every plug-in library to get Java installations.
78 : typedef std::vector<OUString>::const_iterator ci_pl;
79 0 : for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i)
80 : {
81 0 : const OUString & vendor = *i;
82 : jfw::VersionInfo versionInfo =
83 0 : aVendorSettings.getVersionInformation(vendor);
84 :
85 : //get all installations of one vendor according to minVersion,
86 : //maxVersion and excludeVersions
87 0 : sal_Int32 cInfos = 0;
88 0 : JavaInfo** arInfos = NULL;
89 0 : std::vector<rtl::Reference<jfw_plugin::VendorBase>> infos;
90 : javaPluginError plerr = jfw_plugin_getAllJavaInfos(
91 : true,
92 : vendor,
93 : versionInfo.sMinVersion,
94 : versionInfo.sMaxVersion,
95 : versionInfo.getExcludeVersions(),
96 : versionInfo.getExcludeVersionSize(),
97 : & arInfos,
98 : & cInfos,
99 0 : infos);
100 :
101 0 : if (plerr != JFW_PLUGIN_E_NONE)
102 0 : return JFW_E_ERROR;
103 :
104 0 : for (int j = 0; j < cInfos; j++)
105 0 : vecInfo.push_back(jfw::CJavaInfo::createWrapper(arInfos[j]));
106 :
107 0 : rtl_freeMemory(arInfos);
108 :
109 : //Check if the current plugin can detect JREs at the location
110 : // of the paths added by jfw_addJRELocation
111 : //get the function from the plugin
112 : typedef std::vector<OUString>::const_iterator citLoc;
113 : //Check every manually added location
114 0 : for (citLoc ii = vecJRELocations.begin();
115 0 : ii != vecJRELocations.end(); ++ii)
116 : {
117 0 : jfw::CJavaInfo aInfo;
118 : plerr = jfw_plugin_getJavaInfoByPath(
119 0 : *ii,
120 : vendor,
121 : versionInfo.sMinVersion,
122 : versionInfo.sMaxVersion,
123 : versionInfo.getExcludeVersions(),
124 : versionInfo.getExcludeVersionSize(),
125 0 : & aInfo.pInfo);
126 0 : if (plerr == JFW_PLUGIN_E_NO_JRE)
127 0 : continue;
128 0 : if (plerr == JFW_PLUGIN_E_FAILED_VERSION)
129 0 : continue;
130 0 : else if (plerr !=JFW_PLUGIN_E_NONE)
131 0 : return JFW_E_ERROR;
132 :
133 0 : if (aInfo)
134 : {
135 : //Was this JRE already added?. Different plugins could detect
136 : //the same JRE
137 : it_info it_duplicate =
138 : std::find_if(vecInfoManual.begin(), vecInfoManual.end(),
139 0 : std::bind(areEqualJavaInfo, std::placeholders::_1, aInfo));
140 0 : if (it_duplicate == vecInfoManual.end())
141 0 : vecInfoManual.push_back(aInfo);
142 : }
143 0 : }
144 0 : }
145 : //Make sure vecInfoManual contains only JavaInfos for the vendors for which
146 : //there is a javaSelection/plugins/library entry in the javavendors.xml
147 : //To obtain the JavaInfos for the manually added JRE locations the function
148 : //jfw_getJavaInfoByPath is called which can return a JavaInfo of any vendor.
149 0 : std::vector<jfw::CJavaInfo> vecInfoManual2;
150 0 : for (it_info ivm = vecInfoManual.begin(); ivm != vecInfoManual.end(); ++ivm)
151 : {
152 0 : for (ci_pl ii = vecVendors.begin(); ii != vecVendors.end(); ++ii)
153 : {
154 0 : if ( ii->equals((*ivm)->sVendor))
155 : {
156 0 : vecInfoManual2.push_back(*ivm);
157 0 : break;
158 : }
159 : }
160 : }
161 : //Check which JavaInfo from vector vecInfoManual2 is already
162 : //contained in vecInfo. If it already exists then remove it from
163 : //vecInfoManual2
164 0 : for (it_info j = vecInfo.begin(); j != vecInfo.end(); ++j)
165 : {
166 : it_info it_duplicate =
167 : std::find_if(vecInfoManual2.begin(), vecInfoManual2.end(),
168 0 : std::bind(areEqualJavaInfo, std::placeholders::_1, *j));
169 0 : if (it_duplicate != vecInfoManual2.end())
170 0 : vecInfoManual2.erase(it_duplicate);
171 : }
172 : //create an fill the array of JavaInfo*
173 0 : sal_Int32 nSize = vecInfo.size() + vecInfoManual2.size();
174 : *pparInfo = static_cast<JavaInfo**>(rtl_allocateMemory(
175 0 : nSize * sizeof(JavaInfo*)));
176 0 : if (*pparInfo == NULL)
177 0 : return JFW_E_ERROR;
178 :
179 : typedef std::vector<jfw::CJavaInfo>::iterator it;
180 0 : int index = 0;
181 : //Add the automatically detected JREs
182 0 : for (it k = vecInfo.begin(); k != vecInfo.end(); ++k)
183 0 : (*pparInfo)[index++] = k->detach();
184 : //Add the manually detected JREs
185 0 : for (it l = vecInfoManual2.begin(); l != vecInfoManual2.end(); ++l)
186 0 : (*pparInfo)[index++] = l->detach();
187 :
188 0 : *pSize = nSize;
189 0 : return errcode;
190 : }
191 0 : catch (const jfw::FrameworkException& e)
192 : {
193 0 : retVal = e.errorCode;
194 0 : fprintf(stderr, "%s\n", e.message.getStr());
195 : OSL_FAIL(e.message.getStr());
196 : }
197 0 : return retVal;
198 : }
199 :
200 11 : javaFrameworkError SAL_CALL jfw_startVM(
201 : JavaInfo const * pInfo, JavaVMOption * arOptions, sal_Int32 cOptions,
202 : JavaVM ** ppVM, JNIEnv ** ppEnv)
203 : {
204 11 : javaFrameworkError errcode = JFW_E_NONE;
205 11 : if (cOptions > 0 && arOptions == NULL)
206 0 : return JFW_E_INVALID_ARG;
207 :
208 : try
209 : {
210 11 : osl::MutexGuard guard(jfw::FwkMutex::get());
211 :
212 : //We keep this pointer so we can determine if a VM has already
213 : //been created.
214 11 : if (g_pJavaVM != NULL)
215 0 : return JFW_E_RUNNING_JVM;
216 :
217 11 : if (ppVM == NULL)
218 0 : return JFW_E_INVALID_ARG;
219 :
220 18 : std::vector<OString> vmParams;
221 18 : OString sUserClassPath;
222 18 : jfw::CJavaInfo aInfo;
223 11 : if (pInfo == NULL)
224 : {
225 7 : jfw::JFW_MODE mode = jfw::getMode();
226 7 : if (mode == jfw::JFW_MODE_APPLICATION)
227 : {
228 4 : const jfw::MergedSettings settings;
229 4 : if (!settings.getEnabled())
230 0 : return JFW_E_JAVA_DISABLED;
231 4 : aInfo.attach(settings.createJavaInfo());
232 : //check if a Java has ever been selected
233 4 : if (aInfo == NULL)
234 4 : return JFW_E_NO_SELECT;
235 :
236 : #ifdef WNT
237 : //Because on Windows there is no system setting that we can use to determine
238 : //if Assistive Technology Tool support is needed, we ship a .reg file that the
239 : //user can use to create a registry setting. When the user forgets to set
240 : //the key before he starts the office then a JRE may be selected without access bridge.
241 : //When he later sets the key then we select a JRE with accessibility support but
242 : //only if the user has not manually changed the selected JRE in the options dialog.
243 : if (jfw::isAccessibilitySupportDesired())
244 : {
245 : // If no JRE has been selected then we do not select one. This function shall then
246 : //return JFW_E_NO_SELECT
247 : if (aInfo != NULL &&
248 : (aInfo->nFeatures & JFW_FEATURE_ACCESSBRIDGE) == 0)
249 : {
250 : //has the user manually selected a JRE?
251 : if (settings.getJavaInfoAttrAutoSelect() == true)
252 : {
253 : // if not then the automatism has previously selected a JRE
254 : //without accessibility support. We return JFW_E_NO_SELECT
255 : //to cause that we search for another JRE. The search code will
256 : //then prefer a JRE with accessibility support.
257 : return JFW_E_NO_SELECT;
258 : }
259 : }
260 : }
261 : #endif
262 : //check if the javavendors.xml has changed after a Java was selected
263 0 : OString sVendorUpdate = jfw::getElementUpdated();
264 :
265 0 : if (sVendorUpdate != settings.getJavaInfoAttrVendorUpdate())
266 0 : return JFW_E_INVALID_SETTINGS;
267 :
268 : //check if JAVA is disabled
269 : //If Java is enabled, but it was disabled when this process was started
270 : // then no preparational work, such as setting the LD_LIBRARY_PATH, was
271 : //done. Therefore if a JRE needs it, it must not be started.
272 0 : if (g_bEnabledSwitchedOn &&
273 0 : (aInfo->nRequirements & JFW_REQUIRE_NEEDRESTART))
274 0 : return JFW_E_NEED_RESTART;
275 :
276 : //Check if the selected Java was set in this process. If so it
277 : //must not have the requirments flag JFW_REQUIRE_NEEDRESTART
278 0 : if ((aInfo->nRequirements & JFW_REQUIRE_NEEDRESTART)
279 0 : && jfw::wasJavaSelectedInSameProcess())
280 0 : return JFW_E_NEED_RESTART;
281 :
282 0 : vmParams = settings.getVmParametersUtf8();
283 0 : sUserClassPath = jfw::makeClassPathOption(settings.getUserClassPath());
284 : } // end mode FWK_MODE_OFFICE
285 3 : else if (mode == jfw::JFW_MODE_DIRECT)
286 : {
287 3 : errcode = jfw_getSelectedJRE(&aInfo.pInfo);
288 3 : if (errcode != JFW_E_NONE)
289 0 : return errcode;
290 : //In direct mode the options are specified by bootstrap variables
291 : //of the form UNO_JAVA_JFW_PARAMETER_1 .. UNO_JAVA_JFW_PARAMETER_n
292 3 : vmParams = jfw::BootParams::getVMParameters();
293 6 : sUserClassPath =
294 9 : "-Djava.class.path=" + jfw::BootParams::getClasspath();
295 : }
296 : else
297 : OSL_ASSERT(false);
298 3 : pInfo = aInfo.pInfo;
299 : }
300 : assert(pInfo != NULL);
301 :
302 : //get the function jfw_plugin_startJavaVirtualMachine
303 14 : jfw::VendorSettings aVendorSettings;
304 :
305 : // create JavaVMOptions array that is passed to the plugin
306 : // it contains the classpath and all options set in the
307 : //options dialog
308 : boost::scoped_array<JavaVMOption> sarJOptions(
309 14 : new JavaVMOption[cOptions + 2 + vmParams.size()]);
310 7 : JavaVMOption * arOpt = sarJOptions.get();
311 7 : if (! arOpt)
312 0 : return JFW_E_ERROR;
313 :
314 : //The first argument is the classpath
315 7 : arOpt[0].optionString= const_cast<char*>(sUserClassPath.getStr());
316 7 : arOpt[0].extraInfo = NULL;
317 : // Set a flag that this JVM has been created via the JNI Invocation API
318 : // (used, for example, by UNO remote bridges to share a common thread pool
319 : // factory among Java and native bridge implementations):
320 7 : arOpt[1].optionString = const_cast<char *>("-Dorg.openoffice.native=");
321 7 : arOpt[1].extraInfo = 0;
322 :
323 : //add the options set by options dialog
324 7 : int index = 2;
325 : typedef std::vector<OString>::const_iterator cit;
326 7 : for (cit i = vmParams.begin(); i != vmParams.end(); ++i)
327 : {
328 0 : arOpt[index].optionString = const_cast<sal_Char*>(i->getStr());
329 0 : arOpt[index].extraInfo = 0;
330 0 : index ++;
331 : }
332 : //add all options of the arOptions argument
333 19 : for (int ii = 0; ii < cOptions; ii++)
334 : {
335 12 : arOpt[index].optionString = arOptions[ii].optionString;
336 12 : arOpt[index].extraInfo = arOptions[ii].extraInfo;
337 12 : index++;
338 : }
339 :
340 : //start Java
341 7 : JavaVM *pVm = NULL;
342 : SAL_INFO("jfw", "Starting Java");
343 7 : javaPluginError plerr = jfw_plugin_startJavaVirtualMachine(pInfo, arOpt, index, & pVm, ppEnv);
344 7 : if (plerr == JFW_PLUGIN_E_VM_CREATION_FAILED)
345 : {
346 0 : errcode = JFW_E_VM_CREATION_FAILED;
347 : }
348 7 : else if (plerr != JFW_PLUGIN_E_NONE )
349 : {
350 0 : errcode = JFW_E_ERROR;
351 : }
352 : else
353 : {
354 7 : g_pJavaVM = pVm;
355 7 : *ppVM = pVm;
356 : }
357 7 : OSL_ASSERT(plerr != JFW_PLUGIN_E_WRONG_VENDOR);
358 : }
359 0 : catch (const jfw::FrameworkException& e)
360 : {
361 0 : errcode = e.errorCode;
362 0 : fprintf(stderr, "%s\n", e.message.getStr());
363 : OSL_FAIL(e.message.getStr());
364 : }
365 :
366 7 : return errcode;
367 : }
368 :
369 : /** We do not use here jfw_findAllJREs and then check if a JavaInfo
370 : meets the requirements, because that means using all plug-ins, which
371 : may take quite a while. The implementation first inspects JAVA_HOME and
372 : PATH environment variables. If no suitable JavaInfo is found there, it
373 : inspects all JavaInfos found by the jfw_plugin_get* functions.
374 : */
375 4 : javaFrameworkError SAL_CALL jfw_findAndSelectJRE(JavaInfo **pInfo)
376 : {
377 4 : javaFrameworkError errcode = JFW_E_NONE;
378 : try
379 : {
380 4 : osl::MutexGuard guard(jfw::FwkMutex::get());
381 4 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
382 0 : return JFW_E_DIRECT_MODE;
383 4 : sal_uInt64 nFeatureFlags = 0;
384 8 : jfw::CJavaInfo aCurrentInfo;
385 : //Determine if accessibility support is needed
386 4 : bool bSupportAccessibility = jfw::isAccessibilitySupportDesired();
387 : nFeatureFlags = bSupportAccessibility ?
388 4 : JFW_FEATURE_ACCESSBRIDGE : 0L;
389 :
390 :
391 : // 'bInfoFound' indicates whether a Java installation has been found
392 : // that supports all desired features
393 4 : bool bInfoFound = false;
394 :
395 : // get list of vendors for Java installations
396 8 : jfw::VendorSettings aVendorSettings;
397 : std::vector<OUString> vecVendors =
398 8 : aVendorSettings.getSupportedVendors();
399 :
400 : // save vendors and respective version requirements pair-wise in a vector
401 8 : std::vector<std::pair<OUString, jfw::VersionInfo>> versionInfos;
402 : typedef std::vector<OUString>::const_iterator ciVendor;
403 32 : for (ciVendor i = vecVendors.begin(); i != vecVendors.end(); ++i)
404 : {
405 28 : const OUString & vendor = *i;
406 : jfw::VersionInfo versionInfo =
407 28 : aVendorSettings.getVersionInformation(vendor);
408 :
409 : versionInfos.push_back(
410 28 : std::pair<OUString, jfw::VersionInfo>(vendor, versionInfo));
411 28 : }
412 :
413 8 : std::vector<rtl::Reference<jfw_plugin::VendorBase>> infos;
414 :
415 : // first inspect Java installation that the JAVA_HOME
416 : // environment variable points to (if it is set)
417 4 : JavaInfo* pHomeInfo = NULL;
418 4 : if (jfw_plugin_getJavaInfoFromJavaHome(versionInfos, &pHomeInfo, infos)
419 : == JFW_PLUGIN_E_NONE)
420 : {
421 4 : aCurrentInfo = pHomeInfo;
422 :
423 : // compare features
424 : // if the user does not require any features (nFeatureFlags = 0)
425 : // or the Java installation provides all features, then this installation is used
426 4 : if ((pHomeInfo->nFeatures & nFeatureFlags) == nFeatureFlags)
427 : {
428 4 : bInfoFound = true;
429 : }
430 4 : jfw_freeJavaInfo(pHomeInfo);
431 : }
432 :
433 : // if no Java installation providing all features was detected by using JAVA_HOME,
434 : // query PATH for Java installations
435 4 : if (!bInfoFound)
436 : {
437 0 : std::vector<JavaInfo*> vecJavaInfosFromPath;
438 0 : if (jfw_plugin_getJavaInfosFromPath(
439 0 : versionInfos, vecJavaInfosFromPath, infos)
440 : == JFW_PLUGIN_E_NONE)
441 : {
442 0 : std::vector<JavaInfo*>::const_iterator it = vecJavaInfosFromPath.begin();
443 0 : while(it != vecJavaInfosFromPath.end() && !bInfoFound)
444 : {
445 0 : JavaInfo* pJInfo = *it;
446 0 : if (pJInfo != NULL)
447 : {
448 : // if the current Java installation implements all required features: use it
449 0 : if ((pJInfo->nFeatures & nFeatureFlags) == nFeatureFlags)
450 : {
451 0 : aCurrentInfo = pJInfo;
452 0 : bInfoFound = true;
453 : }
454 0 : else if (static_cast<JavaInfo*>(aCurrentInfo) == NULL)
455 : {
456 : // current Java installation does not provide all features
457 : // but no Java installation has been detected before
458 : // -> remember the current one until one is found
459 : // that provides all features
460 0 : aCurrentInfo = pJInfo;
461 : }
462 :
463 0 : jfw_freeJavaInfo(pJInfo);
464 : }
465 0 : ++it;
466 : }
467 0 : }
468 : }
469 :
470 :
471 : // if no suitable Java installation has been found yet:
472 : // first iterate over all vendors to find a suitable Java installation,
473 : // then try paths that have been added manually
474 4 : if (!bInfoFound)
475 : {
476 : //Use every vendor to get Java installations. At the first usable
477 : //Java the loop will break
478 : typedef std::vector<OUString>::const_iterator ci_pl;
479 0 : for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i)
480 : {
481 0 : const OUString & vendor = *i;
482 : jfw::VersionInfo versionInfo =
483 0 : aVendorSettings.getVersionInformation(vendor);
484 :
485 : //get all installations of one vendor according to minVersion,
486 : //maxVersion and excludeVersions
487 0 : sal_Int32 cInfos = 0;
488 0 : JavaInfo** arInfos = NULL;
489 : javaPluginError plerr = jfw_plugin_getAllJavaInfos(
490 : false,
491 : vendor,
492 : versionInfo.sMinVersion,
493 : versionInfo.sMaxVersion,
494 : versionInfo.getExcludeVersions(),
495 : versionInfo.getExcludeVersionSize(),
496 : & arInfos,
497 : & cInfos,
498 0 : infos);
499 :
500 0 : if (plerr != JFW_PLUGIN_E_NONE)
501 0 : continue;
502 : //iterate over all installations to find the best which has
503 : //all features
504 0 : if (cInfos == 0)
505 : {
506 0 : rtl_freeMemory(arInfos);
507 0 : continue;
508 : }
509 0 : for (int ii = 0; ii < cInfos; ii++)
510 : {
511 0 : JavaInfo* pJInfo = arInfos[ii];
512 :
513 : //We remember the first installation in aCurrentInfo
514 : // if no JavaInfo has been found before
515 0 : if (aCurrentInfo.getLocation().isEmpty())
516 0 : aCurrentInfo = pJInfo;
517 : // compare features
518 : // If the user does not require any features (nFeatureFlags = 0)
519 : // then the first installation is used
520 0 : if ((pJInfo->nFeatures & nFeatureFlags) == nFeatureFlags)
521 : {
522 : //the just found Java implements all required features
523 : //currently there is only accessibility!!!
524 0 : aCurrentInfo = pJInfo;
525 0 : bInfoFound = true;
526 0 : break;
527 : }
528 : }
529 : //The array returned by jfw_plugin_getAllJavaInfos must be freed as well as
530 : //its contents
531 0 : for (int j = 0; j < cInfos; j++)
532 0 : jfw_freeJavaInfo(arInfos[j]);
533 0 : rtl_freeMemory(arInfos);
534 :
535 0 : if (bInfoFound)
536 0 : break;
537 : //All Java installations found by the current plug-in lib
538 : //do not provide the required features. Try the next plug-in
539 0 : }
540 0 : if (static_cast<JavaInfo*>(aCurrentInfo) == NULL)
541 : {//The plug-ins did not find a suitable Java. Now try the paths which have been
542 : //added manually.
543 : //get the list of paths to jre locations which have been added manually
544 0 : const jfw::MergedSettings settings;
545 : //node.loadFromSettings();
546 : const std::vector<OUString> & vecJRELocations =
547 0 : settings.getJRELocations();
548 : //use every plug-in to determine the JavaInfo objects
549 0 : for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i)
550 : {
551 0 : const OUString & vendor = *i;
552 : jfw::VersionInfo versionInfo =
553 0 : aVendorSettings.getVersionInformation(vendor);
554 :
555 : typedef std::vector<OUString>::const_iterator citLoc;
556 0 : for (citLoc it = vecJRELocations.begin();
557 0 : it != vecJRELocations.end(); ++it)
558 : {
559 0 : jfw::CJavaInfo aInfo;
560 : javaPluginError err = jfw_plugin_getJavaInfoByPath(
561 0 : *it,
562 : vendor,
563 : versionInfo.sMinVersion,
564 : versionInfo.sMaxVersion,
565 : versionInfo.getExcludeVersions(),
566 : versionInfo.getExcludeVersionSize(),
567 0 : & aInfo.pInfo);
568 0 : if (err == JFW_PLUGIN_E_NO_JRE)
569 0 : continue;
570 0 : if (err == JFW_PLUGIN_E_FAILED_VERSION)
571 0 : continue;
572 0 : else if (err !=JFW_PLUGIN_E_NONE)
573 0 : return JFW_E_ERROR;
574 :
575 0 : if (aInfo)
576 : {
577 : //We remember the very first installation in aCurrentInfo
578 0 : if (aCurrentInfo.getLocation().isEmpty())
579 0 : aCurrentInfo = aInfo;
580 : // compare features
581 : // If the user does not require any features (nFeatureFlags = 0)
582 : // then the first installation is used
583 0 : if ((aInfo.getFeatures() & nFeatureFlags) == nFeatureFlags)
584 : {
585 : //the just found Java implements all required features
586 : //currently there is only accessibility!!!
587 0 : aCurrentInfo = aInfo;
588 0 : bInfoFound = true;
589 0 : break;
590 : }
591 : }
592 0 : }//end iterate over paths
593 0 : if (bInfoFound)
594 0 : break;
595 0 : }// end iterate plug-ins
596 : }
597 : }
598 4 : if (static_cast<JavaInfo*>(aCurrentInfo))
599 : {
600 4 : jfw::NodeJava javaNode(jfw::NodeJava::USER);
601 4 : javaNode.setJavaInfo(aCurrentInfo,true);
602 4 : javaNode.write();
603 : //remember that this JRE was selected in this process
604 4 : jfw::setJavaSelected();
605 :
606 4 : if (pInfo !=NULL)
607 : {
608 : //copy to out param
609 4 : *pInfo = aCurrentInfo.cloneJavaInfo();
610 4 : }
611 : }
612 : else
613 : {
614 0 : errcode = JFW_E_NO_JAVA_FOUND;
615 4 : }
616 : }
617 0 : catch (const jfw::FrameworkException& e)
618 : {
619 0 : errcode = e.errorCode;
620 0 : fprintf(stderr, "%s\n", e.message.getStr());
621 : OSL_FAIL(e.message.getStr());
622 : }
623 :
624 4 : return errcode;
625 : }
626 :
627 0 : sal_Bool SAL_CALL jfw_areEqualJavaInfo(
628 : JavaInfo const * pInfoA,JavaInfo const * pInfoB)
629 : {
630 0 : if (pInfoA == pInfoB)
631 0 : return sal_True;
632 0 : if (pInfoA == NULL || pInfoB == NULL)
633 0 : return sal_False;
634 0 : OUString sVendor(pInfoA->sVendor);
635 0 : OUString sLocation(pInfoA->sLocation);
636 0 : OUString sVersion(pInfoA->sVersion);
637 0 : rtl::ByteSequence sData(pInfoA->arVendorData);
638 0 : if (sVendor.equals(pInfoB->sVendor)
639 0 : && sLocation.equals(pInfoB->sLocation)
640 0 : && sVersion.equals(pInfoB->sVersion)
641 0 : && pInfoA->nFeatures == pInfoB->nFeatures
642 0 : && pInfoA->nRequirements == pInfoB->nRequirements
643 0 : && sData == pInfoB->arVendorData)
644 : {
645 0 : return sal_True;
646 : }
647 0 : return sal_False;
648 : }
649 :
650 :
651 321 : void SAL_CALL jfw_freeJavaInfo(JavaInfo *pInfo)
652 : {
653 321 : if (pInfo == NULL)
654 487 : return;
655 155 : rtl_uString_release(pInfo->sVendor);
656 155 : rtl_uString_release(pInfo->sLocation);
657 155 : rtl_uString_release(pInfo->sVersion);
658 155 : rtl_byte_sequence_release(pInfo->arVendorData);
659 155 : rtl_freeMemory(pInfo);
660 : }
661 :
662 73 : javaFrameworkError SAL_CALL jfw_getSelectedJRE(JavaInfo **ppInfo)
663 : {
664 73 : javaFrameworkError errcode = JFW_E_NONE;
665 : try
666 : {
667 73 : osl::MutexGuard guard(jfw::FwkMutex::get());
668 73 : if (ppInfo == NULL)
669 0 : return JFW_E_INVALID_ARG;
670 :
671 73 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
672 : {
673 73 : OUString sJRE = jfw::BootParams::getJREHome();
674 :
675 146 : jfw::CJavaInfo aInfo;
676 73 : if ((errcode = jfw_getJavaInfoByPath(sJRE.pData, & aInfo.pInfo))
677 : != JFW_E_NONE)
678 : throw jfw::FrameworkException(
679 : JFW_E_CONFIGURATION,
680 : OString(
681 : "[Java framework] The JRE specified by the bootstrap "
682 : "variable UNO_JAVA_JFW_JREHOME or UNO_JAVA_JFW_ENV_JREHOME "
683 : " could not be recognized. Check the values and make sure that you "
684 0 : "use a plug-in library that can recognize that JRE."));
685 :
686 73 : *ppInfo = aInfo.detach();
687 146 : return JFW_E_NONE;
688 : }
689 :
690 0 : const jfw::MergedSettings settings;
691 0 : jfw::CJavaInfo aInfo;
692 0 : aInfo.attach(settings.createJavaInfo());
693 0 : if (! aInfo)
694 : {
695 0 : *ppInfo = NULL;
696 0 : return JFW_E_NONE;
697 : }
698 : //If the javavendors.xml has changed, then the current selected
699 : //Java is not valid anymore
700 : // /java/javaInfo/@vendorUpdate != javaSelection/updated (javavendors.xml)
701 0 : OString sUpdated = jfw::getElementUpdated();
702 :
703 0 : if (!sUpdated.equals(settings.getJavaInfoAttrVendorUpdate()))
704 0 : return JFW_E_INVALID_SETTINGS;
705 0 : *ppInfo = aInfo.detach();
706 : }
707 0 : catch (const jfw::FrameworkException& e)
708 : {
709 0 : errcode = e.errorCode;
710 0 : fprintf(stderr, "%s\n", e.message.getStr());
711 : OSL_FAIL(e.message.getStr());
712 : }
713 0 : return errcode;
714 : }
715 :
716 0 : javaFrameworkError SAL_CALL jfw_isVMRunning(sal_Bool *bRunning)
717 : {
718 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
719 0 : if (bRunning == NULL)
720 0 : return JFW_E_INVALID_ARG;
721 0 : if (g_pJavaVM == NULL)
722 0 : *bRunning = sal_False;
723 : else
724 0 : *bRunning = sal_True;
725 0 : return JFW_E_NONE;
726 : }
727 :
728 73 : javaFrameworkError SAL_CALL jfw_getJavaInfoByPath(
729 : rtl_uString *pPath, JavaInfo **ppInfo)
730 : {
731 73 : javaFrameworkError errcode = JFW_E_NONE;
732 : try
733 : {
734 73 : osl::MutexGuard guard(jfw::FwkMutex::get());
735 73 : if (pPath == NULL || ppInfo == NULL)
736 0 : return JFW_E_INVALID_ARG;
737 :
738 146 : OUString ouPath(pPath);
739 :
740 146 : jfw::VendorSettings aVendorSettings;
741 : std::vector<OUString> vecVendors =
742 146 : aVendorSettings.getSupportedVendors();
743 :
744 : //Use every plug-in library to determine if the path represents a
745 : //JRE. If a plugin recognized it then the loop will break
746 : typedef std::vector<OUString>::const_iterator ci_pl;
747 146 : for (ci_pl i = vecVendors.begin(); i != vecVendors.end(); ++i)
748 : {
749 146 : const OUString & vendor = *i;
750 : jfw::VersionInfo versionInfo =
751 146 : aVendorSettings.getVersionInformation(vendor);
752 :
753 : //ask the plugin if this is a JRE.
754 : //If so check if it meets the version requirements.
755 : //Only if it does return a JavaInfo
756 146 : JavaInfo* pInfo = NULL;
757 : javaPluginError plerr = jfw_plugin_getJavaInfoByPath(
758 : ouPath,
759 : vendor,
760 : versionInfo.sMinVersion,
761 : versionInfo.sMaxVersion,
762 : versionInfo.getExcludeVersions(),
763 : versionInfo.getExcludeVersionSize(),
764 146 : & pInfo);
765 :
766 146 : if (plerr == JFW_PLUGIN_E_NONE)
767 : {
768 73 : *ppInfo = pInfo;
769 73 : break;
770 : }
771 73 : else if(plerr == JFW_PLUGIN_E_FAILED_VERSION)
772 : {//found JRE but it has the wrong version
773 0 : *ppInfo = NULL;
774 0 : errcode = JFW_E_FAILED_VERSION;
775 0 : break;
776 : }
777 73 : else if (plerr == JFW_PLUGIN_E_NO_JRE)
778 : {// plugin does not recognize this path as belonging to JRE
779 73 : continue;
780 : }
781 : OSL_ASSERT(false);
782 0 : }
783 73 : if (*ppInfo == NULL && errcode != JFW_E_FAILED_VERSION)
784 73 : errcode = JFW_E_NOT_RECOGNIZED;
785 : }
786 0 : catch (const jfw::FrameworkException& e)
787 : {
788 0 : errcode = e.errorCode;
789 0 : fprintf(stderr, "%s\n", e.message.getStr());
790 : OSL_FAIL(e.message.getStr());
791 : }
792 :
793 73 : return errcode;
794 : }
795 :
796 :
797 0 : javaFrameworkError SAL_CALL jfw_setSelectedJRE(JavaInfo const *pInfo)
798 : {
799 0 : javaFrameworkError errcode = JFW_E_NONE;
800 : try
801 : {
802 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
803 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
804 0 : return JFW_E_DIRECT_MODE;
805 : //check if pInfo is the selected JRE
806 0 : JavaInfo *currentInfo = NULL;
807 0 : errcode = jfw_getSelectedJRE( & currentInfo);
808 0 : if (errcode != JFW_E_NONE && errcode != JFW_E_INVALID_SETTINGS)
809 0 : return errcode;
810 :
811 0 : if (jfw_areEqualJavaInfo(currentInfo, pInfo) == sal_False)
812 : {
813 0 : jfw::NodeJava node(jfw::NodeJava::USER);
814 0 : node.setJavaInfo(pInfo, false);
815 0 : node.write();
816 : //remember that the JRE was selected in this process
817 0 : jfw::setJavaSelected();
818 : }
819 :
820 0 : jfw_freeJavaInfo(currentInfo);
821 : }
822 0 : catch (const jfw::FrameworkException& e)
823 : {
824 0 : errcode = e.errorCode;
825 0 : fprintf(stderr, "%s\n", e.message.getStr());
826 : OSL_FAIL(e.message.getStr());
827 : }
828 0 : return errcode;
829 : }
830 0 : javaFrameworkError SAL_CALL jfw_setEnabled(sal_Bool bEnabled)
831 : {
832 0 : javaFrameworkError errcode = JFW_E_NONE;
833 : try
834 : {
835 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
836 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
837 0 : return JFW_E_DIRECT_MODE;
838 :
839 0 : if (!g_bEnabledSwitchedOn && bEnabled == sal_True)
840 : {
841 : //When the process started then Enabled was false.
842 : //This is first time enabled is set to true.
843 : //That means, no preparational work has been done, such as setting the
844 : //LD_LIBRARY_PATH, etc.
845 :
846 : //check if Enabled is false;
847 0 : const jfw::MergedSettings settings;
848 0 : if (!settings.getEnabled())
849 0 : g_bEnabledSwitchedOn = true;
850 : }
851 0 : jfw::NodeJava node(jfw::NodeJava::USER);
852 0 : node.setEnabled(bEnabled);
853 0 : node.write();
854 : }
855 0 : catch (const jfw::FrameworkException& e)
856 : {
857 0 : errcode = e.errorCode;
858 0 : fprintf(stderr, "%s\n", e.message.getStr());
859 : OSL_FAIL(e.message.getStr());
860 : }
861 0 : return errcode;
862 : }
863 :
864 137 : javaFrameworkError SAL_CALL jfw_getEnabled(sal_Bool *pbEnabled)
865 : {
866 137 : javaFrameworkError errcode = JFW_E_NONE;
867 : try
868 : {
869 137 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
870 226 : return JFW_E_DIRECT_MODE;
871 24 : osl::MutexGuard guard(jfw::FwkMutex::get());
872 24 : if (pbEnabled == NULL)
873 0 : return JFW_E_INVALID_ARG;
874 48 : jfw::MergedSettings settings;
875 48 : *pbEnabled = settings.getEnabled();
876 : }
877 0 : catch (const jfw::FrameworkException& e)
878 : {
879 0 : errcode = e.errorCode;
880 0 : fprintf(stderr, "%s\n", e.message.getStr());
881 : OSL_FAIL(e.message.getStr());
882 : }
883 24 : return errcode;
884 : }
885 :
886 :
887 0 : javaFrameworkError SAL_CALL jfw_setVMParameters(
888 : rtl_uString * * arOptions, sal_Int32 nLen)
889 : {
890 0 : javaFrameworkError errcode = JFW_E_NONE;
891 : try
892 : {
893 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
894 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
895 0 : return JFW_E_DIRECT_MODE;
896 0 : jfw::NodeJava node(jfw::NodeJava::USER);
897 0 : if (arOptions == NULL && nLen != 0)
898 0 : return JFW_E_INVALID_ARG;
899 0 : node.setVmParameters(arOptions, nLen);
900 0 : node.write();
901 : }
902 0 : catch (const jfw::FrameworkException& e)
903 : {
904 0 : errcode = e.errorCode;
905 0 : fprintf(stderr, "%s\n", e.message.getStr());
906 : OSL_FAIL(e.message.getStr());
907 : }
908 :
909 0 : return errcode;
910 : }
911 :
912 0 : javaFrameworkError SAL_CALL jfw_getVMParameters(
913 : rtl_uString *** parOptions, sal_Int32 * pLen)
914 : {
915 0 : javaFrameworkError errcode = JFW_E_NONE;
916 : try
917 : {
918 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
919 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
920 0 : return JFW_E_DIRECT_MODE;
921 :
922 0 : if (parOptions == NULL || pLen == NULL)
923 0 : return JFW_E_INVALID_ARG;
924 0 : const jfw::MergedSettings settings;
925 0 : settings.getVmParametersArray(parOptions, pLen);
926 : }
927 0 : catch (const jfw::FrameworkException& e)
928 : {
929 0 : errcode = e.errorCode;
930 0 : fprintf(stderr, "%s\n", e.message.getStr());
931 : OSL_FAIL(e.message.getStr());
932 : }
933 0 : return errcode;
934 : }
935 :
936 0 : javaFrameworkError SAL_CALL jfw_setUserClassPath(rtl_uString * pCp)
937 : {
938 0 : javaFrameworkError errcode = JFW_E_NONE;
939 : try
940 : {
941 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
942 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
943 0 : return JFW_E_DIRECT_MODE;
944 0 : jfw::NodeJava node(jfw::NodeJava::USER);
945 0 : if (pCp == NULL)
946 0 : return JFW_E_INVALID_ARG;
947 0 : node.setUserClassPath(pCp);
948 0 : node.write();
949 : }
950 0 : catch (const jfw::FrameworkException& e)
951 : {
952 0 : errcode = e.errorCode;
953 0 : fprintf(stderr, "%s\n", e.message.getStr());
954 : OSL_FAIL(e.message.getStr());
955 : }
956 0 : return errcode;
957 : }
958 :
959 0 : javaFrameworkError SAL_CALL jfw_getUserClassPath(rtl_uString ** ppCP)
960 : {
961 0 : javaFrameworkError errcode = JFW_E_NONE;
962 : try
963 : {
964 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
965 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
966 0 : return JFW_E_DIRECT_MODE;
967 0 : if (ppCP == NULL)
968 0 : return JFW_E_INVALID_ARG;
969 0 : const jfw::MergedSettings settings;
970 0 : *ppCP = settings.getUserClassPath().pData;
971 0 : rtl_uString_acquire(*ppCP);
972 : }
973 0 : catch (const jfw::FrameworkException& e)
974 : {
975 0 : errcode = e.errorCode;
976 0 : fprintf(stderr, "%s\n", e.message.getStr());
977 : OSL_FAIL(e.message.getStr());
978 : }
979 0 : return errcode;
980 : }
981 :
982 0 : javaFrameworkError SAL_CALL jfw_addJRELocation(rtl_uString * sLocation)
983 : {
984 0 : javaFrameworkError errcode = JFW_E_NONE;
985 : try
986 : {
987 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
988 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
989 0 : return JFW_E_DIRECT_MODE;
990 0 : jfw::NodeJava node(jfw::NodeJava::USER);
991 0 : if (sLocation == NULL)
992 0 : return JFW_E_INVALID_ARG;
993 0 : node.load();
994 0 : node.addJRELocation(sLocation);
995 0 : node.write();
996 : }
997 0 : catch (const jfw::FrameworkException& e)
998 : {
999 0 : errcode = e.errorCode;
1000 0 : fprintf(stderr, "%s\n", e.message.getStr());
1001 : OSL_FAIL(e.message.getStr());
1002 : }
1003 :
1004 0 : return errcode;
1005 :
1006 : }
1007 :
1008 0 : javaFrameworkError SAL_CALL jfw_getJRELocations(
1009 : rtl_uString *** parLocations, sal_Int32 *pLen)
1010 : {
1011 0 : javaFrameworkError errcode = JFW_E_NONE;
1012 : try
1013 : {
1014 0 : osl::MutexGuard guard(jfw::FwkMutex::get());
1015 0 : if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
1016 0 : return JFW_E_DIRECT_MODE;
1017 :
1018 0 : if (parLocations == NULL || pLen == NULL)
1019 0 : return JFW_E_INVALID_ARG;
1020 0 : const jfw::MergedSettings settings;
1021 0 : settings.getJRELocations(parLocations, pLen);
1022 : }
1023 0 : catch (const jfw::FrameworkException& e)
1024 : {
1025 0 : errcode = e.errorCode;
1026 0 : fprintf(stderr, "%s\n", e.message.getStr());
1027 : OSL_FAIL(e.message.getStr());
1028 : }
1029 :
1030 0 : return errcode;
1031 : }
1032 :
1033 :
1034 70 : javaFrameworkError jfw_existJRE(const JavaInfo *pInfo, sal_Bool *exist)
1035 : {
1036 : //get the function jfw_plugin_existJRE
1037 70 : jfw::VendorSettings aVendorSettings;
1038 140 : jfw::CJavaInfo aInfo;
1039 70 : aInfo = pInfo; //makes a copy of pInfo
1040 70 : javaPluginError plerr = jfw_plugin_existJRE(pInfo, exist);
1041 :
1042 70 : javaFrameworkError ret = JFW_E_NONE;
1043 70 : switch (plerr)
1044 : {
1045 : case JFW_PLUGIN_E_NONE:
1046 70 : ret = JFW_E_NONE;
1047 70 : break;
1048 : case JFW_PLUGIN_E_INVALID_ARG:
1049 0 : ret = JFW_E_INVALID_ARG;
1050 0 : break;
1051 : case JFW_PLUGIN_E_ERROR:
1052 0 : ret = JFW_E_ERROR;
1053 0 : break;
1054 : default:
1055 0 : ret = JFW_E_ERROR;
1056 : }
1057 140 : return ret;
1058 : }
1059 :
1060 0 : void SAL_CALL jfw_lock()
1061 : {
1062 0 : jfw::FwkMutex::get().acquire();
1063 0 : }
1064 :
1065 0 : void SAL_CALL jfw_unlock()
1066 : {
1067 0 : jfw::FwkMutex::get().release();
1068 0 : }
1069 :
1070 :
1071 : namespace jfw
1072 : {
1073 158 : CJavaInfo::CJavaInfo(): pInfo(0)
1074 : {
1075 158 : }
1076 :
1077 0 : CJavaInfo::CJavaInfo(const CJavaInfo & info)
1078 : {
1079 0 : pInfo = copyJavaInfo(info.pInfo);
1080 0 : }
1081 :
1082 0 : CJavaInfo::CJavaInfo(::JavaInfo * info, _transfer_ownership)
1083 : {
1084 0 : pInfo = info;
1085 0 : }
1086 0 : CJavaInfo CJavaInfo::createWrapper(::JavaInfo* info)
1087 : {
1088 0 : return CJavaInfo(info, TRANSFER);
1089 : }
1090 4 : void CJavaInfo::attach(::JavaInfo * info)
1091 : {
1092 4 : jfw_freeJavaInfo(pInfo);
1093 4 : pInfo = info;
1094 4 : }
1095 73 : ::JavaInfo * CJavaInfo::detach()
1096 : {
1097 73 : JavaInfo * tmp = pInfo;
1098 73 : pInfo = NULL;
1099 73 : return tmp;
1100 : }
1101 :
1102 158 : CJavaInfo::~CJavaInfo()
1103 : {
1104 158 : jfw_freeJavaInfo(pInfo);
1105 158 : }
1106 :
1107 :
1108 78 : JavaInfo * CJavaInfo::copyJavaInfo(const JavaInfo * pInfo)
1109 : {
1110 78 : if (pInfo == NULL)
1111 0 : return NULL;
1112 : JavaInfo* newInfo =
1113 78 : static_cast<JavaInfo*>(rtl_allocateMemory(sizeof(JavaInfo)));
1114 78 : if (newInfo)
1115 : {
1116 78 : memcpy(newInfo, pInfo, sizeof(JavaInfo));
1117 78 : rtl_uString_acquire(pInfo->sVendor);
1118 78 : rtl_uString_acquire(pInfo->sLocation);
1119 78 : rtl_uString_acquire(pInfo->sVersion);
1120 78 : rtl_byte_sequence_acquire(pInfo->arVendorData);
1121 : }
1122 78 : return newInfo;
1123 : }
1124 :
1125 :
1126 4 : JavaInfo* CJavaInfo::cloneJavaInfo() const
1127 : {
1128 4 : if (pInfo == NULL)
1129 0 : return NULL;
1130 4 : return copyJavaInfo(pInfo);
1131 : }
1132 :
1133 0 : CJavaInfo & CJavaInfo::operator = (const CJavaInfo& info)
1134 : {
1135 0 : if (&info == this)
1136 0 : return *this;
1137 :
1138 0 : jfw_freeJavaInfo(pInfo);
1139 0 : pInfo = copyJavaInfo(info.pInfo);
1140 0 : return *this;
1141 : }
1142 74 : CJavaInfo & CJavaInfo::operator = (const ::JavaInfo* info)
1143 : {
1144 74 : if (info == pInfo)
1145 0 : return *this;
1146 :
1147 74 : jfw_freeJavaInfo(pInfo);
1148 74 : pInfo = copyJavaInfo(info);
1149 74 : return *this;
1150 : }
1151 :
1152 0 : OUString CJavaInfo::getLocation() const
1153 : {
1154 0 : if (pInfo)
1155 0 : return OUString(pInfo->sLocation);
1156 : else
1157 0 : return OUString();
1158 : }
1159 :
1160 0 : sal_uInt64 CJavaInfo::getFeatures() const
1161 : {
1162 0 : if (pInfo)
1163 0 : return pInfo->nFeatures;
1164 : else
1165 0 : return 0l;
1166 : }
1167 :
1168 : }
1169 :
1170 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|