diff --git a/tinyxml2.h b/tinyxml2.h index c8011174..e70b97d6 100644 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -561,22 +561,28 @@ class TINYXML2_LIB XMLUtil static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); } + inline static bool IsSpace( unsigned char ch ) { + static constexpr uint64_t mask = + 1ULL << 9 + | 1ULL << 10 + | 1ULL << 11 + | 1ULL << 12 + | 1ULL << 13 + | 1ULL << 32; + if ( ch > 32 ) { + return false; + } + return mask >> ch & 1; + } - // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't - // correct, but simple, and usually works. static bool IsWhiteSpace( char p ) { - return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + return IsSpace( static_cast(p) ); } + // The method checks a char for matching ':', '_', alphabetic symbols or char >= 128 by bit mask inline static bool IsNameStartChar( unsigned char ch ) { - if ( ch >= 128 ) { - // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() - return true; - } - if ( isalpha( ch ) ) { - return true; - } - return ch == ':' || ch == '_'; + static constexpr uint64_t mask[4] = { 1ULL << 58 , 1ULL << 31 | 0x07FFFFFE07FFFFFE , ~0ULL, ~0ULL}; + return ( mask[ch >> 6] >> ( ch & 63 ) ) & 1; } inline static bool IsNameChar( unsigned char ch ) { diff --git a/xmltest.cpp b/xmltest.cpp index 75d4babf..41a06a24 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -2729,6 +2729,26 @@ int main( int argc, const char ** argv ) } } } + + // ---------- Testing IsNameStartChar ---------- + { + XMLUtil test; + // Tests validate key edge cases for IsNameStartChar without exhaustive coverage + XMLTest("IsNameStartChar(':')", true, test.IsNameStartChar(':')); + XMLTest("IsNameStartChar('_')", true, test.IsNameStartChar('_')); + XMLTest("IsNameStartChar('@')", false, test.IsNameStartChar('@')); + XMLTest("IsNameStartChar('A')", true, test.IsNameStartChar('A')); + XMLTest("IsNameStartChar('Z')", true, test.IsNameStartChar('Z')); + XMLTest("IsNameStartChar('[')", false, test.IsNameStartChar('[')); + XMLTest("IsNameStartChar('`')", false, test.IsNameStartChar('`')); + XMLTest("IsNameStartChar('a')", true, test.IsNameStartChar('a')); + XMLTest("IsNameStartChar('z')", true, test.IsNameStartChar('z')); + XMLTest("IsNameStartChar('{')", false, test.IsNameStartChar('{')); + XMLTest("IsNameStartChar(127)", false, test.IsNameStartChar(static_cast(127))); + XMLTest("IsNameStartChar(128)", true, test.IsNameStartChar(static_cast(128))); + XMLTest("IsNameStartChar(255)", true, test.IsNameStartChar(static_cast(255))); + } + // ----------- Performance tracking -------------- {