[dali_2.1.1] Merge branch 'devel/master'
[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
24 /*
25  * In the original file, static analysis complains about return type from decode methods
26  * not being testable against Error constant (due to difference of type sizes).
27  *
28  * Modified decode methods to return error through an out parameter instead.
29  */
30
31 #ifndef BASEN_HPP
32 #define BASEN_HPP
33
34 #include <algorithm>
35 #include <cctype>
36 #include <cassert>
37 #include <cstring>
38
39 namespace bn
40 {
41
42 template<class Iter1, class Iter2>
43 void encode_b16(Iter1 start, Iter1 end, Iter2 out);
44
45 template<class Iter1, class Iter2>
46 void encode_b32(Iter1 start, Iter1 end, Iter2 out);
47
48 template<class Iter1, class Iter2>
49 void encode_b64(Iter1 start, Iter1 end, Iter2 out);
50
51 template<class Iter1, class Iter2>
52 void decode_b16(Iter1 start, Iter1 end, Iter2 out);
53
54 template<class Iter1, class Iter2>
55 void decode_b32(Iter1 start, Iter1 end, Iter2 out);
56
57 template<class Iter1, class Iter2>
58 void decode_b64(Iter1 start, Iter1 end, Iter2 out);
59
60 namespace impl
61 {
62
63 const int Error = -1;
64
65 namespace {
66
67 char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
68 {
69     assert(start_bit + bits_count < 8);
70     // shift extracted bits to the beginning of the byte
71     char t1 = value >> (8 - bits_count - start_bit);
72     // mask out bits on the left
73     char t2 = t1 & ~(0xff << bits_count);
74     return t2;
75 }
76
77 char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
78 {
79     assert(start_bit + bits_count < 16);
80     size_t bits_count_in_previous = 8 - start_bit;
81     size_t bits_count_in_next = bits_count - bits_count_in_previous;
82     char t1 = previous << bits_count_in_next;
83     char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
84     return (t1 | t2) & ~(0xff << bits_count);
85 }
86
87 }
88
89 struct b16_conversion_traits
90 {
91     static size_t group_length()
92     {
93        return 4;
94     }
95
96     static char encode(unsigned int index)
97     {
98         const char* const dictionary = "0123456789ABCDEF";
99         assert(index < strlen(dictionary));
100         return dictionary[index];
101     }
102
103     /*
104      * In the original file, error code was passed through return value, but used int -1 (out of range of char).
105      * Separated error value from return value by using out parameter.
106      */
107     static char decode(char c, bool& error)
108     {
109         error=false;
110         if (c >= '0' && c <= '9') {
111             return c - '0';
112         } else if (c >= 'A' && c <= 'F') {
113             return c - 'A' + 10;
114         }
115         error=true;
116         return 0;
117     }
118 };
119
120 struct b32_conversion_traits
121 {
122     static size_t group_length()
123     {
124        return 5;
125     }
126
127     static char encode(unsigned int index)
128     {
129         const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
130         assert(index < strlen(dictionary));
131         return dictionary[index];
132     }
133
134     /*
135      * In the original file, error code was passed through return value, but used int -1 (out of range of char).
136      * Separated error value from return value by using out parameter.
137      */
138     static char decode(char c, bool& error)
139     {
140         error=false;
141         if (c >= 'A' && c <= 'Z') {
142             return c - 'A';
143         } else if (c >= '2' && c <= '7') {
144             return c - '2' + 26;
145         }
146         error=true;
147         return 0;
148     }
149 };
150
151 struct b64_conversion_traits
152 {
153     static size_t group_length()
154     {
155        return 6;
156     }
157
158     static char encode(unsigned int index)
159     {
160         const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
161         assert(index < strlen(dictionary));
162         return dictionary[index];
163     }
164
165     /*
166      * In the original file, error code was passed through return value, but used int -1 (out of range of char).
167      * Separated error value from return value by using out parameter.
168      */
169     static char decode(char c, bool& error)
170     {
171         error=false;
172         const int alph_len = 26;
173         if (c >= 'A' && c <= 'Z') {
174             return c - 'A';
175         } else if (c >= 'a' && c <= 'z') {
176             return c - 'a' + alph_len * 1;
177         } else if (c >= '0' && c <= '9') {
178             return c - '0' + alph_len * 2;
179         } else if (c == '+') {
180             return c - '+' + alph_len * 2 + 10;
181         } else if (c == '/') {
182             return c - '/' + alph_len * 2 + 11;
183         }
184         error=true;
185         return 0;
186     }
187 };
188
189 template<class ConversionTraits, class Iter1, class Iter2>
190 void decode(Iter1 start, Iter1 end, Iter2 out)
191 {
192     Iter1 iter = start;
193     size_t output_current_bit = 0;
194     char buffer = 0;
195
196     while (iter != end) {
197         if (std::isspace(*iter)) {
198             ++iter;
199             continue;
200         }
201
202         /*
203          * In the original file, error value was out of range of return type.
204          * Separated error value from return value by using out parameter.
205          */
206         bool error=false;
207         char value = ConversionTraits::decode(*iter, error);
208         if (error) {
209             // malformed data, but let's go on...
210             ++iter;
211             continue;
212         }
213         size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
214         if (bits_in_current_byte == ConversionTraits::group_length()) {
215             // the value fits within current byte, so we can extract it directly
216             buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
217             output_current_bit += ConversionTraits::group_length();
218             // check if we filled up current byte completely; in such case we flush output and continue
219             if (output_current_bit == 8) {
220                 *out++ = buffer;
221                 buffer = 0;
222                 output_current_bit = 0;
223             }
224         } else {
225             // the value spans across the current and the next byte
226             size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
227             // fill the current byte and flush it to our output
228             buffer |= value >> bits_in_next_byte;
229             *out++ = buffer;
230             buffer = 0;
231             // save the remainder of our value in the buffer; it will be flushed
232             // during next iterations
233             buffer |= value << (8 - bits_in_next_byte);
234             output_current_bit = bits_in_next_byte;
235         }
236         ++iter;
237     }
238 }
239
240 template<class ConversionTraits, class Iter1, class Iter2>
241 void encode(Iter1 start, Iter1 end, Iter2 out)
242 {
243     Iter1 iter = start;
244     size_t start_bit = 0;
245     bool has_backlog = false;
246     char backlog = 0;
247
248     while (has_backlog || iter != end) {
249         if (!has_backlog) {
250             if (start_bit + ConversionTraits::group_length() < 8) {
251                 // the value fits within single byte, so we can extract it
252                 // directly
253                 char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
254                 *out++ = ConversionTraits::encode(v);
255                 // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
256                 // to the next byte
257                 start_bit += ConversionTraits::group_length();
258             } else {
259                 // our bits are spanning across byte border; we need to keep the
260                 // starting point and move over to next byte.
261                 backlog = *iter++;
262                 has_backlog = true;
263             }
264         } else {
265             // encode value which is made from bits spanning across byte
266             // boundary
267             char v;
268             if (iter == end)
269                  v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
270             else
271                  v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
272             *out++ = ConversionTraits::encode(v);
273             has_backlog = false;
274             start_bit = (start_bit + ConversionTraits::group_length()) % 8;
275         }
276     }
277 }
278
279 } // impl
280
281 using namespace bn::impl;
282
283 template<class Iter1, class Iter2>
284 void encode_b16(Iter1 start, Iter1 end, Iter2 out)
285 {
286     encode<b16_conversion_traits>(start, end, out);
287 }
288
289 template<class Iter1, class Iter2>
290 void encode_b32(Iter1 start, Iter1 end, Iter2 out)
291 {
292     encode<b32_conversion_traits>(start, end, out);
293 }
294
295 template<class Iter1, class Iter2>
296 void encode_b64(Iter1 start, Iter1 end, Iter2 out)
297 {
298     encode<b64_conversion_traits>(start, end, out);
299 }
300
301 template<class Iter1, class Iter2>
302 void decode_b16(Iter1 start, Iter1 end, Iter2 out)
303 {
304     decode<b16_conversion_traits>(start, end, out);
305 }
306
307 template<class Iter1, class Iter2>
308 void decode_b32(Iter1 start, Iter1 end, Iter2 out)
309 {
310     decode<b32_conversion_traits>(start, end, out);
311 }
312
313 template<class Iter1, class Iter2>
314 void decode_b64(Iter1 start, Iter1 end, Iter2 out)
315 {
316     decode<b64_conversion_traits>(start, end, out);
317 }
318
319 } // bn
320
321 #endif // BASEN_HPP