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