1 /*
2 Copyright (C) 2005-2007 Feeling Software Inc.
3 Portions of the code are:
4 Copyright (C) 2005-2007 Sony Computer Entertainment America
5
6 MIT License: http://www.opensource.org/licenses/mit-license.php
7 */
8
9 /**
10 @file FUString.h
11 This file includes FUStringBuilder.h and FUStringConversion.h
12 and defines important string-related macros and inline functions.
13 */
14
15 #ifndef _FU_STRING_H_
16 #define _FU_STRING_H_
17
18 #ifndef _FM_ARRAY_H_
19 #include "FMath/FMArray.h"
20 #endif // _FM_ARRAY_H_
21
22 /** An empty UTF-8 string. This string is returned in many functions when there is an error. */
23 extern FCOLLADA_EXPORT const char* emptyCharString;
24 /** An empty Unicode string. This string is returned in many functions when there is an error. */
25 extern FCOLLADA_EXPORT const fchar* emptyFCharString;
26
27 // Already documented elsewhere.
28 namespace fm
29 {
30 /** A string template.
31 Intentionally has an interface similar to STL.
32 You should use fm::string for UTF8 strings and
33 fstring for UNICODE strings.
34 @ingroup FUtils */
35 template <class CH>
36 class FCOLLADA_EXPORT stringT : public fm::vector<CH, true>
37 {
38 public:
39 typedef fm::vector<CH, true> Parent; /**< The parent class. */
40
41 public:
42 /** Constant for infinity length.
43 This important constant is used throughout the
44 class to indicate infinity or values not found. */
45 static const size_t npos = ~(size_t)0;
46
47 /** Default constructor. Defaults to an empty string. */
stringT()48 stringT() : Parent() {}
49
50 /** Copy constructor.
51 @param c The string to clone. */
stringT(const stringT & c)52 stringT(const stringT& c) : Parent(c) {}
53
54 /** Copy constructor.
55 @param c A NULL-terminated character buffer to clone. */
stringT(const CH * c)56 stringT(const CH* c) : Parent()
57 {
58 append(c);
59 if (c == NULL || (*c) == 0) Parent::push_back((CH) 0);
60 }
61
62 /** Copy constructor.
63 @param c A character buffer to clone.
64 @param length A partial length to copy.
65 Use stringT::npos for copying full NULL-terminated strings. */
stringT(const CH * c,size_t length)66 stringT(const CH* c, size_t length) : Parent()
67 {
68 if (c == NULL || length == 0) return;
69
70 if (length != npos)
71 {
72 Parent::resize(length + 1);
73 memcpy(Parent::begin(), c, sizeof(CH) * length);
74 Parent::back() = 0; // NULL-terminate.
75 }
76 else
77 {
78 append(c);
79 if (c == NULL || (*c) == 0) Parent::push_back((CH) 0);
80 }
81 }
82
83 /** Constructor.
84 @param length The number of characters to repeat in the string.
85 @param c The character value to repeat within the string. */
stringT(size_t length,const CH & c)86 stringT(size_t length, const CH& c) : Parent()
87 {
88 Parent::reserve(length + 1);
89 Parent::insert(Parent::begin(), length, c);
90 Parent::push_back((CH) 0);
91 }
92
93 /** Retrieves the length of the string.
94 This function is NULL-termination aware.
95 @return The length of the string. */
length()96 inline size_t length() const { return Parent::size() > 1 ? Parent::size() - 1 : 0; }
size()97 inline size_t size() const { return Parent::size() > 1 ? Parent::size() - 1 : 0; } /**< See above. */
98
99 /** Retrieves the last element of the string.
100 This function is NULL-termination aware.
101 @return The last element of the string. */
back()102 inline CH& back() { return *(Parent::end() - 2); }
back()103 inline const CH& back() const { return *(Parent::end() - 2); } /**< See above. */
104
105 /** Removes the last character from a string.
106 This function is NULL-termination aware. */
pop_back()107 inline void pop_back() { if (Parent::size() > 0) { Parent::pop_back(); Parent::back() = 0; } }
108
109 /** Retrieves whether the string contains useful data.
110 This function differs from the parent because it checks for NULL-termination.
111 @return Whether the string contains useful data. */
empty()112 inline bool empty() const { return Parent::size() <= 1; }
113
114 /** Retrieves a segment of the string.
115 @param start The index of the first character to extract.
116 @param count The number of characters to extract. When the count
117 is 'npos', all the remaining characters are extracted.
118 @return The partial string. */
119 stringT substr(size_t start, size_t count = npos) const
120 {
121 if (start >= length()) return stringT();
122 if (count == npos || count + start > length()) count = length() - start;
123 return stringT(c_str() + start, count);
124 }
125
126 /** Appends a string to this string.
127 @param str A second string. */
append(const stringT & str)128 inline void append(const stringT& str)
129 {
130 insert(npos, str);
131 }
132
133 /** Appends a NULL-terminated character buffer to this string.
134 @param str A NULL-terminated character buffer.
135 @param count The number of characters to append. If the count
136 is 'npos', all available characters are appended. */
137 inline void append(const CH* str, size_t count=npos)
138 {
139 insert(npos, str, count);
140 }
141
142 /** Appends one character to this string.
143 @param c A character. */
append(const CH & c)144 void append(const CH& c)
145 {
146 if (c != 0)
147 {
148 size_t originalSize = length();
149 Parent::resize(originalSize + 2);
150 *(Parent::end() - 2) = c;
151 Parent::back() = 0; // NULL-terminate
152 }
153 }
154
155 /** Inserts a character buffer in this string.
156 @param offset The position at which to insert the character buffer.
157 @param str A NULL-terminated character buffer.
158 @param count The number of characters to append. If the count
159 is 'npos', all available characters are appended. */
160 void insert(size_t offset, const CH* str, size_t count=npos)
161 {
162 if (str != NULL && (*str != 0))
163 {
164 size_t originalSize = length();
165 offset = min(offset, originalSize);
166
167 size_t str_length = 0;
168 const CH* s = str;
169 while(*s != 0 && str_length < count) { ++s; ++str_length; }
170 resize(originalSize + str_length);
171 if (offset < originalSize)
172 {
173 memmove(Parent::begin() + offset + str_length, Parent::begin() + offset, (originalSize - offset) * sizeof(CH));
174 }
175 memcpy(Parent::begin() + offset, str, sizeof(CH) * str_length);
176 Parent::back() = 0; // NULL-terminate
177 }
178 }
179
180 /** Inserts a string in this string.
181 @param offset The position at which to insert the string.
182 @param str A second string. */
insert(size_t offset,const stringT & str)183 void insert(size_t offset, const stringT& str)
184 {
185 size_t str_length = str.length();
186 if (str_length > 0)
187 {
188 size_t originalSize = length();
189 offset = min(offset, originalSize);
190 resize(originalSize + str_length);
191 if (offset < originalSize)
192 {
193 memmove(Parent::begin() + offset + str_length, Parent::begin() + offset, (originalSize - offset) * sizeof(CH));
194 }
195 memcpy(Parent::begin() + offset, str.c_str(), sizeof(CH) * str_length);
196 }
197 }
198
199 /** Retrieves the character buffer attached to this string.
200 @return The NULL-terminated character buffer for this string. */
c_str()201 const CH* c_str() const
202 {
203 static CH empty = 0;
204 if (Parent::size() == 0) return ∅
205 return Parent::begin();
206 }
207 inline operator const CH*() const { return c_str(); } /**< See above. */
208
209 /** Retrieves the position of the first matching character found within the string.
210 @param character The character to match.
211 @param offset An offset at which to start searching. Defaults to zero.
212 @return The position of the first matching character. If 'npos' is returned, the
213 character was not matched within the given (sub)string. */
214 size_t find(const CH& character, size_t offset=0) const
215 {
216 if (character > 0)
217 {
218 for (const CH* it = Parent::begin() + offset; it < Parent::end(); ++it)
219 {
220 if ((*it) == character) return it - Parent::begin();
221 }
222 }
223 return npos;
224 }
225
226 /** Retrieves the position of the first matching string found within the string.
227 @param str The string to match. If the string is zero-terminated, the null
228 character will not be included in the search.
229 @param offset An offset at which to start searching. Defaults to zero.
230 @return The position of the first matching string. If 'npos' is returned, the
231 string was not matched within the given (sub)string. */
232 size_t find(const stringT& str, size_t offset=0) const
233 {
234 if (str.length() > 0 && length() >= str.length())
235 {
236 CH firstMatch = str.front();
237 const CH* end_fence = Parent::end() - str.size() + 1;
238 for (const CH* it = Parent::begin() + offset; it < end_fence; ++it)
239 {
240 if ((*it) == firstMatch)
241 {
242 const CH* it2 = it;
243 const CH* sit = str.begin();
244 const CH* endIt = (*(str.end() - 1) == 0) ? str.end() - 1 : str.end();
245 for (; it2 != Parent::end() && sit != endIt; ++sit, ++it2)
246 {
247 if ((*sit) != (*it2)) break;
248 }
249 if (sit == endIt) return it - Parent::begin();
250 }
251 }
252 }
253 return npos;
254 }
255
256 /** Retrieves the position of the first matching character buffer found within the string.
257 @param c The character buffer to match.
258 @param offset An offset at which to start searching. Defaults to zero.
259 @return The position of the first matching character buffer. If 'npos' is returned, the
260 character buffer was not matched within the given (sub)string. */
261 size_t find(const CH* c, size_t offset=0) const
262 {
263 size_t length = 0; const CH* d = c; while (*d != 0) { ++length; ++d; }
264 if (length > 0 && Parent::size() >= length)
265 {
266 const CH* end_fence = Parent::end() - length + 1;
267 for (const CH* it = Parent::begin() + offset; it < end_fence; ++it)
268 {
269 if ((*it) == (*c))
270 {
271 const CH* it2 = it;
272 for (d = c; it2 != Parent::end() && (*d) != 0; ++it2, ++d)
273 {
274 if ((*it2) != (*d)) break;
275 }
276 if (*d == 0) return it - Parent::begin();
277 }
278 }
279 }
280 return npos;
281 }
282
283 /** Retrieves the position of the last matching character found within the string.
284 @param character The character to match.
285 @param offset An offset at which to start searching. Defaults to zero.
286 @return The position of the last matching character. If 'npos' is returned, the
287 character was not matched within the given (sub)string. */
288 size_t rfind(const CH& character, size_t offset=0) const
289 {
290 size_t ret = npos;
291 if (character > 0)
292 {
293 for (const CH* it = Parent::begin() + offset; it < Parent::end(); ++it)
294 {
295 if ((*it) == character) ret = it - Parent::begin();
296 }
297 }
298 return ret;
299 }
300
301 /** Retrieves the position of the last matching string found within the string.
302 @param str The string to match. If the string is zero-terminated, the null
303 character will not be included in the search.
304 @param offset An offset at which to start searching. Defaults to zero.
305 @return The position of the last matching string. If 'npos' is returned, the
306 string was not matched within the given (sub)string. */
307 size_t rfind(const stringT& str, size_t offset=0) const
308 {
309 size_t ret = npos;
310 if (str.length() > 0 && length() >= str.length())
311 {
312 CH firstMatch = str.front();
313 const CH* end_fence = Parent::end() - str.size() + 1;
314 for (const CH* it = Parent::begin() + offset; it < end_fence; ++it)
315 {
316 if ((*it) == firstMatch)
317 {
318 const CH* it2 = it;
319 const CH* sit = str.begin();
320 const CH* endIt = (*(str.end() - 1) == 0) ? str.end() - 1 : str.end();
321 for (; it2 != Parent::end() && sit != endIt; ++sit, ++it2)
322 {
323 if ((*sit) != (*it2)) break;
324 }
325 if (sit == endIt) ret = it - Parent::begin();
326 }
327 }
328 }
329 return ret;
330 }
331
332 /** Retrieves the position of the last matching character buffer found within the string.
333 @param c The character buffer to match.
334 @param offset An offset at which to start searching. Defaults to zero.
335 @return The position of the last matching character buffer. If 'npos' is returned, the
336 character buffer was not matched within the given (sub)string. */
337 size_t rfind(const CH* c, size_t offset=0) const
338 {
339 size_t ret = npos;
340 size_t length = 0; const CH* d = c; while (*d != 0) { ++length; ++d; }
341 if (length > 0 && Parent::size() >= length)
342 {
343 const CH* end_fence = Parent::end() - length + 1;
344 for (const CH* it = Parent::begin() + offset; it < end_fence; ++it)
345 {
346 if ((*it) == (*c))
347 {
348 const CH* it2 = it;
349 for (d = c; it2 != Parent::end() && (*d) != 0; ++it2, ++d)
350 {
351 if ((*it2) != (*d)) break;
352 }
353 if (*d == 0) ret = it - Parent::begin();
354 }
355 }
356 }
357 return ret;
358 }
359
360 /** Retrieves the position of the first matching character from a list of possible characters.
361 @param c A list of possible characters to match.
362 @param offset An offset at which to start searching. Defaults to zero.
363 @return The position of the first matching character within the list of possible characters.
364 If 'npos' is returned, none of the possible characters were found within the (sub)string. */
365 size_t find_first_of(const CH* c, size_t offset=0) const
366 {
367 size_t length = 0; const CH* d = c; while (*d != 0) { ++length; ++d; }
368 if (length > 0 && Parent::size() >= length)
369 {
370 for (const CH* it = Parent::begin() + offset; it < Parent::end(); ++it)
371 {
372 d = c;
373 while (*d != 0 && *d != *it) { ++d; }
374 if (*d != 0) return it - Parent::begin();
375 }
376 }
377 return npos;
378 }
379
380 /** Retrieves the position of the last matching character from a list of possible characters.
381 @param c A list of possible characters to match.
382 @param offset An offset (from the end of the string) at which to start searching. Defaults to zero.
383 @return The position of the last matching character within the list of possible characters.
384 If 'npos' is returned, none of the possible characters were found within the (sub)string. */
385 size_t find_last_of(const CH* c, size_t offset=0) const
386 {
387 size_t ret = length() - offset; // UNOPTIMIZE. Didn't feel like this is an important-enough function.
388 size_t length = 0; const CH* d = c; while (*d != 0) { ++length; ++d; }
389 if (length > 0 && Parent::size() >= length)
390 {
391 const CH* end = Parent::end() - (length + offset);
392 const CH* begin = Parent::begin();
393 for (const CH* it = end; it >= begin; --it)
394 {
395 d = c;
396 while (*d != 0)
397 {
398 if (*d == *it) return ret;
399 ++d;
400 }
401 --ret;
402 }
403 }
404 return npos;
405 }
406
407 /** Removes a range of characters from a string.
408 @param start The start of the range of characters to remove.
409 Defaults to zero.
410 @param end The end of the range of characters to remove.
411 The character at this position will not be removed so
412 that if (start==end), no operation is done.
413 Defaults to npos, which indicates that all characters from
414 the start of the range should be removed. */
415 void erase(size_t start=0, size_t end=npos)
416 {
417 if (start < length() && start < end) // covers size() == 0.
418 {
419 if (end > length()) end = length();
420 Parent::erase(Parent::begin() + start, Parent::begin() + end);
421 }
422 }
423
424 /** Override the fm::vector resize. That call
425 does not handle the assumption this class makes that
426 every string is null terminated.
427
428 The fm::string resize command will automatically create
429 a null terminated string of length size
430 @param size Length of resulting string */
resize(size_t size)431 void resize(size_t size)
432 {
433 Parent::resize(size + 1);
434 Parent::back() = 0; // NULL-terminate
435 }
436
437 /** Override the fm::vector resize. That call
438 does not handle the assumption this class makes that
439 every string is null terminated.
440
441 Sets the number of values contained in the list.
442 @param count The new number of values contained in the list.
443 @param value The value to assign to the new entries in the list. */
resize(size_t count,const CH & value)444 void resize(size_t count, const CH& value)
445 {
446 Parent::resize(count + 1, value);
447 Parent::back() = 0; // NULL-terminate
448 }
449 };
450
451 /** A string of UTF8 characters. */
452 typedef stringT<char> string;
453
454 /** Concatenates two strings.
455 @param A A first string.
456 @param B A second string.
457 @return The concatenation of the two strings. */
458 template <class CharT> stringT<CharT> operator+(const stringT<CharT>& A, const stringT<CharT>& B) { stringT<CharT> C = A; C.append(B); return C; }
459 template <class CharT> stringT<CharT> operator+(const CharT* A, const stringT<CharT>& B) { stringT<CharT> C = A; C.append(B); return C; } /**< See above. */
460 template <class CharT> stringT<CharT> operator+(const stringT<CharT>& A, const CharT* B) { stringT<CharT> C = A; C.append(B); return C; } /**< See above. */
461 template <class CharT> stringT<CharT>& operator+=(stringT<CharT>& A, const stringT<CharT>& B) { A.append(B); return A; } /**< See above. */
462 template <class CharT> stringT<CharT>& operator+=(stringT<CharT>& A, const CharT* B) { A.append(B); return A; } /**< See above. */
463
464 /** Appends a character to a string.
465 @param A A string.
466 @param B A character.
467 @return The concatenation of the string with the character. */
468 template <class CharT> stringT<CharT>& operator+=(stringT<CharT>& A, const CharT& B) { A.append(B); return A; }
469
470 /** Retrieves whether a first string is lesser than a second string.
471 This comparison is done solely on the character buffers and not the lengths.
472 @param A A first string.
473 @param B A second string.
474 @return Whether the first string is lesser than the second string. */
475 template <class CharT> bool operator<(const stringT<CharT>& A, const stringT<CharT>& B)
476 {
477 const CharT* a = A.c_str(); const CharT* b = B.c_str();
478 while ((*a) != 0 && (*b) != 0 && (*a) == (*b)) { ++a; ++b; }
479 return (*a) < (*b);
480 }
481
482 /** Retrieves whether a first string is equal to a second string.
483 @param A A first string.
484 @param B A second string.
485 @return Whether the first string is equal to the second string. */
486 template <class CharT> bool operator==(const stringT<CharT>& A, const stringT<CharT>& B)
487 {
488 if (A.length() != B.length()) return false;
489 const CharT* a = A.c_str(); const CharT* b = B.c_str();
490 while ((*a) != 0 && (*a) == (*b)) { ++a; ++b; }
491 return (*a) == (*b);
492 }
493
494 /** Retrieves whether a first string differs from a second string.
495 @param A A first string.
496 @param B A second string.
497 @return Whether the first string differs from the second string. */
498 template <class CharT> bool operator!=(const stringT<CharT>& A, const stringT<CharT>& B)
499 {
500 if (A.length() != B.length()) return true;
501 const CharT* a = A.c_str(); const CharT* b = B.c_str();
502 while ((*a) != 0 && (*a) == (*b)) { ++a; ++b; }
503 return (*a) != (*b);
504 }
505
506 /** Retrieves whether a first string differs from a second string.
507 @param A A first string.
508 @param B A second string.
509 @return Whether the first string differs from the second string. */
510 template <class CharT> bool operator!=(const stringT<CharT>& A, const CharT* B)
511 {
512 if (B == NULL) return true;
513 size_t B_length = 0; { const CharT* b = B; while (*b != 0) { ++b; ++B_length; } }
514 if (A.length() != B_length) return true;
515 const CharT* a = A.c_str(); const CharT* b = B;
516 while ((*a) != 0 && (*a) == (*b)) { ++a; ++b; }
517 return (*a) != (*b);
518 }
519 };
520
521 /** A string of UNICODE characters. */
522 typedef fm::stringT<fchar> fstring;
523
524 /** A dynamically-sized array of Unicode strings. */
525 typedef fm::vector<fstring> FStringList;
526
527 /** A dynamically-sized array of simple strings. */
528 typedef fm::vector<fm::string> StringList;
529
530 /** Returns whether two 8-bit strings are equivalent. This is a case-sensitive comparison.
531 @param sz1 The first 8-bit string to compare.
532 @param sz2 The second 8-bit string to compare.
533 @return Whether the two 8-bit strings are equivalent. */
IsEquivalent(const char * sz1,const char * sz2)534 inline bool IsEquivalent(const char* sz1, const char* sz2) { return strcmp(sz1, sz2) == 0; }
IsEquivalent(const fm::string & sz1,const char * sz2)535 inline bool IsEquivalent(const fm::string& sz1, const char* sz2) { return strcmp(sz1.c_str(), sz2) == 0; } /**< See above. */
IsEquivalent(const char * sz1,const fm::string & sz2)536 inline bool IsEquivalent(const char* sz1, const fm::string& sz2) { return strcmp(sz1, sz2.c_str()) == 0; } /**< See above. */
IsEquivalent(const fm::string & sz1,const fm::string & sz2)537 inline bool IsEquivalent(const fm::string& sz1, const fm::string& sz2) { return strcmp(sz1.c_str(), sz2.c_str()) == 0; } /**< See above. */
538
539 /** Returns whether two 8-bit strings are equivalent. This is a case-insensitive comparison.
540 @param sz1 The first 8-bit string to compare.
541 @param sz2 The second 8-bit string to compare.
542 @return Whether the two 8-bit strings are equivalent. */
IsEquivalentI(const char * sz1,const char * sz2)543 inline bool IsEquivalentI(const char* sz1, const char* sz2) { return _stricmp(sz1, sz2) == 0; }
IsEquivalentI(const fm::string & sz1,const char * sz2)544 inline bool IsEquivalentI(const fm::string& sz1, const char* sz2) { return _stricmp(sz1.c_str(), sz2) == 0; } /**< See above. */
IsEquivalentI(const char * sz1,const fm::string & sz2)545 inline bool IsEquivalentI(const char* sz1, const fm::string& sz2) { return _stricmp(sz1, sz2.c_str()) == 0; } /**< See above. */
IsEquivalentI(const fm::string & sz1,const fm::string & sz2)546 inline bool IsEquivalentI(const fm::string& sz1, const fm::string& sz2) { return _stricmp(sz1.c_str(), sz2.c_str()) == 0; } /**< See above. */
547 #ifdef UNICODE
IsEquivalentI(const fchar * sz1,const fchar * sz2)548 inline bool IsEquivalentI(const fchar* sz1, const fchar* sz2) { return fstricmp(sz1, sz2) == 0; } /**< See above. */
IsEquivalentI(const fstring & sz1,const fchar * sz2)549 inline bool IsEquivalentI(const fstring& sz1, const fchar* sz2) { return fstricmp(sz1.c_str(), sz2) == 0; } /**< See above. */
IsEquivalentI(const fchar * sz1,const fstring & sz2)550 inline bool IsEquivalentI(const fchar* sz1, const fstring& sz2) { return fstricmp(sz1, sz2.c_str()) == 0; } /**< See above. */
IsEquivalentI(const fstring & sz1,const fstring & sz2)551 inline bool IsEquivalentI(const fstring& sz1, const fstring& sz2) { return fstricmp(sz1.c_str(), sz2.c_str()) == 0; } /**< See above. */
552 #endif // UNICODE
553
554 /** Returns whether two 8-bit strings are equivalent. This is a case-sensitive comparison.
555 @param sz1 The first 8-bit string to compare.
556 @param sz2 The second 8-bit string to compare.
557 @return Whether the two 8-bit strings are equivalent. */
558 inline bool operator==(const fm::string& sz1, const char* sz2) { return strcmp(sz1.c_str(), sz2) == 0; }
559
560 #ifdef UNICODE
561 /** Returns whether two Unicode strings are equivalent. This is a case-sensitive comparison.
562 @param sz1 The first Unicode string to compare.
563 @param sz2 The second Unicode string to compare.
564 @return Whether the two Unicode strings are equivalent. */
IsEquivalent(const fchar * sz1,const fchar * sz2)565 inline bool IsEquivalent(const fchar* sz1, const fchar* sz2)
566 {
567 return (sz1 == sz2) ? true : // ptrs same, are equivalent
568 (sz1 == NULL || sz2 == NULL) ? // either ptr null, not equivalent
569 false : fstrcmp(sz1, sz2) == 0; // do actual test
570 }
IsEquivalent(const fstring & sz1,const fchar * sz2)571 inline bool IsEquivalent(const fstring& sz1, const fchar* sz2) { return IsEquivalent(sz1.c_str(), sz2); } /**< See above. */
IsEquivalent(const fchar * sz1,const fstring & sz2)572 inline bool IsEquivalent(const fchar* sz1, const fstring& sz2) { return IsEquivalent(sz1, sz2.c_str()); } /**< See above. */
IsEquivalent(const fstring & sz1,const fstring & sz2)573 inline bool IsEquivalent(const fstring& sz1, const fstring& sz2) { return IsEquivalent(sz1.c_str(), sz2.c_str()); } /**< See above. */
574
575 /** Returns whether two Unicode strings are equivalent. This is a case-sensitive comparison.
576 @param sz1 The first Unicode string to compare.
577 @param sz2 The second Unicode string to compare.
578 @return Whether the two Unicode strings are equivalent. */
579 inline bool operator==(const fstring& sz1, const fchar* sz2) { return IsEquivalent(sz1.c_str(), sz2); }
580 #endif // UNICODE
581
582 // Include the main string modification classes.
583 #include "FUtils/FUStringBuilder.h"
584 #include "FUtils/FUStringConversion.h"
585
586 /** A Unicode string from a constant 8-bit string. */
587 #define FS(a) fstring(FC(a))
588 /** A Unicode string from any convertable value: string, vector-type or simple numeric. */
589 #define TO_FSTRING(a) FUStringConversion::ToFString(a)
590 /** An 8-bit string from any convertable value: Unicode string, vector-type or simple numeric. */
591 #define TO_STRING(a) FUStringConversion::ToString(a)
592
593 /** An empty UTF-8 string. This string is returned in many functions when there is an error. */
594 extern FCOLLADA_EXPORT const fm::string emptyString;
595 /** An empty Unicode string. This string is returned in many functions when there is an error. */
596 extern FCOLLADA_EXPORT const fstring emptyFString;
597
598 /** Returns whether a string builder and a string are equivalent. This is a case-sensitive comparison.
599 @param builder The string builder to compare.
600 @param sz The string to compare.
601 @return Whether the two strings are equivalent. */
IsEquivalent(FUSStringBuilder & builder,const char * sz)602 inline bool IsEquivalent(FUSStringBuilder& builder, const char* sz) { return IsEquivalent(builder.ToCharPtr(), sz); }
IsEquivalent(FUSStringBuilder & builder,const fm::string & sz)603 inline bool IsEquivalent(FUSStringBuilder& builder, const fm::string& sz) { return IsEquivalent(builder.ToCharPtr(), sz.c_str()); } /**< See above. */
604 #ifdef UNICODE
IsEquivalent(FUStringBuilder & builder,const fchar * sz)605 inline bool IsEquivalent(FUStringBuilder& builder, const fchar* sz) { return IsEquivalent(builder.ToCharPtr(), sz); } /**< See above. */
IsEquivalent(FUStringBuilder & builder,const fstring & sz)606 inline bool IsEquivalent(FUStringBuilder& builder, const fstring& sz) { return IsEquivalent(builder.ToCharPtr(), sz.c_str()); } /**< See above. */
607 #endif
608
609 #endif // _FU_STRING_H_
610