2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #include <CoreFoundation/CFData.h>
31 #include "CFUtilities.h"
32 #include "CFInternal.h"
37 CFIndex _length
; /* number of bytes */
38 CFIndex _capacity
; /* maximum number of bytes */
39 CFAllocatorRef _bytesDeallocator
; /* used only for immutable; if NULL, no deallocation */
43 /* Bits 3-2 are used for mutability variation */
45 CF_INLINE UInt32
__CFMutableVariety(const void *cf
) {
46 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 3, 2);
49 CF_INLINE
void __CFSetMutableVariety(void *cf
, UInt32 v
) {
50 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 3, 2, v
);
53 CF_INLINE UInt32
__CFMutableVarietyFromFlags(UInt32 flags
) {
54 return __CFBitfieldGetValue(flags
, 1, 0);
57 #define __CFGenericValidateMutabilityFlags(flags) \
58 CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags);
60 CF_INLINE CFIndex
__CFDataLength(CFDataRef data
) {
64 CF_INLINE
void __CFDataSetLength(CFMutableDataRef data
, CFIndex v
) {
65 /* for a CFData, _bytesUsed == _length */
68 CF_INLINE CFIndex
__CFDataCapacity(CFDataRef data
) {
69 return data
->_capacity
;
72 CF_INLINE
void __CFDataSetCapacity(CFMutableDataRef data
, CFIndex v
) {
73 /* for a CFData, _bytesNum == _capacity */
76 CF_INLINE CFIndex
__CFDataNumBytesUsed(CFDataRef data
) {
80 CF_INLINE
void __CFDataSetNumBytesUsed(CFMutableDataRef data
, CFIndex v
) {
84 CF_INLINE CFIndex
__CFDataNumBytes(CFDataRef data
) {
85 return data
->_capacity
;
88 CF_INLINE
void __CFDataSetNumBytes(CFMutableDataRef data
, CFIndex v
) {
92 CF_INLINE CFIndex
__CFDataRoundUpCapacity(CFIndex capacity
) {
93 if (capacity
< 16) return 16;
94 // CF: quite probably, this doubling should slow as the data gets larger and larger; should not use strict doubling
95 return (1 << (CFLog2(capacity
) + 1));
98 CF_INLINE CFIndex
__CFDataNumBytesForCapacity(CFIndex capacity
) {
103 CF_INLINE
void __CFDataValidateRange(CFDataRef data
, CFRange range
, const char *func
) {
104 CFAssert2(0 <= range
.location
&& range
.location
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): range.location index (%d) out of bounds", func
, range
.location
);
105 CFAssert2(0 <= range
.length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", func
, range
.length
);
106 CFAssert2(range
.location
+ range
.length
<= __CFDataLength(data
), __kCFLogAssertion
, "%s(): ending index (%d) out of bounds", func
, range
.location
+ range
.length
);
109 #define __CFDataValidateRange(a,r,f)
112 static bool __CFDataEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
113 CFDataRef data1
= (CFDataRef
)cf1
;
114 CFDataRef data2
= (CFDataRef
)cf2
;
116 length
= __CFDataLength(data1
);
117 if (length
!= __CFDataLength(data2
)) return false;
118 return 0 == memcmp(data1
->_bytes
, data2
->_bytes
, length
);
121 static CFHashCode
__CFDataHash(CFTypeRef cf
) {
122 CFDataRef data
= (CFDataRef
)cf
;
123 return CFHashBytes(data
->_bytes
, __CFMin(__CFDataLength(data
), 16));
126 static CFStringRef
__CFDataCopyDescription(CFTypeRef cf
) {
127 CFDataRef data
= (CFDataRef
)cf
;
128 CFMutableStringRef result
;
131 const uint8_t *bytes
;
132 len
= __CFDataLength(data
);
133 bytes
= data
->_bytes
;
134 result
= CFStringCreateMutable(CFGetAllocator(data
), 0);
135 CFStringAppendFormat(result
, NULL
, CFSTR("<CFData %p [%p]>{length = %u, capacity = %u, bytes = 0x"), cf
, CFGetAllocator(data
), len
, __CFDataCapacity(data
));
137 for (idx
= 0; idx
< 16; idx
+= 4) {
138 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
140 CFStringAppend(result
, CFSTR(" ... "));
141 for (idx
= len
- 8; idx
< len
; idx
+= 4) {
142 CFStringAppendFormat(result
, NULL
, CFSTR("%02x%02x%02x%02x"), bytes
[idx
], bytes
[idx
+ 1], bytes
[idx
+ 2], bytes
[idx
+ 3]);
145 for (idx
= 0; idx
< len
; idx
++) {
146 CFStringAppendFormat(result
, NULL
, CFSTR("%02x"), bytes
[idx
]);
149 CFStringAppend(result
, CFSTR("}"));
154 kCFImmutable
= 0x0, /* unchangable and fixed capacity; default */
155 kCFMutable
= 0x1, /* changeable and variable capacity */
156 kCFFixedMutable
= 0x3 /* changeable and fixed capacity */
159 static void __CFDataDeallocate(CFTypeRef cf
) {
160 CFMutableDataRef data
= (CFMutableDataRef
)cf
;
161 CFAllocatorRef allocator
= CFGetAllocator(data
);
162 switch (__CFMutableVariety(data
)) {
164 CFAllocatorDeallocate(allocator
, data
->_bytes
);
166 case kCFFixedMutable
:
169 if (NULL
!= data
->_bytesDeallocator
) {
170 CFAllocatorDeallocate(data
->_bytesDeallocator
, data
->_bytes
);
171 CFRelease(data
->_bytesDeallocator
);
177 static CFTypeID __kCFDataTypeID
= _kCFRuntimeNotATypeID
;
179 static const CFRuntimeClass __CFDataClass
= {
185 (void *)__CFDataEqual
,
188 __CFDataCopyDescription
191 __private_extern__
void __CFDataInitialize(void) {
192 __kCFDataTypeID
= _CFRuntimeRegisterClass(&__CFDataClass
);
195 CFTypeID
CFDataGetTypeID(void) {
196 return __kCFDataTypeID
;
199 // NULL bytesDeallocator to this function does not mean the default allocator, it means
200 // that there should be no deallocator, and the bytes should be copied.
201 static CFMutableDataRef
__CFDataInit(CFAllocatorRef allocator
, CFOptionFlags flags
, CFIndex capacity
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
202 CFMutableDataRef memory
;
204 __CFGenericValidateMutabilityFlags(flags
);
205 CFAssert2(0 <= capacity
, __kCFLogAssertion
, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__
, capacity
);
206 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
);
207 CFAssert2(0 <= length
, __kCFLogAssertion
, "%s(): length (%d) cannot be less than zero", __PRETTY_FUNCTION__
, length
);
208 size
= sizeof(struct __CFData
) - sizeof(CFRuntimeBase
);
209 if (__CFMutableVarietyFromFlags(flags
) != kCFMutable
&& (bytesDeallocator
== NULL
)) {
210 size
+= sizeof(uint8_t) * __CFDataNumBytesForCapacity(capacity
);
212 if (__CFMutableVarietyFromFlags(flags
) != kCFMutable
) {
213 size
+= sizeof(uint8_t) * 15; // for 16-byte alignment fixup
215 memory
= (CFMutableDataRef
)_CFRuntimeCreateInstance(allocator
, __kCFDataTypeID
, size
, NULL
);
216 if (NULL
== memory
) {
219 __CFDataSetNumBytesUsed(memory
, 0);
220 __CFDataSetLength(memory
, 0);
221 switch (__CFMutableVarietyFromFlags(flags
)) {
223 __CFDataSetCapacity(memory
, __CFDataRoundUpCapacity(1));
224 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(__CFDataRoundUpCapacity(1)));
225 // assume that allocators give 16-byte aligned memory back -- it is their responsibility
226 memory
->_bytes
= CFAllocatorAllocate(allocator
, __CFDataNumBytes(memory
) * sizeof(uint8_t), 0);
227 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
->_bytes
, "CFData (store)");
228 if (NULL
== memory
->_bytes
) {
232 memory
->_bytesDeallocator
= NULL
;
233 __CFSetMutableVariety(memory
, kCFMutable
);
234 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
236 case kCFFixedMutable
:
237 /* Don't round up capacity */
238 __CFDataSetCapacity(memory
, capacity
);
239 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
240 memory
->_bytes
= (uint8_t *)((uintptr_t)((int8_t *)memory
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
241 memory
->_bytesDeallocator
= NULL
;
242 __CFSetMutableVariety(memory
, kCFFixedMutable
);
243 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
246 /* Don't round up capacity */
247 __CFDataSetCapacity(memory
, capacity
);
248 __CFDataSetNumBytes(memory
, __CFDataNumBytesForCapacity(capacity
));
249 if (bytesDeallocator
!= NULL
) {
250 memory
->_bytes
= (uint8_t *)bytes
;
251 memory
->_bytesDeallocator
= CFRetain(bytesDeallocator
);
252 __CFDataSetNumBytesUsed(memory
, length
);
253 __CFDataSetLength(memory
, length
);
255 memory
->_bytes
= (uint8_t *)((uintptr_t)((int8_t *)memory
+ sizeof(struct __CFData
) + 15) & ~0xF); // 16-byte align
256 memory
->_bytesDeallocator
= NULL
;
257 __CFSetMutableVariety(memory
, kCFFixedMutable
);
258 CFDataReplaceBytes(memory
, CFRangeMake(0, 0), bytes
, length
);
262 __CFSetMutableVariety(memory
, __CFMutableVarietyFromFlags(flags
));
266 CFDataRef
CFDataCreate(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
) {
267 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, NULL
);
270 CFDataRef
CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator
, const uint8_t *bytes
, CFIndex length
, CFAllocatorRef bytesDeallocator
) {
271 CFAssert1((0 == length
|| bytes
!= NULL
), __kCFLogAssertion
, "%s(): bytes pointer cannot be NULL if length is non-zero", __PRETTY_FUNCTION__
);
272 if (NULL
== bytesDeallocator
) bytesDeallocator
= __CFGetDefaultAllocator();
273 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
274 bytesDeallocator
= NULL
;
276 return __CFDataInit(allocator
, kCFImmutable
, length
, bytes
, length
, bytesDeallocator
);
279 CFDataRef
CFDataCreateCopy(CFAllocatorRef allocator
, CFDataRef data
) {
280 CFIndex length
= CFDataGetLength(data
);
281 return __CFDataInit(allocator
, kCFImmutable
, length
, CFDataGetBytePtr(data
), length
, NULL
);
284 CFMutableDataRef
CFDataCreateMutable(CFAllocatorRef allocator
, CFIndex capacity
) {
285 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, NULL
, 0, NULL
);
288 CFMutableDataRef
CFDataCreateMutableCopy(CFAllocatorRef allocator
, CFIndex capacity
, CFDataRef data
) {
289 return __CFDataInit(allocator
, (0 == capacity
) ? kCFMutable
: kCFFixedMutable
, capacity
, CFDataGetBytePtr(data
), CFDataGetLength(data
), NULL
);
292 CFIndex
CFDataGetLength(CFDataRef data
) {
293 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, CFIndex
, data
, "length");
294 __CFGenericValidateType(data
, __kCFDataTypeID
);
295 return __CFDataLength(data
);
298 const uint8_t *CFDataGetBytePtr(CFDataRef data
) {
299 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, const uint8_t *, data
, "bytes");
300 __CFGenericValidateType(data
, __kCFDataTypeID
);
304 uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data
) {
305 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID
, uint8_t *, data
, "mutableBytes");
306 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
310 void CFDataGetBytes(CFDataRef data
, CFRange range
, uint8_t *buffer
) {
311 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "getBytes:range:", buffer
, range
);
312 memmove(buffer
, data
->_bytes
+ range
.location
, range
.length
);
315 static void __CFDataGrow(CFMutableDataRef data
, CFIndex numNewValues
) {
316 CFIndex oldLength
= __CFDataLength(data
);
317 CFIndex capacity
= __CFDataRoundUpCapacity(oldLength
+ numNewValues
);
318 __CFDataSetCapacity(data
, capacity
);
319 __CFDataSetNumBytes(data
, __CFDataNumBytesForCapacity(capacity
));
320 data
->_bytes
= CFAllocatorReallocate(CFGetAllocator(data
), data
->_bytes
, __CFDataNumBytes(data
) * sizeof(uint8_t), 0);
321 if (__CFOASafe
) __CFSetLastAllocationEventName(data
->_bytes
, "CFData (store)");
322 if (NULL
== data
->_bytes
) HALT
;
325 void CFDataSetLength(CFMutableDataRef data
, CFIndex length
) {
327 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "setLength:", length
);
328 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
329 len
= __CFDataLength(data
);
330 switch (__CFMutableVariety(data
)) {
333 // CF: should only grow when new length exceeds current capacity, not whenever it exceeds the current length
334 __CFDataGrow(data
, length
- len
);
337 case kCFFixedMutable
:
338 CFAssert1(length
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
342 memset(data
->_bytes
+ len
, 0, length
- len
);
344 __CFDataSetLength(data
, length
);
345 __CFDataSetNumBytesUsed(data
, length
);
348 void CFDataIncreaseLength(CFMutableDataRef data
, CFIndex extraLength
) {
349 CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID
, void, data
, "increaseLengthBy:", extraLength
);
350 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
351 CFDataSetLength(data
, __CFDataLength(data
) + extraLength
);
354 void CFDataAppendBytes(CFMutableDataRef data
, const uint8_t *bytes
, CFIndex length
) {
355 CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID
, void, data
, "appendBytes:length:", bytes
, length
);
356 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
357 CFDataReplaceBytes(data
, CFRangeMake(__CFDataLength(data
), 0), bytes
, length
);
360 void CFDataDeleteBytes(CFMutableDataRef data
, CFRange range
) {
361 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, NULL
, 0);
362 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
363 CFDataReplaceBytes(data
, range
, NULL
, 0);
366 void CFDataReplaceBytes(CFMutableDataRef data
, CFRange range
, const uint8_t *newBytes
, CFIndex newLength
) {
368 CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID
, void, data
, "replaceBytesInRange:withBytes:length:", range
, newBytes
, newLength
);
369 __CFGenericValidateType(data
, __kCFDataTypeID
);
370 __CFDataValidateRange(data
, range
, __PRETTY_FUNCTION__
);
371 CFAssert1(__CFMutableVariety(data
) == kCFMutable
|| __CFMutableVariety(data
) == kCFFixedMutable
, __kCFLogAssertion
, "%s(): data is immutable", __PRETTY_FUNCTION__
);
372 CFAssert2(0 <= newLength
, __kCFLogAssertion
, "%s(): newLength (%d) cannot be less than zero", __PRETTY_FUNCTION__
, newLength
);
373 len
= __CFDataLength(data
);
374 switch (__CFMutableVariety(data
)) {
376 if (range
.length
< newLength
&& __CFDataNumBytes(data
) < len
- range
.length
+ newLength
) {
377 __CFDataGrow(data
, newLength
- range
.length
);
380 case kCFFixedMutable
:
381 CFAssert1(len
- range
.length
+ newLength
<= __CFDataCapacity(data
), __kCFLogAssertion
, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__
);
384 if (newLength
!= range
.length
&& range
.location
+ range
.length
< len
) {
385 memmove(data
->_bytes
+ range
.location
+ newLength
, data
->_bytes
+ range
.location
+ range
.length
, (len
- range
.location
- range
.length
) * sizeof(uint8_t));
388 memmove(data
->_bytes
+ range
.location
, newBytes
, newLength
* sizeof(uint8_t));
390 __CFDataSetNumBytesUsed(data
, (len
- range
.length
+ newLength
));
391 __CFDataSetLength(data
, (len
- range
.length
+ newLength
));
394 #undef __CFDataValidateRange
395 #undef __CFGenericValidateMutabilityFlags