From 20f4ff436e3ba78b03defd8ea04214425075553f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Fri, 11 Aug 2023 22:11:22 +0200 Subject: [PATCH] Enable Automatic Reference Counting (ARC) for Objective-C code that needs it (#90379) We noticed that ARC isn't enabled for System.Globalization.Native code but we aren't properly doing manual memory management by calling `release`. Enable ARC for the System.Globalization.Native ObjC code so it is handled automatically by the compiler. Disable it for System.Native code since that one is less complex and we can manually manage it. We need to wrap all public entrypoints to the library in `@autoreleasepool` blocks so that the releasing of autoreleased objects occurs at the end of the block, rather than at some undetermined point in the future (and we don't even know if we have an autorelease pool in the thread). --- src/mono/mono/mini/CMakeLists.txt | 2 +- .../CMakeLists.txt | 9 +- .../pal_calendarData.m | 147 ++--- .../System.Globalization.Native/pal_casing.m | 102 ++-- .../pal_collation.m | 304 +++++----- .../System.Globalization.Native/pal_locale.m | 552 +++++++++--------- src/native/libs/System.Native/CMakeLists.txt | 79 ++- src/native/libs/System.Native/entrypoints.c | 1 + .../libs/System.Native/pal_autoreleasepool.m | 4 + src/native/libs/System.Native/pal_datetime.c | 6 + src/native/libs/System.Native/pal_datetime.h | 2 - src/native/libs/System.Native/pal_datetime.m | 4 + .../libs/System.Native/pal_environment.m | 4 + .../System.Native/pal_iossupportversion.m | 16 +- src/native/libs/System.Native/pal_log.m | 4 + .../libs/System.Native/pal_searchpath.m | 4 + 16 files changed, 661 insertions(+), 579 deletions(-) diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index 4ed9d8bfba7..884b43c1b1e 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -83,7 +83,7 @@ if(HAVE_SYS_ICU) set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_DEFINITIONS OSX_ICU_LIBRARY_PATH="${OSX_ICU_LIBRARY_PATH}") set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_FLAGS "-I\"${ICU_INCLUDEDIR}\" -I\"${CLR_SRC_NATIVE_DIR}/libs/System.Globalization.Native/\" -I\"${CLR_SRC_NATIVE_DIR}/libs/Common/\" ${ICU_FLAGS}") if(TARGET_DARWIN) - set_property(SOURCE ${icu_shim_darwin_sources} APPEND_STRING PROPERTY COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") + set_property(SOURCE ${icu_shim_darwin_sources} APPEND_STRING PROPERTY COMPILE_FLAGS " -fobjc-arc ${CLR_CMAKE_COMMON_OBJC_FLAGS}") endif() if(TARGET_WIN32) set_source_files_properties(${icu_shim_sources} PROPERTIES LANGUAGE CXX) diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt index 83ec10d583e..0545ace30f4 100644 --- a/src/native/libs/System.Globalization.Native/CMakeLists.txt +++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt @@ -93,8 +93,13 @@ else() endif() if (CLR_CMAKE_TARGET_APPLE) - set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_locale.m pal_collation.m pal_casing.m pal_calendarData.m) - set_source_files_properties(pal_locale.m pal_collation.m pal_casing.m pal_calendarData.m PROPERTIES COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") + set(NATIVEGLOBALIZATION_SOURCES_OBJC + pal_locale.m + pal_collation.m + pal_casing.m + pal_calendarData.m) + set_source_files_properties(${NATIVEGLOBALIZATION_SOURCES_OBJC} PROPERTIES COMPILE_FLAGS "-fobjc-arc ${CLR_CMAKE_COMMON_OBJC_FLAGS}") + set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} ${NATIVEGLOBALIZATION_SOURCES_OBJC}) endif() # time zone names are filtered out of icu data for the browser and associated functionality is disabled diff --git a/src/native/libs/System.Globalization.Native/pal_calendarData.m b/src/native/libs/System.Globalization.Native/pal_calendarData.m index 307590dfc7a..c17c8f343dd 100644 --- a/src/native/libs/System.Globalization.Native/pal_calendarData.m +++ b/src/native/libs/System.Globalization.Native/pal_calendarData.m @@ -6,6 +6,10 @@ #include "pal_calendarData.h" #import +#if !__has_feature(objc_arc) +#error This file relies on ARC for memory management, but ARC is not enabled. +#endif + #if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS) /* @@ -55,83 +59,86 @@ with the requested value. */ const char* GlobalizationNative_GetCalendarInfoNative(const char* localeName, CalendarId calendarId, CalendarDataType dataType) { - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - - if (dataType == CalendarData_MonthDay) + @autoreleasepool { - NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMMd" options:0 locale:currentLocale]; - return formatString ? strdup([formatString UTF8String]) : NULL; - } - else if (dataType == CalendarData_YearMonths) - { - NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMM yyyy" options:0 locale:currentLocale]; - return formatString ? strdup([formatString UTF8String]) : NULL; - } + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - NSString *calendarIdentifier = GetCalendarIdentifier(calendarId); - NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]; + if (dataType == CalendarData_MonthDay) + { + NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMMd" options:0 locale:currentLocale]; + return formatString ? strdup([formatString UTF8String]) : NULL; + } + else if (dataType == CalendarData_YearMonths) + { + NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"MMMM yyyy" options:0 locale:currentLocale]; + return formatString ? strdup([formatString UTF8String]) : NULL; + } - if (dataType == CalendarData_NativeName) - return calendar ? strdup([[calendar calendarIdentifier] UTF8String]) : NULL; + NSString *calendarIdentifier = GetCalendarIdentifier(calendarId); + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]; - NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; - dateFormat.locale = currentLocale; - dateFormat.calendar = calendar; + if (dataType == CalendarData_NativeName) + return calendar ? strdup([[calendar calendarIdentifier] UTF8String]) : NULL; - NSArray *result; - switch (dataType) - { - case CalendarData_ShortDates: - { - [dateFormat setDateStyle:NSDateFormatterShortStyle]; - NSString *shortFormatString = [dateFormat dateFormat]; - [dateFormat setDateStyle:NSDateFormatterMediumStyle]; - NSString *mediumFormatString = [dateFormat dateFormat]; - NSString *yearMonthDayFormat = [NSDateFormatter dateFormatFromTemplate:@"yMd" options:0 locale:currentLocale]; - result = @[shortFormatString, mediumFormatString, yearMonthDayFormat]; - break; - } - case CalendarData_LongDates: + NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; + dateFormat.locale = currentLocale; + dateFormat.calendar = calendar; + + NSArray *result; + switch (dataType) { - [dateFormat setDateStyle:NSDateFormatterLongStyle]; - NSString *longFormatString = [dateFormat dateFormat]; - [dateFormat setDateStyle:NSDateFormatterFullStyle]; - NSString *fullFormatString = [dateFormat dateFormat]; - result = @[longFormatString, fullFormatString]; - break; + case CalendarData_ShortDates: + { + [dateFormat setDateStyle:NSDateFormatterShortStyle]; + NSString *shortFormatString = [dateFormat dateFormat]; + [dateFormat setDateStyle:NSDateFormatterMediumStyle]; + NSString *mediumFormatString = [dateFormat dateFormat]; + NSString *yearMonthDayFormat = [NSDateFormatter dateFormatFromTemplate:@"yMd" options:0 locale:currentLocale]; + result = @[shortFormatString, mediumFormatString, yearMonthDayFormat]; + break; + } + case CalendarData_LongDates: + { + [dateFormat setDateStyle:NSDateFormatterLongStyle]; + NSString *longFormatString = [dateFormat dateFormat]; + [dateFormat setDateStyle:NSDateFormatterFullStyle]; + NSString *fullFormatString = [dateFormat dateFormat]; + result = @[longFormatString, fullFormatString]; + break; + } + case CalendarData_DayNames: + result = [dateFormat standaloneWeekdaySymbols]; + break; + case CalendarData_AbbrevDayNames: + result = [dateFormat shortStandaloneWeekdaySymbols]; + break; + case CalendarData_MonthNames: + result = [dateFormat standaloneMonthSymbols]; + break; + case CalendarData_AbbrevMonthNames: + result = [dateFormat shortStandaloneMonthSymbols]; + break; + case CalendarData_SuperShortDayNames: + result = [dateFormat veryShortStandaloneWeekdaySymbols]; + break; + case CalendarData_MonthGenitiveNames: + result = [dateFormat monthSymbols]; + break; + case CalendarData_AbbrevMonthGenitiveNames: + result = [dateFormat shortMonthSymbols]; + break; + case CalendarData_EraNames: + case CalendarData_AbbrevEraNames: + result = [dateFormat eraSymbols]; + break; + default: + assert(false); + return NULL; } - case CalendarData_DayNames: - result = [dateFormat standaloneWeekdaySymbols]; - break; - case CalendarData_AbbrevDayNames: - result = [dateFormat shortStandaloneWeekdaySymbols]; - break; - case CalendarData_MonthNames: - result = [dateFormat standaloneMonthSymbols]; - break; - case CalendarData_AbbrevMonthNames: - result = [dateFormat shortStandaloneMonthSymbols]; - break; - case CalendarData_SuperShortDayNames: - result = [dateFormat veryShortStandaloneWeekdaySymbols]; - break; - case CalendarData_MonthGenitiveNames: - result = [dateFormat monthSymbols]; - break; - case CalendarData_AbbrevMonthGenitiveNames: - result = [dateFormat shortMonthSymbols]; - break; - case CalendarData_EraNames: - case CalendarData_AbbrevEraNames: - result = [dateFormat eraSymbols]; - break; - default: - assert(false); - return NULL; - } - NSString *arrayToString = [[result valueForKey:@"description"] componentsJoinedByString:@"||"]; - return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + NSString *arrayToString = [[result valueForKey:@"description"] componentsJoinedByString:@"||"]; + return arrayToString ? strdup([arrayToString UTF8String]) : NULL; + } } #endif diff --git a/src/native/libs/System.Globalization.Native/pal_casing.m b/src/native/libs/System.Globalization.Native/pal_casing.m index eec471f9ab6..16467e6b9cb 100644 --- a/src/native/libs/System.Globalization.Native/pal_casing.m +++ b/src/native/libs/System.Globalization.Native/pal_casing.m @@ -7,6 +7,10 @@ #import +#if !__has_feature(objc_arc) +#error This file relies on ARC for memory management, but ARC is not enabled. +#endif + #if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS) /** @@ -97,39 +101,42 @@ Returns 0 for success, non-zero on failure see ErrorCodes. int32_t GlobalizationNative_ChangeCaseNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpSrc, int32_t cwSrcLength, uint16_t* lpDst, int32_t cwDstLength, int32_t bToUpper) { - NSLocale *currentLocale; - if(localeName == NULL || lNameLength == 0) + @autoreleasepool { - currentLocale = [NSLocale systemLocale]; - } - else - { - NSString *locName = [NSString stringWithCharacters: localeName length: lNameLength]; - currentLocale = [NSLocale localeWithLocaleIdentifier:locName]; - } + NSLocale *currentLocale; + if(localeName == NULL || lNameLength == 0) + { + currentLocale = [NSLocale systemLocale]; + } + else + { + NSString *locName = [NSString stringWithCharacters: localeName length: lNameLength]; + currentLocale = [NSLocale localeWithLocaleIdentifier:locName]; + } - int32_t srcIdx = 0, dstIdx = 0, isError = 0; - uint16_t dstCodepoint; - while (srcIdx < cwSrcLength) - { - int32_t startIndex = srcIdx; - NEXTOFFSET(lpSrc, srcIdx, cwSrcLength); - int32_t srcLength = srcIdx - startIndex; - NSString *src = [NSString stringWithCharacters: lpSrc + startIndex length: srcLength]; - NSString *dst = bToUpper ? [src uppercaseStringWithLocale:currentLocale] : [src lowercaseStringWithLocale:currentLocale]; - int32_t index = 0; - // iterate over all code points of a surrogate pair character - while (index < srcLength) + int32_t srcIdx = 0, dstIdx = 0, isError = 0; + uint16_t dstCodepoint; + while (srcIdx < cwSrcLength) { - // the dst.length > srcLength is to prevent code point expansions - dstCodepoint = dst.length > srcLength ? [src characterAtIndex: index] : [dst characterAtIndex: index]; - Append(lpDst, dstIdx, cwDstLength, dstCodepoint, isError); - index++; + int32_t startIndex = srcIdx; + NEXTOFFSET(lpSrc, srcIdx, cwSrcLength); + int32_t srcLength = srcIdx - startIndex; + NSString *src = [NSString stringWithCharacters: lpSrc + startIndex length: srcLength]; + NSString *dst = bToUpper ? [src uppercaseStringWithLocale:currentLocale] : [src lowercaseStringWithLocale:currentLocale]; + int32_t index = 0; + // iterate over all code points of a surrogate pair character + while (index < srcLength) + { + // the dst.length > srcLength is to prevent code point expansions + dstCodepoint = dst.length > srcLength ? [src characterAtIndex: index] : [dst characterAtIndex: index]; + Append(lpDst, dstIdx, cwDstLength, dstCodepoint, isError); + index++; + } + if (isError) + return isError; } - if (isError) - return isError; + return Success; } - return Success; } /* @@ -146,28 +153,31 @@ Returns 0 for success, non-zero on failure see ErrorCodes. */ int32_t GlobalizationNative_ChangeCaseInvariantNative(const uint16_t* lpSrc, int32_t cwSrcLength, uint16_t* lpDst, int32_t cwDstLength, int32_t bToUpper) { - int32_t srcIdx = 0, dstIdx = 0, isError = 0; - uint16_t dstCodepoint; - while (srcIdx < cwSrcLength) + @autoreleasepool { - int32_t startIndex = srcIdx; - NEXTOFFSET(lpSrc, srcIdx, cwSrcLength); - int32_t srcLength = srcIdx - startIndex; - NSString *src = [NSString stringWithCharacters: lpSrc + startIndex length: srcLength]; - NSString *dst = bToUpper ? src.uppercaseString : src.lowercaseString; - int32_t index = 0; - // iterate over all code points of a surrogate pair character - while (index < srcLength) + int32_t srcIdx = 0, dstIdx = 0, isError = 0; + uint16_t dstCodepoint; + while (srcIdx < cwSrcLength) { - // the dst.length > srcLength is to prevent code point expansions - dstCodepoint = dst.length > srcLength ? [src characterAtIndex: index] : [dst characterAtIndex: index]; - Append(lpDst, dstIdx, cwDstLength, dstCodepoint, isError); - index++; + int32_t startIndex = srcIdx; + NEXTOFFSET(lpSrc, srcIdx, cwSrcLength); + int32_t srcLength = srcIdx - startIndex; + NSString *src = [NSString stringWithCharacters: lpSrc + startIndex length: srcLength]; + NSString *dst = bToUpper ? src.uppercaseString : src.lowercaseString; + int32_t index = 0; + // iterate over all code points of a surrogate pair character + while (index < srcLength) + { + // the dst.length > srcLength is to prevent code point expansions + dstCodepoint = dst.length > srcLength ? [src characterAtIndex: index] : [dst characterAtIndex: index]; + Append(lpDst, dstIdx, cwDstLength, dstCodepoint, isError); + index++; + } + if (isError) + return isError; } - if (isError) - return isError; + return Success; } - return Success; } #endif diff --git a/src/native/libs/System.Globalization.Native/pal_collation.m b/src/native/libs/System.Globalization.Native/pal_collation.m index ac59a428aa4..0c7872725af 100644 --- a/src/native/libs/System.Globalization.Native/pal_collation.m +++ b/src/native/libs/System.Globalization.Native/pal_collation.m @@ -7,6 +7,10 @@ #import +#if !__has_feature(objc_arc) +#error This file relies on ARC for memory management, but ARC is not enabled. +#endif + #if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS) // Enum that corresponds to C# CompareOptions @@ -70,23 +74,26 @@ CompareString int32_t GlobalizationNative_CompareStringNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpSource, int32_t cwSourceLength, const uint16_t* lpTarget, int32_t cwTargetLength, int32_t comparisonOptions) { - NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); - NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; - NSString *sourceStrPrecomposed = sourceString.precomposedStringWithCanonicalMapping; - NSString *targetString = [NSString stringWithCharacters: lpTarget length: cwTargetLength]; - NSString *targetStrPrecomposed = targetString.precomposedStringWithCanonicalMapping; - - NSRange comparisonRange = NSMakeRange(0, sourceStrPrecomposed.length); - NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); - - // in case mapping is not found - if (options == 0) - return ERROR_COMPARISON_OPTIONS_NOT_FOUND; - - return [sourceStrPrecomposed compare:targetStrPrecomposed - options:options - range:comparisonRange - locale:currentLocale]; + @autoreleasepool + { + NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); + NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; + NSString *sourceStrPrecomposed = sourceString.precomposedStringWithCanonicalMapping; + NSString *targetString = [NSString stringWithCharacters: lpTarget length: cwTargetLength]; + NSString *targetStrPrecomposed = targetString.precomposedStringWithCanonicalMapping; + + NSRange comparisonRange = NSMakeRange(0, sourceStrPrecomposed.length); + NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); + + // in case mapping is not found + if (options == 0) + return ERROR_COMPARISON_OPTIONS_NOT_FOUND; + + return [sourceStrPrecomposed compare:targetStrPrecomposed + options:options + range:comparisonRange + locale:currentLocale]; + } } static NSString* RemoveWeightlessCharacters(NSString* source) @@ -120,109 +127,112 @@ Find detailed explanation how this function works in https://github.com/dotnet/r Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpTarget, int32_t cwTargetLength, const uint16_t* lpSource, int32_t cwSourceLength, int32_t comparisonOptions, int32_t fromBeginning) { - assert(cwTargetLength >= 0); - Range result = {ERROR_INDEX_NOT_FOUND, 0}; - NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); - - // in case mapping is not found - if (options == 0) + @autoreleasepool { - result.location = ERROR_COMPARISON_OPTIONS_NOT_FOUND; + assert(cwTargetLength >= 0); + Range result = {ERROR_INDEX_NOT_FOUND, 0}; + NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); + + // in case mapping is not found + if (options == 0) + { + result.location = ERROR_COMPARISON_OPTIONS_NOT_FOUND; + return result; + } + + NSString *searchString = [NSString stringWithCharacters: lpTarget length: cwTargetLength]; + NSString *searchStrCleaned = RemoveWeightlessCharacters(searchString); + NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; + NSString *sourceStrCleaned = RemoveWeightlessCharacters(sourceString); + + if (sourceStrCleaned.length == 0 || searchStrCleaned.length == 0) + { + result.location = fromBeginning ? 0 : sourceString.length; return result; - } - - NSString *searchString = [NSString stringWithCharacters: lpTarget length: cwTargetLength]; - NSString *searchStrCleaned = RemoveWeightlessCharacters(searchString); - NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; - NSString *sourceStrCleaned = RemoveWeightlessCharacters(sourceString); + } - if (sourceStrCleaned.length == 0 || searchStrCleaned.length == 0) - { - result.location = fromBeginning ? 0 : sourceString.length; - return result; - } + NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); + NSString *searchStrPrecomposed = searchStrCleaned.precomposedStringWithCanonicalMapping; + NSString *sourceStrPrecomposed = sourceStrCleaned.precomposedStringWithCanonicalMapping; - NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); - NSString *searchStrPrecomposed = searchStrCleaned.precomposedStringWithCanonicalMapping; - NSString *sourceStrPrecomposed = sourceStrCleaned.precomposedStringWithCanonicalMapping; + // last index + if (!fromBeginning) + options |= NSBackwardsSearch; - // last index - if (!fromBeginning) - options |= NSBackwardsSearch; - - // check if there is a possible match and return -1 if not - // doesn't matter which normalization form is used here - NSRange rangeOfReceiverToSearch = NSMakeRange(0, sourceStrPrecomposed.length); - NSRange containsRange = [sourceStrPrecomposed rangeOfString:searchStrPrecomposed - options:options - range:rangeOfReceiverToSearch - locale:currentLocale]; - - if (containsRange.location == NSNotFound) - return result; + // check if there is a possible match and return -1 if not + // doesn't matter which normalization form is used here + NSRange rangeOfReceiverToSearch = NSMakeRange(0, sourceStrPrecomposed.length); + NSRange containsRange = [sourceStrPrecomposed rangeOfString:searchStrPrecomposed + options:options + range:rangeOfReceiverToSearch + locale:currentLocale]; - // in case search string is inside source string but we can't find the index return -3 - result.location = ERROR_MIXED_COMPOSITION_NOT_FOUND; - // sourceString and searchString possibly have the same composition of characters - rangeOfReceiverToSearch = NSMakeRange(0, sourceStrCleaned.length); - NSRange nsRange = [sourceStrCleaned rangeOfString:searchStrCleaned - options:options - range:rangeOfReceiverToSearch - locale:currentLocale]; - - if (nsRange.location != NSNotFound) - { - result.location = nsRange.location; - result.length = nsRange.length; - // in case of CompareOptions.IgnoreCase if letters have different representations in source and search strings - // and case insensitive search appears more than one time in source string take last index for LastIndexOf and first index for IndexOf - // e.g. new CultureInfo().CompareInfo.LastIndexOf("Is \u0055\u0308 or \u0075\u0308 the same as \u00DC or \u00FC?", "U\u0308", 25,18, CompareOptions.IgnoreCase); - // should return 24 but here it will be 9 - if (!(comparisonOptions & IgnoreCase)) + if (containsRange.location == NSNotFound) return result; - } - // check if sourceString has precomposed form of characters and searchString has decomposed form of characters - // convert searchString to a precomposed form - NSRange precomposedRange = [sourceStrCleaned rangeOfString:searchStrPrecomposed - options:options - range:rangeOfReceiverToSearch - locale:currentLocale]; - - if (precomposedRange.location != NSNotFound) - { - // in case of CompareOptions.IgnoreCase if letters have different representations in source and search strings - // and search appears more than one time in source string take last index for LastIndexOf and first index for IndexOf - // e.g. new CultureInfo().CompareInfo.LastIndexOf("Is \u0055\u0308 or \u0075\u0308 the same as \u00DC or \u00FC?", "U\u0308", 25,18, CompareOptions.IgnoreCase); - // this will return 24 - if ((comparisonOptions & IgnoreCase) && IsIndexFound(fromBeginning, (int32_t)result.location, (int32_t)precomposedRange.location)) + // in case search string is inside source string but we can't find the index return -3 + result.location = ERROR_MIXED_COMPOSITION_NOT_FOUND; + // sourceString and searchString possibly have the same composition of characters + rangeOfReceiverToSearch = NSMakeRange(0, sourceStrCleaned.length); + NSRange nsRange = [sourceStrCleaned rangeOfString:searchStrCleaned + options:options + range:rangeOfReceiverToSearch + locale:currentLocale]; + + if (nsRange.location != NSNotFound) + { + result.location = nsRange.location; + result.length = nsRange.length; + // in case of CompareOptions.IgnoreCase if letters have different representations in source and search strings + // and case insensitive search appears more than one time in source string take last index for LastIndexOf and first index for IndexOf + // e.g. new CultureInfo().CompareInfo.LastIndexOf("Is \u0055\u0308 or \u0075\u0308 the same as \u00DC or \u00FC?", "U\u0308", 25,18, CompareOptions.IgnoreCase); + // should return 24 but here it will be 9 + if (!(comparisonOptions & IgnoreCase)) + return result; + } + + // check if sourceString has precomposed form of characters and searchString has decomposed form of characters + // convert searchString to a precomposed form + NSRange precomposedRange = [sourceStrCleaned rangeOfString:searchStrPrecomposed + options:options + range:rangeOfReceiverToSearch + locale:currentLocale]; + + if (precomposedRange.location != NSNotFound) + { + // in case of CompareOptions.IgnoreCase if letters have different representations in source and search strings + // and search appears more than one time in source string take last index for LastIndexOf and first index for IndexOf + // e.g. new CultureInfo().CompareInfo.LastIndexOf("Is \u0055\u0308 or \u0075\u0308 the same as \u00DC or \u00FC?", "U\u0308", 25,18, CompareOptions.IgnoreCase); + // this will return 24 + if ((comparisonOptions & IgnoreCase) && IsIndexFound(fromBeginning, (int32_t)result.location, (int32_t)precomposedRange.location)) + return result; + + result.location = precomposedRange.location; + result.length = precomposedRange.length; + if (!(comparisonOptions & IgnoreCase)) return result; - - result.location = precomposedRange.location; - result.length = precomposedRange.length; - if (!(comparisonOptions & IgnoreCase)) - return result; - } - - // check if sourceString has decomposed form of characters and searchString has precomposed form of characters - // convert searchString to a decomposed form - NSString *searchStrDecomposed = searchStrCleaned.decomposedStringWithCanonicalMapping; - NSRange decomposedRange = [sourceStrCleaned rangeOfString:searchStrDecomposed - options:options - range:rangeOfReceiverToSearch - locale:currentLocale]; - - if (decomposedRange.location != NSNotFound) - { - if ((comparisonOptions & IgnoreCase) && IsIndexFound(fromBeginning, (int32_t)result.location, (int32_t)decomposedRange.location)) + } + + // check if sourceString has decomposed form of characters and searchString has precomposed form of characters + // convert searchString to a decomposed form + NSString *searchStrDecomposed = searchStrCleaned.decomposedStringWithCanonicalMapping; + NSRange decomposedRange = [sourceStrCleaned rangeOfString:searchStrDecomposed + options:options + range:rangeOfReceiverToSearch + locale:currentLocale]; + + if (decomposedRange.location != NSNotFound) + { + if ((comparisonOptions & IgnoreCase) && IsIndexFound(fromBeginning, (int32_t)result.location, (int32_t)decomposedRange.location)) + return result; + + result.location = decomposedRange.location; + result.length = decomposedRange.length; return result; + } - result.location = decomposedRange.location; - result.length = decomposedRange.length; return result; } - - return result; } /* @@ -231,25 +241,28 @@ Range GlobalizationNative_IndexOfNative(const uint16_t* localeName, int32_t lNam int32_t GlobalizationNative_StartsWithNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpPrefix, int32_t cwPrefixLength, const uint16_t* lpSource, int32_t cwSourceLength, int32_t comparisonOptions) { - NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); - - // in case mapping is not found - if (options == 0) - return ERROR_COMPARISON_OPTIONS_NOT_FOUND; - - NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); - NSString *prefixString = [NSString stringWithCharacters: lpPrefix length: cwPrefixLength]; - NSString *prefixStrComposed = RemoveWeightlessCharacters(prefixString.precomposedStringWithCanonicalMapping); - NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; - NSString *sourceStrComposed = RemoveWeightlessCharacters(sourceString.precomposedStringWithCanonicalMapping); - - NSRange sourceRange = NSMakeRange(0, prefixStrComposed.length > sourceStrComposed.length ? sourceStrComposed.length : prefixStrComposed.length); + @autoreleasepool + { + NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); - int32_t result = [sourceStrComposed compare:prefixStrComposed - options:options - range:sourceRange - locale:currentLocale]; - return result == NSOrderedSame ? 1 : 0; + // in case mapping is not found + if (options == 0) + return ERROR_COMPARISON_OPTIONS_NOT_FOUND; + + NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); + NSString *prefixString = [NSString stringWithCharacters: lpPrefix length: cwPrefixLength]; + NSString *prefixStrComposed = RemoveWeightlessCharacters(prefixString.precomposedStringWithCanonicalMapping); + NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; + NSString *sourceStrComposed = RemoveWeightlessCharacters(sourceString.precomposedStringWithCanonicalMapping); + + NSRange sourceRange = NSMakeRange(0, prefixStrComposed.length > sourceStrComposed.length ? sourceStrComposed.length : prefixStrComposed.length); + + int32_t result = [sourceStrComposed compare:prefixStrComposed + options:options + range:sourceRange + locale:currentLocale]; + return result == NSOrderedSame ? 1 : 0; + } } /* @@ -258,25 +271,28 @@ int32_t GlobalizationNative_StartsWithNative(const uint16_t* localeName, int32_t int32_t GlobalizationNative_EndsWithNative(const uint16_t* localeName, int32_t lNameLength, const uint16_t* lpSuffix, int32_t cwSuffixLength, const uint16_t* lpSource, int32_t cwSourceLength, int32_t comparisonOptions) { - NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); - - // in case mapping is not found - if (options == 0) - return ERROR_COMPARISON_OPTIONS_NOT_FOUND; - - NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); - NSString *suffixString = [NSString stringWithCharacters: lpSuffix length: cwSuffixLength]; - NSString *suffixStrComposed = RemoveWeightlessCharacters(suffixString.precomposedStringWithCanonicalMapping); - NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; - NSString *sourceStrComposed = RemoveWeightlessCharacters(sourceString.precomposedStringWithCanonicalMapping); - int32_t startIndex = suffixStrComposed.length > sourceStrComposed.length ? 0 : sourceStrComposed.length - suffixStrComposed.length; - NSRange sourceRange = NSMakeRange(startIndex, sourceStrComposed.length - startIndex); - - int32_t result = [sourceStrComposed compare:suffixStrComposed - options:options - range:sourceRange - locale:currentLocale]; - return result == NSOrderedSame ? 1 : 0; + @autoreleasepool + { + NSStringCompareOptions options = ConvertFromCompareOptionsToNSStringCompareOptions(comparisonOptions); + + // in case mapping is not found + if (options == 0) + return ERROR_COMPARISON_OPTIONS_NOT_FOUND; + + NSLocale *currentLocale = GetCurrentLocale(localeName, lNameLength); + NSString *suffixString = [NSString stringWithCharacters: lpSuffix length: cwSuffixLength]; + NSString *suffixStrComposed = RemoveWeightlessCharacters(suffixString.precomposedStringWithCanonicalMapping); + NSString *sourceString = [NSString stringWithCharacters: lpSource length: cwSourceLength]; + NSString *sourceStrComposed = RemoveWeightlessCharacters(sourceString.precomposedStringWithCanonicalMapping); + int32_t startIndex = suffixStrComposed.length > sourceStrComposed.length ? 0 : sourceStrComposed.length - suffixStrComposed.length; + NSRange sourceRange = NSMakeRange(startIndex, sourceStrComposed.length - startIndex); + + int32_t result = [sourceStrComposed compare:suffixStrComposed + options:options + range:sourceRange + locale:currentLocale]; + return result == NSOrderedSame ? 1 : 0; + } } #endif diff --git a/src/native/libs/System.Globalization.Native/pal_locale.m b/src/native/libs/System.Globalization.Native/pal_locale.m index 4f31e359e94..d8ab7da1fbe 100644 --- a/src/native/libs/System.Globalization.Native/pal_locale.m +++ b/src/native/libs/System.Globalization.Native/pal_locale.m @@ -10,6 +10,10 @@ #import #import +#if !__has_feature(objc_arc) +#error This file relies on ARC for memory management, but ARC is not enabled. +#endif + char* DetectDefaultAppleLocaleName(void) { NSLocale *currentLocale = [NSLocale currentLocale]; @@ -36,10 +40,13 @@ char* DetectDefaultAppleLocaleName(void) const char* GlobalizationNative_GetLocaleNameNative(const char* localeName) { - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - const char* value = [currentLocale.localeIdentifier UTF8String]; - return strdup(value); + @autoreleasepool + { + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + const char* value = [currentLocale.localeIdentifier UTF8String]; + return strdup(value); + } } /** @@ -88,140 +95,143 @@ static void GetParent(const char* localeID, char* parent, int32_t parentCapacity const char* GlobalizationNative_GetLocaleInfoStringNative(const char* localeName, LocaleStringData localeStringData) { - const char* value; - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; - numberFormatter.locale = currentLocale; - NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setLocale:currentLocale]; - NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"]; - - switch (localeStringData) + @autoreleasepool { - ///// localized name of locale, eg "German (Germany)" in UI language (corresponds to LOCALE_SLOCALIZEDDISPLAYNAME) - case LocaleString_LocalizedDisplayName: - /// Display name (language + country usually) in English, eg "German (Germany)" (corresponds to LOCALE_SENGLISHDISPLAYNAME) - case LocaleString_EnglishDisplayName: - value = [[gbLocale displayNameForKey:NSLocaleIdentifier value:currentLocale.localeIdentifier] UTF8String]; - break; - /// Display name in native locale language, eg "Deutsch (Deutschland) (corresponds to LOCALE_SNATIVEDISPLAYNAME) - case LocaleString_NativeDisplayName: - value = [[currentLocale displayNameForKey:NSLocaleIdentifier value:currentLocale.localeIdentifier] UTF8String]; - break; - /// Language Display Name for a language, eg "German" in UI language (corresponds to LOCALE_SLOCALIZEDLANGUAGENAME) - case LocaleString_LocalizedLanguageName: - /// English name of language, eg "German" (corresponds to LOCALE_SENGLISHLANGUAGENAME) - case LocaleString_EnglishLanguageName: - value = [[gbLocale localizedStringForLanguageCode:currentLocale.languageCode] UTF8String]; - break; - /// native name of language, eg "Deutsch" (corresponds to LOCALE_SNATIVELANGUAGENAME) - case LocaleString_NativeLanguageName: - value = [[currentLocale localizedStringForLanguageCode:currentLocale.languageCode] UTF8String]; - break; - /// English name of country, eg "Germany" (corresponds to LOCALE_SENGLISHCOUNTRYNAME) - case LocaleString_EnglishCountryName: - value = [[gbLocale localizedStringForCountryCode:currentLocale.countryCode] UTF8String]; - break; - /// native name of country, eg "Deutschland" (corresponds to LOCALE_SNATIVECOUNTRYNAME) - case LocaleString_NativeCountryName: - value = [[currentLocale localizedStringForCountryCode:currentLocale.countryCode] UTF8String]; - break; - case LocaleString_ThousandSeparator: - value = [currentLocale.groupingSeparator UTF8String]; - break; - case LocaleString_DecimalSeparator: - value = [currentLocale.decimalSeparator UTF8String]; - // or value = [[currentLocale objectForKey:NSLocaleDecimalSeparator] UTF8String]; - break; - case LocaleString_Digits: - { - NSString *digitsString = @"0123456789"; - NSNumberFormatter *nf1 = [[NSNumberFormatter alloc] init]; - [nf1 setLocale:currentLocale]; - - NSNumber *newNum = [nf1 numberFromString:digitsString]; - value = [[newNum stringValue] UTF8String]; - break; - } - case LocaleString_MonetarySymbol: - value = [currentLocale.currencySymbol UTF8String]; - break; - case LocaleString_Iso4217MonetarySymbol: - // check if this is correct, check currencyISOCode - value = [currentLocale.currencySymbol UTF8String]; - break; - case LocaleString_CurrencyEnglishName: - value = [[gbLocale localizedStringForCurrencyCode:currentLocale.currencyCode] UTF8String]; - break; - case LocaleString_CurrencyNativeName: - value = [[currentLocale localizedStringForCurrencyCode:currentLocale.currencyCode] UTF8String]; - break; - case LocaleString_MonetaryDecimalSeparator: - value = [numberFormatter.currencyDecimalSeparator UTF8String]; - break; - case LocaleString_MonetaryThousandSeparator: - value = [numberFormatter.currencyGroupingSeparator UTF8String]; - break; - case LocaleString_AMDesignator: - value = [dateFormatter.AMSymbol UTF8String]; - break; - case LocaleString_PMDesignator: - value = [dateFormatter.PMSymbol UTF8String]; - break; - case LocaleString_PositiveSign: - value = [numberFormatter.plusSign UTF8String]; - break; - case LocaleString_NegativeSign: - value = [numberFormatter.minusSign UTF8String]; - break; - case LocaleString_Iso639LanguageTwoLetterName: - value = [[currentLocale objectForKey:NSLocaleLanguageCode] UTF8String]; - break; - case LocaleString_Iso639LanguageThreeLetterName: + const char* value; + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setLocale:currentLocale]; + NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"]; + + switch (localeStringData) { - NSString *iso639_2 = [currentLocale objectForKey:NSLocaleLanguageCode]; - value = uloc_getISO3LanguageByLangCode([iso639_2 UTF8String]); - break; - } - case LocaleString_Iso3166CountryName: - value = [[currentLocale objectForKey:NSLocaleCountryCode] UTF8String]; - break; - case LocaleString_Iso3166CountryName2: - { - const char *countryCode = strdup([[currentLocale objectForKey:NSLocaleCountryCode] UTF8String]); - value = uloc_getISO3CountryByCountryCode(countryCode); - break; - } - case LocaleString_NaNSymbol: - value = [numberFormatter.notANumberSymbol UTF8String]; - break; - case LocaleString_PositiveInfinitySymbol: - value = [numberFormatter.positiveInfinitySymbol UTF8String]; - break; - case LocaleString_NegativeInfinitySymbol: - value = [numberFormatter.negativeInfinitySymbol UTF8String]; - break; - case LocaleString_PercentSymbol: - value = [numberFormatter.percentSymbol UTF8String]; - break; - case LocaleString_PerMilleSymbol: - value = [numberFormatter.perMillSymbol UTF8String]; - break; - case LocaleString_ParentName: - { - char localeNameTemp[FULLNAME_CAPACITY]; - const char* lName = [currentLocale.localeIdentifier UTF8String]; - GetParent(lName, localeNameTemp, FULLNAME_CAPACITY); - value = strdup(localeNameTemp); + ///// localized name of locale, eg "German (Germany)" in UI language (corresponds to LOCALE_SLOCALIZEDDISPLAYNAME) + case LocaleString_LocalizedDisplayName: + /// Display name (language + country usually) in English, eg "German (Germany)" (corresponds to LOCALE_SENGLISHDISPLAYNAME) + case LocaleString_EnglishDisplayName: + value = [[gbLocale displayNameForKey:NSLocaleIdentifier value:currentLocale.localeIdentifier] UTF8String]; + break; + /// Display name in native locale language, eg "Deutsch (Deutschland) (corresponds to LOCALE_SNATIVEDISPLAYNAME) + case LocaleString_NativeDisplayName: + value = [[currentLocale displayNameForKey:NSLocaleIdentifier value:currentLocale.localeIdentifier] UTF8String]; + break; + /// Language Display Name for a language, eg "German" in UI language (corresponds to LOCALE_SLOCALIZEDLANGUAGENAME) + case LocaleString_LocalizedLanguageName: + /// English name of language, eg "German" (corresponds to LOCALE_SENGLISHLANGUAGENAME) + case LocaleString_EnglishLanguageName: + value = [[gbLocale localizedStringForLanguageCode:currentLocale.languageCode] UTF8String]; + break; + /// native name of language, eg "Deutsch" (corresponds to LOCALE_SNATIVELANGUAGENAME) + case LocaleString_NativeLanguageName: + value = [[currentLocale localizedStringForLanguageCode:currentLocale.languageCode] UTF8String]; break; + /// English name of country, eg "Germany" (corresponds to LOCALE_SENGLISHCOUNTRYNAME) + case LocaleString_EnglishCountryName: + value = [[gbLocale localizedStringForCountryCode:currentLocale.countryCode] UTF8String]; + break; + /// native name of country, eg "Deutschland" (corresponds to LOCALE_SNATIVECOUNTRYNAME) + case LocaleString_NativeCountryName: + value = [[currentLocale localizedStringForCountryCode:currentLocale.countryCode] UTF8String]; + break; + case LocaleString_ThousandSeparator: + value = [currentLocale.groupingSeparator UTF8String]; + break; + case LocaleString_DecimalSeparator: + value = [currentLocale.decimalSeparator UTF8String]; + // or value = [[currentLocale objectForKey:NSLocaleDecimalSeparator] UTF8String]; + break; + case LocaleString_Digits: + { + NSString *digitsString = @"0123456789"; + NSNumberFormatter *nf1 = [[NSNumberFormatter alloc] init]; + [nf1 setLocale:currentLocale]; + + NSNumber *newNum = [nf1 numberFromString:digitsString]; + value = [[newNum stringValue] UTF8String]; + break; + } + case LocaleString_MonetarySymbol: + value = [currentLocale.currencySymbol UTF8String]; + break; + case LocaleString_Iso4217MonetarySymbol: + // check if this is correct, check currencyISOCode + value = [currentLocale.currencySymbol UTF8String]; + break; + case LocaleString_CurrencyEnglishName: + value = [[gbLocale localizedStringForCurrencyCode:currentLocale.currencyCode] UTF8String]; + break; + case LocaleString_CurrencyNativeName: + value = [[currentLocale localizedStringForCurrencyCode:currentLocale.currencyCode] UTF8String]; + break; + case LocaleString_MonetaryDecimalSeparator: + value = [numberFormatter.currencyDecimalSeparator UTF8String]; + break; + case LocaleString_MonetaryThousandSeparator: + value = [numberFormatter.currencyGroupingSeparator UTF8String]; + break; + case LocaleString_AMDesignator: + value = [dateFormatter.AMSymbol UTF8String]; + break; + case LocaleString_PMDesignator: + value = [dateFormatter.PMSymbol UTF8String]; + break; + case LocaleString_PositiveSign: + value = [numberFormatter.plusSign UTF8String]; + break; + case LocaleString_NegativeSign: + value = [numberFormatter.minusSign UTF8String]; + break; + case LocaleString_Iso639LanguageTwoLetterName: + value = [[currentLocale objectForKey:NSLocaleLanguageCode] UTF8String]; + break; + case LocaleString_Iso639LanguageThreeLetterName: + { + NSString *iso639_2 = [currentLocale objectForKey:NSLocaleLanguageCode]; + value = uloc_getISO3LanguageByLangCode([iso639_2 UTF8String]); + break; + } + case LocaleString_Iso3166CountryName: + value = [[currentLocale objectForKey:NSLocaleCountryCode] UTF8String]; + break; + case LocaleString_Iso3166CountryName2: + { + const char *countryCode = strdup([[currentLocale objectForKey:NSLocaleCountryCode] UTF8String]); + value = uloc_getISO3CountryByCountryCode(countryCode); + break; + } + case LocaleString_NaNSymbol: + value = [numberFormatter.notANumberSymbol UTF8String]; + break; + case LocaleString_PositiveInfinitySymbol: + value = [numberFormatter.positiveInfinitySymbol UTF8String]; + break; + case LocaleString_NegativeInfinitySymbol: + value = [numberFormatter.negativeInfinitySymbol UTF8String]; + break; + case LocaleString_PercentSymbol: + value = [numberFormatter.percentSymbol UTF8String]; + break; + case LocaleString_PerMilleSymbol: + value = [numberFormatter.perMillSymbol UTF8String]; + break; + case LocaleString_ParentName: + { + char localeNameTemp[FULLNAME_CAPACITY]; + const char* lName = [currentLocale.localeIdentifier UTF8String]; + GetParent(lName, localeNameTemp, FULLNAME_CAPACITY); + value = strdup(localeNameTemp); + break; + } + default: + value = ""; + break; } - default: - value = ""; - break; - } - return value ? strdup(value) : ""; + return value ? strdup(value) : ""; + } } // invariant character definitions @@ -463,104 +473,107 @@ static int32_t GetValueForNumberFormat(NSLocale *currentLocale, LocaleNumberData int32_t GlobalizationNative_GetLocaleInfoIntNative(const char* localeName, LocaleNumberData localeNumberData) { + @autoreleasepool + { #ifndef NDEBUG - bool isSuccess = true; + bool isSuccess = true; #endif - int32_t value; - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + int32_t value; + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - switch (localeNumberData) - { - case LocaleNumber_MeasurementSystem: - { - const char *measurementSystem = [[currentLocale objectForKey:NSLocaleMeasurementSystem] UTF8String]; - NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; - const char *us_measurementSystem = [[usLocale objectForKey:NSLocaleMeasurementSystem] UTF8String]; - value = (measurementSystem == us_measurementSystem) ? 1 : 0; - break; - } - case LocaleNumber_FractionalDigitsCount: - { - NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; - numberFormatter.locale = currentLocale; - numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; - value = (int32_t)numberFormatter.maximumFractionDigits; - break; - } - case LocaleNumber_MonetaryFractionalDigitsCount: - { - NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; - numberFormatter.locale = currentLocale; - numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; - value = (int32_t)numberFormatter.maximumFractionDigits; - break; - } - case LocaleNumber_PositiveMonetaryNumberFormat: - case LocaleNumber_NegativeMonetaryNumberFormat: - case LocaleNumber_NegativeNumberFormat: - case LocaleNumber_NegativePercentFormat: - case LocaleNumber_PositivePercentFormat: + switch (localeNumberData) { - value = GetValueForNumberFormat(currentLocale, localeNumberData); -#ifndef NDEBUG - if (value < 0) + case LocaleNumber_MeasurementSystem: { - isSuccess = false; + const char *measurementSystem = [[currentLocale objectForKey:NSLocaleMeasurementSystem] UTF8String]; + NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + const char *us_measurementSystem = [[usLocale objectForKey:NSLocaleMeasurementSystem] UTF8String]; + value = (measurementSystem == us_measurementSystem) ? 1 : 0; + break; } -#endif - break; - } - case LocaleNumber_FirstWeekOfYear: - { - NSCalendar *calendar = [currentLocale objectForKey:NSLocaleCalendar]; - int minDaysInWeek = (int32_t)[calendar minimumDaysInFirstWeek]; - if (minDaysInWeek == 1) + case LocaleNumber_FractionalDigitsCount: { - value = WeekRule_FirstDay; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + value = (int32_t)numberFormatter.maximumFractionDigits; + break; } - else if (minDaysInWeek == 7) + case LocaleNumber_MonetaryFractionalDigitsCount: { - value = WeekRule_FirstFullWeek; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + value = (int32_t)numberFormatter.maximumFractionDigits; + break; } - else if (minDaysInWeek >= 4) + case LocaleNumber_PositiveMonetaryNumberFormat: + case LocaleNumber_NegativeMonetaryNumberFormat: + case LocaleNumber_NegativeNumberFormat: + case LocaleNumber_NegativePercentFormat: + case LocaleNumber_PositivePercentFormat: { - value = WeekRule_FirstFourDayWeek; + value = GetValueForNumberFormat(currentLocale, localeNumberData); +#ifndef NDEBUG + if (value < 0) + { + isSuccess = false; + } +#endif + break; } - else + case LocaleNumber_FirstWeekOfYear: { - value = -1; + NSCalendar *calendar = [currentLocale objectForKey:NSLocaleCalendar]; + int minDaysInWeek = (int32_t)[calendar minimumDaysInFirstWeek]; + if (minDaysInWeek == 1) + { + value = WeekRule_FirstDay; + } + else if (minDaysInWeek == 7) + { + value = WeekRule_FirstFullWeek; + } + else if (minDaysInWeek >= 4) + { + value = WeekRule_FirstFourDayWeek; + } + else + { + value = -1; #ifndef NDEBUG - isSuccess = false; + isSuccess = false; #endif + } + break; } - break; - } - case LocaleNumber_ReadingLayout: - { - NSLocaleLanguageDirection langDir = [NSLocale characterDirectionForLanguage:[currentLocale objectForKey:NSLocaleLanguageCode]]; - // 0 - Left to right (such as en-US) - // 1 - Right to left (such as arabic locales) - value = NSLocaleLanguageDirectionRightToLeft == langDir ? 1 : 0; - break; - } - case LocaleNumber_FirstDayofWeek: - { - NSCalendar *calendar = [currentLocale objectForKey:NSLocaleCalendar]; - value = [calendar firstWeekday] - 1; // .NET is 0-based and in Apple is 1-based; - break; - } - default: - value = -1; + case LocaleNumber_ReadingLayout: + { + NSLocaleLanguageDirection langDir = [NSLocale characterDirectionForLanguage:[currentLocale objectForKey:NSLocaleLanguageCode]]; + // 0 - Left to right (such as en-US) + // 1 - Right to left (such as arabic locales) + value = NSLocaleLanguageDirectionRightToLeft == langDir ? 1 : 0; + break; + } + case LocaleNumber_FirstDayofWeek: + { + NSCalendar *calendar = [currentLocale objectForKey:NSLocaleCalendar]; + value = [calendar firstWeekday] - 1; // .NET is 0-based and in Apple is 1-based; + break; + } + default: + value = -1; #ifndef NDEBUG - isSuccess = false; + isSuccess = false; #endif - break; - } + break; + } - assert(isSuccess); + assert(isSuccess); - return value; + return value; + } } /* @@ -571,24 +584,27 @@ Returns primary grouping size for decimal and currency */ int32_t GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative(const char* localeName, LocaleNumberData localeGroupingData) { - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; - numberFormatter.locale = currentLocale; - - switch (localeGroupingData) + @autoreleasepool { - case LocaleNumber_Digit: - numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; - break; - case LocaleNumber_Monetary: - numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; - break; - default: - assert(false); - break; + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + + switch (localeGroupingData) + { + case LocaleNumber_Digit: + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + break; + case LocaleNumber_Monetary: + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + break; + default: + assert(false); + break; + } + return [numberFormatter groupingSize]; } - return [numberFormatter groupingSize]; } /* @@ -599,25 +615,28 @@ Returns secondary grouping size for decimal and currency */ int32_t GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative(const char* localeName, LocaleNumberData localeGroupingData) { - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; - numberFormatter.locale = currentLocale; - - switch (localeGroupingData) + @autoreleasepool { - case LocaleNumber_Digit: - numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; - break; - case LocaleNumber_Monetary: - numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; - break; - default: - assert(false); - break; - } + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + + switch (localeGroupingData) + { + case LocaleNumber_Digit: + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + break; + case LocaleNumber_Monetary: + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + break; + default: + assert(false); + break; + } - return [numberFormatter secondaryGroupingSize]; + return [numberFormatter secondaryGroupingSize]; + } } /* @@ -628,21 +647,24 @@ Returns time format information (in native format, it needs to be converted to . */ const char* GlobalizationNative_GetLocaleTimeFormatNative(const char* localeName, int shortFormat) { - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setLocale:currentLocale]; - - if (shortFormat != 0) - { - [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; - } - else + @autoreleasepool { - [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; - } + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setLocale:currentLocale]; + + if (shortFormat != 0) + { + [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; + } + else + { + [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; + } - return strdup([[dateFormatter dateFormat] UTF8String]); + return strdup([[dateFormatter dateFormat] UTF8String]); + } } #endif @@ -650,15 +672,21 @@ const char* GlobalizationNative_GetLocaleTimeFormatNative(const char* localeName #if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS) const char* GlobalizationNative_GetICUDataPathRelativeToAppBundleRoot(const char* path) { - NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; - NSString *dataPath = [bundlePath stringByAppendingPathComponent: [NSString stringWithFormat:@"%s", path]]; + @autoreleasepool + { + NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; + NSString *dataPath = [bundlePath stringByAppendingPathComponent: [NSString stringWithFormat:@"%s", path]]; - return strdup([dataPath UTF8String]); + return strdup([dataPath UTF8String]); + } } const char* GlobalizationNative_GetICUDataPathFallback(void) { - NSString *dataPath = [[NSBundle mainBundle] pathForResource:@"icudt" ofType:@"dat"]; - return strdup([dataPath UTF8String]); + @autoreleasepool + { + NSString *dataPath = [[NSBundle mainBundle] pathForResource:@"icudt" ofType:@"dat"]; + return strdup([dataPath UTF8String]); + } } #endif diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index cdac9a185a9..960e0502e14 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -67,56 +67,45 @@ else() endif() if (CLR_CMAKE_TARGET_APPLE) - list (APPEND NATIVE_SOURCES pal_autoreleasepool.m) - set_source_files_properties(pal_autoreleasepool.m PROPERTIES COMPILE_FLAGS "-fno-objc-arc ${CLR_CMAKE_COMMON_OBJC_FLAGS}") -else() - list (APPEND NATIVE_SOURCES pal_autoreleasepool.c) -endif() - -if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) - list (APPEND NATIVE_SOURCES pal_environment.m) - set_source_files_properties(pal_environment.m PROPERTIES COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") -else() - list (APPEND NATIVE_SOURCES pal_environment.c) -endif() - -if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) - set(NATIVE_SOURCES ${NATIVE_SOURCES} + list (APPEND NATIVE_SOURCES_OBJC_NO_ARC + pal_autoreleasepool.m + pal_environment.m + pal_searchpath.m pal_datetime.m) - set_source_files_properties(pal_datetime.m PROPERTIES COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") -endif() -if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) - set(NATIVE_SOURCES ${NATIVE_SOURCES} - pal_log.m - pal_searchpath.m) - set_source_files_properties(pal_log.m pal_searchpath.m PROPERTIES COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") -elseif (CLR_CMAKE_TARGET_OSX) - list (APPEND NATIVE_SOURCES - pal_searchpath.m - pal_console.c - pal_log.c) - set_source_files_properties(pal_searchpath.m PROPERTIES COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") -elseif (CLR_CMAKE_TARGET_WASI) - list (APPEND NATIVE_SOURCES - pal_searchpath.c - pal_console_wasi.c - pal_log.c) -else () + if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) + list (APPEND NATIVE_SOURCES_OBJC_NO_ARC pal_log.m) + + if (CLR_CMAKE_TARGET_MACCATALYST) + list (APPEND NATIVE_SOURCES_OBJC_NO_ARC pal_iossupportversion.m) + else() + list (APPEND NATIVE_SOURCES pal_iossupportversion.c) + endif () + elseif (CLR_CMAKE_TARGET_OSX) + list (APPEND NATIVE_SOURCES + pal_console.c + pal_log.c + pal_iossupportversion.c) + else() + message(FATAL_ERROR "Unsupported Apple platform") + endif () + + set_source_files_properties(${NATIVE_SOURCES_OBJC_NO_ARC} PROPERTIES COMPILE_FLAGS "-fno-objc-arc ${CLR_CMAKE_COMMON_OBJC_FLAGS}") + list (APPEND NATIVE_SOURCES ${NATIVE_SOURCES_OBJC_NO_ARC}) +else() list (APPEND NATIVE_SOURCES + pal_autoreleasepool.c + pal_environment.c pal_searchpath.c - pal_console.c - pal_log.c) -endif () - -if (CLR_CMAKE_TARGET_MACCATALYST) - set(NATIVE_SOURCES ${NATIVE_SOURCES} - pal_iossupportversion.m) - set_source_files_properties(pal_iossupportversion.m PROPERTIES COMPILE_FLAGS "${CLR_CMAKE_COMMON_OBJC_FLAGS}") -else () - list (APPEND NATIVE_SOURCES + pal_log.c pal_iossupportversion.c) -endif () + + if (CLR_CMAKE_TARGET_WASI) + list (APPEND NATIVE_SOURCES pal_console_wasi.c) + else() + list (APPEND NATIVE_SOURCES pal_console.c) + endif() +endif() if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI) list (APPEND NATIVE_SOURCES pal_networkchange.c) diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c index 0b719b1545f..8491ab83c46 100644 --- a/src/native/libs/System.Native/entrypoints.c +++ b/src/native/libs/System.Native/entrypoints.c @@ -48,6 +48,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_GetSignalForBreak) DllImportEntry(SystemNative_SetSignalForBreak) DllImportEntry(SystemNative_GetSystemTimeAsTicks) + DllImportEntry(SystemNative_GetDefaultTimeZone) DllImportEntry(SystemNative_GetTimeZoneData) DllImportEntry(SystemNative_ConvertErrorPlatformToPal) DllImportEntry(SystemNative_ConvertErrorPalToPlatform) diff --git a/src/native/libs/System.Native/pal_autoreleasepool.m b/src/native/libs/System.Native/pal_autoreleasepool.m index 191d145babe..9f20031ffca 100644 --- a/src/native/libs/System.Native/pal_autoreleasepool.m +++ b/src/native/libs/System.Native/pal_autoreleasepool.m @@ -5,6 +5,10 @@ #include #include +#if __has_feature(objc_arc) +#error This file uses manual memory management and must not use ARC, but ARC is enabled. +#endif + void EnsureNSThreadIsMultiThreaded(void) { if (![NSThread isMultiThreaded]) diff --git a/src/native/libs/System.Native/pal_datetime.c b/src/native/libs/System.Native/pal_datetime.c index 94a05ebb63e..d762fe50681 100644 --- a/src/native/libs/System.Native/pal_datetime.c +++ b/src/native/libs/System.Native/pal_datetime.c @@ -61,6 +61,12 @@ char* SystemNative_GetDefaultTimeZone(void) return NULL; } } +#elif !defined(__APPLE__) +char* SystemNative_GetDefaultTimeZone(void) +{ + assert_err(false, "This function is not supported on this platform.", EINVAL); + return NULL; +} #endif const char* SystemNative_GetTimeZoneData(const char* name, int* length) diff --git a/src/native/libs/System.Native/pal_datetime.h b/src/native/libs/System.Native/pal_datetime.h index b6da4a89cc3..7d4fb4a1d37 100644 --- a/src/native/libs/System.Native/pal_datetime.h +++ b/src/native/libs/System.Native/pal_datetime.h @@ -8,8 +8,6 @@ PALEXPORT int64_t SystemNative_GetSystemTimeAsTicks(void); -#if defined(TARGET_ANDROID) || defined(__APPLE__) PALEXPORT char* SystemNative_GetDefaultTimeZone(void); -#endif PALEXPORT const char* SystemNative_GetTimeZoneData(const char* name, int* length); diff --git a/src/native/libs/System.Native/pal_datetime.m b/src/native/libs/System.Native/pal_datetime.m index cd45b54358f..f023703f27b 100644 --- a/src/native/libs/System.Native/pal_datetime.m +++ b/src/native/libs/System.Native/pal_datetime.m @@ -4,6 +4,10 @@ #include "pal_datetime.h" #import +#if __has_feature(objc_arc) +#error This file uses manual memory management and must not use ARC, but ARC is enabled. +#endif + char* SystemNative_GetDefaultTimeZone() { NSTimeZone *tz = [NSTimeZone localTimeZone]; diff --git a/src/native/libs/System.Native/pal_environment.m b/src/native/libs/System.Native/pal_environment.m index ea4edc6ccd3..fe02a2f96d4 100644 --- a/src/native/libs/System.Native/pal_environment.m +++ b/src/native/libs/System.Native/pal_environment.m @@ -9,6 +9,10 @@ #include #include +#if __has_feature(objc_arc) +#error This file uses manual memory management and must not use ARC, but ARC is enabled. +#endif + char* SystemNative_GetEnv(const char* variable) { return getenv(variable); diff --git a/src/native/libs/System.Native/pal_iossupportversion.m b/src/native/libs/System.Native/pal_iossupportversion.m index 8199b9822e8..0a531350a1d 100644 --- a/src/native/libs/System.Native/pal_iossupportversion.m +++ b/src/native/libs/System.Native/pal_iossupportversion.m @@ -5,14 +5,16 @@ #include "pal_autoreleasepool.h" #import +#if __has_feature(objc_arc) +#error This file uses manual memory management and must not use ARC, but ARC is enabled. +#endif + const char* SystemNative_iOSSupportVersion() { - EnsureNSThreadIsMultiThreaded(); + NSDictionary *plist = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; + NSString *iOSSupportVersion = (NSString *)[plist objectForKey:@"iOSSupportVersion"]; + const char* version = strdup([iOSSupportVersion UTF8String]); + [plist release]; - @autoreleasepool - { - NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; - NSString *iOSSupportVersion = (NSString *)[plist objectForKey:@"iOSSupportVersion"]; - return strdup([iOSSupportVersion UTF8String]); - } + return version; } diff --git a/src/native/libs/System.Native/pal_log.m b/src/native/libs/System.Native/pal_log.m index ce6e26a4931..b62e4f750a8 100644 --- a/src/native/libs/System.Native/pal_log.m +++ b/src/native/libs/System.Native/pal_log.m @@ -4,6 +4,10 @@ #include "pal_log.h" #import +#if __has_feature(objc_arc) +#error This file uses manual memory management and must not use ARC, but ARC is enabled. +#endif + void SystemNative_Log (uint8_t* buffer, int32_t length) { NSString *msg = [[NSString alloc] initWithBytes: buffer length: length encoding: NSUTF16LittleEndianStringEncoding]; diff --git a/src/native/libs/System.Native/pal_searchpath.m b/src/native/libs/System.Native/pal_searchpath.m index 231c508c527..e8d07c163cc 100644 --- a/src/native/libs/System.Native/pal_searchpath.m +++ b/src/native/libs/System.Native/pal_searchpath.m @@ -4,6 +4,10 @@ #include "pal_searchpath.h" #import +#if __has_feature(objc_arc) +#error This file uses manual memory management and must not use ARC, but ARC is enabled. +#endif + const char* SystemNative_SearchPath(int32_t folderId) { NSSearchPathDirectory spd = (NSSearchPathDirectory) folderId; -- GitLab