1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/media/router/data_decoder_util.h"
#include "services/data_decoder/public/cpp/safe_xml_parser.h"
#include "url/gurl.h"
namespace media_router {
namespace {
// If a friendly name does not exist, falls back to use model name + last 4
// digits of the UUID as the friendly name.
std::string ComputeFriendlyName(const std::string& unique_id,
const std::string& model_name) {
if (model_name.empty() || unique_id.length() < 4) {
return std::string();
}
std::string trimmed_unique_id = unique_id.substr(unique_id.length() - 4);
return base::StringPrintf("%s [%s]", model_name.c_str(),
trimmed_unique_id.c_str());
}
void NotifyParsingError(SafeDialDeviceDescriptionParser::ParseCallback callback,
SafeDialDeviceDescriptionParser::ParsingResult error) {
std::move(callback).Run(ParsedDialDeviceDescription(), error);
}
} // namespace
SafeDialDeviceDescriptionParser::SafeDialDeviceDescriptionParser() = default;
SafeDialDeviceDescriptionParser::~SafeDialDeviceDescriptionParser() = default;
void SafeDialDeviceDescriptionParser::Parse(const std::string& xml_text,
const GURL& app_url,
ParseCallback callback) {
DCHECK(callback);
GetDataDecoder().ParseXml(
xml_text, data_decoder::mojom::XmlParser::WhitespaceBehavior::kIgnore,
base::BindOnce(&SafeDialDeviceDescriptionParser::OnXmlParsingDone,
weak_factory_.GetWeakPtr(), std::move(callback), app_url));
}
void SafeDialDeviceDescriptionParser::OnXmlParsingDone(
SafeDialDeviceDescriptionParser::ParseCallback callback,
const GURL& app_url,
data_decoder::DataDecoder::ValueOrError result) {
if (!result.has_value() || !result->is_dict()) {
std::move(callback).Run(
ParsedDialDeviceDescription(),
SafeDialDeviceDescriptionParser::ParsingResult::kInvalidXml);
return;
}
bool unique_device = true;
const base::Value* device_element = data_decoder::FindXmlElementPath(
*result, {"root", "device"}, &unique_device);
if (!device_element) {
NotifyParsingError(
std::move(callback),
SafeDialDeviceDescriptionParser::ParsingResult::kInvalidXml);
return;
}
DCHECK(unique_device);
ParsedDialDeviceDescription device_description;
static constexpr size_t kArraySize = 4U;
static constexpr std::array<const char* const, kArraySize> kNodeNames{
{"UDN", "friendlyName", "modelName", "deviceType"}};
static constexpr std::array<ParsingResult, kArraySize> kParsingErrors{
{ParsingResult::kFailedToReadUdn,
ParsingResult::kFailedToReadFriendlyName,
ParsingResult::kFailedToReadModelName,
ParsingResult::kFailedToReadDeviceType}};
const std::array<std::string*, kArraySize> kFields{
{&device_description.unique_id, &device_description.friendly_name,
&device_description.model_name, &device_description.device_type}};
for (size_t i = 0; i < kArraySize; i++) {
const base::Value* value =
data_decoder::GetXmlElementChildWithTag(*device_element, kNodeNames[i]);
if (value) {
DCHECK_EQ(1, data_decoder::GetXmlElementChildrenCount(*device_element,
kNodeNames[i]));
bool parsed = data_decoder::GetXmlElementText(*value, kFields[i]);
if (!parsed) {
NotifyParsingError(std::move(callback), kParsingErrors[i]);
return;
}
}
}
if (device_description.friendly_name.empty()) {
device_description.friendly_name = ComputeFriendlyName(
device_description.unique_id, device_description.model_name);
}
device_description.app_url = app_url;
std::move(callback).Run(device_description, ParsingResult::kSuccess);
}
} // namespace media_router
|