base16.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Base16 encoder/decoder
  2. //
  3. // Platform: ISO C++ 98/11
  4. // $Id$
  5. //
  6. // (c) __vic 2016
  7. #ifndef __VIC_BASE16_H
  8. #define __VIC_BASE16_H
  9. #include<__vic/defs.h>
  10. #include<__vic/bits.h>
  11. #include<__vic/ascii.h>
  12. #include<exception>
  13. namespace __vic {
  14. //////////////////////////////////////////////////////////////////////////////
  15. class base16
  16. {
  17. template<class CharWriter, class Func>
  18. static void encode_byte_(unsigned char , CharWriter & , Func );
  19. template<class ByteReader, class CharWriter, class Func>
  20. static void encode_(ByteReader & , CharWriter & , Func );
  21. struct to_hex_digit_lower
  22. {
  23. char operator()(int d) const { return ascii::toxdigit_lower(d); }
  24. };
  25. struct to_hex_digit_upper
  26. {
  27. char operator()(int d) const { return ascii::toxdigit_upper(d); }
  28. };
  29. public:
  30. __VIC_SCOPED_ENUM_BEGIN(status)
  31. {
  32. ok,
  33. invalid_length,
  34. invalid_digit
  35. }
  36. __VIC_SCOPED_ENUM_END(status)
  37. struct bad_format : public std::exception
  38. {
  39. };
  40. struct bad_length : public bad_format
  41. {
  42. const char *what() const noexcept;
  43. };
  44. struct bad_digit : public bad_format
  45. {
  46. const char *what() const noexcept;
  47. };
  48. // Byte -> Text
  49. template<class CharWriter>
  50. static void encode_byte_lower(unsigned char , CharWriter );
  51. template<class CharWriter>
  52. static void encode_byte_upper(unsigned char , CharWriter );
  53. // Bytes -> Text
  54. template<class ByteReader, class CharWriter>
  55. static void encode_lower(ByteReader , CharWriter );
  56. template<class ByteReader, class CharWriter>
  57. static void encode_upper(ByteReader , CharWriter );
  58. // Text -> Bytes
  59. template<class CharReader, class ByteWriter>
  60. static void decode(CharReader , ByteWriter );
  61. template<class CharReader, class ByteWriter>
  62. static status_t try_decode(CharReader , ByteWriter );
  63. };
  64. //////////////////////////////////////////////////////////////////////////////
  65. //----------------------------------------------------------------------------
  66. template<class CharWriter, class Func>
  67. inline void base16::encode_byte_(
  68. unsigned char byte, CharWriter &w, Func to_hex_digit)
  69. {
  70. w.write(to_hex_digit(hi_nibble(byte)));
  71. w.write(to_hex_digit(lo_nibble(byte)));
  72. }
  73. //----------------------------------------------------------------------------
  74. template<class ByteReader, class CharWriter, class Func>
  75. inline void base16::encode_(ByteReader &r, CharWriter &w, Func to_hex_digit)
  76. {
  77. unsigned char byte;
  78. while(r.read(byte))
  79. encode_byte_(byte, w, to_hex_digit);
  80. }
  81. //----------------------------------------------------------------------------
  82. template<class CharWriter>
  83. void base16::encode_byte_lower(unsigned char byte, CharWriter w)
  84. {
  85. encode_byte_(byte, w, to_hex_digit_lower());
  86. }
  87. //----------------------------------------------------------------------------
  88. template<class CharWriter>
  89. void base16::encode_byte_upper(unsigned char byte, CharWriter w)
  90. {
  91. encode_byte_(byte, w, to_hex_digit_upper());
  92. }
  93. //----------------------------------------------------------------------------
  94. template<class ByteReader, class CharWriter>
  95. void base16::encode_lower(ByteReader r, CharWriter w)
  96. {
  97. encode_(r, w, to_hex_digit_lower());
  98. }
  99. //----------------------------------------------------------------------------
  100. template<class ByteReader, class CharWriter>
  101. void base16::encode_upper(ByteReader r, CharWriter w)
  102. {
  103. encode_(r, w, to_hex_digit_upper());
  104. }
  105. //----------------------------------------------------------------------------
  106. template<class CharReader, class ByteWriter>
  107. base16::status_t base16::try_decode(CharReader r, ByteWriter w)
  108. {
  109. bool first = true;
  110. int hi_part;
  111. char ch;
  112. while(r.read(ch))
  113. {
  114. int d = ascii::xdigit_to_number(ch);
  115. if(d < 0) return status::invalid_digit;
  116. if(first) hi_part = d;
  117. else w.write(static_cast<unsigned char>((hi_part << 4) | d));
  118. first = !first;
  119. }
  120. if(!first) return status::invalid_length; // the length is odd
  121. return status::ok;
  122. }
  123. //----------------------------------------------------------------------------
  124. template<class CharReader, class ByteWriter>
  125. void base16::decode(CharReader r, ByteWriter w)
  126. {
  127. switch(base16::try_decode(__VIC_STD_MOVE(r), __VIC_STD_MOVE(w)))
  128. {
  129. case status::ok: return;
  130. case status::invalid_length: throw bad_length();
  131. case status::invalid_digit: throw bad_digit();
  132. }
  133. // UNREACHABLE
  134. }
  135. //----------------------------------------------------------------------------
  136. } // namespace
  137. #endif // header guard