/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#include <iostream>
-#include <stdlib.h>
+#include <iterator>
+#include <vector>
+#include <algorithm>
+#include <cstdlib>
+
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/devel-api/builder/builder.h>
+#include <dali-toolkit/devel-api/builder/base64-encoding.h>
#include <dali/integration-api/events/touch-event-integ.h>
#include <dali-toolkit/dali-toolkit.h>
#include <test-button.h>
#include <test-animation-data.h>
+
#define STRINGIFY(A)#A
using namespace Dali;
END_TEST;
}
+
+
+int UtcDaliBase64EncodingP(void)
+{
+ std::vector<uint32_t> data = { 0, 1, 2, 3, 4, 5, std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max() };
+
+ Property::Value value;
+ EncodeBase64PropertyData( value, data );
+
+ std::cout << "Max uint32_t:" << std::numeric_limits<uint32_t>::max() << std::endl;
+ std::cout << "Input data: ";
+ std::ostream_iterator<uint32_t> out_it (std::cout,", ");
+ std::copy ( data.begin(), data.end(), out_it );
+ std::cout << std::endl;
+
+ std::string output;
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output, "AAAAAAEAAAACAAAAAwAAAAQAAAAFAAAAAAAAAP////8", TEST_LOCATION );
+
+ std::cout << "Output data: " << output << std::endl;
+
+ END_TEST;
+}
+
+int UtcDaliBase64EncodingN(void)
+{
+ tet_infoline( "Test encoding an empty vector returns empty string" );
+ std::vector<uint32_t> data;
+
+ Property::Value value;
+ EncodeBase64PropertyData( value, data );
+
+ std::string output;
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output.empty(), true, TEST_LOCATION );
+
+ END_TEST;
+}
+
+template <typename T>
+int b64l(std::vector<T>&data)
+{
+ auto lengthInBytes = 4*data.size();
+ return ceil( lengthInBytes * 1.33333f );
+}
+
+int UtcDaliBase64EncodingP02(void)
+{
+ tet_infoline( "Test encoding vectors of lengths m .. m+4 encode and decode back to the same length vectors" );
+
+ std::vector<uint32_t> testData;
+ for(int i=0; i<8; ++i ) // 8 chosen to stay within single string output
+ {
+ testData.push_back(i);
+ }
+ Property::Value value;
+ EncodeBase64PropertyData( value, testData );
+
+ std::string output;
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+ std::vector<uint32_t> outData;
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+ DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+ // n+1
+ testData.push_back( 12345 );
+ EncodeBase64PropertyData( value, testData );
+
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+ outData.clear();
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+ DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+ // n+2
+ testData.push_back( 67890 );
+ EncodeBase64PropertyData( value, testData );
+
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+ outData.clear();
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+ DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+ // n+3
+ testData.push_back( -1 );
+ EncodeBase64PropertyData( value, testData );
+
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+ outData.clear();
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+ DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+
+ END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP03(void)
+{
+ tet_infoline( "Test encoding a vector of length 12 has output within single string" );
+
+ std::vector<uint32_t> testData;
+ for(int i=0; i<12; ++i )
+ {
+ testData.push_back(i);
+ }
+ Property::Value value;
+ EncodeBase64PropertyData( value, testData );
+
+ std::string output;
+ DALI_TEST_CHECK( value.Get( output ) );
+ DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+ std::vector<uint32_t> outData;
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP04(void)
+{
+ tet_infoline( "Test encoding a vector of length 13 has output split over 2 strings" );
+
+ std::vector<uint32_t> testData;
+ for(int i=0; i<13; ++i )
+ {
+ testData.push_back(i);
+ }
+ Property::Value value;
+ EncodeBase64PropertyData( value, testData );
+
+ auto array = value.GetArray();
+ DALI_TEST_CHECK( array );
+
+ DALI_TEST_EQUALS( array->Count(), 2, TEST_LOCATION );
+
+ std::vector<uint32_t> outData;
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP05(void)
+{
+ tet_infoline( "Test encoding a vector of length 24 has output split over 2 strings" );
+
+ std::vector<uint32_t> testData;
+ for(int i=0; i<24; ++i )
+ {
+ testData.push_back(i);
+ }
+ Property::Value value;
+ EncodeBase64PropertyData( value, testData );
+
+ auto array = value.GetArray();
+ DALI_TEST_CHECK( array );
+
+ DALI_TEST_EQUALS( array->Count(), 2, TEST_LOCATION );
+
+ std::vector<uint32_t> outData;
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP06(void)
+{
+ tet_infoline( "Test encoding a vector of arbitrary length decodes OK." );
+
+ std::vector<uint32_t> testData;
+ for(int i=0; i<97; ++i )
+ {
+ testData.push_back(i);
+ }
+ Property::Value value;
+ EncodeBase64PropertyData( value, testData );
+
+ auto array = value.GetArray();
+ DALI_TEST_CHECK( array );
+
+ std::vector<uint32_t> outData;
+ DecodeBase64PropertyData( value, outData );
+ DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+ END_TEST;
+}
+
+
+int UtcDaliBase64DecodingN01(void)
+{
+ tet_infoline( "Test decoding empty string results in empty data" );
+
+ Property::Value value("");
+ std::vector<uint32_t> outputData;
+ DecodeBase64PropertyData( value, outputData);
+ DALI_TEST_EQUALS( outputData.size(), 0, TEST_LOCATION );
+ END_TEST;
+}
+
+
+int UtcDaliBase64DecodingN02(void)
+{
+ tet_infoline( "Test decoding array with non-string values results in empty data" );
+
+ Property::Array array;
+ array.Resize(2);
+ array[0] = "Stuff, things";
+ array[1] = 1;
+ Property::Value value(array);
+
+ std::vector<uint32_t> outputData;
+ DecodeBase64PropertyData( value, outputData);
+ DALI_TEST_EQUALS( outputData.size(), 0, TEST_LOCATION );
+ END_TEST;
+}
+
+int UtcDaliBase64DecodingP01(void)
+{
+ tet_infoline( "Test decoding string of known data gives expected result");
+
+ std::string testInput("//////7+/v4DAgEA");
+ std::vector<uint32_t> expectedResults = { 0xffffffff, 0xfefefefe, 0x00010203 };
+
+ std::vector<uint32_t> outputData;
+ DecodeBase64PropertyData(Property::Value(testInput), outputData);
+
+ DALI_TEST_EQUALS( std::equal( expectedResults.begin(), expectedResults.end(), outputData.begin() ), true,
+ TEST_LOCATION );
+
+ END_TEST;
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iterator>
+
+#include <dali/public-api/object/property-value.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali-toolkit/devel-api/builder/base64-encoding.h>
+#include <dali-toolkit/third-party/base-n/basen.hpp>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace
+{
+const int MAX_PROPERTY_STRING_LENGTH(64); // Cuts larger strings into blocks of this size.
+
+bool GetStringFromProperty( const Property::Value& value, std::string& output )
+{
+ bool extracted = false;
+ if( value.Get( output ) )
+ {
+ extracted = true;
+ }
+ else
+ {
+ Property::Array* array = value.GetArray();
+ if( array )
+ {
+ const unsigned int arraySize = array->Size();
+ for( unsigned int i = 0; i < arraySize; ++i )
+ {
+ std::string element;
+ if( array->GetElementAt( i ).Get( element ) )
+ {
+ extracted = true;
+ output += element;
+ }
+ else
+ {
+ // If property in array is anything other than a string, then it is invalid so break and clear output.
+ output.clear();
+ extracted = false;
+ break;
+ }
+ }
+ }
+ }
+ return extracted;
+}
+
+}//anonymous namespace
+
+bool DecodeBase64PropertyData( const Property::Value& value, std::vector<uint32_t>& outputData )
+{
+ bool decoded = false;
+ std::string encodedString;
+
+
+ if( GetStringFromProperty( value, encodedString ) )
+ {
+ std::vector<unsigned char> outputTmpData;
+ outputTmpData.reserve( ceil( encodedString.size() * 0.75f ) );
+ bn::decode_b64( encodedString.begin(), encodedString.end(), std::back_inserter(outputTmpData) );
+
+ outputData.clear();
+ outputData.resize( outputTmpData.size() / sizeof(uint32_t) );
+ // Treat as a block of data
+ memcpy( &outputData[0], &outputTmpData[0], outputTmpData.size() );
+
+ decoded = true;
+ }
+ return decoded;
+}
+
+void EncodeBase64PropertyData( Property::Value& value, const std::vector<uint32_t>& inputData )
+{
+ std::ostringstream oss;
+
+ bn::encode_b64( reinterpret_cast<const char*>(&inputData[0]),
+ reinterpret_cast<const char*>(&inputData[0]+inputData.size()),
+ std::ostream_iterator<unsigned char>(oss, "") );
+
+
+ std::string encodedString = oss.str();
+ if( encodedString.length() > MAX_PROPERTY_STRING_LENGTH)
+ {
+ // cut string up into blocks of MAX_PROPERTY_STRING_LENGTH and store to an array
+ auto numStrings = encodedString.length() / MAX_PROPERTY_STRING_LENGTH +
+ ((encodedString.length() % MAX_PROPERTY_STRING_LENGTH) != 0);
+
+ Property::Array array;
+ for(auto i=0u; i<numStrings; ++i)
+ {
+ array.PushBack( encodedString.substr( i*MAX_PROPERTY_STRING_LENGTH, MAX_PROPERTY_STRING_LENGTH));
+ }
+ value = array;
+ }
+ else
+ {
+ value = encodedString;
+ }
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TOOLKIT_BASE64_ENCODING_H
+#define DALI_TOOLKIT_BASE64_ENCODING_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Parses a Property::STRING or Property::ARRAY of STRINGS to
+ * retrieve a block of uint32_t data.
+ *
+ * Data can be encoded using the base64 encoding scheme to allow it to be used
+ * in JSON (The property system maps to JSON types).
+ *
+ * @param[in] value The property value to decode
+ * @param[out] outputData The output data block
+ * @return True if a data block was decoded successfully.
+ */
+bool DecodeBase64PropertyData( const Property::Value& value, std::vector<uint32_t>& outputData );
+
+/**
+ * @brief Convert a block of uint32_t data into a Property::STRING or ARRAY of STRINGs
+ * encoded using base64. This allows the data to be mapped to JSON easily.
+ *
+ * @param[out] value The value to write data into (to avoid copying).
+ * @param[in] inputData The input
+ */
+void EncodeBase64PropertyData( Property::Value& value, const std::vector<uint32_t>& inputData );
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_BASE64_ENCODING_H
# Add local source files here
devel_api_src_files = \
+ $(devel_api_src_dir)/builder/base64-encoding.cpp \
$(devel_api_src_dir)/builder/builder.cpp \
$(devel_api_src_dir)/builder/json-parser.cpp \
$(devel_api_src_dir)/builder/tree-node.cpp \
$(devel_api_src_dir)/controls/buttons/toggle-button.h
devel_api_builder_header_files = \
+ $(devel_api_src_dir)/builder/base64-encoding.h \
$(devel_api_src_dir)/builder/builder.h \
$(devel_api_src_dir)/builder/json-parser.h \
$(devel_api_src_dir)/builder/tree-node.h
--- /dev/null
+/**
+ * base-n, 1.0
+ * Copyright (C) 2012 Andrzej Zawadzki (azawadzki@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+**/
+#ifndef BASEN_HPP
+#define BASEN_HPP
+
+#include <algorithm>
+#include <cctype>
+#include <cassert>
+#include <cstring>
+
+namespace bn
+{
+
+template<class Iter1, class Iter2>
+void encode_b16(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void encode_b32(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void encode_b64(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void decode_b16(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void decode_b32(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void decode_b64(Iter1 start, Iter1 end, Iter2 out);
+
+namespace impl
+{
+
+const int Error = -1;
+
+namespace {
+
+char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
+{
+ assert(start_bit + bits_count < 8);
+ // shift extracted bits to the beginning of the byte
+ char t1 = value >> (8 - bits_count - start_bit);
+ // mask out bits on the left
+ char t2 = t1 & ~(0xff << bits_count);
+ return t2;
+}
+
+char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
+{
+ assert(start_bit + bits_count < 16);
+ size_t bits_count_in_previous = 8 - start_bit;
+ size_t bits_count_in_next = bits_count - bits_count_in_previous;
+ char t1 = previous << bits_count_in_next;
+ char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
+ return (t1 | t2) & ~(0xff << bits_count);
+}
+
+}
+
+struct b16_conversion_traits
+{
+ static size_t group_length()
+ {
+ return 4;
+ }
+
+ static char encode(unsigned int index)
+ {
+ const char* const dictionary = "0123456789ABCDEF";
+ assert(index < strlen(dictionary));
+ return dictionary[index];
+ }
+
+ static char decode(char c)
+ {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 10;
+ }
+ return Error;
+ }
+};
+
+struct b32_conversion_traits
+{
+ static size_t group_length()
+ {
+ return 5;
+ }
+
+ static char encode(unsigned int index)
+ {
+ const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+ assert(index < strlen(dictionary));
+ return dictionary[index];
+ }
+
+ static char decode(char c)
+ {
+ if (c >= 'A' && c <= 'Z') {
+ return c - 'A';
+ } else if (c >= '2' && c <= '7') {
+ return c - '2' + 26;
+ }
+ return Error;
+ }
+};
+
+struct b64_conversion_traits
+{
+ static size_t group_length()
+ {
+ return 6;
+ }
+
+ static char encode(unsigned int index)
+ {
+ const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ assert(index < strlen(dictionary));
+ return dictionary[index];
+ }
+
+ static char decode(char c)
+ {
+ const int alph_len = 26;
+ if (c >= 'A' && c <= 'Z') {
+ return c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ return c - 'a' + alph_len * 1;
+ } else if (c >= '0' && c <= '9') {
+ return c - '0' + alph_len * 2;
+ } else if (c == '+') {
+ return c - '+' + alph_len * 2 + 10;
+ } else if (c == '/') {
+ return c - '/' + alph_len * 2 + 11;
+ }
+ return Error;
+ }
+};
+
+template<class ConversionTraits, class Iter1, class Iter2>
+void decode(Iter1 start, Iter1 end, Iter2 out)
+{
+ Iter1 iter = start;
+ size_t output_current_bit = 0;
+ char buffer = 0;
+
+ while (iter != end) {
+ if (std::isspace(*iter)) {
+ ++iter;
+ continue;
+ }
+ char value = ConversionTraits::decode(*iter);
+ if (value == Error) {
+ // malformed data, but let's go on...
+ ++iter;
+ continue;
+ }
+ size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
+ if (bits_in_current_byte == ConversionTraits::group_length()) {
+ // the value fits within current byte, so we can extract it directly
+ buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
+ output_current_bit += ConversionTraits::group_length();
+ // check if we filled up current byte completely; in such case we flush output and continue
+ if (output_current_bit == 8) {
+ *out++ = buffer;
+ buffer = 0;
+ output_current_bit = 0;
+ }
+ } else {
+ // the value spans across the current and the next byte
+ size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
+ // fill the current byte and flush it to our output
+ buffer |= value >> bits_in_next_byte;
+ *out++ = buffer;
+ buffer = 0;
+ // save the remainder of our value in the buffer; it will be flushed
+ // during next iterations
+ buffer |= value << (8 - bits_in_next_byte);
+ output_current_bit = bits_in_next_byte;
+ }
+ ++iter;
+ }
+}
+
+template<class ConversionTraits, class Iter1, class Iter2>
+void encode(Iter1 start, Iter1 end, Iter2 out)
+{
+ Iter1 iter = start;
+ size_t start_bit = 0;
+ bool has_backlog = false;
+ char backlog = 0;
+
+ while (has_backlog || iter != end) {
+ if (!has_backlog) {
+ if (start_bit + ConversionTraits::group_length() < 8) {
+ // the value fits within single byte, so we can extract it
+ // directly
+ char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
+ *out++ = ConversionTraits::encode(v);
+ // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
+ // to the next byte
+ start_bit += ConversionTraits::group_length();
+ } else {
+ // our bits are spanning across byte border; we need to keep the
+ // starting point and move over to next byte.
+ backlog = *iter++;
+ has_backlog = true;
+ }
+ } else {
+ // encode value which is made from bits spanning across byte
+ // boundary
+ char v;
+ if (iter == end)
+ v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
+ else
+ v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
+ *out++ = ConversionTraits::encode(v);
+ has_backlog = false;
+ start_bit = (start_bit + ConversionTraits::group_length()) % 8;
+ }
+ }
+}
+
+} // impl
+
+using namespace bn::impl;
+
+template<class Iter1, class Iter2>
+void encode_b16(Iter1 start, Iter1 end, Iter2 out)
+{
+ encode<b16_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void encode_b32(Iter1 start, Iter1 end, Iter2 out)
+{
+ encode<b32_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void encode_b64(Iter1 start, Iter1 end, Iter2 out)
+{
+ encode<b64_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void decode_b16(Iter1 start, Iter1 end, Iter2 out)
+{
+ decode<b16_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void decode_b32(Iter1 start, Iter1 end, Iter2 out)
+{
+ decode<b32_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void decode_b64(Iter1 start, Iter1 end, Iter2 out)
+{
+ decode<b64_conversion_traits>(start, end, out);
+}
+
+} // bn
+
+#endif // BASEN_HPP