]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSData.cpp
61b4342d2326d4cdc6a2a058be395b7021f7aa3d
[apple/xnu.git] / libkern / c++ / OSData.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* IOData.m created by rsulack on Thu 25-Sep-1997 */
29
30 #include <string.h>
31
32 #include <libkern/c++/OSData.h>
33 #include <libkern/c++/OSSerialize.h>
34 #include <libkern/c++/OSLib.h>
35 #include <libkern/c++/OSString.h>
36 #include <string.h>
37
38 #define super OSObject
39
40 OSDefineMetaClassAndStructors(OSData, OSObject)
41 OSMetaClassDefineReservedUsed(OSData, 0); // setDeallocFunction
42 OSMetaClassDefineReservedUnused(OSData, 1);
43 OSMetaClassDefineReservedUnused(OSData, 2);
44 OSMetaClassDefineReservedUnused(OSData, 3);
45 OSMetaClassDefineReservedUnused(OSData, 4);
46 OSMetaClassDefineReservedUnused(OSData, 5);
47 OSMetaClassDefineReservedUnused(OSData, 6);
48 OSMetaClassDefineReservedUnused(OSData, 7);
49
50 #define EXTERNAL ((unsigned int) -1)
51
52 #if OSALLOCDEBUG
53 extern int debug_container_malloc_size;
54 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
55 #else
56 #define ACCUMSIZE(s)
57 #endif
58
59 struct OSData::ExpansionData
60 {
61 DeallocFunction deallocFunction;
62 bool disableSerialization;
63 };
64
65 bool OSData::initWithCapacity(unsigned int inCapacity)
66 {
67 if (!super::init())
68 return false;
69
70 if (data && (!inCapacity || capacity < inCapacity) ) {
71 // clean out old data's storage if it isn't big enough
72 kfree(data, capacity);
73 data = 0;
74 ACCUMSIZE(-capacity);
75 }
76
77 if (inCapacity && !data) {
78 data = (void *) kalloc(inCapacity);
79 if (!data)
80 return false;
81 capacity = inCapacity;
82 ACCUMSIZE(inCapacity);
83 }
84
85 length = 0;
86 if (inCapacity < 16)
87 capacityIncrement = 16;
88 else
89 capacityIncrement = inCapacity;
90
91 return true;
92 }
93
94 bool OSData::initWithBytes(const void *bytes, unsigned int inLength)
95 {
96 if ((inLength && !bytes) || !initWithCapacity(inLength))
97 return false;
98
99 if (bytes != data)
100 bcopy(bytes, data, inLength);
101 length = inLength;
102
103 return true;
104 }
105
106 bool OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength)
107 {
108 if (!super::init())
109 return false;
110
111 length = inLength;
112 capacity = EXTERNAL;
113 data = bytes;
114
115 return true;
116 }
117
118 bool OSData::initWithData(const OSData *inData)
119 {
120 return initWithBytes(inData->data, inData->length);
121 }
122
123 bool OSData::initWithData(const OSData *inData,
124 unsigned int start, unsigned int inLength)
125 {
126 const void *localData = inData->getBytesNoCopy(start, inLength);
127
128 if (localData)
129 return initWithBytes(localData, inLength);
130 else
131 return false;
132 }
133
134 OSData *OSData::withCapacity(unsigned int inCapacity)
135 {
136 OSData *me = new OSData;
137
138 if (me && !me->initWithCapacity(inCapacity)) {
139 me->release();
140 return 0;
141 }
142
143 return me;
144 }
145
146 OSData *OSData::withBytes(const void *bytes, unsigned int inLength)
147 {
148 OSData *me = new OSData;
149
150 if (me && !me->initWithBytes(bytes, inLength)) {
151 me->release();
152 return 0;
153 }
154 return me;
155 }
156
157 OSData *OSData::withBytesNoCopy(void *bytes, unsigned int inLength)
158 {
159 OSData *me = new OSData;
160
161 if (me && !me->initWithBytesNoCopy(bytes, inLength)) {
162 me->release();
163 return 0;
164 }
165
166 return me;
167 }
168
169 OSData *OSData::withData(const OSData *inData)
170 {
171 OSData *me = new OSData;
172
173 if (me && !me->initWithData(inData)) {
174 me->release();
175 return 0;
176 }
177
178 return me;
179 }
180
181 OSData *OSData::withData(const OSData *inData,
182 unsigned int start, unsigned int inLength)
183 {
184 OSData *me = new OSData;
185
186 if (me && !me->initWithData(inData, start, inLength)) {
187 me->release();
188 return 0;
189 }
190
191 return me;
192 }
193
194 void OSData::free()
195 {
196 if (capacity != EXTERNAL && data && capacity) {
197 kfree(data, capacity);
198 ACCUMSIZE( -capacity );
199 } else if (capacity == EXTERNAL) {
200 DeallocFunction freemem = reserved ? reserved->deallocFunction : NULL;
201 if (freemem && data && length) {
202 freemem(data, length);
203 }
204 }
205 if (reserved) kfree(reserved, sizeof(ExpansionData));
206 super::free();
207 }
208
209 unsigned int OSData::getLength() const { return length; }
210 unsigned int OSData::getCapacity() const { return capacity; }
211
212 unsigned int OSData::getCapacityIncrement() const
213 {
214 return capacityIncrement;
215 }
216
217 unsigned int OSData::setCapacityIncrement(unsigned increment)
218 {
219 return capacityIncrement = increment;
220 }
221
222 // xx-review: does not check for capacity == EXTERNAL
223
224 unsigned int OSData::ensureCapacity(unsigned int newCapacity)
225 {
226 unsigned char * newData;
227
228 if (newCapacity <= capacity)
229 return capacity;
230
231 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
232 * capacityIncrement;
233
234 newData = (unsigned char *) kalloc(newCapacity);
235
236 if ( newData ) {
237 bzero(newData + capacity, newCapacity - capacity);
238 if (data) {
239 bcopy(data, newData, capacity);
240 kfree(data, capacity);
241 }
242 ACCUMSIZE( newCapacity - capacity );
243 data = (void *) newData;
244 capacity = newCapacity;
245 }
246
247 return capacity;
248 }
249
250 bool OSData::appendBytes(const void *bytes, unsigned int inLength)
251 {
252 unsigned int newSize;
253
254 if (!inLength)
255 return true;
256
257 if (capacity == EXTERNAL)
258 return false;
259
260 newSize = length + inLength;
261 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) )
262 return false;
263
264 if (bytes)
265 bcopy(bytes, &((unsigned char *)data)[length], inLength);
266 else
267 bzero(&((unsigned char *)data)[length], inLength);
268
269 length = newSize;
270
271 return true;
272 }
273
274 bool OSData::appendByte(unsigned char byte, unsigned int inLength)
275 {
276 unsigned int newSize;
277
278 if (!inLength)
279 return true;
280
281 if (capacity == EXTERNAL)
282 return false;
283
284 newSize = length + inLength;
285 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) )
286 return false;
287
288 memset(&((unsigned char *)data)[length], byte, inLength);
289 length = newSize;
290
291 return true;
292 }
293
294 bool OSData::appendBytes(const OSData *other)
295 {
296 return appendBytes(other->data, other->length);
297 }
298
299 const void *OSData::getBytesNoCopy() const
300 {
301 if (!length)
302 return 0;
303 else
304 return data;
305 }
306
307 const void *OSData::getBytesNoCopy(unsigned int start,
308 unsigned int inLength) const
309 {
310 const void *outData = 0;
311
312 if (length
313 && start < length
314 && (start + inLength) <= length)
315 outData = (const void *) ((char *) data + start);
316
317 return outData;
318 }
319
320 bool OSData::isEqualTo(const OSData *aData) const
321 {
322 unsigned int len;
323
324 len = aData->length;
325 if ( length != len )
326 return false;
327
328 return isEqualTo(aData->data, len);
329 }
330
331 bool OSData::isEqualTo(const void *someData, unsigned int inLength) const
332 {
333 return (length >= inLength) && (bcmp(data, someData, inLength) == 0);
334 }
335
336 bool OSData::isEqualTo(const OSMetaClassBase *obj) const
337 {
338 OSData * otherData;
339 OSString * str;
340
341 if ((otherData = OSDynamicCast(OSData, obj)))
342 return isEqualTo(otherData);
343 else if ((str = OSDynamicCast (OSString, obj)))
344 return isEqualTo(str);
345 else
346 return false;
347 }
348
349 bool OSData::isEqualTo(const OSString *obj) const
350 {
351 const char * aCString;
352 char * dataPtr;
353 unsigned int checkLen = length;
354 unsigned int stringLen;
355
356 if (!obj)
357 return false;
358
359 stringLen = obj->getLength ();
360
361 dataPtr = (char *)data;
362
363 if (stringLen != checkLen) {
364
365 // check for the fact that OSData may be a buffer that
366 // that includes a termination byte and will thus have
367 // a length of the actual string length PLUS 1. In this
368 // case we verify that the additional byte is a terminator
369 // and if so count the two lengths as being the same.
370
371 if ( (checkLen - stringLen) == 1) {
372 if (dataPtr[checkLen-1] != 0) // non-zero means not a terminator and thus not likely the same
373 return false;
374 checkLen--;
375 }
376 else
377 return false;
378 }
379
380 aCString = obj->getCStringNoCopy ();
381
382 for ( unsigned int i=0; i < checkLen; i++ ) {
383 if ( *dataPtr++ != aCString[i] )
384 return false;
385 }
386
387 return true;
388 }
389
390 //this was taken from CFPropertyList.c
391 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
392
393 bool OSData::serialize(OSSerialize *s) const
394 {
395 unsigned int i;
396 const unsigned char *p;
397 unsigned char c;
398 unsigned int serializeLength;
399
400 if (s->previouslySerialized(this)) return true;
401
402 if (!s->addXMLStartTag(this, "data")) return false;
403
404 serializeLength = length;
405 if (reserved && reserved->disableSerialization) serializeLength = 0;
406
407 for (i = 0, p = (unsigned char *)data; i < serializeLength; i++, p++) {
408 /* 3 bytes are encoded as 4 */
409 switch (i % 3) {
410 case 0:
411 c = __CFPLDataEncodeTable [ ((p[0] >> 2) & 0x3f)];
412 if (!s->addChar(c)) return false;
413 break;
414 case 1:
415 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 4) & 0x3f)];
416 if (!s->addChar(c)) return false;
417 break;
418 case 2:
419 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 6) & 0x3f)];
420 if (!s->addChar(c)) return false;
421 c = __CFPLDataEncodeTable [ (p[0] & 0x3f)];
422 if (!s->addChar(c)) return false;
423 break;
424 }
425 }
426 switch (i % 3) {
427 case 0:
428 break;
429 case 1:
430 c = __CFPLDataEncodeTable [ ((p[-1] << 4) & 0x30)];
431 if (!s->addChar(c)) return false;
432 if (!s->addChar('=')) return false;
433 if (!s->addChar('=')) return false;
434 break;
435 case 2:
436 c = __CFPLDataEncodeTable [ ((p[-1] << 2) & 0x3c)];
437 if (!s->addChar(c)) return false;
438 if (!s->addChar('=')) return false;
439 break;
440 }
441
442 return s->addXMLEndTag("data");
443 }
444
445 void OSData::setDeallocFunction(DeallocFunction func)
446 {
447 if (!reserved)
448 {
449 reserved = (typeof(reserved)) kalloc(sizeof(ExpansionData));
450 if (!reserved) return;
451 bzero(reserved, sizeof(ExpansionData));
452 }
453 reserved->deallocFunction = func;
454 }
455
456 void OSData::setSerializable(bool serializable)
457 {
458 if (!reserved)
459 {
460 reserved = (typeof(reserved)) kalloc(sizeof(ExpansionData));
461 if (!reserved) return;
462 bzero(reserved, sizeof(ExpansionData));
463 }
464 reserved->disableSerialization = (!serializable);
465 }