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/* IOString.m created by rsulack on Wed 17-Sep-1997 */
29/* IOString.cpp converted to C++ on Tue 1998-9-22 */
30
31#include <string.h>
32
33#include <libkern/c++/OSString.h>
34#include <libkern/c++/OSSerialize.h>
35#include <libkern/c++/OSLib.h>
36#include <libkern/c++/OSData.h>
37#include <string.h>
38
39#define super OSObject
40
41OSDefineMetaClassAndStructors(OSString, OSObject)
42OSMetaClassDefineReservedUnused(OSString,  0);
43OSMetaClassDefineReservedUnused(OSString,  1);
44OSMetaClassDefineReservedUnused(OSString,  2);
45OSMetaClassDefineReservedUnused(OSString,  3);
46OSMetaClassDefineReservedUnused(OSString,  4);
47OSMetaClassDefineReservedUnused(OSString,  5);
48OSMetaClassDefineReservedUnused(OSString,  6);
49OSMetaClassDefineReservedUnused(OSString,  7);
50OSMetaClassDefineReservedUnused(OSString,  8);
51OSMetaClassDefineReservedUnused(OSString,  9);
52OSMetaClassDefineReservedUnused(OSString, 10);
53OSMetaClassDefineReservedUnused(OSString, 11);
54OSMetaClassDefineReservedUnused(OSString, 12);
55OSMetaClassDefineReservedUnused(OSString, 13);
56OSMetaClassDefineReservedUnused(OSString, 14);
57OSMetaClassDefineReservedUnused(OSString, 15);
58
59#if OSALLOCDEBUG
60extern "C" {
61    extern int debug_container_malloc_size;
62};
63#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
64#else
65#define ACCUMSIZE(s)
66#endif
67
68bool OSString::initWithString(const OSString *aString)
69{
70    return initWithCString(aString->string);
71}
72
73bool OSString::initWithCString(const char *cString)
74{
75    if (!cString || !super::init())
76        return false;
77
78    length = strlen(cString) + 1;
79    string = (char *) kalloc(length);
80    if (!string)
81        return false;
82
83    bcopy(cString, string, length);
84
85    ACCUMSIZE(length);
86
87    return true;
88}
89
90bool OSString::initWithStringOfLength(const char *cString, size_t inlength)
91{
92    if (!cString || !super::init())
93        return false;
94
95    length = inlength + 1;
96    string = (char *) kalloc(length);
97    if (!string)
98        return false;
99
100    bcopy(cString, string, inlength);
101    string[inlength] = 0;
102
103    ACCUMSIZE(length);
104
105    return true;
106}
107
108bool OSString::initWithCStringNoCopy(const char *cString)
109{
110    if (!cString || !super::init())
111        return false;
112
113    length = strlen(cString) + 1;
114    flags |= kOSStringNoCopy;
115    string = const_cast<char *>(cString);
116
117    return true;
118}
119
120OSString *OSString::withString(const OSString *aString)
121{
122    OSString *me = new OSString;
123
124    if (me && !me->initWithString(aString)) {
125        me->release();
126        return 0;
127    }
128
129    return me;
130}
131
132OSString *OSString::withCString(const char *cString)
133{
134    OSString *me = new OSString;
135
136    if (me && !me->initWithCString(cString)) {
137        me->release();
138        return 0;
139    }
140
141    return me;
142}
143
144OSString *OSString::withCStringNoCopy(const char *cString)
145{
146    OSString *me = new OSString;
147
148    if (me && !me->initWithCStringNoCopy(cString)) {
149        me->release();
150        return 0;
151    }
152
153    return me;
154}
155
156OSString *OSString::withStringOfLength(const char *cString, size_t length)
157{
158    OSString *me = new OSString;
159
160    if (me && !me->initWithStringOfLength(cString, length)) {
161        me->release();
162        return 0;
163    }
164
165    return me;
166}
167
168
169
170/* @@@ gvdl */
171#if 0
172OSString *OSString::stringWithFormat(const char *format, ...)
173{
174#ifndef KERNEL			// mach3xxx
175    OSString *me;
176    va_list argList;
177
178    if (!format)
179        return 0;
180
181    va_start(argList, format);
182    me = stringWithCapacity(256);
183    me->length = vsnprintf(me->string, 256, format, argList);
184    me->length++;	// we include the null in the length
185    if (me->Length > 256)
186        me->Length = 256;
187    va_end (argList);
188
189    return me;
190#else
191    return 0;
192#endif
193}
194#endif /* 0 */
195
196void OSString::free()
197{
198    if ( !(flags & kOSStringNoCopy) && string) {
199        kfree(string, (vm_size_t)length);
200        ACCUMSIZE(-length);
201    }
202
203    super::free();
204}
205
206unsigned int OSString::getLength()  const { return length - 1; }
207
208const char *OSString::getCStringNoCopy() const
209{
210    return string;
211}
212
213bool OSString::setChar(char aChar, unsigned int index)
214{
215    if ( !(flags & kOSStringNoCopy) && index < length - 1) {
216        string[index] = aChar;
217
218        return true;
219    }
220    else
221        return false;
222}
223
224char OSString::getChar(unsigned int index) const
225{
226    if (index < length)
227        return string[index];
228    else
229        return '\0';
230}
231
232
233bool OSString::isEqualTo(const OSString *aString) const
234{
235    if (length != aString->length)
236        return false;
237    else
238        return isEqualTo((const char *) aString->string);
239}
240
241bool OSString::isEqualTo(const char *aCString) const
242{
243    return strncmp(string, aCString, length) == 0;
244}
245
246bool OSString::isEqualTo(const OSMetaClassBase *obj) const
247{
248    OSString *	str;
249    OSData *    data;
250
251    if ((str = OSDynamicCast(OSString, obj)))
252        return isEqualTo(str);
253    else if ((data = OSDynamicCast (OSData, obj)))
254        return isEqualTo(data);
255    else
256        return false;
257}
258
259bool OSString::isEqualTo(const OSData *obj) const
260{
261    if (NULL == obj)
262      return false;
263
264    unsigned int dataLen = obj->getLength ();;
265    char * dataPtr = (char *) obj->getBytesNoCopy ();
266
267    if (dataLen != length) {
268
269      // check for the fact that OSData may be a buffer that
270      // that includes a termination byte and will thus have
271      // a length of the actual string length PLUS 1. In this
272      // case we verify that the additional byte is a terminator
273      // and if so count the two lengths as being the same.
274
275      if ( (dataLen - length) == 1 ) {
276	if (dataPtr[dataLen-1] != 0)
277	  return false;
278	dataLen--;
279      }
280      else
281	return false;
282    }
283
284    for ( unsigned int i=0; i < dataLen; i++ ) {
285      if ( *dataPtr++ != string[i] )
286        return false;
287    }
288
289    return true;
290}
291
292bool OSString::serialize(OSSerialize *s) const
293{
294    char *c = string;
295
296    if (s->previouslySerialized(this)) return true;
297
298    if (!s->addXMLStartTag(this, "string")) return false;
299    while (*c) {
300        if (*c == '<') {
301            if (!s->addString("&lt;")) return false;
302        } else if (*c == '>') {
303            if (!s->addString("&gt;")) return false;
304        } else if (*c == '&') {
305            if (!s->addString("&amp;")) return false;
306        } else {
307            if (!s->addChar(*c)) return false;
308        }
309        c++;
310    }
311
312    return s->addXMLEndTag("string");
313}
314