]> git.saurik.com Git - apple/cf.git/blob - Collections.subproj/CFData.c
CF-299.35.tar.gz
[apple/cf.git] / Collections.subproj / CFData.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFData.c
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
28 */
29
30 #include <CoreFoundation/CFData.h>
31 #include "CFUtilities.h"
32 #include "CFInternal.h"
33 #include <string.h>
34
35 struct __CFData {
36 CFRuntimeBase _base;
37 CFIndex _length; /* number of bytes */
38 CFIndex _capacity; /* maximum number of bytes */
39 CFAllocatorRef _bytesDeallocator; /* used only for immutable; if NULL, no deallocation */
40 uint8_t *_bytes;
41 };
42
43 /* Bits 3-2 are used for mutability variation */
44
45 CF_INLINE UInt32 __CFMutableVariety(const void *cf) {
46 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 2);
47 }
48
49 CF_INLINE void __CFSetMutableVariety(void *cf, UInt32 v) {
50 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 2, v);
51 }
52
53 CF_INLINE UInt32 __CFMutableVarietyFromFlags(UInt32 flags) {
54 return __CFBitfieldGetValue(flags, 1, 0);
55 }
56
57 #define __CFGenericValidateMutabilityFlags(flags) \
58 CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags);
59
60 CF_INLINE CFIndex __CFDataLength(CFDataRef data) {
61 return data->_length;
62 }
63
64 CF_INLINE void __CFDataSetLength(CFMutableDataRef data, CFIndex v) {
65 /* for a CFData, _bytesUsed == _length */
66 }
67
68 CF_INLINE CFIndex __CFDataCapacity(CFDataRef data) {
69 return data->_capacity;
70 }
71
72 CF_INLINE void __CFDataSetCapacity(CFMutableDataRef data, CFIndex v) {
73 /* for a CFData, _bytesNum == _capacity */
74 }
75
76 CF_INLINE CFIndex __CFDataNumBytesUsed(CFDataRef data) {
77 return data->_length;
78 }
79
80 CF_INLINE void __CFDataSetNumBytesUsed(CFMutableDataRef data, CFIndex v) {
81 data->_length = v;
82 }
83
84 CF_INLINE CFIndex __CFDataNumBytes(CFDataRef data) {
85 return data->_capacity;
86 }
87
88 CF_INLINE void __CFDataSetNumBytes(CFMutableDataRef data, CFIndex v) {
89 data->_capacity = v;
90 }
91
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));
96 }
97
98 CF_INLINE CFIndex __CFDataNumBytesForCapacity(CFIndex capacity) {
99 return capacity;
100 }
101
102 #if defined(DEBUG)
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);
107 }
108 #else
109 #define __CFDataValidateRange(a,r,f)
110 #endif
111
112 static bool __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) {
113 CFDataRef data1 = (CFDataRef)cf1;
114 CFDataRef data2 = (CFDataRef)cf2;
115 CFIndex length;
116 length = __CFDataLength(data1);
117 if (length != __CFDataLength(data2)) return false;
118 return 0 == memcmp(data1->_bytes, data2->_bytes, length);
119 }
120
121 static CFHashCode __CFDataHash(CFTypeRef cf) {
122 CFDataRef data = (CFDataRef)cf;
123 return CFHashBytes(data->_bytes, __CFMin(__CFDataLength(data), 16));
124 }
125
126 static CFStringRef __CFDataCopyDescription(CFTypeRef cf) {
127 CFDataRef data = (CFDataRef)cf;
128 CFMutableStringRef result;
129 CFIndex idx;
130 CFIndex len;
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));
136 if (24 < len) {
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]);
139 }
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]);
143 }
144 } else {
145 for (idx = 0; idx < len; idx++) {
146 CFStringAppendFormat(result, NULL, CFSTR("%02x"), bytes[idx]);
147 }
148 }
149 CFStringAppend(result, CFSTR("}"));
150 return result;
151 }
152
153 enum {
154 kCFImmutable = 0x0, /* unchangable and fixed capacity; default */
155 kCFMutable = 0x1, /* changeable and variable capacity */
156 kCFFixedMutable = 0x3 /* changeable and fixed capacity */
157 };
158
159 static void __CFDataDeallocate(CFTypeRef cf) {
160 CFMutableDataRef data = (CFMutableDataRef)cf;
161 CFAllocatorRef allocator = CFGetAllocator(data);
162 switch (__CFMutableVariety(data)) {
163 case kCFMutable:
164 CFAllocatorDeallocate(allocator, data->_bytes);
165 break;
166 case kCFFixedMutable:
167 break;
168 case kCFImmutable:
169 if (NULL != data->_bytesDeallocator) {
170 CFAllocatorDeallocate(data->_bytesDeallocator, data->_bytes);
171 CFRelease(data->_bytesDeallocator);
172 }
173 break;
174 }
175 }
176
177 static CFTypeID __kCFDataTypeID = _kCFRuntimeNotATypeID;
178
179 static const CFRuntimeClass __CFDataClass = {
180 0,
181 "CFData",
182 NULL, // init
183 NULL, // copy
184 __CFDataDeallocate,
185 (void *)__CFDataEqual,
186 __CFDataHash,
187 NULL, //
188 __CFDataCopyDescription
189 };
190
191 __private_extern__ void __CFDataInitialize(void) {
192 __kCFDataTypeID = _CFRuntimeRegisterClass(&__CFDataClass);
193 }
194
195 CFTypeID CFDataGetTypeID(void) {
196 return __kCFDataTypeID;
197 }
198
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;
203 CFIndex size;
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);
211 }
212 if (__CFMutableVarietyFromFlags(flags) != kCFMutable) {
213 size += sizeof(uint8_t) * 15; // for 16-byte alignment fixup
214 }
215 memory = (CFMutableDataRef)_CFRuntimeCreateInstance(allocator, __kCFDataTypeID, size, NULL);
216 if (NULL == memory) {
217 return NULL;
218 }
219 __CFDataSetNumBytesUsed(memory, 0);
220 __CFDataSetLength(memory, 0);
221 switch (__CFMutableVarietyFromFlags(flags)) {
222 case kCFMutable:
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) {
229 CFRelease(memory);
230 return NULL;
231 }
232 memory->_bytesDeallocator = NULL;
233 __CFSetMutableVariety(memory, kCFMutable);
234 CFDataReplaceBytes(memory, CFRangeMake(0, 0), bytes, length);
235 break;
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);
244 break;
245 case kCFImmutable:
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);
254 } else {
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);
259 }
260 break;
261 }
262 __CFSetMutableVariety(memory, __CFMutableVarietyFromFlags(flags));
263 return memory;
264 }
265
266 CFDataRef CFDataCreate(CFAllocatorRef allocator, const uint8_t *bytes, CFIndex length) {
267 return __CFDataInit(allocator, kCFImmutable, length, bytes, length, NULL);
268 }
269
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;
275 }
276 return __CFDataInit(allocator, kCFImmutable, length, bytes, length, bytesDeallocator);
277 }
278
279 CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) {
280 CFIndex length = CFDataGetLength(data);
281 return __CFDataInit(allocator, kCFImmutable, length, CFDataGetBytePtr(data), length, NULL);
282 }
283
284 CFMutableDataRef CFDataCreateMutable(CFAllocatorRef allocator, CFIndex capacity) {
285 return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, NULL, 0, NULL);
286 }
287
288 CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFDataRef data) {
289 return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, CFDataGetBytePtr(data), CFDataGetLength(data), NULL);
290 }
291
292 CFIndex CFDataGetLength(CFDataRef data) {
293 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, CFIndex, data, "length");
294 __CFGenericValidateType(data, __kCFDataTypeID);
295 return __CFDataLength(data);
296 }
297
298 const uint8_t *CFDataGetBytePtr(CFDataRef data) {
299 CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, const uint8_t *, data, "bytes");
300 __CFGenericValidateType(data, __kCFDataTypeID);
301 return data->_bytes;
302 }
303
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__);
307 return data->_bytes;
308 }
309
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);
313 }
314
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;
323 }
324
325 void CFDataSetLength(CFMutableDataRef data, CFIndex length) {
326 CFIndex len;
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)) {
331 case kCFMutable:
332 if (len < length) {
333 // CF: should only grow when new length exceeds current capacity, not whenever it exceeds the current length
334 __CFDataGrow(data, length - len);
335 }
336 break;
337 case kCFFixedMutable:
338 CFAssert1(length <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__);
339 break;
340 }
341 if (len < length) {
342 memset(data->_bytes + len, 0, length - len);
343 }
344 __CFDataSetLength(data, length);
345 __CFDataSetNumBytesUsed(data, length);
346 }
347
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);
352 }
353
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);
358 }
359
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);
364 }
365
366 void CFDataReplaceBytes(CFMutableDataRef data, CFRange range, const uint8_t *newBytes, CFIndex newLength) {
367 CFIndex len;
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)) {
375 case kCFMutable:
376 if (range.length < newLength && __CFDataNumBytes(data) < len - range.length + newLength) {
377 __CFDataGrow(data, newLength - range.length);
378 }
379 break;
380 case kCFFixedMutable:
381 CFAssert1(len - range.length + newLength <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__);
382 break;
383 }
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));
386 }
387 if (0 < newLength) {
388 memmove(data->_bytes + range.location, newBytes, newLength * sizeof(uint8_t));
389 }
390 __CFDataSetNumBytesUsed(data, (len - range.length + newLength));
391 __CFDataSetLength(data, (len - range.length + newLength));
392 }
393
394 #undef __CFDataValidateRange
395 #undef __CFGenericValidateMutabilityFlags
396