- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# FUtils/FUStringConversion.hpp

    00001 /*
    00002     Copyright (C) 2005-2007 Feeling Software Inc.
    00003     Portions of the code are:
    00004     Copyright (C) 2005-2007 Sony Computer Entertainment America
    00005
    00006     MIT License: http://www.opensource.org/licenses/mit-license.php
    00007 */
    00008
    00009 #include "FUtils/FUDateTime.h"
    00010 #include <limits>
    00011
    00012 //
    00013 // FUStringConversion template functions
    00014 //
    00015
    00016 // Some string writer macros
    00017 #define SPACE builder.append((CH) ' ')
    00018 #define VAL(x) builder.append(x)
    00019
    00020 // Convert a fstring to a boolean value
    00021 template<class CH>
    00022 FCOLLADA_EXPORT bool FUStringConversion::ToBoolean(const CH* value)
    00023 {
    00024     return value != NULL && *value != 0 && *value != '0' && *value != 'f' && *value != 'F';
    00025 }
    00026
    00027 // Convert a fstring to a int32 and advance the character pointer
    00028 template <class CH>
    00029 FCOLLADA_EXPORT int32 FUStringConversion::ToInt32(const CH** value)
    00030 {
    00031     if (!*value) return 0;
    00032
    00033     // Skip beginning white spaces
    00034     const CH* s = *value;
    00035     CH c;
    00036     while ((c = *s) != 0 && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { ++s; }
    00037
    00038     int32 val = 0;
    00039     int32 sign = 1;
    00040     if (*s == '-') { ++s; sign = -1; }
    00041
    00042     while ((c = *s) != 0)
    00043     {
    00044         if (c >= '0' && c <= '9') val = val * 10 + c - '0';
    00045         else break;
    00046         ++s;
    00047     }
    00048     val *= sign;
    00049     while ((c = *s) != '\0' && (c != ' ' && c != '\t' && c != '\n')) s++;
    00050     while ((c = *s) != '\0' && (c == ' ' || c == '\t' || c == '\n')) s++;
    00051     *value = s;
    00052     return val;
    00053 }
    00054
    00055 // Convert a fstring to a float and advance the character pointer
    00056 template<class CH>
    00057 FCOLLADA_EXPORT float FUStringConversion::ToFloat(const CH** value)
    00058 {
    00059     const CH* s = *value;
    00060     if (s == NULL || *s == 0) return 0.0f;
    00061
    00062     // Skip beginning white spaces
    00063     CH c;
    00064     while ((c = *s) != 0 && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { ++s; }
    00065
    00066     // Skip all the plausible numerical characters
    00067     double val = 0.0;
    00068     float sign = 1.0;
    00069     if (*s == '-') { ++s; sign = -1.0; }
    00070     float decimals = 0.0;
    00071     int32 exponent = 0;
    00072     bool infinity = false;
    00073     bool nonValidFound = false;
    00074     while ((c = *s) != 0 && !nonValidFound)
    00075     {
    00076         switch (c)
    00077         {
    00078         case '.': decimals = 1; break;
    00079         case '0': val *= 10.0; decimals *= 10.0; break;
    00080         case '1': val = val * 10.0 + 1.0; decimals *= 10.0; break;
    00081         case '2': val = val * 10.0 + 2.0; decimals *= 10.0; break;
    00082         case '3': val = val * 10.0 + 3.0; decimals *= 10.0; break;
    00083         case '4': val = val * 10.0 + 4.0; decimals *= 10.0; break;
    00084         case '5': val = val * 10.0 + 5.0; decimals *= 10.0; break;
    00085         case '6': val = val * 10.0 + 6.0; decimals *= 10.0; break;
    00086         case '7': val = val * 10.0 + 7.0; decimals *= 10.0; break;
    00087         case '8': val = val * 10.0 + 8.0; decimals *= 10.0; break;
    00088         case '9': val = val * 10.0 + 9.0; decimals *= 10.0; break;
    00089         case 'e':
    00090         case 'E': ++s; exponent = ToInt32(&s); s -= 2; nonValidFound = true; break;
    00091         case 'I': infinity = true; // intentional pass-through.
    00092         default: nonValidFound = true; --s; break;
    00093         }
    00094         ++s;
    00095     }
    00096
    00097     float out = 0.0f;
    00098     if (infinity) // test for infinity
    00099     {
    00100         infinity = false;
    00101         c = *(s++);
    00102         if (c != 'I') infinity = false;
    00103         else
    00104         {
    00105             c = *(s++);
    00106             if (c != 'N') infinity = false;
    00107             else
    00108             {
    00109                 c = *(s++);
    00110                 if (c != 'F') infinity = false;
    00111                 else out = std::numeric_limits<float>::infinity() * ((float) sign);
    00112             }
    00113         }
    00114     }
    00115     if (!infinity)
    00116     {
    00117         // Generate the value
    00118         if (decimals == 0.0) decimals = 1.0;
    00119         out = (float) (val * sign / decimals);
    00120         if (exponent != 0) out *= powf(10.0f, (float) exponent);
    00121     }
    00122
    00123     // Find next whitespaces and Skip end whitespaces
    00124     while ((c = *s) != 0 && c != ' ' && c != '\t' && c != '\r' && c != '\n') { ++s; }
    00125     while ((c = *s) != 0 && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { ++s; }
    00126
    00127     *value = s;
    00128     return out;
    00129 }
    00130
    00131 // Convert a fstring to a uint32 and advance the character pointer
    00132 template<class CH>
    00133 FCOLLADA_EXPORT uint32 FUStringConversion::ToUInt32(const CH** value)
    00134 {
    00135     if (value == NULL || *value == NULL || **value == 0) return 0;
    00136
    00137     // Skip beginning white spaces
    00138     const CH* s = *value;
    00139     CH c;
    00140     while ((c = *s) != 0 && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { ++s; }
    00141
    00142     uint32 val = 0;
    00143     while ((c = *s) != 0)
    00144     {
    00145         if (c >= '0' && c <= '9') val = val * 10 + c - '0';
    00146         else break;
    00147         ++s;
    00148     }
    00149
    00150     while ((c = *s) != '\0' && (c != ' ' && c != '\t' && c != '\n')) s++;
    00151     while ((c = *s) != '\0' && (c == ' ' || c == '\t' || c == '\n')) s++;
    00152     *value = s;
    00153     return val;
    00154 }
    00155
    00156 template<class CH>
    00157 FCOLLADA_EXPORT uint32 FUStringConversion::HexToUInt32(const CH** value, uint32 count)
    00158 {
    00159     if (value == NULL || *value == NULL || **value == 0) return 0;
    00160
    00161     const CH* s = *value;
    00162     CH c;
    00163
    00164     // Skip any '0x' prefix.
    00165     if (*s == '0' && (*(s+1) == 'x' || *(s+1) == 'X')) s += 2;
    00166
    00167     uint32 val = 0;
    00168     for (uint32 i = 0; i < count && (c = *s) != 0; ++i)
    00169     {
    00170         if (c >= '0' && c <= '9') val = val * 16 + c - '0';
    00171         else if (c >= 'A' && c <= 'F') val = val * 16 + c + 10 - 'A';
    00172         else if (c >= 'a' && c <= 'f') val = val * 16 + c + 10 - 'a';
    00173         else break;
    00174         ++s;
    00175     }
    00176
    00177     *value = s;
    00178     return val;
    00179 }
    00180
    00181 template<class CH>
    00182 FCOLLADA_EXPORT void FUStringConversion::ToMatrix(const CH** s, FMMatrix44& mx)
    00183 {
    00184     if (s != NULL && *s != NULL && **s != 0)
    00185     {
    00186         // COLLADA is Column major
    00187         mx[0][0] = ToFloat(s); mx[1][0] = ToFloat(s); mx[2][0] = ToFloat(s); mx[3][0] = ToFloat(s);
    00188         mx[0][1] = ToFloat(s); mx[1][1] = ToFloat(s); mx[2][1] = ToFloat(s); mx[3][1] = ToFloat(s);
    00189         mx[0][2] = ToFloat(s); mx[1][2] = ToFloat(s); mx[2][2] = ToFloat(s); mx[3][2] = ToFloat(s);
    00190         mx[0][3] = ToFloat(s); mx[1][3] = ToFloat(s); mx[2][3] = ToFloat(s); mx[3][3] = ToFloat(s);
    00191     }
    00192 }
    00193
    00194 template<class CH>
    00195 FCOLLADA_EXPORT void FUStringConversion::ToDateTime(const CH* value, FUDateTime& dateTime)
    00196 {
    00197     // Manually calculate the length in order to avoid the strlen/fstrlen nightmare.
    00198     size_t length;
    00199     const CH* c = value;
    00200     for (length = 0; *c != 0; ++length) ++c;
    00201
    00202     if (length == 20)
    00203     {
    00204         dateTime.SetYear(ToUInt32(value)); value += 5;
    00205         dateTime.SetMonth(ToUInt32(value)); value += 3;
    00206         dateTime.SetDay(ToUInt32(value)); value += 3;
    00207         dateTime.SetHour(ToUInt32(value)); value += 3;
    00208         dateTime.SetMinutes(ToUInt32(value)); value += 3;
    00209         dateTime.SetSeconds(ToUInt32(value));
    00210     }
    00211 }
    00212
    00213 // Convert a fstring to a (X,Y,Z) Point object
    00214 template<class CH>
    00215 FCOLLADA_EXPORT FMVector2 FUStringConversion::ToVector2(const CH** value)
    00216 {
    00217     FMVector2 p;
    00218     if (value != NULL && *value != NULL && **value != 0)
    00219     {
    00220         p.x = ToFloat(value);
    00221         p.y = ToFloat(value);
    00222     }
    00223     return p;
    00224 }
    00225
    00226 template<class CH>
    00227 FCOLLADA_EXPORT FMVector3 FUStringConversion::ToVector3(const CH** value)
    00228 {
    00229     FMVector3 p;
    00230     if (value != NULL && *value != NULL && **value != 0)
    00231     {
    00232         p.x = ToFloat(value);
    00233         p.y = ToFloat(value);
    00234         p.z = ToFloat(value);
    00235     }
    00236     return p;
    00237 }
    00238
    00239 template<class CH>
    00240 FCOLLADA_EXPORT FMVector4 FUStringConversion::ToVector4(const CH** value)
    00241 {
    00242     FMVector4 p;
    00243     if (value != NULL && *value != NULL && **value != 0)
    00244     {
    00245         p.x = ToFloat(value);
    00246         p.y = ToFloat(value);
    00247         p.z = ToFloat(value);
    00248
    00249         // If the fourth component is not provided, default to 1.0f.
    00250         p.w = (*value != NULL && **value != 0) ? ToFloat(value) : 1.0f;
    00251     }
    00252     return p;
    00253 }
    00254
    00255 // Convert a matrix to a string
    00256 template <class CH>
    00257 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const FMMatrix44& m)
    00258 {
    00259     VAL(m[0][0]); SPACE; VAL(m[1][0]); SPACE; VAL(m[2][0]); SPACE; VAL(m[3][0]); SPACE;
    00260     VAL(m[0][1]); SPACE; VAL(m[1][1]); SPACE; VAL(m[2][1]); SPACE; VAL(m[3][1]); SPACE;
    00261     VAL(m[0][2]); SPACE; VAL(m[1][2]); SPACE; VAL(m[2][2]); SPACE; VAL(m[3][2]); SPACE;
    00262     VAL(m[0][3]); SPACE; VAL(m[1][3]); SPACE; VAL(m[2][3]); SPACE; VAL(m[3][3]);
    00263 }
    00264
    00265 template <class CH>
    00266 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const FMVector2& p)
    00267 {
    00268     VAL(p.u); SPACE; VAL(p.v);
    00269 }
    00270
    00271 template <class CH>
    00272 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const FMVector3& p)
    00273 {
    00274     VAL(p.x); SPACE; VAL(p.y); SPACE; VAL(p.z);
    00275 }
    00276
    00277 template <class CH>
    00278 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const FMVector4& p)
    00279 {
    00280     VAL(p.x); SPACE; VAL(p.y); SPACE; VAL(p.z); SPACE; VAL(p.w);
    00281 }
    00282
    00283 template <class CH>
    00284 FCOLLADA_EXPORT size_t FUStringConversion::CountValues(const CH* sz)
    00285 {
    00286     size_t count = 0;
    00287     if (sz != NULL && *sz > 0)
    00288     {
    00289         while (*sz != 0)
    00290         {
    00291             // Clear all whitespace
    00292             while (*sz != 0 && (*sz == ' ' || *sz == '\t' || *sz == '\r' || *sz == '\n')) ++sz;
    00293             if (*sz == 0) break;
    00294
    00295             // New value found.
    00296             ++count;
    00297             while (*sz != 0 && *sz != ' ' && *sz != '\t' && *sz != '\r' && *sz != '\n') ++sz;
    00298         }
    00299     }
    00300     return count;
    00301 }
    00302
    00303 #ifdef HAS_VECTORTYPES
    00304
    00305 template<class CH>
    00306 FCOLLADA_EXPORT void FUStringConversion::ToBooleanList(const CH* value, BooleanList& array)
    00307 {
    00308     const CH* s = value;
    00309     CH c = *s;
    00310     array.clear();
    00311
    00312     // Start by eating all the white spaces.
    00313     while ((c = *s) != 0 && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { ++s; }
    00314
    00315     while (*s != 0)
    00316     {
    00317         // Process this value
    00318         array.push_back(ToBoolean(s));
    00319
    00320         // Find next white space
    00321         while ((c = *s) != 0 && c != ' ' && c != '\t' && c != '\r' && c != '\n') { ++s; }
    00322
    00323         // Skip all the white spaces.
    00324         while ((c = *s) != 0 && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { ++s; }
    00325     }
    00326 }
    00327
    00328 // Convert a fstring to a 32-bit integer list
    00329 template<class CH>
    00330 FCOLLADA_EXPORT void FUStringConversion::ToInt32List(const CH* value, Int32List& array)
    00331 {
    00332     size_t length = 0;
    00333     if (value != NULL && *value != 0)
    00334     {
    00335         // Read in values within the already allocated space.
    00336         size_t oldLength = array.size();
    00337         for (; length < oldLength && *value != 0; ++length) array[length] = ToInt32(&value);
    00338
    00339         // Count the value-space necessary to parse in the rest of the string.
    00340         size_t count = CountValues(value);
    00341         if (count > 0) array.reserve(oldLength + count);
    00342         while (*value != 0) { array.push_back(ToInt32(&value)); ++length; }
    00343     }
    00344     if (length != array.size()) array.resize(length);
    00345 }
    00346
    00347 // Convert a fstring to a 32-bit unsigned integer list
    00348 template<class CH>
    00349 FCOLLADA_EXPORT void FUStringConversion::ToUInt32List(const CH* value, UInt32List& array)
    00350 {
    00351     size_t length = 0;
    00352     if (value != NULL && *value != 0)
    00353     {
    00354         // Read in values within the already allocated space.
    00355         size_t oldLength = array.size();
    00356         for (; length < oldLength && *value != 0; ++length) array[length] = ToUInt32(&value);
    00357
    00358         // Count the value-space necessary to parse in the rest of the string.
    00359         size_t count = CountValues(value);
    00360         if (count > 0) array.reserve(oldLength + count);
    00361         while (*value != 0) { array.push_back(ToUInt32(&value)); ++length; }
    00362     }
    00363     if (length != array.size()) array.resize(length);
    00364 }
    00365
    00366 // Convert a fstring to 32-bit floating point list
    00367 template<class CH>
    00368 FCOLLADA_EXPORT void FUStringConversion::ToFloatList(const CH* value, FloatList& array)
    00369 {
    00370     size_t length = 0;
    00371     if (value != NULL && *value != 0)
    00372     {
    00373         // Read in values within the already allocated space.
    00374         size_t oldLength = array.size();
    00375         for (; length < oldLength && *value != 0; ++length) array[length] = ToFloat(&value);
    00376
    00377         // Count the value-space necessary to parse in the rest of the string.
    00378         size_t count = CountValues(value);
    00379         if (count > 0) array.reserve(oldLength + count);
    00380         while (*value != 0) { array.push_back(ToFloat(&value)); ++length; }
    00381     }
    00382     if (length != array.size()) array.resize(length);
    00383 }
    00384
    00385 // Convert a fstring to a list of interleaved floating points
    00386 template<class CH>
    00387 FCOLLADA_EXPORT void FUStringConversion::ToInterleavedFloatList(const CH* value, fm::pvector<FloatList>& arrays)
    00388 {
    00389     size_t stride = arrays.size();
    00390     size_t validCount = 0;
    00391     if (value != NULL && *value != 0 && stride > 0)
    00392     {
    00393         size_t length = arrays[0]->size();
    00394         for (size_t count = 0; count < length && *value != 0; ++count, ++validCount)
    00395         {
    00396             for (size_t i = 0; i < stride && *value != 0; ++i)
    00397             {
    00398                 FloatList* array = arrays[i];
    00399                 if (array != NULL) array->at(count) = ToFloat(&value);
    00400                 else ToFloat(&value);
    00401             }
    00402         }
    00403
    00404         if (*value != 0)
    00405         {
    00406             // Count the number of additional values to add to the array.
    00407             size_t additional = (CountValues(value) + stride - 1) / stride;
    00408             for (size_t i = 0; i < stride && *value != 0; ++i)
    00409             {
    00410                 FloatList* array = arrays[i];
    00411                 if (array != NULL) array->reserve(array->size() + additional);
    00412             }
    00413
    00414             // Parse in the extra values.
    00415             while (*value != 0)
    00416             {
    00417                 size_t i = 0;
    00418                 for (; i < stride && *value != 0; ++i)
    00419                 {
    00420                     FloatList* array = arrays[i];
    00421                     if (array != NULL) array->push_back(ToFloat(&value));
    00422                     else ToFloat(&value);
    00423                 }
    00424                 if (i == stride) ++validCount;
    00425             }
    00426         }
    00427     }
    00428
    00429     for (size_t i = 0; i < stride; ++i)
    00430     {
    00431         if (arrays[i] != NULL) arrays[i]->resize(validCount);
    00432     }
    00433 }
    00434
    00435 template <class CH>
    00436 FCOLLADA_EXPORT void FUStringConversion::ToInterleavedUInt32List(const CH* value, fm::pvector<UInt32List>& arrays)
    00437 {
    00438     size_t stride = arrays.size();
    00439     size_t validCount = 0;
    00440     if (value != NULL && *value != 0 && stride > 0)
    00441     {
    00442         size_t length = arrays[0]->size();
    00443         for (size_t count = 0; count < length && *value != 0; ++count, ++validCount)
    00444         {
    00445             for (size_t i = 0; i < stride && *value != 0; ++i)
    00446             {
    00447                 UInt32List* array = arrays[i];
    00448                 if (array != NULL) array->at(count) = ToUInt32(&value);
    00449                 else ToUInt32(&value);
    00450             }
    00451         }
    00452
    00453         if (*value != 0)
    00454         {
    00455             // Count the number of additional values to add to the array.
    00456             size_t additional = (CountValues(value) + stride - 1) / stride;
    00457             for (size_t i = 0; i < stride && *value != 0; ++i)
    00458             {
    00459                 UInt32List* array = arrays[i];
    00460                 if (array != NULL) array->reserve(array->size() + additional);
    00461             }
    00462
    00463             // Parse in the extra values.
    00464             while (*value != 0)
    00465             {
    00466                 size_t i = 0;
    00467                 for (; i < stride && *value != 0; ++i)
    00468                 {
    00469                     UInt32List* array = arrays[i];
    00470                     if (array != NULL) array->push_back(ToUInt32(&value));
    00471                     else ToUInt32(&value);
    00472                 }
    00473                 if (i == stride) ++validCount;
    00474             }
    00475         }
    00476     }
    00477
    00478     for (size_t i = 0; i < stride; ++i)
    00479     {
    00480         if (arrays[i] != NULL) arrays[i]->resize(validCount);
    00481     }
    00482 }
    00483
    00484 // Convert a string to a list of matrices
    00485 template<class CH>
    00486 FCOLLADA_EXPORT void FUStringConversion::ToMatrixList(const CH* value, FMMatrix44List& array)
    00487 {
    00488     size_t count = 0;
    00489     if (value != NULL && *value != 0)
    00490     {
    00491         size_t length = array.size();
    00492         for (; count < length && *value != 0; ++count)
    00493         {
    00494             ToMatrix(&value, array[count]);
    00495         }
    00496
    00497         while (*value != 0)
    00498         {
    00499             FMMatrix44List::iterator it = array.insert(array.end(), FMMatrix44::Identity);
    00500             ToMatrix(&value, *it);
    00501             ++count;
    00502         }
    00503     }
    00504     array.resize(count);
    00505 }
    00506
    00507 template<class CH>
    00508 FCOLLADA_EXPORT void FUStringConversion::ToVector2List(const CH* value, FMVector2List& array)
    00509 {
    00510     size_t count = 0;
    00511     if (value != NULL && *value != 0)
    00512     {
    00513         size_t length = array.size();
    00514         for (; count < length && *value != 0; ++count)
    00515         {
    00516             array[count] = ToVector2(&value);
    00517         }
    00518
    00519         while (*value != 0) { array.push_back(ToVector2(&value)); ++count; }
    00520     }
    00521     array.resize(count);
    00522 }
    00523
    00524 template<class CH>
    00525 FCOLLADA_EXPORT void FUStringConversion::ToVector3List(const CH* value, FMVector3List& array)
    00526 {
    00527     size_t count = 0;
    00528     if (value != NULL && *value != 0)
    00529     {
    00530         size_t length = array.size();
    00531         for (; count < length && *value != 0; ++count)
    00532         {
    00533             array[count] = ToVector3(&value);
    00534         }
    00535
    00536         while (*value != 0) { array.push_back(ToVector3(&value)); ++count; }
    00537     }
    00538     array.resize(count);
    00539 }
    00540
    00541 template<class CH>
    00542 FCOLLADA_EXPORT void FUStringConversion::ToVector4List(const CH* value, FMVector4List& array)
    00543 {
    00544     size_t count = 0;
    00545     if (value != NULL && *value != 0)
    00546     {
    00547         size_t length = array.size();
    00548         for (; count < length && *value != 0; ++count)
    00549         {
    00550             array[count] = ToVector4(&value);
    00551         }
    00552
    00553         while (*value != 0) { array.push_back(ToVector4(&value)); ++count; }
    00554     }
    00555     array.resize(count);
    00556 }
    00557
    00558 template <class CH>
    00559 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const FloatList& values)
    00560 {
    00561     if (values.empty()) return;
    00562     if (!builder.empty()) SPACE;
    00563     FloatList::const_iterator itV = values.begin();
    00564     builder.append(*itV);
    00565     for (++itV; itV != values.end(); ++itV) { SPACE; VAL(*itV); }
    00566 }
    00567
    00568 template <class CH>
    00569 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const Int32List& values)
    00570 {
    00571     if (values.empty()) return;
    00572     if (!builder.empty()) SPACE;
    00573     Int32List::const_iterator itV = values.begin();
    00574     builder.append(*itV);
    00575     for (++itV; itV != values.end(); ++itV) { SPACE; VAL(*itV); }
    00576 }
    00577
    00578 template <class CH>
    00579 FCOLLADA_EXPORT void FUStringConversion::ToString(FUStringBuilderT<CH>& builder, const uint32* values, size_t count)
    00580 {
    00581     if (count > 0)
    00582     {
    00583         if (builder.empty()) { builder.append(*values++); --count; }
    00584         while (((intptr_t) count) > 0) { SPACE; VAL(*values++); --count; }
    00585     }
    00586 }
    00587
    00588 #endif // HAS_VECTORTYPES
    00589
    00590 #undef SPACE
    00591 #undef VAL