xref: /xnu-11215/libkern/c++/OSString.cpp (revision 8d741a5d)
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 
44 OSDefineMetaClassAndStructorsWithZone(OSString, OSObject,
45     (zone_create_flags_t) (ZC_CACHING | ZC_ZFREE_CLEARMEM))
46 OSMetaClassDefineReservedUnused(OSString, 0);
47 OSMetaClassDefineReservedUnused(OSString, 1);
48 OSMetaClassDefineReservedUnused(OSString, 2);
49 OSMetaClassDefineReservedUnused(OSString, 3);
50 OSMetaClassDefineReservedUnused(OSString, 4);
51 OSMetaClassDefineReservedUnused(OSString, 5);
52 OSMetaClassDefineReservedUnused(OSString, 6);
53 OSMetaClassDefineReservedUnused(OSString, 7);
54 OSMetaClassDefineReservedUnused(OSString, 8);
55 OSMetaClassDefineReservedUnused(OSString, 9);
56 OSMetaClassDefineReservedUnused(OSString, 10);
57 OSMetaClassDefineReservedUnused(OSString, 11);
58 OSMetaClassDefineReservedUnused(OSString, 12);
59 OSMetaClassDefineReservedUnused(OSString, 13);
60 OSMetaClassDefineReservedUnused(OSString, 14);
61 OSMetaClassDefineReservedUnused(OSString, 15);
62 
63 bool
64 OSString::initWithString(const OSString *aString)
65 {
66 	return initWithCString(aString->string);
67 }
68 
69 bool
70 OSString::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(cString, 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(cString, newString, 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 
106 bool
107 OSString::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(cString, 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(cString, newString, 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 
151 bool
152 OSString::initWithCStringNoCopy(const char *cString)
153 {
154 	if (!cString || !super::init()) {
155 		return false;
156 	}
157 
158 	length = (unsigned int) strnlen(cString, 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 
170 OSSharedPtr<OSString>
171 OSString::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 
182 OSSharedPtr<OSString>
183 OSString::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 
194 OSSharedPtr<OSString>
195 OSString::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 
206 OSSharedPtr<OSString>
207 OSString::withCString(const char *cString, size_t length)
208 {
209 	OSSharedPtr<OSString> me = OSMakeShared<OSString>();
210 
211 	if (me && !me->initWithStringOfLength(cString, length)) {
212 		return nullptr;
213 	}
214 
215 	return me;
216 }
217 
218 
219 
220 /* @@@ gvdl */
221 #if 0
222 OSString *
223 OSString::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 
249 void
250 OSString::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 
260 unsigned int
261 OSString::getLength()  const
262 {
263 	return length - 1;
264 }
265 
266 const char *
267 OSString::getCStringNoCopy() const
268 {
269 	return string;
270 }
271 
272 bool
273 OSString::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 
284 char
285 OSString::getChar(unsigned int index) const
286 {
287 	if (index < length) {
288 		return string[index];
289 	} else {
290 		return '\0';
291 	}
292 }
293 
294 
295 bool
296 OSString::isEqualTo(const OSString *aString) const
297 {
298 	if (length != aString->length) {
299 		return false;
300 	} else {
301 		return isEqualTo((const char *) aString->string);
302 	}
303 }
304 
305 bool
306 OSString::isEqualTo(const char *aCString) const
307 {
308 	return strncmp(string, aCString, length) == 0;
309 }
310 
311 bool
312 OSString::isEqualTo(const OSMetaClassBase *obj) const
313 {
314 	OSString *  str;
315 	OSData *    data;
316 
317 	if ((str = OSDynamicCast(OSString, obj))) {
318 		return isEqualTo(str);
319 	} else if ((data = OSDynamicCast(OSData, obj))) {
320 		return isEqualTo(data);
321 	} else {
322 		return false;
323 	}
324 }
325 
326 bool
327 OSString::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 
362 bool
363 OSString::serialize(OSSerialize *s) const
364 {
365 	char *c = string;
366 
367 	if (s->previouslySerialized(this)) {
368 		return true;
369 	}
370 
371 	if (!s->addXMLStartTag(this, "string")) {
372 		return false;
373 	}
374 	while (*c) {
375 		if (*c == '<') {
376 			if (!s->addString("&lt;")) {
377 				return false;
378 			}
379 		} else if (*c == '>') {
380 			if (!s->addString("&gt;")) {
381 				return false;
382 			}
383 		} else if (*c == '&') {
384 			if (!s->addString("&amp;")) {
385 				return false;
386 			}
387 		} else {
388 			if (!s->addChar(*c)) {
389 				return false;
390 			}
391 		}
392 		c++;
393 	}
394 
395 	return s->addXMLEndTag("string");
396 }
397