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