]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSData.cpp
xnu-344.21.73.tar.gz
[apple/xnu.git] / libkern / c++ / OSData.cpp
1 /*
2 * Copyright (c) 2000 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 /* IOData.m created by rsulack on Thu 25-Sep-1997 */
26
27 #include <string.h>
28
29 #include <libkern/c++/OSData.h>
30 #include <libkern/c++/OSSerialize.h>
31 #include <libkern/c++/OSLib.h>
32 #include <libkern/c++/OSString.h>
33 #include <string.h>
34
35 #define super OSObject
36
37 OSDefineMetaClassAndStructors(OSData, OSObject)
38 OSMetaClassDefineReservedUnused(OSData, 0);
39 OSMetaClassDefineReservedUnused(OSData, 1);
40 OSMetaClassDefineReservedUnused(OSData, 2);
41 OSMetaClassDefineReservedUnused(OSData, 3);
42 OSMetaClassDefineReservedUnused(OSData, 4);
43 OSMetaClassDefineReservedUnused(OSData, 5);
44 OSMetaClassDefineReservedUnused(OSData, 6);
45 OSMetaClassDefineReservedUnused(OSData, 7);
46
47 #define EXTERNAL ((unsigned int) -1)
48
49 #if OSALLOCDEBUG
50 extern int debug_container_malloc_size;
51 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
52 #else
53 #define ACCUMSIZE(s)
54 #endif
55
56 bool OSData::initWithCapacity(unsigned int inCapacity)
57 {
58 if (!super::init())
59 return false;
60
61 if (data && (!inCapacity || capacity < inCapacity) ) {
62 // clean out old data's storage if it isn't big enough
63 kfree((vm_address_t) data, capacity);
64 data = 0;
65 ACCUMSIZE(-capacity);
66 }
67
68 if (inCapacity && !data) {
69 data = (void *) kalloc(inCapacity);
70 if (!data)
71 return false;
72 capacity = inCapacity;
73 ACCUMSIZE(inCapacity);
74 }
75
76 length = 0;
77 if (inCapacity < 16)
78 capacityIncrement = 16;
79 else
80 capacityIncrement = inCapacity;
81
82 return true;
83 }
84
85 bool OSData::initWithBytes(const void *bytes, unsigned int inLength)
86 {
87 if ((inLength && !bytes) || !initWithCapacity(inLength))
88 return false;
89
90 if (bytes != data)
91 bcopy(bytes, data, inLength);
92 length = inLength;
93
94 return true;
95 }
96
97 bool OSData::initWithBytesNoCopy(void *bytes, unsigned int inLength)
98 {
99 if (!super::init())
100 return false;
101
102 length = inLength;
103 capacity = EXTERNAL;
104 data = bytes;
105
106 return true;
107 }
108
109 bool OSData::initWithData(const OSData *inData)
110 {
111 return initWithBytes(inData->data, inData->length);
112 }
113
114 bool OSData::initWithData(const OSData *inData,
115 unsigned int start, unsigned int inLength)
116 {
117 const void *localData = inData->getBytesNoCopy(start, inLength);
118
119 if (localData)
120 return initWithBytes(localData, inLength);
121 else
122 return false;
123 }
124
125 OSData *OSData::withCapacity(unsigned int inCapacity)
126 {
127 OSData *me = new OSData;
128
129 if (me && !me->initWithCapacity(inCapacity)) {
130 me->release();
131 return 0;
132 }
133
134 return me;
135 }
136
137 OSData *OSData::withBytes(const void *bytes, unsigned int inLength)
138 {
139 OSData *me = new OSData;
140
141 if (me && !me->initWithBytes(bytes, inLength)) {
142 me->release();
143 return 0;
144 }
145 return me;
146 }
147
148 OSData *OSData::withBytesNoCopy(void *bytes, unsigned int inLength)
149 {
150 OSData *me = new OSData;
151
152 if (me && !me->initWithBytesNoCopy(bytes, inLength)) {
153 me->release();
154 return 0;
155 }
156
157 return me;
158 }
159
160 OSData *OSData::withData(const OSData *inData)
161 {
162 OSData *me = new OSData;
163
164 if (me && !me->initWithData(inData)) {
165 me->release();
166 return 0;
167 }
168
169 return me;
170 }
171
172 OSData *OSData::withData(const OSData *inData,
173 unsigned int start, unsigned int inLength)
174 {
175 OSData *me = new OSData;
176
177 if (me && !me->initWithData(inData, start, inLength)) {
178 me->release();
179 return 0;
180 }
181
182 return me;
183 }
184
185 void OSData::free()
186 {
187 if (capacity != EXTERNAL && data && capacity) {
188 kfree((vm_offset_t)data, capacity);
189 ACCUMSIZE( -capacity );
190 }
191 super::free();
192 }
193
194 unsigned int OSData::getLength() const { return length; }
195 unsigned int OSData::getCapacity() const { return capacity; }
196
197 unsigned int OSData::getCapacityIncrement() const
198 {
199 return capacityIncrement;
200 }
201
202 unsigned int OSData::setCapacityIncrement(unsigned increment)
203 {
204 return capacityIncrement = increment;
205 }
206
207 unsigned int OSData::ensureCapacity(unsigned int newCapacity)
208 {
209 unsigned char * newData;
210
211 if (newCapacity <= capacity)
212 return capacity;
213
214 newCapacity = (((newCapacity - 1) / capacityIncrement) + 1)
215 * capacityIncrement;
216
217 newData = (unsigned char *) kalloc(newCapacity);
218
219 if ( newData ) {
220 bzero(newData + capacity, newCapacity - capacity);
221 if (data) {
222 bcopy(data, newData, capacity);
223 kfree((vm_offset_t)data, capacity);
224 }
225 ACCUMSIZE( newCapacity - capacity );
226 data = (void *) newData;
227 capacity = newCapacity;
228 }
229
230 return capacity;
231 }
232
233 bool OSData::appendBytes(const void *bytes, unsigned int inLength)
234 {
235 unsigned int newSize;
236
237 if (!inLength)
238 return true;
239
240 if (capacity == EXTERNAL)
241 return false;
242
243 newSize = length + inLength;
244 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) )
245 return false;
246
247 if (bytes)
248 bcopy(bytes, &((unsigned char *)data)[length], inLength);
249 else
250 bzero(&((unsigned char *)data)[length], inLength);
251
252 length = newSize;
253
254 return true;
255 }
256
257 bool OSData::appendByte(unsigned char byte, unsigned int inLength)
258 {
259 unsigned int newSize;
260
261 if (!inLength)
262 return true;
263
264 if (capacity == EXTERNAL)
265 return false;
266
267 newSize = length + inLength;
268 if ( (newSize > capacity) && newSize > ensureCapacity(newSize) )
269 return false;
270
271 memset(&((unsigned char *)data)[length], byte, inLength);
272 length = newSize;
273
274 return true;
275 }
276
277 bool OSData::appendBytes(const OSData *other)
278 {
279 return appendBytes(other->data, other->length);
280 }
281
282 const void *OSData::getBytesNoCopy() const
283 {
284 if (!length)
285 return 0;
286 else
287 return data;
288 }
289
290 const void *OSData::getBytesNoCopy(unsigned int start,
291 unsigned int inLength) const
292 {
293 const void *outData = 0;
294
295 if (length
296 && start < length
297 && (start + inLength) <= length)
298 outData = (const void *) ((char *) data + start);
299
300 return outData;
301 }
302
303 bool OSData::isEqualTo(const OSData *aData) const
304 {
305 unsigned int len;
306
307 len = aData->length;
308 if ( length != len )
309 return false;
310
311 return isEqualTo(aData->data, len);
312 }
313
314 bool OSData::isEqualTo(const void *someData, unsigned int inLength) const
315 {
316 return (length >= inLength) && (bcmp(data, someData, inLength) == 0);
317 }
318
319 bool OSData::isEqualTo(const OSMetaClassBase *obj) const
320 {
321 OSData * data;
322 OSString * str;
323
324 if ((data = OSDynamicCast(OSData, obj)))
325 return isEqualTo(data);
326 else if ((str = OSDynamicCast (OSString, obj)))
327 return isEqualTo(str);
328 else
329 return false;
330 }
331
332 bool OSData::isEqualTo(const OSString *obj) const
333 {
334 const char * aCString;
335 char * dataPtr;
336 unsigned int checkLen = length;
337 unsigned int stringLen;
338
339 if (!obj)
340 return false;
341
342 stringLen = obj->getLength ();
343
344 dataPtr = (char *)data;
345
346 if (stringLen != checkLen) {
347
348 // check for the fact that OSData may be a buffer that
349 // that includes a termination byte and will thus have
350 // a length of the actual string length PLUS 1. In this
351 // case we verify that the additional byte is a terminator
352 // and if so count the two lengths as being the same.
353
354 if ( (checkLen - stringLen) == 1) {
355 if (dataPtr[checkLen-1] != 0) // non-zero means not a terminator and thus not likely the same
356 return false;
357 checkLen--;
358 }
359 else
360 return false;
361 }
362
363 aCString = obj->getCStringNoCopy ();
364
365 for ( unsigned int i=0; i < checkLen; i++ ) {
366 if ( *dataPtr++ != aCString[i] )
367 return false;
368 }
369
370 return true;
371 }
372
373 //this was taken from CFPropertyList.c
374 static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
375
376 bool OSData::serialize(OSSerialize *s) const
377 {
378 unsigned int i;
379 const unsigned char *p;
380 unsigned char c;
381
382 if (s->previouslySerialized(this)) return true;
383
384 if (!s->addXMLStartTag(this, "data")) return false;
385
386 for (i = 0, p = (unsigned char *)data; i < length; i++, p++) {
387 /* 3 bytes are encoded as 4 */
388 switch (i % 3) {
389 case 0:
390 c = __CFPLDataEncodeTable [ ((p[0] >> 2) & 0x3f)];
391 if (!s->addChar(c)) return false;
392 break;
393 case 1:
394 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 4) & 0x3f)];
395 if (!s->addChar(c)) return false;
396 break;
397 case 2:
398 c = __CFPLDataEncodeTable [ ((((p[-1] << 8) | p[0]) >> 6) & 0x3f)];
399 if (!s->addChar(c)) return false;
400 c = __CFPLDataEncodeTable [ (p[0] & 0x3f)];
401 if (!s->addChar(c)) return false;
402 break;
403 }
404 }
405 switch (i % 3) {
406 case 0:
407 break;
408 case 1:
409 c = __CFPLDataEncodeTable [ ((p[-1] << 4) & 0x30)];
410 if (!s->addChar(c)) return false;
411 if (!s->addChar('=')) return false;
412 if (!s->addChar('=')) return false;
413 break;
414 case 2:
415 c = __CFPLDataEncodeTable [ ((p[-1] << 2) & 0x3c)];
416 if (!s->addChar(c)) return false;
417 if (!s->addChar('=')) return false;
418 break;
419 }
420
421 return s->addXMLEndTag("data");
422 }