util: Improvements of string helpers
Improvements include:
- test cases for every string helper
- a new `printHex` helper to output hex conversion directly to std::ostream
- new `toHex` and `printHex` helpers that accept Buffer as input parameter
- a new `fromHex` helper to convert the supplied string to shared_ptr<const Buffer>
- replaced uses of CryptoPP routines with `toHex` and `fromHex` helpers where applicable
Change-Id: I092c9fa8fd21c413b53ea5624b82f769287bb42c
Refs: #3006
diff --git a/src/util/string-helper.hpp b/src/util/string-helper.hpp
index f9f37e4..e0ba8a6 100644
--- a/src/util/string-helper.hpp
+++ b/src/util/string-helper.hpp
@@ -17,131 +17,126 @@
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Jeff Thompson <jefft0@remap.ucla.edu>
*/
#ifndef NDN_STRING_HELPER_HPP
#define NDN_STRING_HELPER_HPP
-#include <string>
-#include <sstream>
+#include "../common.hpp"
+#include "../encoding/buffer.hpp"
namespace ndn {
-static const char* WHITESPACE_CHARS = " \n\r\t";
+class StringHelperError : public std::invalid_argument
+{
+public:
+ explicit
+ StringHelperError(const std::string& what)
+ : std::invalid_argument(what)
+ {
+ }
+};
+
+/**
+ * @brief Output the hex representation of the bytes in array to the output stream @p os
+ *
+ * @param os Output stream
+ * @param buffer The array of bytes
+ * @param length Size of the array
+ * @param isUpperCase if true (default) output use uppercase for hex values
+ *
+ * @example
+ * printHex(std::cout, "Hello, World!") outputs "48656C6C6F2C20776F726C6421"
+ * printHex(std::cout, "Hello, World!", false) outputs "48656c6c6f2c20776f726c6421"
+ *
+ * Each octet is always represented as two hex characters ("00" for octet==0).
+ *
+ * The output string is a continuous sequence of hex characters without any whitespace separators.
+ */
+void
+printHex(std::ostream& os, const uint8_t* buffer, size_t length, bool isUpperCase = true);
+
+/**
+ * @brief Output the hex representation of the bytes in the @p buffer to the output stream @p os
+ *
+ * @param os Output stream
+ * @param buffer The array of bytes
+ * @param isUpperCase if true (default) output use uppercase for hex values
+ */
+void
+printHex(std::ostream& os, const Buffer& buffer, bool isUpperCase = true);
/**
* @brief Return the hex representation of the bytes in array
*
- * @param array The array of bytes
- * @param arraySize Size of the array
+ * @param buffer The array of bytes
+ * @param length Size of the array
+ * @param isUpperCase if true (default) output use uppercase for hex values
+ *
+ * @example
+ * toHex("Hello, World!") == "48656C6C6F2C20776F726C6421"
+ * toHex("Hello, World!", false) == "48656c6c6f2c20776f726c6421"
+ *
+ * Each octet is always represented as two hex characters ("00" for octet==0).
+ *
+ * The output string is a continuous sequence of hex characters without any whitespace separators.
*/
-inline std::string
-toHex(const uint8_t* array, size_t arraySize)
-{
- if (array == 0 || arraySize == 0)
- return "";
+std::string
+toHex(const uint8_t* buffer, size_t length, bool isUpperCase = true);
- std::ostringstream result;
- result.flags(std::ios::hex | std::ios::uppercase);
- for (size_t i = 0; i < arraySize; ++i) {
- uint8_t x = array[i];
- if (x < 16)
- result << '0';
- result << (unsigned int)x;
- }
+/**
+ * @brief Return the hex representation of the bytes in the @p buffer to the output stream @p os
+ *
+ * @param buffer The array of bytes
+ * @param isUpperCase if true (default) output use uppercase for hex values
+ */
+std::string
+toHex(const Buffer& buffer, bool isUpperCase = true);
- return result.str();
-}
+/**
+ * @brief Convert the hex string to buffer
+ * @param hexString sequence of pairs of hex numbers (lower and upper case can be mixed)
+ * without any whitespace separators (e.g., "48656C6C6F2C20776F726C6421")
+ * @throw StringHelperError if input is invalid
+ */
+shared_ptr<const Buffer>
+fromHex(const std::string& hexString);
/**
* @brief Modify str in place to erase whitespace on the left
*/
-inline void
-trimLeft(std::string& str)
-{
- size_t found = str.find_first_not_of(WHITESPACE_CHARS);
- if (found != std::string::npos) {
- if (found > 0)
- str.erase(0, found);
- }
- else
- // All whitespace
- str.clear();
-}
+void
+trimLeft(std::string& str);
/**
* @brief Modify str in place to erase whitespace on the right
*/
-inline void
-trimRight(std::string& str)
-{
- size_t found = str.find_last_not_of(WHITESPACE_CHARS);
- if (found != std::string::npos) {
- if (found + 1 < str.size())
- str.erase(found + 1);
- }
- else
- // All whitespace
- str.clear();
-}
+void
+trimRight(std::string& str);
/**
* @brief Modify str in place to erase whitespace on the left and right
*/
-inline void
-trim(std::string& str)
-{
- trimLeft(str);
- trimRight(str);
-}
+void
+trim(std::string& str);
/**
* @brief Convert the hex character to an integer from 0 to 15, or -1 if not a hex character
*/
-inline int
-fromHexChar(uint8_t c)
-{
- if (c >= '0' && c <= '9')
- return (int)c - (int)'0';
- else if (c >= 'A' && c <= 'F')
- return (int)c - (int)'A' + 10;
- else if (c >= 'a' && c <= 'f')
- return (int)c - (int)'a' + 10;
- else
- return -1;
-}
+int
+fromHexChar(uint8_t c);
/**
- * @brief Return a copy of str, converting each escaped "%XX" to the char value
+ * @brief Decode a percent-encoded string
+ * @see RFC 3986 section 2
+ *
+ * When % is not followed by two hex characters, the output is not transformed.
+ *
+ * @example unescape("hello%20world") == "hello world"
+ * @example unescape("hello%20world%FooBar") == "hello world%FooBar"
*/
-inline std::string
-unescape(const std::string& str)
-{
- std::ostringstream result;
-
- for (size_t i = 0; i < str.size(); ++i) {
- if (str[i] == '%' && i + 2 < str.size()) {
- int hi = fromHexChar(str[i + 1]);
- int lo = fromHexChar(str[i + 2]);
-
- if (hi < 0 || lo < 0)
- // Invalid hex characters, so just keep the escaped string.
- result << str[i] << str[i + 1] << str[i + 2];
- else
- result << (uint8_t)(16 * hi + lo);
-
- // Skip ahead past the escaped value.
- i += 2;
- }
- else
- // Just copy through.
- result << str[i];
- }
-
- return result.str();
-}
+std::string
+unescape(const std::string& str);
} // namespace ndn