xref: /xnu-11215/libkern/c++/OSData.cpp (revision 14e3d835)
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((vm_address_t) 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((vm_offset_t)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((vm_offset_t)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 }
420