* limitations under the License.
*/
+#include "parcel/parcel.hh"
+
#include <glib.h>
-#include <iostream>
#include <exception>
+#include <iostream>
#include <mutex>
#include "parcel/common.hh"
#include "parcel/log_private.hh"
-#include "parcel/parcel.hh"
#include "parcel/parcel_implementation.hh"
#include "parcel/parcelable.hh"
data_ = static_cast<uint8_t*>(malloc(data_capacity_));
}
+Parcel::Impl::Impl(Parcel* parent, uint8_t* start_pos, size_t data_size) {
+ data_ = start_pos;
+ data_capacity_ = data_size;
+ data_size_ = 0;
+ ownership_ = false;
+ pin_ = true;
+}
+
Parcel::Impl::~Impl() {
- free(data_);
+ if (ownership_) free(data_);
}
void Parcel::Impl::Write(const void* buf, uint32_t size) {
if (data_size_ + size > data_capacity_) {
+ if (!ownership_ || pin_) throw std::bad_alloc();
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();
+ if (data == nullptr) throw std::bad_alloc();
data_ = data;
data_capacity_ = new_size;
data_size_ += size;
}
+void Parcel::Impl::Reserve(uint32_t size) {
+ if (data_size_ + size > data_capacity_) {
+ if (!ownership_ || pin_) throw std::bad_alloc();
+ 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;
+ }
+
+ data_size_ += size;
+}
+
int Parcel::Impl::Read(void* buf, uint32_t size) {
- if (data_size_ == 0)
- return TIZEN_ERROR_NO_DATA;
+ if (data_size_ == 0) return TIZEN_ERROR_NO_DATA;
- if (reader_ + size > data_size_)
- return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
+ if (reader_ + size > data_size_) return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
memcpy(buf, data_ + reader_, size);
reader_ += size;
return TIZEN_ERROR_NONE;
}
-void Parcel::Impl::ResetReader() {
- reader_ = 0;
-}
+void Parcel::Impl::ResetReader() { reader_ = 0; }
bool Parcel::Impl::SetReader(uint32_t pos) {
- if (pos > data_size_)
- return false;
+ if (pos > data_size_) return false;
reader_ = pos;
return true;
}
Write(buf, size);
}
-bool Parcel::Impl::IsEmpty() {
- return data_size_ == 0;
-}
+bool Parcel::Impl::IsEmpty() { return data_size_ == 0; }
void Parcel::Impl::WriteSize(uint32_t size) {
- if (IsBigEndian())
- size = GUINT32_TO_BE(size);
+ if (IsBigEndian()) size = GUINT32_TO_BE(size);
Write<uint32_t>(size);
}
template <typename T>
void Parcel::Impl::Write(T d) {
if (data_size_ + sizeof(T) > data_capacity_) {
+ if (!ownership_ || pin_) throw std::bad_alloc();
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();
+ if (data == nullptr) throw std::bad_alloc();
data_ = data;
data_capacity_ = new_size;
}
int Parcel::Impl::ReadSize(uint32_t* size) {
- if (data_size_ == 0)
- return TIZEN_ERROR_NO_DATA;
+ if (data_size_ == 0) return TIZEN_ERROR_NO_DATA;
int ret = Read<uint32_t>(size);
- if (ret != TIZEN_ERROR_NONE)
- return ret;
+ if (ret != TIZEN_ERROR_NONE) return ret;
- if (IsBigEndian())
- *size = GUINT32_FROM_BE(*size);
+ if (IsBigEndian()) *size = GUINT32_FROM_BE(*size);
return TIZEN_ERROR_NONE;
}
template <typename T>
int Parcel::Impl::Read(T* d) {
- if (data_size_ == 0)
- return TIZEN_ERROR_NO_DATA;
+ if (data_size_ == 0) return TIZEN_ERROR_NO_DATA;
uint32_t size = static_cast<uint32_t>(sizeof(T));
- if (reader_ + size > data_size_)
- return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
+ if (reader_ + size > data_size_) return TIZEN_ERROR_ILLEGAL_BYTE_SEQ;
auto* p = reinterpret_cast<uint8_t*>(d);
memcpy(p, data_ + reader_, size);
}
void* Parcel::Impl::ReadPtr(uint32_t size) {
- if (reader_ + size > data_size_)
- return nullptr;
+ if (reader_ + size > data_size_) return nullptr;
auto* ptr = data_ + reader_;
reader_ += size;
return ptr;
}
-void Parcel::Impl::SetByteOrder(bool big_endian) {
- big_endian_ = big_endian;
-}
+void Parcel::Impl::SetByteOrder(bool big_endian) { big_endian_ = big_endian; }
-bool Parcel::Impl::IsBigEndian() const {
- return big_endian_;
-}
+bool Parcel::Impl::IsBigEndian() const { return big_endian_; }
-uint8_t* Parcel::Impl::GetData() const {
- return data_;
-}
+uint8_t* Parcel::Impl::GetData() const { return data_; }
-size_t Parcel::Impl::GetDataSize() const {
- return data_size_;
-}
+size_t Parcel::Impl::GetDataSize() const { return data_size_; }
+
+bool Parcel::Impl::SetDataSize(size_t size) {
+ if (size > data_capacity_) return false;
-size_t Parcel::Impl::GetDataCapacity() const {
- return data_capacity_;
+ data_size_ = size;
+ return true;
}
+size_t Parcel::Impl::GetDataCapacity() const { return data_capacity_; }
+
void Parcel::Impl::SetDataCapacity(size_t size) {
+ if (!ownership_) throw std::bad_alloc();
uint8_t* data = static_cast<uint8_t*>(realloc(data_, size));
- if (data == nullptr)
- throw std::bad_alloc();
+ if (data == nullptr) throw std::bad_alloc();
data_ = data;
data_capacity_ = size;
return data;
}
-uint32_t Parcel::Impl::GetReader() const {
- return reader_;
-}
+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();
+void Parcel::Impl::Pin() { pin_ = true; }
+
+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,
+ : impl_(new Impl(
+ this, size,
copy ? nullptr : static_cast<uint8_t*>(const_cast<void*>(buf)))) {
- if (impl_->data_ == nullptr)
- throw std::bad_alloc();
+ if (impl_->data_ == nullptr) throw std::bad_alloc();
- if (copy)
- impl_->Write(buf, size);
+ if (copy) impl_->Write(buf, size);
+}
+
+Parcel::Parcel(const Parcel& parcel, uint32_t start_pos, uint32_t size)
+ : impl_(new Impl(this, parcel.GetData() + start_pos, size)) {
+ if (!parcel.impl_->pin_) throw std::bad_alloc();
}
Parcel::~Parcel() {}
-Parcel::Parcel(const Parcel& p)
- : impl_(new Impl(this, kDataCapacity)) {
+Parcel::Parcel(const Parcel& p) : impl_(new Impl(this, kDataCapacity)) {
impl_->big_endian_ = p.impl_->big_endian_;
impl_->data_capacity_ = p.impl_->data_capacity_;
impl_->data_size_ = p.impl_->data_size_;
+ impl_->ownership_ = p.impl_->ownership_;
+ impl_->pin_ = p.impl_->pin_;
- uint8_t* data = static_cast<uint8_t*>(
- realloc(impl_->data_, impl_->data_capacity_));
- if (data == nullptr)
- throw std::bad_alloc();
+ if (impl_->ownership_) {
+ 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_->data_ = data;
+ memcpy(impl_->data_, p.impl_->data_, impl_->data_size_);
+ } else {
+ impl_->data_ = p.impl_->data_;
+ }
impl_->reader_ = p.impl_->reader_;
}
-Parcel& Parcel::operator = (const Parcel& p) {
+Parcel& Parcel::operator=(const Parcel& p) {
if (this != &p) {
impl_->big_endian_ = p.impl_->big_endian_;
impl_->data_capacity_ = p.impl_->data_capacity_;
impl_->data_size_ = p.impl_->data_size_;
+ impl_->ownership_ = p.impl_->ownership_;
+ impl_->pin_ = p.impl_->pin_;
- uint8_t* data = static_cast<uint8_t*>(
- realloc(impl_->data_, impl_->data_capacity_));
- if (data == nullptr)
- throw std::bad_alloc();
+ if (impl_->ownership_) {
+ 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_->data_ = data;
+ memcpy(impl_->data_, p.impl_->data_, impl_->data_size_);
+ } else {
+ impl_->data_ = p.impl_->data_;
+ }
impl_->reader_ = p.impl_->reader_;
}
return *this;
}
-Parcel::Parcel(Parcel&& p) noexcept
- : impl_(new Impl(this, kDataCapacity)) {
+Parcel::Parcel(Parcel&& p) noexcept : impl_(new Impl(this, kDataCapacity)) {
impl_->big_endian_ = p.impl_->big_endian_;
impl_->data_size_ = p.impl_->data_size_;
impl_->reader_ = p.impl_->reader_;
p.impl_->reader_ = 0;
+ impl_->ownership_ = p.impl_->ownership_;
+ impl_->pin_ = p.impl_->pin_;
+ p.impl_->pin_ = false;
}
-Parcel& Parcel::operator = (Parcel&& p) noexcept {
+Parcel& Parcel::operator=(Parcel&& p) noexcept {
if (this != &p) {
impl_->big_endian_ = p.impl_->big_endian_;
impl_->reader_ = p.impl_->reader_;
p.impl_->reader_ = 0;
+ impl_->ownership_ = p.impl_->ownership_;
+ impl_->pin_ = p.impl_->pin_;
+ p.impl_->pin_ = false;
}
return *this;
}
-bool Parcel::IsEmpty() const noexcept {
- return impl_->IsEmpty();
-}
+bool Parcel::IsEmpty() const noexcept { return impl_->IsEmpty(); }
-void Parcel::Write(const void* buf, uint32_t size) {
- impl_->Write(buf, size);
-}
+void Parcel::Write(const void* buf, uint32_t size) { impl_->Write(buf, size); }
-int Parcel::Read(void* buf, uint32_t size) {
- return impl_->Read(buf, size);
-}
+void Parcel::Reserve(uint32_t size) { impl_->Reserve(size); }
-void* Parcel::ReadPtr(uint32_t size) {
- return impl_->ReadPtr(size);
-}
+int Parcel::Read(void* buf, uint32_t size) { return impl_->Read(buf, size); }
-void Parcel::WriteBool(bool val) {
- impl_->Write<bool>(val);
-}
+void* Parcel::ReadPtr(uint32_t size) { return impl_->ReadPtr(size); }
-void Parcel::WriteByte(char val) {
- impl_->Write<char>(val);
-}
+void Parcel::WriteBool(bool val) { impl_->Write<bool>(val); }
+
+void Parcel::WriteByte(char val) { impl_->Write<char>(val); }
void Parcel::WriteUInt16(uint16_t val) {
- if (impl_->IsBigEndian())
- val = GUINT16_TO_BE(val);
+ if (impl_->IsBigEndian()) val = GUINT16_TO_BE(val);
impl_->Write<uint16_t>(val);
}
void Parcel::WriteUInt32(uint32_t val) {
- if (impl_->IsBigEndian())
- val = GUINT32_TO_BE(val);
+ if (impl_->IsBigEndian()) val = GUINT32_TO_BE(val);
impl_->Write<uint32_t>(val);
}
void Parcel::WriteUInt64(uint64_t val) {
- if (impl_->IsBigEndian())
- val = GUINT64_TO_BE(val);
+ if (impl_->IsBigEndian()) val = GUINT64_TO_BE(val);
impl_->Write<uint64_t>(val);
}
void Parcel::WriteInt16(int16_t val) {
- if (impl_->IsBigEndian())
- val = GINT16_TO_BE(val);
+ if (impl_->IsBigEndian()) val = GINT16_TO_BE(val);
impl_->Write<int16_t>(val);
}
void Parcel::WriteInt32(int32_t val) {
- if (impl_->IsBigEndian())
- val = GINT32_TO_BE(val);
+ if (impl_->IsBigEndian()) val = GINT32_TO_BE(val);
impl_->Write<int32_t>(val);
}
void Parcel::WriteInt64(int64_t val) {
- if (impl_->IsBigEndian())
- val = GINT64_TO_BE(val);
+ if (impl_->IsBigEndian()) val = GINT64_TO_BE(val);
impl_->Write<int64_t>(val);
}
void Parcel::WriteFloat(float val) {
- if (impl_->IsBigEndian())
- val = static_cast<float>(GINT32_TO_BE(val));
+ if (impl_->IsBigEndian()) val = static_cast<float>(GINT32_TO_BE(val));
impl_->Write<float>(val);
}
void Parcel::WriteDouble(double val) {
- if (impl_->IsBigEndian())
- val = static_cast<double>(GINT64_TO_BE(val));
+ if (impl_->IsBigEndian()) val = static_cast<double>(GINT64_TO_BE(val));
impl_->Write<double>(val);
}
impl_->Write(str, strlen(str) + 1);
}
-int Parcel::ReadBool(bool* val) {
- return impl_->Read<bool>(val);
-}
+int Parcel::ReadBool(bool* val) { return impl_->Read<bool>(val); }
-int Parcel::ReadByte(char* val) {
- return impl_->Read<char>(val);
-}
+int Parcel::ReadByte(char* val) { return impl_->Read<char>(val); }
int Parcel::ReadUInt16(uint16_t* val) {
int ret = impl_->Read<uint16_t>(val);
- if (impl_->IsBigEndian())
- *val = GUINT16_FROM_BE(*val);
+ if (impl_->IsBigEndian()) *val = GUINT16_FROM_BE(*val);
return ret;
}
int Parcel::ReadUInt32(uint32_t* val) {
int ret = impl_->Read<uint32_t>(val);
- if (impl_->IsBigEndian())
- *val = GUINT32_FROM_BE(*val);
+ if (impl_->IsBigEndian()) *val = GUINT32_FROM_BE(*val);
return ret;
}
int Parcel::ReadUInt64(uint64_t* val) {
int ret = impl_->Read<uint64_t>(val);
- if (impl_->IsBigEndian())
- *val = GUINT64_FROM_BE(*val);
+ if (impl_->IsBigEndian()) *val = GUINT64_FROM_BE(*val);
return ret;
}
int Parcel::ReadInt16(int16_t* val) {
int ret = impl_->Read<int16_t>(val);
- if (impl_->IsBigEndian())
- *val = GINT16_FROM_BE(*val);
+ if (impl_->IsBigEndian()) *val = GINT16_FROM_BE(*val);
return ret;
}
int Parcel::ReadInt32(int32_t* val) {
int ret = impl_->Read<int32_t>(val);
- if (impl_->IsBigEndian())
- *val = GINT32_FROM_BE(*val);
+ if (impl_->IsBigEndian()) *val = GINT32_FROM_BE(*val);
return ret;
}
int Parcel::ReadInt64(int64_t* val) {
int ret = impl_->Read<int64_t>(val);
- if (impl_->IsBigEndian())
- *val = GINT64_FROM_BE(*val);
+ if (impl_->IsBigEndian()) *val = GINT64_FROM_BE(*val);
return ret;
}
int Parcel::ReadFloat(float* val) {
int ret = impl_->Read<float>(val);
- if (impl_->IsBigEndian())
- *val = static_cast<float>(GINT32_FROM_BE(*val));
+ if (impl_->IsBigEndian()) *val = static_cast<float>(GINT32_FROM_BE(*val));
return ret;
}
int Parcel::ReadDouble(double* val) {
int ret = impl_->Read<double>(val);
- if (impl_->IsBigEndian())
- *val = static_cast<double>(GINT64_FROM_BE(*val));
+ if (impl_->IsBigEndian()) *val = static_cast<double>(GINT64_FROM_BE(*val));
return ret;
}
int Parcel::ReadCString(char** str) {
uint32_t len = 0;
int ret = impl_->ReadSize(&len);
- if (ret != TIZEN_ERROR_NONE)
- return ret;
+ if (ret != TIZEN_ERROR_NONE) return ret;
char* val = static_cast<char*>(calloc(len, sizeof(char)));
- if (val == nullptr)
- return TIZEN_ERROR_OUT_OF_MEMORY;
+ if (val == nullptr) return TIZEN_ERROR_OUT_OF_MEMORY;
ret = impl_->Read(val, len);
if (ret != TIZEN_ERROR_NONE) {
return TIZEN_ERROR_NONE;
}
-void Parcel::ResetReader() {
- impl_->ResetReader();
-}
+void Parcel::ResetReader() { impl_->ResetReader(); }
-bool Parcel::SetReader(uint32_t pos) {
- return impl_->SetReader(pos);
-}
+bool Parcel::SetReader(uint32_t pos) { return impl_->SetReader(pos); }
-void Parcel::Clear() {
- impl_->Clear();
-}
+void Parcel::Clear() { impl_->Clear(); }
-void Parcel::Reset(const void* buf, uint32_t size) {
- impl_->Reset(buf, size);
-}
+void Parcel::Reset(const void* buf, uint32_t size) { impl_->Reset(buf, size); }
void Parcel::WriteParcelable(const Parcelable& parcelable) {
parcelable.WriteToParcel(this);
return TIZEN_ERROR_NONE;
}
-void Parcel::SetByteOrder(bool big_endian) {
- impl_->SetByteOrder(big_endian);
-}
+void Parcel::SetByteOrder(bool big_endian) { impl_->SetByteOrder(big_endian); }
-uint8_t* Parcel::GetData() const {
- return impl_->GetData();
-}
+uint8_t* Parcel::GetData() const { return impl_->GetData(); }
-size_t Parcel::GetDataSize() const {
- return impl_->GetDataSize();
-}
+size_t Parcel::GetDataSize() const { return impl_->GetDataSize(); }
-size_t Parcel::GetDataCapacity() const {
- return impl_->GetDataCapacity();
-}
+bool Parcel::SetDataSize(size_t size) { return impl_->SetDataSize(size); }
-void Parcel::SetDataCapacity(size_t size) {
- impl_->SetDataCapacity(size);
-}
+size_t Parcel::GetDataCapacity() const { return impl_->GetDataCapacity(); }
-uint8_t* Parcel::Detach(size_t* size) {
- return impl_->Detach(size);
-}
+void Parcel::SetDataCapacity(size_t size) { impl_->SetDataCapacity(size); }
-uint32_t Parcel::GetReader() const {
- return impl_->GetReader();
-}
+uint8_t* Parcel::Detach(size_t* size) { return impl_->Detach(size); }
-std::vector<uint8_t> Parcel::ToRaw() {
- return impl_->ToRaw();
-}
+uint32_t Parcel::GetReader() const { return impl_->GetReader(); }
+
+std::vector<uint8_t> Parcel::ToRaw() { return impl_->ToRaw(); }
+
+void Parcel::Pin() { return impl_->Pin(); }
} // namespace tizen_base
auto raw = GetHandle().ToRaw();
ASSERT_EQ(raw.size(), sizeof(int32_t));
}
+
+TEST_F(ParcelCppTest, SubParcel) {
+ auto& p = GetHandle();
+
+ p.Reserve(400);
+ p.Pin();
+
+ Parcel w1(p, 0, 100);
+ Parcel w2(p, 100, 100);
+ Parcel w3(p, 200, 100);
+ Parcel w4(p, 300, 100);
+
+ w1.WriteString("Test subparcel1 1");
+ w2.WriteString("Test subparcel2 1");
+ w3.WriteString("Test subparcel3 1");
+ w4.WriteString("Test subparcel4 1");
+ w1.WriteString("Test subparcel1 2");
+ w2.WriteString("Test subparcel2 2");
+ w3.WriteString("Test subparcel3 2");
+ w4.WriteString("Test subparcel4 2");
+
+ Parcel r1(p, 0, 100);
+ Parcel r2(p, 100, 100);
+ Parcel r3(p, 200, 100);
+ Parcel r4(p, 300, 100);
+ r1.Reserve(100);
+ r2.Reserve(100);
+ r3.Reserve(100);
+ r4.Reserve(100);
+
+ ASSERT_EQ(r1.ReadString(), "Test subparcel1 1");
+ ASSERT_EQ(r1.ReadString(), "Test subparcel1 2");
+
+ ASSERT_EQ(r3.ReadString(), "Test subparcel3 1");
+ ASSERT_EQ(r3.ReadString(), "Test subparcel3 2");
+
+ ASSERT_EQ(r2.ReadString(), "Test subparcel2 1");
+ ASSERT_EQ(r2.ReadString(), "Test subparcel2 2");
+
+ ASSERT_EQ(r4.ReadString(), "Test subparcel4 1");
+ ASSERT_EQ(r4.ReadString(), "Test subparcel4 2");
+}
+
+TEST_F(ParcelCppTest, SubParcel2) {
+ auto& p = GetHandle();
+ int pos0 = p.GetDataSize();
+
+ p.WriteString("Test subparcel1 1");
+ p.WriteString("Test subparcel1 2");
+ int pos1 = p.GetDataSize();
+ p.WriteString("Test subparcel2 1");
+ p.WriteString("Test subparcel2 2");
+ int pos2 = p.GetDataSize();
+ p.WriteString("Test subparcel3 1");
+ p.WriteString("Test subparcel3 2");
+ int pos3 = p.GetDataSize();
+ p.WriteString("Test subparcel4 1");
+ p.WriteString("Test subparcel4 2");
+ int pos4 = p.GetDataSize();
+ p.Pin();
+
+ Parcel r1(p, pos0, pos1 - pos0);
+ Parcel r2(p, pos1, pos2 - pos1);
+ Parcel r3(p, pos2, pos3 - pos2);
+ Parcel r4(p, pos3, pos4 - pos3);
+ r1.Reserve(pos1 - pos0);
+ r2.Reserve(pos2 - pos1);
+ r3.Reserve(pos3 - pos2);
+ r4.Reserve(pos4 - pos3);
+
+ ASSERT_EQ(r1.ReadString(), "Test subparcel1 1");
+ ASSERT_EQ(r1.ReadString(), "Test subparcel1 2");
+
+ ASSERT_EQ(r3.ReadString(), "Test subparcel3 1");
+ ASSERT_EQ(r3.ReadString(), "Test subparcel3 2");
+
+ ASSERT_EQ(r2.ReadString(), "Test subparcel2 1");
+ ASSERT_EQ(r2.ReadString(), "Test subparcel2 2");
+
+ ASSERT_EQ(r4.ReadString(), "Test subparcel4 1");
+ ASSERT_EQ(r4.ReadString(), "Test subparcel4 2");
+}
+
+TEST_F(ParcelCppTest, SubParcel_N) {
+ auto& p = GetHandle();
+ p.Reserve(400);
+
+ EXPECT_THROW(Parcel w1(p, 0, 100), std::bad_alloc);
+}