src/jdk.packager/macosx/native/library/MacPlatform.mm
branchJDK-8200758-branch
changeset 56821 565d54ca1f41
child 56854 aedce3eaaf17
equal deleted inserted replaced
56820:b763f6492df9 56821:565d54ca1f41
       
     1 /*
       
     2  * Copyright (c) 2014, 2017, 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 "Platform.h"
       
    35 
       
    36 #ifdef MAC
       
    37 
       
    38 #include "MacPlatform.h"
       
    39 #include "Helpers.h"
       
    40 #include "Package.h"
       
    41 #include "PropertyFile.h"
       
    42 #include "IniFile.h"
       
    43 
       
    44 #include <sys/sysctl.h>
       
    45 #include <pthread.h>
       
    46 #include <vector>
       
    47 
       
    48 #import <Foundation/Foundation.h>
       
    49 #import <AppKit/NSRunningApplication.h>
       
    50 
       
    51 #include <CoreFoundation/CoreFoundation.h>
       
    52 #include <CoreFoundation/CFString.h>
       
    53 
       
    54 #ifdef __OBJC__
       
    55 #import <Cocoa/Cocoa.h>
       
    56 #endif //__OBJC__
       
    57 
       
    58 #define MAC_PACKAGER_TMP_DIR "/Library/Application Support/Oracle/Java/Packager/tmp"
       
    59 
       
    60 //--------------------------------------------------------------------------------------------------
       
    61 
       
    62 NSString* StringToNSString(TString Value) {
       
    63     NSString* result = [NSString stringWithCString:Value.c_str()
       
    64                                           encoding:[NSString defaultCStringEncoding]];
       
    65     return result;
       
    66 }
       
    67 
       
    68 //--------------------------------------------------------------------------------------------------
       
    69 
       
    70 MacPlatform::MacPlatform(void) : Platform(), GenericPlatform(), PosixPlatform() {
       
    71 }
       
    72 
       
    73 MacPlatform::~MacPlatform(void) {
       
    74 }
       
    75 
       
    76 bool MacPlatform::UsePListForConfigFile() {
       
    77     return FilePath::FileExists(GetConfigFileName()) == false;
       
    78 }
       
    79 
       
    80 void MacPlatform::ShowMessage(TString Title, TString Description) {
       
    81     NSString *ltitle = StringToNSString(Title);
       
    82     NSString *ldescription = StringToNSString(Description);
       
    83 
       
    84     NSLog(@"%@:%@", ltitle, ldescription);
       
    85 }
       
    86 
       
    87 void MacPlatform::ShowMessage(TString Description) {
       
    88     TString appname = GetModuleFileName();
       
    89     appname = FilePath::ExtractFileName(appname);
       
    90     ShowMessage(appname, Description);
       
    91 }
       
    92 
       
    93 TString MacPlatform::getTmpDirString() {
       
    94     return TString(MAC_PACKAGER_TMP_DIR);
       
    95 }
       
    96 
       
    97 void MacPlatform::reactivateAnotherInstance() {
       
    98     if (singleInstanceProcessId == 0) {
       
    99         printf("Unable to reactivate another instance, PID is undefined");
       
   100         return;
       
   101     }
       
   102     NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier: singleInstanceProcessId];
       
   103     if (app != nil) {
       
   104         [app activateWithOptions: NSApplicationActivateIgnoringOtherApps];
       
   105     } else {
       
   106         printf("Unable to reactivate another instance PID: %d", singleInstanceProcessId);
       
   107     }
       
   108 }
       
   109 
       
   110 TCHAR* MacPlatform::ConvertStringToFileSystemString(TCHAR* Source, bool &release) {
       
   111     TCHAR* result = NULL;
       
   112     release = false;
       
   113     CFStringRef StringRef = CFStringCreateWithCString(kCFAllocatorDefault, Source, kCFStringEncodingUTF8);
       
   114 
       
   115     if (StringRef != NULL) {
       
   116         @try {
       
   117             CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(StringRef);
       
   118             result = new char[length + 1];
       
   119 
       
   120             if (CFStringGetFileSystemRepresentation(StringRef, result, length)) {
       
   121                 release = true;
       
   122             }
       
   123             else {
       
   124                 delete[] result;
       
   125                 result = NULL;
       
   126             }
       
   127         }
       
   128         @finally {
       
   129             CFRelease(StringRef);
       
   130         }
       
   131     }
       
   132 
       
   133     return result;
       
   134 }
       
   135 
       
   136 TCHAR* MacPlatform::ConvertFileSystemStringToString(TCHAR* Source, bool &release) {
       
   137     TCHAR* result = NULL;
       
   138     release = false;
       
   139     CFStringRef StringRef = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, Source);
       
   140 
       
   141     if (StringRef != NULL) {
       
   142         @try {
       
   143             CFIndex length = CFStringGetLength(StringRef);
       
   144 
       
   145             if (length > 0) {
       
   146                 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
       
   147 
       
   148                 result = new char[maxSize + 1];
       
   149 
       
   150                 if (CFStringGetCString(StringRef, result, maxSize, kCFStringEncodingUTF8) == true) {
       
   151                     release = true;
       
   152                 }
       
   153                 else {
       
   154                     delete[] result;
       
   155                     result = NULL;
       
   156                 }
       
   157             }
       
   158         }
       
   159         @finally {
       
   160             CFRelease(StringRef);
       
   161         }
       
   162     }
       
   163 
       
   164     return result;
       
   165 }
       
   166 
       
   167 void MacPlatform::SetCurrentDirectory(TString Value) {
       
   168     chdir(PlatformString(Value).toPlatformString());
       
   169 }
       
   170 
       
   171 TString MacPlatform::GetPackageRootDirectory() {
       
   172     NSBundle *mainBundle = [NSBundle mainBundle];
       
   173     NSString *mainBundlePath = [mainBundle bundlePath];
       
   174     NSString *contentsPath = [mainBundlePath stringByAppendingString:@"/Contents"];
       
   175     TString result = [contentsPath UTF8String];
       
   176     return result;
       
   177 }
       
   178 
       
   179 TString MacPlatform::GetAppDataDirectory() {
       
   180     TString result;
       
   181     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
       
   182     NSString *applicationSupportDirectory = [paths firstObject];
       
   183     result = [applicationSupportDirectory UTF8String];
       
   184     return result;
       
   185 }
       
   186 
       
   187 TString MacPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) {
       
   188     TString result;
       
   189 
       
   190     result = FilePath::IncludeTrailingSeparater(RuntimePath) + _T("Contents/Home/jre/lib/jli/libjli.dylib");
       
   191 
       
   192     if (FilePath::FileExists(result) == false) {
       
   193         result = FilePath::IncludeTrailingSeparater(RuntimePath) + _T("Contents/Home/lib/jli/libjli.dylib");
       
   194 
       
   195         if (FilePath::FileExists(result) == false) {
       
   196             result = _T("");
       
   197         }
       
   198     }
       
   199 
       
   200     return result;
       
   201 }
       
   202 
       
   203 TString MacPlatform::GetAppName() {
       
   204     NSString *appName = [[NSProcessInfo processInfo] processName];
       
   205     TString result = [appName UTF8String];
       
   206     return result;
       
   207 }
       
   208 
       
   209 void AppendPListArrayToIniFile(NSDictionary *infoDictionary, IniFile *result, TString Section) {
       
   210     NSString *sectionKey = [NSString stringWithUTF8String:PlatformString(Section).toMultibyte()];
       
   211     NSDictionary *array = [infoDictionary objectForKey:sectionKey];
       
   212 
       
   213     for (id option in array) {
       
   214         if ([option isKindOfClass:[NSString class]]) {
       
   215             TString arg = [option UTF8String];
       
   216 
       
   217             TString name;
       
   218             TString value;
       
   219 
       
   220             if (Helpers::SplitOptionIntoNameValue(arg, name, value) == true) {
       
   221                 result->Append(Section, name, value);
       
   222             }
       
   223         }
       
   224     }
       
   225 }
       
   226 
       
   227 void AppendPListDictionaryToIniFile(NSDictionary *infoDictionary, IniFile *result, TString Section, bool FollowSection = true) {
       
   228     NSDictionary *dictionary = NULL;
       
   229 
       
   230     if (FollowSection == true) {
       
   231         NSString *sectionKey = [NSString stringWithUTF8String:PlatformString(Section).toMultibyte()];
       
   232         dictionary = [infoDictionary objectForKey:sectionKey];
       
   233     }
       
   234     else {
       
   235         dictionary = infoDictionary;
       
   236     }
       
   237 
       
   238     for (id key in dictionary) {
       
   239         id option = [dictionary valueForKey:key];
       
   240 
       
   241         if ([key isKindOfClass:[NSString class]] && [option isKindOfClass:[NSString class]]) {
       
   242             TString name = [key UTF8String];
       
   243             TString value = [option UTF8String];
       
   244             result->Append(Section, name, value);
       
   245         }
       
   246     }
       
   247 }
       
   248 
       
   249 // Convert parts of the info.plist to the INI format the rest of the packager uses unless
       
   250 // a packager config file exists.
       
   251 ISectionalPropertyContainer* MacPlatform::GetConfigFile(TString FileName) {
       
   252     IniFile* result = new IniFile();
       
   253 
       
   254     if (UsePListForConfigFile() == false) {
       
   255         if (result->LoadFromFile(FileName) == false) {
       
   256             // New property file format was not found, attempt to load old property file format.
       
   257             Helpers::LoadOldConfigFile(FileName, result);
       
   258         }
       
   259     }
       
   260     else {
       
   261         NSBundle *mainBundle = [NSBundle mainBundle];
       
   262         NSDictionary *infoDictionary = [mainBundle infoDictionary];
       
   263         std::map<TString, TString> keys = GetKeys();
       
   264 
       
   265         // Packager options.
       
   266         AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_APPLICATION], false);
       
   267 
       
   268         // jvmargs
       
   269         AppendPListArrayToIniFile(infoDictionary, result, keys[CONFIG_SECTION_JVMOPTIONS]);
       
   270 
       
   271         // jvmuserargs
       
   272         AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_JVMUSEROPTIONS]);
       
   273 
       
   274         // Generate AppCDS Cache
       
   275         AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_APPCDSJVMOPTIONS]);
       
   276         AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS]);
       
   277 
       
   278         // args
       
   279         AppendPListArrayToIniFile(infoDictionary, result, keys[CONFIG_SECTION_ARGOPTIONS]);
       
   280     }
       
   281 
       
   282     return result;
       
   283 }
       
   284 
       
   285 TString GetModuleFileNameOSX() {
       
   286     Dl_info module_info;
       
   287     if (dladdr(reinterpret_cast<void*>(GetModuleFileNameOSX), &module_info) == 0) {
       
   288         // Failed to find the symbol we asked for.
       
   289         return std::string();
       
   290     }
       
   291     return TString(module_info.dli_fname);
       
   292 }
       
   293 
       
   294 #include <mach-o/dyld.h>
       
   295 
       
   296 TString MacPlatform::GetModuleFileName() {
       
   297     //return GetModuleFileNameOSX();
       
   298 
       
   299     TString result;
       
   300     DynamicBuffer<TCHAR> buffer(MAX_PATH);
       
   301     uint32_t size = buffer.GetSize();
       
   302 
       
   303     if (_NSGetExecutablePath(buffer.GetData(), &size) == 0) {
       
   304         result = FileSystemStringToString(buffer.GetData());
       
   305     }
       
   306 
       
   307     return result;
       
   308 }
       
   309 
       
   310 bool MacPlatform::IsMainThread() {
       
   311     bool result = (pthread_main_np() == 1);
       
   312     return result;
       
   313 }
       
   314 
       
   315 TPlatformNumber MacPlatform::GetMemorySize() {
       
   316     unsigned long long memory = [[NSProcessInfo processInfo] physicalMemory];
       
   317     TPlatformNumber result = memory / 1048576; // Convert from bytes to megabytes.
       
   318     return result;
       
   319 }
       
   320 
       
   321 std::map<TString, TString> MacPlatform::GetKeys() {
       
   322     std::map<TString, TString> keys;
       
   323 
       
   324     if (UsePListForConfigFile() == false) {
       
   325         return GenericPlatform::GetKeys();
       
   326     }
       
   327     else {
       
   328         keys.insert(std::map<TString, TString>::value_type(CONFIG_VERSION,            _T("app.version")));
       
   329         keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINJAR_KEY,        _T("JVMMainJarName")));
       
   330         keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINMODULE_KEY,     _T("JVMMainModuleName")));
       
   331         keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINCLASSNAME_KEY,  _T("JVMMainClassName")));
       
   332         keys.insert(std::map<TString, TString>::value_type(CONFIG_CLASSPATH_KEY,      _T("JVMAppClasspath")));
       
   333         keys.insert(std::map<TString, TString>::value_type(APP_NAME_KEY,              _T("CFBundleName")));
       
   334         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_ID_KEY,         _T("JVMPreferencesID")));
       
   335         keys.insert(std::map<TString, TString>::value_type(JVM_RUNTIME_KEY,           _T("JVMRuntime")));
       
   336         keys.insert(std::map<TString, TString>::value_type(PACKAGER_APP_DATA_DIR,     _T("CFBundleIdentifier")));
       
   337 
       
   338         keys.insert(std::map<TString, TString>::value_type(CONFIG_SPLASH_KEY,         _T("app.splash")));
       
   339         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_MEMORY,         _T("app.memory")));
       
   340         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_DEBUG,          _T("app.debug")));
       
   341         keys.insert(std::map<TString, TString>::value_type(CONFIG_APPLICATION_INSTANCE,   _T("app.application.instance")));
       
   342 
       
   343         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPLICATION,    _T("Application")));
       
   344         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMOPTIONS,     _T("JVMOptions")));
       
   345         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMUSEROPTIONS, _T("JVMUserOptions")));
       
   346         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS, _T("JVMUserOverrideOptions")));
       
   347         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPCDSJVMOPTIONS, _T("AppCDSJVMOptions")));
       
   348         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS, _T("AppCDSGenerateCacheJVMOptions")));
       
   349         keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_ARGOPTIONS,     _T("ArgOptions")));
       
   350     }
       
   351 
       
   352     return keys;
       
   353 }
       
   354 
       
   355 #ifdef DEBUG
       
   356 bool MacPlatform::IsNativeDebuggerPresent() {
       
   357     int state;
       
   358     int mib[4];
       
   359     struct kinfo_proc info;
       
   360     size_t size;
       
   361 
       
   362     info.kp_proc.p_flag = 0;
       
   363 
       
   364     mib[0] = CTL_KERN;
       
   365     mib[1] = KERN_PROC;
       
   366     mib[2] = KERN_PROC_PID;
       
   367     mib[3] = getpid();
       
   368 
       
   369     size = sizeof(info);
       
   370     state = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
       
   371     assert(state == 0);
       
   372     return ((info.kp_proc.p_flag & P_TRACED) != 0);
       
   373 }
       
   374 
       
   375 int MacPlatform::GetProcessID() {
       
   376     int pid = [[NSProcessInfo processInfo] processIdentifier];
       
   377     return pid;
       
   378 }
       
   379 #endif //DEBUG
       
   380 
       
   381 //--------------------------------------------------------------------------------------------------
       
   382 
       
   383 class UserDefaults {
       
   384 private:
       
   385     OrderedMap<TString, TString> FData;
       
   386     TString FDomainName;
       
   387 
       
   388     bool ReadDictionary(NSDictionary *Items, OrderedMap<TString, TString> &Data) {
       
   389         bool result = false;
       
   390 
       
   391         for (id key in Items) {
       
   392             id option = [Items valueForKey:key];
       
   393 
       
   394             if ([key isKindOfClass:[NSString class]] && [option isKindOfClass:[NSString class]]) {
       
   395                 TString name = [key UTF8String];
       
   396                 TString value = [option UTF8String];
       
   397 
       
   398                 if (name.empty() == false) {
       
   399                     Data.Append(name, value);
       
   400                 }
       
   401             }
       
   402         }
       
   403 
       
   404         return result;
       
   405     }
       
   406 
       
   407     // Open and read the defaults file specified by domain.
       
   408     bool ReadPreferences(NSDictionary *Defaults, std::list<TString> Keys, OrderedMap<TString, TString> &Data) {
       
   409         bool result = false;
       
   410 
       
   411         if (Keys.size() > 0 && Defaults != NULL) {
       
   412             NSDictionary *node = Defaults;
       
   413 
       
   414             while (Keys.size() > 0 && node != NULL) {
       
   415                 TString key = Keys.front();
       
   416                 Keys.pop_front();
       
   417                 NSString *tempKey = StringToNSString(key);
       
   418                 node = [node valueForKey:tempKey];
       
   419 
       
   420                 if (Keys.size() == 0) {
       
   421                     break;
       
   422                 }
       
   423             }
       
   424 
       
   425             if (node != NULL) {
       
   426                 result = ReadDictionary(node, Data);
       
   427             }
       
   428         }
       
   429 
       
   430         return result;
       
   431     }
       
   432 
       
   433     NSDictionary* LoadPreferences(TString DomainName) {
       
   434         NSDictionary *result = NULL;
       
   435 
       
   436         if (DomainName.empty() == false) {
       
   437             NSUserDefaults *prefs = [[NSUserDefaults alloc] init];
       
   438 
       
   439             if (prefs != NULL) {
       
   440                 NSString *lDomainName = StringToNSString(DomainName);
       
   441                 result = [prefs persistentDomainForName: lDomainName];
       
   442             }
       
   443         }
       
   444 
       
   445         return result;
       
   446     }
       
   447 
       
   448 public:
       
   449     UserDefaults(TString DomainName) {
       
   450         FDomainName = DomainName;
       
   451     }
       
   452 
       
   453     bool Read(std::list<TString> Keys) {
       
   454         NSDictionary *defaults = LoadPreferences(FDomainName);
       
   455         return ReadPreferences(defaults, Keys, FData);
       
   456     }
       
   457 
       
   458     OrderedMap<TString, TString> GetData() {
       
   459         return FData;
       
   460     }
       
   461 };
       
   462 
       
   463 //--------------------------------------------------------------------------------------------------
       
   464 
       
   465 MacJavaUserPreferences::MacJavaUserPreferences(void) : JavaUserPreferences() {
       
   466 }
       
   467 
       
   468 TString toLowerCase(TString Value) {
       
   469     // Use Cocoa's lowercase method because it is better than the ones provided by C/C++.
       
   470     NSString *temp = StringToNSString(Value);
       
   471     temp = [temp lowercaseString];
       
   472     TString result = [temp UTF8String];
       
   473     return result;
       
   474 }
       
   475 
       
   476 // Split the string Value into using Delimiter.
       
   477 std::list<TString> Split(TString Value, TString Delimiter) {
       
   478     std::list<TString> result;
       
   479     std::vector<char> buffer(Value.c_str(), Value.c_str() + Value.size() + 1);
       
   480     char *p = strtok(&buffer[0], Delimiter.data());
       
   481 
       
   482     while (p != NULL) {
       
   483         TString token = p;
       
   484         result.push_back(token);
       
   485         p = strtok(NULL, Delimiter.data());
       
   486     }
       
   487 
       
   488     return result;
       
   489 }
       
   490 
       
   491 // 1. If the path is fewer than three components (Example: one/two/three) then the domain is the
       
   492 //    default domain "com.apple.java.util.prefs" stored in the plist file
       
   493 //    ~/Library/Preferences/com.apple.java.util.prefs.plist
       
   494 //
       
   495 //    For example: If AppID = "hello", the path is "hello/JVMUserOptions and the
       
   496 //    plist file is ~/Library/Preferences/com.apple.java.util.prefs.plist containing the contents:
       
   497 //
       
   498 //    <?xml version="1.0" encoding="UTF-8"?>
       
   499 //    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
       
   500 //    <plist version="1.0">
       
   501 //    <dict>
       
   502 //      <key>/</key>
       
   503 //      <dict>
       
   504 //        <key>hello/</key>
       
   505 //        <dict>
       
   506 //          <key>JVMUserOptions/</key>
       
   507 //          <dict>
       
   508 //            <key>-DXmx</key>
       
   509 //            <string>512m</string>
       
   510 //          </dict>
       
   511 //        </dict>
       
   512 //      </dict>
       
   513 //    </dict>
       
   514 //    </plist>
       
   515 //
       
   516 // 2. If the path is three or more, the first three become the domain name (even
       
   517 //    if shared across applicaitons) and the remaining become individual keys.
       
   518 //
       
   519 //    For example: If AppID = "com/hello/foo", the path is "hello/JVMUserOptions and the
       
   520 //    domain is "com.hello.foo" stored in the plist file ~/Library/Preferences/com.hello.foo.plist
       
   521 //    containing the contents:
       
   522 //
       
   523 //    <?xml version="1.0" encoding="UTF-8"?>
       
   524 //    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
       
   525 //    <plist version="1.0">
       
   526 //    <dict>
       
   527 //      <key>/com/hello/foo/</key>
       
   528 //      <dict>
       
   529 //        <key>JVMUserOptions/</key>
       
   530 //        <dict>
       
   531 //          <key>-DXmx</key>
       
   532 //          <string>512m</string>
       
   533 //        </dict>
       
   534 //      </dict>
       
   535 //    </dict>
       
   536 //    </plist>
       
   537 //
       
   538 // NOTE: To change these values use the command line utility "defaults":
       
   539 // Example: defaults read com.apple.java.util.prefs /
       
   540 // Since OS 10.9 Mavericks the defaults are cashed so directly modifying the files is not recommended.
       
   541 bool MacJavaUserPreferences::Load(TString Appid) {
       
   542     bool result = false;
       
   543 
       
   544     if (Appid.empty() == false) {
       
   545         // This is for backwards compatability. Older packaged applications have an
       
   546         // app.preferences.id that is delimited by period (".") rather than
       
   547         // slash ("/") so convert to newer style.
       
   548         TString path = Helpers::ReplaceString(Appid, _T("."), _T("/"));
       
   549 
       
   550         path = path + _T("/JVMUserOptions");
       
   551         TString domainName;
       
   552         std::list<TString> keys = Split(path, _T("/"));
       
   553 
       
   554         // If there are less than three parts to the path then use the default preferences file.
       
   555         if (keys.size() < 3) {
       
   556             domainName = _T("com.apple.java.util.prefs");
       
   557 
       
   558             // Append slash to the end of each key.
       
   559             for (std::list<TString>::iterator iterator = keys.begin(); iterator != keys.end(); iterator++) {
       
   560                 TString item = *iterator;
       
   561                 item = item + _T("/");
       
   562                 *iterator = item;
       
   563             }
       
   564 
       
   565             // The root key is /.
       
   566             keys.push_front(_T("/"));
       
   567         }
       
   568         else {
       
   569             // Remove the first three keys and use them for the root key and the preferencesID.
       
   570             TString one = keys.front();
       
   571             keys.pop_front();
       
   572             TString two = keys.front();
       
   573             keys.pop_front();
       
   574             TString three = keys.front();
       
   575             keys.pop_front();
       
   576             domainName = one + TString(".") + two + TString(".") + three;
       
   577             domainName = toLowerCase(domainName);
       
   578 
       
   579             // Append slash to the end of each key.
       
   580             for (std::list<TString>::iterator iterator = keys.begin(); iterator != keys.end(); iterator++) {
       
   581                 TString item = *iterator;
       
   582                 item = item + _T("/");
       
   583                 *iterator = item;
       
   584             }
       
   585 
       
   586             // The root key is /one/two/three/
       
   587             TString key = TString("/") + one + TString("/") + two + TString("/") + three + TString("/");
       
   588             keys.push_front(key);
       
   589         }
       
   590 
       
   591         UserDefaults userDefaults(domainName);
       
   592 
       
   593         if (userDefaults.Read(keys) == true) {
       
   594             result = true;
       
   595             FMap = userDefaults.GetData();
       
   596         }
       
   597     }
       
   598 
       
   599     return result;
       
   600 }
       
   601 
       
   602 //--------------------------------------------------------------------------------------------------
       
   603 
       
   604 #endif //MAC