1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/hash-str.h"
24 #include "common/list.h"
25 #include "common/memorypool.h"
26 #include "common/str.h"
27 #include "common/util.h"
28 #include "common/mutex.h"
29 
30 namespace Common {
31 
String(char c)32 String::String(char c)
33 	: BaseString<char>() {
34 
35 	_storage[0] = c;
36 	_storage[1] = 0;
37 
38 	_size = (c == 0) ? 0 : 1;
39 }
40 
41 #ifndef SCUMMVM_UTIL
String(const U32String & str,Common::CodePage page)42 String::String(const U32String &str, Common::CodePage page)
43 	: BaseString<char>() {
44 	_storage[0] = 0;
45 	*this = String(str.encode(page));
46 }
47 #endif
48 
operator =(const char * str)49 String &String::operator=(const char *str) {
50 	assign(str);
51 	return *this;
52 }
53 
operator =(const String & str)54 String &String::operator=(const String &str) {
55 	assign(str);
56 	return *this;
57 }
58 
operator =(char c)59 String &String::operator=(char c) {
60 	assign(c);
61 	return *this;
62 }
63 
operator +=(const char * str)64 String &String::operator+=(const char *str) {
65 	assignAppend(str);
66 	return *this;
67 }
68 
operator +=(const String & str)69 String &String::operator+=(const String &str) {
70 	assignAppend(str);
71 	return *this;
72 }
73 
operator +=(char c)74 String &String::operator+=(char c) {
75 	assignAppend(c);
76 	return *this;
77 }
78 
hasPrefix(const String & x) const79 bool String::hasPrefix(const String &x) const {
80 	return hasPrefix(x.c_str());
81 }
82 
hasPrefix(const char * x) const83 bool String::hasPrefix(const char *x) const {
84 	assert(x != nullptr);
85 	// Compare x with the start of _str.
86 	const char *y = c_str();
87 	while (*x && *x == *y) {
88 		++x;
89 		++y;
90 	}
91 	// It's a prefix, if and only if all letters in x are 'used up' before
92 	// _str ends.
93 	return *x == 0;
94 }
95 
hasPrefixIgnoreCase(const String & x) const96 bool String::hasPrefixIgnoreCase(const String &x) const {
97 	return hasPrefixIgnoreCase(x.c_str());
98 }
99 
hasPrefixIgnoreCase(const char * x) const100 bool String::hasPrefixIgnoreCase(const char *x) const {
101 	assert(x != nullptr);
102 	// Compare x with the start of _str.
103 	const char *y = c_str();
104 	while (*x && tolower(*x) == tolower(*y)) {
105 		++x;
106 		++y;
107 	}
108 	// It's a prefix, if and only if all letters in x are 'used up' before
109 	// _str ends.
110 	return *x == 0;
111 }
112 
hasSuffix(const String & x) const113 bool String::hasSuffix(const String &x) const {
114 	return hasSuffix(x.c_str());
115 }
116 
hasSuffix(const char * x) const117 bool String::hasSuffix(const char *x) const {
118 	assert(x != nullptr);
119 	// Compare x with the end of _str.
120 	const uint32 x_size = strlen(x);
121 	if (x_size > _size)
122 		return false;
123 	const char *y = c_str() + _size - x_size;
124 	while (*x && *x == *y) {
125 		++x;
126 		++y;
127 	}
128 	// It's a suffix, if and only if all letters in x are 'used up' before
129 	// _str ends.
130 	return *x == 0;
131 }
132 
hasSuffixIgnoreCase(const String & x) const133 bool String::hasSuffixIgnoreCase(const String &x) const {
134 	return hasSuffixIgnoreCase(x.c_str());
135 }
136 
hasSuffixIgnoreCase(const char * x) const137 bool String::hasSuffixIgnoreCase(const char *x) const {
138 	assert(x != nullptr);
139 	// Compare x with the end of _str.
140 	const uint32 x_size = strlen(x);
141 	if (x_size > _size)
142 		return false;
143 	const char *y = c_str() + _size - x_size;
144 	while (*x && tolower(*x) == tolower(*y)) {
145 		++x;
146 		++y;
147 	}
148 	// It's a suffix, if and only if all letters in x are 'used up' before
149 	// _str ends.
150 	return *x == 0;
151 }
152 
contains(const String & x) const153 bool String::contains(const String &x) const {
154 	return strstr(c_str(), x.c_str()) != nullptr;
155 }
156 
contains(const char * x) const157 bool String::contains(const char *x) const {
158 	assert(x != nullptr);
159 	return strstr(c_str(), x) != nullptr;
160 }
161 
contains(char x) const162 bool String::contains(char x) const {
163 	return strchr(c_str(), x) != nullptr;
164 }
165 
contains(uint32 x) const166 bool String::contains(uint32 x) const {
167 	for (String::const_iterator itr = begin(); itr != end(); itr++) {
168 		if (uint32(*itr) == x) {
169 			return true;
170 		}
171 	}
172 	return false;
173 }
174 
175 #ifdef USE_CXX11
contains(char32_t x) const176 bool String::contains(char32_t x) const {
177 	return contains((uint32)x);
178 }
179 #endif
180 
181 #ifndef SCUMMVM_UTIL
182 
matchString(const char * pat,bool ignoreCase,const char * wildcardExclusions) const183 bool String::matchString(const char *pat, bool ignoreCase, const char *wildcardExclusions) const {
184 	return Common::matchString(c_str(), pat, ignoreCase, wildcardExclusions);
185 }
186 
matchString(const String & pat,bool ignoreCase,const char * wildcardExclusions) const187 bool String::matchString(const String &pat, bool ignoreCase, const char *wildcardExclusions) const {
188 	return Common::matchString(c_str(), pat.c_str(), ignoreCase, wildcardExclusions);
189 }
190 
191 #endif
192 
replace(uint32 pos,uint32 count,const String & str)193 void String::replace(uint32 pos, uint32 count, const String &str) {
194 	replace(pos, count, str, 0, str._size);
195 }
196 
replace(uint32 pos,uint32 count,const char * str)197 void String::replace(uint32 pos, uint32 count, const char *str) {
198 	replace(pos, count, str, 0, strlen(str));
199 }
200 
replace(iterator begin_,iterator end_,const String & str)201 void String::replace(iterator begin_, iterator end_, const String &str) {
202 	replace(begin_ - _str, end_ - begin_, str._str, 0, str._size);
203 }
204 
replace(iterator begin_,iterator end_,const char * str)205 void String::replace(iterator begin_, iterator end_, const char *str) {
206 	replace(begin_ - _str, end_ - begin_, str, 0, strlen(str));
207 }
208 
replace(uint32 posOri,uint32 countOri,const String & str,uint32 posDest,uint32 countDest)209 void String::replace(uint32 posOri, uint32 countOri, const String &str,
210 					 uint32 posDest, uint32 countDest) {
211 	replace(posOri, countOri, str._str, posDest, countDest);
212 }
213 
replace(uint32 posOri,uint32 countOri,const char * str,uint32 posDest,uint32 countDest)214 void String::replace(uint32 posOri, uint32 countOri, const char *str,
215 					 uint32 posDest, uint32 countDest) {
216 
217 	// Prepare string for the replaced text.
218 	if (countOri < countDest) {
219 		uint32 offset = countDest - countOri; ///< Offset to copy the characters
220 		uint32 newSize = _size + offset;
221 
222 		ensureCapacity(newSize, true);
223 
224 		_size = newSize;
225 
226 		// Push the old characters to the end of the string
227 		for (uint32 i = _size; i >= posOri + countDest; i--)
228 			_str[i] = _str[i - offset];
229 
230 	} else if (countOri > countDest){
231 		uint32 offset = countOri - countDest; ///< Number of positions that we have to pull back
232 
233 		makeUnique();
234 
235 		// Pull the remainder string back
236 		for (uint32 i = posOri + countDest; i + offset <= _size; i++)
237 			_str[i] = _str[i + offset];
238 
239 		_size -= offset;
240 	} else {
241 		makeUnique();
242 	}
243 
244 	// Copy the replaced part of the string
245 	for (uint32 i = 0; i < countDest; i++)
246 		_str[posOri + i] = str[posDest + i];
247 
248 }
249 
250 // static
format(const char * fmt,...)251 String String::format(const char *fmt, ...) {
252 	String output;
253 
254 	va_list va;
255 	va_start(va, fmt);
256 	output = String::vformat(fmt, va);
257 	va_end(va);
258 
259 	return output;
260 }
261 
262 // static
vformat(const char * fmt,va_list args)263 String String::vformat(const char *fmt, va_list args) {
264 	String output;
265 	assert(output.isStorageIntern());
266 
267 	va_list va;
268 	scumm_va_copy(va, args);
269 	int len = vsnprintf(output._str, _builtinCapacity, fmt, va);
270 	va_end(va);
271 
272 	if (len == -1 || len == _builtinCapacity - 1) {
273 		// MSVC and IRIX don't return the size the full string would take up.
274 		// MSVC returns -1, IRIX returns the number of characters actually written,
275 		// which is at the most the size of the buffer minus one, as the string is
276 		// truncated to fit.
277 
278 		// We assume MSVC failed to output the correct, null-terminated string
279 		// if the return value is either -1 or size.
280 		// For IRIX, because we lack a better mechanism, we assume failure
281 		// if the return value equals size - 1.
282 		// The downside to this is that whenever we try to format a string where the
283 		// size is 1 below the built-in capacity, the size is needlessly increased.
284 
285 		// Try increasing the size of the string until it fits.
286 		int size = _builtinCapacity;
287 		do {
288 			size *= 2;
289 			output.ensureCapacity(size - 1, false);
290 			assert(!output.isStorageIntern());
291 			size = output._extern._capacity;
292 
293 			scumm_va_copy(va, args);
294 			len = vsnprintf(output._str, size, fmt, va);
295 			va_end(va);
296 		} while (len == -1 || len >= size - 1);
297 		output._size = len;
298 	} else if (len < (int)_builtinCapacity) {
299 		// vsnprintf succeeded
300 		output._size = len;
301 	} else {
302 		// vsnprintf didn't have enough space, so grow buffer
303 		output.ensureCapacity(len, false);
304 		scumm_va_copy(va, args);
305 		int len2 = vsnprintf(output._str, len + 1, fmt, va);
306 		va_end(va);
307 		assert(len == len2);
308 		output._size = len2;
309 	}
310 
311 	return output;
312 }
313 
rfind(const char * s) const314 size_t String::rfind(const char *s) const {
315 	int sLen = strlen(s);
316 
317 	for (int idx = (int)_size - sLen; idx >= 0; --idx) {
318 		if (!strncmp(_str + idx, s, sLen))
319 			return idx;
320 	}
321 
322 	return npos;
323 }
324 
rfind(char c,size_t pos) const325 size_t String::rfind(char c, size_t pos) const {
326 	for (int idx = MIN((int)_size - 1, (int)pos); idx >= 0; --idx) {
327 		if ((*this)[idx] == c)
328 			return idx;
329 	}
330 
331 	return npos;
332 }
333 
findFirstOf(char c,size_t pos) const334 size_t String::findFirstOf(char c, size_t pos) const {
335 	const char *strP = (pos >= _size) ? 0 : strchr(_str + pos, c);
336 	return strP ? strP - _str : npos;
337 }
338 
findFirstOf(const char * chars,size_t pos) const339 size_t String::findFirstOf(const char *chars, size_t pos) const {
340 	for (uint idx = pos; idx < _size; ++idx) {
341 		if (strchr(chars, (*this)[idx]))
342 			return idx;
343 	}
344 
345 	return npos;
346 }
347 
findLastOf(char c,size_t pos) const348 size_t String::findLastOf(char c, size_t pos) const {
349 	int start = (pos == npos) ? (int)_size - 1 : MIN((int)_size - 1, (int)pos);
350 	for (int idx = start; idx >= 0; --idx) {
351 		if ((*this)[idx] == c)
352 			return idx;
353 	}
354 
355 	return npos;
356 }
357 
findLastOf(const char * chars,size_t pos) const358 size_t String::findLastOf(const char *chars, size_t pos) const {
359 	int start = (pos == npos) ? (int)_size - 1 : MIN((int)_size - 1, (int)pos);
360 	for (int idx = start; idx >= 0; --idx) {
361 		if (strchr(chars, (*this)[idx]))
362 			return idx;
363 	}
364 
365 	return npos;
366 }
367 
findFirstNotOf(char c,size_t pos) const368 size_t String::findFirstNotOf(char c, size_t pos) const {
369 	for (uint idx = pos; idx < _size; ++idx) {
370 		if ((*this)[idx] != c)
371 			return idx;
372 	}
373 
374 	return npos;
375 }
376 
findFirstNotOf(const char * chars,size_t pos) const377 size_t String::findFirstNotOf(const char *chars, size_t pos) const {
378 	for (uint idx = pos; idx < _size; ++idx) {
379 		if (!strchr(chars, (*this)[idx]))
380 			return idx;
381 	}
382 
383 	return npos;
384 }
385 
findLastNotOf(char c) const386 size_t String::findLastNotOf(char c) const {
387 	for (int idx = (int)_size - 1; idx >= 0; --idx) {
388 		if ((*this)[idx] != c)
389 			return idx;
390 	}
391 
392 	return npos;
393 }
394 
findLastNotOf(const char * chars) const395 size_t String::findLastNotOf(const char *chars) const {
396 	for (int idx = (int)_size - 1; idx >= 0; --idx) {
397 		if (!strchr(chars, (*this)[idx]))
398 			return idx;
399 	}
400 
401 	return npos;
402 }
403 
substr(size_t pos,size_t len) const404 String String::substr(size_t pos, size_t len) const {
405 	if (pos >= _size)
406 		return String();
407 	else if (len == npos)
408 		return String(_str + pos);
409 	else
410 		return String(_str + pos, MIN((size_t)_size - pos, len));
411 }
412 
forEachLine(String (* func)(const String,va_list args),...) const413 String String::forEachLine(String(*func)(const String, va_list args), ...) const {
414 	String result = "";
415 	size_t index = findFirstOf('\n', 0);
416 	size_t prev_index = 0;
417 	va_list args;
418 	va_start(args, func);
419 	while (index != npos) {
420 		String textLine = substr(prev_index, index - prev_index);
421 		textLine = (*func)(textLine, args);
422 		result = result + textLine + '\n';
423 		prev_index = index + 1;
424 		index = findFirstOf('\n', index + 1);
425 	}
426 
427 	String textLine = substr(prev_index);
428 	textLine = (*func)(textLine, args);
429 	result = result + textLine;
430 	va_end(args);
431 	return result;
432 }
433 
434 #pragma mark -
435 
operator ==(const char * y,const String & x)436 bool operator==(const char* y, const String &x) {
437 	return (x == y);
438 }
439 
operator !=(const char * y,const String & x)440 bool operator!=(const char* y, const String &x) {
441 	return x != y;
442 }
443 
444 #pragma mark -
445 
equalsIgnoreCase(const String & x) const446 bool String::equalsIgnoreCase(const String &x) const {
447 	return (0 == compareToIgnoreCase(x));
448 }
449 
equalsIgnoreCase(const char * x) const450 bool String::equalsIgnoreCase(const char *x) const {
451 	assert(x != nullptr);
452 	return (0 == compareToIgnoreCase(x));
453 }
454 
compareToIgnoreCase(const String & x) const455 int String::compareToIgnoreCase(const String &x) const {
456 	return compareToIgnoreCase(x.c_str());
457 }
458 
compareToIgnoreCase(const char * x) const459 int String::compareToIgnoreCase(const char *x) const {
460 	assert(x != nullptr);
461 	return scumm_stricmp(c_str(), x);
462 }
463 
compareDictionary(const String & x) const464 int String::compareDictionary(const String &x) const {
465 	return compareDictionary(x.c_str());
466 }
467 
compareDictionary(const char * x) const468 int String::compareDictionary(const char *x) const {
469 	assert(x != nullptr);
470 	return scumm_compareDictionary(c_str(), x);
471 }
472 
473 #pragma mark -
474 
operator +(const String & x,const String & y)475 String operator+(const String &x, const String &y) {
476 	String temp(x);
477 	temp += y;
478 	return temp;
479 }
480 
operator +(const char * x,const String & y)481 String operator+(const char *x, const String &y) {
482 	String temp(x);
483 	temp += y;
484 	return temp;
485 }
486 
operator +(const String & x,const char * y)487 String operator+(const String &x, const char *y) {
488 	String temp(x);
489 	temp += y;
490 	return temp;
491 }
492 
operator +(char x,const String & y)493 String operator+(char x, const String &y) {
494 	String temp(x);
495 	temp += y;
496 	return temp;
497 }
498 
operator +(const String & x,char y)499 String operator+(const String &x, char y) {
500 	String temp(x);
501 	temp += y;
502 	return temp;
503 }
504 
505 #ifndef SCUMMVM_UTIL
506 
ltrim(char * t)507 char *ltrim(char *t) {
508 	while (isSpace(*t))
509 		t++;
510 	return t;
511 }
512 
rtrim(char * t)513 char *rtrim(char *t) {
514 	int l = strlen(t) - 1;
515 	while (l >= 0 && isSpace(t[l]))
516 		t[l--] = 0;
517 	return t;
518 }
519 
trim(char * t)520 char *trim(char *t) {
521 	return rtrim(ltrim(t));
522 }
523 
524 #endif
525 
lastPathComponent(const String & path,const char sep)526 String lastPathComponent(const String &path, const char sep) {
527 	const char *str = path.c_str();
528 	const char *last = str + path.size();
529 
530 	// Skip over trailing slashes
531 	while (last > str && *(last - 1) == sep)
532 		--last;
533 
534 	// Path consisted of only slashes -> return empty string
535 	if (last == str)
536 		return String();
537 
538 	// Now scan the whole component
539 	const char *first = last - 1;
540 	while (first > str && *first != sep)
541 		--first;
542 
543 	if (*first == sep)
544 		first++;
545 
546 	return String(first, last);
547 }
548 
normalizePath(const String & path,const char sep)549 String normalizePath(const String &path, const char sep) {
550 	if (path.empty())
551 		return path;
552 
553 	const char *cur = path.c_str();
554 	String result;
555 
556 	// If there is a leading slash, preserve that:
557 	if (*cur == sep) {
558 		result += sep;
559 		// Skip over multiple leading slashes, so "//" equals "/"
560 		while (*cur == sep)
561 			++cur;
562 	}
563 
564 	// Scan for path components till the end of the String
565 	List<String> comps;
566 	while (*cur != 0) {
567 		const char *start = cur;
568 
569 		// Scan till the next path separator resp. the end of the string
570 		while (*cur != sep && *cur != 0)
571 			cur++;
572 
573 		const String component(start, cur);
574 
575 		if (component.empty() || component == ".") {
576 			// Skip empty components and dot components
577 		} else if (!comps.empty() && component == ".." && comps.back() != "..") {
578 			// If stack is non-empty and top is not "..", remove top
579 			comps.pop_back();
580 		} else {
581 			// Add the component to the stack
582 			comps.push_back(component);
583 		}
584 
585 		// Skip over separator chars
586 		while (*cur == sep)
587 			cur++;
588 	}
589 
590 	// Finally, assemble all components back into a path
591 	while (!comps.empty()) {
592 		result += comps.front();
593 		comps.pop_front();
594 		if (!comps.empty())
595 			result += sep;
596 	}
597 
598 	return result;
599 }
600 
601 #ifndef SCUMMVM_UTIL
602 
matchString(const char * str,const char * pat,bool ignoreCase,const char * wildcardExclusions)603 bool matchString(const char *str, const char *pat, bool ignoreCase, const char *wildcardExclusions) {
604 	assert(str);
605 	assert(pat);
606 
607 	const char *p = nullptr;
608 	const char *q = nullptr;
609 	bool escaped = false;
610 
611 	for (;;) {
612 		if (wildcardExclusions && strchr(wildcardExclusions, *str)) {
613 			p = nullptr;
614 			q = nullptr;
615 			if (*pat == '?')
616 				return false;
617 		}
618 
619 		const char curPat = *pat;
620 		switch (*pat) {
621 		case '*':
622 			if (*str) {
623 				// Record pattern / string position for backtracking
624 				p = ++pat;
625 				q = str;
626 			} else {
627 				// If we've reached the end of str, we can't backtrack further
628 				// NB: We can't simply check if pat also ended here, because
629 				// the pattern might end with any number of *s.
630 				++pat;
631 				p = nullptr;
632 				q = nullptr;
633 			}
634 			// If pattern ended with * -> match
635 			if (!*pat)
636 				return true;
637 			break;
638 
639 		case '\\':
640 			if (!escaped) {
641 				pat++;
642 				break;
643 			}
644 			// fallthrough
645 
646 		case '#':
647 			// treat # as a wildcard for digits unless escaped
648 			if (!escaped) {
649 				if (!isDigit(*str))
650 					return false;
651 				pat++;
652 				str++;
653 				break;
654 			}
655 			// fallthrough
656 
657 		default:
658 			if ((!ignoreCase && *pat != *str) ||
659 				(ignoreCase && tolower(*pat) != tolower(*str))) {
660 				if (p) {
661 					// No match, oops -> try to backtrack
662 					pat = p;
663 					str = ++q;
664 					if (!*str)
665 						return !*pat;
666 					break;
667 				}
668 				else
669 					return false;
670 			}
671 			// fallthrough
672 		case '?':
673 			if (!*str)
674 				return !*pat;
675 			pat++;
676 			str++;
677 		}
678 
679 		escaped = !escaped && (curPat == '\\');
680 	}
681 }
682 
replace(Common::String & source,const Common::String & what,const Common::String & with)683 void replace(Common::String &source, const Common::String &what, const Common::String &with) {
684 	const char *cstr = source.c_str();
685 	const char *position = strstr(cstr, what.c_str());
686 	if (position) {
687 		uint32 index = position - cstr;
688 		source.replace(index, what.size(), with);
689 	}
690 }
691 
tag2string(uint32 tag,bool nonPrintable)692 String tag2string(uint32 tag, bool nonPrintable) {
693 	Common::String res;
694 
695 	for (int i = 3; i >= 0; i--) {
696 		byte b = (tag >> (8 * i)) & 0xff;
697 
698 		if (!Common::isPrint(b)) {
699 			if (nonPrintable) {
700 				res += Common::String::format("\\%03o", b);
701 			} else {
702 				res += '.';
703 			}
704 		} else {
705 			res += b;
706 		}
707 	}
708 
709 	return res;
710 }
711 
712 #endif
713 
strlcpy(char * dst,const char * src,size_t size)714 size_t strlcpy(char *dst, const char *src, size_t size) {
715 	// Our backup of the source's start, we need this
716 	// to calculate the source's length.
717 	const char * const srcStart = src;
718 
719 	// In case a non-empty size was specified we
720 	// copy over (size - 1) bytes at max.
721 	if (size != 0) {
722 		// Copy over (size - 1) bytes at max.
723 		while (--size != 0) {
724 			if ((*dst++ = *src) == 0)
725 				break;
726 			++src;
727 		}
728 
729 		// In case the source string was longer than the
730 		// destination, we need to add a terminating
731 		// zero.
732 		if (size == 0)
733 			*dst = 0;
734 	}
735 
736 	// Move to the terminating zero of the source
737 	// string, we need this to determine the length
738 	// of the source string.
739 	while (*src)
740 		++src;
741 
742 	// Return the source string's length.
743 	return src - srcStart;
744 }
745 
strlcat(char * dst,const char * src,size_t size)746 size_t strlcat(char *dst, const char *src, size_t size) {
747 	// In case the destination buffer does not contain
748 	// space for at least 1 character, we will just
749 	// return the source string's length.
750 	if (size == 0)
751 		return strlen(src);
752 
753 	// Our backup of the source's start, we need this
754 	// to calculate the source's length.
755 	const char * const srcStart = src;
756 
757 	// Our backup of the destination's start, we need
758 	// this to calculate the destination's length.
759 	const char * const dstStart = dst;
760 
761 	// Search the end of the destination, but do not
762 	// move past the terminating zero.
763 	while (size-- != 0 && *dst != 0)
764 		++dst;
765 
766 	// Calculate the destination's length;
767 	const size_t dstLength = dst - dstStart;
768 
769 	// In case we reached the end of the destination
770 	// buffer before we had a chance to append any
771 	// characters we will just return the destination
772 	// length plus the source string's length.
773 	if (size == 0)
774 		return dstLength + strlen(srcStart);
775 
776 	// Copy over all of the source that fits
777 	// the destination buffer. We also need
778 	// to take the terminating zero we will
779 	// add into consideration.
780 	while (size-- != 0 && *src != 0)
781 		*dst++ = *src++;
782 	*dst = 0;
783 
784 	// Move to the terminating zero of the source
785 	// string, we need this to determine the length
786 	// of the source string.
787 	while (*src)
788 		++src;
789 
790 	// Return the total length of the result string
791 	return dstLength + (src - srcStart);
792 }
793 
strnlen(const char * src,size_t maxSize)794 size_t strnlen(const char *src, size_t maxSize) {
795 	size_t counter = 0;
796 	while (counter != maxSize && *src++)
797 		++counter;
798 	return counter;
799 }
800 
toPrintable(const String & in,bool keepNewLines)801 String toPrintable(const String &in, bool keepNewLines) {
802 	Common::String res;
803 
804 	const char *tr = "\x01\x01\x02\x03\x04\x05\x06" "a"
805 				  //"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
806 					   "b" "t" "n" "v" "f" "r\x0e\x0f"
807 					"\x10\x11\x12\x13\x14\x15\x16\x17"
808 					"\x18\x19\x1a" "e\x1c\x1d\x1e\x1f";
809 
810 	for (const byte *p = (const byte *)in.c_str(); *p; p++) {
811 		if (*p == '\n') {
812 			if (keepNewLines)
813 				res += *p;
814 			else
815 				res += "\\n";
816 
817 			continue;
818 		}
819 
820 		if (*p < 0x20 || *p == '\'' || *p == '\"' || *p == '\\') {
821 			res += '\\';
822 
823 			if (*p < 0x20) {
824 				if (tr[*p] < 0x20)
825 					res += Common::String::format("x%02x", *p);
826 				else
827 					res += tr[*p];
828 			} else {
829 				res += *p;	// We will escape it
830 			}
831 		} else if (*p > 0x7e) {
832 			res += Common::String::format("\\x%02x", *p);
833 		} else
834 			res += *p;
835 	}
836 
837 	return res;
838 }
839 
840 } // End of namespace Common
841 
842 // Portable implementation of stricmp / strcasecmp / strcmpi.
843 // TODO: Rename this to Common::strcasecmp
scumm_stricmp(const char * s1,const char * s2)844 int scumm_stricmp(const char *s1, const char *s2) {
845 	byte l1, l2;
846 	do {
847 		// Don't use ++ inside tolower, in case the macro uses its
848 		// arguments more than once.
849 		l1 = (byte)*s1++;
850 		l1 = tolower(l1);
851 		l2 = (byte)*s2++;
852 		l2 = tolower(l2);
853 	} while (l1 == l2 && l1 != 0);
854 	return l1 - l2;
855 }
856 
857 // Portable implementation of strnicmp / strncasecmp / strncmpi.
858 // TODO: Rename this to Common::strncasecmp
scumm_strnicmp(const char * s1,const char * s2,uint n)859 int scumm_strnicmp(const char *s1, const char *s2, uint n) {
860 	byte l1, l2;
861 	do {
862 		if (n-- == 0)
863 			return 0; // no difference found so far -> signal equality
864 
865 		// Don't use ++ inside tolower, in case the macro uses its
866 		// arguments more than once.
867 		l1 = (byte)*s1++;
868 		l1 = tolower(l1);
869 		l2 = (byte)*s2++;
870 		l2 = tolower(l2);
871 	} while (l1 == l2 && l1 != 0);
872 	return l1 - l2;
873 }
874 
scumm_skipArticle(const char * s1)875 const char *scumm_skipArticle(const char *s1) {
876 	int o1 = 0;
877 	if (!scumm_strnicmp(s1, "the ", 4))
878 		o1 = 4;
879 	else if (!scumm_strnicmp(s1, "a ", 2))
880 		o1 = 2;
881 	else if (!scumm_strnicmp(s1, "an ", 3))
882 		o1 = 3;
883 
884 	return &s1[o1];
885 }
886 
scumm_compareDictionary(const char * s1,const char * s2)887 int scumm_compareDictionary(const char *s1, const char *s2) {
888 	return scumm_stricmp(scumm_skipArticle(s1), scumm_skipArticle(s2));
889 }
890 
891 //  Portable implementation of strdup.
scumm_strdup(const char * in)892 char *scumm_strdup(const char *in) {
893 	const size_t len = strlen(in) + 1;
894 	char *out = (char *)malloc(len);
895 	if (out) {
896 		strcpy(out, in);
897 	}
898 	return out;
899 }
900 
901 //  Portable implementation of strcasestr.
scumm_strcasestr(const char * s,const char * find)902 const char *scumm_strcasestr(const char *s, const char *find) {
903 	char c, sc;
904 	size_t len;
905 
906 	if ((c = *find++) != 0) {
907 		c = (char)tolower((unsigned char)c);
908 		len = strlen(find);
909 		do {
910 			do {
911 				if ((sc = *s++) == 0)
912 					return (NULL);
913 			} while ((char)tolower((unsigned char)sc) != c);
914 		} while (scumm_strnicmp(s, find, len) != 0);
915 		s--;
916 	}
917 	return s;
918 }
919