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_element_attributes_packet.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include <algorithm>
22 
23 namespace bluetooth {
24 namespace avrcp {
25 
GetIdentifier() const26 uint64_t GetElementAttributesRequest::GetIdentifier() const {
27   auto it = begin() + VendorPacket::kMinSize();
28   return it.extract<uint64_t>();
29 }
30 
GetNumAttributes() const31 uint8_t GetElementAttributesRequest::GetNumAttributes() const {
32   auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
33   return it.extract<uint8_t>();
34 }
35 
GetAttributesRequested() const36 std::vector<Attribute> GetElementAttributesRequest::GetAttributesRequested()
37     const {
38   auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(8);
39 
40   size_t number_of_attributes = it.extract<uint8_t>();
41 
42   std::vector<Attribute> attribute_list;
43 
44   for (size_t i = 0; i < number_of_attributes; i++) {
45     attribute_list.push_back((Attribute)it.extractBE<uint32_t>());
46   }
47 
48   return attribute_list;
49 }
50 
IsValid() const51 bool GetElementAttributesRequest::IsValid() const {
52   if (!VendorPacket::IsValid()) return false;
53   if (size() < kMinSize()) return false;
54 
55   size_t num_attributes = GetNumAttributes();
56   auto attr_start = begin() + VendorPacket::kMinSize() + static_cast<size_t>(9);
57 
58   // Casting the int returned from end - attr_start should be fine. If an
59   // overflow occurs we can definitly say the packet is invalid
60   return (num_attributes * sizeof(Attribute)) == (size_t)(end() - attr_start);
61 }
62 
ToString() const63 std::string GetElementAttributesRequest::ToString() const {
64   std::stringstream ss;
65   ss << "RegisterNotificationPacket: " << std::endl;
66   ss << "  └ cType = " << GetCType() << std::endl;
67   ss << "  └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
68   ss << "  └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
69   ss << "  └ OpCode = " << GetOpcode() << std::endl;
70   ss << "  └ Company ID = " << loghex(GetCompanyId()) << std::endl;
71   ss << "  └ Command PDU = " << GetCommandPdu() << std::endl;
72   ss << "  └ PacketType = " << GetPacketType() << std::endl;
73   ss << "  └ Parameter Length = " << GetParameterLength() << std::endl;
74   ss << "  └ Identifier = " << loghex(GetIdentifier()) << std::endl;
75 
76   auto attr_list = GetAttributesRequested();
77 
78   ss << "  └ Attribute List: Size: " << attr_list.size() << std::endl;
79   for (auto it = attr_list.begin(); it != attr_list.end(); it++) {
80     ss << "      └ " << loghex((uint32_t)(*it)) << std::endl;
81   }
82   ss << std::endl;
83 
84   return ss.str();
85 }
86 
87 std::unique_ptr<GetElementAttributesResponseBuilder>
MakeBuilder(size_t mtu)88 GetElementAttributesResponseBuilder::MakeBuilder(size_t mtu) {
89   std::unique_ptr<GetElementAttributesResponseBuilder> builder(
90       new GetElementAttributesResponseBuilder(mtu));
91 
92   return builder;
93 }
94 
AddAttributeEntry(AttributeEntry entry)95 size_t GetElementAttributesResponseBuilder::AddAttributeEntry(
96     AttributeEntry entry) {
97   log::assert_that(entries_.size() < size_t(0xFF), "attribute entry overflow");
98 
99   size_t remaining_space = mtu_ - size();
100   if (entry.size() > remaining_space) {
101     entry.resize(remaining_space);
102   }
103 
104   if (entry.empty()) {
105     return 0;
106   }
107 
108   entries_.insert(entry);
109   return entry.size();
110 }
111 
AddAttributeEntry(Attribute attribute,const std::string & value)112 size_t GetElementAttributesResponseBuilder::AddAttributeEntry(
113     Attribute attribute, const std::string& value) {
114   return AddAttributeEntry(AttributeEntry(attribute, value));
115 }
116 
size() const117 size_t GetElementAttributesResponseBuilder::size() const {
118   size_t attr_list_size = 0;
119 
120   for (auto& attribute_entry : entries_) {
121     attr_list_size += attribute_entry.size();
122   }
123 
124   return kHeaderSize() + attr_list_size;
125 }
126 
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)127 bool GetElementAttributesResponseBuilder::Serialize(
128     const std::shared_ptr<::bluetooth::Packet>& pkt) {
129   ReserveSpace(pkt, size());
130 
131   PacketBuilder::PushHeader(pkt);
132 
133   VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
134 
135   AddPayloadOctets1(pkt, entries_.size());
136   for (const auto& attribute_entry : entries_) {
137     PushAttributeValue(pkt, attribute_entry);
138   }
139 
140   return true;
141 }
142 
143 }  // namespace avrcp
144 }  // namespace bluetooth
145