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