diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 43eb18383a5a786a40b17c4b6c19d37350813e70..557558c886d4fd2241aee7b3f3a42a75c06ae0bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,7 @@ set(SOURCES anbox/common/loop_device.cpp anbox/common/loop_device_allocator.cpp anbox/common/mount_entry.cpp + anbox/common/binary_writer.cpp anbox/testing/gtest_utils.h diff --git a/src/anbox/common/binary_writer.cpp b/src/anbox/common/binary_writer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6d4973cd95559441d75835af98bc7e5ec7f97bf --- /dev/null +++ b/src/anbox/common/binary_writer.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 Thomas Voss + * Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/common/binary_writer.h" + +#include +#include + +#include + +namespace { +bool is_little_endian() { + std::uint32_t v = 1; + return (*reinterpret_cast(&v) == 1); +} +} + +namespace anbox { +namespace common { + +BinaryWriter::BinaryWriter(std::vector::iterator begin, + std::vector::iterator end) : + begin_{begin}, current_{begin}, end_{end}, + byte_order_{is_little_endian() ? Order::Little : Order::Big} {} + +void BinaryWriter::set_byte_order(Order order) { + byte_order_ = order; +} + +void BinaryWriter::write_unsigned_short(std::uint16_t value) { + if (current_ + sizeof(value) > end_) + throw std::out_of_range{"Write buffer exhausted"}; + + std::uint16_t v = value; + switch (byte_order_) { + case Order::Big: + v = boost::endian::native_to_big(value); + break; + case Order::Little: + v = boost::endian::native_to_little(value); + break; + default: + break; + } + + *reinterpret_cast(&(*current_)) = v; + current_ += sizeof(v); +} + +void BinaryWriter::write_unsigned_long(std::uint32_t value) { + if (current_ + sizeof(value) > end_) + throw std::out_of_range{"Write buffer exhausted"}; + + std::uint32_t v = value; + switch (byte_order_) { + case Order::Big: + v = boost::endian::native_to_big(value); + break; + case Order::Little: + v = boost::endian::native_to_little(value); + break; + default: + break; + } + + *reinterpret_cast(&(*current_)) = v; + current_ += sizeof(v); +} + +void BinaryWriter::write_string(const char *s, std::size_t size) { + if (current_ + size > end_) + throw std::out_of_range{"Write buffer exhausted"}; + + memcpy(&(*current_), s, size); + current_ += size; +} + +void BinaryWriter::write_string_with_size(const std::string &str) { + write_string_with_size(str.c_str(), str.length()); +} + +void BinaryWriter::write_string_with_size(const char *s, std::size_t size) { + write_unsigned_short(size); + write_string(s, size); +} + +std::size_t BinaryWriter::bytes_written() const { + return current_ - begin_; +} +} // namespace common +} // namespace anbox diff --git a/src/anbox/common/binary_writer.h b/src/anbox/common/binary_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..f2aeefdfd0d2f90c978d1e0d15d0bcd02854259d --- /dev/null +++ b/src/anbox/common/binary_writer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Thomas Voss + * Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_COMMON_BINARY_WRITER_H_ +#define ANBOX_COMMON_BINARY_WRITER_H_ + +#include +#include +#include + +namespace anbox { +namespace common { +class BinaryWriter { + public: + enum class Order { + Big, + Little, + }; + + explicit BinaryWriter(std::vector::iterator begin_, + std::vector::iterator end_); + + void set_byte_order(Order order); + + void write_unsigned_short(std::uint16_t value); + void write_unsigned_long(std::uint32_t value); + void write_string(const char *s, std::size_t size); + void write_string_with_size(const std::string &str); + void write_string_with_size(const char *s, std::size_t size); + + std::size_t bytes_written() const; + + private: + std::vector::iterator begin_; + std::vector::iterator current_; + std::vector::iterator end_; + Order byte_order_; +}; +} // namespace common +} // namespace anbox + +#endif diff --git a/tests/anbox/common/CMakeLists.txt b/tests/anbox/common/CMakeLists.txt index 4d04ebef900e3af2f5169dcd3264222d20f4817c..facd443fe76312459493d12257a20667740ea922 100644 --- a/tests/anbox/common/CMakeLists.txt +++ b/tests/anbox/common/CMakeLists.txt @@ -2,3 +2,4 @@ ANBOX_ADD_TEST(message_channel_tests message_channel_tests.cpp) ANBOX_ADD_TEST(small_vector_tests small_vector_tests.cpp) ANBOX_ADD_TEST(type_traits_tests type_traits_tests.cpp) ANBOX_ADD_TEST(scope_ptr_tests scope_ptr_tests.cpp) +ANBOX_ADD_TEST(binary_writer_tests binary_writer_tests.cpp) diff --git a/tests/anbox/common/binary_writer_tests.cpp b/tests/anbox/common/binary_writer_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f12a233d351b6e99aa519f585d8aa7cf3b53391 --- /dev/null +++ b/tests/anbox/common/binary_writer_tests.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/common/binary_writer.h" + +#include + +namespace ac = anbox::common; + +using namespace ::testing; + +TEST(BinaryWriter, WritesUnsignedLong) { + std::vector buffer; + buffer.resize(sizeof(std::uint32_t) * 2); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.write_unsigned_long(0x10); + writer.write_unsigned_long(0x3322); + + ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x00, 0x00, 0x22, 0x33, 0x00, 0x00)); +} + +TEST(BinaryWriter, WriteUnsignedLongFailsWithExhaustedError) { + std::vector buffer; + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + EXPECT_THROW(writer.write_unsigned_long(0x11), std::out_of_range); +} + +TEST(BinaryWriter, WriteUnsignedLongWithChangedBinaryOrder) { + std::vector buffer; + buffer.resize(sizeof(std::uint32_t)); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Big); + writer.write_unsigned_long(0x11223344); + + ASSERT_THAT(buffer, ElementsAre(0x11, 0x22, 0x33, 0x44)); + + buffer.clear(); + buffer.resize(sizeof(std::uint32_t)); + + writer = ac::BinaryWriter(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Little); + writer.write_unsigned_long(0x11223344); + + ASSERT_THAT(buffer, ElementsAre(0x44, 0x33, 0x22, 0x11)); +} + +TEST(BinaryWriter, WriteUnsignedShort) { + std::vector buffer; + buffer.resize(sizeof(std::uint16_t) * 2); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.write_unsigned_short(0x10); + writer.write_unsigned_short(0x3322); + + ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x22, 0x33)); +} + +TEST(BinaryWriter, WriteUnsignedShortFailsWithExhaustedError) { + std::vector buffer; + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + EXPECT_THROW(writer.write_unsigned_short(0x11), std::out_of_range); +} + +TEST(BinaryWriter, WriteUnsignedShortWithChangedBinaryOrder) { + std::vector buffer; + buffer.resize(sizeof(std::uint16_t)); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Big); + writer.write_unsigned_short(0x1122); + + ASSERT_THAT(buffer, ElementsAre(0x11, 0x22)); + + buffer.clear(); + buffer.resize(sizeof(std::uint16_t)); + + writer = ac::BinaryWriter(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Little); + writer.write_unsigned_short(0x1122); + + ASSERT_THAT(buffer, ElementsAre(0x22, 0x11)); +}