1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
/* CFListFormatter.h
Copyright (c) 2018-2019, Apple Inc. and the Swift project authors
Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
*/
#include "CFListFormatter.h"
#include "CFICULogging.h"
#include "CFInternal.h"
#include "CFRuntime_Internal.h"
#include <assert.h>
#define BUFFER_SIZE 256
#define RESULT_BUFFER_SIZE 768
struct __CFListFormatter {
CFRuntimeBase _base;
CFLocaleRef _locale;
};
static void __CFListFormatterDeallocate(CFTypeRef cf) {
assert(cf != NULL);
CFListFormatterRef formatter = (CFListFormatterRef)cf;
if (formatter->_locale) { CFRelease(formatter->_locale); }
}
static CFStringRef __CFListFormatterCopyDescription(CFTypeRef cf) {
assert(cf != NULL);
CFListFormatterRef formatter = (CFListFormatterRef)cf;
return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFListFormatter %p>[%p]"), formatter, CFGetAllocator(formatter));
}
CFTypeID _CFListFormatterGetTypeID(void) {
return _kCFRuntimeIDCFListFormatter;
}
const CFRuntimeClass __CFListFormatterClass = {
0,
"CFListFormatter",
NULL, // init
NULL, // copy
__CFListFormatterDeallocate,
NULL, // equal
NULL, // hash
NULL, // copy formatting desc
__CFListFormatterCopyDescription
};
CFListFormatterRef _CFListFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale) {
assert(allocator != NULL);
__CFGenericValidateType(allocator, CFAllocatorGetTypeID());
assert(locale != NULL);
__CFGenericValidateType(locale, CFLocaleGetTypeID());
size_t size = sizeof(struct __CFListFormatter) - sizeof(CFRuntimeBase);
struct __CFListFormatter *memory = (struct __CFListFormatter *)_CFRuntimeCreateInstance(allocator, _CFListFormatterGetTypeID(), size, NULL);
if (memory == NULL) {
return NULL;
}
memory->_locale = CFRetain(locale);
return memory;
}
CFStringRef _CFListFormatterCreateStringByJoiningStrings(CFAllocatorRef allocator, const CFListFormatterRef formatter, const CFArrayRef strings) {
CFAssert1(strings != NULL, __kCFLogAssertion, "%s(): strings should not be NULL", __PRETTY_FUNCTION__);
if (strings == NULL) {
return NULL;
}
CFIndex const count = CFArrayGetCount(strings);
if (!count) {
return CFSTR("");
}
CFLocaleRef locale = formatter->_locale;
CFAssert1(locale != NULL, __kCFLogAssertion, "%s(): locale should not be NULL", __PRETTY_FUNCTION__);
UChar** ucharStrings = malloc(sizeof(UChar *) * count);
int32_t* uStringLengths = malloc(sizeof(int32_t) * count);
bool *needsFree = calloc(count, sizeof(bool));
CFStringRef string;
for (int i = 0; i < count; ++i) {
string = CFArrayGetValueAtIndex(strings, i);
CFIndex const len = CFStringGetLength(string);
UChar const *ucharString = CFStringGetCharactersPtr(string);
if (ucharString == NULL) {
UChar *ubuffer = malloc(sizeof(UChar) * len);
CFStringGetCharacters(string, CFRangeMake(0, len), ubuffer);
ucharString = ubuffer;
needsFree[i] = true;
}
uStringLengths[i] = len;
ucharStrings[i] = (UChar *)ucharString;
}
UErrorCode status = U_ZERO_ERROR;
CFStringRef localeName = CFLocaleGetIdentifier(locale);
char const *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
char buffer[BUFFER_SIZE];
if (NULL == cstr && CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) {
cstr = buffer;
}
UListFormatter *fmt = __cficu_ulistfmt_open(cstr, &status);
void (^cleanUp)(void) = ^{
if (fmt) {
__cficu_ulistfmt_close(fmt);
}
for (int i = 0; i < count; ++i) {
UChar *ucharString = ucharStrings[i];
if (ucharString && needsFree[i]) {
free(ucharString);
}
}
free(needsFree);
free(ucharStrings);
free(uStringLengths);
};
if (U_FAILURE(status)) {
cleanUp();
return NULL;
}
CFAssert1(fmt != NULL, __kCFLogAssertion, "%s(): UListFormatter should not be NULL", __PRETTY_FUNCTION__);
CFStringRef result = NULL;
UChar resultBuffer[RESULT_BUFFER_SIZE + 1];
status = U_ZERO_ERROR;
int32_t length = __cficu_ulistfmt_format(fmt, (const UChar **)ucharStrings, uStringLengths, count, resultBuffer, RESULT_BUFFER_SIZE, &status);
if (U_SUCCESS(status)) {
result = CFStringCreateWithCharacters(allocator, resultBuffer, length);
} else if (status == U_BUFFER_OVERFLOW_ERROR || length > count) {
status = U_ZERO_ERROR;
UChar *largeBuffer = malloc(sizeof(UChar) * (length + 1));
length = __cficu_ulistfmt_format(fmt, (const UChar **)ucharStrings, uStringLengths, count, largeBuffer, length + 1, &status);
if (U_SUCCESS(status)) {
result = CFStringCreateWithCharacters(allocator, largeBuffer, length);
}
free(largeBuffer);
}
cleanUp();
return result;
}
|