TrinityCore
BaseEncoding.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITY_BASE_ENCODING_HPP
19#define TRINITY_BASE_ENCODING_HPP
20
21#include "Define.h"
22#include "Optional.h"
23#include <numeric>
24#include <string>
25#include <string_view>
26#include <vector>
27
28namespace Trinity
29{
30namespace Impl
31{
32template <typename Encoding>
34{
35 static constexpr std::size_t BITS_PER_CHAR = Encoding::BITS_PER_CHAR;
36 static constexpr std::size_t PAD_TO = std::lcm(8u, BITS_PER_CHAR);
37
38 static_assert(BITS_PER_CHAR < 8, "Encoding parameters are invalid");
39
40 static constexpr uint8 DECODE_ERROR = Encoding::DECODE_ERROR;
41 static constexpr char PADDING = Encoding::PADDING;
42
43 static constexpr std::size_t EncodedSize(std::size_t size)
44 {
45 size *= 8; // bits in input
46 if (size % PAD_TO) // pad to boundary
47 size += (PAD_TO - (size % PAD_TO));
48 return (size / BITS_PER_CHAR);
49 }
50
51 static constexpr std::size_t DecodedSize(std::size_t size)
52 {
53 size *= BITS_PER_CHAR; // bits in input
54 if (size % PAD_TO) // pad to boundary
55 size += (PAD_TO - (size % PAD_TO));
56 return (size / 8);
57 }
58
59 static std::string Encode(std::vector<uint8> const& data)
60 {
61 auto it = data.begin(), end = data.end();
62 if (it == end)
63 return "";
64
65 std::string s;
66 s.reserve(EncodedSize(data.size()));
67
68 uint8 bitsLeft = 8; // in current byte
69 do
70 {
71 uint8 thisC = 0;
72 if (bitsLeft >= BITS_PER_CHAR)
73 {
74 bitsLeft -= BITS_PER_CHAR;
75 thisC = ((*it >> bitsLeft) & ((1 << BITS_PER_CHAR)-1));
76 if (!bitsLeft)
77 {
78 ++it;
79 bitsLeft = 8;
80 }
81 }
82 else
83 {
84 thisC = (*it & ((1 << bitsLeft) - 1)) << (BITS_PER_CHAR - bitsLeft);
85 bitsLeft += (8 - BITS_PER_CHAR);
86 if ((++it) != end)
87 thisC |= (*it >> bitsLeft);
88 }
89 s.append(1, Encoding::Encode(thisC));
90 } while (it != end);
91
92 while (bitsLeft != 8)
93 {
94 if (bitsLeft > BITS_PER_CHAR)
95 bitsLeft -= BITS_PER_CHAR;
96 else
97 bitsLeft += (8 - BITS_PER_CHAR);
98 s.append(1, PADDING);
99 }
100
101 return s;
102 }
103
104 static Optional<std::vector<uint8>> Decode(std::string_view data)
105 {
106 auto it = data.begin(), end = data.end();
107 if (it == end)
108 return std::vector<uint8>();
109
110 std::vector<uint8> v;
111 v.reserve(DecodedSize(data.size()));
112
113 uint8 currentByte = 0;
114 uint8 bitsLeft = 8; // in current byte
115 while ((it != end) && (*it != PADDING))
116 {
117 uint8 cur = Encoding::Decode(*(it++));
118 if (cur == DECODE_ERROR)
119 return {};
120
121 if (bitsLeft > BITS_PER_CHAR)
122 {
123 bitsLeft -= BITS_PER_CHAR;
124 currentByte |= (cur << bitsLeft);
125 }
126 else
127 {
128 bitsLeft = BITS_PER_CHAR - bitsLeft; // in encoded char
129 currentByte |= (cur >> bitsLeft);
130 v.push_back(currentByte);
131 currentByte = (cur & ((1 << bitsLeft) - 1));
132 bitsLeft = 8 - bitsLeft; // in byte again
133 currentByte <<= bitsLeft;
134 }
135 }
136
137 if (currentByte)
138 return {}; // decode error, trailing non-zero bits
139
140 // process padding
141 while ((it != end) && (*it == PADDING) && (bitsLeft != 8))
142 {
143 if (bitsLeft > BITS_PER_CHAR)
144 bitsLeft -= BITS_PER_CHAR;
145 else
146 bitsLeft += (8 - BITS_PER_CHAR);
147 ++it;
148 }
149
150 // ok, all padding should be consumed, and we should be at end of string
151 if (it == end)
152 return v;
153
154 // anything else is an error
155 return {};
156 }
157};
158}
159}
160
161#endif
uint8_t uint8
Definition: Define.h:144
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
constexpr std::size_t size()
Definition: UpdateField.h:796
static constexpr std::size_t PAD_TO
Definition: BaseEncoding.h:36
static constexpr std::size_t BITS_PER_CHAR
Definition: BaseEncoding.h:35
static std::string Encode(std::vector< uint8 > const &data)
Definition: BaseEncoding.h:59
static Optional< std::vector< uint8 > > Decode(std::string_view data)
Definition: BaseEncoding.h:104
static constexpr char PADDING
Definition: BaseEncoding.h:41
static constexpr std::size_t EncodedSize(std::size_t size)
Definition: BaseEncoding.h:43
static constexpr uint8 DECODE_ERROR
Definition: BaseEncoding.h:40
static constexpr std::size_t DecodedSize(std::size_t size)
Definition: BaseEncoding.h:51