1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "get_item_attributes.h"
18
19 namespace bluetooth {
20 namespace avrcp {
21
22 std::unique_ptr<GetItemAttributesResponseBuilder>
MakeBuilder(Status status,size_t mtu)23 GetItemAttributesResponseBuilder::MakeBuilder(Status status, size_t mtu) {
24 std::unique_ptr<GetItemAttributesResponseBuilder> builder(
25 new GetItemAttributesResponseBuilder(status, mtu));
26
27 return builder;
28 }
29
AddAttributeEntry(AttributeEntry entry)30 size_t GetItemAttributesResponseBuilder::AddAttributeEntry(
31 AttributeEntry entry) {
32 CHECK(entries_.size() < 0xFF);
33
34 size_t remaining_space = mtu_ - size();
35 if (entry.size() > remaining_space) {
36 entry.resize(remaining_space);
37 }
38
39 if (entry.empty()) {
40 return 0;
41 }
42
43 entries_.insert(entry);
44 return entry.size();
45 }
46
AddAttributeEntry(Attribute attribute,const std::string & value)47 size_t GetItemAttributesResponseBuilder::AddAttributeEntry(
48 Attribute attribute, const std::string& value) {
49 return AddAttributeEntry(AttributeEntry(attribute, value));
50 }
51
size() const52 size_t GetItemAttributesResponseBuilder::size() const {
53 size_t len = kHeaderSize();
54 if (status_ != Status::NO_ERROR) return kErrorHeaderSize();
55
56 for (const auto& entry : entries_) {
57 len += entry.size();
58 }
59 return len;
60 }
61
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)62 bool GetItemAttributesResponseBuilder::Serialize(
63 const std::shared_ptr<::bluetooth::Packet>& pkt) {
64 ReserveSpace(pkt, size());
65
66 BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
67
68 AddPayloadOctets1(pkt, (uint8_t)status_);
69 if (status_ != Status::NO_ERROR) return true;
70
71 AddPayloadOctets1(pkt, entries_.size());
72 for (const auto& entry : entries_) {
73 AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
74 uint16_t character_set = 0x006a; // UTF-8
75 AddPayloadOctets2(pkt, base::ByteSwap(character_set));
76 uint16_t value_length = entry.value().length();
77 AddPayloadOctets2(pkt, base::ByteSwap(value_length));
78 for (const uint8_t& byte : entry.value()) {
79 AddPayloadOctets1(pkt, byte);
80 }
81 }
82
83 return true;
84 }
85
GetScope() const86 Scope GetItemAttributesRequest::GetScope() const {
87 auto it = begin() + BrowsePacket::kMinSize();
88 return static_cast<Scope>(*it);
89 }
90
GetUid() const91 uint64_t GetItemAttributesRequest::GetUid() const {
92 auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
93 return it.extractBE<uint64_t>();
94 }
95
GetUidCounter() const96 uint16_t GetItemAttributesRequest::GetUidCounter() const {
97 auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
98 return it.extractBE<uint16_t>();
99 }
100
GetNumAttributes() const101 uint8_t GetItemAttributesRequest::GetNumAttributes() const {
102 auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
103 return *it;
104 }
105
GetAttributesRequested() const106 std::vector<Attribute> GetItemAttributesRequest::GetAttributesRequested()
107 const {
108 auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
109 size_t number_of_attributes = it.extract<uint8_t>();
110
111 std::vector<Attribute> attribute_list;
112 for (size_t i = 0; i < number_of_attributes; i++) {
113 attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
114 }
115
116 return attribute_list;
117 }
118
IsValid() const119 bool GetItemAttributesRequest::IsValid() const {
120 if (!BrowsePacket::IsValid()) return false;
121 if (size() < kMinSize()) return false;
122
123 // Casting the int returned from end - attr_start should be fine. If an
124 // overflow occurs we can definitly say the packet is invalid
125 return (GetNumAttributes() * sizeof(Attribute)) == (size() - kMinSize());
126 }
127
ToString() const128 std::string GetItemAttributesRequest::ToString() const {
129 std::stringstream ss;
130 ss << "GetItemAttributesRequestPacket: " << std::endl;
131 ss << " └ PDU = " << GetPdu() << std::endl;
132 ss << " └ Length = " << GetLength() << std::endl;
133 ss << " └ Scope = " << GetScope() << std::endl;
134 ss << " └ UID Requested = " << loghex(GetUid()) << std::endl;
135 ss << " └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
136 ss << " └ Num Attributes = " << loghex(GetNumAttributes()) << std::endl;
137
138 auto attr_list = GetAttributesRequested();
139 ss << " └ Attribute List: Size: " << attr_list.size() << std::endl;
140 for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
141 ss << " └ " << loghex((uint32_t)(*it)) << std::endl;
142 }
143 ss << std::endl;
144
145 return ss.str();
146 }
147
148 } // namespace avrcp
149 } // namespace bluetooth
150