2 * Copyright (c) 2005 Apple Computer, 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>
29 #include "CFUtilitiesPriv.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
)->_info
, 3, 2);
47 CF_INLINE
void __CFSetMutableVariety(void *cf
, UInt32 v
) {
48 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 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 << (CFLog2(capacity
) + 1));
96 CF_INLINE CFIndex
__CFDataNumBytesForCapacity(CFIndex capacity
) {
101 CF_INLINE
void __CFDataValidateRange(CFDataRef data
, CFRange range
, const char *func
) {
102 CFAssert2(0 <= range
.location
&& range
.location
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): range.location index (%d) out of bounds", func
, range
.location
);
103 CFAssert2(0 <= range
.length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", func
, range
.length
);
104 CFAssert2(range
.location
+ range
.length
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): ending index (%d) out of bounds", func
, range
.location
+ range
.length
);
107 #define __CFDataValidateRange(a,r,f)
110 static bool __CFDataEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
111 CFDataRef data1
= (CFDataRef
)cf1
;
112 CFDataRef data2
= (CFDataRef
)cf2
;
114 length
= __CFDataLength(data1
);
115 if (length
!= __CFDataLength(data2
)) return false;
116 return 0 == memcmp(data1
->_bytes
, data2
->_bytes
, length
);
119 static CFHashCode
__CFDataHash(CFTypeRef cf
) {
120 CFDataRef data
= (CFDataRef
)cf
;
121 return CFHashBytes(data
->_bytes
, __CFMin(__CFDataLength(data
), 16));
124 static CFStringRef
__CFDataCopyDescription(CFTypeRef cf
) {
125 CFDataRef data
= (CFDataRef
)cf
;
126 CFMutableStringRef result
;
129 const uint8_t *bytes
;
130 len
= __CFDataLength(data
);
131 bytes
= data
->_bytes
;
132 result
= CFStringCreateMutable(CFGetAllocator(data
), 0);
133 CFStringAppendFormat(result
, NULL
, CFSTR("<CFData %p [%p]>{length = %u, capacity = %u, bytes = 0x"), cf
, CFGetAllocator(data
), len
, __CFDataCapacity(data
));
135 for (idx
= 0; idx
< 16; idx
+= 4) {
136 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
138 CFStringAppend(result
, CFSTR(" ... "));
139 for (idx
= len
- 8; idx
< len
; idx
+= 4) {
140 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
143 for (idx
= 0; idx
< len
; idx
++) {
144 CFStringAppendFormat(result
, NULL
, CFSTR("%02x"), bytes
[idx
]);
147 CFStringAppend(result
, CFSTR("}"));
152 kCFImmutable
= 0x0, /* unchangable and fixed capacity; default */
153 kCFMutable
= 0x1, /* changeable and variable capacity */
154 kCFFixedMutable
= 0x3 /* changeable and fixed capacity */
157 static void __CFDataDeallocate(CFTypeRef cf
) {
158 CFMutableDataRef data
= (CFMutableDataRef
)cf
;
159 CFAllocatorRef allocator
= CFGetAllocator(data
);
160 switch (__CFMutableVariety(data
)) {
162 _CFAllocatorDeallocateGC(allocator
, data
->_bytes
);
165 case kCFFixedMutable
:
168 if (NULL
!= data
->_bytesDeallocator
) {
169 if (CF_IS_COLLECTABLE_ALLOCATOR(data
->_bytesDeallocator
)) {
170 // GC: for finalization safety, let collector reclaim the buffer in the next GC cycle.
171 auto_zone_release(__CFCollectableZone
, data
->_bytes
);
173 CFAllocatorDeallocate(data
->_bytesDeallocator
, data
->_bytes
);
174 CFRelease(data
->_bytesDeallocator
);
182 static CFTypeID __kCFDataTypeID
= _kCFRuntimeNotATypeID
;
184 static const CFRuntimeClass __CFDataClass
= {
190 (void *)__CFDataEqual
,
193 __CFDataCopyDescription
196 __private_extern__
void __CFDataInitialize(void) {
197 __kCFDataTypeID
= _CFRuntimeRegisterClass(&__CFDataClass
);
200 CFTypeID
CFDataGetTypeID(void) {
201 return __kCFDataTypeID
;
204 // NULL bytesDeallocator to this function does not mean the default allocator, it means
205 // that there should be no deallocator, and the bytes should be copied.
206 static CFMutableDataRef
__CFDataInit(CFAllocatorRef allocator
, CFOptionFlags flags
, CFIndex capacity
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
207 CFMutableDataRef memory
;
209 __CFGenericValidateMutabilityFlags(flags
);
210 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
211 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
);
212 CFAssert2(0 <= length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", __PRETTY_FUNCTION__
, length
);
213 size
= sizeof(struct __CFData
) - sizeof(CFRuntimeBase
);
214 if (__CFMutableVarietyFromFlags(flags
) != kCFMutable
&& (bytesDeallocator
== NULL
)) {
215 size
+= sizeof(uint8_t) * __CFDataNumBytesForCapacity(capacity
);
217 if (__CFMutableVarietyFromFlags(flags
) != kCFMutable
) {
218 size
+= sizeof(uint8_t) * 15; // for 16-byte alignment fixup
220 memory
= (CFMutableDataRef
)_CFRuntimeCreateInstance(allocator
, __kCFDataTypeID
, size
, NULL
);
221 if (NULL
== memory
) {
224 __CFDataSetNumBytesUsed(memory
, 0);
225 __CFDataSetLength(memory
, 0);
226 switch (__CFMutableVarietyFromFlags(flags
)) {
228 __CFDataSetCapacity(memory
, __CFDataRoundUpCapacity(1));
229 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(__CFDataRoundUpCapacity(1)));
230 // GC: if allocated in the collectable zone, mark the object as needing to be scanned.
231 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) auto_zone_set_layout_type(__CFCollectableZone
, memory
, AUTO_MEMORY_SCANNED
);
232 // assume that allocators give 16-byte aligned memory back -- it is their responsibility
233 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, memory
, memory
->_bytes
, _CFAllocatorAllocateGC(allocator
, __CFDataNumBytes(memory
) * sizeof(uint8_t), AUTO_MEMORY_UNSCANNED
));
234 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
->_bytes
, "CFData (store)");
235 if (NULL
== memory
->_bytes
) {
239 memory
->_bytesDeallocator
= NULL
;
240 __CFSetMutableVariety(memory
, kCFMutable
);
241 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
243 case kCFFixedMutable
:
244 /* Don't round up capacity */
245 __CFDataSetCapacity(memory
, capacity
);
246 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
247 memory
->_bytes
= (uint8_t *)((uintptr_t)((int8_t *)memory
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
248 memory
->_bytesDeallocator
= NULL
;
249 __CFSetMutableVariety(memory
, kCFFixedMutable
);
250 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
253 /* Don't round up capacity */
254 __CFDataSetCapacity(memory
, capacity
);
255 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
256 if (bytesDeallocator
!= NULL
) {
257 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, memory
, memory
->_bytes
, (uint8_t *)bytes
);
258 memory
->_bytesDeallocator
= CFRetain(bytesDeallocator
);
259 __CFDataSetNumBytesUsed(memory
, length
);
260 __CFDataSetLength(memory
, length
);
262 memory
->_bytes
= (uint8_t *)((uintptr_t)((int8_t *)memory
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
263 memory
->_bytesDeallocator
= NULL
;
264 __CFSetMutableVariety(memory
, kCFFixedMutable
);
265 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
269 __CFSetMutableVariety(memory
, __CFMutableVarietyFromFlags(flags
));
273 CFDataRef
CFDataCreate(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
) {
274 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, NULL
);
277 CFDataRef
CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
278 CFAssert1((0 == length
|| bytes
!= NULL
), __kCFLogAssertion
, "%s(): bytes pointer cannot be NULL if length is non-zero", __PRETTY_FUNCTION__
);
279 if (NULL
== bytesDeallocator
) bytesDeallocator
= __CFGetDefaultAllocator();
280 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
281 bytesDeallocator
= NULL
;
283 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, bytesDeallocator
);
286 CFDataRef
CFDataCreateCopy(CFAllocatorRef allocator
, CFDataRef data
) {
287 CFIndex length
= CFDataGetLength(data
);
288 return __CFDataInit(allocator
, kCFImmutable
, length
, CFDataGetBytePtr(data
), length
, NULL
);
291 CFMutableDataRef
CFDataCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
) {
292 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, NULL
, 0, NULL
);
295 CFMutableDataRef
CFDataCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFDataRef data
) {
296 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, CFDataGetBytePtr(data
), CFDataGetLength(data
), NULL
);
299 CFIndex
CFDataGetLength(CFDataRef data
) {
300 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, CFIndex
, data
, "length");
301 __CFGenericValidateType(data
, __kCFDataTypeID
);
302 return __CFDataLength(data
);
305 const uint8_t *CFDataGetBytePtr(CFDataRef data
) {
306 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, const uint8_t *, data
, "bytes");
307 __CFGenericValidateType(data
, __kCFDataTypeID
);
311 uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data
) {
312 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, uint8_t *, data
, "mutableBytes");
313 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
317 void CFDataGetBytes(CFDataRef data
, CFRange range
, uint8_t *buffer
) {
318 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "getBytes:range:", buffer
, range
);
319 memmove(buffer
, data
->_bytes
+ range
.location
, range
.length
);
322 static void __CFDataGrow(CFMutableDataRef data
, CFIndex numNewValues
) {
323 CFIndex oldLength
= __CFDataLength(data
);
324 CFIndex capacity
= __CFDataRoundUpCapacity(oldLength
+ numNewValues
);
325 CFAllocatorRef allocator
= CFGetAllocator(data
);
326 __CFDataSetCapacity(data
, capacity
);
327 __CFDataSetNumBytes(data
, __CFDataNumBytesForCapacity(capacity
));
328 CF_WRITE_BARRIER_BASE_ASSIGN(allocator
, data
, data
->_bytes
, _CFAllocatorReallocateGC(allocator
, data
->_bytes
, __CFDataNumBytes(data
) * sizeof(uint8_t), AUTO_MEMORY_UNSCANNED
));
329 if (__CFOASafe
) __CFSetLastAllocationEventName(data
->_bytes
, "CFData (store)");
330 if (NULL
== data
->_bytes
) HALT
;
333 void CFDataSetLength(CFMutableDataRef data
, CFIndex length
) {
335 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "setLength:", length
);
336 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
337 len
= __CFDataLength(data
);
338 switch (__CFMutableVariety(data
)) {
341 // CF: should only grow when new length exceeds current capacity, not whenever it exceeds the current length
342 __CFDataGrow(data
, length
- len
);
345 case kCFFixedMutable
:
346 CFAssert1(length
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
350 memset(data
->_bytes
+ len
, 0, length
- len
);
352 __CFDataSetLength(data
, length
);
353 __CFDataSetNumBytesUsed(data
, length
);
356 void CFDataIncreaseLength(CFMutableDataRef data
, CFIndex extraLength
) {
357 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "increaseLengthBy:", extraLength
);
358 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
359 CFDataSetLength(data
, __CFDataLength(data
) + extraLength
);
362 void CFDataAppendBytes(CFMutableDataRef data
, const uint8_t *bytes
, CFIndex length
) {
363 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "appendBytes:length:", bytes
, length
);
364 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
365 CFDataReplaceBytes(data
, CFRangeMake(__CFDataLength(data
), 0), bytes
, length
);
368 void CFDataDeleteBytes(CFMutableDataRef data
, CFRange range
) {
369 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, NULL
, 0);
370 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
371 CFDataReplaceBytes(data
, range
, NULL
, 0);
374 void CFDataReplaceBytes(CFMutableDataRef data
, CFRange range
, const uint8_t *newBytes
, CFIndex newLength
) {
376 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, newBytes
, newLength
);
377 __CFGenericValidateType(data
, __kCFDataTypeID
);
378 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
379 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
380 CFAssert2(0 <= newLength
, __kCFLogAssertion
, "%s(): newLength (%d) cannot be less than zero", __PRETTY_FUNCTION__
, newLength
);
381 len
= __CFDataLength(data
);
382 switch (__CFMutableVariety(data
)) {
384 if (range
.length
< newLength
&& __CFDataNumBytes(data
) < len
- range
.length
+ newLength
) {
385 __CFDataGrow(data
, newLength
- range
.length
);
388 case kCFFixedMutable
:
389 CFAssert1(len
- range
.length
+ newLength
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
392 if (newLength
!= range
.length
&& range
.location
+ range
.length
< len
) {
393 memmove(data
->_bytes
+ range
.location
+ newLength
, data
->_bytes
+ range
.location
+ range
.length
, (len
- range
.location
- range
.length
) * sizeof(uint8_t));
396 memmove(data
->_bytes
+ range
.location
, newBytes
, newLength
* sizeof(uint8_t));
398 __CFDataSetNumBytesUsed(data
, (len
- range
.length
+ newLength
));
399 __CFDataSetLength(data
, (len
- range
.length
+ newLength
));
402 #undef __CFDataValidateRange
403 #undef __CFGenericValidateMutabilityFlags