]> git.saurik.com Git - apple/cf.git/blob - CFData.c
CF-476.13.tar.gz
[apple/cf.git] / CFData.c
1 /*
2 * Copyright (c) 2008 Apple 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 "CFPriv.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)->_cfinfo[CF_INFO_BITS], 3, 2);
45 }
46
47 CF_INLINE void __CFSetMutableVariety(void *cf, UInt32 v) {
48 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 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 << flsl(capacity));
94 }
95
96 CF_INLINE CFIndex __CFDataNumBytesForCapacity(CFIndex capacity) {
97 return capacity;
98 }
99
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);
105 HALT;
106 }
107 CFRelease(msg);
108 }
109
110 #if defined(DEBUG)
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);
115 }
116 #else
117 #define __CFDataValidateRange(a,r,f)
118 #endif
119
120 static Boolean __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) {
121 CFDataRef data1 = (CFDataRef)cf1;
122 CFDataRef data2 = (CFDataRef)cf2;
123 CFIndex length;
124 length = __CFDataLength(data1);
125 if (length != __CFDataLength(data2)) return false;
126 return 0 == memcmp(data1->_bytes, data2->_bytes, length);
127 }
128
129 static CFHashCode __CFDataHash(CFTypeRef cf) {
130 CFDataRef data = (CFDataRef)cf;
131 return CFHashBytes(data->_bytes, __CFMin(__CFDataLength(data), 80));
132 }
133
134 static CFStringRef __CFDataCopyDescription(CFTypeRef cf) {
135 CFDataRef data = (CFDataRef)cf;
136 CFMutableStringRef result;
137 CFIndex idx;
138 CFIndex len;
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));
144 if (24 < len) {
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]);
147 }
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]);
151 }
152 } else {
153 for (idx = 0; idx < len; idx++) {
154 CFStringAppendFormat(result, NULL, CFSTR("%02x"), bytes[idx]);
155 }
156 }
157 CFStringAppend(result, CFSTR("}"));
158 return result;
159 }
160
161 enum {
162 kCFImmutable = 0x0, /* unchangable and fixed capacity; default */
163 kCFMutable = 0x1, /* changeable and variable capacity */
164 kCFFixedMutable = 0x3 /* changeable and fixed capacity */
165 };
166
167 static void __CFDataDeallocate(CFTypeRef cf) {
168 CFMutableDataRef data = (CFMutableDataRef)cf;
169 CFAllocatorRef allocator = __CFGetAllocator(data);
170 switch (__CFMutableVariety(data)) {
171 case kCFMutable:
172 _CFAllocatorDeallocateGC(allocator, data->_bytes);
173 data->_bytes = NULL;
174 break;
175 case kCFFixedMutable:
176 break;
177 case kCFImmutable:
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);
182 } else {
183 CFAllocatorDeallocate(data->_bytesDeallocator, data->_bytes);
184 CFRelease(data->_bytesDeallocator);
185 data->_bytes = NULL;
186 }
187 }
188 break;
189 }
190 }
191
192 static CFTypeID __kCFDataTypeID = _kCFRuntimeNotATypeID;
193
194 static const CFRuntimeClass __CFDataClass = {
195 0,
196 "CFData",
197 NULL, // init
198 NULL, // copy
199 __CFDataDeallocate,
200 __CFDataEqual,
201 __CFDataHash,
202 NULL, //
203 __CFDataCopyDescription
204 };
205
206 __private_extern__ void __CFDataInitialize(void) {
207 __kCFDataTypeID = _CFRuntimeRegisterClass(&__CFDataClass);
208 }
209
210 CFTypeID CFDataGetTypeID(void) {
211 return __kCFDataTypeID;
212 }
213
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;
218 CFIndex size;
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);
226 }
227 if (__CFMutableVarietyFromFlags(flags) != kCFMutable) {
228 size += sizeof(uint8_t) * 15; // for 16-byte alignment fixup
229 }
230 memory = (CFMutableDataRef)_CFRuntimeCreateInstance(allocator, __kCFDataTypeID, size, NULL);
231 if (NULL == memory) {
232 return NULL;
233 }
234 __CFDataSetNumBytesUsed(memory, 0);
235 __CFDataSetLength(memory, 0);
236 switch (__CFMutableVarietyFromFlags(flags)) {
237 case kCFMutable:
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) {
246 CFRelease(memory);
247 return NULL;
248 }
249 memory->_bytesDeallocator = NULL;
250 __CFSetMutableVariety(memory, kCFMutable);
251 CFDataReplaceBytes(memory, CFRangeMake(0, 0), bytes, length);
252 break;
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);
261 break;
262 case kCFImmutable:
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);
271 } else {
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);
276 }
277 break;
278 }
279 __CFSetMutableVariety(memory, __CFMutableVarietyFromFlags(flags));
280 return memory;
281 }
282
283 CFDataRef CFDataCreate(CFAllocatorRef allocator, const uint8_t *bytes, CFIndex length) {
284 return __CFDataInit(allocator, kCFImmutable, length, bytes, length, NULL);
285 }
286
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);
291 }
292
293 CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) {
294 CFIndex length = CFDataGetLength(data);
295 return __CFDataInit(allocator, kCFImmutable, length, CFDataGetBytePtr(data), length, NULL);
296 }
297
298 CFMutableDataRef CFDataCreateMutable(CFAllocatorRef allocator, CFIndex capacity) {
299 return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, NULL, 0, NULL);
300 }
301
302 CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFDataRef data) {
303 return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, CFDataGetBytePtr(data), CFDataGetLength(data), NULL);
304 }
305
306 CFIndex CFDataGetLength(CFDataRef data) {
307 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, CFIndex, data, "length");
308 __CFGenericValidateType(data, __kCFDataTypeID);
309 return __CFDataLength(data);
310 }
311
312 const uint8_t *CFDataGetBytePtr(CFDataRef data) {
313 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, const uint8_t *, data, "bytes");
314 __CFGenericValidateType(data, __kCFDataTypeID);
315 return data->_bytes;
316 }
317
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__);
321 return data->_bytes;
322 }
323
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);
327 }
328
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)");
339 }
340
341 void CFDataSetLength(CFMutableDataRef data, CFIndex length) {
342 CFIndex len;
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)) {
347 case kCFMutable:
348 if (len < length) {
349 // CF: should only grow when new length exceeds current capacity, not whenever it exceeds the current length
350 __CFDataGrow(data, length - len);
351 }
352 break;
353 case kCFFixedMutable:
354 CFAssert1(length <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__);
355 break;
356 }
357 if (len < length) {
358 memset(data->_bytes + len, 0, length - len);
359 }
360 __CFDataSetLength(data, length);
361 __CFDataSetNumBytesUsed(data, length);
362 }
363
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);
368 }
369
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);
374 }
375
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);
380 }
381
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);
388
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;
393
394 switch (__CFMutableVariety(data)) {
395 case kCFMutable:
396 if (__CFDataNumBytes(data) < newCount) {
397 __CFDataGrow(data, newLength - range.length);
398 }
399 break;
400 case kCFFixedMutable:
401 CFAssert1(newCount <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__);
402 break;
403 }
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));
406 }
407 if (0 < newLength) {
408 memmove(data->_bytes + range.location, newBytes, newLength * sizeof(uint8_t));
409 }
410 __CFDataSetNumBytesUsed(data, newCount);
411 __CFDataSetLength(data, newCount);
412 }
413
414 #undef __CFDataValidateRange
415 #undef __CFGenericValidateMutabilityFlags
416