3ed31e8c2fa58600420ade7f800bb1b63335694c
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / third-party / base-n / basen.hpp
1 /**
2  * base-n, 1.0
3  * Copyright (C) 2012 Andrzej Zawadzki (azawadzki@gmail.com)
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22 **/
23 #ifndef BASEN_HPP
24 #define BASEN_HPP
25
26 #include <algorithm>
27 #include <cctype>
28 #include <cassert>
29 #include <cstring>
30
31 namespace bn
32 {
33
34 template<class Iter1, class Iter2>
35 void encode_b16(Iter1 start, Iter1 end, Iter2 out);
36
37 template<class Iter1, class Iter2>
38 void encode_b32(Iter1 start, Iter1 end, Iter2 out);
39
40 template<class Iter1, class Iter2>
41 void encode_b64(Iter1 start, Iter1 end, Iter2 out);
42
43 template<class Iter1, class Iter2>
44 void decode_b16(Iter1 start, Iter1 end, Iter2 out);
45
46 template<class Iter1, class Iter2>
47 void decode_b32(Iter1 start, Iter1 end, Iter2 out);
48
49 template<class Iter1, class Iter2>
50 void decode_b64(Iter1 start, Iter1 end, Iter2 out);
51
52 namespace impl
53 {
54
55 const int Error = -1;
56
57 namespace {
58
59 char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
60 {
61     assert(start_bit + bits_count < 8);
62     // shift extracted bits to the beginning of the byte
63     char t1 = value >> (8 - bits_count - start_bit);
64     // mask out bits on the left
65     char t2 = t1 & ~(0xff << bits_count);
66     return t2;
67 }
68
69 char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
70 {
71     assert(start_bit + bits_count < 16);
72     size_t bits_count_in_previous = 8 - start_bit;
73     size_t bits_count_in_next = bits_count - bits_count_in_previous;
74     char t1 = previous << bits_count_in_next;
75     char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
76     return (t1 | t2) & ~(0xff << bits_count);
77 }
78
79 }
80
81 struct b16_conversion_traits
82 {
83     static size_t group_length()
84     {
85        return 4;
86     }
87
88     static char encode(unsigned int index)
89     {
90         const char* const dictionary = "0123456789ABCDEF";
91         assert(index < strlen(dictionary));
92         return dictionary[index];
93     }
94
95     static char decode(char c)
96     {
97         if (c >= '0' && c <= '9') {
98             return c - '0';
99         } else if (c >= 'A' && c <= 'F') {
100             return c - 'A' + 10;
101         }
102         return Error;
103     }
104 };
105
106 struct b32_conversion_traits
107 {
108     static size_t group_length()
109     {
110        return 5;
111     }
112
113     static char encode(unsigned int index)
114     {
115         const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
116         assert(index < strlen(dictionary));
117         return dictionary[index];
118     }
119
120     static char decode(char c)
121     {
122         if (c >= 'A' && c <= 'Z') {
123             return c - 'A';
124         } else if (c >= '2' && c <= '7') {
125             return c - '2' + 26;
126         }
127         return Error;
128     }
129 };
130
131 struct b64_conversion_traits
132 {
133     static size_t group_length()
134     {
135        return 6;
136     }
137
138     static char encode(unsigned int index)
139     {
140         const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
141         assert(index < strlen(dictionary));
142         return dictionary[index];
143     }
144
145     static char decode(char c)
146     {
147         const int alph_len = 26;
148         if (c >= 'A' && c <= 'Z') {
149             return c - 'A';
150         } else if (c >= 'a' && c <= 'z') {
151             return c - 'a' + alph_len * 1;
152         } else if (c >= '0' && c <= '9') {
153             return c - '0' + alph_len * 2;
154         } else if (c == '+') {
155             return c - '+' + alph_len * 2 + 10;
156         } else if (c == '/') {
157             return c - '/' + alph_len * 2 + 11;
158         }
159         return Error;
160     }
161 };
162
163 template<class ConversionTraits, class Iter1, class Iter2>
164 void decode(Iter1 start, Iter1 end, Iter2 out)
165 {
166     Iter1 iter = start;
167     size_t output_current_bit = 0;
168     char buffer = 0;
169
170     while (iter != end) {
171         if (std::isspace(*iter)) {
172             ++iter;
173             continue;
174         }
175         char value = ConversionTraits::decode(*iter);
176         if (value == Error) {
177             // malformed data, but let's go on...
178             ++iter;
179             continue;
180         }
181         size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
182         if (bits_in_current_byte == ConversionTraits::group_length()) {
183             // the value fits within current byte, so we can extract it directly
184             buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
185             output_current_bit += ConversionTraits::group_length();
186             // check if we filled up current byte completely; in such case we flush output and continue
187             if (output_current_bit == 8) {
188                 *out++ = buffer;
189                 buffer = 0;
190                 output_current_bit = 0;
191             }
192         } else {
193             // the value spans across the current and the next byte
194             size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
195             // fill the current byte and flush it to our output
196             buffer |= value >> bits_in_next_byte;
197             *out++ = buffer;
198             buffer = 0;
199             // save the remainder of our value in the buffer; it will be flushed
200             // during next iterations
201             buffer |= value << (8 - bits_in_next_byte);
202             output_current_bit = bits_in_next_byte;
203         }
204         ++iter;
205     }
206 }
207
208 template<class ConversionTraits, class Iter1, class Iter2>
209 void encode(Iter1 start, Iter1 end, Iter2 out)
210 {
211     Iter1 iter = start;
212     size_t start_bit = 0;
213     bool has_backlog = false;
214     char backlog = 0;
215
216     while (has_backlog || iter != end) {
217         if (!has_backlog) {
218             if (start_bit + ConversionTraits::group_length() < 8) {
219                 // the value fits within single byte, so we can extract it
220                 // directly
221                 char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
222                 *out++ = ConversionTraits::encode(v);
223                 // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
224                 // to the next byte
225                 start_bit += ConversionTraits::group_length();
226             } else {
227                 // our bits are spanning across byte border; we need to keep the
228                 // starting point and move over to next byte.
229                 backlog = *iter++;
230                 has_backlog = true;
231             }
232         } else {
233             // encode value which is made from bits spanning across byte
234             // boundary
235             char v;
236             if (iter == end)
237                  v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
238             else
239                  v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
240             *out++ = ConversionTraits::encode(v);
241             has_backlog = false;
242             start_bit = (start_bit + ConversionTraits::group_length()) % 8;
243         }
244     }
245 }
246
247 } // impl
248
249 using namespace bn::impl;
250
251 template<class Iter1, class Iter2>
252 void encode_b16(Iter1 start, Iter1 end, Iter2 out)
253 {
254     encode<b16_conversion_traits>(start, end, out);
255 }
256
257 template<class Iter1, class Iter2>
258 void encode_b32(Iter1 start, Iter1 end, Iter2 out)
259 {
260     encode<b32_conversion_traits>(start, end, out);
261 }
262
263 template<class Iter1, class Iter2>
264 void encode_b64(Iter1 start, Iter1 end, Iter2 out)
265 {
266     encode<b64_conversion_traits>(start, end, out);
267 }
268
269 template<class Iter1, class Iter2>
270 void decode_b16(Iter1 start, Iter1 end, Iter2 out)
271 {
272     decode<b16_conversion_traits>(start, end, out);
273 }
274
275 template<class Iter1, class Iter2>
276 void decode_b32(Iter1 start, Iter1 end, Iter2 out)
277 {
278     decode<b32_conversion_traits>(start, end, out);
279 }
280
281 template<class Iter1, class Iter2>
282 void decode_b64(Iter1 start, Iter1 end, Iter2 out)
283 {
284     decode<b64_conversion_traits>(start, end, out);
285 }
286
287 } // bn
288
289 #endif // BASEN_HPP