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