Index: gtest/unittest/Utility/StringExtractorTest.cpp =================================================================== --- gtest/unittest/Utility/StringExtractorTest.cpp +++ gtest/unittest/Utility/StringExtractorTest.cpp @@ -21,8 +21,6 @@ ASSERT_EQ (true, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); - - ASSERT_EQ (nullptr, ex.Peek()); } TEST_F (StringExtractorTest, InitMisc) @@ -38,6 +36,79 @@ ASSERT_EQ (kInitMiscString[0], *ex.Peek()); } +TEST_F (StringExtractorTest, DecodeHexU8_Underflow) +{ + const char kEmptyString[] = ""; + StringExtractor ex (kEmptyString); + + ASSERT_EQ (-1, ex.DecodeHexU8()); + ASSERT_EQ (true, ex.IsGood()); + ASSERT_EQ (0, ex.GetFilePos()); + ASSERT_EQ (true, ex.Empty()); + ASSERT_EQ (0, ex.GetBytesLeft()); + ASSERT_EQ (nullptr, ex.Peek()); +} + +TEST_F (StringExtractorTest, DecodeHexU8_Underflow2) +{ + const char kEmptyString[] = "1"; + StringExtractor ex (kEmptyString); + + ASSERT_EQ (-1, ex.DecodeHexU8()); + ASSERT_EQ (true, ex.IsGood()); + ASSERT_EQ (0, ex.GetFilePos()); + ASSERT_EQ (1, ex.GetBytesLeft()); + ASSERT_EQ ('1', *ex.Peek()); +} + +TEST_F (StringExtractorTest, DecodeHexU8_InvalidHex) +{ + const char kInvalidHex[] = "xa"; + StringExtractor ex (kInvalidHex); + + ASSERT_EQ (-1, ex.DecodeHexU8()); + ASSERT_EQ (true, ex.IsGood()); + ASSERT_EQ (0, ex.GetFilePos()); + ASSERT_EQ (2, ex.GetBytesLeft()); + ASSERT_EQ ('x', *ex.Peek()); +} + +TEST_F (StringExtractorTest, DecodeHexU8_InvalidHex2) +{ + const char kInvalidHex[] = "ax"; + StringExtractor ex (kInvalidHex); + + ASSERT_EQ (-1, ex.DecodeHexU8()); + ASSERT_EQ (true, ex.IsGood()); + ASSERT_EQ (0, ex.GetFilePos()); + ASSERT_EQ (2, ex.GetBytesLeft()); + ASSERT_EQ ('a', *ex.Peek()); +} + +TEST_F (StringExtractorTest, DecodeHexU8_Exact) +{ + const char kValidHexPair[] = "12"; + StringExtractor ex (kValidHexPair); + + ASSERT_EQ (0x12, ex.DecodeHexU8()); + ASSERT_EQ (true, ex.IsGood()); + ASSERT_EQ (2, ex.GetFilePos()); + ASSERT_EQ (0, ex.GetBytesLeft()); + ASSERT_EQ (nullptr, ex.Peek()); +} + +TEST_F (StringExtractorTest, DecodeHexU8_Extra) +{ + const char kValidHexPair[] = "1234"; + StringExtractor ex (kValidHexPair); + + ASSERT_EQ (0x12, ex.DecodeHexU8()); + ASSERT_EQ (true, ex.IsGood()); + ASSERT_EQ (2, ex.GetFilePos()); + ASSERT_EQ (2, ex.GetBytesLeft()); + ASSERT_EQ ('3', *ex.Peek()); +} + TEST_F (StringExtractorTest, GetHexU8_Underflow) { const char kEmptyString[] = ""; @@ -46,7 +117,6 @@ ASSERT_EQ (0xab, ex.GetHexU8(0xab)); ASSERT_EQ (false, ex.IsGood()); ASSERT_EQ (UINT64_MAX, ex.GetFilePos()); - ASSERT_STREQ (kEmptyString, ex.GetStringRef().c_str()); ASSERT_EQ (true, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); @@ -60,8 +130,6 @@ ASSERT_EQ (0xbc, ex.GetHexU8(0xbc)); ASSERT_EQ (false, ex.IsGood()); ASSERT_EQ (UINT64_MAX, ex.GetFilePos()); - ASSERT_STREQ (kOneNibble, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); } @@ -74,8 +142,6 @@ ASSERT_EQ (0xcd, ex.GetHexU8(0xcd)); ASSERT_EQ (false, ex.IsGood()); ASSERT_EQ (UINT64_MAX, ex.GetFilePos()); - ASSERT_STREQ (kInvalidHex, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); } @@ -88,8 +154,6 @@ ASSERT_EQ (0x12, ex.GetHexU8(0x12)); ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (2, ex.GetFilePos()); - ASSERT_STREQ (kValidHexPair, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); } @@ -102,8 +166,6 @@ ASSERT_EQ (0x12, ex.GetHexU8(0x12)); ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (2, ex.GetFilePos()); - ASSERT_STREQ (kValidHexPair, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (2, ex.GetBytesLeft()); ASSERT_EQ ('3', *ex.Peek()); } @@ -117,7 +179,6 @@ ASSERT_EQ (0xab, ex.GetHexU8(0xab, kSetEofOnFail)); ASSERT_EQ (false, ex.IsGood()); // this result seems inconsistent with kSetEofOnFail == false ASSERT_EQ (UINT64_MAX, ex.GetFilePos()); - ASSERT_STREQ (kEmptyString, ex.GetStringRef().c_str()); ASSERT_EQ (true, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); @@ -132,8 +193,6 @@ ASSERT_EQ (0xbc, ex.GetHexU8(0xbc, kSetEofOnFail)); ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (0, ex.GetFilePos()); - ASSERT_STREQ (kOneNibble, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (1, ex.GetBytesLeft()); ASSERT_EQ ('1', *ex.Peek()); } @@ -147,8 +206,6 @@ ASSERT_EQ (0xcd, ex.GetHexU8(0xcd, kSetEofOnFail)); ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (0, ex.GetFilePos()); - ASSERT_STREQ (kInvalidHex, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (2, ex.GetBytesLeft()); ASSERT_EQ ('x', *ex.Peek()); } @@ -162,8 +219,6 @@ ASSERT_EQ (0x12, ex.GetHexU8(0x12, kSetEofOnFail)); ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (2, ex.GetFilePos()); - ASSERT_STREQ (kValidHexPair, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (0, ex.GetBytesLeft()); ASSERT_EQ (nullptr, ex.Peek()); } @@ -177,8 +232,6 @@ ASSERT_EQ (0x12, ex.GetHexU8(0x12, kSetEofOnFail)); ASSERT_EQ (true, ex.IsGood()); ASSERT_EQ (2, ex.GetFilePos()); - ASSERT_STREQ (kValidHexPair, ex.GetStringRef().c_str()); - ASSERT_EQ (false, ex.Empty()); ASSERT_EQ (2, ex.GetBytesLeft()); ASSERT_EQ ('3', *ex.Peek()); } @@ -265,3 +318,89 @@ ASSERT_EQ(12, ex.GetBytesLeft()); ASSERT_EQ('2', *ex.Peek()); } + +TEST_F (StringExtractorTest, GetHexBytesAvail) +{ + const char kHexEncodedBytes[] = "abcdef0123456789xyzw"; + const size_t kValidHexPairs = 8; + StringExtractor ex(kHexEncodedBytes); + + uint8_t dst[kValidHexPairs]; + ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail (dst, kValidHexPairs)); + EXPECT_EQ(0xab,dst[0]); + EXPECT_EQ(0xcd,dst[1]); + EXPECT_EQ(0xef,dst[2]); + EXPECT_EQ(0x01,dst[3]); + EXPECT_EQ(0x23,dst[4]); + EXPECT_EQ(0x45,dst[5]); + EXPECT_EQ(0x67,dst[6]); + EXPECT_EQ(0x89,dst[7]); + + ASSERT_EQ(true, ex.IsGood()); + ASSERT_EQ(2*kValidHexPairs, ex.GetFilePos()); + ASSERT_EQ(false, ex.Empty()); + ASSERT_EQ(4, ex.GetBytesLeft()); + ASSERT_EQ('x', *ex.Peek()); +} + +TEST_F (StringExtractorTest, GetHexBytesAvail_Underflow) +{ + const char kHexEncodedBytes[] = "abcdef0123456789xyzw"; + const size_t kValidHexPairs = 8; + StringExtractor ex(kHexEncodedBytes); + + uint8_t dst[12]; + memset(dst, 0xef, sizeof(dst)); + ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail (dst, sizeof(dst))); + EXPECT_EQ(0xab,dst[0]); + EXPECT_EQ(0xcd,dst[1]); + EXPECT_EQ(0xef,dst[2]); + EXPECT_EQ(0x01,dst[3]); + EXPECT_EQ(0x23,dst[4]); + EXPECT_EQ(0x45,dst[5]); + EXPECT_EQ(0x67,dst[6]); + EXPECT_EQ(0x89,dst[7]); + // these bytes should be unchanged + EXPECT_EQ(0xef,dst[8]); + EXPECT_EQ(0xef,dst[9]); + EXPECT_EQ(0xef,dst[10]); + EXPECT_EQ(0xef,dst[11]); + + ASSERT_EQ(true, ex.IsGood()); + ASSERT_EQ(kValidHexPairs*2, ex.GetFilePos()); + ASSERT_EQ(false, ex.Empty()); + ASSERT_EQ(4, ex.GetBytesLeft()); + ASSERT_EQ('x', *ex.Peek()); +} + +TEST_F (StringExtractorTest, GetHexBytesAvail_Partial) +{ + const char kHexEncodedBytes[] = "abcdef0123456789xyzw"; + const size_t kReadBytes = 4; + StringExtractor ex(kHexEncodedBytes); + + uint8_t dst[12]; + memset(dst, 0xab, sizeof(dst)); + ASSERT_EQ(kReadBytes, ex.GetHexBytesAvail (dst, kReadBytes)); + EXPECT_EQ(0xab,dst[0]); + EXPECT_EQ(0xcd,dst[1]); + EXPECT_EQ(0xef,dst[2]); + EXPECT_EQ(0x01,dst[3]); + // these bytes should be unchanged + EXPECT_EQ(0xab,dst[4]); + EXPECT_EQ(0xab,dst[5]); + EXPECT_EQ(0xab,dst[6]); + EXPECT_EQ(0xab,dst[7]); + EXPECT_EQ(0xab,dst[8]); + EXPECT_EQ(0xab,dst[9]); + EXPECT_EQ(0xab,dst[10]); + EXPECT_EQ(0xab,dst[11]); + + ASSERT_EQ(true, ex.IsGood()); + ASSERT_EQ(kReadBytes*2, ex.GetFilePos()); + ASSERT_EQ(false, ex.Empty()); + ASSERT_EQ(12, ex.GetBytesLeft()); + ASSERT_EQ('2', *ex.Peek()); +} + + Index: source/Utility/StringExtractor.h =================================================================== --- source/Utility/StringExtractor.h +++ source/Utility/StringExtractor.h @@ -92,9 +92,13 @@ return m_packet.size() - m_index; return 0; } + char GetChar (char fail_value = '\0'); + int + DecodeHexU8(); + uint8_t GetHexU8 (uint8_t fail_value = 0, bool set_eof_on_fail = true); @@ -122,6 +126,9 @@ size_t GetHexBytes (void *dst, size_t dst_len, uint8_t fail_fill_value); + size_t + GetHexBytesAvail (void *dst, size_t dst_len); + uint64_t GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value); Index: source/Utility/StringExtractor.cpp =================================================================== --- source/Utility/StringExtractor.cpp +++ source/Utility/StringExtractor.cpp @@ -16,43 +16,6 @@ // Other libraries and framework includes // Project includes -static const uint8_t -g_hex_ascii_to_hex_integer[256] = { - - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, - 0x8, 0x9, 255, 255, 255, 255, 255, 255, - 255, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, -}; - static inline int xdigit_to_sint (char ch) { @@ -60,7 +23,9 @@ return 10 + ch - 'a'; if (ch >= 'A' && ch <= 'F') return 10 + ch - 'A'; - return ch - '0'; + if (ch >= '0' && ch <= '9') + return ch - '0'; + return -1; } //---------------------------------------------------------------------- @@ -129,25 +94,45 @@ } //---------------------------------------------------------------------- +// If a pair of valid hex digits exist at the head of the +// StringExtractor they are decoded into an unsigned byte and returned +// by this function +// +// If there is not a pair of valid hex digits at the head of the +// StringExtractor, it is left unchanged and -1 is returned +//---------------------------------------------------------------------- +int +StringExtractor::DecodeHexU8() +{ + if (GetBytesLeft() < 2) + { + return -1; + } + const int hi_nibble = xdigit_to_sint(m_packet[m_index]); + const int lo_nibble = xdigit_to_sint(m_packet[m_index+1]); + if (hi_nibble == -1 || lo_nibble == -1) + { + return -1; + } + m_index += 2; + return (uint8_t)((hi_nibble << 4) + lo_nibble); +} + +//---------------------------------------------------------------------- // Extract an unsigned character from two hex ASCII chars in the packet // string //---------------------------------------------------------------------- uint8_t StringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail) { - if (GetBytesLeft() >= 2) + int byte = DecodeHexU8(); + if (byte == -1) { - const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast(m_packet[m_index])]; - const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast(m_packet[m_index+1])]; - if (hi_nibble < 16 && lo_nibble < 16) - { - m_index += 2; - return (hi_nibble << 4) + lo_nibble; - } + if (set_eof_on_fail || m_index >= m_packet.size()) + m_index = UINT64_MAX; + return fail_value; } - if (set_eof_on_fail || m_index >= m_packet.size()) - m_index = UINT64_MAX; - return fail_value; + return (uint8_t)byte; } uint32_t @@ -372,6 +357,28 @@ return bytes_extracted; } +//---------------------------------------------------------------------- +// Decodes all valid hex encoded bytes at the head of the +// StringExtractor, limited by dst_len. +// +// Returns the number of bytes successfully decoded +//---------------------------------------------------------------------- +size_t +StringExtractor::GetHexBytesAvail (void *dst_void, size_t dst_len) +{ + uint8_t *dst = (uint8_t*)dst_void; + size_t bytes_extracted = 0; + while (bytes_extracted < dst_len) + { + int decode = DecodeHexU8(); + if (decode == -1) + { + break; + } + dst[bytes_extracted++] = (uint8_t)decode; + } + return bytes_extracted; +} // Consume ASCII hex nibble character pairs until we have decoded byte_size // bytes of data.