]> git.saurik.com Git - apple/cf.git/blob - Collections.subproj/CFData.c
CF-368.26.tar.gz
[apple/cf.git] / Collections.subproj / CFData.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFData.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include <CoreFoundation/CFData.h>
29 #include "CFUtilitiesPriv.h"
30 #include "CFInternal.h"
31 #include <string.h>
32
33 struct __CFData {
34 CFRuntimeBase _base;
35 CFIndex _length; /* number of bytes */
36 CFIndex _capacity; /* maximum number of bytes */
37 CFAllocatorRef _bytesDeallocator; /* used only for immutable; if NULL, no deallocation */
38 uint8_t *_bytes;
39 };
40
41 /* Bits 3-2 are used for mutability variation */
42
43 CF_INLINE UInt32 __CFMutableVariety(const void *cf) {
44 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 2);
45 }
46
47 CF_INLINE void __CFSetMutableVariety(void *cf, UInt32 v) {
48 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 2, v);
49 }
50
51 CF_INLINE UInt32 __CFMutableVarietyFromFlags(UInt32 flags) {
52 return __CFBitfieldGetValue(flags, 1, 0);
53 }
54
55 #define __CFGenericValidateMutabilityFlags(flags) \
56 CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags);
57
58 CF_INLINE CFIndex __CFDataLength(CFDataRef data) {
59 return data->_length;
60 }
61
62 CF_INLINE void __CFDataSetLength(CFMutableDataRef data, CFIndex v) {
63 /* for a CFData, _bytesUsed == _length */
64 }
65
66 CF_INLINE CFIndex __CFDataCapacity(CFDataRef data) {
67 return data->_capacity;
68 }
69
70 CF_INLINE void __CFDataSetCapacity(CFMutableDataRef data, CFIndex v) {
71 /* for a CFData, _bytesNum == _capacity */
72 }
73
74 CF_INLINE CFIndex __CFDataNumBytesUsed(CFDataRef data) {
75 return data->_length;
76 }
77
78 CF_INLINE void __CFDataSetNumBytesUsed(CFMutableDataRef data, CFIndex v) {
79 data->_length = v;
80 }
81
82 CF_INLINE CFIndex __CFDataNumBytes(CFDataRef data) {
83 return data->_capacity;
84 }
85
86 CF_INLINE void __CFDataSetNumBytes(CFMutableDataRef data, CFIndex v) {
87 data->_capacity = v;
88 }
89
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));
94 }
95
96 CF_INLINE CFIndex __CFDataNumBytesForCapacity(CFIndex capacity) {
97 return capacity;
98 }
99
100 #if defined(DEBUG)
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);
105 }
106 #else
107 #define __CFDataValidateRange(a,r,f)
108 #endif
109
110 static bool __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) {
111 CFDataRef data1 = (CFDataRef)cf1;
112 CFDataRef data2 = (CFDataRef)cf2;
113 CFIndex length;
114 length = __CFDataLength(data1);
115 if (length != __CFDataLength(data2)) return false;
116 return 0 == memcmp(data1->_bytes, data2->_bytes, length);
117 }
118
119 static CFHashCode __CFDataHash(CFTypeRef cf) {
120 CFDataRef data = (CFDataRef)cf;
121 return CFHashBytes(data->_bytes, __CFMin(__CFDataLength(data), 16));
122 }
123
124 static CFStringRef __CFDataCopyDescription(CFTypeRef cf) {
125 CFDataRef data = (CFDataRef)cf;
126 CFMutableStringRef result;
127 CFIndex idx;
128 CFIndex len;
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));
134 if (24 < len) {
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]);
137 }
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]);
141 }
142 } else {
143 for (idx = 0; idx < len; idx++) {
144 CFStringAppendFormat(result, NULL, CFSTR("%02x"), bytes[idx]);
145 }
146 }
147 CFStringAppend(result, CFSTR("}"));
148 return result;
149 }
150
151 enum {
152 kCFImmutable = 0x0, /* unchangable and fixed capacity; default */
153 kCFMutable = 0x1, /* changeable and variable capacity */
154 kCFFixedMutable = 0x3 /* changeable and fixed capacity */
155 };
156
157 static void __CFDataDeallocate(CFTypeRef cf) {
158 CFMutableDataRef data = (CFMutableDataRef)cf;
159 CFAllocatorRef allocator = CFGetAllocator(data);
160 switch (__CFMutableVariety(data)) {
161 case kCFMutable:
162 _CFAllocatorDeallocateGC(allocator, data->_bytes);
163 data->_bytes = NULL;
164 break;
165 case kCFFixedMutable:
166 break;
167 case kCFImmutable:
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);
172 } else {
173 CFAllocatorDeallocate(data->_bytesDeallocator, data->_bytes);
174 CFRelease(data->_bytesDeallocator);
175 data->_bytes = NULL;
176 }
177 }
178 break;
179 }
180 }
181
182 static CFTypeID __kCFDataTypeID = _kCFRuntimeNotATypeID;
183
184 static const CFRuntimeClass __CFDataClass = {
185 0,
186 "CFData",
187 NULL, // init
188 NULL, // copy
189 __CFDataDeallocate,
190 (void *)__CFDataEqual,
191 __CFDataHash,
192 NULL, //
193 __CFDataCopyDescription
194 };
195
196 __private_extern__ void __CFDataInitialize(void) {
197 __kCFDataTypeID = _CFRuntimeRegisterClass(&__CFDataClass);
198 }
199
200 CFTypeID CFDataGetTypeID(void) {
201 return __kCFDataTypeID;
202 }
203
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;
208 CFIndex size;
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);
216 }
217 if (__CFMutableVarietyFromFlags(flags) != kCFMutable) {
218 size += sizeof(uint8_t) * 15; // for 16-byte alignment fixup
219 }
220 memory = (CFMutableDataRef)_CFRuntimeCreateInstance(allocator, __kCFDataTypeID, size, NULL);
221 if (NULL == memory) {
222 return NULL;
223 }
224 __CFDataSetNumBytesUsed(memory, 0);
225 __CFDataSetLength(memory, 0);
226 switch (__CFMutableVarietyFromFlags(flags)) {
227 case kCFMutable:
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) {
236 CFRelease(memory);
237 return NULL;
238 }
239 memory->_bytesDeallocator = NULL;
240 __CFSetMutableVariety(memory, kCFMutable);
241 CFDataReplaceBytes(memory, CFRangeMake(0, 0), bytes, length);
242 break;
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);
251 break;
252 case kCFImmutable:
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);
261 } else {
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);
266 }
267 break;
268 }
269 __CFSetMutableVariety(memory, __CFMutableVarietyFromFlags(flags));
270 return memory;
271 }
272
273 CFDataRef CFDataCreate(CFAllocatorRef allocator, const uint8_t *bytes, CFIndex length) {
274 return __CFDataInit(allocator, kCFImmutable, length, bytes, length, NULL);
275 }
276
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;
282 }
283 return __CFDataInit(allocator, kCFImmutable, length, bytes, length, bytesDeallocator);
284 }
285
286 CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) {
287 CFIndex length = CFDataGetLength(data);
288 return __CFDataInit(allocator, kCFImmutable, length, CFDataGetBytePtr(data), length, NULL);
289 }
290
291 CFMutableDataRef CFDataCreateMutable(CFAllocatorRef allocator, CFIndex capacity) {
292 return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, NULL, 0, NULL);
293 }
294
295 CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFDataRef data) {
296 return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, CFDataGetBytePtr(data), CFDataGetLength(data), NULL);
297 }
298
299 CFIndex CFDataGetLength(CFDataRef data) {
300 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, CFIndex, data, "length");
301 __CFGenericValidateType(data, __kCFDataTypeID);
302 return __CFDataLength(data);
303 }
304
305 const uint8_t *CFDataGetBytePtr(CFDataRef data) {
306 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, const uint8_t *, data, "bytes");
307 __CFGenericValidateType(data, __kCFDataTypeID);
308 return data->_bytes;
309 }
310
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__);
314 return data->_bytes;
315 }
316
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);
320 }
321
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;
331 }
332
333 void CFDataSetLength(CFMutableDataRef data, CFIndex length) {
334 CFIndex len;
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)) {
339 case kCFMutable:
340 if (len < length) {
341 // CF: should only grow when new length exceeds current capacity, not whenever it exceeds the current length
342 __CFDataGrow(data, length - len);
343 }
344 break;
345 case kCFFixedMutable:
346 CFAssert1(length <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__);
347 break;
348 }
349 if (len < length) {
350 memset(data->_bytes + len, 0, length - len);
351 }
352 __CFDataSetLength(data, length);
353 __CFDataSetNumBytesUsed(data, length);
354 }
355
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);
360 }
361
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);
366 }
367
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);
372 }
373
374 void CFDataReplaceBytes(CFMutableDataRef data, CFRange range, const uint8_t *newBytes, CFIndex newLength) {
375 CFIndex len;
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)) {
383 case kCFMutable:
384 if (range.length < newLength && __CFDataNumBytes(data) < len - range.length + newLength) {
385 __CFDataGrow(data, newLength - range.length);
386 }
387 break;
388 case kCFFixedMutable:
389 CFAssert1(len - range.length + newLength <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__);
390 break;
391 }
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));
394 }
395 if (0 < newLength) {
396 memmove(data->_bytes + range.location, newBytes, newLength * sizeof(uint8_t));
397 }
398 __CFDataSetNumBytesUsed(data, (len - range.length + newLength));
399 __CFDataSetLength(data, (len - range.length + newLength));
400 }
401
402 #undef __CFDataValidateRange
403 #undef __CFGenericValidateMutabilityFlags
404