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