1/*
2 * Copyright (c) 2019 Apple 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#define IOKIT_ENABLE_SHARED_PTR
32
33#include <string.h>
34
35#include <libkern/c++/OSString.h>
36#include <libkern/c++/OSSerialize.h>
37#include <libkern/c++/OSSharedPtr.h>
38#include <libkern/c++/OSLib.h>
39#include <libkern/c++/OSData.h>
40#include <string.h>
41
42#define super OSObject
43
44OSDefineMetaClassAndStructorsWithZone(OSString, OSObject,
45 (zone_create_flags_t) (ZC_CACHING | ZC_ZFREE_CLEARMEM))
46OSMetaClassDefineReservedUnused(OSString, 0);
47OSMetaClassDefineReservedUnused(OSString, 1);
48OSMetaClassDefineReservedUnused(OSString, 2);
49OSMetaClassDefineReservedUnused(OSString, 3);
50OSMetaClassDefineReservedUnused(OSString, 4);
51OSMetaClassDefineReservedUnused(OSString, 5);
52OSMetaClassDefineReservedUnused(OSString, 6);
53OSMetaClassDefineReservedUnused(OSString, 7);
54OSMetaClassDefineReservedUnused(OSString, 8);
55OSMetaClassDefineReservedUnused(OSString, 9);
56OSMetaClassDefineReservedUnused(OSString, 10);
57OSMetaClassDefineReservedUnused(OSString, 11);
58OSMetaClassDefineReservedUnused(OSString, 12);
59OSMetaClassDefineReservedUnused(OSString, 13);
60OSMetaClassDefineReservedUnused(OSString, 14);
61OSMetaClassDefineReservedUnused(OSString, 15);
62
63bool
64OSString::initWithString(const OSString *aString)
65{
66 return initWithCString(cString: aString->string);
67}
68
69bool
70OSString::initWithCString(const char *cString)
71{
72 unsigned int newLength;
73 char * newString;
74
75 if (!cString || !super::init()) {
76 return false;
77 }
78
79 newLength = (unsigned int) strnlen(s: cString, n: kMaxStringLength);
80 if (newLength >= kMaxStringLength) {
81 return false;
82 }
83
84 newLength++;
85 newString = (char *)kalloc_data(newLength,
86 Z_VM_TAG_BT(Z_WAITOK, VM_KERN_MEMORY_LIBKERN));
87 if (!newString) {
88 return false;
89 }
90
91 bcopy(src: cString, dst: newString, n: newLength);
92
93 if (!(flags & kOSStringNoCopy) && string) {
94 kfree_data(string, length);
95 OSCONTAINER_ACCUMSIZE(-((size_t)length));
96 }
97 string = newString;
98 length = newLength;
99 flags &= ~kOSStringNoCopy;
100
101 OSCONTAINER_ACCUMSIZE(length);
102
103 return true;
104}
105
106bool
107OSString::initWithStringOfLength(const char *cString, size_t inlength)
108{
109 unsigned int newLength;
110 unsigned int cStringLength;
111 char * newString;
112
113 if (!cString || !super::init()) {
114 return false;
115 }
116
117 if (inlength >= kMaxStringLength) {
118 return false;
119 }
120
121 cStringLength = (unsigned int)strnlen(s: cString, n: inlength);
122
123 if (cStringLength < inlength) {
124 inlength = cStringLength;
125 }
126
127 newLength = (unsigned int) (inlength + 1);
128 newString = (char *)kalloc_data(newLength,
129 Z_VM_TAG_BT(Z_WAITOK, VM_KERN_MEMORY_LIBKERN));
130 if (!newString) {
131 return false;
132 }
133
134 bcopy(src: cString, dst: newString, n: inlength);
135 newString[inlength] = 0;
136
137 if (!(flags & kOSStringNoCopy) && string) {
138 kfree_data(string, length);
139 OSCONTAINER_ACCUMSIZE(-((size_t)length));
140 }
141
142 string = newString;
143 length = newLength;
144 flags &= ~kOSStringNoCopy;
145
146 OSCONTAINER_ACCUMSIZE(length);
147
148 return true;
149}
150
151bool
152OSString::initWithCStringNoCopy(const char *cString)
153{
154 if (!cString || !super::init()) {
155 return false;
156 }
157
158 length = (unsigned int) strnlen(s: cString, n: kMaxStringLength);
159 if (length >= kMaxStringLength) {
160 return false;
161 }
162
163 length++;
164 flags |= kOSStringNoCopy;
165 string = const_cast<char *>(cString);
166
167 return true;
168}
169
170OSSharedPtr<OSString>
171OSString::withString(const OSString *aString)
172{
173 OSSharedPtr<OSString> me = OSMakeShared<OSString>();
174
175 if (me && !me->initWithString(aString)) {
176 return nullptr;
177 }
178
179 return me;
180}
181
182OSSharedPtr<OSString>
183OSString::withCString(const char *cString)
184{
185 OSSharedPtr<OSString> me = OSMakeShared<OSString>();
186
187 if (me && !me->initWithCString(cString)) {
188 return nullptr;
189 }
190
191 return me;
192}
193
194OSSharedPtr<OSString>
195OSString::withCStringNoCopy(const char *cString)
196{
197 OSSharedPtr<OSString> me = OSMakeShared<OSString>();
198
199 if (me && !me->initWithCStringNoCopy(cString)) {
200 return nullptr;
201 }
202
203 return me;
204}
205
206OSSharedPtr<OSString>
207OSString::withCString(const char *cString, size_t length)
208{
209 OSSharedPtr<OSString> me = OSMakeShared<OSString>();
210
211 if (me && !me->initWithStringOfLength(cString, inlength: length)) {
212 return nullptr;
213 }
214
215 return me;
216}
217
218
219
220/* @@@ gvdl */
221#if 0
222OSString *
223OSString::stringWithFormat(const char *format, ...)
224{
225#ifndef KERNEL // mach3xxx
226 OSString *me;
227 va_list argList;
228
229 if (!format) {
230 return 0;
231 }
232
233 va_start(argList, format);
234 me = stringWithCapacity(256);
235 me->length = vsnprintf(me->string, 256, format, argList);
236 me->length++; // we include the null in the length
237 if (me->Length > 256) {
238 me->Length = 256;
239 }
240 va_end(argList);
241
242 return me;
243#else
244 return 0;
245#endif
246}
247#endif /* 0 */
248
249void
250OSString::free()
251{
252 if (!(flags & kOSStringNoCopy) && string) {
253 kfree_data(string, length);
254 OSCONTAINER_ACCUMSIZE(-((size_t)length));
255 }
256
257 super::free();
258}
259
260unsigned int
261OSString::getLength() const
262{
263 return length - 1;
264}
265
266const char *
267OSString::getCStringNoCopy() const
268{
269 return string;
270}
271
272bool
273OSString::setChar(char aChar, unsigned int index)
274{
275 if (!(flags & kOSStringNoCopy) && index < length - 1) {
276 string[index] = aChar;
277
278 return true;
279 } else {
280 return false;
281 }
282}
283
284char
285OSString::getChar(unsigned int index) const
286{
287 if (index < length) {
288 return string[index];
289 } else {
290 return '\0';
291 }
292}
293
294
295bool
296OSString::isEqualTo(const OSString *aString) const
297{
298 if (length != aString->length) {
299 return false;
300 } else {
301 return isEqualTo(cString: (const char *) aString->string);
302 }
303}
304
305bool
306OSString::isEqualTo(const char *aCString) const
307{
308 return strncmp(s1: string, s2: aCString, n: length) == 0;
309}
310
311bool
312OSString::isEqualTo(const OSMetaClassBase *obj) const
313{
314 OSString * str;
315 OSData * data;
316
317 if ((str = OSDynamicCast(OSString, obj))) {
318 return isEqualTo(aString: str);
319 } else if ((data = OSDynamicCast(OSData, obj))) {
320 return isEqualTo(aDataObject: data);
321 } else {
322 return false;
323 }
324}
325
326bool
327OSString::isEqualTo(const OSData *obj) const
328{
329 if (NULL == obj) {
330 return false;
331 }
332
333 unsigned int dataLen = obj->getLength();
334 const char * dataPtr = (const char *) obj->getBytesNoCopy();
335
336 if (dataLen != length) {
337 // check for the fact that OSData may be a buffer that
338 // that includes a termination byte and will thus have
339 // a length of the actual string length PLUS 1. In this
340 // case we verify that the additional byte is a terminator
341 // and if so count the two lengths as being the same.
342
343 if ((dataLen - length) == 1) {
344 if (dataPtr[dataLen - 1] != 0) {
345 return false;
346 }
347 dataLen--;
348 } else {
349 return false;
350 }
351 }
352
353 for (unsigned int i = 0; i < dataLen; i++) {
354 if (*dataPtr++ != string[i]) {
355 return false;
356 }
357 }
358
359 return true;
360}
361
362bool
363OSString::serialize(OSSerialize *s) const
364{
365 char *c = string;
366
367 if (s->previouslySerialized(object: this)) {
368 return true;
369 }
370
371 if (!s->addXMLStartTag(object: this, tagString: "string")) {
372 return false;
373 }
374 while (*c) {
375 if (*c == '<') {
376 if (!s->addString(cString: "&lt;")) {
377 return false;
378 }
379 } else if (*c == '>') {
380 if (!s->addString(cString: "&gt;")) {
381 return false;
382 }
383 } else if (*c == '&') {
384 if (!s->addString(cString: "&amp;")) {
385 return false;
386 }
387 } else {
388 if (!s->addChar(aChar: *c)) {
389 return false;
390 }
391 }
392 c++;
393 }
394
395 return s->addXMLEndTag(tagString: "string");
396}
397