File: safe_dial_device_description_parser.cc

package info (click to toggle)
chromium 139.0.7258.127-1~deb13u1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,096 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (112 lines) | stat: -rw-r--r-- 4,218 bytes parent folder | download | duplicates (6)
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