1 /*
   2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 
  34 #include "Package.h"
  35 #include "Lock.h"
  36 #include "Helpers.h"
  37 #include "JavaUserPreferences.h"
  38 #include "Macros.h"
  39 #include "IniFile.h"
  40 
  41 #include <assert.h>
  42 
  43 
  44 Package::Package(void) {
  45     FInitialized = false;
  46     Initialize();
  47 }
  48 
  49 TPlatformNumber StringToPercentageOfNumber(TString Value, TPlatformNumber Number) {
  50     TPlatformNumber result = 0;
  51     size_t percentage = atoi(PlatformString(Value.c_str()));
  52 
  53     if (percentage > 0 && Number > 0) {
  54         result = Number * percentage / 100;
  55     }
  56 
  57     return result;
  58 }
  59 
  60 void Package::Initialize() {
  61     if (FInitialized == true) {
  62         return;
  63     }
  64 
  65     Platform& platform = Platform::GetInstance();
  66 
  67     FBootFields = new PackageBootFields();
  68     FDebugging = dsNone;
  69 
  70     FBootFields->FPackageRootDirectory = platform.GetPackageRootDirectory();
  71     FBootFields->FPackageAppDirectory = platform.GetPackageAppDirectory();
  72     FBootFields->FPackageLauncherDirectory = platform.GetPackageLauncherDirectory();
  73     FBootFields->FAppDataDirectory = platform.GetAppDataDirectory();
  74 
  75     std::map<TString, TString> keys = platform.GetKeys();
  76 
  77     // Read from configure.cfg/Info.plist
  78     AutoFreePtr<ISectionalPropertyContainer> config = platform.GetConfigFile(platform.GetConfigFileName());
  79 
  80     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_ID_KEY], FBootFields->FAppID);
  81     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[PACKAGER_APP_DATA_DIR], FBootFields->FPackageAppDataDirectory);
  82     FBootFields->FPackageAppDataDirectory = FilePath::FixPathForPlatform(FBootFields->FPackageAppDataDirectory);
  83 
  84     // Main JAR.
  85     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINJAR_KEY], FBootFields->FMainJar);
  86     FBootFields->FMainJar = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
  87                             FilePath::FixPathForPlatform(FBootFields->FMainJar);
  88 
  89     // Classpath.
  90     // 1. If the provided class path contains main jar then only use provided class path.
  91     // 2. If class path provided by config file is empty then add main jar.
  92     // 3. If main jar is not in provided class path then add it.
  93     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath);
  94     FBootFields->FClassPath = FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath);
  95 
  96     if (FBootFields->FClassPath.empty() == true) {
  97         FBootFields->FClassPath = GetMainJar();
  98     }
  99     else if (FBootFields->FClassPath.find(GetMainJar()) == TString::npos) {
 100         FBootFields->FClassPath = GetMainJar() + FilePath::PathSeparator() + FBootFields->FClassPath;
 101     }
 102 
 103     // Main Class.
 104     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName);
 105 
 106     // Splash Screen.
 107     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_SPLASH_KEY], FBootFields->FSplashScreenFileName) == true) {
 108         FBootFields->FSplashScreenFileName = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
 109                                              FilePath::FixPathForPlatform(FBootFields->FSplashScreenFileName);
 110 
 111         if (FilePath::FileExists(FBootFields->FSplashScreenFileName) == false) {
 112             FBootFields->FSplashScreenFileName = _T("");
 113         }
 114     }
 115 
 116     // Runtime.
 117     FBootFields->FIsRuntimeBundled = true;
 118     config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory);
 119 
 120     if (FBootFields->FJVMRuntimeDirectory.empty()) {
 121         FBootFields->FIsRuntimeBundled = false;
 122         FBootFields->FJVMRuntimeDirectory = platform.GetSystemJRE();
 123     }
 124 
 125     // Read jvmargs.
 126     PromoteAppCDSState(config);
 127     ReadJVMArgs(config);
 128 
 129     // Read args if none were passed in.
 130     if (FBootFields->FArgs.size() == 0) {
 131         OrderedMap<TString, TString> args;
 132 
 133         if (config->GetSection(keys[CONFIG_SECTION_ARGOPTIONS], args) == true) {
 134             FBootFields->FArgs = Helpers::MapToNameValueList(args);
 135         }
 136     }
 137 
 138     // Read jvmuserarg defaults.
 139     config->GetSection(keys[CONFIG_SECTION_JVMUSEROPTIONS], FDefaultJVMUserArgs);
 140 
 141     // Load JVM user overrides.
 142     TString jvmUserArgsConfigFileName = GetJVMUserArgsConfigFileName();
 143 
 144     if (FilePath::FileExists(jvmUserArgsConfigFileName) == true) {
 145         // Load new location for user VM overrides.
 146         IniFile userConfig;
 147 
 148         if (userConfig.LoadFromFile(jvmUserArgsConfigFileName) == false) {
 149             // New property file format was not found, attempt to load old property file format.
 150             userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
 151         }
 152 
 153         userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
 154     }
 155     else {
 156         // Attemp to load java.util.prefs for legacy JVM user overrides.
 157         AutoFreePtr<JavaUserPreferences> javaPreferences(JavaUserPreferences::CreateInstance());
 158 
 159         if (javaPreferences->Load(GetAppID()) == true) {
 160             FJVMUserArgsOverrides = javaPreferences->GetData();
 161         }
 162     }
 163 
 164     // Auto Memory.
 165     TString autoMemory;
 166 
 167     if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_MEMORY], autoMemory) == true) {
 168         if (autoMemory == _T("auto") || autoMemory == _T("100%")) {
 169             FBootFields->FMemoryState = PackageBootFields::msAuto;
 170             FBootFields->FMemorySize = platform.GetMemorySize();
 171         }
 172         else if (autoMemory.length() == 2 && isdigit(autoMemory[0]) && autoMemory[1] == '%') {
 173             FBootFields->FMemoryState = PackageBootFields::msAuto;
 174             FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 1), platform.GetMemorySize());
 175         }
 176         else if (autoMemory.length() == 3 && isdigit(autoMemory[0]) && isdigit(autoMemory[1]) && autoMemory[2] == '%') {
 177             FBootFields->FMemoryState = PackageBootFields::msAuto;
 178             FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 2), platform.GetMemorySize());
 179         }
 180         else {
 181             FBootFields->FMemoryState = PackageBootFields::msManual;
 182             FBootFields->FMemorySize = 0;
 183         }
 184     }
 185 
 186     MergeJVMDefaultsWithOverrides();
 187 }
 188 
 189 void Package::Clear() {
 190     FreeBootFields();
 191     FJVMUserArgsOverrides.Clear();
 192     FDefaultJVMUserArgs.Clear();
 193     FJVMUserArgs.Clear();
 194     FInitialized = false;
 195 }
 196 
 197 // This is the only location that the AppCDS state should be modified except
 198 // by command line arguments provided by the user.
 199 //
 200 // The state of AppCDS is as follows:
 201 //
 202 // -> cdsUninitialized
 203 //    -> cdsGenCache If -Xappcds:generatecache
 204 //    -> cdsDisabled If -Xappcds:off
 205 //    -> cdsEnabled If "AppCDSJVMOptions" section is present
 206 //    -> cdsAuto If "AppCDSJVMOptions" section is present and app.appcds.cache=auto
 207 //    -> cdsDisabled Default
 208 //
 209 void Package::PromoteAppCDSState(ISectionalPropertyContainer* Config) {
 210     Platform& platform = Platform::GetInstance();
 211     std::map<TString, TString> keys = platform.GetKeys();
 212 
 213     // The AppCDS state can change at this point.
 214     switch (platform.GetAppCDSState()) {
 215         case cdsEnabled:
 216         case cdsAuto:
 217         case cdsDisabled:
 218         case cdsGenCache: {
 219             // Do nothing.
 220             break;
 221         }
 222 
 223         case cdsUninitialized: {
 224             if (Config->ContainsSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS]) == true) {
 225                 // If the AppCDS section is present then enable AppCDS.
 226                 TString appCDSCacheValue;
 227 
 228                 // If running with AppCDS enabled, and the configuration has been setup so "auto" is enabled, then
 229                 // the launcher will attempt to generate the cache file automatically and run the application.
 230                 if (Config->GetValue(keys[CONFIG_SECTION_APPLICATION], _T("app.appcds.cache"), appCDSCacheValue) == true &&
 231                     appCDSCacheValue == _T("auto")) {
 232                     platform.SetAppCDSState(cdsAuto);
 233                 }
 234                 else {
 235                     platform.SetAppCDSState(cdsEnabled);
 236                 }
 237             }
 238             else {
 239 
 240                 platform.SetAppCDSState(cdsDisabled);
 241             }
 242         }
 243     }
 244 }
 245 
 246 void Package::ReadJVMArgs(ISectionalPropertyContainer* Config) {
 247     Platform& platform = Platform::GetInstance();
 248     std::map<TString, TString> keys = platform.GetKeys();
 249 
 250     // Evaluate based on the current AppCDS state.
 251     switch (platform.GetAppCDSState()) {
 252         case cdsUninitialized: {
 253             throw Exception(_T("Internal Error"));
 254     }
 255 
 256         case cdsDisabled: {
 257             Config->GetSection(keys[CONFIG_SECTION_JVMOPTIONS], FBootFields->FJVMArgs);
 258             break;
 259         }
 260 
 261         case cdsGenCache: {
 262             Config->GetSection(keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS], FBootFields->FJVMArgs);
 263             break;
 264         }
 265 
 266         case cdsAuto:
 267         case cdsEnabled: {
 268             if (Config->GetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
 269                                  _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName) == true) {
 270                 // File names may contain the incorrect path separators. The cache file name must be
 271                 // corrected at this point.
 272                 if (FBootFields->FAppCDSCacheFileName.empty() == false) {
 273                     IniFile* iniConfig = dynamic_cast<IniFile*>(Config);
 274 
 275                     if (iniConfig != NULL) {
 276                         FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
 277                         iniConfig->SetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
 278                                      _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName);
 279                     }
 280                 }
 281 
 282                 Config->GetSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], FBootFields->FJVMArgs);
 283             }
 284 
 285             break;
 286         }
 287     }
 288 }
 289 
 290 void Package::SetCommandLineArguments(int argc, TCHAR* argv[]) {
 291     if (argc > 0) {
 292         std::list<TString> args;
 293 
 294         // Prepare app arguments. Skip value at index 0 - this is path to executable.
 295         FBootFields->FCommandName = argv[0];
 296 
 297         // Path to executable is at 0 index so start at index 1.
 298         for (int index = 1; index < argc; index++) {
 299             TString arg = argv[index];
 300 
 301 #ifdef DEBUG
 302             if (arg == _T("-debug")) {
 303                 FDebugging = dsNative;
 304             }
 305 
 306             if (arg == _T("-javadebug")) {
 307                 FDebugging = dsJava;
 308             }
 309 #endif //DEBUG
 310 #ifdef MAC
 311             if (arg.find(_T("-psn_"), 0) != TString::npos) {
 312                 Platform& platform = Platform::GetInstance();
 313 
 314                 if (platform.IsMainThread() == true) {
 315 #ifdef DEBUG
 316                     printf("%s\n", arg.c_str());
 317 #endif //DEBUG
 318                     continue;
 319                 }
 320             }
 321 
 322             if (arg == _T("-NSDocumentRevisionsDebugMode")) {
 323                 // Ignore -NSDocumentRevisionsDebugMode and the following YES/NO
 324                 index++;
 325                 continue;
 326             }
 327 #endif //MAC
 328 
 329             args.push_back(arg);
 330         }
 331 
 332         if (args.size() > 0) {
 333             FBootFields->FArgs = args;
 334         }
 335     }
 336 }
 337 
 338 Package& Package::GetInstance() {
 339     static Package instance; // Guaranteed to be destroyed. Instantiated on first use.
 340     return instance;
 341 }
 342 
 343 Package::~Package(void) {
 344     FreeBootFields();
 345 }
 346 
 347 void Package::FreeBootFields() {
 348     if (FBootFields != NULL) {
 349         delete FBootFields;
 350         FBootFields = NULL;
 351     }
 352 }
 353 
 354 OrderedMap<TString, TString> Package::GetJVMArgs() {
 355     return FBootFields->FJVMArgs;
 356 }
 357 
 358 OrderedMap<TString, TString> Package::GetDefaultJVMUserArgs() {
 359     return FDefaultJVMUserArgs;
 360 }
 361 
 362 OrderedMap<TString, TString> Package::GetJVMUserArgOverrides() {
 363     return FJVMUserArgsOverrides;
 364 }
 365 
 366 std::vector<TString> GetKeysThatAreNotDuplicates(OrderedMap<TString, TString> &Defaults,
 367                                                OrderedMap<TString, TString> &Overrides) {
 368     std::vector<TString> result;
 369     std::vector<TString> overrideKeys = Overrides.GetKeys();
 370 
 371     for (size_t index = 0; index < overrideKeys.size(); index++) {
 372         TString overridesKey = overrideKeys[index];
 373         TString overridesValue;
 374         TString defaultValue;
 375 
 376         if ((Defaults.ContainsKey(overridesKey) == false) ||
 377            (Defaults.GetValue(overridesKey, defaultValue) == true &&
 378             Overrides.GetValue(overridesKey, overridesValue) == true &&
 379             defaultValue != overridesValue)) {
 380             result.push_back(overridesKey);
 381         }
 382     }
 383 
 384     return result;
 385 }
 386 
 387 OrderedMap<TString, TString> CreateOrderedMapFromKeyList(OrderedMap<TString, TString> &Map,
 388                                                          std::vector<TString> &Keys) {
 389     OrderedMap<TString, TString> result;
 390 
 391     for (size_t index = 0; index < Keys.size(); index++) {
 392         TString key = Keys[index];
 393         TString value;
 394 
 395         if (Map.GetValue(key, value) == true) {
 396             result.Append(key, value);
 397         }
 398     }
 399 
 400     return result;
 401 }
 402 
 403 void Package::SetJVMUserArgOverrides(OrderedMap<TString, TString> Value) {
 404     OrderedMap<TString, TString> defaults = GetDefaultJVMUserArgs();
 405     OrderedMap<TString, TString> overrides = Value;
 406 
 407     // 1. Remove entries in the overrides that are the same as the defaults.
 408     std::vector<TString> overrideKeys = GetKeysThatAreNotDuplicates(defaults, overrides);
 409 
 410     // 2. Create an ordered map from the overrides that weren't removed.
 411     FJVMUserArgsOverrides = CreateOrderedMapFromKeyList(overrides, overrideKeys);
 412 
 413     // 3. Overwrite JVM user config overrides with provided key/value pair.
 414     SaveJVMUserArgOverrides(FJVMUserArgsOverrides);
 415 
 416     // 4. Merge defaults and overrides to produce FJVMUserArgs.
 417     MergeJVMDefaultsWithOverrides();
 418 }
 419 
 420 void Package::SaveJVMUserArgOverrides(OrderedMap<TString, TString> Data) {
 421     IniFile userConfig;
 422     Platform& platform = Platform::GetInstance();
 423     std::map<TString, TString> keys = platform.GetKeys();
 424     userConfig.AppendSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], Data);
 425     userConfig.SaveToFile(GetJVMUserArgsConfigFileName());
 426 }
 427 
 428 OrderedMap<TString, TString> Package::GetJVMUserArgs() {
 429     return FJVMUserArgs;
 430 }
 431 
 432 std::vector<TString> GetKeysThatAreNotOverridesOfDefaultValues(OrderedMap<TString, TString> &Defaults,
 433                                                                OrderedMap<TString, TString> &Overrides) {
 434     std::vector<TString> result;
 435     std::vector<TString> keys = Overrides.GetKeys();
 436 
 437     for (unsigned int index = 0; index< keys.size(); index++) {
 438         TString key = keys[index];
 439 
 440         if (Defaults.ContainsKey(key) == true) {
 441             try {
 442                 TString value = Overrides[key];
 443                 Defaults[key] = value;
 444             }
 445             catch (std::out_of_range) {
 446             }
 447         }
 448         else {
 449             result.push_back(key);
 450         }
 451     }
 452 
 453     return result;
 454 }
 455 
 456 void Package::MergeJVMDefaultsWithOverrides() {
 457     // Merge jvmuserarg defaults and jvmuserarg overrides to populate FJVMUserArgs.
 458     // 1. If the key is in the config file and not the java.user.preferences the default value is used,
 459     //    the one from the config file.
 460     // 2. If the key is in the java.user.preferences then the value from the java.user.preferences is used and
 461     //    the config file value is ignored.
 462     // 3. If the key is not in the config file but it is in the java.user.preferences then it is added anyway.
 463     //    And if it is removed it won't show back up.
 464     FJVMUserArgs.Clear();
 465     FJVMUserArgs.Append(FDefaultJVMUserArgs);
 466 
 467     OrderedMap<TString, TString> overrides = GetJVMUserArgOverrides();
 468 
 469     // 1. Iterate over all elements in overrides to see if any items
 470     //    override a default value.
 471     std::vector<TString> keys = GetKeysThatAreNotOverridesOfDefaultValues(FJVMUserArgs, overrides);
 472 
 473 
 474     // 2. All remaining items in overrides are appended to the end.
 475     for (unsigned int index = 0; index< keys.size(); index++) {
 476         TString key = keys[index];
 477         TString value;
 478 
 479         if (overrides.GetValue(key, value) == true) {
 480             FJVMUserArgs.Append(key, value);
 481         }
 482     }
 483 }
 484 
 485 std::list<TString> Package::GetArgs() {
 486     assert(FBootFields != NULL);
 487     return FBootFields->FArgs;
 488 }
 489 
 490 TString Package::GetPackageRootDirectory() {
 491     assert(FBootFields != NULL);
 492     return FBootFields->FPackageRootDirectory;
 493 }
 494 
 495 TString Package::GetPackageAppDirectory() {
 496     assert(FBootFields != NULL);
 497     return FBootFields->FPackageAppDirectory;
 498 }
 499 
 500 TString Package::GetPackageLauncherDirectory() {
 501     assert(FBootFields != NULL);
 502     return FBootFields->FPackageLauncherDirectory;
 503 }
 504 
 505 TString Package::GetAppDataDirectory() {
 506     assert(FBootFields != NULL);
 507     return FBootFields->FAppDataDirectory;
 508 }
 509 
 510 TString Package::GetJVMUserArgsConfigFileName() {
 511     if (FJVMUserArgsConfigFileName.empty()) {
 512         Platform& platform = Platform::GetInstance();
 513 
 514         FJVMUserArgsConfigFileName = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
 515                                         FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
 516                                         FilePath::IncludeTrailingSeparater(_T("packager")) +
 517                                         _T("jvmuserargs.cfg");
 518     }
 519 
 520     return FJVMUserArgsConfigFileName;
 521 }
 522 
 523 TString Package::GetAppCDSCacheDirectory() {
 524     if (FAppCDSCacheDirectory.empty()) {
 525         Platform& platform = Platform::GetInstance();
 526         FAppCDSCacheDirectory = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
 527                                 FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
 528                                 _T("cache");
 529 
 530         Macros& macros = Macros::GetInstance();
 531         FAppCDSCacheDirectory = macros.ExpandMacros(FAppCDSCacheDirectory);
 532         FAppCDSCacheDirectory = FilePath::FixPathForPlatform(FAppCDSCacheDirectory);
 533     }
 534 
 535     return FAppCDSCacheDirectory;
 536 }
 537 
 538 TString Package::GetAppCDSCacheFileName() {
 539     assert(FBootFields != NULL);
 540 
 541     if (FBootFields->FAppCDSCacheFileName.empty() == false) {
 542         Macros& macros = Macros::GetInstance();
 543         FBootFields->FAppCDSCacheFileName = macros.ExpandMacros(FBootFields->FAppCDSCacheFileName);
 544         FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
 545     }
 546 
 547     return FBootFields->FAppCDSCacheFileName;
 548 }
 549 
 550 TString Package::GetAppID() {
 551     assert(FBootFields != NULL);
 552     return FBootFields->FAppID;
 553 }
 554 
 555 TString Package::GetPackageAppDataDirectory() {
 556     assert(FBootFields != NULL);
 557     return FBootFields->FPackageAppDataDirectory;
 558 }
 559 
 560 TString Package::GetClassPath() {
 561     assert(FBootFields != NULL);
 562     return FBootFields->FClassPath;
 563 }
 564 
 565 TString Package::GetMainJar() {
 566     assert(FBootFields != NULL);
 567     return FBootFields->FMainJar;
 568 }
 569 
 570 TString Package::GetMainClassName() {
 571     assert(FBootFields != NULL);
 572     return FBootFields->FMainClassName;
 573 }
 574 
 575 bool Package::IsRuntimeBundled() {
 576     assert(FBootFields != NULL);
 577     return FBootFields->FIsRuntimeBundled;
 578 }
 579 
 580 TString Package::GetJVMLibraryFileName() {
 581     assert(FBootFields != NULL);
 582 
 583     if (FBootFields->FJVMLibraryFileName.empty() == true) {
 584         Platform& platform = Platform::GetInstance();
 585         if (IsRuntimeBundled() == true) {
 586             Macros& macros = Macros::GetInstance();
 587             TString jvmRuntimePath = macros.ExpandMacros(GetJVMRuntimeDirectory());
 588             FBootFields->FJVMLibraryFileName = platform.GetBundledJVMLibraryFileName(jvmRuntimePath);
 589         }
 590         else {
 591             FBootFields->FJVMLibraryFileName = platform.GetSystemJVMLibraryFileName();
 592         }
 593     }
 594 
 595     return FBootFields->FJVMLibraryFileName;
 596 }
 597 
 598 TString Package::GetJVMRuntimeDirectory() {
 599     assert(FBootFields != NULL);
 600     return FBootFields->FJVMRuntimeDirectory;
 601 }
 602 
 603 TString Package::GetSplashScreenFileName() {
 604     assert(FBootFields != NULL);
 605     return FBootFields->FSplashScreenFileName;
 606 }
 607 
 608 bool Package::HasSplashScreen() {
 609     assert(FBootFields != NULL);
 610     return FilePath::FileExists(FBootFields->FSplashScreenFileName);
 611 }
 612 
 613 TString Package::GetCommandName() {
 614     assert(FBootFields != NULL);
 615     return FBootFields->FCommandName;
 616 }
 617 
 618 TPlatformNumber Package::GetMemorySize() {
 619     assert(FBootFields != NULL);
 620     return FBootFields->FMemorySize;
 621 }
 622 
 623 PackageBootFields::MemoryState Package::GetMemoryState() {
 624     assert(FBootFields != NULL);
 625     return FBootFields->FMemoryState;
 626 }
 627 
 628 DebugState Package::Debugging() {
 629     return FDebugging;
 630 }