| Index: content/browser/android/string_message_codec.cc
|
| diff --git a/content/browser/android/string_message_codec.cc b/content/browser/android/string_message_codec.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aa258875ef539ec64df030c2bb84a4a9943c0865
|
| --- /dev/null
|
| +++ b/content/browser/android/string_message_codec.cc
|
| @@ -0,0 +1,153 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/browser/android/string_message_codec.h"
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +namespace content {
|
| +namespace {
|
| +
|
| +const uint32_t kVarIntShift = 7;
|
| +const uint32_t kVarIntMask = (1 << kVarIntShift) - 1;
|
| +
|
| +const uint8_t kVersionTag = 0xFF;
|
| +const uint8_t kPaddingTag = '\0';
|
| +const uint8_t kOneByteStringTag = '"';
|
| +const uint8_t kTwoByteStringTag = 'c';
|
| +
|
| +const uint32_t kVersion = 10;
|
| +
|
| +static size_t BytesNeededForUint32(uint32_t value) {
|
| + size_t result = 0;
|
| + do {
|
| + result++;
|
| + value >>= kVarIntShift;
|
| + } while (value);
|
| + return result;
|
| +}
|
| +
|
| +void WriteUint8(uint8_t value, std::vector<uint8_t>* buffer) {
|
| + buffer->push_back(value);
|
| +}
|
| +
|
| +void WriteUint32(uint32_t value, std::vector<uint8_t>* buffer) {
|
| + for (;;) {
|
| + uint8_t b = (value & kVarIntMask);
|
| + value >>= kVarIntShift;
|
| + if (!value) {
|
| + WriteUint8(b, buffer);
|
| + break;
|
| + }
|
| + WriteUint8(b | (1 << kVarIntShift), buffer);
|
| + }
|
| +}
|
| +
|
| +void WriteBytes(const char* bytes, size_t num_bytes,
|
| + std::vector<uint8_t>* buffer) {
|
| + buffer->insert(buffer->end(), bytes, bytes + num_bytes);
|
| +}
|
| +
|
| +bool ReadUint8(const uint8_t** ptr, const uint8_t* end, uint8_t* value) {
|
| + if (*ptr >= end)
|
| + return false;
|
| + *value = *(*ptr)++;
|
| + return true;
|
| +}
|
| +
|
| +bool ReadUint32(const uint8_t** ptr, const uint8_t* end, uint32_t* value) {
|
| + *value = 0;
|
| + uint8_t current_byte;
|
| + int shift = 0;
|
| + do {
|
| + if (*ptr >= end)
|
| + return false;
|
| + current_byte = *(*ptr)++;
|
| + *value |= (static_cast<uint32_t>(current_byte & kVarIntMask) << shift);
|
| + shift += kVarIntShift;
|
| + } while (current_byte & (1 << kVarIntShift));
|
| + return true;
|
| +}
|
| +
|
| +bool ContainsOnlyLatin1(const base::string16& data) {
|
| + base::char16 x = 0;
|
| + for (base::char16 c : data)
|
| + x |= c;
|
| + return !(x & 0xFF00);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +base::string16 EncodeStringMessage(const base::string16& data) {
|
| + std::vector<uint8_t> buffer;
|
| + WriteUint8(kVersionTag, &buffer);
|
| + WriteUint32(kVersion, &buffer);
|
| +
|
| + if (ContainsOnlyLatin1(data)) {
|
| + std::string data_latin1(data.begin(), data.end());
|
| + WriteUint8(kOneByteStringTag, &buffer);
|
| + WriteUint32(data_latin1.size(), &buffer);
|
| + WriteBytes(data_latin1.c_str(), data_latin1.size(), &buffer);
|
| + } else {
|
| + size_t num_bytes = data.size() * sizeof(base::char16);
|
| + if ((buffer.size() + 1 + BytesNeededForUint32(num_bytes)) & 1)
|
| + WriteUint8(kPaddingTag, &buffer);
|
| + WriteUint8(kTwoByteStringTag, &buffer);
|
| + WriteUint32(num_bytes, &buffer);
|
| + WriteBytes(reinterpret_cast<const char*>(data.data()), num_bytes, &buffer);
|
| + }
|
| +
|
| + base::string16 result;
|
| + size_t result_num_bytes = (buffer.size() + 1) & ~1;
|
| + result.resize(result_num_bytes / 2);
|
| + uint8_t* destination = reinterpret_cast<uint8_t*>(&result[0]);
|
| + memcpy(destination, &buffer[0], buffer.size());
|
| + return result;
|
| +}
|
| +
|
| +bool DecodeStringMessage(const base::string16& encoded_data,
|
| + base::string16* result) {
|
| + size_t num_bytes = encoded_data.size() * 2;
|
| +
|
| + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&encoded_data[0]);
|
| + const uint8_t* end = ptr + num_bytes;
|
| +
|
| + uint8_t tag;
|
| + if (!ReadUint8(&ptr, end, &tag) || tag != kVersionTag)
|
| + return false;
|
| +
|
| + uint32_t version;
|
| + if (!ReadUint32(&ptr, end, &version))
|
| + return false;
|
| +
|
| + do {
|
| + if (!ReadUint8(&ptr, end, &tag))
|
| + return false;
|
| + } while (tag == kPaddingTag);
|
| +
|
| + switch (tag) {
|
| + case kOneByteStringTag: {
|
| + uint32_t num_bytes;
|
| + if (!ReadUint32(&ptr, end, &num_bytes))
|
| + return false;
|
| + result->assign(reinterpret_cast<const char*>(ptr),
|
| + reinterpret_cast<const char*>(ptr) + num_bytes);
|
| + return true;
|
| + }
|
| + case kTwoByteStringTag: {
|
| + uint32_t num_bytes;
|
| + if (!ReadUint32(&ptr, end, &num_bytes))
|
| + return false;
|
| + result->assign(reinterpret_cast<const base::char16*>(ptr), num_bytes / 2);
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + DLOG(WARNING) << "Unexpected tag: " << tag;
|
| + return false;
|
| +}
|
| +
|
| +} // namespace content
|
|
|