ASSERT_EQ (true, ex.Empty());
ASSERT_EQ (0, ex.GetBytesLeft());
ASSERT_EQ (nullptr, ex.Peek());
-
- ASSERT_EQ (nullptr, ex.Peek());
}
TEST_F (StringExtractorTest, InitMisc)
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[] = "";
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());
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());
}
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());
}
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());
}
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());
}
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());
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());
}
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());
}
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());
}
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());
}
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());
+}
+
+
// 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)
{
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;
}
//----------------------------------------------------------------------
}
//----------------------------------------------------------------------
+// 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<uint8_t>(m_packet[m_index])];
- const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(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
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.