1/* 2 * Copyright (c) 2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* CFStringEncodings.c 25 Copyright (c) 1999-2013, Apple Inc. All rights reserved. 26 Responsibility: Aki Inoue 27*/ 28 29#include "CFInternal.h" 30#include <CoreFoundation/CFString.h> 31#include <CoreFoundation/CFByteOrder.h> 32#include <CoreFoundation/CFPriv.h> 33#include <string.h> 34#include <CoreFoundation/CFStringEncodingConverterExt.h> 35#include <CoreFoundation/CFUniChar.h> 36#include <CoreFoundation/CFUnicodeDecomposition.h> 37#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) 38#include <stdlib.h> 39#include <fcntl.h> 40#include <pwd.h> 41#include <sys/param.h> 42#include <unistd.h> 43#include <string.h> 44#include <stdio.h> 45#include <xlocale.h> 46#include <CoreFoundation/CFStringDefaultEncoding.h> 47#endif 48 49static bool __CFWantsToUseASCIICompatibleConversion = false; 50CF_INLINE UInt32 __CFGetASCIICompatibleFlag(void) { return __CFWantsToUseASCIICompatibleConversion; } 51 52void _CFStringEncodingSetForceASCIICompatibility(Boolean flag) { 53 __CFWantsToUseASCIICompatibleConversion = (flag ? (UInt32)true : (UInt32)false); 54} 55 56Boolean (*__CFCharToUniCharFunc)(UInt32 flags, uint8_t ch, UniChar *unicodeChar) = NULL; 57 58// To avoid early initialization issues, we just initialize this here 59// This should not be const as it is changed 60CF_PRIVATE UniChar __CFCharToUniCharTable[256] = { 61 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 62 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 63 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 64 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 65 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 66 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 67 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 68112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 69128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 70144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 71160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 72176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 73192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 74208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 75224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 76240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 77}; 78 79CF_PRIVATE void __CFSetCharToUniCharFunc(Boolean (*func)(UInt32 flags, UInt8 ch, UniChar *unicodeChar)) { 80 if (__CFCharToUniCharFunc != func) { 81 int ch; 82 __CFCharToUniCharFunc = func; 83 if (func) { 84 for (ch = 128; ch < 256; ch++) { 85 UniChar uch; 86 __CFCharToUniCharTable[ch] = (__CFCharToUniCharFunc(0, ch, &uch) ? uch : 0xFFFD); 87 } 88 } else { // If we have no __CFCharToUniCharFunc, assume 128..255 return the value as-is 89 for (ch = 128; ch < 256; ch++) __CFCharToUniCharTable[ch] = ch; 90 } 91 } 92} 93 94CF_PRIVATE void __CFStrConvertBytesToUnicode(const uint8_t *bytes, UniChar *buffer, CFIndex numChars) { 95 CFIndex idx; 96 for (idx = 0; idx < numChars; idx++) buffer[idx] = __CFCharToUniCharTable[bytes[idx]]; 97} 98 99 100/* The minimum length the output buffers should be in the above functions 101*/ 102#define kCFCharConversionBufferLength 512 103 104 105#define MAX_LOCAL_CHARS (sizeof(buffer->localBuffer) / sizeof(uint8_t)) 106#define MAX_LOCAL_UNICHARS (sizeof(buffer->localBuffer) / sizeof(UniChar)) 107 108/* Convert a byte stream to ASCII (7-bit!) or Unicode, with a CFVarWidthCharBuffer struct on the stack. false return indicates an error occured during the conversion. The caller needs to free the returned buffer in either ascii or unicode (indicated by isASCII), if shouldFreeChars is true. 1099/18/98 __CFStringDecodeByteStream now avoids to allocate buffer if buffer->chars is not NULL 110Added useClientsMemoryPtr; if not-NULL, and the provided memory can be used as is, this is set to true 111__CFStringDecodeByteStream2() is kept around for any internal clients who might be using it; it should be deprecated 112!!! converterFlags is only used for the UTF8 converter at this point 113*/ 114Boolean __CFStringDecodeByteStream2(const uint8_t *bytes, UInt32 len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr) { 115 return __CFStringDecodeByteStream3(bytes, len, encoding, alwaysUnicode, buffer, useClientsMemoryPtr, 0); 116} 117 118enum { 119 __NSNonLossyErrorMode = -1, 120 __NSNonLossyASCIIMode = 0, 121 __NSNonLossyBackslashMode = 1, 122 __NSNonLossyHexInitialMode = __NSNonLossyBackslashMode + 1, 123 __NSNonLossyHexFinalMode = __NSNonLossyHexInitialMode + 4, 124 __NSNonLossyOctalInitialMode = __NSNonLossyHexFinalMode + 1, 125 __NSNonLossyOctalFinalMode = __NSNonLossyHexFinalMode + 3 126}; 127 128Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, CFIndex len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr, UInt32 converterFlags) { 129 CFIndex idx; 130 const uint8_t *chars = (const uint8_t *)bytes; 131 const uint8_t *end = chars + len; 132 Boolean result = TRUE; 133 134 if (useClientsMemoryPtr) *useClientsMemoryPtr = false; 135 136 buffer->isASCII = !alwaysUnicode; 137 buffer->shouldFreeChars = false; 138 buffer->numChars = 0; 139 140 if (0 == len) return true; 141 142 buffer->allocator = (buffer->allocator ? buffer->allocator : __CFGetDefaultAllocator()); 143 144 if ((encoding == kCFStringEncodingUTF16) || (encoding == kCFStringEncodingUTF16BE) || (encoding == kCFStringEncodingUTF16LE)) { // UTF-16 145 const UTF16Char *src = (const UTF16Char *)bytes; 146 const UTF16Char *limit = src + (len / sizeof(UTF16Char)); // <rdar://problem/7854378> avoiding odd len issue 147 bool swap = false; 148 149 if (kCFStringEncodingUTF16 == encoding) { 150 UTF16Char bom = ((*src == 0xFFFE) || (*src == 0xFEFF) ? *(src++) : 0); 151 152#if __CF_BIG_ENDIAN__ 153 if (bom == 0xFFFE) swap = true; 154#else 155 if (bom != 0xFEFF) swap = true; 156#endif 157 if (bom) useClientsMemoryPtr = NULL; 158 } else { 159#if __CF_BIG_ENDIAN__ 160 if (kCFStringEncodingUTF16LE == encoding) swap = true; 161#else 162 if (kCFStringEncodingUTF16BE == encoding) swap = true; 163#endif 164 } 165 166 buffer->numChars = limit - src; 167 168 if (useClientsMemoryPtr && !swap) { // If the caller is ready to deal with no-copy situation, and the situation is possible, indicate it... 169 *useClientsMemoryPtr = true; 170 buffer->chars.unicode = (UniChar *)src; 171 buffer->isASCII = false; 172 } else { 173 if (buffer->isASCII) { // Let's see if we can reduce the Unicode down to ASCII... 174 const UTF16Char *characters = src; 175 UTF16Char mask = (swap ? 0x80FF : 0xFF80); 176 177 while (characters < limit) { 178 if (*(characters++) & mask) { 179 buffer->isASCII = false; 180 break; 181 } 182 } 183 } 184 185 if (buffer->isASCII) { 186 uint8_t *dst; 187 if (NULL == buffer->chars.ascii) { // we never reallocate when buffer is supplied 188 if (buffer->numChars > MAX_LOCAL_CHARS) { 189 buffer->chars.ascii = (UInt8 *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(uint8_t)), 0); 190 if (!buffer->chars.ascii) goto memoryErrorExit; 191 buffer->shouldFreeChars = true; 192 } else { 193 buffer->chars.ascii = (uint8_t *)buffer->localBuffer; 194 } 195 } 196 dst = buffer->chars.ascii; 197 198 if (swap) { 199 while (src < limit) *(dst++) = (*(src++) >> 8); 200 } else { 201 while (src < limit) *(dst++) = (uint8_t)*(src++); 202 } 203 } else { 204 UTF16Char *dst; 205 206 if (NULL == buffer->chars.unicode) { // we never reallocate when buffer is supplied 207 if (buffer->numChars > MAX_LOCAL_UNICHARS) { 208 buffer->chars.unicode = (UniChar *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(UTF16Char)), 0); 209 if (!buffer->chars.unicode) goto memoryErrorExit; 210 buffer->shouldFreeChars = true; 211 } else { 212 buffer->chars.unicode = (UTF16Char *)buffer->localBuffer; 213 } 214 } 215 dst = buffer->chars.unicode; 216 217 if (swap) { 218 while (src < limit) *(dst++) = CFSwapInt16(*(src++)); 219 } else { 220 memmove(dst, src, buffer->numChars * sizeof(UTF16Char)); 221 } 222 } 223 } 224 } else if ((encoding == kCFStringEncodingUTF32) || (encoding == kCFStringEncodingUTF32BE) || (encoding == kCFStringEncodingUTF32LE)) { 225 const UTF32Char *src = (const UTF32Char *)bytes; 226 const UTF32Char *limit = src + (len / sizeof(UTF32Char)); // <rdar://problem/7854378> avoiding odd len issue 227 bool swap = false; 228 static bool strictUTF32 = (bool)-1; 229 230 if ((bool)-1 == strictUTF32) strictUTF32 = (1 != 0); 231 232 if (kCFStringEncodingUTF32 == encoding) { 233 UTF32Char bom = ((*src == 0xFFFE0000) || (*src == 0x0000FEFF) ? *(src++) : 0); 234 235#if __CF_BIG_ENDIAN__ 236 if (bom == 0xFFFE0000) swap = true; 237#else 238 if (bom != 0x0000FEFF) swap = true; 239#endif 240 } else { 241#if __CF_BIG_ENDIAN__ 242 if (kCFStringEncodingUTF32LE == encoding) swap = true; 243#else 244 if (kCFStringEncodingUTF32BE == encoding) swap = true; 245#endif 246 } 247 248 buffer->numChars = limit - src; 249 250 { 251 // Let's see if we have non-ASCII or non-BMP 252 const UTF32Char *characters = src; 253 UTF32Char asciiMask = (swap ? 0x80FFFFFF : 0xFFFFFF80); 254 UTF32Char bmpMask = (swap ? 0x0000FFFF : 0xFFFF0000); 255 256 while (characters < limit) { 257 if (*characters & asciiMask) { 258 buffer->isASCII = false; 259 if (*characters & bmpMask) { 260 if (strictUTF32 && ((swap ? (UTF32Char)CFSwapInt32(*characters) : *characters) > 0x10FFFF)) return false; // outside of Unicode Scaler Value. Haven't allocated buffer, yet. 261 ++(buffer->numChars); 262 } 263 } 264 ++characters; 265 } 266 } 267 268 if (buffer->isASCII) { 269 uint8_t *dst; 270 if (NULL == buffer->chars.ascii) { // we never reallocate when buffer is supplied 271 if (buffer->numChars > MAX_LOCAL_CHARS) { 272 buffer->chars.ascii = (UInt8 *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(uint8_t)), 0); 273 if (!buffer->chars.ascii) goto memoryErrorExit; 274 buffer->shouldFreeChars = true; 275 } else { 276 buffer->chars.ascii = (uint8_t *)buffer->localBuffer; 277 } 278 } 279 dst = buffer->chars.ascii; 280 281 if (swap) { 282 while (src < limit) *(dst++) = (*(src++) >> 24); 283 } else { 284 while (src < limit) *(dst++) = *(src++); 285 } 286 } else { 287 if (NULL == buffer->chars.unicode) { // we never reallocate when buffer is supplied 288 if (buffer->numChars > MAX_LOCAL_UNICHARS) { 289 buffer->chars.unicode = (UniChar *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(UTF16Char)), 0); 290 if (!buffer->chars.unicode) goto memoryErrorExit; 291 buffer->shouldFreeChars = true; 292 } else { 293 buffer->chars.unicode = (UTF16Char *)buffer->localBuffer; 294 } 295 } 296 result = (CFUniCharFromUTF32(src, limit - src, buffer->chars.unicode, (strictUTF32 ? false : true), __CF_BIG_ENDIAN__ ? !swap : swap) ? TRUE : FALSE); 297 } 298 } else if (kCFStringEncodingUTF8 == encoding) { 299 if ((len >= 3) && (chars[0] == 0xef) && (chars[1] == 0xbb) && (chars[2] == 0xbf)) { // If UTF8 BOM, skip 300 chars += 3; 301 len -= 3; 302 if (0 == len) return true; 303 } 304 if (buffer->isASCII) { 305 for (idx = 0; idx < len; idx++) { 306 if (128 <= chars[idx]) { 307 buffer->isASCII = false; 308 break; 309 } 310 } 311 } 312 if (buffer->isASCII) { 313 buffer->numChars = len; 314 buffer->shouldFreeChars = !buffer->chars.ascii && (len <= MAX_LOCAL_CHARS) ? false : true; 315 buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : (UInt8 *)CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); 316 if (!buffer->chars.ascii) goto memoryErrorExit; 317 memmove(buffer->chars.ascii, chars, len * sizeof(uint8_t)); 318 } else { 319 CFIndex numDone; 320 static CFStringEncodingToUnicodeProc __CFFromUTF8 = NULL; 321 322 if (!__CFFromUTF8) { 323 const CFStringEncodingConverter *converter = CFStringEncodingGetConverter(kCFStringEncodingUTF8); 324 __CFFromUTF8 = (CFStringEncodingToUnicodeProc)converter->toUnicode; 325 } 326 327 buffer->shouldFreeChars = !buffer->chars.unicode && (len <= MAX_LOCAL_UNICHARS) ? false : true; 328 buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); 329 if (!buffer->chars.unicode) goto memoryErrorExit; 330 buffer->numChars = 0; 331 while (chars < end) { 332 numDone = 0; 333 chars += __CFFromUTF8(converterFlags, chars, end - chars, &(buffer->chars.unicode[buffer->numChars]), len - buffer->numChars, &numDone); 334 335 if (0 == numDone) { 336 result = FALSE; 337 break; 338 } 339 buffer->numChars += numDone; 340 } 341 } 342 } else if (kCFStringEncodingNonLossyASCII == encoding) { 343 UTF16Char currentValue = 0; 344 uint8_t character; 345 int8_t mode = __NSNonLossyASCIIMode; 346 347 buffer->isASCII = false; 348 buffer->shouldFreeChars = !buffer->chars.unicode && (len <= MAX_LOCAL_UNICHARS) ? false : true; 349 buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); 350 if (!buffer->chars.unicode) goto memoryErrorExit; 351 buffer->numChars = 0; 352 353 while (chars < end) { 354 character = (*chars++); 355 356 switch (mode) { 357 case __NSNonLossyASCIIMode: 358 if (character == '\\') { 359 mode = __NSNonLossyBackslashMode; 360 } else if (character < 0x80) { 361 currentValue = character; 362 } else { 363 mode = __NSNonLossyErrorMode; 364 } 365 break; 366 367 case __NSNonLossyBackslashMode: 368 if ((character == 'U') || (character == 'u')) { 369 mode = __NSNonLossyHexInitialMode; 370 currentValue = 0; 371 } else if ((character >= '0') && (character <= '9')) { 372 mode = __NSNonLossyOctalInitialMode; 373 currentValue = character - '0'; 374 } else if (character == '\\') { 375 mode = __NSNonLossyASCIIMode; 376 currentValue = character; 377 } else { 378 mode = __NSNonLossyErrorMode; 379 } 380 break; 381 382 default: 383 if (mode < __NSNonLossyHexFinalMode) { 384 if ((character >= '0') && (character <= '9')) { 385 currentValue = (currentValue << 4) | (character - '0'); 386 if (++mode == __NSNonLossyHexFinalMode) mode = __NSNonLossyASCIIMode; 387 } else { 388 if (character >= 'a') character -= ('a' - 'A'); 389 if ((character >= 'A') && (character <= 'F')) { 390 currentValue = (currentValue << 4) | ((character - 'A') + 10); 391 if (++mode == __NSNonLossyHexFinalMode) mode = __NSNonLossyASCIIMode; 392 } else { 393 mode = __NSNonLossyErrorMode; 394 } 395 } 396 } else { 397 if ((character >= '0') && (character <= '9')) { 398 currentValue = (currentValue << 3) | (character - '0'); 399 if (++mode == __NSNonLossyOctalFinalMode) mode = __NSNonLossyASCIIMode; 400 } else { 401 mode = __NSNonLossyErrorMode; 402 } 403 } 404 break; 405 } 406 407 if (mode == __NSNonLossyASCIIMode) { 408 buffer->chars.unicode[buffer->numChars++] = currentValue; 409 } else if (mode == __NSNonLossyErrorMode) { 410 break; 411 } 412 } 413 result = ((mode == __NSNonLossyASCIIMode) ? YES : NO); 414 } else { 415 const CFStringEncodingConverter *converter = CFStringEncodingGetConverter(encoding); 416 417 if (!converter) return false; 418 419 Boolean isASCIISuperset = __CFStringEncodingIsSupersetOfASCII(encoding); 420 421 if (!isASCIISuperset) buffer->isASCII = false; 422 423 if (buffer->isASCII) { 424 for (idx = 0; idx < len; idx++) { 425 if (128 <= chars[idx]) { 426 buffer->isASCII = false; 427 break; 428 } 429 } 430 } 431 432 if (converter->encodingClass == kCFStringEncodingConverterCheapEightBit) { 433 if (buffer->isASCII) { 434 buffer->numChars = len; 435 buffer->shouldFreeChars = !buffer->chars.ascii && (len <= MAX_LOCAL_CHARS) ? false : true; 436 buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : (UInt8 *)CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); 437 if (!buffer->chars.ascii) goto memoryErrorExit; 438 memmove(buffer->chars.ascii, chars, len * sizeof(uint8_t)); 439 } else { 440 buffer->shouldFreeChars = !buffer->chars.unicode && (len <= MAX_LOCAL_UNICHARS) ? false : true; 441 buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); 442 if (!buffer->chars.unicode) goto memoryErrorExit; 443 buffer->numChars = len; 444 if (kCFStringEncodingASCII == encoding || kCFStringEncodingISOLatin1 == encoding) { 445 for (idx = 0; idx < len; idx++) buffer->chars.unicode[idx] = (UniChar)chars[idx]; 446 } else { 447 for (idx = 0; idx < len; idx++) { 448 if (chars[idx] < 0x80 && isASCIISuperset) { 449 buffer->chars.unicode[idx] = (UniChar)chars[idx]; 450 } else if (!((CFStringEncodingCheapEightBitToUnicodeProc)converter->toUnicode)(0, chars[idx], buffer->chars.unicode + idx)) { 451 result = FALSE; 452 break; 453 } 454 } 455 } 456 } 457 } else { 458 if (buffer->isASCII) { 459 buffer->numChars = len; 460 buffer->shouldFreeChars = !buffer->chars.ascii && (len <= MAX_LOCAL_CHARS) ? false : true; 461 buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : (UInt8 *)CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); 462 if (!buffer->chars.ascii) goto memoryErrorExit; 463 memmove(buffer->chars.ascii, chars, len * sizeof(uint8_t)); 464 } else { 465 CFIndex guessedLength = CFStringEncodingCharLengthForBytes(encoding, 0, bytes, len); 466 static UInt32 lossyFlag = (UInt32)-1; 467 468 buffer->shouldFreeChars = !buffer->chars.unicode && (guessedLength <= MAX_LOCAL_UNICHARS) ? false : true; 469 buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (guessedLength <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, guessedLength * sizeof(UniChar), 0)); 470 if (!buffer->chars.unicode) goto memoryErrorExit; 471 472 if (lossyFlag == (UInt32)-1) lossyFlag = 0; 473 474 if (CFStringEncodingBytesToUnicode(encoding, lossyFlag|__CFGetASCIICompatibleFlag(), bytes, len, NULL, buffer->chars.unicode, (guessedLength > MAX_LOCAL_UNICHARS ? guessedLength : MAX_LOCAL_UNICHARS), &(buffer->numChars))) result = FALSE; 475 } 476 } 477 } 478 479 if (FALSE == result) { 480memoryErrorExit: // Added for <rdar://problem/6581621>, but it's not clear whether an exception would be a better option 481 result = FALSE; // In case we come here from a goto 482 if (buffer->shouldFreeChars && buffer->chars.unicode) CFAllocatorDeallocate(buffer->allocator, buffer->chars.unicode); 483 buffer->isASCII = !alwaysUnicode; 484 buffer->shouldFreeChars = false; 485 buffer->chars.ascii = NULL; 486 buffer->numChars = 0; 487 } 488 return result; 489} 490 491 492/* Create a byte stream from a CFString backing. Can convert a string piece at a time 493 into a fixed size buffer. Returns number of characters converted. 494 Characters that cannot be converted to the specified encoding are represented 495 with the char specified by lossByte; if 0, then lossy conversion is not allowed 496 and conversion stops, returning partial results. 497 Pass buffer==NULL if you don't care about the converted string (but just the convertability, 498 or number of bytes required, indicated by usedBufLen). 499 Does not zero-terminate. If you want to create Pascal or C string, allow one extra byte at start or end. 500 501 Note: This function is intended to work through CFString functions, so it should work 502 with NSStrings as well as CFStrings. 503*/ 504CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLoc, CFIndex rangeLen, Boolean generatingExternalFile, CFStringEncoding encoding, char lossByte, uint8_t *buffer, CFIndex max, CFIndex *usedBufLen) { 505 CFIndex totalBytesWritten = 0; /* Number of written bytes */ 506 CFIndex numCharsProcessed = 0; /* Number of processed chars */ 507 const UniChar *unichars; 508 509 if (encoding == kCFStringEncodingUTF8 && (unichars = CFStringGetCharactersPtr(string))) { 510 static CFStringEncodingToBytesProc __CFToUTF8 = NULL; 511 512 if (!__CFToUTF8) { 513 const CFStringEncodingConverter *utf8Converter = CFStringEncodingGetConverter(kCFStringEncodingUTF8); 514 __CFToUTF8 = (CFStringEncodingToBytesProc)utf8Converter->toBytes; 515 } 516 numCharsProcessed = __CFToUTF8((generatingExternalFile ? kCFStringEncodingPrependBOM : 0), unichars + rangeLoc, rangeLen, buffer, (buffer ? max : 0), &totalBytesWritten); 517 518 } else if (encoding == kCFStringEncodingNonLossyASCII) { 519 const char *hex = "0123456789abcdef"; 520 UniChar ch; 521 CFStringInlineBuffer buf; 522 CFStringInitInlineBuffer(string, &buf, CFRangeMake(rangeLoc, rangeLen)); 523 while (numCharsProcessed < rangeLen) { 524 CFIndex reqLength; /* Required number of chars to encode this UniChar */ 525 CFIndex cnt; 526 char tmp[6]; 527 ch = CFStringGetCharacterFromInlineBuffer(&buf, numCharsProcessed); 528 if ((ch >= ' ' && ch <= '~' && ch != '\\') || (ch == '\n' || ch == '\r' || ch == '\t')) { 529 reqLength = 1; 530 tmp[0] = (char)ch; 531 } else { 532 if (ch == '\\') { 533 tmp[1] = '\\'; 534 reqLength = 2; 535 } else if (ch < 256) { /* \nnn; note that this is not NEXTSTEP encoding but a (small) UniChar */ 536 tmp[1] = '0' + (ch >> 6); 537 tmp[2] = '0' + ((ch >> 3) & 7); 538 tmp[3] = '0' + (ch & 7); 539 reqLength = 4; 540 } else { /* \Unnnn */ 541 tmp[1] = 'u'; // Changed to small+u in order to be aligned with Java 542 tmp[2] = hex[(ch >> 12) & 0x0f]; 543 tmp[3] = hex[(ch >> 8) & 0x0f]; 544 tmp[4] = hex[(ch >> 4) & 0x0f]; 545 tmp[5] = hex[ch & 0x0f]; 546 reqLength = 6; 547 } 548 tmp[0] = '\\'; 549 } 550 if (buffer) { 551 if (totalBytesWritten + reqLength > max) break; /* Doesn't fit.. 552.*/ 553 for (cnt = 0; cnt < reqLength; cnt++) { 554 buffer[totalBytesWritten + cnt] = tmp[cnt]; 555 } 556 } 557 totalBytesWritten += reqLength; 558 numCharsProcessed++; 559 } 560 } else if ((encoding == kCFStringEncodingUTF16) || (encoding == kCFStringEncodingUTF16BE) || (encoding == kCFStringEncodingUTF16LE)) { 561 CFIndex extraForBOM = (generatingExternalFile && (encoding == kCFStringEncodingUTF16) ? sizeof(UniChar) : 0); 562 numCharsProcessed = rangeLen; 563 if (buffer && (numCharsProcessed * (CFIndex)sizeof(UniChar) + extraForBOM > max)) { 564 numCharsProcessed = (max > extraForBOM) ? ((max - extraForBOM) / sizeof(UniChar)) : 0; 565 } 566 totalBytesWritten = (numCharsProcessed * sizeof(UniChar)) + extraForBOM; 567 if (buffer) { 568 if (extraForBOM) { /* Generate BOM */ 569#if __CF_BIG_ENDIAN__ 570 *buffer++ = 0xfe; *buffer++ = 0xff; 571#else 572 *buffer++ = 0xff; *buffer++ = 0xfe; 573#endif 574 } 575 CFStringGetCharacters(string, CFRangeMake(rangeLoc, numCharsProcessed), (UniChar *)buffer); 576 if ((__CF_BIG_ENDIAN__ ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE) == encoding) { // Need to swap 577 UTF16Char *characters = (UTF16Char *)buffer; 578 const UTF16Char *limit = characters + numCharsProcessed; 579 580 while (characters < limit) { 581 *characters = CFSwapInt16(*characters); 582 ++characters; 583 } 584 } 585 } 586 } else if ((encoding == kCFStringEncodingUTF32) || (encoding == kCFStringEncodingUTF32BE) || (encoding == kCFStringEncodingUTF32LE)) { 587 UTF32Char character; 588 CFStringInlineBuffer buf; 589 UTF32Char *characters = (UTF32Char *)buffer; 590 591 bool swap = (encoding == (__CF_BIG_ENDIAN__ ? kCFStringEncodingUTF32LE : kCFStringEncodingUTF32BE) ? true : false); 592 if (generatingExternalFile && (encoding == kCFStringEncodingUTF32)) { 593 totalBytesWritten += sizeof(UTF32Char); 594 if (characters) { 595 if (totalBytesWritten > max) { // insufficient buffer 596 totalBytesWritten = 0; 597 } else { 598 *(characters++) = 0x0000FEFF; 599 } 600 } 601 } 602 603 CFStringInitInlineBuffer(string, &buf, CFRangeMake(rangeLoc, rangeLen)); 604 while (numCharsProcessed < rangeLen) { 605 character = CFStringGetCharacterFromInlineBuffer(&buf, numCharsProcessed); 606 607 if (CFUniCharIsSurrogateHighCharacter(character)) { 608 UTF16Char otherCharacter; 609 610 if (((numCharsProcessed + 1) < rangeLen) && CFUniCharIsSurrogateLowCharacter((otherCharacter = CFStringGetCharacterFromInlineBuffer(&buf, numCharsProcessed + 1)))) { 611 character = CFUniCharGetLongCharacterForSurrogatePair(character, otherCharacter); 612 } else if (lossByte) { 613 character = lossByte; 614 } else { 615 break; 616 } 617 } else if (CFUniCharIsSurrogateLowCharacter(character)) { 618 if (lossByte) { 619 character = lossByte; 620 } else { 621 break; 622 } 623 } 624 625 totalBytesWritten += sizeof(UTF32Char); 626 627 if (characters) { 628 if (totalBytesWritten > max) { 629 totalBytesWritten -= sizeof(UTF32Char); 630 break; 631 } 632 *(characters++) = (swap ? CFSwapInt32(character) : character); 633 } 634 635 numCharsProcessed += (character > 0xFFFF ? 2 : 1); 636 } 637 } else { 638 CFIndex numChars; 639 UInt32 flags; 640 const unsigned char *cString = NULL; 641 Boolean isASCIISuperset = __CFStringEncodingIsSupersetOfASCII(encoding); 642 643 if (!CFStringEncodingIsValidEncoding(encoding)) return 0; 644 645 if (!CF_IS_OBJC(CFStringGetTypeID(), string) && isASCIISuperset) { // Checking for NSString to avoid infinite recursion 646 const unsigned char *ptr; 647 if ((cString = (const unsigned char *)CFStringGetCStringPtr(string, __CFStringGetEightBitStringEncoding()))) { 648 ptr = (cString += rangeLoc); 649 if (__CFStringGetEightBitStringEncoding() == encoding) { 650 numCharsProcessed = (rangeLen < max || buffer == NULL ? rangeLen : max); 651 if (buffer) memmove(buffer, cString, numCharsProcessed); 652 if (usedBufLen) *usedBufLen = numCharsProcessed; 653 return numCharsProcessed; 654 } 655 656 CFIndex uninterestingTailLen = buffer ? (rangeLen - MIN(max, rangeLen)) : 0; 657 while (*ptr < 0x80 && rangeLen > uninterestingTailLen) { 658 ++ptr; 659 --rangeLen; 660 } 661 numCharsProcessed = ptr - cString; 662 if (buffer) { 663 numCharsProcessed = (numCharsProcessed < max ? numCharsProcessed : max); 664 memmove(buffer, cString, numCharsProcessed); 665 buffer += numCharsProcessed; 666 max -= numCharsProcessed; 667 } 668 if (!rangeLen || (buffer && (max == 0))) { 669 if (usedBufLen) *usedBufLen = numCharsProcessed; 670 return numCharsProcessed; 671 } 672 rangeLoc += numCharsProcessed; 673 totalBytesWritten += numCharsProcessed; 674 } 675 if (!cString && (cString = CFStringGetPascalStringPtr(string, __CFStringGetEightBitStringEncoding()))) { 676 ptr = (cString += (rangeLoc + 1)); 677 if (__CFStringGetEightBitStringEncoding() == encoding) { 678 numCharsProcessed = (rangeLen < max || buffer == NULL ? rangeLen : max); 679 if (buffer) memmove(buffer, cString, numCharsProcessed); 680 if (usedBufLen) *usedBufLen = numCharsProcessed; 681 return numCharsProcessed; 682 } 683 while (*ptr < 0x80 && rangeLen > 0) { 684 ++ptr; 685 --rangeLen; 686 } 687 numCharsProcessed = ptr - cString; 688 if (buffer) { 689 numCharsProcessed = (numCharsProcessed < max ? numCharsProcessed : max); 690 memmove(buffer, cString, numCharsProcessed); 691 buffer += numCharsProcessed; 692 max -= numCharsProcessed; 693 } 694 if (!rangeLen || (buffer && (max == 0))) { 695 if (usedBufLen) *usedBufLen = numCharsProcessed; 696 return numCharsProcessed; 697 } 698 rangeLoc += numCharsProcessed; 699 totalBytesWritten += numCharsProcessed; 700 } 701 } 702 703 if (!buffer) max = 0; 704 705 // Special case for Foundation. When lossByte == 0xFF && encoding kCFStringEncodingASCII, we do the default ASCII fallback conversion 706 // Aki 11/24/04 __CFGetASCIICompatibleFlag() is called only for non-ASCII superset encodings. Otherwise, it could lead to a deadlock (see 3890536). 707 flags = (lossByte ? ((unsigned char)lossByte == 0xFF && encoding == kCFStringEncodingASCII ? kCFStringEncodingAllowLossyConversion : CFStringEncodingLossyByteToMask(lossByte)) : 0) | (generatingExternalFile ? kCFStringEncodingPrependBOM : 0) | (isASCIISuperset ? 0 : __CFGetASCIICompatibleFlag()); 708 709 if (!cString && (cString = (const unsigned char *)CFStringGetCharactersPtr(string))) { // Must be Unicode string 710 CFStringEncodingUnicodeToBytes(encoding, flags, (const UniChar *)cString + rangeLoc, rangeLen, &numCharsProcessed, buffer, max, &totalBytesWritten); 711 } else { 712 UniChar charBuf[kCFCharConversionBufferLength]; 713 CFIndex currentLength; 714 CFIndex usedLen; 715 CFIndex lastUsedLen = 0, lastNumChars = 0; 716 uint32_t result; 717 uint32_t streamingMask; 718 uint32_t streamID = 0; 719#define MAX_DECOMP_LEN (6) 720 721 while (rangeLen > 0) { 722 currentLength = (rangeLen > kCFCharConversionBufferLength ? kCFCharConversionBufferLength : rangeLen); 723 CFStringGetCharacters(string, CFRangeMake(rangeLoc, currentLength), charBuf); 724 725 // could be in the middle of surrogate pair; back up. 726 if ((rangeLen > kCFCharConversionBufferLength) && CFUniCharIsSurrogateHighCharacter(charBuf[kCFCharConversionBufferLength - 1])) --currentLength; 727 728 streamingMask = ((rangeLen > currentLength) ? kCFStringEncodingPartialInput : 0)|CFStringEncodingStreamIDToMask(streamID); 729 730 result = CFStringEncodingUnicodeToBytes(encoding, flags|streamingMask, charBuf, currentLength, &numChars, buffer, max, &usedLen); 731 streamID = CFStringEncodingStreamIDFromMask(result); 732 result &= ~CFStringEncodingStreamIDMask; 733 734 if (result != kCFStringEncodingConversionSuccess) { 735 if (kCFStringEncodingInvalidInputStream == result) { 736 CFRange composedRange; 737 // Check the tail 738 if ((rangeLen > kCFCharConversionBufferLength) && ((currentLength - numChars) < MAX_DECOMP_LEN)) { 739 composedRange = CFStringGetRangeOfComposedCharactersAtIndex(string, rangeLoc + currentLength); 740 741 if ((composedRange.length <= MAX_DECOMP_LEN) && (composedRange.location < (rangeLoc + numChars))) { 742 result = CFStringEncodingUnicodeToBytes(encoding, flags|streamingMask, charBuf, composedRange.location - rangeLoc, &numChars, buffer, max, &usedLen); 743 streamID = CFStringEncodingStreamIDFromMask(result); 744 result &= ~CFStringEncodingStreamIDMask; 745 } 746 } 747 748 // Check the head 749 if ((kCFStringEncodingConversionSuccess != result) && (lastNumChars > 0) && (numChars < MAX_DECOMP_LEN)) { 750 composedRange = CFStringGetRangeOfComposedCharactersAtIndex(string, rangeLoc); 751 752 if ((composedRange.length <= MAX_DECOMP_LEN) && (composedRange.location < rangeLoc)) { 753 // Try if the composed range can be converted 754 CFStringGetCharacters(string, composedRange, charBuf); 755 756 if (CFStringEncodingUnicodeToBytes(encoding, flags, charBuf, composedRange.length, &numChars, NULL, 0, &usedLen) == kCFStringEncodingConversionSuccess) { // OK let's try the last run 757 CFIndex lastRangeLoc = rangeLoc - lastNumChars; 758 759 currentLength = composedRange.location - lastRangeLoc; 760 CFStringGetCharacters(string, CFRangeMake(lastRangeLoc, currentLength), charBuf); 761 762 result = CFStringEncodingUnicodeToBytes(encoding, flags|streamingMask, charBuf, currentLength, &numChars, (max ? buffer - lastUsedLen : NULL), (max ? max + lastUsedLen : 0), &usedLen); 763 streamID = CFStringEncodingStreamIDFromMask(result); 764 result &= ~CFStringEncodingStreamIDMask; 765 766 if (result == kCFStringEncodingConversionSuccess) { // OK let's try the last run 767 // Looks good. back up 768 totalBytesWritten -= lastUsedLen; 769 numCharsProcessed -= lastNumChars; 770 771 rangeLoc = lastRangeLoc; 772 rangeLen += lastNumChars; 773 774 if (max) { 775 buffer -= lastUsedLen; 776 max += lastUsedLen; 777 } 778 } 779 } 780 } 781 } 782 } 783 784 if (kCFStringEncodingConversionSuccess != result) { // really failed 785 totalBytesWritten += usedLen; 786 numCharsProcessed += numChars; 787 break; 788 } 789 } 790 791 totalBytesWritten += usedLen; 792 numCharsProcessed += numChars; 793 794 rangeLoc += numChars; 795 rangeLen -= numChars; 796 if (max) { 797 buffer += usedLen; 798 max -= usedLen; 799 if (max <= 0) break; 800 } 801 lastUsedLen = usedLen; lastNumChars = numChars; 802 flags &= ~kCFStringEncodingPrependBOM; 803 } 804 } 805 } 806 if (usedBufLen) *usedBufLen = totalBytesWritten; 807 return numCharsProcessed; 808} 809 810CFStringRef CFStringCreateWithFileSystemRepresentation(CFAllocatorRef alloc, const char *buffer) { 811 return CFStringCreateWithCString(alloc, buffer, CFStringFileSystemEncoding()); 812} 813 814CFIndex CFStringGetMaximumSizeOfFileSystemRepresentation(CFStringRef string) { 815 CFIndex len = CFStringGetLength(string); 816 CFStringEncoding enc = CFStringGetFastestEncoding(string); 817 switch (enc) { 818 case kCFStringEncodingASCII: 819 case kCFStringEncodingMacRoman: 820 if (len > (LONG_MAX - 1L) / 3L) return kCFNotFound; // Avoid wrap-around 821 return len * 3L + 1L; 822 default: 823 if (len > (LONG_MAX - 1L) / 9L) return kCFNotFound; // Avoid wrap-around 824 return len * 9L + 1L; 825 } 826} 827 828Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CFIndex maxBufLen) { 829#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 830#define MAX_STACK_BUFFER_LEN (255) 831 const UTF16Char *characters = CFStringGetCharactersPtr(string); 832 const char *origBuffer = buffer; 833 const char *bufferLimit = buffer + maxBufLen; 834 CFIndex length = CFStringGetLength(string); 835 CFIndex usedBufLen; 836 837 if (maxBufLen < length) return false; // Since we're using UTF-8, the byte length is never shorter than the char length. Also, it filters out 0 == maxBufLen 838 839 if (NULL == characters) { 840 UTF16Char charactersBuffer[MAX_STACK_BUFFER_LEN]; 841 CFRange range = CFRangeMake(0, 0); 842 const char *bytes = CFStringGetCStringPtr(string, __CFStringGetEightBitStringEncoding()); 843 844 if (NULL != bytes) { 845 const char *originalBytes = bytes; 846 const char *bytesLimit = bytes + length; 847 848 while ((bytes < bytesLimit) && (buffer < bufferLimit) && (0 == (*bytes & 0x80))) *(buffer++) = *(bytes++); 849 850 range.location = bytes - originalBytes; 851 } 852 while ((range.location < length) && (buffer < bufferLimit)) { 853 range.length = length - range.location; 854 if (range.length > MAX_STACK_BUFFER_LEN) range.length = MAX_STACK_BUFFER_LEN; 855 856 CFStringGetCharacters(string, range, charactersBuffer); 857 if ((range.length == MAX_STACK_BUFFER_LEN) && CFUniCharIsSurrogateHighCharacter(charactersBuffer[MAX_STACK_BUFFER_LEN - 1])) --range.length; // Backup for a high surrogate 858 859 if (!CFUniCharDecompose(charactersBuffer, range.length, NULL, (void *)buffer, bufferLimit - buffer, &usedBufLen, true, kCFUniCharUTF8Format, true)) return false; 860 861 buffer += usedBufLen; 862 range.location += range.length; 863 } 864 } else { 865 if (!CFUniCharDecompose(characters, length, NULL, (void *)buffer, maxBufLen, &usedBufLen, true, kCFUniCharUTF8Format, true)) return false; 866 buffer += usedBufLen; 867 } 868 869 if (buffer < bufferLimit) { // Since the filename has its own limit, this is ok for now 870 *buffer = '\0'; 871 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) { 872 while (origBuffer < buffer) if (*origBuffer++ == 0) { // There's a zero in there. Now see if the rest are all zeroes. 873 while (origBuffer < buffer) if (*origBuffer++ != 0) return false; // Embedded NULLs should cause failure: <rdar://problem/5863219> 874 } 875 } 876 return true; 877 } else { 878 return false; 879 } 880#else 881 return CFStringGetCString(string, buffer, maxBufLen, CFStringFileSystemEncoding()); 882#endif 883} 884 885Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, uint8_t *buffer, CFIndex maxBufLen) { 886 return CFStringGetFileSystemRepresentation(string, (char *)buffer, maxBufLen); 887} 888 889 890#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) 891 892/* This function is used to obtain users' default script/region code. 893 The function first looks at environment variable __kCFUserEncodingEnvVariableName, then, reads the configuration file in user's home directory. 894*/ 895void _CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oRegionValue) { 896 char *stringValue; 897 char buffer[__kCFMaxDefaultEncodingFileLength]; 898 int uid = getuid(); 899 900 if ((stringValue = (char *)__CFgetenv(__kCFUserEncodingEnvVariableName)) != NULL) { 901 if ((uid == strtol_l(stringValue, &stringValue, 0, NULL)) && (':' == *stringValue)) { 902 ++stringValue; 903 } else { 904 stringValue = NULL; 905 } 906 } 907 908 if ((stringValue == NULL) && ((uid > 0) || __CFgetenv("HOME"))) { 909 char passwdExtraBuf[1000 + MAXPATHLEN]; // Extra memory buffer for getpwuid_r(); no clue as to how large this should be... 910 struct passwd passwdBuf, *passwdp = NULL; 911 912 switch (getpwuid_r((uid_t)uid, &passwdBuf, passwdExtraBuf, sizeof(passwdExtraBuf), &passwdp)) { 913 case 0: // Success 914 break; 915 case ERANGE: // Somehow we didn't give it enough memory; let the system handle the storage this time; but beware 5778609 916 passwdp = getpwuid((uid_t)uid); 917 break; 918 default: 919 passwdp = NULL; 920 } 921 if (passwdp) { 922 char filename[MAXPATHLEN + 1]; 923 924 const char *path = NULL; 925 if (!issetugid()) { 926 path = __CFgetenv("CFFIXED_USER_HOME"); 927 } 928 if (!path) { 929 path = passwdp->pw_dir; 930 } 931 932 strlcpy(filename, path, sizeof(filename)); 933 strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); 934 935 int no_hang_fd = __CFProphylacticAutofsAccess ? open("/dev/autofs_nowait", 0) : -1; 936 int fd = open(filename, O_RDONLY, 0); 937 if (fd == -1) { 938 // Cannot open the file. Let's fallback to smRoman/verUS 939 snprintf(filename, sizeof(filename), "0x%X:0:0", uid); 940 setenv(__kCFUserEncodingEnvVariableName, filename, 1); 941 } else { 942 ssize_t readSize; 943 readSize = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1); 944 buffer[(readSize < 0 ? 0 : readSize)] = '\0'; 945 close(fd); 946 stringValue = buffer; 947 948 // Well, we already have a buffer, let's reuse it 949 snprintf(filename, sizeof(filename), "0x%X:%s", uid, buffer); 950 setenv(__kCFUserEncodingEnvVariableName, filename, 1); 951 } 952 if (-1 != no_hang_fd) close(no_hang_fd); 953 } 954 } 955 956 if (stringValue) { 957 *oScriptValue = strtol_l(stringValue, &stringValue, 0, NULL); 958 if (*stringValue == ':') { 959 if (oRegionValue) *oRegionValue = strtol_l(++stringValue, NULL, 0, NULL); 960 return; 961 } 962 } 963 964 // Falling back 965 *oScriptValue = 0; // smRoman 966 if (oRegionValue) *oRegionValue = 0; // verUS 967} 968 969void _CFStringGetInstallationEncodingAndRegion(uint32_t *encoding, uint32_t *region) { 970 char buffer[__kCFMaxDefaultEncodingFileLength]; 971 char *stringValue = NULL; 972 973 *encoding = 0; 974 *region = 0; 975 976 struct passwd *passwdp = getpwuid((uid_t)0); 977 if (passwdp) { 978 const char *path = passwdp->pw_dir; 979 980 char filename[MAXPATHLEN + 1]; 981 strlcpy(filename, path, sizeof(filename)); 982 strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); 983 984 int no_hang_fd = __CFProphylacticAutofsAccess ? open("/dev/autofs_nowait", 0) : -1; 985 int fd = open(filename, O_RDONLY, 0); 986 if (0 <= fd) { 987 ssize_t size = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1); 988 buffer[(size < 0 ? 0 : size)] = '\0'; 989 close(fd); 990 stringValue = buffer; 991 } 992 if (-1 != no_hang_fd) close(no_hang_fd); 993 } 994 995 if (stringValue) { 996 *encoding = strtol_l(stringValue, &stringValue, 0, NULL); 997 if (*stringValue == ':') *region = strtol_l(++stringValue, NULL, 0, NULL); 998 } 999} 1000 1001Boolean _CFStringSaveUserDefaultEncoding(UInt32 iScriptValue, UInt32 iRegionValue) { 1002 Boolean success = false; 1003 struct passwd *passwdp = getpwuid(getuid()); 1004 if (passwdp) { 1005 const char *path = passwdp->pw_dir; 1006 if (!issetugid()) { 1007 const char *value = __CFgetenv("CFFIXED_USER_HOME"); 1008 if (value) path = value; // override 1009 } 1010 1011 char filename[MAXPATHLEN + 1]; 1012 strlcpy(filename, path, sizeof(filename)); 1013 strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); 1014 1015 int no_hang_fd = __CFProphylacticAutofsAccess ? open("/dev/autofs_nowait", 0) : -1; 1016 (void)unlink(filename); 1017 int fd = open(filename, O_WRONLY|O_CREAT, 0400); 1018 if (0 <= fd) { 1019 char buffer[__kCFMaxDefaultEncodingFileLength]; 1020 size_t size = snprintf(buffer, __kCFMaxDefaultEncodingFileLength, "0x%X:0x%X", (unsigned int)iScriptValue, (unsigned int)iRegionValue); 1021 if (size <= __kCFMaxDefaultEncodingFileLength) { 1022 int ret = write(fd, buffer, size); 1023 if (size <= ret) success = true; 1024 } 1025 int save_err = errno; 1026 close(fd); 1027 errno = save_err; 1028 } 1029 int save_err = errno; 1030 if (-1 != no_hang_fd) close(no_hang_fd); 1031 errno = save_err; 1032 } 1033 return success; 1034} 1035 1036#endif 1037 1038