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