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