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   log::assert_that(entries_.size() < 0xFF,
33                    "assert failed: entries_.size() < 0xFF");
34 
35   size_t remaining_space = mtu_ - size();
36   if (entry.size() > remaining_space) {
37     entry.resize(remaining_space);
38   }
39 
40   if (entry.empty()) {
41     return 0;
42   }
43 
44   entries_.insert(entry);
45   return entry.size();
46 }
47 
AddAttributeEntry(Attribute attribute,const std::string & value)48 size_t GetItemAttributesResponseBuilder::AddAttributeEntry(
49     Attribute attribute, const std::string& value) {
50   return AddAttributeEntry(AttributeEntry(attribute, value));
51 }
52 
size() const53 size_t GetItemAttributesResponseBuilder::size() const {
54   size_t len = kHeaderSize();
55   if (status_ != Status::NO_ERROR) return kErrorHeaderSize();
56 
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