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