xref: /xnu-11215/libkern/c++/OSData.cpp (revision 368ad365)
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 }
423