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 }