From 32cb720c6fc5950df14b22afaf803488e9da5aed Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Fri, 26 Mar 2021 20:43:04 +0900 Subject: [PATCH] Support byte order setting The platform byte order is little-endian. The network byte order is defined to be always big-endian. The developer can change byte order of the parcel using parcel_set_byte_order(). Adds: - Parcel.SetByteOrder() - parcel_set_byte_order() Change-Id: I1f6b7166eec508862fe4771355a1a4a53093b3c6 Signed-off-by: Hwankyu Jhun --- parcel/CMakeLists.txt | 2 +- parcel/api/parcel.h | 16 +++++ parcel/parcel.cc | 104 ++++++++++++++++++++++++++---- parcel/parcel.hh | 13 +++- parcel/parcel_implementation.hh | 6 +- parcel/stub.cc | 12 ++++ tests/parcel_unittests/test_parcel.cc | 16 +++++ tests/parcel_unittests/test_parcel_cpp.cc | 12 +++- 8 files changed, 165 insertions(+), 16 deletions(-) diff --git a/parcel/CMakeLists.txt b/parcel/CMakeLists.txt index d8b9d2b..cac7578 100644 --- a/parcel/CMakeLists.txt +++ b/parcel/CMakeLists.txt @@ -2,7 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) PROJECT(parcel C CXX) INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(pkgs REQUIRED dlog capi-base-common) +PKG_CHECK_MODULES(pkgs REQUIRED dlog capi-base-common glib-2.0) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/parcel/api/parcel.h b/parcel/api/parcel.h index 6338030..640b3b1 100644 --- a/parcel/api/parcel.h +++ b/parcel/api/parcel.h @@ -513,6 +513,22 @@ int parcel_read(parcel_h parcel, parcelable_t *parcelable, void *data); */ int parcel_get_raw(parcel_h parcel, void **raw, uint32_t *size); +/** + * @brief Sets byte order of the parcel handle. + * @since_tizen 6.5 + * @remarks The platform byte order is little-endian. + * The network byte order is defined to always be big-endian. + * If you want to change byte order of the raw data of the parcel handle, + * you set byte order of the parcel handle using the function. + * @param[in] parcel The parcel handle + * @param[in] big_endian @ true, if byte order of the parcel is big-endian + * @return @c 0 on success, + * otherwise a negative error value + * @retval #PARCEL_ERROR_NONE Successful + * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter + */ +int parcel_set_byte_order(parcel_h parcle, bool big_endian); + #ifdef __cplusplus } #endif diff --git a/parcel/parcel.cc b/parcel/parcel.cc index f74f9dd..322f377 100644 --- a/parcel/parcel.cc +++ b/parcel/parcel.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "parcel/common.hh" #include "parcel/log_private.hh" #include "parcel/parcel.hh" @@ -22,7 +24,8 @@ namespace tizen_base { -Parcel::Impl::Impl(Parcel* parent) : parent_(parent) { +Parcel::Impl::Impl(Parcel* parent, bool big_endian) + : parent_(parent), big_endian_(big_endian) { } Parcel::Impl::~Impl() = default; @@ -69,6 +72,9 @@ bool Parcel::Impl::IsEmpty() { } void Parcel::Impl::WriteSize(uint32_t size) { + if (IsBigEndian()) + size = GUINT32_TO_BE(size); + auto* p = reinterpret_cast(&size); std::copy(p, p + sizeof(size), std::back_inserter(data_)); } @@ -89,6 +95,10 @@ int Parcel::Impl::ReadSize(uint32_t* size) { auto* p = reinterpret_cast(size); std::copy(&data_[reader_], &data_[reader_] + sizeof(uint32_t), p); reader_ += sizeof(uint32_t); + + if (IsBigEndian()) + *size = GUINT32_FROM_BE(*size); + return TIZEN_ERROR_NONE; } @@ -104,10 +114,19 @@ int Parcel::Impl::Read(T* d) { return TIZEN_ERROR_NONE; } -Parcel::Parcel() : impl_(new Impl(this)) { +void Parcel::Impl::SetByteOrder(bool big_endian) { + big_endian_ = big_endian; } -Parcel::Parcel(const void* buf, uint32_t size) : impl_(new Impl(this)) { +bool Parcel::Impl::IsBigEndian() { + return big_endian_; +} + +Parcel::Parcel(bool big_endian) : impl_(new Impl(this, big_endian)) { +} + +Parcel::Parcel(const void* buf, uint32_t size, bool big_endian) + : impl_(new Impl(this, big_endian)) { impl_->Write(buf, size); } @@ -115,6 +134,7 @@ Parcel::~Parcel() = default; Parcel::Parcel(const Parcel& p) : impl_(new Impl(this)) { + impl_->big_endian_ = p.impl_->big_endian_; std::copy(p.impl_->data_.begin(), p.impl_->data_.end(), std::back_inserter(impl_->data_)); impl_->reader_ = p.impl_->reader_; @@ -122,6 +142,7 @@ Parcel::Parcel(const Parcel& p) Parcel& Parcel::operator = (const Parcel& p) { if (this != &p) { + impl_->big_endian_ = p.impl_->big_endian_; std::copy(p.impl_->data_.begin(), p.impl_->data_.end(), std::back_inserter(impl_->data_)); impl_->reader_ = p.impl_->reader_; @@ -136,6 +157,7 @@ Parcel::Parcel(Parcel&& p) noexcept { Parcel& Parcel::operator = (Parcel&& p) noexcept { if (this != &p) { + impl_->big_endian_ = p.impl_->big_endian_; impl_->data_ = std::move(p.impl_->data_); impl_->reader_ = p.impl_->reader_; p.impl_->reader_ = 0; @@ -164,34 +186,58 @@ void Parcel::WriteByte(char val) { } void Parcel::WriteUInt16(uint16_t val) { + if (impl_->IsBigEndian()) + val = GUINT16_TO_BE(val); + impl_->Write(val); } void Parcel::WriteUInt32(uint32_t val) { + if (impl_->IsBigEndian()) + val = GUINT32_TO_BE(val); + impl_->Write(val); } void Parcel::WriteUInt64(uint64_t val) { + if (impl_->IsBigEndian()) + val = GUINT64_TO_BE(val); + impl_->Write(val); } void Parcel::WriteInt16(int16_t val) { + if (impl_->IsBigEndian()) + val = GINT16_TO_BE(val); + impl_->Write(val); } void Parcel::WriteInt32(int32_t val) { + if (impl_->IsBigEndian()) + val = GINT32_TO_BE(val); + impl_->Write(val); } void Parcel::WriteInt64(int64_t val) { + if (impl_->IsBigEndian()) + val = GINT64_TO_BE(val); + impl_->Write(val); } void Parcel::WriteFloat(float val) { + if (impl_->IsBigEndian()) + val = static_cast(GINT32_TO_BE(val)); + impl_->Write(val); } void Parcel::WriteDouble(double val) { + if (impl_->IsBigEndian()) + val = static_cast(GINT64_TO_BE(val)); + impl_->Write(val); } @@ -214,35 +260,67 @@ int Parcel::ReadByte(char* val) { } int Parcel::ReadUInt16(uint16_t* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = GUINT16_FROM_BE(*val); + + return ret; } int Parcel::ReadUInt32(uint32_t* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = GUINT32_FROM_BE(*val); + + return ret; } int Parcel::ReadUInt64(uint64_t* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = GUINT64_FROM_BE(*val); + + return ret; } int Parcel::ReadInt16(int16_t* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = GINT16_FROM_BE(*val); + + return ret; } int Parcel::ReadInt32(int32_t* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = GINT32_FROM_BE(*val); + + return ret; } int Parcel::ReadInt64(int64_t* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = GINT64_FROM_BE(*val); + + return ret; } int Parcel::ReadFloat(float* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = static_cast(GINT32_FROM_BE(*val)); + + return ret; } int Parcel::ReadDouble(double* val) { - return impl_->Read(val); + int ret = impl_->Read(val); + if (impl_->IsBigEndian()) + *val = static_cast(GINT64_FROM_BE(*val)); + + return ret; } std::string Parcel::ReadString() { @@ -315,4 +393,8 @@ int Parcel::ReadParcelable(Parcelable* parcelable) { return TIZEN_ERROR_NONE; } +void Parcel::SetByteOrder(bool big_endian) { + impl_->SetByteOrder(big_endian); +} + } // naemspace tizen_base diff --git a/parcel/parcel.hh b/parcel/parcel.hh index d924c93..87af7d7 100644 --- a/parcel/parcel.hh +++ b/parcel/parcel.hh @@ -54,16 +54,18 @@ class EXPORT Parcel final { /** * @brief Constructor. * @since_tizen 6.5 + * @param[in] big_endian @c true, if byte order of the parcel is big-endian */ - Parcel(); + Parcel(bool big_endian = false); /** * @brief Constructor * @since_tizen 6.5 * @param[in] buf The bytes to write * @param[in] size the size of bytes to write + * @param[in] big_endian @c true, if byte order of the parcel is big-endian */ - Parcel(const void* buf, uint32_t size); + Parcel(const void* buf, uint32_t size, bool big_endian = false); /** * @brief Destructor @@ -369,6 +371,13 @@ class EXPORT Parcel final { */ int ReadParcelable(Parcelable* parcelable); + /** + * @brief Sets byte order of the parcel. + * @since_tizen 6.5 + * @param[in] big_endian @c true, if byte order of the parcel is big-endian + */ + void SetByteOrder(bool big_endian); + private: class Impl; std::unique_ptr impl_; diff --git a/parcel/parcel_implementation.hh b/parcel/parcel_implementation.hh index 5ae09c5..ed6c62f 100644 --- a/parcel/parcel_implementation.hh +++ b/parcel/parcel_implementation.hh @@ -44,12 +44,16 @@ class Parcel::Impl { template int Read(T* d); + void SetByteOrder(bool big_endian); + bool IsBigEndian(); + private: friend class Parcel; - explicit Impl(Parcel* parent); + explicit Impl(Parcel* parent, bool big_endian = false); private: Parcel* parent_; + bool big_endian_; std::vector data_; uint64_t reader_ = 0; }; diff --git a/parcel/stub.cc b/parcel/stub.cc index da80f8c..ce62584 100644 --- a/parcel/stub.cc +++ b/parcel/stub.cc @@ -391,3 +391,15 @@ extern "C" EXPORT int parcel_get_raw(parcel_h parcel, void** raw, *size = raw_data.size(); return PARCEL_ERROR_NONE; } + +extern "C" EXPORT int parcel_set_byte_order(parcel_h parcel, + bool big_endian) { + if (parcel == nullptr) { + _E("Invalid parameter"); + return PARCEL_ERROR_INVALID_PARAMETER; + } + + auto* h = static_cast(parcel); + h->SetByteOrder(big_endian); + return PARCEL_ERROR_NONE; +} diff --git a/tests/parcel_unittests/test_parcel.cc b/tests/parcel_unittests/test_parcel.cc index a8aaa97..e05f553 100644 --- a/tests/parcel_unittests/test_parcel.cc +++ b/tests/parcel_unittests/test_parcel.cc @@ -522,3 +522,19 @@ TEST_F(ParcelTest, parcel_get_raw_N) { int ret = parcel_get_raw(nullptr, nullptr, nullptr); ASSERT_EQ(ret, PARCEL_ERROR_INVALID_PARAMETER); } + +TEST_F(ParcelTest, parcel_set_byte_order_P) { + int ret = parcel_set_byte_order(GetHandle(), true); + ASSERT_EQ(ret, PARCEL_ERROR_NONE); + ret = parcel_write_int32(GetHandle(), 1); + ASSERT_EQ(ret, PARCEL_ERROR_NONE); + int32_t val = 0; + ret = parcel_read_int32(GetHandle(), &val); + ASSERT_EQ(ret, PARCEL_ERROR_NONE); + ASSERT_EQ(val, 1); +} + +TEST_F(ParcelTest, parcel_set_byte_order_N) { + int ret = parcel_set_byte_order(nullptr, false); + ASSERT_EQ(ret, PARCEL_ERROR_INVALID_PARAMETER); +} diff --git a/tests/parcel_unittests/test_parcel_cpp.cc b/tests/parcel_unittests/test_parcel_cpp.cc index d3e5af0..ff52fb1 100644 --- a/tests/parcel_unittests/test_parcel_cpp.cc +++ b/tests/parcel_unittests/test_parcel_cpp.cc @@ -14,8 +14,9 @@ * limitations under the License. */ -#include #include +#include + #include #include @@ -236,3 +237,12 @@ TEST_F(ParcelCppTest, IsEmpty) { GetHandle().WriteInt32(1); ASSERT_EQ(GetHandle().IsEmpty(), false); } + +TEST_F(ParcelCppTest, SetByteOrder) { + GetHandle().SetByteOrder(true); + GetHandle().WriteInt32(1); + int32_t val = 0; + int ret = GetHandle().ReadInt32(&val); + ASSERT_EQ(ret, Parcel::Error::None); + ASSERT_EQ(val, 1); +} -- 2.7.4