2 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
26 Responsibility: Kevin Perry
29 #include <CoreFoundation/CFData.h>
30 #include <CoreFoundation/CFPriv.h>
31 #include "CFInternal.h"
33 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
34 #include <mach/mach_init.h>
35 #elif DEPLOYMENT_TARGET_WINDOWS
36 #include <windows.h> // For GetSystemInfo()
40 #define CFDATA_MAX_SIZE ((1ULL << 42) - 1)
42 #define CFDATA_MAX_SIZE ((1ULL << 31) - 1)
45 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
46 CF_INLINE
unsigned long __CFPageSize() { return vm_page_size
; }
47 #elif DEPLOYMENT_TARGET_WINDOWS
48 CF_INLINE
unsigned long __CFPageSize() {
50 GetSystemInfo(&sysInfo
);
51 return sysInfo
.dwPageSize
;
55 #define INLINE_BYTES_THRESHOLD ((4 * __CFPageSize()) - sizeof(struct __CFData) - 15)
59 CFIndex _length
; /* number of bytes */
60 CFIndex _capacity
; /* maximum number of bytes */
61 CFAllocatorRef _bytesDeallocator
; /* used only for immutable; if NULL, no deallocation */
69 Bit 3 = use given CFAllocator
70 Bit 5 = allocate collectable memory
72 Bits 1-0 are used for mutability variation
74 Bit 6 = not all bytes have been zeroed yet (mutable)
80 __kCFMutableVarietyMask
= 0x03,
81 __kCFBytesInline
= 0x04,
82 __kCFUseAllocator
= 0x08,
83 __kCFAllocatesCollectable
= 0x20,
87 kCFImmutable
= 0x0, /* unchangable and fixed capacity; default */
88 kCFFixedMutable
= 0x1, /* changeable and fixed capacity */
89 kCFMutable
= 0x3 /* changeable and variable capacity */
92 CF_INLINE
void __CFDataSetInfoBits(CFDataRef data
, UInt32 v
) {__CFBitfieldSetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 5, 0, v
);}
93 CF_INLINE Boolean
__CFDataGetInfoBit(CFDataRef data
, UInt32 b
) {return ((((const CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
] & b
) != 0);}
94 CF_INLINE Boolean
__CFDataIsMutable(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFMutable
);}
95 CF_INLINE Boolean
__CFDataIsGrowable(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFGrowable
);}
96 CF_INLINE Boolean
__CFDataBytesInline(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFBytesInline
);}
97 CF_INLINE Boolean
__CFDataUseAllocator(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFUseAllocator
);}
98 CF_INLINE Boolean
__CFDataAllocatesCollectable(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFAllocatesCollectable
);}
100 CF_INLINE UInt32
__CFMutableVariety(const void *cf
) {
101 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
104 CF_INLINE
void __CFSetMutableVariety(void *cf
, UInt32 v
) {
105 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 1, 0, v
);
108 CF_INLINE UInt32
__CFMutableVarietyFromFlags(UInt32 flags
) {
109 return (flags
& __kCFMutableVarietyMask
);
112 #define __CFGenericValidateMutabilityFlags(flags) \
113 CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags);
115 CF_INLINE Boolean
__CFDataNeedsToZero(CFDataRef data
) {
116 return __CFBitfieldGetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
119 CF_INLINE
void __CFDataSetNeedsToZero(CFDataRef data
, Boolean zero
) {
120 __CFBitfieldSetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 6, 6, (zero
? 1 : 0));
123 CF_INLINE CFIndex
__CFDataLength(CFDataRef data
) {
124 return data
->_length
;
127 CF_INLINE
void __CFDataSetLength(CFMutableDataRef data
, CFIndex v
) {
128 /* for a CFData, _bytesUsed == _length */
131 CF_INLINE CFIndex
__CFDataCapacity(CFDataRef data
) {
132 return data
->_capacity
;
135 CF_INLINE
void __CFDataSetCapacity(CFMutableDataRef data
, CFIndex v
) {
136 /* for a CFData, _bytesNum == _capacity */
139 CF_INLINE CFIndex
__CFDataNumBytesUsed(CFDataRef data
) {
140 return data
->_length
;
143 CF_INLINE
void __CFDataSetNumBytesUsed(CFMutableDataRef data
, CFIndex v
) {
147 CF_INLINE CFIndex
__CFDataNumBytes(CFDataRef data
) {
148 return data
->_capacity
;
151 CF_INLINE
void __CFDataSetNumBytes(CFMutableDataRef data
, CFIndex v
) {
156 #define CHUNK_SIZE (1ULL << 29)
157 #define LOW_THRESHOLD (1ULL << 20)
158 #define HIGH_THRESHOLD (1ULL << 32)
160 #define CHUNK_SIZE (1ULL << 26)
161 #define LOW_THRESHOLD (1ULL << 20)
162 #define HIGH_THRESHOLD (1ULL << 29)
165 CF_INLINE CFIndex
__CFDataRoundUpCapacity(CFIndex capacity
) {
168 } else if (capacity
< LOW_THRESHOLD
) {
170 int idx
= flsl(capacity
);
171 return (1 << (idx
+ ((idx
% 2 == 0) ? 0 : 1)));
172 } else if (capacity
< HIGH_THRESHOLD
) {
174 return (1 << flsl(capacity
));
176 /* Round up to next multiple of CHUNK_SIZE */
177 unsigned long newCapacity
= CHUNK_SIZE
* (1+(capacity
>> (flsl(CHUNK_SIZE
)-1)));
178 return __CFMin(newCapacity
, CFDATA_MAX_SIZE
);
182 CF_INLINE CFIndex
__CFDataNumBytesForCapacity(CFIndex capacity
) {
186 static void __CFDataHandleOutOfMemory(CFTypeRef obj
, CFIndex numBytes
) {
188 if(0 < numBytes
&& numBytes
<= CFDATA_MAX_SIZE
) {
189 msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for NS/CFData failed"), numBytes
);
191 msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for NS/CFData failed. Maximum size: %ld"), numBytes
, CFDATA_MAX_SIZE
);
194 CFLog(kCFLogLevelCritical
, CFSTR("%@"), msg
);
201 CF_INLINE
void __CFDataValidateRange(CFDataRef data
, CFRange range
, const char *func
) {
202 CFAssert2(0 <= range
.location
&& range
.location
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): range.location index (%d) out of bounds", func
, range
.location
);
203 CFAssert2(0 <= range
.length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", func
, range
.length
);
204 CFAssert2(range
.location
+ range
.length
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): ending index (%d) out of bounds", func
, range
.location
+ range
.length
);
207 #define __CFDataValidateRange(a,r,f)
210 static Boolean
__CFDataEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
211 CFDataRef data1
= (CFDataRef
)cf1
;
212 CFDataRef data2
= (CFDataRef
)cf2
;
214 length
= __CFDataLength(data1
);
215 if (length
!= __CFDataLength(data2
)) return false;
216 return 0 == memcmp(data1
->_bytes
, data2
->_bytes
, length
);
219 static CFHashCode
__CFDataHash(CFTypeRef cf
) {
220 CFDataRef data
= (CFDataRef
)cf
;
221 return CFHashBytes(data
->_bytes
, __CFMin(__CFDataLength(data
), 80));
224 static CFStringRef
__CFDataCopyDescription(CFTypeRef cf
) {
225 CFDataRef data
= (CFDataRef
)cf
;
226 CFMutableStringRef result
;
229 const uint8_t *bytes
;
230 len
= __CFDataLength(data
);
231 bytes
= data
->_bytes
;
232 result
= CFStringCreateMutable(CFGetAllocator(data
), 0);
233 CFStringAppendFormat(result
, NULL
, CFSTR("<CFData %p [%p]>{length = %u, capacity = %u, bytes = 0x"), cf
, CFGetAllocator(data
), len
, __CFDataCapacity(data
));
235 for (idx
= 0; idx
< 16; idx
+= 4) {
236 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
238 CFStringAppend(result
, CFSTR(" ... "));
239 for (idx
= len
- 8; idx
< len
; idx
+= 4) {
240 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
243 for (idx
= 0; idx
< len
; idx
++) {
244 CFStringAppendFormat(result
, NULL
, CFSTR("%02x"), bytes
[idx
]);
247 CFStringAppend(result
, CFSTR("}"));
251 static void *__CFDataInlineBytesPtr(CFDataRef data
) {
252 return (void *)((uintptr_t)((int8_t *)data
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
255 static Boolean
__CFDataShouldAllocateCleared(CFDataRef data
, CFIndex size
) {
257 if (__CFDataUseAllocator(data
)) {
260 if (__CFDataAllocatesCollectable(data
)) {
264 result
= (size
> (64 * 1024));
267 result
= (size
> (128 * 1024));
274 // Check __CFDataShouldAllocateCleared before passing true.
275 static void *__CFDataAllocate(CFDataRef data
, CFIndex size
, Boolean clear
) {
277 if (__CFDataUseAllocator(data
)) {
278 CFAllocatorRef allocator
= __CFGetAllocator(data
);
279 bytes
= CFAllocatorAllocate(allocator
, size
, 0);
280 if (clear
) memset((uint8_t *)bytes
, 0, size
);
282 if (__CFDataAllocatesCollectable(data
)) {
283 bytes
= auto_zone_allocate_object(auto_zone(), size
, AUTO_MEMORY_UNSCANNED
, 0, clear
);
286 bytes
= malloc_zone_calloc(malloc_default_zone(), 1, size
);
288 bytes
= malloc_zone_malloc(malloc_default_zone(), size
);
295 static void __CFDataDeallocate(CFTypeRef cf
) {
296 CFMutableDataRef data
= (CFMutableDataRef
)cf
;
297 if (!__CFDataBytesInline(data
)) {
298 CFAllocatorRef deallocator
= data
->_bytesDeallocator
;
299 if (deallocator
!= NULL
) {
300 _CFAllocatorDeallocateGC(deallocator
, data
->_bytes
);
301 CFRelease(deallocator
);
304 if (__CFDataUseAllocator(data
)) {
305 _CFAllocatorDeallocateGC(__CFGetAllocator(data
), data
->_bytes
);
306 } else if (!__CFDataAllocatesCollectable(data
)) {
307 malloc_zone_free(malloc_default_zone(), data
->_bytes
);
314 static CFTypeID __kCFDataTypeID
= _kCFRuntimeNotATypeID
;
316 static const CFRuntimeClass __CFDataClass
= {
317 _kCFRuntimeScannedObject
,
325 __CFDataCopyDescription
328 __private_extern__
void __CFDataInitialize(void) {
329 __kCFDataTypeID
= _CFRuntimeRegisterClass(&__CFDataClass
);
332 CFTypeID
CFDataGetTypeID(void) {
333 return __kCFDataTypeID
;
337 // NULL bytesDeallocator to this function does not mean the default allocator, it means
338 // that there should be no deallocator, and the bytes should be copied.
339 static CFMutableDataRef
__CFDataInit(CFAllocatorRef allocator
, CFOptionFlags flags
, CFIndex capacity
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
340 CFMutableDataRef memory
;
341 __CFGenericValidateMutabilityFlags(flags
);
342 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
343 CFAssert3(kCFFixedMutable
!= __CFMutableVarietyFromFlags(flags
) || length
<= capacity
, __kCFLogAssertion
, "%s(): for kCFFixedMutable type, capacity (%d) must be greater than or equal to number of initial elements (%d)", __PRETTY_FUNCTION__
, capacity
, length
);
344 CFAssert2(0 <= length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", __PRETTY_FUNCTION__
, length
);
345 Boolean collectableMemory
= CF_IS_COLLECTABLE_ALLOCATOR(allocator
);
346 Boolean noCopy
= bytesDeallocator
!= NULL
;
347 Boolean isMutable
= ((flags
& __kCFMutable
) != 0);
348 Boolean isGrowable
= ((flags
& __kCFGrowable
) != 0);
349 Boolean allocateInline
= !isGrowable
&& !noCopy
&& capacity
< INLINE_BYTES_THRESHOLD
;
350 allocator
= (allocator
== NULL
) ? __CFGetDefaultAllocator() : allocator
;
351 Boolean useAllocator
= (allocator
!= kCFAllocatorSystemDefault
&& allocator
!= kCFAllocatorMalloc
&& allocator
!= kCFAllocatorMallocZone
);
353 CFIndex size
= sizeof(struct __CFData
) - sizeof(CFRuntimeBase
);
354 if (allocateInline
) {
355 size
+= sizeof(uint8_t) * __CFDataNumBytesForCapacity(capacity
) + sizeof(uint8_t) * 15; // for 16-byte alignment fixup
357 memory
= (CFMutableDataRef
)_CFRuntimeCreateInstance(allocator
, __kCFDataTypeID
, size
, NULL
);
358 if (NULL
== memory
) {
361 __CFDataSetNumBytesUsed(memory
, 0);
362 __CFDataSetLength(memory
, 0);
363 __CFDataSetInfoBits(memory
,
364 (allocateInline
? __kCFBytesInline
: 0) |
365 (useAllocator
? __kCFUseAllocator
: 0) |
366 (collectableMemory
? __kCFAllocatesCollectable
: 0));
370 if (collectableMemory
) {
371 if (allocateInline
) {
372 // We have no pointer to anything that needs to be reclaimed, so don't scan or finalize.
376 if (CF_IS_COLLECTABLE_ALLOCATOR(bytesDeallocator
)) {
377 // We're taking responsibility for externally GC-allocated memory, so scan us, but we don't need to finalize.
379 } else if (bytesDeallocator
== kCFAllocatorNull
) {
380 // We don't have responsibility for these bytes, so there's no need to be scanned and we don't need to finalize.
384 // We have a pointer to non-GC-allocated memory, so don't scan, but do finalize.
388 if (!scan
) auto_zone_set_unscanned(auto_zone(), memory
);
389 if (!finalize
) auto_zone_set_nofinalize(auto_zone(), memory
);
391 if (isMutable
&& isGrowable
) {
392 __CFDataSetCapacity(memory
, __CFDataRoundUpCapacity(1));
393 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(__CFDataRoundUpCapacity(1)));
394 __CFSetMutableVariety(memory
, kCFMutable
);
396 /* Don't round up capacity */
397 __CFDataSetCapacity(memory
, capacity
);
398 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
399 __CFSetMutableVariety(memory
, kCFFixedMutable
);
402 __CFAssignWithWriteBarrier((void **)&memory
->_bytes
, (uint8_t *)bytes
);
404 memory
->_bytesDeallocator
= (CFAllocatorRef
)CFRetain(bytesDeallocator
);
406 if (CF_IS_COLLECTABLE_ALLOCATOR(bytesDeallocator
)) {
407 // When given a GC allocator as the deallocator, we can assume that the no-copy memory is GC-allocated with a retain count of (at least) 1 and we should release it now instead of waiting until __CFDataDeallocate.
408 auto_zone_release(auto_zone(), memory
->_bytes
);
410 __CFDataSetNumBytesUsed(memory
, length
);
411 __CFDataSetLength(memory
, length
);
412 // Mutable no-copy datas are not allowed, so don't bother setting needsToZero flag.
414 Boolean cleared
= (isMutable
&& !isGrowable
&& !_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
));
415 if (!allocateInline
) {
416 // assume that allocators give 16-byte aligned memory back -- it is their responsibility
417 __CFAssignWithWriteBarrier((void **)&memory
->_bytes
, __CFDataAllocate(memory
, __CFDataNumBytes(memory
) * sizeof(uint8_t), cleared
));
418 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
->_bytes
, "CFData (store)");
419 if (NULL
== memory
->_bytes
) {
424 memory
->_bytes
= (uint8_t *)__CFDataInlineBytesPtr(memory
);
427 __CFDataSetNeedsToZero(memory
, !cleared
);
428 memory
->_bytesDeallocator
= NULL
;
429 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
431 __CFSetMutableVariety(memory
, __CFMutableVarietyFromFlags(flags
));
435 CFDataRef
CFDataCreate(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
) {
436 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, NULL
);
439 CFDataRef
CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
440 CFAssert1((0 == length
|| bytes
!= NULL
), __kCFLogAssertion
, "%s(): bytes pointer cannot be NULL if length is non-zero", __PRETTY_FUNCTION__
);
441 if (NULL
== bytesDeallocator
) bytesDeallocator
= __CFGetDefaultAllocator();
442 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, bytesDeallocator
);
445 CFDataRef
CFDataCreateCopy(CFAllocatorRef allocator
, CFDataRef data
) {
446 CFIndex length
= CFDataGetLength(data
);
447 return __CFDataInit(allocator
, kCFImmutable
, length
, CFDataGetBytePtr(data
), length
, NULL
);
450 CFMutableDataRef
CFDataCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
) {
451 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, NULL
, 0, NULL
);
454 CFMutableDataRef
CFDataCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFDataRef data
) {
455 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, CFDataGetBytePtr(data
), CFDataGetLength(data
), NULL
);
458 CFIndex
CFDataGetLength(CFDataRef data
) {
459 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, CFIndex
, data
, "length");
460 __CFGenericValidateType(data
, __kCFDataTypeID
);
461 return __CFDataLength(data
);
464 const uint8_t *CFDataGetBytePtr(CFDataRef data
) {
465 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, const uint8_t *, data
, "bytes");
466 __CFGenericValidateType(data
, __kCFDataTypeID
);
470 uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data
) {
471 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, uint8_t *, data
, "mutableBytes");
472 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
476 void CFDataGetBytes(CFDataRef data
, CFRange range
, uint8_t *buffer
) {
477 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "getBytes:range:", buffer
, range
);
478 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
479 memmove(buffer
, data
->_bytes
+ range
.location
, range
.length
);
482 /* Allocates new block of data with at least numNewValues more bytes than the current length. If clear is true, the new bytes up to at least the new length with be zeroed. */
483 static void __CFDataGrow(CFMutableDataRef data
, CFIndex numNewValues
, Boolean clear
) {
484 CFIndex oldLength
= __CFDataLength(data
);
485 CFIndex newLength
= oldLength
+ numNewValues
;
486 if (newLength
> CFDATA_MAX_SIZE
|| newLength
< 0) __CFDataHandleOutOfMemory(data
, newLength
* sizeof(uint8_t));
487 CFIndex capacity
= __CFDataRoundUpCapacity(newLength
);
488 CFIndex numBytes
= __CFDataNumBytesForCapacity(capacity
);
489 CFAllocatorRef allocator
= CFGetAllocator(data
);
491 void *oldBytes
= data
->_bytes
;
492 Boolean allocateCleared
= clear
&& __CFDataShouldAllocateCleared(data
, numBytes
);
493 if (allocateCleared
&& !__CFDataUseAllocator(data
) && (oldLength
== 0 || (newLength
/ oldLength
) > 4)) {
494 // If the length that needs to be zeroed is significantly greater than the length of the data, then calloc/memmove is probably more efficient than realloc/memset.
495 bytes
= __CFDataAllocate(data
, numBytes
* sizeof(uint8_t), true);
497 memmove(bytes
, oldBytes
, oldLength
);
498 __CFDataDeallocate(data
);
502 // If the calloc/memmove approach either failed or was never attempted, then realloc.
503 allocateCleared
= false;
504 if (__CFDataUseAllocator(data
)) {
505 bytes
= CFAllocatorReallocate(allocator
, oldBytes
, numBytes
* sizeof(uint8_t), 0);
507 bytes
= malloc_zone_realloc(__CFDataAllocatesCollectable(data
) ? auto_zone() : malloc_default_zone(), oldBytes
, numBytes
* sizeof(uint8_t));
510 if (NULL
== bytes
) __CFDataHandleOutOfMemory(data
, numBytes
* sizeof(uint8_t));
511 __CFDataSetCapacity(data
, capacity
);
512 __CFDataSetNumBytes(data
, numBytes
);
513 if (clear
&& !allocateCleared
&& oldLength
< newLength
) memset((uint8_t *)bytes
+ oldLength
, 0, newLength
- oldLength
);
514 __CFDataSetNeedsToZero(data
, !allocateCleared
);
515 __CFAssignWithWriteBarrier((void **)&data
->_bytes
, bytes
);
516 if (__CFOASafe
) __CFSetLastAllocationEventName(data
->_bytes
, "CFData (store)");
519 void CFDataSetLength(CFMutableDataRef data
, CFIndex newLength
) {
520 CFIndex oldLength
, capacity
;
522 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "setLength:", newLength
);
523 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
524 oldLength
= __CFDataLength(data
);
525 capacity
= __CFDataCapacity(data
);
526 isGrowable
= __CFDataIsGrowable(data
);
527 if (__CFDataIsMutable(data
)) {
530 __CFDataHandleOutOfMemory(data
, newLength
);
534 } else if (capacity
< newLength
) {
536 __CFDataGrow(data
, newLength
- oldLength
, true);
538 CFAssert1(newLength
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
540 } else if (oldLength
< newLength
&& __CFDataNeedsToZero(data
)) {
541 memset(data
->_bytes
+ oldLength
, 0, newLength
- oldLength
);
542 } else if (newLength
< oldLength
) {
543 __CFDataSetNeedsToZero(data
, true);
546 __CFDataSetLength(data
, newLength
);
547 __CFDataSetNumBytesUsed(data
, newLength
);
550 void CFDataIncreaseLength(CFMutableDataRef data
, CFIndex extraLength
) {
551 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "increaseLengthBy:", extraLength
);
552 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
553 CFDataSetLength(data
, __CFDataLength(data
) + extraLength
);
556 void CFDataAppendBytes(CFMutableDataRef data
, const uint8_t *bytes
, CFIndex length
) {
557 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "appendBytes:length:", bytes
, length
);
558 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
559 CFDataReplaceBytes(data
, CFRangeMake(__CFDataLength(data
), 0), bytes
, length
);
562 void CFDataDeleteBytes(CFMutableDataRef data
, CFRange range
) {
563 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, NULL
, 0);
564 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
565 CFDataReplaceBytes(data
, range
, NULL
, 0);
568 void CFDataReplaceBytes(CFMutableDataRef data
, CFRange range
, const uint8_t *newBytes
, CFIndex newLength
) {
569 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, newBytes
, newLength
);
570 __CFGenericValidateType(data
, __kCFDataTypeID
);
571 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
572 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
573 CFAssert2(0 <= newLength
, __kCFLogAssertion
, "%s(): newLength (%d) cannot be less than zero", __PRETTY_FUNCTION__
, newLength
);
575 CFIndex len
= __CFDataLength(data
);
576 if (len
< 0 || range
.length
< 0 || newLength
< 0) HALT
;
577 CFIndex newCount
= len
- range
.length
+ newLength
;
578 if (newCount
< 0) HALT
;
580 switch (__CFMutableVariety(data
)) {
582 if (__CFDataNumBytes(data
) < newCount
) {
583 __CFDataGrow(data
, newLength
- range
.length
, false);
586 case kCFFixedMutable
:
587 CFAssert1(newCount
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
590 if (newLength
!= range
.length
&& range
.location
+ range
.length
< len
) {
591 memmove(data
->_bytes
+ range
.location
+ newLength
, data
->_bytes
+ range
.location
+ range
.length
, (len
- range
.location
- range
.length
) * sizeof(uint8_t));
594 memmove(data
->_bytes
+ range
.location
, newBytes
, newLength
* sizeof(uint8_t));
596 __CFDataSetNumBytesUsed(data
, newCount
);
597 __CFDataSetLength(data
, newCount
);
600 #define REVERSE_BUFFER(type, buf, len) { \
602 for(int i = 0; i < (len)/2; i++) { \
604 (buf)[i] = (buf)[(len) - i - 1]; \
605 (buf)[(len) - i - 1] = tmp; \
609 static void _computeGoodSubstringShift(const uint8_t *needle
, int needleLength
, unsigned long shift
[], unsigned long suff
[]) {
612 // Compute suffix lengths
614 suff
[needleLength
- 1] = needleLength
;
615 g
= needleLength
- 1;
616 for (i
= needleLength
- 2; i
>= 0; --i
) {
617 if (i
> g
&& suff
[i
+ needleLength
- 1 - f
] < i
- g
)
618 suff
[i
] = suff
[i
+ needleLength
- 1 - f
];
623 while (g
>= 0 && needle
[g
] == needle
[g
+ needleLength
- 1 - f
])
629 // Compute shift table
631 for (i
= 0; i
< needleLength
; ++i
)
632 shift
[i
] = needleLength
;
634 for (i
= needleLength
- 1; i
>= 0; --i
)
635 if (suff
[i
] == i
+ 1)
636 for (; j
< needleLength
- 1 - i
; ++j
)
637 if (shift
[j
] == needleLength
)
638 shift
[j
] = needleLength
- 1 - i
;
639 // Set the amount of shift necessary to move each of the suffix matches found into a position where it overlaps with the suffix. If there are duplicate matches the latest one is the one that should take effect.
640 for (i
= 0; i
<= needleLength
- 2; ++i
)
641 shift
[needleLength
- 1 - suff
[i
]] = needleLength
- 1 - i
;
642 // Since the Boyer-Moore algorithm moves the pointer back while scanning substrings, add the distance to the end of the potential substring.
643 for (i
= 0; i
< needleLength
- 1; ++i
) {
644 shift
[i
] += (needleLength
- 1 - i
);
648 static const uint8_t * __CFDataSearchBoyerMoore(const CFDataRef data
, const uint8_t *haystack
, unsigned long haystackLength
, const uint8_t *needle
, unsigned long needleLength
, Boolean backwards
) {
649 unsigned long badCharacterShift
[UCHAR_MAX
+ 1] = {0};
650 unsigned long *goodSubstringShift
= (unsigned long *)malloc(needleLength
* sizeof(unsigned long));
651 unsigned long *suffixLengths
= (unsigned long *)malloc(needleLength
* sizeof(unsigned long));
652 if (!goodSubstringShift
|| !suffixLengths
) {
653 __CFDataHandleOutOfMemory(data
, needleLength
* sizeof(unsigned long));
657 for (int i
= 0; i
< sizeof(badCharacterShift
) / sizeof(*badCharacterShift
); i
++)
658 badCharacterShift
[i
] = needleLength
;
660 for (int i
= needleLength
- 1; i
>= 0; i
--)
661 badCharacterShift
[needle
[i
]] = i
;
663 // To get the correct shift table for backwards search reverse the needle, compute the forwards shift table, and then reverse the result.
664 uint8_t *needleCopy
= (uint8_t *)malloc(needleLength
* sizeof(uint8_t));
666 __CFDataHandleOutOfMemory(data
, needleLength
* sizeof(uint8_t));
668 memmove(needleCopy
, needle
, needleLength
);
669 REVERSE_BUFFER(uint8_t, needleCopy
, needleLength
);
670 _computeGoodSubstringShift(needleCopy
, needleLength
, goodSubstringShift
, suffixLengths
);
671 REVERSE_BUFFER(unsigned long, goodSubstringShift
, needleLength
);
674 for (int i
= 0; i
< sizeof(badCharacterShift
) / sizeof(*badCharacterShift
); i
++)
675 badCharacterShift
[i
] = needleLength
;
677 for (int i
= 0; i
< needleLength
; i
++)
678 badCharacterShift
[needle
[i
]] = needleLength
- i
- 1;
680 _computeGoodSubstringShift(needle
, needleLength
, goodSubstringShift
, suffixLengths
);
683 const uint8_t *scan_needle
;
684 const uint8_t *scan_haystack
;
685 const uint8_t *result
= NULL
;
687 const uint8_t *const end_needle
= needle
+ needleLength
;
688 scan_needle
= needle
;
689 scan_haystack
= haystack
+ haystackLength
- needleLength
;
690 while (scan_haystack
>= haystack
&& scan_needle
< end_needle
) {
691 if (*scan_haystack
== *scan_needle
) {
695 scan_haystack
-= __CFMax(badCharacterShift
[*scan_haystack
], goodSubstringShift
[scan_needle
- needle
]);
696 scan_needle
= needle
;
699 if (scan_needle
== end_needle
) {
700 result
= (scan_haystack
- needleLength
);
703 const uint8_t *const end_haystack
= haystack
+ haystackLength
;
704 scan_needle
= needle
+ needleLength
- 1;
705 scan_haystack
= haystack
+ needleLength
- 1;
706 while (scan_haystack
< end_haystack
&& scan_needle
>= needle
) {
707 if (*scan_haystack
== *scan_needle
) {
711 scan_haystack
+= __CFMax(badCharacterShift
[*scan_haystack
], goodSubstringShift
[scan_needle
- needle
]);
712 scan_needle
= needle
+ needleLength
- 1;
715 if (scan_needle
< needle
) {
716 result
= (scan_haystack
+ 1);
720 free(goodSubstringShift
);
726 CFRange
_CFDataFindBytes(CFDataRef data
, CFDataRef dataToFind
, CFRange searchRange
, CFDataSearchFlags compareOptions
) {
727 const uint8_t *fullHaystack
= CFDataGetBytePtr(data
);
728 const uint8_t *needle
= CFDataGetBytePtr(dataToFind
);
729 unsigned long fullHaystackLength
= CFDataGetLength(data
);
730 unsigned long needleLength
= CFDataGetLength(dataToFind
);
732 if(compareOptions
& kCFDataSearchAnchored
) {
733 if(searchRange
.length
> needleLength
) {
734 if(compareOptions
& kCFDataSearchBackwards
) {
735 searchRange
.location
+= (searchRange
.length
- needleLength
);
737 searchRange
.length
= needleLength
;
740 if(searchRange
.length
> fullHaystackLength
- searchRange
.location
) {
741 searchRange
.length
= fullHaystackLength
- searchRange
.location
;
744 if(searchRange
.length
< needleLength
|| fullHaystackLength
== 0 || needleLength
== 0) {
745 return CFRangeMake(kCFNotFound
, 0);
748 const uint8_t *haystack
= fullHaystack
+ searchRange
.location
;
749 const uint8_t *searchResult
= __CFDataSearchBoyerMoore(data
, haystack
, searchRange
.length
, needle
, needleLength
, (compareOptions
& kCFDataSearchBackwards
) != 0);
750 CFIndex resultLocation
= (searchResult
== NULL
) ? kCFNotFound
: searchRange
.location
+ (searchResult
- haystack
);
752 return CFRangeMake(resultLocation
, resultLocation
== kCFNotFound
? 0: needleLength
);
755 CFRange
CFDataFind(CFDataRef data
, CFDataRef dataToFind
, CFRange searchRange
, CFDataSearchFlags compareOptions
) {
757 __CFGenericValidateType(data
, __kCFDataTypeID
);
758 __CFGenericValidateType(dataToFind
, __kCFDataTypeID
);
759 __CFDataValidateRange(data
, searchRange
, __PRETTY_FUNCTION__
);
761 return _CFDataFindBytes(data
, dataToFind
, searchRange
, compareOptions
);
764 #undef __CFDataValidateRange
765 #undef __CFGenericValidateMutabilityFlags
766 #undef INLINE_BYTES_THRESHOLD
767 #undef CFDATA_MAX_SIZE
768 #undef REVERSE_BUFFER