File: CFBundle_DebugStrings.c

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (125 lines) | stat: -rw-r--r-- 7,297 bytes parent folder | download
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
/*      CFBundle_DebugStrings.c
 Copyright (c) 1999-2017, Apple Inc. and the Swift project authors
 
 Portions Copyright (c) 2014-2017, 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
 Responsibility: Sean Stewart <sean_stewart@apple.com>
 */

#include <assert.h>
#include "CFBundle_Internal.h"

// Directionality formatting codepoints
#define UTF16_RIGHT_TO_LEFT_OVERRIDE 0x202e
#define UTF16_POP_DIRECTIONAL_FORMATTING 0x202c

// Combining accent codepoints
#define UTF16_COMBINING_GRAVE_ACCENT 0x0300
#define UTF16_COMBINING_CEDILLA 0x0327
#define UTF16_COMBINING_TILDE 0x0303
#define UTF16_COMBINING_RING_BELOW 0x0325
#define UTF16_COMBINING_RING_ABOVE 0x030A
#define UTF16_COMBINING_DIAERESIS 0x0308

CF_EXPORT CFStringRef _CFDoubledStringCreate(CFStringRef theString) {
    CFMutableStringRef _Nonnull doubledString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
    CFStringAppend(doubledString, theString);
    // Prevent doubling any format string specifiers that may be present
    CFStringFindAndReplace(doubledString, CFSTR("%"), CFSTR(""), CFRangeMake(0, CFStringGetLength(doubledString)), 0);
    CFStringAppendFormat(doubledString, NULL, CFSTR(" %@"), theString);
    return (CFStringRef)doubledString;
}

static CFStringRef __CFAccentuatedStringCreateWithAcceptableAccentChars(CFStringRef inString, UniChar const *acceptableAccentChars, CFIndex acceptableCharLength) {
    // Copy the incoming string
    CFMutableStringRef _Nonnull workingString = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(inString), inString);

    // Create UniChar (UTF-16) buffer from original string
    CFIndex const workingStringLength = CFStringGetLength(workingString);
    CFStringInlineBuffer originalStringInlineBuffer;
    CFStringInitInlineBuffer(workingString, &originalStringInlineBuffer, CFRangeMake(0, workingStringLength));

    // Create new double-length UniChar (UTF-16) buffer for the new string
    // We will trim the size later, but worst case is that there will be no skipped whitespace characters
    UniChar *_Nonnull const accentedStringBuffer = malloc((workingStringLength * 2 + 1) * sizeof(UniChar)); // +1 for null char
    CFIndex accentedStringCursor = 0;

    // Create CFCharacterSets that contain characters we wish to skip over during the accentuation loop
    static CFCharacterSetRef _Nullable charsToSkip = NULL;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        CFMutableCharacterSetRef _Nonnull charsToSkipMutable = CFCharacterSetCreateMutable(kCFAllocatorDefault);
        CFCharacterSetUnion(charsToSkipMutable, CFCharacterSetGetPredefined(kCFCharacterSetControl));
        CFCharacterSetUnion(charsToSkipMutable, CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline));
        CFCharacterSetUnion(charsToSkipMutable, CFCharacterSetGetPredefined(kCFCharacterSetPunctuation));
        CFCharacterSetUnion(charsToSkipMutable, CFCharacterSetGetPredefined(kCFCharacterSetSymbol));
        CFCharacterSetUnion(charsToSkipMutable, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit));
        CFCharacterSetUnion(charsToSkipMutable, CFCharacterSetGetPredefined(kCFCharacterSetNonBase));
        charsToSkip = CFCharacterSetCreateCopy(kCFAllocatorDefault, charsToSkipMutable);
        CFRelease(charsToSkipMutable);
    });

    // For each non-skipped character, add a combining accent after the codepoint
    for (CFIndex i = 0; i < workingStringLength;) { // inner loop increments i
        CFRange const composedCharRange = CFStringGetRangeOfComposedCharactersAtIndex(workingString, i); // range length will always be >=1
        UniChar c;
        // Enqueue the characters within the composedCharRange
        for (CFIndex j = 0; j < composedCharRange.length; j++) {
            c = CFStringGetCharacterFromInlineBuffer(&originalStringInlineBuffer, i++);
            // Defend against CFStringGetCharacterFromInlineBuffer edge case listed in documentation
            if (c == 0) assert("UniChar at specified index could not be accessed as it is outside the original range specified when initializing the CFStringInlineBuffer");
            accentedStringBuffer[accentedStringCursor++] = c;
        }
        // Don't sprinkle accents onto composed char sequences and characters belonging to certain ranges
        // The goal here is to _never_ ever accentuate composed char sequences (like emoji)
        if ((composedCharRange.length == 1) && !CFCharacterSetIsCharacterMember(charsToSkip, c)) {
            // Deterministically pair a combining accent
            CFIndex const combiningAccentIndex = c % acceptableCharLength;
            UniChar const accentChar = acceptableAccentChars[combiningAccentIndex];
            accentedStringBuffer[accentedStringCursor++] = accentChar;
        }
    }
    // Terminate the UniChar buffer with a null char
    accentedStringBuffer[accentedStringCursor] = (UniChar)0x0;

    // Create a mutable string ref from the new char buffer (dealloc using kCFAllocatorNull and free the char buffer later ourselves)
    CFMutableStringRef _Nonnull const accentedStringFromCharBuffer = CFStringCreateMutableWithExternalCharactersNoCopy(NULL, accentedStringBuffer, accentedStringCursor, accentedStringCursor, kCFAllocatorNull);

    // Make a copy of the string so that CFString can optimize itself
    // CFStrings bound to client-owned buffers do not benefit from CFString-internal optimizations
    CFStringRef _Nonnull accentedString = CFStringCreateCopy(kCFAllocatorDefault, accentedStringFromCharBuffer);

    // Cleanup
    CFRelease(workingString);
    CFRelease(accentedStringFromCharBuffer);
    free(accentedStringBuffer);
    return (CFStringRef)accentedString;
}

CF_EXPORT CFStringRef _CFAccentuatedStringCreate(CFStringRef theString) {
    /* Default set of "acceptable" Unicode combining accent codepoints
     * These are hand-selected from the superset of combining accents because this subset is commonly used on Latin characters
     * Additionally they're visually obvious and all look unique (that's why we choose to use only the GRAVE and not GRAVE & ACUTE accents due to similarity)
     */
    static UniChar const acceptableAccentChars[] = {
        UTF16_COMBINING_GRAVE_ACCENT,
        UTF16_COMBINING_CEDILLA,
        UTF16_COMBINING_TILDE,
        UTF16_COMBINING_RING_BELOW,
        UTF16_COMBINING_RING_ABOVE,
        UTF16_COMBINING_DIAERESIS
    };
    static CFIndex const len = sizeof(acceptableAccentChars)/sizeof(UniChar);
    return __CFAccentuatedStringCreateWithAcceptableAccentChars(theString, acceptableAccentChars, len);
}

CF_EXPORT CFStringRef _CFAffixedStringCreate(CFStringRef theString, CFStringRef prefix, CFStringRef suffix) {
    return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@%@"), prefix, theString, suffix);
}

CF_EXPORT CFStringRef _CFRLORightToLeftStringCreate(CFStringRef theString) {
    CFStringRef rtlString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%C%@%C"), UTF16_RIGHT_TO_LEFT_OVERRIDE, theString, UTF16_POP_DIRECTIONAL_FORMATTING);
    return rtlString;
}