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 #include <base/sys_byteorder.h>
20 
21 #include "internal_include/bt_trace.h"
22 
23 namespace bluetooth {
24 namespace avrcp {
25 
MakeBuilder(Status status,size_t mtu)26 std::unique_ptr<GetItemAttributesResponseBuilder> GetItemAttributesResponseBuilder::MakeBuilder(
27         Status status, size_t mtu) {
28   std::unique_ptr<GetItemAttributesResponseBuilder> builder(
29           new GetItemAttributesResponseBuilder(status, mtu));
30 
31   return builder;
32 }
33 
AddAttributeEntry(AttributeEntry entry)34 size_t GetItemAttributesResponseBuilder::AddAttributeEntry(AttributeEntry entry) {
35   log::assert_that(entries_.size() < 0xFF, "assert failed: entries_.size() < 0xFF");
36 
37   size_t remaining_space = mtu_ - size();
38   if (entry.size() > remaining_space) {
39     entry.resize(remaining_space);
40   }
41 
42   if (entry.empty()) {
43     return 0;
44   }
45 
46   entries_.insert(entry);
47   return entry.size();
48 }
49 
AddAttributeEntry(Attribute attribute,const std::string & value)50 size_t GetItemAttributesResponseBuilder::AddAttributeEntry(Attribute attribute,
51                                                            const std::string& value) {
52   return AddAttributeEntry(AttributeEntry(attribute, value));
53 }
54 
size() const55 size_t GetItemAttributesResponseBuilder::size() const {
56   size_t len = kHeaderSize();
57   if (status_ != Status::NO_ERROR) {
58     return kErrorHeaderSize();
59   }
60 
61   for (const auto& entry : entries_) {
62     len += entry.size();
63   }
64   return len;
65 }
66 
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)67 bool GetItemAttributesResponseBuilder::Serialize(const std::shared_ptr<::bluetooth::Packet>& pkt) {
68   ReserveSpace(pkt, size());
69 
70   BrowsePacketBuilder::PushHeader(pkt, size() - BrowsePacket::kMinSize());
71 
72   AddPayloadOctets1(pkt, (uint8_t)status_);
73   if (status_ != Status::NO_ERROR) {
74     return true;
75   }
76 
77   AddPayloadOctets1(pkt, entries_.size());
78   for (const auto& entry : entries_) {
79     AddPayloadOctets4(pkt, base::ByteSwap((uint32_t)entry.attribute()));
80     uint16_t character_set = 0x006a;  // UTF-8
81     AddPayloadOctets2(pkt, base::ByteSwap(character_set));
82     uint16_t value_length = entry.value().length();
83     AddPayloadOctets2(pkt, base::ByteSwap(value_length));
84     for (const uint8_t& byte : entry.value()) {
85       AddPayloadOctets1(pkt, byte);
86     }
87   }
88 
89   return true;
90 }
91 
GetScope() const92 Scope GetItemAttributesRequest::GetScope() const {
93   auto it = begin() + BrowsePacket::kMinSize();
94   return static_cast<Scope>(*it);
95 }
96 
GetUid() const97 uint64_t GetItemAttributesRequest::GetUid() const {
98   auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(1);
99   return it.extractBE<uint64_t>();
100 }
101 
GetUidCounter() const102 uint16_t GetItemAttributesRequest::GetUidCounter() const {
103   auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(9);
104   return it.extractBE<uint16_t>();
105 }
106 
GetNumAttributes() const107 uint8_t GetItemAttributesRequest::GetNumAttributes() const {
108   auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
109   return *it;
110 }
111 
GetAttributesRequested() const112 std::vector<Attribute> GetItemAttributesRequest::GetAttributesRequested() const {
113   auto it = begin() + BrowsePacket::kMinSize() + static_cast<size_t>(11);
114   size_t number_of_attributes = it.extract<uint8_t>();
115 
116   std::vector<Attribute> attribute_list;
117   for (size_t i = 0; i < number_of_attributes; i++) {
118     attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
119   }
120 
121   return attribute_list;
122 }
123 
IsValid() const124 bool GetItemAttributesRequest::IsValid() const {
125   if (!BrowsePacket::IsValid()) {
126     return false;
127   }
128   if (size() < kMinSize()) {
129     return false;
130   }
131 
132   // Casting the int returned from end - attr_start should be fine. If an
133   // overflow occurs we can definitly say the packet is invalid
134   return (GetNumAttributes() * sizeof(Attribute)) == (size() - kMinSize());
135 }
136 
ToString() const137 std::string GetItemAttributesRequest::ToString() const {
138   std::stringstream ss;
139   ss << "GetItemAttributesRequestPacket: " << std::endl;
140   ss << "  └ PDU = " << GetPdu() << std::endl;
141   ss << "  └ Length = " << GetLength() << std::endl;
142   ss << "  └ Scope = " << GetScope() << std::endl;
143   ss << "  └ UID Requested = " << loghex(GetUid()) << std::endl;
144   ss << "  └ UID Counter = " << loghex(GetUidCounter()) << std::endl;
145   ss << "  └ Num Attributes = " << loghex(GetNumAttributes()) << std::endl;
146 
147   auto attr_list = GetAttributesRequested();
148   ss << "  └ Attribute List: Size: " << attr_list.size() << std::endl;
149   for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
150     ss << "      └ " << loghex((uint32_t)(*it)) << std::endl;
151   }
152   ss << std::endl;
153 
154   return ss.str();
155 }
156 
157 }  // namespace avrcp
158 }  // namespace bluetooth
159