2 * Copyright (c) 2008 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@
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFData.h>
30 #include "CFInternal.h"
35 CFIndex _length
; /* number of bytes */
36 CFIndex _capacity
; /* maximum number of bytes */
37 CFAllocatorRef _bytesDeallocator
; /* used only for immutable; if NULL, no deallocation */
41 /* Bits 3-2 are used for mutability variation */
43 CF_INLINE UInt32
__CFMutableVariety(const void *cf
) {
44 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 2);
47 CF_INLINE
void __CFSetMutableVariety(void *cf
, UInt32 v
) {
48 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 2, v
);
51 CF_INLINE UInt32
__CFMutableVarietyFromFlags(UInt32 flags
) {
52 return __CFBitfieldGetValue(flags
, 1, 0);
55 #define __CFGenericValidateMutabilityFlags(flags) \
56 CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags);
58 CF_INLINE CFIndex
__CFDataLength(CFDataRef data
) {
62 CF_INLINE
void __CFDataSetLength(CFMutableDataRef data
, CFIndex v
) {
63 /* for a CFData, _bytesUsed == _length */
66 CF_INLINE CFIndex
__CFDataCapacity(CFDataRef data
) {
67 return data
->_capacity
;
70 CF_INLINE
void __CFDataSetCapacity(CFMutableDataRef data
, CFIndex v
) {
71 /* for a CFData, _bytesNum == _capacity */
74 CF_INLINE CFIndex
__CFDataNumBytesUsed(CFDataRef data
) {
78 CF_INLINE
void __CFDataSetNumBytesUsed(CFMutableDataRef data
, CFIndex v
) {
82 CF_INLINE CFIndex
__CFDataNumBytes(CFDataRef data
) {
83 return data
->_capacity
;
86 CF_INLINE
void __CFDataSetNumBytes(CFMutableDataRef data
, CFIndex v
) {
90 CF_INLINE CFIndex
__CFDataRoundUpCapacity(CFIndex capacity
) {
91 if (capacity
< 16) return 16;
92 // CF: quite probably, this doubling should slow as the data gets larger and larger; should not use strict doubling
93 return (1 << flsl(capacity
));
96 CF_INLINE CFIndex
__CFDataNumBytesForCapacity(CFIndex capacity
) {
100 static void __CFDataHandleOutOfMemory(CFTypeRef obj
, CFIndex numBytes
) {
101 CFStringRef msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for NS/CFData failed"), numBytes
);
102 CFBadErrorCallBack cb
= _CFGetOutOfMemoryErrorCallBack();
103 if (NULL
== cb
|| !cb(obj
, CFSTR("NS/CFData"), msg
)) {
104 CFLog(kCFLogLevelCritical
, CFSTR("%@"), msg
);
111 CF_INLINE
void __CFDataValidateRange(CFDataRef data
, CFRange range
, const char *func
) {
112 CFAssert2(0 <= range
.location
&& range
.location
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): range.location index (%d) out of bounds", func
, range
.location
);
113 CFAssert2(0 <= range
.length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", func
, range
.length
);
114 CFAssert2(range
.location
+ range
.length
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): ending index (%d) out of bounds", func
, range
.location
+ range
.length
);
117 #define __CFDataValidateRange(a,r,f)
120 static Boolean
__CFDataEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
121 CFDataRef data1
= (CFDataRef
)cf1
;
122 CFDataRef data2
= (CFDataRef
)cf2
;
124 length
= __CFDataLength(data1
);
125 if (length
!= __CFDataLength(data2
)) return false;
126 return 0 == memcmp(data1
->_bytes
, data2
->_bytes
, length
);
129 static CFHashCode
__CFDataHash(CFTypeRef cf
) {
130 CFDataRef data
= (CFDataRef
)cf
;
131 return CFHashBytes(data
->_bytes
, __CFMin(__CFDataLength(data
), 80));
134 static CFStringRef
__CFDataCopyDescription(CFTypeRef cf
) {
135 CFDataRef data
= (CFDataRef
)cf
;
136 CFMutableStringRef result
;
139 const uint8_t *bytes
;
140 len
= __CFDataLength(data
);
141 bytes
= data
->_bytes
;
142 result
= CFStringCreateMutable(CFGetAllocator(data
), 0);
143 CFStringAppendFormat(result
, NULL
, CFSTR("<CFData %p [%p]>{length = %u, capacity = %u, bytes = 0x"), cf
, CFGetAllocator(data
), len
, __CFDataCapacity(data
));
145 for (idx
= 0; idx
< 16; idx
+= 4) {
146 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
148 CFStringAppend(result
, CFSTR(" ... "));
149 for (idx
= len
- 8; idx
< len
; idx
+= 4) {
150 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
153 for (idx
= 0; idx
< len
; idx
++) {
154 CFStringAppendFormat(result
, NULL
, CFSTR("%02x"), bytes
[idx
]);
157 CFStringAppend(result
, CFSTR("}"));
162 kCFImmutable
= 0x0, /* unchangable and fixed capacity; default */
163 kCFMutable
= 0x1, /* changeable and variable capacity */
164 kCFFixedMutable
= 0x3 /* changeable and fixed capacity */
167 static void __CFDataDeallocate(CFTypeRef cf
) {
168 CFMutableDataRef data
= (CFMutableDataRef
)cf
;
169 CFAllocatorRef allocator
= __CFGetAllocator(data
);
170 switch (__CFMutableVariety(data
)) {
172 _CFAllocatorDeallocateGC(allocator
, data
->_bytes
);
175 case kCFFixedMutable
:
178 if (NULL
!= data
->_bytesDeallocator
) {
179 if (CF_IS_COLLECTABLE_ALLOCATOR(data
->_bytesDeallocator
)) {
180 // GC: for finalization safety, let collector reclaim the buffer in the next GC cycle.
181 auto_zone_release(__CFCollectableZone
, data
->_bytes
);
183 CFAllocatorDeallocate(data
->_bytesDeallocator
, data
->_bytes
);
184 CFRelease(data
->_bytesDeallocator
);
192 static CFTypeID __kCFDataTypeID
= _kCFRuntimeNotATypeID
;
194 static const CFRuntimeClass __CFDataClass
= {
203 __CFDataCopyDescription
206 __private_extern__
void __CFDataInitialize(void) {
207 __kCFDataTypeID
= _CFRuntimeRegisterClass(&__CFDataClass
);
210 CFTypeID
CFDataGetTypeID(void) {
211 return __kCFDataTypeID
;
214 // NULL bytesDeallocator to this function does not mean the default allocator, it means
215 // that there should be no deallocator, and the bytes should be copied.
216 static CFMutableDataRef
__CFDataInit(CFAllocatorRef allocator
, CFOptionFlags flags
, CFIndex capacity
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
217 CFMutableDataRef memory
;
219 __CFGenericValidateMutabilityFlags(flags
);
220 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
221 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
);
222 CFAssert2(0 <= length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", __PRETTY_FUNCTION__
, length
);
223 size
= sizeof(struct __CFData
) - sizeof(CFRuntimeBase
);
224 if (__CFMutableVarietyFromFlags(flags
) != kCFMutable
&& (bytesDeallocator
== NULL
)) {
225 size
+= sizeof(uint8_t) * __CFDataNumBytesForCapacity(capacity
);
227 if (__CFMutableVarietyFromFlags(flags
) != kCFMutable
) {
228 size
+= sizeof(uint8_t) * 15; // for 16-byte alignment fixup
230 memory
= (CFMutableDataRef
)_CFRuntimeCreateInstance(allocator
, __kCFDataTypeID
, size
, NULL
);
231 if (NULL
== memory
) {
234 __CFDataSetNumBytesUsed(memory
, 0);
235 __CFDataSetLength(memory
, 0);
236 switch (__CFMutableVarietyFromFlags(flags
)) {
238 __CFDataSetCapacity(memory
, __CFDataRoundUpCapacity(1));
239 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(__CFDataRoundUpCapacity(1)));
240 // GC: if allocated in the collectable zone, mark the object as needing to be scanned.
241 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) auto_zone_set_layout_type(__CFCollectableZone
, memory
, AUTO_MEMORY_SCANNED
);
242 // assume that allocators give 16-byte aligned memory back -- it is their responsibility
243 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, memory
, memory
->_bytes
, _CFAllocatorAllocateGC(allocator
, __CFDataNumBytes(memory
) * sizeof(uint8_t), 0));
244 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
->_bytes
, "CFData (store)");
245 if (NULL
== memory
->_bytes
) {
249 memory
->_bytesDeallocator
= NULL
;
250 __CFSetMutableVariety(memory
, kCFMutable
);
251 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
253 case kCFFixedMutable
:
254 /* Don't round up capacity */
255 __CFDataSetCapacity(memory
, capacity
);
256 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
257 memory
->_bytes
= (uint8_t *)((uintptr_t)((int8_t *)memory
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
258 memory
->_bytesDeallocator
= NULL
;
259 __CFSetMutableVariety(memory
, kCFFixedMutable
);
260 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
263 /* Don't round up capacity */
264 __CFDataSetCapacity(memory
, capacity
);
265 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
266 if (bytesDeallocator
!= NULL
) {
267 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, memory
, memory
->_bytes
, (uint8_t *)bytes
);
268 memory
->_bytesDeallocator
= (CFAllocatorRef
)CFRetain(bytesDeallocator
);
269 __CFDataSetNumBytesUsed(memory
, length
);
270 __CFDataSetLength(memory
, length
);
272 memory
->_bytes
= (uint8_t *)((uintptr_t)((int8_t *)memory
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
273 memory
->_bytesDeallocator
= NULL
;
274 __CFSetMutableVariety(memory
, kCFFixedMutable
);
275 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
279 __CFSetMutableVariety(memory
, __CFMutableVarietyFromFlags(flags
));
283 CFDataRef
CFDataCreate(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
) {
284 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, NULL
);
287 CFDataRef
CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
288 CFAssert1((0 == length
|| bytes
!= NULL
), __kCFLogAssertion
, "%s(): bytes pointer cannot be NULL if length is non-zero", __PRETTY_FUNCTION__
);
289 if (NULL
== bytesDeallocator
) bytesDeallocator
= __CFGetDefaultAllocator();
290 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, bytesDeallocator
);
293 CFDataRef
CFDataCreateCopy(CFAllocatorRef allocator
, CFDataRef data
) {
294 CFIndex length
= CFDataGetLength(data
);
295 return __CFDataInit(allocator
, kCFImmutable
, length
, CFDataGetBytePtr(data
), length
, NULL
);
298 CFMutableDataRef
CFDataCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
) {
299 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, NULL
, 0, NULL
);
302 CFMutableDataRef
CFDataCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFDataRef data
) {
303 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, CFDataGetBytePtr(data
), CFDataGetLength(data
), NULL
);
306 CFIndex
CFDataGetLength(CFDataRef data
) {
307 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, CFIndex
, data
, "length");
308 __CFGenericValidateType(data
, __kCFDataTypeID
);
309 return __CFDataLength(data
);
312 const uint8_t *CFDataGetBytePtr(CFDataRef data
) {
313 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, const uint8_t *, data
, "bytes");
314 __CFGenericValidateType(data
, __kCFDataTypeID
);
318 uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data
) {
319 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, uint8_t *, data
, "mutableBytes");
320 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
324 void CFDataGetBytes(CFDataRef data
, CFRange range
, uint8_t *buffer
) {
325 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "getBytes:range:", buffer
, range
);
326 memmove(buffer
, data
->_bytes
+ range
.location
, range
.length
);
329 static void __CFDataGrow(CFMutableDataRef data
, CFIndex numNewValues
) {
330 CFIndex oldLength
= __CFDataLength(data
);
331 CFIndex capacity
= __CFDataRoundUpCapacity(oldLength
+ numNewValues
);
332 CFAllocatorRef allocator
= CFGetAllocator(data
);
333 __CFDataSetCapacity(data
, capacity
);
334 __CFDataSetNumBytes(data
, __CFDataNumBytesForCapacity(capacity
));
335 void *bytes
= _CFAllocatorReallocateGC(allocator
, data
->_bytes
, __CFDataNumBytes(data
) * sizeof(uint8_t), 0);
336 if (NULL
== bytes
) __CFDataHandleOutOfMemory(data
, __CFDataNumBytes(data
) * sizeof(uint8_t));
337 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, data
, data
->_bytes
, bytes
);
338 if (__CFOASafe
) __CFSetLastAllocationEventName(data
->_bytes
, "CFData (store)");
341 void CFDataSetLength(CFMutableDataRef data
, CFIndex length
) {
343 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "setLength:", length
);
344 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
345 len
= __CFDataLength(data
);
346 switch (__CFMutableVariety(data
)) {
349 // CF: should only grow when new length exceeds current capacity, not whenever it exceeds the current length
350 __CFDataGrow(data
, length
- len
);
353 case kCFFixedMutable
:
354 CFAssert1(length
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
358 memset(data
->_bytes
+ len
, 0, length
- len
);
360 __CFDataSetLength(data
, length
);
361 __CFDataSetNumBytesUsed(data
, length
);
364 void CFDataIncreaseLength(CFMutableDataRef data
, CFIndex extraLength
) {
365 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "increaseLengthBy:", extraLength
);
366 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
367 CFDataSetLength(data
, __CFDataLength(data
) + extraLength
);
370 void CFDataAppendBytes(CFMutableDataRef data
, const uint8_t *bytes
, CFIndex length
) {
371 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "appendBytes:length:", bytes
, length
);
372 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
373 CFDataReplaceBytes(data
, CFRangeMake(__CFDataLength(data
), 0), bytes
, length
);
376 void CFDataDeleteBytes(CFMutableDataRef data
, CFRange range
) {
377 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, NULL
, 0);
378 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
379 CFDataReplaceBytes(data
, range
, NULL
, 0);
382 void CFDataReplaceBytes(CFMutableDataRef data
, CFRange range
, const uint8_t *newBytes
, CFIndex newLength
) {
383 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, newBytes
, newLength
);
384 __CFGenericValidateType(data
, __kCFDataTypeID
);
385 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
386 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
387 CFAssert2(0 <= newLength
, __kCFLogAssertion
, "%s(): newLength (%d) cannot be less than zero", __PRETTY_FUNCTION__
, newLength
);
389 CFIndex len
= __CFDataLength(data
);
390 if (len
< 0 || range
.length
< 0 || newLength
< 0) HALT
;
391 CFIndex newCount
= len
- range
.length
+ newLength
;
392 if (newCount
< 0) HALT
;
394 switch (__CFMutableVariety(data
)) {
396 if (__CFDataNumBytes(data
) < newCount
) {
397 __CFDataGrow(data
, newLength
- range
.length
);
400 case kCFFixedMutable
:
401 CFAssert1(newCount
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
404 if (newLength
!= range
.length
&& range
.location
+ range
.length
< len
) {
405 memmove(data
->_bytes
+ range
.location
+ newLength
, data
->_bytes
+ range
.location
+ range
.length
, (len
- range
.location
- range
.length
) * sizeof(uint8_t));
408 memmove(data
->_bytes
+ range
.location
, newBytes
, newLength
* sizeof(uint8_t));
410 __CFDataSetNumBytesUsed(data
, newCount
);
411 __CFDataSetLength(data
, newCount
);
414 #undef __CFDataValidateRange
415 #undef __CFGenericValidateMutabilityFlags