CF_EXPORT CFStringRef CFBundleCopyLocalizedStringForLocalization(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName, CFStringRef localizationName) {
    if (!key) { return (value ? (CFStringRef)CFRetain(value) : (CFStringRef)CFRetain(CFSTR(""))); }
    
    // Make sure to check the mixed localizations key early -- if the main bundle has not yet been cached, then we need to create the cache of the Info.plist before we start asking for resources (11172381)
    (void)CFBundleAllowMixedLocalizations();
    
    if (!tableName || CFEqual(tableName, CFSTR(""))) tableName = _CFBundleDefaultStringTableName;
    
    CFStringRef result = _copyStringFromTable(bundle, tableName, key, localizationName);
    
    if (!result) {
        if (!value) {
            result = (CFStringRef)CFRetain(key);
        } else if (CFEqual(value, CFSTR(""))) {
            result = (CFStringRef)CFRetain(key);
        } else {
            result = (CFStringRef)CFRetain(value);
        }
        static Boolean capitalize = false;
        if (capitalize) {
            CFMutableStringRef capitalizedResult = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, result);
            os_log_error(_CFBundleLocalizedStringLogger(), "ERROR: %@ not found in table %@ of bundle %@", key, tableName, bundle);
            CFStringUppercase(capitalizedResult, NULL);
            CFRelease(result);
            result = capitalizedResult;
        }
    }
    os_log_debug(_CFBundleLocalizedStringLogger(), "Bundle: %{private}@, key: %{public}@, value: %{public}@, table: %{public}@, localizationName: %{public}@, result: %{public}@", bundle, key, value, tableName, localizationName, result);
    return result;
}
Example #2
0
void
mono_log_write_asl (const char *log_domain, GLogLevelFlags level, mono_bool hdr, const char *message)
{
	switch (level & G_LOG_LEVEL_MASK)
	{
		case G_LOG_LEVEL_MESSAGE:
			os_log (OS_LOG_DEFAULT, "%s%s%s\n",
				log_domain != NULL ? log_domain : "",
				log_domain != NULL ? ": " : "",
				message);
			break;
		case G_LOG_LEVEL_INFO:
			os_log_info (OS_LOG_DEFAULT, "%s%s%s\n",
				log_domain != NULL ? log_domain : "",
				log_domain != NULL ? ": " : "",
				message);
			break;
		case G_LOG_LEVEL_DEBUG:
			os_log_debug (OS_LOG_DEFAULT, "%s%s%s\n",
				log_domain != NULL ? log_domain : "",
				log_domain != NULL ? ": " : "",
				message);
			break;
		case G_LOG_LEVEL_ERROR:
		case G_LOG_LEVEL_WARNING:
			os_log_error (OS_LOG_DEFAULT, "%s%s%s\n",
				log_domain != NULL ? log_domain : "",
				log_domain != NULL ? ": " : "",
				message);
		case G_LOG_LEVEL_CRITICAL:
		default:
			os_log_fault (OS_LOG_DEFAULT, "%s%s%s\n",
				log_domain != NULL ? log_domain : "",
				log_domain != NULL ? ": " : "",
				message);
			break;
	}

	if (level & G_LOG_LEVEL_ERROR)
		abort();
}
static CFStringRef _copyStringFromTable(CFBundleRef bundle, CFStringRef tableName, CFStringRef key, CFStringRef localizationName) {
    // Check the cache first. If it's not there, populate the cache and check again.
    
    __CFLock(&bundle->_lock);
    // Only consult the cache when a specific localization has not been requested. We only cache results for the preferred language as determined by normal bundle lookup rules.
    if (!localizationName && bundle->_stringTable) {
        CFDictionaryRef stringTable = (CFDictionaryRef)CFDictionaryGetValue(bundle->_stringTable, tableName);
        if (stringTable) {
            CFStringRef result = CFDictionaryGetValue(stringTable, key);
            if (result) {
                CFRetain(result);
            }
            __CFUnlock(&bundle->_lock);
            return result;
        }
    }

    // Not in the local cache, so load the table. Unlock so we don't hold the lock across file system access.
    __CFUnlock(&bundle->_lock);

    CFDictionaryRef stringsTable = NULL;
    CFURLRef stringsTableURL = NULL;
    CFURLRef stringsDictTableURL = NULL;
    
    // Find the resource URL.
    if (localizationName) {
        stringsTableURL = CFBundleCopyResourceURLForLocalization(bundle, tableName, _CFBundleStringTableType, NULL, localizationName);
        stringsDictTableURL = CFBundleCopyResourceURLForLocalization(bundle, tableName, _CFBundleStringDictTableType, NULL, localizationName);
    } else {
        stringsTableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL);
        stringsDictTableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringDictTableType, NULL);
    }
    
    
    // Next, look on disk for the regular strings file.
    if (!stringsTable && stringsTableURL) {
        CFDataRef tableData = _CFDataCreateFromURL(stringsTableURL, NULL);
        if (tableData) {
            CFErrorRef error = NULL;
            stringsTable = (CFDictionaryRef)CFPropertyListCreateWithData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, NULL, &error);
            CFRelease(tableData);
            
            if (stringsTable && CFDictionaryGetTypeID() != CFGetTypeID(stringsTable)) {
                os_log_error(_CFBundleLocalizedStringLogger(), "Unable to load .strings file: %@ / %@: Top-level object was not a dictionary", bundle, tableName);
                CFRelease(stringsTable);
                stringsTable = NULL;
            } else if (!stringsTable && error) {
                os_log_error(_CFBundleLocalizedStringLogger(), "Unable to load .strings file: %@ / %@: %@", bundle, tableName, error);
                CFRelease(error);
                error = NULL;
            }
        }
        
    }
    
    // Check for a .stringsdict file.
    if (stringsDictTableURL) {
        CFDataRef tableData = _CFDataCreateFromURL(stringsDictTableURL, NULL);
        if (tableData) {
            CFErrorRef error = NULL;
            CFDictionaryRef stringsDictTable = (CFDictionaryRef)CFPropertyListCreateWithData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, NULL, &error);
            CFRelease(tableData);
            
            if (!stringsDictTable && error) {
                os_log_error(_CFBundleLocalizedStringLogger(), "Unable to load .stringsdict file: %@ / %@: %@", bundle, tableName, error);
                CFRelease(error);
                error = NULL;
            } else if (stringsDictTable && CFDictionaryGetTypeID() != CFGetTypeID(stringsDictTable)) {
                os_log_error(_CFBundleLocalizedStringLogger(), "Unable to load .stringsdict file: %@ / %@: Top-level object was not a dictionary", bundle, tableName);
                CFRelease(stringsDictTable);
                stringsDictTable = NULL;
            } else if (stringsDictTable) {
                // Post-process the strings table.
                CFMutableDictionaryRef mutableStringsDictTable;
                if (stringsTable) {
                    // Any strings that are in the stringsTable that are not in the stringsDict must be added to the stringsDict.
                    // However, any entry in the stringsDictTable must override the content from stringsTable.
                    
                    // Start by copying the stringsTable.
                    mutableStringsDictTable = CFDictionaryCreateMutableCopy(NULL, 0, stringsTable);
                    
                    // Replace any stringsTable entries with entries from stringsDictTable. This will override any entries from the original stringsTable if they existed.
                    CFDictionaryApplyFunction(stringsDictTable, __CFStringsDictMergeApplyFunction, mutableStringsDictTable);
                } else {
                    // Start with a copy of the stringsDictTable on its own.
                    mutableStringsDictTable = CFDictionaryCreateMutableCopy(NULL, 0, stringsDictTable);
                }
                
                CFRelease(stringsDictTable);

                if (stringsTable) CFRelease(stringsTable);
                // The new strings table is the result of all the transforms above.
                stringsTable = mutableStringsDictTable;
            }
        }
    }
    
    if (stringsTableURL) CFRelease(stringsTableURL);
    if (stringsDictTableURL) CFRelease(stringsDictTableURL);
    
    // Last resort: create an empty table
    if (!stringsTable) {
        os_log_debug(_CFBundleLocalizedStringLogger(), "Hit last resort and creating empty strings table");
        stringsTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    }
    
    // Insert the result into our local cache
    if ((!CFStringHasSuffix(tableName, CFSTR(".nocache")) || !_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) && localizationName == NULL) {
        // Take lock again, because this we will unlock after getting the value out of the table.
        __CFLock(&bundle->_lock);
        if (!bundle->_stringTable) bundle->_stringTable = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        
        // If another thread beat us to setting this tableName, then we'll just replace it here.
        CFDictionarySetValue(bundle->_stringTable, tableName, stringsTable);
    } else {
        // Take lock again, because this we will unlock after getting the value out of the table.
        __CFLock(&bundle->_lock);
    }
    
    // Finally, fetch the result from the table
    CFStringRef result = CFDictionaryGetValue(stringsTable, key);
    if (result) {
        CFRetain(result);
    }
    __CFUnlock(&bundle->_lock);

    CFRelease(stringsTable);
    
    return result;
}