*/
int parcel_set_byte_order(parcel_h parcle, bool big_endian);
+/**
+ * @brief Gets the size of the data capacity of the parcel handle.
+ * @since_tizen 7.0
+ * @param[in] parcel The parcel handle
+ * @param[out] size The size of the data capacity
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #PARCEL_ERROR_NONE Successful
+ * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int parcel_get_data_capacity(parcel_h parcel, size_t *size);
+
+/**
+ * @brief Sets the size of the data capacity of the parcel handle.
+ * @since_tizen 7.0
+ * @remarks The raw data will be reallocated using the given size.
+ * @param[in] parcel The parcel handle
+ * @param[in] size The size of the data capacity
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #PARCEL_ERROR_NONE Successful
+ * @retval #PARCEL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #PARCEL_ERROR_OUT_OF_MEMORY
+ */
+int parcel_set_data_capacity(parcel_h parcel, size_t size);
+
#ifdef __cplusplus
}
#endif
#include <glib.h>
+#include <exception>
+#include <mutex>
+
#include "parcel/common.hh"
#include "parcel/log_private.hh"
#include "parcel/parcel.hh"
#include "parcel/parcelable.hh"
namespace tizen_base {
+namespace {
+
+constexpr const size_t kDataCapacity = 128;
+
+} // namespace
-Parcel::Impl::Impl(Parcel* parent, bool big_endian)
- : parent_(parent), big_endian_(big_endian) {
+Parcel::Impl::Impl(Parcel* parent, size_t data_capacity, uint8_t* data)
+ : parent_(parent), data_capacity_(data_capacity), data_(data) {
+ if (data_ != nullptr)
+ data_size_ = data_capacity_;
+ else
+ data_ = static_cast<uint8_t*>(malloc(data_capacity_));
}
-Parcel::Impl::~Impl() {}
+Parcel::Impl::~Impl() {
+ free(data_);
+}
void Parcel::Impl::Write(const void* buf, uint32_t size) {
- auto* p = reinterpret_cast<const uint8_t*>(buf);
- data_.insert(data_.end(), p, p + size);
+ if (data_size_ + size > data_capacity_) {
+ size_t new_size = (data_capacity_ + size) * 3 / 2;
+ uint8_t* data = static_cast<uint8_t*>(realloc(data_, new_size));
+ if (data == nullptr)
+ throw std::bad_alloc();
+
+ data_ = data;
+ data_capacity_ = new_size;
+ }
+
+ memcpy(data_ + data_size_, buf, size);
+ data_size_ += size;
}
int Parcel::Impl::Read(void* buf, uint32_t size) {
- if (data_.size() == 0)
+ if (data_size_ == 0)
return TIZEN_ERROR_NO_DATA;
- if (reader_ + size > data_.size())
+ if (reader_ + size > data_size_)
return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
- auto* p = reinterpret_cast<uint8_t*>(buf);
- std::copy(&data_[reader_], &data_[reader_] + size, p);
+ memcpy(buf, data_ + reader_, size);
reader_ += size;
set_last_result(TIZEN_ERROR_NONE);
return TIZEN_ERROR_NONE;
}
-const std::vector<uint8_t>& Parcel::Impl::GetRaw() {
- return data_;
-}
-
void Parcel::Impl::ResetReader() {
reader_ = 0;
}
void Parcel::Impl::Clear() {
- data_.clear();
+ data_size_ = 0;
reader_ = 0;
}
}
bool Parcel::Impl::IsEmpty() {
- return data_.size() == 0;
+ return data_size_ == 0;
}
void Parcel::Impl::WriteSize(uint32_t size) {
template <typename T>
void Parcel::Impl::Write(T d) {
+ if (data_size_ + sizeof(T) > data_capacity_) {
+ size_t new_size = (data_capacity_ + sizeof(T)) * 3 / 2;
+ uint8_t* data = static_cast<uint8_t*>(realloc(data_, new_size));
+ if (data == nullptr)
+ throw std::bad_alloc();
+
+ data_ = data;
+ data_capacity_ = new_size;
+ }
+
auto* p = reinterpret_cast<uint8_t*>(&d);
- data_.insert(data_.end(), p, p + sizeof(T));
+ memcpy(data_ + data_size_, p, sizeof(T));
+ data_size_ += sizeof(T);
}
int Parcel::Impl::ReadSize(uint32_t* size) {
- if (data_.size() == 0)
+ if (data_size_ == 0)
return TIZEN_ERROR_NO_DATA;
- if (reader_ + sizeof(uint32_t) > data_.size())
- return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
-
- auto* p = reinterpret_cast<uint8_t*>(size);
- std::copy(&data_[reader_], &data_[reader_] + sizeof(uint32_t), p);
- reader_ += sizeof(uint32_t);
+ int ret = Read<uint32_t>(size);
+ if (ret != TIZEN_ERROR_NONE)
+ return ret;
if (IsBigEndian())
*size = GUINT32_FROM_BE(*size);
template <typename T>
int Parcel::Impl::Read(T* d) {
uint32_t size = sizeof(T);
- if (reader_ + size > data_.size())
+ if (reader_ + size > data_size_)
return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
auto* p = reinterpret_cast<uint8_t*>(d);
- std::copy(&data_[reader_], &data_[reader_] + size, p);
+ memcpy(p, data_ + reader_, size);
reader_ += size;
return TIZEN_ERROR_NONE;
}
big_endian_ = big_endian;
}
-bool Parcel::Impl::IsBigEndian() {
+bool Parcel::Impl::IsBigEndian() const {
return big_endian_;
}
-Parcel::Parcel(bool big_endian) : impl_(new Impl(this, big_endian)) {
+uint8_t* Parcel::Impl::GetData() const {
+ return data_;
}
-Parcel::Parcel(const void* buf, uint32_t size, bool big_endian)
- : impl_(new Impl(this, big_endian)) {
- impl_->Write(buf, size);
+size_t Parcel::Impl::GetDataSize() const {
+ return data_size_;
+}
+
+size_t Parcel::Impl::GetDataCapacity() const {
+ return data_capacity_;
+}
+
+void Parcel::Impl::SetDataCapacity(size_t size) {
+ uint8_t* data = static_cast<uint8_t*>(realloc(data_, size));
+ if (data == nullptr)
+ throw std::bad_alloc();
+
+ data_ = data;
+ data_capacity_ = size;
+}
+
+uint8_t* Parcel::Impl::Detach(size_t* size) {
+ uint8_t* data = data_;
+ *size = data_size_;
+ data_ = nullptr;
+ data_capacity_ = 0;
+ data_size_ = 0;
+ reader_= 0;
+ return data;
+}
+
+uint32_t Parcel::Impl::GetReader() const {
+ return reader_;
+}
+
+std::vector<uint8_t> Parcel::Impl::ToRaw() {
+ return std::vector<uint8_t>(data_, data_ + data_size_);
+}
+
+Parcel::Parcel()
+ : impl_(new Impl(this, kDataCapacity, nullptr)) {
+ if (impl_->data_ == nullptr)
+ throw std::bad_alloc();
+}
+
+Parcel::Parcel(const void* buf, uint32_t size, bool copy)
+ : impl_(new Impl(this, size,
+ copy ? nullptr : static_cast<uint8_t*>(const_cast<void*>(buf)))) {
+ if (impl_->data_ == nullptr)
+ throw std::bad_alloc();
+
+ if (copy)
+ impl_->Write(buf, size);
}
Parcel::~Parcel() {};
Parcel::Parcel(const Parcel& p)
- : impl_(new Impl(this)) {
+ : impl_(new Impl(this, kDataCapacity)) {
impl_->big_endian_ = p.impl_->big_endian_;
- impl_->data_ = p.impl_->data_;
+ impl_->data_capacity_ = p.impl_->data_capacity_;
+ impl_->data_size_ = p.impl_->data_size_;
+
+ uint8_t* data = static_cast<uint8_t*>(
+ realloc(impl_->data_, impl_->data_capacity_));
+ if (data == nullptr)
+ throw std::bad_alloc();
+
+ impl_->data_ = data;
+ memcpy(impl_->data_, p.impl_->data_, impl_->data_size_);
+
impl_->reader_ = p.impl_->reader_;
}
Parcel& Parcel::operator = (const Parcel& p) {
if (this != &p) {
impl_->big_endian_ = p.impl_->big_endian_;
- impl_->data_ = p.impl_->data_;
+ impl_->data_capacity_ = p.impl_->data_capacity_;
+ impl_->data_size_ = p.impl_->data_size_;
+
+ uint8_t* data = static_cast<uint8_t*>(
+ realloc(impl_->data_, impl_->data_capacity_));
+ if (data == nullptr)
+ throw std::bad_alloc();
+
+ impl_->data_ = data;
+ memcpy(impl_->data_, p.impl_->data_, impl_->data_size_);
+
impl_->reader_ = p.impl_->reader_;
}
return *this;
}
Parcel::Parcel(Parcel&& p) noexcept
- : impl_(new Impl(this)) {
- impl_ = std::move(p.impl_);
- impl_->parent_ = this;
+ : impl_(new Impl(this, kDataCapacity)) {
+ impl_->big_endian_ = p.impl_->big_endian_;
+
+ impl_->data_size_ = p.impl_->data_size_;
+ p.impl_->data_size_ = 0;
+
+ uint8_t* data = impl_->data_;
+ size_t data_capacity = impl_->data_capacity_;
+
+ impl_->data_ = p.impl_->data_;
+ impl_->data_capacity_ = p.impl_->data_capacity_;
+
+ p.impl_->data_ = data;
+ p.impl_->data_capacity_ = data_capacity;
+
+ impl_->reader_ = p.impl_->reader_;
+ p.impl_->reader_ = 0;
}
Parcel& Parcel::operator = (Parcel&& p) noexcept {
if (this != &p) {
impl_->big_endian_ = p.impl_->big_endian_;
- impl_->data_ = std::move(p.impl_->data_);
+
+ impl_->data_size_ = p.impl_->data_size_;
+ p.impl_->data_size_ = 0;
+
+ uint8_t* data = impl_->data_;
+ size_t data_capacity = impl_->data_capacity_;
+
+ impl_->data_ = p.impl_->data_;
+ impl_->data_capacity_ = p.impl_->data_capacity_;
+
+ p.impl_->data_ = data;
+ p.impl_->data_capacity_ = data_capacity;
+
impl_->reader_ = p.impl_->reader_;
p.impl_->reader_ = 0;
}
return TIZEN_ERROR_NONE;
}
-const std::vector<uint8_t>& Parcel::GetRaw() {
- return impl_->GetRaw();
-}
-
void Parcel::ResetReader() {
impl_->ResetReader();
}
impl_->SetByteOrder(big_endian);
}
+uint8_t* Parcel::GetData() const {
+ return impl_->GetData();
+}
+
+size_t Parcel::GetDataSize() const {
+ return impl_->GetDataSize();
+}
+
+size_t Parcel::GetDataCapacity() const {
+ return impl_->GetDataCapacity();
+}
+
+void Parcel::SetDataCapacity(size_t size) {
+ impl_->SetDataCapacity(size);
+}
+
+uint8_t* Parcel::Detach(size_t* size) {
+ return impl_->Detach(size);
+}
+
+uint32_t Parcel::GetReader() const {
+ return impl_->GetReader();
+}
+
+std::vector<uint8_t> Parcel::ToRaw() {
+ return impl_->ToRaw();
+}
+
} // namespace tizen_base
/**
* @brief Constructor.
* @since_tizen 6.5
- * @param[in] big_endian @c true, if byte order of the parcel is big-endian
*/
- Parcel(bool big_endian = false);
+ Parcel();
/**
* @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
+ * @param[in] copy If @c is true, this object copies bytes.
+ * If @c is false, this object takes ownership of @buf.
*/
- Parcel(const void* buf, uint32_t size, bool big_endian = false);
+ Parcel(const void* buf, uint32_t size, bool copy = true);
/**
* @brief Destructor
int ReadCString(char** str);
/**
- * @brief Gets the raw data of the parcel.
- * @since_tizen 6.5
- * @return The raw data
- */
- const std::vector<uint8_t>& GetRaw();
-
- /**
* @brief Resets the reader pointer of the parcel to the start.
* @since_tizen 6.5
*/
*/
void SetByteOrder(bool big_endian);
+ /**
+ * @brief Gets the raw data of the parcel.
+ * @since_tizen 7.0
+ * @return The raw data
+ */
+ uint8_t* GetData() const;
+
+ /**
+ * @breif Gets the size of the raw data of the parcel.
+ * @since_tizen 7.0
+ * @return The size of the raw data
+ */
+ size_t GetDataSize() const;
+
+ /**
+ * @brief Gets the size of the data capacity of the parcel.
+ * @since_tizen 7.0
+ * @return The size of the data capacity
+ */
+ size_t GetDataCapacity() const;
+
+ /**
+ * @breif Sets the size of the data capacity of the parcel.
+ * @since_tizen 7.0
+ * @param[in] size The size of the data capcity
+ */
+ void SetDataCapacity(size_t size);
+
+ /**
+ * @brief Detaches the raw data from the parcel.
+ * @since_tizen 7.0
+ * @param[out] size The size of the raw data
+ * @return The raw data
+ */
+ uint8_t* Detach(size_t* size);
+
+ /**
+ * @brief Gets the position of the reader of the parcel.
+ * @since_tizen 7.0
+ * @return The position of the reader
+ */
+ uint32_t GetReader() const;
+
+ /**
+ * @brief Converts the raw data of the parcel to the vector.
+ * @since_tizen 7.0
+ * @return The vector of the raw data
+ */
+ std::vector<uint8_t> ToRaw();
+
private:
class Impl;
std::unique_ptr<Impl> impl_;
void Write(const void* buf, uint32_t size);
int Read(void* buf, uint32_t size);
- const std::vector<uint8_t>& GetRaw();
void ResetReader();
void Clear();
void Reset(const void* buf, uint32_t size);
int Read(T* d);
void SetByteOrder(bool big_endian);
- bool IsBigEndian();
+ bool IsBigEndian() const;
+ uint8_t* GetData() const;
+ size_t GetDataSize() const;
+ size_t GetDataCapacity() const;
+ void SetDataCapacity(size_t size);
+ uint8_t* Detach(size_t* size);
+ uint32_t GetReader() const;
+ std::vector<uint8_t> ToRaw();
private:
friend class Parcel;
- explicit Impl(Parcel* parent, bool big_endian = false);
+ explicit Impl(Parcel* parent, size_t data_capacity, uint8_t* data = nullptr);
private:
Parcel* parent_;
- bool big_endian_;
- std::vector<uint8_t> data_;
- uint64_t reader_ = 0;
+ size_t data_capacity_;
+ bool big_endian_ = false;
+ size_t data_size_ = 0;
+ uint8_t* data_ = nullptr;
+ uint32_t reader_ = 0;
};
} // naemspace tizen_base
*/
#include "parcel/api/parcel.h"
+
+#include <exception>
+
#include "parcel/common.hh"
#include "parcel/log_private.hh"
#include "parcel/parcel.hh"
}
auto* h = static_cast<Parcel*>(parcel);
- auto& raw_data = h->GetRaw();
- *raw = reinterpret_cast<void*>(const_cast<uint8_t*>(&raw_data[0]));
- *size = raw_data.size();
+ *raw = reinterpret_cast<void*>(h->GetData());
+ *size = h->GetDataSize();
return PARCEL_ERROR_NONE;
}
h->SetByteOrder(big_endian);
return PARCEL_ERROR_NONE;
}
+
+extern "C" EXPORT int parcel_get_data_capacity(parcel_h parcel,
+ size_t* size) {
+ if (parcel == nullptr || size == nullptr) {
+ _E("Invalid parameter");
+ return PARCEL_ERROR_INVALID_PARAMETER;
+ }
+
+ auto* h = static_cast<Parcel*>(parcel);
+ *size = h->GetDataCapacity();
+ return PARCEL_ERROR_NONE;
+}
+
+extern "C" EXPORT int parcel_set_data_capacity(parcel_h parcel,
+ size_t size) {
+ if (parcel == nullptr || size == 0) {
+ _E("Invalid parameter");
+ return PARCEL_ERROR_INVALID_PARAMETER;
+ }
+
+ auto* h = static_cast<Parcel*>(parcel);
+ try {
+ h->SetDataCapacity(size);
+ } catch (const std::bad_alloc& e) {
+ _E("Exception occurs. error(%s)", e.what());
+ return PARCEL_ERROR_OUT_OF_MEMORY;
+ }
+
+ return PARCEL_ERROR_NONE;
+}
int ret = parcel_set_byte_order(nullptr, false);
ASSERT_EQ(ret, PARCEL_ERROR_INVALID_PARAMETER);
}
+
+TEST_F(ParcelTest, parcel_get_data_capacity_P) {
+ size_t size = 0;
+ int ret = parcel_get_data_capacity(GetHandle(), &size);
+ ASSERT_EQ(ret, PARCEL_ERROR_NONE);
+ ASSERT_NE(size, 0);
+}
+
+TEST_F(ParcelTest, parcel_get_data_capacity_N) {
+ int ret = parcel_get_data_capacity(nullptr, nullptr);
+ ASSERT_EQ(ret, PARCEL_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(ParcelTest, parcel_set_data_capacity_P) {
+ int ret = parcel_set_data_capacity(GetHandle(), 128);
+ ASSERT_EQ(ret, PARCEL_ERROR_NONE);
+
+ size_t size = 0;
+ ret = parcel_get_data_capacity(GetHandle(), &size);
+ ASSERT_EQ(ret, PARCEL_ERROR_NONE);
+ ASSERT_EQ(size, 128);
+}
+
+TEST_F(ParcelTest, parcel_set_data_capacity_N) {
+ int ret = parcel_set_data_capacity(nullptr, 0);
+ ASSERT_EQ(ret, PARCEL_ERROR_INVALID_PARAMETER);
+}
ASSERT_EQ(std::string(str), "TestCString");
}
-TEST_F(ParcelCppTest, GetRaw) {
- GetHandle().WriteInt32(0);
- auto& raw = GetHandle().GetRaw();
- ASSERT_EQ(raw.size(), sizeof(int32_t));
-}
-
TEST_F(ParcelCppTest, ResetReader) {
GetHandle().WriteInt32(1);
GetHandle().WriteInt32(2);
ASSERT_EQ(ret, Parcel::Error::None);
ASSERT_EQ(val, 1);
}
+
+TEST_F(ParcelCppTest, GetData) {
+ uint8_t* data = GetHandle().GetData();
+ ASSERT_NE(data, nullptr);
+}
+
+TEST_F(ParcelCppTest, GetDataSize) {
+ GetHandle().WriteInt32(1);
+ ASSERT_EQ(GetHandle().GetDataSize(), sizeof(int32_t));
+ GetHandle().WriteInt32(2);
+ ASSERT_EQ(GetHandle().GetDataSize(), sizeof(int32_t) + sizeof(int32_t));
+}
+
+TEST_F(ParcelCppTest, GetDataCapacity) {
+ size_t size = GetHandle().GetDataCapacity();
+ ASSERT_NE(size, 0);
+}
+
+TEST_F(ParcelCppTest, SetDataCapacity) {
+ GetHandle().SetDataCapacity(128);
+ size_t size = GetHandle().GetDataCapacity();
+ ASSERT_EQ(size, 128);
+}
+
+TEST_F(ParcelCppTest, Detach) {
+ GetHandle().WriteInt32(1);
+ size_t data_size = 0;
+ uint8_t* data = GetHandle().Detach(&data_size);
+ std::unique_ptr<uint8_t, decltype(std::free)*> data_auto(data, std::free);
+ ASSERT_NE(data, nullptr);
+ ASSERT_EQ(data_size, sizeof(int32_t));
+}
+
+TEST_F(ParcelCppTest, GetReader) {
+ GetHandle().WriteInt32(1);
+ GetHandle().WriteString("GetReader");
+ int32_t value = 0;
+ GetHandle().ReadInt32(&value);
+ uint32_t reader = GetHandle().GetReader();
+ ASSERT_EQ(reader, sizeof(int32_t));
+}
+
+TEST_F(ParcelCppTest, ToRaw) {
+ GetHandle().WriteInt32(0);
+ auto raw = GetHandle().ToRaw();
+ ASSERT_EQ(raw.size(), sizeof(int32_t));
+}