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