2 * Copyright (c) 2015 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-2014, Apple Inc. All rights reserved.
26 Responsibility: Kevin Perry
29 #include <CoreFoundation/CFData.h>
30 #include <CoreFoundation/CFPriv.h>
31 #include "CFInternal.h"
37 #define CFDATA_MAX_SIZE ((1ULL << 42) - 1)
39 #define CFDATA_MAX_SIZE ((1ULL << 31) - 1)
42 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
44 CF_INLINE
unsigned long __CFPageSize() { return vm_page_size
; }
45 #elif DEPLOYMENT_TARGET_WINDOWS
46 CF_INLINE
unsigned long __CFPageSize() {
48 GetSystemInfo(&sysInfo
);
49 return sysInfo
.dwPageSize
;
51 #elif DEPLOYMENT_TARGET_LINUX
53 CF_INLINE
unsigned long __CFPageSize() {
54 return (unsigned long)getpagesize();
58 #define INLINE_BYTES_THRESHOLD ((4 * __CFPageSize()) - sizeof(struct __CFData) - 15)
62 CFIndex _length
; /* number of bytes */
63 CFIndex _capacity
; /* maximum number of bytes */
64 CFAllocatorRef _bytesDeallocator
; /* used only for immutable; if NULL, no deallocation */
65 uint8_t *_bytes
; /* compaction: direct access to _bytes is only valid when data is not inline */
72 Bit 3 = use given CFAllocator
73 Bit 5 = allocate collectable memory
75 Bits 1-0 are used for mutability variation
77 Bit 6 = not all bytes have been zeroed yet (mutable)
83 __kCFMutableVarietyMask
= 0x03,
84 __kCFBytesInline
= 0x04,
85 __kCFUseAllocator
= 0x08,
86 __kCFAllocatesCollectable
= 0x20,
90 kCFImmutable
= 0x0, /* unchangable and fixed capacity; default */
91 kCFFixedMutable
= 0x1, /* changeable and fixed capacity */
92 kCFMutable
= 0x3 /* changeable and variable capacity */
95 CF_INLINE
void __CFDataSetInfoBits(CFDataRef data
, UInt32 v
) {__CFBitfieldSetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 5, 0, v
);}
96 CF_INLINE Boolean
__CFDataGetInfoBit(CFDataRef data
, UInt32 b
) {return ((((const CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
] & b
) != 0);}
97 CF_INLINE Boolean
__CFDataIsMutable(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFMutable
);}
98 CF_INLINE Boolean
__CFDataIsGrowable(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFGrowable
);}
99 CF_INLINE Boolean
__CFDataBytesInline(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFBytesInline
);}
100 CF_INLINE Boolean
__CFDataUseAllocator(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFUseAllocator
);}
101 CF_INLINE Boolean
__CFDataAllocatesCollectable(CFDataRef data
) {return __CFDataGetInfoBit(data
, __kCFAllocatesCollectable
);}
103 CF_INLINE UInt32
__CFMutableVariety(const void *cf
) {
104 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
107 CF_INLINE
void __CFSetMutableVariety(void *cf
, UInt32 v
) {
108 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 1, 0, v
);
111 CF_INLINE UInt32
__CFMutableVarietyFromFlags(UInt32 flags
) {
112 return (flags
& __kCFMutableVarietyMask
);
115 #define __CFGenericValidateMutabilityFlags(flags) \
116 CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags);
118 CF_INLINE
void __CFDataSetInline(CFDataRef data
, Boolean flag
) {
119 __CFBitfieldSetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 2, 2, (flag
? 1 : 0));
122 CF_INLINE Boolean
__CFDataNeedsToZero(CFDataRef data
) {
123 return __CFBitfieldGetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 6, 6);
126 CF_INLINE
void __CFDataSetNeedsToZero(CFDataRef data
, Boolean zero
) {
127 __CFBitfieldSetValue(((CFRuntimeBase
*)data
)->_cfinfo
[CF_INFO_BITS
], 6, 6, (zero
? 1 : 0));
130 CF_INLINE CFIndex
__CFDataLength(CFDataRef data
) {
131 return data
->_length
;
134 CF_INLINE
void __CFDataSetLength(CFMutableDataRef data
, CFIndex v
) {
135 /* for a CFData, _bytesUsed == _length */
138 CF_INLINE CFIndex
__CFDataCapacity(CFDataRef data
) {
139 return data
->_capacity
;
142 CF_INLINE
void __CFDataSetCapacity(CFMutableDataRef data
, CFIndex v
) {
143 /* for a CFData, _bytesNum == _capacity */
146 CF_INLINE
void __CFDataSetNumBytesUsed(CFMutableDataRef data
, CFIndex v
) {
150 CF_INLINE CFIndex
__CFDataNumBytes(CFDataRef data
) {
151 return data
->_capacity
;
154 CF_INLINE
void __CFDataSetNumBytes(CFMutableDataRef data
, CFIndex v
) {
159 #define CHUNK_SIZE (1ULL << 29)
160 #define LOW_THRESHOLD (1ULL << 20)
161 #define HIGH_THRESHOLD (1ULL << 32)
163 #define CHUNK_SIZE (1ULL << 26)
164 #define LOW_THRESHOLD (1ULL << 20)
165 #define HIGH_THRESHOLD (1ULL << 29)
168 CF_INLINE CFIndex
__CFDataRoundUpCapacity(CFIndex capacity
) {
171 } else if (capacity
< LOW_THRESHOLD
) {
173 long idx
= flsl(capacity
);
174 return (1L << (long)(idx
+ ((idx
% 2 == 0) ? 0 : 1)));
175 } else if (capacity
< HIGH_THRESHOLD
) {
177 return (1L << (long)flsl(capacity
));
179 /* Round up to next multiple of CHUNK_SIZE */
180 unsigned long newCapacity
= CHUNK_SIZE
* (1+(capacity
>> ((long)flsl(CHUNK_SIZE
)-1)));
181 return __CFMin(newCapacity
, CFDATA_MAX_SIZE
);
185 CF_INLINE CFIndex
__CFDataNumBytesForCapacity(CFIndex capacity
) {
189 static void __CFDataHandleOutOfMemory(CFTypeRef obj
, CFIndex numBytes
) {
191 if(0 < numBytes
&& numBytes
<= CFDATA_MAX_SIZE
) {
192 msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for NS/CFData failed"), numBytes
);
194 msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for NS/CFData failed. Maximum size: %lld"), numBytes
, CFDATA_MAX_SIZE
);
197 CFLog(kCFLogLevelCritical
, CFSTR("%@"), msg
);
204 CF_INLINE
void __CFDataValidateRange(CFDataRef data
, CFRange range
, const char *func
) {
205 CFAssert2(0 <= range
.location
&& range
.location
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): range.location index (%d) out of bounds", func
, range
.location
);
206 CFAssert2(0 <= range
.length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", func
, range
.length
);
207 CFAssert2(range
.location
+ range
.length
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): ending index (%d) out of bounds", func
, range
.location
+ range
.length
);
210 #define __CFDataValidateRange(a,r,f)
213 static Boolean
__CFDataEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
214 CFDataRef data1
= (CFDataRef
)cf1
;
215 CFDataRef data2
= (CFDataRef
)cf2
;
217 length
= __CFDataLength(data1
);
218 if (length
!= __CFDataLength(data2
)) return false;
219 const uint8_t *bytePtr1
= CFDataGetBytePtr(data1
);
220 const uint8_t *bytePtr2
= CFDataGetBytePtr(data2
);
221 return 0 == memcmp(bytePtr1
, bytePtr2
, length
);
224 static CFHashCode
__CFDataHash(CFTypeRef cf
) {
225 CFDataRef data
= (CFDataRef
)cf
;
226 return CFHashBytes((uint8_t *)CFDataGetBytePtr(data
), __CFMin(__CFDataLength(data
), 80));
229 static CFStringRef
__CFDataCopyDescription(CFTypeRef cf
) {
230 CFDataRef data
= (CFDataRef
)cf
;
231 CFMutableStringRef result
;
234 const uint8_t *bytes
;
235 len
= __CFDataLength(data
);
236 bytes
= CFDataGetBytePtr(data
);
237 result
= CFStringCreateMutable(CFGetAllocator(data
), 0);
238 CFStringAppendFormat(result
, NULL
, CFSTR("<CFData %p [%p]>{length = %lu, capacity = %lu, bytes = 0x"), cf
, CFGetAllocator(data
), (unsigned long)len
, (unsigned long)__CFDataCapacity(data
));
240 for (idx
= 0; idx
< 16; idx
+= 4) {
241 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
243 CFStringAppend(result
, CFSTR(" ... "));
244 for (idx
= len
- 8; idx
< len
; idx
+= 4) {
245 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
248 for (idx
= 0; idx
< len
; idx
++) {
249 CFStringAppendFormat(result
, NULL
, CFSTR("%02x"), bytes
[idx
]);
252 CFStringAppend(result
, CFSTR("}"));
256 static void *__CFDataInlineBytesPtr(CFDataRef data
) {
257 return (void *)((uintptr_t)((int8_t *)data
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
260 static Boolean
__CFDataShouldAllocateCleared(CFDataRef data
, CFIndex size
) {
262 if (__CFDataUseAllocator(data
)) {
265 if (__CFDataAllocatesCollectable(data
)) {
269 result
= (size
> (64 * 1024));
272 result
= (size
> (128 * 1024));
279 // Check __CFDataShouldAllocateCleared before passing true.
280 static void *__CFDataAllocate(CFDataRef data
, CFIndex size
, Boolean clear
) {
282 if (__CFDataUseAllocator(data
)) {
283 CFAllocatorRef allocator
= __CFGetAllocator(data
);
284 bytes
= CFAllocatorAllocate(allocator
, size
, 0);
285 if (clear
) memset((uint8_t *)bytes
, 0, size
);
287 if (__CFDataAllocatesCollectable(data
)) {
288 bytes
= auto_zone_allocate_object(objc_collectableZone(), size
, AUTO_MEMORY_UNSCANNED
, 0, clear
);
291 bytes
= calloc(1, size
);
293 bytes
= malloc(size
);
300 static void __CFDataDeallocate(CFTypeRef cf
) {
301 CFMutableDataRef data
= (CFMutableDataRef
)cf
;
302 if (!__CFDataBytesInline(data
)) {
303 CFAllocatorRef deallocator
= data
->_bytesDeallocator
;
304 if (deallocator
!= NULL
) {
305 _CFAllocatorDeallocateGC(deallocator
, data
->_bytes
);
306 CFRelease(deallocator
);
309 if (__CFDataUseAllocator(data
)) {
310 _CFAllocatorDeallocateGC(__CFGetAllocator(data
), data
->_bytes
);
311 } else if (!__CFDataAllocatesCollectable(data
) && data
->_bytes
) {
319 static CFTypeID __kCFDataTypeID
= _kCFRuntimeNotATypeID
;
321 static const CFRuntimeClass __CFDataClass
= {
322 _kCFRuntimeScannedObject
,
330 __CFDataCopyDescription
333 CFTypeID
CFDataGetTypeID(void) {
334 static dispatch_once_t initOnce
;
335 dispatch_once(&initOnce
, ^{ __kCFDataTypeID
= _CFRuntimeRegisterClass(&__CFDataClass
); });
336 return __kCFDataTypeID
;
340 // NULL bytesDeallocator to this function does not mean the default allocator, it means
341 // that there should be no deallocator, and the bytes should be copied.
342 static CFMutableDataRef
__CFDataInit(CFAllocatorRef allocator
, CFOptionFlags flags
, CFIndex capacity
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
343 CFMutableDataRef memory
;
344 __CFGenericValidateMutabilityFlags(flags
);
345 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
346 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
);
347 CFAssert2(0 <= length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", __PRETTY_FUNCTION__
, length
);
349 Boolean collectableMemory
= CF_IS_COLLECTABLE_ALLOCATOR(allocator
);
350 Boolean noCopy
= bytesDeallocator
!= NULL
;
351 Boolean isMutable
= ((flags
& __kCFMutable
) != 0);
352 Boolean isGrowable
= ((flags
& __kCFGrowable
) != 0);
353 Boolean allocateInline
= !isGrowable
&& !noCopy
&& capacity
< INLINE_BYTES_THRESHOLD
;
354 allocator
= (allocator
== NULL
) ? __CFGetDefaultAllocator() : allocator
;
355 Boolean useAllocator
= (allocator
!= kCFAllocatorSystemDefault
&& allocator
!= kCFAllocatorMalloc
&& allocator
!= kCFAllocatorMallocZone
);
357 CFIndex size
= sizeof(struct __CFData
) - sizeof(CFRuntimeBase
);
358 if (allocateInline
) {
359 size
+= sizeof(uint8_t) * __CFDataNumBytesForCapacity(capacity
) + sizeof(uint8_t) * 15; // for 16-byte alignment fixup
361 memory
= (CFMutableDataRef
)_CFRuntimeCreateInstance(allocator
, CFDataGetTypeID(), size
, NULL
);
362 if (NULL
== memory
) {
365 __CFDataSetNumBytesUsed(memory
, 0);
366 __CFDataSetLength(memory
, 0);
367 __CFDataSetInfoBits(memory
,
368 (allocateInline
? __kCFBytesInline
: 0) |
369 (useAllocator
? __kCFUseAllocator
: 0) |
370 (collectableMemory
? __kCFAllocatesCollectable
: 0));
374 if (collectableMemory
) {
375 if (allocateInline
) {
376 // We have no pointer to anything that needs to be reclaimed, so don't scan or finalize.
380 if (CF_IS_COLLECTABLE_ALLOCATOR(bytesDeallocator
)) {
381 // We're taking responsibility for externally GC-allocated memory, so scan us, but we don't need to finalize.
383 } else if (bytesDeallocator
== kCFAllocatorNull
) {
384 // We don't have responsibility for these bytes, so there's no need to be scanned and we don't need to finalize.
388 // We have a pointer to non-GC-allocated memory, so don't scan, but do finalize.
392 if (!scan
) auto_zone_set_unscanned(objc_collectableZone(), memory
);
393 if (!finalize
) auto_zone_set_nofinalize(objc_collectableZone(), memory
);
395 if (isMutable
&& isGrowable
) {
396 __CFDataSetCapacity(memory
, __CFDataRoundUpCapacity(1));
397 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(__CFDataRoundUpCapacity(1)));
398 __CFSetMutableVariety(memory
, kCFMutable
);
400 /* Don't round up capacity */
401 __CFDataSetCapacity(memory
, capacity
);
402 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
403 __CFSetMutableVariety(memory
, kCFFixedMutable
);
406 __CFAssignWithWriteBarrier((void **)&memory
->_bytes
, (uint8_t *)bytes
);
409 memory
->_bytesDeallocator
= bytesDeallocator
;
411 memory
->_bytesDeallocator
= (CFAllocatorRef
)CFRetain(bytesDeallocator
);
414 if (CF_IS_COLLECTABLE_ALLOCATOR(bytesDeallocator
) && !(0)) {
415 // we 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.
416 auto_zone_release(objc_collectableZone(), memory
->_bytes
);
418 __CFDataSetNumBytesUsed(memory
, length
);
419 __CFDataSetLength(memory
, length
);
420 // Mutable no-copy datas are not allowed, so don't bother setting needsToZero flag.
422 Boolean cleared
= (isMutable
&& !isGrowable
&& !_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
));
423 if (!allocateInline
) {
424 // assume that allocators give 16-byte aligned memory back -- it is their responsibility
425 __CFAssignWithWriteBarrier((void **)&memory
->_bytes
, __CFDataAllocate(memory
, __CFDataNumBytes(memory
) * sizeof(uint8_t), cleared
));
426 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
->_bytes
, "CFData (store)");
427 if (NULL
== memory
->_bytes
) {
432 if (length
== 0 && !isMutable
) {
433 // NSData sets its bytes pointer to NULL when its length is zero. Starting in 10.7 we do the same for CFData.
434 memory
->_bytes
= NULL
;
435 // It is important to set this data as not inlined, so we do not recalculate a bytes pointer from null.
436 __CFDataSetInline(memory
, false);
440 __CFDataSetNeedsToZero(memory
, !cleared
);
441 memory
->_bytesDeallocator
= NULL
;
442 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
444 __CFSetMutableVariety(memory
, __CFMutableVarietyFromFlags(flags
));
448 CFDataRef
CFDataCreate(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
) {
449 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, NULL
);
452 CFDataRef
CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
453 CFAssert1((0 == length
|| bytes
!= NULL
), __kCFLogAssertion
, "%s(): bytes pointer cannot be NULL if length is non-zero", __PRETTY_FUNCTION__
);
454 if (NULL
== bytesDeallocator
) bytesDeallocator
= __CFGetDefaultAllocator();
455 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, bytesDeallocator
);
458 CFDataRef
CFDataCreateCopy(CFAllocatorRef allocator
, CFDataRef data
) {
459 CFIndex length
= CFDataGetLength(data
);
460 return __CFDataInit(allocator
, kCFImmutable
, length
, CFDataGetBytePtr(data
), length
, NULL
);
463 CFMutableDataRef
CFDataCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
) {
464 // Do not allow magic allocator for now for mutable datas, because it
465 // isn't remembered for proper handling later when growth of the buffer
467 Boolean wasMagic
= (0);
468 CFMutableDataRef r
= (CFMutableDataRef
)__CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, NULL
, 0, NULL
);
469 if (wasMagic
) CFMakeCollectable(r
);
473 CFMutableDataRef
CFDataCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFDataRef data
) {
474 // Do not allow magic allocator for now for mutable datas, because it
475 // isn't remembered for proper handling later when growth of the buffer
477 Boolean wasMagic
= (0);
478 CFMutableDataRef r
= (CFMutableDataRef
) __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, CFDataGetBytePtr(data
), CFDataGetLength(data
), NULL
);
479 if (wasMagic
) CFMakeCollectable(r
);
483 CFIndex
CFDataGetLength(CFDataRef data
) {
484 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), CFIndex
, (NSData
*)data
, length
);
485 __CFGenericValidateType(data
, CFDataGetTypeID());
486 return __CFDataLength(data
);
489 const uint8_t *CFDataGetBytePtr(CFDataRef data
) {
490 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), const uint8_t *, (NSData
*)data
, bytes
);
491 __CFGenericValidateType(data
, CFDataGetTypeID());
492 // compaction: if inline, always do the computation.
493 return __CFDataBytesInline(data
) ? (uint8_t *)__CFDataInlineBytesPtr(data
) : data
->_bytes
;
496 uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data
) {
497 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), uint8_t *, (NSMutableData
*)data
, mutableBytes
);
498 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
499 // compaction: if inline, always do the computation.
500 return __CFDataBytesInline(data
) ? (uint8_t *)__CFDataInlineBytesPtr(data
) : data
->_bytes
;
503 void CFDataGetBytes(CFDataRef data
, CFRange range
, uint8_t *buffer
) {
504 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSData
*)data
, getBytes
:(void *)buffer range
:NSMakeRange(range
.location
, range
.length
));
505 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
506 memmove(buffer
, CFDataGetBytePtr(data
) + range
.location
, range
.length
);
509 /* 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. */
510 static void __CFDataGrow(CFMutableDataRef data
, CFIndex numNewValues
, Boolean clear
) {
511 CFIndex oldLength
= __CFDataLength(data
);
512 CFIndex newLength
= oldLength
+ numNewValues
;
513 if (newLength
> CFDATA_MAX_SIZE
|| newLength
< 0) __CFDataHandleOutOfMemory(data
, newLength
* sizeof(uint8_t));
514 CFIndex capacity
= __CFDataRoundUpCapacity(newLength
);
515 CFIndex numBytes
= __CFDataNumBytesForCapacity(capacity
);
516 CFAllocatorRef allocator
= CFGetAllocator(data
);
518 void *oldBytes
= data
->_bytes
;
519 Boolean allocateCleared
= clear
&& __CFDataShouldAllocateCleared(data
, numBytes
);
520 if (allocateCleared
&& !__CFDataUseAllocator(data
) && (oldLength
== 0 || (newLength
/ oldLength
) > 4)) {
521 // 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.
522 bytes
= __CFDataAllocate(data
, numBytes
* sizeof(uint8_t), true);
524 memmove(bytes
, oldBytes
, oldLength
);
525 __CFDataDeallocate(data
);
529 // If the calloc/memmove approach either failed or was never attempted, then realloc.
530 allocateCleared
= false;
531 if (__CFDataUseAllocator(data
)) {
532 bytes
= CFAllocatorReallocate(allocator
, oldBytes
, numBytes
* sizeof(uint8_t), 0);
534 bytes
= realloc(oldBytes
, numBytes
* sizeof(uint8_t));
537 if (NULL
== bytes
) __CFDataHandleOutOfMemory(data
, numBytes
* sizeof(uint8_t));
538 __CFDataSetCapacity(data
, capacity
);
539 __CFDataSetNumBytes(data
, numBytes
);
540 if (clear
&& !allocateCleared
&& oldLength
< newLength
) memset((uint8_t *)bytes
+ oldLength
, 0, newLength
- oldLength
);
541 __CFDataSetNeedsToZero(data
, !allocateCleared
);
542 __CFAssignWithWriteBarrier((void **)&data
->_bytes
, bytes
);
543 if (__CFOASafe
) __CFSetLastAllocationEventName(data
->_bytes
, "CFData (store)");
546 void CFDataSetLength(CFMutableDataRef data
, CFIndex newLength
) {
547 CFIndex oldLength
, capacity
;
549 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSMutableData
*)data
, setLength
:(NSUInteger
)newLength
);
550 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
551 oldLength
= __CFDataLength(data
);
552 capacity
= __CFDataCapacity(data
);
553 isGrowable
= __CFDataIsGrowable(data
);
554 if (__CFDataIsMutable(data
)) {
557 __CFDataHandleOutOfMemory(data
, newLength
);
561 } else if (capacity
< newLength
) {
563 __CFDataGrow(data
, newLength
- oldLength
, true);
565 CFAssert1(newLength
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
567 } else if (oldLength
< newLength
&& __CFDataNeedsToZero(data
)) {
568 memset(CFDataGetMutableBytePtr(data
) + oldLength
, 0, newLength
- oldLength
);
569 } else if (newLength
< oldLength
) {
570 __CFDataSetNeedsToZero(data
, true);
573 __CFDataSetLength(data
, newLength
);
574 __CFDataSetNumBytesUsed(data
, newLength
);
577 void CFDataIncreaseLength(CFMutableDataRef data
, CFIndex extraLength
) {
578 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSMutableData
*)data
, increaseLengthBy
:(NSUInteger
)extraLength
);
579 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
580 if (extraLength
< 0) HALT
; // Avoid integer overflow.
581 CFDataSetLength(data
, __CFDataLength(data
) + extraLength
);
584 void CFDataAppendBytes(CFMutableDataRef data
, const uint8_t *bytes
, CFIndex length
) {
585 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSMutableData
*)data
, appendBytes
:(const void *)bytes length
:(NSUInteger
)length
);
586 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
587 CFDataReplaceBytes(data
, CFRangeMake(__CFDataLength(data
), 0), bytes
, length
);
590 void CFDataDeleteBytes(CFMutableDataRef data
, CFRange range
) {
591 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSMutableData
*)data
, replaceBytesInRange
:NSMakeRange(range
.location
, range
.length
) withBytes
:NULL length
:0);
592 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
593 CFDataReplaceBytes(data
, range
, NULL
, 0);
596 void CFDataReplaceBytes(CFMutableDataRef data
, CFRange range
, const uint8_t *newBytes
, CFIndex newLength
) {
597 CF_OBJC_FUNCDISPATCHV(CFDataGetTypeID(), void, (NSMutableData
*)data
, replaceBytesInRange
:NSMakeRange(range
.location
, range
.length
) withBytes
:(const void *)newBytes length
:(NSUInteger
)newLength
);
598 __CFGenericValidateType(data
, CFDataGetTypeID());
599 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
600 CFAssert1(__CFDataIsMutable(data
), __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
601 CFAssert2(0 <= newLength
, __kCFLogAssertion
, "%s(): newLength (%d) cannot be less than zero", __PRETTY_FUNCTION__
, newLength
);
603 CFIndex len
= __CFDataLength(data
);
604 if (len
< 0 || range
.length
< 0 || newLength
< 0) HALT
;
605 CFIndex newCount
= len
- range
.length
+ newLength
;
606 if (newCount
< 0) HALT
;
608 uint8_t *bytePtr
= (uint8_t *)CFDataGetMutableBytePtr(data
);
609 uint8_t *srcBuf
= (uint8_t *)newBytes
;
610 switch (__CFMutableVariety(data
)) {
612 if (__CFDataNumBytes(data
) < newCount
) {
613 if (bytePtr
&& newBytes
&& newBytes
< bytePtr
+ __CFDataCapacity(data
) && bytePtr
< newBytes
+ newLength
) {
614 srcBuf
= (uint8_t *)malloc(newLength
* sizeof(uint8_t));
615 memmove(srcBuf
, newBytes
, newLength
* sizeof(uint8_t));
617 __CFDataGrow(data
, newLength
- range
.length
, false);
618 bytePtr
= (uint8_t *)CFDataGetMutableBytePtr(data
);
621 case kCFFixedMutable
:
622 CFAssert1(newCount
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
623 // Continuing after this could cause buffer overruns.
624 if (newCount
> __CFDataCapacity(data
)) HALT
;
627 if (newLength
!= range
.length
&& range
.location
+ range
.length
< len
) {
628 memmove(bytePtr
+ range
.location
+ newLength
, bytePtr
+ range
.location
+ range
.length
, (len
- range
.location
- range
.length
) * sizeof(uint8_t));
631 memmove(bytePtr
+ range
.location
, srcBuf
, newLength
* sizeof(uint8_t));
633 if (srcBuf
!= newBytes
) free(srcBuf
);
634 __CFDataSetNumBytesUsed(data
, newCount
);
635 __CFDataSetLength(data
, newCount
);
638 #define REVERSE_BUFFER(type, buf, len) { \
640 for(int i = 0; i < (len)/2; i++) { \
642 (buf)[i] = (buf)[(len) - i - 1]; \
643 (buf)[(len) - i - 1] = tmp; \
647 static void _computeGoodSubstringShift(const uint8_t *needle
, int needleLength
, unsigned long shift
[], unsigned long suff
[]) {
650 // Compute suffix lengths
652 suff
[needleLength
- 1] = needleLength
;
653 f
= g
= needleLength
- 1;
654 for (i
= needleLength
- 2; i
>= 0; --i
) {
655 if (i
> g
&& suff
[i
+ needleLength
- 1 - f
] < i
- g
)
656 suff
[i
] = suff
[i
+ needleLength
- 1 - f
];
661 while (g
>= 0 && needle
[g
] == needle
[g
+ needleLength
- 1 - f
])
667 // Compute shift table
669 for (i
= 0; i
< needleLength
; ++i
)
670 shift
[i
] = needleLength
;
672 for (i
= needleLength
- 1; i
>= 0; --i
)
673 if (suff
[i
] == i
+ 1)
674 for (; j
< needleLength
- 1 - i
; ++j
)
675 if (shift
[j
] == needleLength
)
676 shift
[j
] = needleLength
- 1 - i
;
677 // 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.
678 for (i
= 0; i
<= needleLength
- 2; ++i
)
679 shift
[needleLength
- 1 - suff
[i
]] = needleLength
- 1 - i
;
680 // Since the Boyer-Moore algorithm moves the pointer back while scanning substrings, add the distance to the end of the potential substring.
681 for (i
= 0; i
< needleLength
- 1; ++i
) {
682 shift
[i
] += (needleLength
- 1 - i
);
686 static const uint8_t * __CFDataSearchBoyerMoore(const CFDataRef data
, const uint8_t *haystack
, unsigned long haystackLength
, const uint8_t *needle
, unsigned long needleLength
, Boolean backwards
) {
687 unsigned long badCharacterShift
[UCHAR_MAX
+ 1] = {0};
688 unsigned long *goodSubstringShift
= (unsigned long *)malloc(needleLength
* sizeof(unsigned long));
689 unsigned long *suffixLengths
= (unsigned long *)malloc(needleLength
* sizeof(unsigned long));
690 if (!goodSubstringShift
|| !suffixLengths
) {
691 __CFDataHandleOutOfMemory(data
, needleLength
* sizeof(unsigned long));
695 for (int i
= 0; i
< sizeof(badCharacterShift
) / sizeof(*badCharacterShift
); i
++)
696 badCharacterShift
[i
] = needleLength
;
698 for (int i
= needleLength
- 1; i
>= 0; i
--)
699 badCharacterShift
[needle
[i
]] = i
;
701 // To get the correct shift table for backwards search reverse the needle, compute the forwards shift table, and then reverse the result.
702 uint8_t *needleCopy
= (uint8_t *)malloc(needleLength
* sizeof(uint8_t));
704 __CFDataHandleOutOfMemory(data
, needleLength
* sizeof(uint8_t));
706 memmove(needleCopy
, needle
, needleLength
);
707 REVERSE_BUFFER(uint8_t, needleCopy
, needleLength
);
708 _computeGoodSubstringShift(needleCopy
, needleLength
, goodSubstringShift
, suffixLengths
);
709 REVERSE_BUFFER(unsigned long, goodSubstringShift
, needleLength
);
712 for (int i
= 0; i
< sizeof(badCharacterShift
) / sizeof(*badCharacterShift
); i
++)
713 badCharacterShift
[i
] = needleLength
;
715 for (int i
= 0; i
< needleLength
; i
++)
716 badCharacterShift
[needle
[i
]] = needleLength
- i
- 1;
718 _computeGoodSubstringShift(needle
, needleLength
, goodSubstringShift
, suffixLengths
);
721 const uint8_t *scan_needle
;
722 const uint8_t *scan_haystack
;
723 const uint8_t *result
= NULL
;
725 const uint8_t *const end_needle
= needle
+ needleLength
;
726 scan_needle
= needle
;
727 scan_haystack
= haystack
+ haystackLength
- needleLength
;
728 while (scan_haystack
>= haystack
&& scan_needle
< end_needle
) {
729 if (*scan_haystack
== *scan_needle
) {
733 scan_haystack
-= __CFMax(badCharacterShift
[*scan_haystack
], goodSubstringShift
[scan_needle
- needle
]);
734 scan_needle
= needle
;
737 if (scan_needle
== end_needle
) {
738 result
= (scan_haystack
- needleLength
);
741 const uint8_t *const end_haystack
= haystack
+ haystackLength
;
742 scan_needle
= needle
+ needleLength
- 1;
743 scan_haystack
= haystack
+ needleLength
- 1;
744 while (scan_haystack
< end_haystack
&& scan_needle
>= needle
) {
745 if (*scan_haystack
== *scan_needle
) {
749 scan_haystack
+= __CFMax(badCharacterShift
[*scan_haystack
], goodSubstringShift
[scan_needle
- needle
]);
750 scan_needle
= needle
+ needleLength
- 1;
753 if (scan_needle
< needle
) {
754 result
= (scan_haystack
+ 1);
758 free(goodSubstringShift
);
764 CFRange
_CFDataFindBytes(CFDataRef data
, CFDataRef dataToFind
, CFRange searchRange
, CFDataSearchFlags compareOptions
) {
765 const uint8_t *fullHaystack
= CFDataGetBytePtr(data
);
766 const uint8_t *needle
= CFDataGetBytePtr(dataToFind
);
767 unsigned long fullHaystackLength
= CFDataGetLength(data
);
768 unsigned long needleLength
= CFDataGetLength(dataToFind
);
770 if(compareOptions
& kCFDataSearchAnchored
) {
771 if(searchRange
.length
> needleLength
) {
772 if(compareOptions
& kCFDataSearchBackwards
) {
773 searchRange
.location
+= (searchRange
.length
- needleLength
);
775 searchRange
.length
= needleLength
;
778 if(searchRange
.length
> fullHaystackLength
- searchRange
.location
) {
779 searchRange
.length
= fullHaystackLength
- searchRange
.location
;
782 if(searchRange
.length
< needleLength
|| fullHaystackLength
== 0 || needleLength
== 0) {
783 return CFRangeMake(kCFNotFound
, 0);
786 const uint8_t *haystack
= fullHaystack
+ searchRange
.location
;
787 const uint8_t *searchResult
= __CFDataSearchBoyerMoore(data
, haystack
, searchRange
.length
, needle
, needleLength
, (compareOptions
& kCFDataSearchBackwards
) != 0);
788 CFIndex resultLocation
= (searchResult
== NULL
) ? kCFNotFound
: searchRange
.location
+ (searchResult
- haystack
);
790 return CFRangeMake(resultLocation
, resultLocation
== kCFNotFound
? 0: needleLength
);
793 CFRange
CFDataFind(CFDataRef data
, CFDataRef dataToFind
, CFRange searchRange
, CFDataSearchFlags compareOptions
) {
795 __CFGenericValidateType(data
, CFDataGetTypeID());
796 __CFGenericValidateType(dataToFind
, CFDataGetTypeID());
797 __CFDataValidateRange(data
, searchRange
, __PRETTY_FUNCTION__
);
799 return _CFDataFindBytes(data
, dataToFind
, searchRange
, compareOptions
);
802 #undef __CFDataValidateRange
803 #undef __CFGenericValidateMutabilityFlags
804 #undef INLINE_BYTES_THRESHOLD
805 #undef CFDATA_MAX_SIZE
806 #undef REVERSE_BUFFER