xoreos  0.0.5
strutil.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos 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 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos 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 xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cctype>
26 #include <climits>
27 #include <cerrno>
28 #include <cstdlib>
29 #include <cstdio>
30 #include <cstring>
31 
32 #include "src/common/system.h"
33 #include "src/common/strutil.h"
34 #include "src/common/util.h"
35 #include "src/common/error.h"
36 #include "src/common/ustring.h"
37 #include "src/common/scopedptr.h"
39 
40 namespace Common {
41 
42 void printDataHex(SeekableReadStream &stream, size_t size) {
43  size_t pos = stream.pos();
44 
45  size = MIN<size_t>(stream.size() - pos, size);
46 
47  if (size == 0)
48  return;
49 
50  uint32 offset = 0;
51  byte rowData[16];
52 
53  while (size > 0) {
54  // At max 16 bytes printed per row
55  uint32 n = MIN<size_t>(size, 16);
56  if (stream.read(rowData, n) != n)
57  throw Exception(kReadError);
58 
59  // Print an offset
60  std::fprintf(stderr, "%08X ", offset);
61 
62  // 2 "blobs" of each 8 bytes per row
63  for (uint32 i = 0; i < 2; i++) {
64  for (uint32 j = 0; j < 8; j++) {
65  uint32 m = i * 8 + j;
66 
67  if (m < n)
68  // Print the data
69  std::fprintf(stderr, "%02X ", rowData[m]);
70  else
71  // Last row, data count not aligned to 16
72  std::fprintf(stderr, " ");
73  }
74 
75  // Separate the blobs by an extra space
76  std::fprintf(stderr, " ");
77  }
78 
79  std::fprintf(stderr, "|");
80 
81  // If the data byte is a printable character, print it. If not, substitute a '.'
82  for (uint32 i = 0; i < n; i++)
83  std::fprintf(stderr, "%c", std::isprint(rowData[i]) ? rowData[i] : '.');
84 
85  std::fprintf(stderr, "|\n");
86 
87  size -= n;
88  offset += n;
89  }
90 
91  // Seek back
92  stream.seek(pos);
93 }
94 
95 void printDataHex(const byte *data, size_t size) {
96  if (!data || (size == 0))
97  return;
98 
99  MemoryReadStream stream(data, size);
100  printDataHex(stream);
101 }
102 
103 static bool tagToString(uint32 tag, bool trim, UString &str) {
104  tag = TO_BE_32(tag);
105 
106  const char *tS = reinterpret_cast<const char *>(&tag);
107  if (!std::isprint(tS[0]) || !std::isprint(tS[1]) || !std::isprint(tS[2]) || !std::isprint(tS[3]))
108  return false;
109 
110  str = UString::format("%c%c%c%c", tS[0], tS[1], tS[2], tS[3]);
111  if (trim)
112  str.trim();
113 
114  return true;
115 }
116 
117 UString debugTag(uint32 tag, bool trim) {
118  UString str;
119  if (tagToString(tag, trim, str))
120  return UString::format("0x%08X ('%s')", FROM_BE_32(tag), str.c_str());
121 
122  return UString::format("0x%08X", FROM_BE_32(tag));
123 }
124 
125 // Helper functions for parseString()
126 
127 static void errorOnSign(const char *str) {
128  if (strchr(str, '-') != 0)
129  errno = ERANGE;
130 }
131 
132 static inline void parse(const char *nptr, char **endptr, signed long long &value) {
133  value = strtoll(nptr, endptr, 0);
134 }
135 
136 static inline void parse(const char *nptr, char **endptr, unsigned long long &value) {
137  errorOnSign(nptr);
138 
139  value = strtoull(nptr, endptr, 0);
140 }
141 
142 static inline void parse(const char *nptr, char **endptr, signed long &value) {
143  value = strtol(nptr, endptr, 0);
144 }
145 
146 static inline void parse(const char *nptr, char **endptr, unsigned long &value) {
147  errorOnSign(nptr);
148 
149  value = strtoul(nptr, endptr, 0);
150 }
151 
152 static inline void parse(const char *nptr, char **endptr, signed int &value) {
153  signed long tmp = strtol(nptr, endptr, 0);
154  if ((tmp < INT_MIN) || (tmp > INT_MAX))
155  errno = ERANGE;
156 
157  value = (signed int) tmp;
158 }
159 
160 static inline void parse(const char *nptr, char **endptr, unsigned int &value) {
161  errorOnSign(nptr);
162 
163  unsigned long tmp = strtoul(nptr, endptr, 0);
164  if (tmp > UINT_MAX)
165  errno = ERANGE;
166 
167  value = (unsigned int) tmp;
168 }
169 
170 static inline void parse(const char *nptr, char **endptr, signed short &value) {
171  signed long tmp = strtol(nptr, endptr, 0);
172  if ((tmp < SHRT_MIN) || (tmp > SHRT_MAX))
173  errno = ERANGE;
174 
175  value = (signed short) tmp;
176 }
177 
178 static inline void parse(const char *nptr, char **endptr, unsigned short &value) {
179  errorOnSign(nptr);
180 
181  unsigned long tmp = strtoul(nptr, endptr, 0);
182  if (tmp > USHRT_MAX)
183  errno = ERANGE;
184 
185  value = (unsigned short) tmp;
186 }
187 
188 static inline void parse(const char *nptr, char **endptr, signed char &value) {
189  signed long tmp = strtol(nptr, endptr, 0);
190  if ((tmp < SCHAR_MIN) || (tmp > SCHAR_MAX))
191  errno = ERANGE;
192 
193  value = (signed char) tmp;
194 }
195 
196 static inline void parse(const char *nptr, char **endptr, unsigned char &value) {
197  errorOnSign(nptr);
198 
199  unsigned long tmp = strtoul(nptr, endptr, 0);
200  if (tmp > UCHAR_MAX)
201  errno = ERANGE;
202 
203  value = (unsigned char) tmp;
204 }
205 
206 static inline void parse(const char *nptr, char **endptr, float &value) {
207  value = strtof(nptr, endptr);
208 }
209 
210 static inline void parse(const char *nptr, char **endptr, double &value) {
211  value = strtod(nptr, endptr);
212 }
213 
214 
215 template<typename T> void parseString(const UString &str, T &value, bool allowEmpty) {
216  if (str.empty()) {
217  if (allowEmpty)
218  return;
219 
220  throw Exception("Trying to parse an empty string");
221  }
222 
223  const char *nptr = str.c_str();
224  char *endptr = 0;
225 
226  errno = 0;
227 
228  T newValue;
229  parse(nptr, &endptr, newValue);
230 
231  while (endptr && isspace(*endptr))
232  endptr++;
233 
234  if (endptr && (*endptr != '\0'))
235  throw Exception("Can't convert \"%s\" to type of size %u", str.c_str(), (uint)sizeof(T));
236  if (errno == ERANGE)
237  throw Exception("\"%s\" out of range for type of size %u", str.c_str(), (uint)sizeof(T));
238 
239  value = newValue;
240 }
241 
242 template<> void parseString(const UString &str, bool &value, bool allowEmpty) {
243  if (str.empty()) {
244  if (allowEmpty)
245  return;
246 
247  throw Exception("Trying to parse an empty string");
248  }
249 
250  // Valid true values are "true", "yes", "y", "on" and "1"
251 
252  value =
253  (str.equalsIgnoreCase("true") ||
254  str.equalsIgnoreCase("yes") ||
255  str.equalsIgnoreCase("y") ||
256  str.equalsIgnoreCase("on") ||
257  str == "1") ?
258  true : false;
259 }
260 
261 template void parseString< signed char >(const UString &str, signed char &value, bool allowEmpty);
262 template void parseString<unsigned char >(const UString &str, unsigned char &value, bool allowEmpty);
263 template void parseString< signed short >(const UString &str, signed short &value, bool allowEmpty);
264 template void parseString<unsigned short >(const UString &str, unsigned short &value, bool allowEmpty);
265 template void parseString< signed int >(const UString &str, signed int &value, bool allowEmpty);
266 template void parseString<unsigned int >(const UString &str, unsigned int &value, bool allowEmpty);
267 template void parseString< signed long >(const UString &str, signed long &value, bool allowEmpty);
268 template void parseString<unsigned long >(const UString &str, unsigned long &value, bool allowEmpty);
269 template void parseString< signed long long>(const UString &str, signed long long &value, bool allowEmpty);
270 template void parseString<unsigned long long>(const UString &str, unsigned long long &value, bool allowEmpty);
271 
272 template void parseString<float >(const UString &str, float &value, bool allowEmpty);
273 template void parseString<double >(const UString &str, double &value, bool allowEmpty);
274 
275 
276 template<typename T> UString composeString(T value) {
277  /* Create a string representation of the value, in decimal notation.
278  *
279  * Build up the string digit by digit, least significant digit first
280  * (thus filling up the string back to front), by repeatedly dividing
281  * the value by 10.
282  */
283 
284  /* Remember whether the value is negative. We use that afterwards to
285  * prepend the negative sign. */
286  const bool isNegative = value < 0;
287 
288  /* Our string buffer and a pointer to the start of the string. We
289  * fill back to front, so it points at the end of the buffer now. */
290  char buf[64], *strStart = buf + sizeof(buf) - 1;
291 
292  /* Start by putting the final string terminator into the string. */
293  *strStart-- = '\0';
294 
295  /* Collect all the digits, back to front.
296  *
297  * Note that the value might be negative [1]. The sign of the result
298  * of the %-operator on negative numbers is implementation-defined,
299  * so we ABS() the result (0-9) back to positive.
300  *
301  * In UTF-8 (as well as ASCII, but we only care about UTF-8 here),
302  * the digits are continuous, so we can just add this remainder to
303  * '0' to get the UTF-8 codepoint for the digit in question.
304  *
305  * [1] We also don't just want to negate a negative number to make
306  * it positive: this would break with INT8_MIN, INT16_MIN, etc.,
307  * because -INT8_MIN (128) is not a valid int8_t value. */
308  do {
309  *strStart-- = ABS(value % 10) + '0';
310  } while ((value /= 10) && (strStart != buf));
311 
312  /* Sanity check; shouldn't happen because the buffer is big enough. */
313  if (strStart == buf)
314  throw Exception("Buffer overrun in composeString()");
315 
316  /* Write the sign, if the value was negative. */
317  if (isNegative)
318  *strStart-- = '-';
319 
320  /* We've moved one past the actual start of the string now. */
321  strStart++;
322 
323  return UString(strStart);
324 }
325 
326 template<> UString composeString(bool value) {
327  return value ? "true" : "false";
328 }
329 
330 template<> UString composeString(float value) {
331  return UString::format("%f", value);
332 }
333 
334 template<> UString composeString(double value) {
335  return UString::format("%lf", value);
336 }
337 
338 template UString composeString< signed char >( signed char value);
339 template UString composeString<unsigned char >(unsigned char value);
340 template UString composeString< signed short >( signed short value);
341 template UString composeString<unsigned short >(unsigned short value);
342 template UString composeString< signed int >( signed int value);
343 template UString composeString<unsigned int >(unsigned int value);
344 template UString composeString< signed long >( signed long value);
345 template UString composeString<unsigned long >(unsigned long value);
346 template UString composeString< signed long long>( signed long long value);
347 template UString composeString<unsigned long long>(unsigned long long value);
348 
349 size_t searchBackwards(SeekableReadStream &haystack, const byte *needle, size_t needleSize,
350  size_t maxReadBack) {
351 
352  if (needleSize == 0 || maxReadBack == 0)
353  return SIZE_MAX;
354 
355  assert(maxReadBack >= needleSize);
356 
357  static const size_t kReadBufferSize = 0x400;
358 
359  const size_t sizeFile = haystack.size();
360  const size_t maxBack = MIN<size_t>(maxReadBack, sizeFile);
361 
362  ScopedArray<byte> buf(new byte[kReadBufferSize + needleSize]);
363 
364  size_t backRead = needleSize;
365  while (backRead < maxBack) {
366  backRead = MIN<size_t>(maxBack, backRead + kReadBufferSize);
367 
368  const size_t readPos = sizeFile - backRead;
369  const size_t readSize = MIN<size_t>(kReadBufferSize + needleSize, sizeFile - readPos);
370 
371  try {
372  haystack.seek(readPos);
373  } catch (...) {
374  break;
375  }
376 
377  if (haystack.read(buf.get(), readSize) != readSize)
378  break;
379 
380  for (size_t i = (readSize - (needleSize - 1)); i-- > 0; )
381  if (!memcmp(buf.get() + i, needle, needleSize))
382  return readPos + i;
383  }
384 
385  return SIZE_MAX;
386 }
387 
388 } // End of namespace Common
#define strtof
Definition: system.h:185
T ABS(T x)
Definition: util.h:69
template void parseString< signed int >(const UString &str, signed int &value, bool allowEmpty)
Definition: 2dafile.h:39
template UString composeString< unsigned long >(unsigned long value)
A class holding an UTF-8 string.
Definition: ustring.h:48
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
template UString composeString< signed short >(signed short value)
UString composeString(T value)
Convert any POD integer, float/double or bool type into a string.
Definition: strutil.cpp:276
template void parseString< signed short >(const UString &str, signed short &value, bool allowEmpty)
bool equalsIgnoreCase(const UString &str) const
Definition: ustring.cpp:218
Implementing the reading stream interfaces for plain memory blocks.
template void parseString< unsigned long long >(const UString &str, unsigned long long &value, bool allowEmpty)
template void parseString< unsigned short >(const UString &str, unsigned short &value, bool allowEmpty)
template void parseString< unsigned long >(const UString &str, unsigned long &value, bool allowEmpty)
Utility templates and functions for working with strings and streams.
A simple scoped smart pointer template.
template void parseString< float >(const UString &str, float &value, bool allowEmpty)
Basic exceptions to throw.
template UString composeString< signed char >(signed char value)
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
size_t searchBackwards(SeekableReadStream &haystack, const byte *needle, size_t needleSize, size_t maxReadBack)
Search the stream, backwards, for the last occurrence of a set of bytes.
Definition: strutil.cpp:349
static UString format(const char *s,...) GCC_PRINTF(1
Print formatted data into an UString object, similar to sprintf().
Definition: ustring.cpp:718
#define strtoull
Definition: system.h:319
Utility templates and functions.
static bool tagToString(uint32 tag, bool trim, UString &str)
Definition: strutil.cpp:103
template UString composeString< signed long long >(signed long long value)
template void parseString< double >(const UString &str, double &value, bool allowEmpty)
virtual size_t read(void *dataPtr, size_t dataSize)=0
Read data from the stream.
Simple memory based &#39;stream&#39;, which implements the ReadStream interface for a plain memory block...
Definition: memreadstream.h:66
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
static void errorOnSign(const char *str)
Definition: strutil.cpp:127
template void parseString< signed char >(const UString &str, signed char &value, bool allowEmpty)
StackException Exception
Definition: error.h:59
const Exception kReadError("Read error")
Exception when reading from a stream failed.
Definition: error.h:62
virtual size_t size() const =0
Obtains the total size of the stream, measured in bytes.
static void parse(const char *nptr, char **endptr, signed long long &value)
Definition: strutil.cpp:132
virtual size_t pos() const =0
Obtains the current value of the stream position indicator of the stream.
template void parseString< unsigned char >(const UString &str, unsigned char &value, bool allowEmpty)
Unicode string handling.
void printDataHex(SeekableReadStream &stream, size_t size)
Print a quick hex dump of the given data.
Definition: strutil.cpp:42
template UString composeString< unsigned long long >(unsigned long long value)
template UString composeString< unsigned char >(unsigned char value)
template void parseString< signed long long >(const UString &str, signed long long &value, bool allowEmpty)
uint32_t uint32
Definition: types.h:204
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
Definition: strutil.cpp:117
template UString composeString< signed long >(signed long value)
Low-level detection of architecture/system properties.
#define SIZE_MAX
Definition: types.h:172
#define strtoll
Definition: system.h:195
template UString composeString< unsigned int >(unsigned int value)
template UString composeString< unsigned short >(unsigned short value)
template void parseString< unsigned int >(const UString &str, unsigned int &value, bool allowEmpty)
Interface for a seekable & readable data stream.
Definition: readstream.h:265
void parseString(const UString &str, T &value, bool allowEmpty)
Parse a string into any POD integer, float/double or bool type.
Definition: strutil.cpp:215
template UString composeString< signed int >(signed int value)
uint8 byte
Definition: types.h:209
unsigned int uint
Definition: types.h:211
template void parseString< signed long >(const UString &str, signed long &value, bool allowEmpty)