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

Generated on Thu Feb 14 16:58:36 2008 for FCollada by  doxygen 1.4.6-NO