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
40OSDefineMetaClassAndStructors(OSData, OSObject)
41OSMetaClassDefineReservedUsed(OSData, 0);    // setDeallocFunction
42OSMetaClassDefineReservedUnused(OSData, 1);
43OSMetaClassDefineReservedUnused(OSData, 2);
44OSMetaClassDefineReservedUnused(OSData, 3);
45OSMetaClassDefineReservedUnused(OSData, 4);
46OSMetaClassDefineReservedUnused(OSData, 5);
47OSMetaClassDefineReservedUnused(OSData, 6);
48OSMetaClassDefineReservedUnused(OSData, 7);
49
50#define EXTERNAL ((unsigned int) -1)
51
52#if OSALLOCDEBUG
53extern 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
59struct OSData::ExpansionData
60{
61    DeallocFunction deallocFunction;
62    bool            disableSerialization;
63};
64
65bool 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
94bool 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
106bool 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
118bool OSData::initWithData(const OSData *inData)
119{
120    return initWithBytes(inData->data, inData->length);
121}
122
123bool 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
134OSData *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
146OSData *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
157OSData *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
169OSData *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
181OSData *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
194void 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
209unsigned int OSData::getLength() const { return length; }
210unsigned int OSData::getCapacity() const { return capacity; }
211
212unsigned int OSData::getCapacityIncrement() const
213{
214    return capacityIncrement;
215}
216
217unsigned int OSData::setCapacityIncrement(unsigned increment)
218{
219    return capacityIncrement = increment;
220}
221
222// xx-review: does not check for capacity == EXTERNAL
223
224unsigned 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
250bool 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
274bool 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
294bool OSData::appendBytes(const OSData *other)
295{
296    return appendBytes(other->data, other->length);
297}
298
299const void *OSData::getBytesNoCopy() const
300{
301    if (!length)
302        return 0;
303    else
304        return data;
305}
306
307const 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
320bool 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
331bool OSData::isEqualTo(const void *someData, unsigned int inLength) const
332{
333    return (length >= inLength) && (bcmp(data, someData, inLength) == 0);
334}
335
336bool 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
349bool 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
391static const char __CFPLDataEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
392
393bool 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
445void 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
456void 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