|
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 |