Merge "[DevTools] Support UTF16 strings with binary protocol (ip)."
diff --git a/lib/Values_cpp.template b/lib/Values_cpp.template
index 4b4ba99..bf31bab 100644
--- a/lib/Values_cpp.template
+++ b/lib/Values_cpp.template
@@ -130,13 +130,19 @@
     }
     case CBORTokenTag::STRING8: {
       span<uint8_t> str = tokenizer->GetString8();
-      std::unique_ptr<Value> value = StringValue::create(StringUtil::fromUTF8(str.data(), str.size()));
+      std::unique_ptr<Value> value =
+          StringValue::create(StringUtil::fromUTF8(str.data(), str.size()));
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::STRING16:
-      // NOT SUPPORTED YET.
-      return nullptr;
+    case CBORTokenTag::STRING16: {
+      span<uint8_t> wire = tokenizer->GetString16WireRep();
+      DCHECK_EQ(wire.size() & 1, 0);
+      std::unique_ptr<Value> value = StringValue::create(StringUtil::fromUTF16(
+          reinterpret_cast<const uint16_t*>(wire.data()), wire.size() / 2));
+      tokenizer->Next();
+      return value;
+    }
     case CBORTokenTag::BINARY: {
       span<uint8_t> payload = tokenizer->GetBinary();
       tokenizer->Next();
@@ -363,10 +369,37 @@
     StringUtil::builderAppendQuotedString(*output, m_stringValue);
 }
 
+namespace {
+// This routine distinguishes between the current encoding for a given
+// string |s|, and calls encoding routines that will
+// - Ensure that all ASCII strings end up being encoded as UTF8 in
+//   the wire format - e.g., EncodeFromUTF16 will detect ASCII and
+//   do the (trivial) transcode to STRING8 on the wire, but if it's
+//   not ASCII it'll do STRING16.
+// - Select a format that's cheap to convert to. E.g., we don't
+//   have LATIN1 on the wire, so we call EncodeFromLatin1 which
+//   transcodes to UTF8 if needed.
+void EncodeString(const String& s, std::vector<uint8_t>* out) {
+  if (StringUtil::CharactersLatin1(s)) {
+    EncodeFromLatin1(span<uint8_t>(StringUtil::CharactersLatin1(s),
+                                   StringUtil::CharacterCount(s)),
+                     out);
+  } else if (StringUtil::CharactersUTF16(s)) {
+    EncodeFromUTF16(span<uint16_t>(StringUtil::CharactersUTF16(s),
+                                   StringUtil::CharacterCount(s)),
+                    out);
+  } else if (StringUtil::CharactersUTF8(s)) {
+    EncodeString8(span<uint8_t>(StringUtil::CharactersUTF8(s),
+                                StringUtil::CharacterCount(s)),
+                  out);
+  } else {
+    EncodeString8(span<uint8_t>(nullptr, 0), out);  // Empty string.
+  }
+}
+}  // namespace
+
 void StringValue::writeBinary(std::vector<uint8_t>* bytes) const {
-    StringUTF8Adapter utf8(m_stringValue);
-    EncodeString8(span<uint8_t>(reinterpret_cast<const uint8_t*>(utf8.Data()),
-                  utf8.length()), bytes);
+  EncodeString(m_stringValue, bytes);
 }
 
 std::unique_ptr<Value> StringValue::clone() const
@@ -557,9 +590,7 @@
         const String& key = m_order[i];
         Dictionary::const_iterator value = m_data.find(key);
         DCHECK(value != m_data.cend() && value->second);
-        StringUTF8Adapter utf8(key);
-        EncodeString8(span<uint8_t>(reinterpret_cast<const uint8_t*>(utf8.Data()),
-	                            utf8.length()), bytes);
+        EncodeString(key, bytes);
         value->second->writeBinary(bytes);
     }
     bytes->push_back(EncodeStop());
diff --git a/lib/base_string_adapter_cc.template b/lib/base_string_adapter_cc.template
index ed33164..24855d4 100644
--- a/lib/base_string_adapter_cc.template
+++ b/lib/base_string_adapter_cc.template
@@ -136,7 +136,7 @@
         reinterpret_cast<const uint8_t*>(message.data()),
         message.length());
   }
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(message);
   return toProtocolValue(value.get(), 1000);
 }
 
@@ -185,6 +185,13 @@
   string_.reserve(capacity);
 }
 
+// static
+String StringUtil::fromUTF16(const uint16_t* data, size_t length) {
+  std::string utf8;
+  base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(data), length, &utf8);
+  return utf8;
+}
+
 Binary::Binary() : bytes_(new base::RefCountedBytes) {}
 Binary::Binary(const Binary& binary) : bytes_(binary.bytes_) {}
 Binary::Binary(scoped_refptr<base::RefCountedMemory> bytes) : bytes_(bytes) {}
diff --git a/lib/base_string_adapter_h.template b/lib/base_string_adapter_h.template
index b0215e0..082c7c0 100644
--- a/lib/base_string_adapter_h.template
+++ b/lib/base_string_adapter_h.template
@@ -32,16 +32,6 @@
 using String = std::string;
 using ProtocolMessage = std::string;
 
-class {{config.lib.export_macro}} StringUTF8Adapter {
- public:
-  StringUTF8Adapter(const std::string& string) : string_(string) { }
-  const char* Data() const { return string_.data(); }
-  size_t length() const { return string_.length(); }
-
- private:
-  const std::string& string_;
-};
-
 class {{config.lib.export_macro}} StringBuilder {
  public:
   StringBuilder();
@@ -109,6 +99,15 @@
   static String fromUTF8(const uint8_t* data, size_t length) {
     return std::string(reinterpret_cast<const char*>(data), length);
   }
+
+  static String fromUTF16(const uint16_t* data, size_t length);
+
+  static const uint8_t* CharactersLatin1(const String& s) { return nullptr; }
+  static const uint8_t* CharactersUTF8(const String& s) {
+    return reinterpret_cast<const uint8_t*>(s.data());
+  }
+  static const uint16_t* CharactersUTF16(const String& s) { return nullptr; }
+  static size_t CharacterCount(const String& s) { return s.size(); }
 };
 
 // A read-only sequence of uninterpreted bytes with reference-counted storage.