Add support for decoding UTF16 to UTF8
This is helpful because many native service developers use std::string
internally, and String16 doesn't work very well with many C++
primitives.
Bug: 26729450
Test: Integration test appears to show this is correct.
Change-Id: Ib75068881da28fd8515685bcbcbe864ba3b7ec23
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index e30e65d..e50e155 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -743,6 +743,37 @@
return NULL;
}
+status_t Parcel::writeUtf8AsUtf16(const std::string& str) {
+ const uint8_t* strData = (uint8_t*)str.data();
+ const size_t strLen= str.length();
+ const ssize_t utf16Len = utf8_to_utf16_length(strData, strLen);
+ if (utf16Len < 0 || utf16Len> std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t err = writeInt32(utf16Len);
+ if (err) {
+ return err;
+ }
+
+ // Allocate enough bytes to hold our converted string and its terminating NULL.
+ void* dst = writeInplace((utf16Len + 1) * sizeof(char16_t));
+ if (!dst) {
+ return NO_MEMORY;
+ }
+
+ utf8_to_utf16(strData, strLen, (char16_t*)dst);
+
+ return NO_ERROR;
+}
+
+status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) {
+ if (!str) {
+ return writeInt32(-1);
+ }
+ return writeUtf8AsUtf16(*str);
+}
+
status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
{
if (!val) {
@@ -846,6 +877,15 @@
return writeNullableTypedVector(val, &Parcel::writeString16);
}
+status_t Parcel::writeUtf8VectorAsUtf16Vector(
+ const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) {
+ return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
+}
+
+status_t Parcel::writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val) {
+ return writeTypedVector(val, &Parcel::writeUtf8AsUtf16);
+}
+
status_t Parcel::writeInt32(int32_t val)
{
return writeAligned(val);
@@ -1485,6 +1525,14 @@
return readTypedVector(val, &Parcel::readString16);
}
+status_t Parcel::readUtf8VectorFromUtf16Vector(
+ std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const {
+ return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
+}
+
+status_t Parcel::readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const {
+ return readTypedVector(val, &Parcel::readUtf8FromUtf16);
+}
status_t Parcel::readInt32(int32_t *pArg) const
{
@@ -1643,6 +1691,46 @@
return int8_t(readInt32());
}
+status_t Parcel::readUtf8FromUtf16(std::string* str) const {
+ size_t utf16Size = 0;
+ const char16_t* src = readString16Inplace(&utf16Size);
+ if (!src) {
+ return UNEXPECTED_NULL;
+ }
+
+ // Save ourselves the trouble, we're done.
+ if (utf16Size == 0u) {
+ str->clear();
+ return NO_ERROR;
+ }
+
+ ssize_t utf8Size = utf16_to_utf8_length(src, utf16Size);
+ if (utf8Size < 0) {
+ return BAD_VALUE;
+ }
+ // Note that while it is probably safe to assume string::resize keeps a
+ // spare byte around for the trailing null, we're going to be explicit.
+ str->resize(utf8Size + 1);
+ utf16_to_utf8(src, utf16Size, &((*str)[0]));
+ str->resize(utf8Size);
+ return NO_ERROR;
+}
+
+status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
+ const int32_t start = dataPosition();
+ int32_t size;
+ status_t status = readInt32(&size);
+ str->reset();
+
+ if (status != OK || size < 0) {
+ return status;
+ }
+
+ setDataPosition(start);
+ str->reset(new std::string());
+ return readUtf8FromUtf16(str->get());
+}
+
const char* Parcel::readCString() const
{
const size_t avail = mDataSize-mDataPos;