1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/common/px_common.h"
29 #include "engines/icb/common/px_string.h"
30 
31 #include "common/textconsole.h"
32 
33 namespace ICB {
34 
35 #define SLEN_CHECK (slen < 0)
36 
operator =(const char * str)37 const char *pxString::operator=(const char *str) {
38 	// Assign a value
39 
40 	// If we are assigning the string to ourself, then no assignment is necessary
41 	if (str == s)
42 		return (s);
43 
44 	if (s)
45 		delete[] s;
46 	if (str) {
47 		// We are not assigning a null string
48 		uint32 len = strlen(const_cast<char *>(str)) + 1;
49 		s = new char[len];
50 		memcpy((unsigned char *)s, (unsigned char *)const_cast<char *>(str), len);
51 	} else
52 		s = NULL; // Just the null string
53 	return (s);
54 }
55 
operator =(const pxString & str)56 void pxString::operator=(const pxString &str) {
57 	// Assign a value
58 	if (s)
59 		delete[] s;
60 	if (str.s) {
61 		// We are not assigning a null string
62 		uint32 len = strlen((char *)(str.s)) + 1;
63 		s = new char[len];
64 		memcpy((unsigned char *)s, (unsigned char *)str.s, len);
65 	} else
66 		s = NULL; // Null string
67 }
68 
operator +=(const char * adder)69 const char *pxString::operator+=(const char *adder) {
70 	// Add a string
71 
72 	if (adder) {
73 		uint32 slen = s ? strlen(s) : 0;             // Get original string length
74 		uint32 adderlen = strlen(const_cast<char *>(adder));     // Get additional string length
75 		char *buf = new char[slen + adderlen + 1]; // Create a buffer
76 		if (s)
77 			memcpy((unsigned char *)buf, (unsigned char *)s, slen); // Move the original string in
78 
79 		memcpy((unsigned char *)buf + slen, (unsigned char *)const_cast<char *>(adder), adderlen + 1); // And put the additional string in
80 
81 		// Tidy up
82 		delete[] s;
83 		s = buf;
84 	}
85 
86 	return (s);
87 }
88 
operator +(const char * adder) const89 const pxString pxString::operator+(const char *adder) const {
90 	// Produce a string addition without affecting this object
91 
92 	pxString temp(s);
93 	temp += adder;
94 	return (temp);
95 }
96 
operator ==(const char * string) const97 bool pxString::operator==(const char *string) const {
98 	// Do a character by character comparison
99 	if (s == NULL)
100 		return ((bool)(string == NULL));
101 	if (string == NULL)
102 		return (false);
103 	return ((bool)(strcmp(s, const_cast<char *>(string)) == 0));
104 }
105 
SetString(const char * data,uint32 len)106 void pxString::SetString(const char *data, uint32 len) {
107 	// Get the first len characters from another string
108 
109 	// Lose any string we currently hold
110 	if (s)
111 		delete[] s;
112 
113 	// If the data is NULL then we become NULL
114 	if (data) {
115 		// Copy in the data
116 		s = new char[len + 1];
117 		memcpy((unsigned char *)s, (unsigned char *)const_cast<char *>(data), len);
118 		// And null terminate it
119 		s[len] = 0;
120 	} else
121 		s = NULL;
122 }
123 
Substr(pxString & rsStr,uint32 nStart,uint32 nNum) const124 void pxString::Substr(pxString &rsStr, uint32 nStart, uint32 nNum) const {
125 	char *pNewString;
126 	uint32 slen = strlen(s); // ds: No need to calculate this several times
127 
128 	// Do some range checking.
129 	if (nStart > (slen - 1)) {
130 		rsStr = "";
131 		return;
132 	}
133 
134 	// If the requested substring goes past the end of the existing string, simply clip it
135 	// after the last character in the existing one.
136 	if (nStart + nNum > slen)
137 		nNum -= (nStart + nNum) - slen;
138 
139 	// Create a buffer the correct size to hold the new substring
140 	pNewString = new char[nNum + 1];
141 
142 	// Copy in the substring.
143 	memcpy((unsigned char *)pNewString, (unsigned char *)&s[nStart], nNum);
144 
145 	// Put the terminator on.
146 	pNewString[nNum] = '\0';
147 
148 	// Make the new pxString from the buffer.
149 	rsStr = pNewString;
150 
151 	// ds: Deallocate the temporary buffer
152 	delete[] pNewString;
153 }
154 
StrChr(char cToFind,uint32 nStartPos) const155 uint32 pxString::StrChr(char cToFind, uint32 nStartPos) const {
156 	char *pcPositionOfFirst;
157 	uint32 nStringLength = strlen(s);
158 
159 	// Check if the start position is outside the string.
160 	if (nStartPos >= nStringLength)
161 		return nStringLength;
162 
163 	// I use strchr, which relies on the pxString being implemented as a character array,
164 	// but it is OK to do it in here, 'cos if the internal representation changed, presumably
165 	// every function in this class would need looking at anyway.
166 	pcPositionOfFirst = strchr(s + nStartPos, static_cast<uint>(cToFind));
167 
168 	if (pcPositionOfFirst) {
169 		// Character was found.  Work out its index from the address.
170 		return (pcPositionOfFirst - s);
171 	} else {
172 		// I use the length of the string as a rogue value to indicate the character wasn't found.
173 		return nStringLength;
174 	}
175 }
176 
ToUpper()177 void pxString::ToUpper() {
178 	if (s) {
179 		char *sp = s;
180 		while (*sp) {
181 			*sp = (char)toupper(*sp);
182 			sp++;
183 		}
184 	}
185 }
186 
ToLower()187 void pxString::ToLower() {
188 	if (s) {
189 		char *sp = s;
190 		while (*sp) {
191 			*sp = (char)tolower(*sp);
192 			sp++;
193 		}
194 	}
195 }
196 
ConvertPath()197 void pxString::ConvertPath() {
198 	if (s) {
199 		char *sp = s;
200 		while (*sp) {
201 			*sp = (*sp == '\\' ? '/' : *sp);
202 			sp++;
203 		}
204 		// trim '/'
205 		if (*s == '/') {
206 			uint32 len = strlen((char *)s);
207 			sp = new char[len];
208 			memcpy((unsigned char *)sp, (unsigned char *)(s + 1), len);
209 			delete[] s;
210 			s = sp;
211 		}
212 	}
213 }
214 
Format(const char * format,...)215 const pxString &pxString::Format(const char *format, ...) {
216 	if (s)
217 		delete[] s;
218 	s = NULL;
219 
220 	// Check for a null parameter
221 	if (format == NULL)
222 		return (*this);
223 
224 	// The data could be any size. Rather than incrementally allocating memory until
225 	// it fits a large buffer multiple is used that should cover 99.9% of all strings
226 	// but will still cope with unfeasably large ones
227 	uint32 startBufferSize = 1024;
228 
229 	// Allocate a start buffer
230 	s = new char[startBufferSize + 2];
231 	if (s == NULL)
232 		return (*this);
233 
234 	// Process the variable arguments
235 	va_list arglist;
236 	int32 slen;
237 
238 	// Keep doubling the size of the buffer until it fits
239 	while (va_start(arglist, format), slen = vsnprintf(s, startBufferSize, const_cast<char *>(format), arglist), SLEN_CHECK) {
240 		delete[] s;
241 
242 		startBufferSize += startBufferSize;
243 		s = new char[startBufferSize + 2];
244 
245 		// According to VC5 release mode this code is unreachable
246 		// I can't see why, so I shall turn the warning off for this bit of code
247 
248 		// If the sllocation failed return an empty string
249 		if (s == NULL)
250 			return (*this);
251 	}
252 
253 	// Tidy up and finish
254 	va_end(arglist);
255 
256 	// At this point the buffer in s is much larger than it needs to be
257 	// In the interest of saving space, it will now be reduced
258 	assert(slen == (int32)strlen(s));
259 	char *tempBuffer = new char[slen + 1];
260 
261 	// If this allocation fails leave the string as it is
262 	if (tempBuffer) {
263 		memcpy((unsigned char *)tempBuffer, (unsigned char *)s, slen + 1);
264 		delete[] s;
265 		s = tempBuffer;
266 	}
267 
268 	return (*this);
269 }
270 
271 // build a temporary string
pxVString(const char * format,...)272 const char *pxVString(const char *format, ...) {
273 #define PXV_BUF_SIZE 1024
274 
275 	static char buf[PXV_BUF_SIZE];
276 	va_list va;
277 
278 	va_start(va, format);
279 	vsnprintf(buf, PXV_BUF_SIZE, format, va);
280 	va_end(va);
281 
282 #undef PXV_BUF_SIZE
283 
284 	return buf;
285 }
286 
pxFixedCharBuffer(uint32 len)287 pxFixedCharBuffer::pxFixedCharBuffer(uint32 len) {
288 	// Construct the object with the appropriate amount of data
289 	m_data = new char[len];
290 
291 	// Check for an error
292 	if (m_data == NULL) {
293 		error("pxFixedCharBuffer memory allocation error");
294 	}
295 }
296 
pxFlexiCharBuffer(uint32 initLen)297 pxFlexiCharBuffer::pxFlexiCharBuffer(uint32 initLen) {
298 	m_bufLen = initLen;
299 
300 	m_buffer = new char[initLen]; // The buffer itself
301 }
302 
~pxFlexiCharBuffer()303 pxFlexiCharBuffer::~pxFlexiCharBuffer() { delete[] m_buffer; }
304 
operator [](uint32 offset)305 char &pxFlexiCharBuffer::operator[](uint32 offset) {
306 	CheckSize(offset);
307 	return (m_buffer[offset]);
308 }
309 
CheckSize(uint32 size)310 void pxFlexiCharBuffer::CheckSize(uint32 size) {
311 	// Make sure we have enough room
312 
313 	if (size >= m_bufLen) {
314 		uint32 newLen = size + 1;
315 		char *newb = new char[newLen];
316 		assert(newb);
317 		memcpy((unsigned char *)newb, (unsigned char *)m_buffer, m_bufLen);
318 		delete[] m_buffer;
319 		m_buffer = newb;
320 		m_bufLen = newLen;
321 	}
322 }
323 
StrCpy(uint32 offset,const char * string)324 void pxFlexiCharBuffer::StrCpy(uint32 offset, const char *string) {
325 	// Add a string
326 	uint32 slen = strlen(const_cast<char *>(string));
327 	CheckSize(offset + slen);
328 	memcpy((unsigned char *)(m_buffer + offset), (unsigned char *)const_cast<char *>(string), slen);
329 }
330 
StrnCpy(uint32 offset,const char * string,uint32 len)331 void pxFlexiCharBuffer::StrnCpy(uint32 offset, const char *string, uint32 len) {
332 	// Copy a number of characters to the buffer
333 	CheckSize(offset + len);
334 	memcpy((unsigned char *)(m_buffer + offset), (unsigned char *)const_cast<char *>(string), len);
335 }
336 
337 } // End of namespace ICB
338