bluetooth: Expose service data from BlueZ

BlueZ exposed Bluetooth device's ServiceData as a{sv} property[1]
where the dict value variant is an array of byte.

This CL exposes that to upper layer by
- Add support to map<string, vector<uint8_t>> in dbus::Property
- Add new service_data property in BluetoothDeviceClient
- Implement GetServiceDataUUIDs() and GetServiceDataForUUID()
  in BluetoothDeviceBlueZ
- Fix misc style issues in original code to make linter happy

[1] http://git.kernel.org/cgit/bluetooth/bluez.git/tree/src/device.c#n2551

BUG=618442,653310,b:28670943
TEST=Manually tested.

Review-Url: https://codereview.chromium.org/2369423003
Cr-Original-Commit-Position: refs/heads/master@{#423434}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 0dd82b1c975662a10f34a53b3df56d98526b36d0
diff --git a/property.cc b/property.cc
index faca4a0..0ac65ef 100644
--- a/property.cc
+++ b/property.cc
@@ -6,6 +6,8 @@
 
 #include <stddef.h>
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/logging.h"
 
@@ -659,6 +661,70 @@
   writer->CloseContainer(&variant_writer);
 }
 
+//
+// Property<std::map<std::string, std::vector<uint8_t>>>
+// specialization.
+//
+
+template <>
+bool Property<std::unordered_map<std::string, std::vector<uint8_t>>>::
+    PopValueFromReader(MessageReader* reader) {
+  MessageReader variant_reader(nullptr);
+  MessageReader dict_reader(nullptr);
+  if (!reader->PopVariant(&variant_reader) ||
+      !variant_reader.PopArray(&dict_reader))
+    return false;
+
+  value_.clear();
+  while (dict_reader.HasMoreData()) {
+    MessageReader entry_reader(nullptr);
+    if (!dict_reader.PopDictEntry(&entry_reader))
+      return false;
+
+    std::string key;
+    MessageReader value_varient_reader(nullptr);
+    if (!entry_reader.PopString(&key) ||
+        !entry_reader.PopVariant(&value_varient_reader))
+      return false;
+
+    const uint8_t* bytes = nullptr;
+    size_t length = 0;
+    if (!value_varient_reader.PopArrayOfBytes(&bytes, &length))
+      return false;
+
+    value_[key].assign(bytes, bytes + length);
+  }
+  return true;
+}
+
+template <>
+void Property<std::unordered_map<std::string, std::vector<uint8_t>>>::
+    AppendSetValueToWriter(MessageWriter* writer) {
+  MessageWriter variant_writer(nullptr);
+  MessageWriter dict_writer(nullptr);
+
+  writer->OpenVariant("a{sv}", &variant_writer);
+  variant_writer.OpenArray("{sv}", &dict_writer);
+
+  for (const auto& pair : set_value_) {
+    MessageWriter entry_writer(nullptr);
+    dict_writer.OpenDictEntry(&entry_writer);
+
+    entry_writer.AppendString(pair.first);
+
+    MessageWriter value_varient_writer(nullptr);
+    entry_writer.OpenVariant("ay", &value_varient_writer);
+    value_varient_writer.AppendArrayOfBytes(pair.second.data(),
+                                            pair.second.size());
+    entry_writer.CloseContainer(&value_varient_writer);
+
+    dict_writer.CloseContainer(&entry_writer);
+  }
+
+  variant_writer.CloseContainer(&dict_writer);
+  writer->CloseContainer(&variant_writer);
+}
+
 template class Property<uint8_t>;
 template class Property<bool>;
 template class Property<int16_t>;
@@ -675,5 +741,6 @@
 template class Property<std::vector<uint8_t>>;
 template class Property<std::map<std::string, std::string>>;
 template class Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
+template class Property<std::unordered_map<std::string, std::vector<uint8_t>>>;
 
 }  // namespace dbus
diff --git a/property.h b/property.h
index efbad22..616a595 100644
--- a/property.h
+++ b/property.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -610,6 +611,17 @@
 extern template class CHROME_DBUS_EXPORT
     Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
 
+template <>
+CHROME_DBUS_EXPORT bool
+Property<std::unordered_map<std::string, std::vector<uint8_t>>>::
+    PopValueFromReader(MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void
+Property<std::unordered_map<std::string, std::vector<uint8_t>>>::
+    AppendSetValueToWriter(MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT
+    Property<std::unordered_map<std::string, std::vector<uint8_t>>>;
+
 #pragma GCC diagnostic pop
 
 }  // namespace dbus
diff --git a/property_unittest.cc b/property_unittest.cc
index 5922554..8208581 100644
--- a/property_unittest.cc
+++ b/property_unittest.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -431,4 +432,59 @@
   EXPECT_EQ(test_list, ip_list.value());
 }
 
+TEST(PropertyTestStatic, ReadWriteStringToByteVectorMap) {
+  std::unique_ptr<Response> message(Response::CreateEmpty());
+  MessageWriter writer(message.get());
+  MessageWriter variant_writer(nullptr);
+  MessageWriter dict_writer(nullptr);
+
+  writer.OpenVariant("a{sv}", &variant_writer);
+  variant_writer.OpenArray("{sv}", &dict_writer);
+
+  const char* keys[] = {"One", "Two", "Three", "Four"};
+  const std::vector<uint8_t> values[] = {{1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}};
+  for (unsigned i = 0; i < arraysize(keys); ++i) {
+    MessageWriter entry_writer(nullptr);
+    dict_writer.OpenDictEntry(&entry_writer);
+
+    entry_writer.AppendString(keys[i]);
+
+    MessageWriter value_varient_writer(nullptr);
+    entry_writer.OpenVariant("ay", &value_varient_writer);
+    value_varient_writer.AppendArrayOfBytes(values[i].data(), values[i].size());
+    entry_writer.CloseContainer(&value_varient_writer);
+
+    dict_writer.CloseContainer(&entry_writer);
+  }
+
+  variant_writer.CloseContainer(&dict_writer);
+  writer.CloseContainer(&variant_writer);
+
+  MessageReader reader(message.get());
+  Property<std::unordered_map<std::string, std::vector<uint8_t>>> test_property;
+  EXPECT_TRUE(test_property.PopValueFromReader(&reader));
+
+  ASSERT_EQ(arraysize(keys), test_property.value().size());
+  for (unsigned i = 0; i < arraysize(keys); ++i)
+    EXPECT_EQ(values[i], test_property.value().at(keys[i]));
+}
+
+TEST(PropertyTestStatic, SerializeStringToByteVectorMap) {
+  std::unordered_map<std::string, std::vector<uint8_t>> test_map;
+  test_map["Hi"] = {1, 2, 3};
+  test_map["Map"] = {0xab, 0xcd};
+  test_map["Random"] = {0x0};
+
+  std::unique_ptr<Response> message(Response::CreateEmpty());
+  MessageWriter writer(message.get());
+
+  Property<std::unordered_map<std::string, std::vector<uint8_t>>> test_property;
+  test_property.ReplaceSetValueForTesting(test_map);
+  test_property.AppendSetValueToWriter(&writer);
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(test_property.PopValueFromReader(&reader));
+  EXPECT_EQ(test_map, test_property.value());
+}
+
 }  // namespace dbus