TrinityCore
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 <vector>
26
27namespace Trinity
28{
29namespace Impl
30{
31template <typename Encoding>
33{
34 static constexpr std::size_t BITS_PER_CHAR = Encoding::BITS_PER_CHAR;
35 static constexpr std::size_t PAD_TO = std::lcm(8u, BITS_PER_CHAR);
36
37 static_assert(BITS_PER_CHAR < 8, "Encoding parameters are invalid");
38
39 static constexpr uint8 DECODE_ERROR = Encoding::DECODE_ERROR;
40 static constexpr char PADDING = Encoding::PADDING;
41
42 static constexpr std::size_t EncodedSize(std::size_t size)
43 {
44 size *= 8; // bits in input
45 if (size % PAD_TO) // pad to boundary
46 size += (PAD_TO - (size % PAD_TO));
47 return (size / BITS_PER_CHAR);
48 }
49
50 static constexpr std::size_t DecodedSize(std::size_t size)
51 {
52 size *= BITS_PER_CHAR; // bits in input
53 if (size % PAD_TO) // pad to boundary
54 size += (PAD_TO - (size % PAD_TO));
55 return (size / 8);
56 }
57
58 static std::string Encode(std::vector<uint8> const& data)
59 {
60 auto it = data.begin(), end = data.end();
61 if (it == end)
62 return "";
63
64 std::string s;
65 s.reserve(EncodedSize(data.size()));
66
67 uint8 bitsLeft = 8; // in current byte
68 do
69 {
70 uint8 thisC = 0;
71 if (bitsLeft >= BITS_PER_CHAR)
72 {
73 bitsLeft -= BITS_PER_CHAR;
74 thisC = ((*it >> bitsLeft) & ((1 << BITS_PER_CHAR)-1));
75 if (!bitsLeft)
76 {
77 ++it;
78 bitsLeft = 8;
79 }
80 }
81 else
82 {
83 thisC = (*it & ((1 << bitsLeft) - 1)) << (BITS_PER_CHAR - bitsLeft);
84 bitsLeft += (8 - BITS_PER_CHAR);
85 if ((++it) != end)
86 thisC |= (*it >> bitsLeft);
87 }
88 s.append(1, Encoding::Encode(thisC));
89 } while (it != end);
90
91 while (bitsLeft != 8)
92 {
93 if (bitsLeft > BITS_PER_CHAR)
94 bitsLeft -= BITS_PER_CHAR;
95 else
96 bitsLeft += (8 - BITS_PER_CHAR);
97 s.append(1, PADDING);
98 }
99
100 return s;
101 }
102
103 static Optional<std::vector<uint8>> Decode(std::string const& data)
104 {
105 auto it = data.begin(), end = data.end();
106 if (it == end)
107 return std::vector<uint8>();
108
109 std::vector<uint8> v;
110 v.reserve(DecodedSize(data.size()));
111
112 uint8 currentByte = 0;
113 uint8 bitsLeft = 8; // in current byte
114 while ((it != end) && (*it != PADDING))
115 {
116 uint8 cur = Encoding::Decode(*(it++));
117 if (cur == DECODE_ERROR)
118 return {};
119
120 if (bitsLeft > BITS_PER_CHAR)
121 {
122 bitsLeft -= BITS_PER_CHAR;
123 currentByte |= (cur << bitsLeft);
124 }
125 else
126 {
127 bitsLeft = BITS_PER_CHAR - bitsLeft; // in encoded char
128 currentByte |= (cur >> bitsLeft);
129 v.push_back(currentByte);
130 currentByte = (cur & ((1 << bitsLeft) - 1));
131 bitsLeft = 8 - bitsLeft; // in byte again
132 currentByte <<= bitsLeft;
133 }
134 }
135
136 if (currentByte)
137 return {}; // decode error, trailing non-zero bits
138
139 // process padding
140 while ((it != end) && (*it == PADDING) && (bitsLeft != 8))
141 {
142 if (bitsLeft > BITS_PER_CHAR)
143 bitsLeft -= BITS_PER_CHAR;
144 else
145 bitsLeft += (8 - BITS_PER_CHAR);
146 ++it;
147 }
148
149 // ok, all padding should be consumed, and we should be at end of string
150 if (it == end)
151 return v;
152
153 // anything else is an error
154 return {};
155 }
156};
157}
158}
159
160#endif
uint8_t uint8
Definition: Define.h:135
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
static constexpr std::size_t PAD_TO
Definition: BaseEncoding.h:35
static constexpr std::size_t BITS_PER_CHAR
Definition: BaseEncoding.h:34
static std::string Encode(std::vector< uint8 > const &data)
Definition: BaseEncoding.h:58
static Optional< std::vector< uint8 > > Decode(std::string const &data)
Definition: BaseEncoding.h:103
static constexpr char PADDING
Definition: BaseEncoding.h:40
static constexpr std::size_t EncodedSize(std::size_t size)
Definition: BaseEncoding.h:42
static constexpr uint8 DECODE_ERROR
Definition: BaseEncoding.h:39
static constexpr std::size_t DecodedSize(std::size_t size)
Definition: BaseEncoding.h:50