1 /*
2  * Copyright 2019 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 "packet/packet_view.h"
18 
19 #include <algorithm>
20 
21 #include "os/log.h"
22 
23 namespace bluetooth {
24 namespace packet {
25 
26 template <bool little_endian>
PacketView(const std::forward_list<class View> fragments)27 PacketView<little_endian>::PacketView(const std::forward_list<class View> fragments)
28     : fragments_(fragments), length_(0) {
29   for (auto fragment : fragments_) {
30     length_ += fragment.size();
31   }
32 }
33 
34 template <bool little_endian>
PacketView(std::shared_ptr<std::vector<uint8_t>> packet)35 PacketView<little_endian>::PacketView(std::shared_ptr<std::vector<uint8_t>> packet)
36     : fragments_({View(packet, 0, packet->size())}), length_(packet->size()) {}
37 
38 template <bool little_endian>
begin() const39 Iterator<little_endian> PacketView<little_endian>::begin() const {
40   return Iterator<little_endian>(this->fragments_, 0);
41 }
42 
43 template <bool little_endian>
end() const44 Iterator<little_endian> PacketView<little_endian>::end() const {
45   return Iterator<little_endian>(this->fragments_, size());
46 }
47 
48 template <bool little_endian>
operator [](size_t index) const49 uint8_t PacketView<little_endian>::operator[](size_t index) const {
50   return at(index);
51 }
52 
53 template <bool little_endian>
at(size_t index) const54 uint8_t PacketView<little_endian>::at(size_t index) const {
55   ASSERT_LOG(index < length_, "Index %zu out of bounds", index);
56   for (const auto& fragment : fragments_) {
57     if (index < fragment.size()) {
58       return fragment[index];
59     }
60     index -= fragment.size();
61   }
62   ASSERT_LOG(false, "Out of fragments searching for index %zu", index);
63   return 0;
64 }
65 
66 template <bool little_endian>
size() const67 size_t PacketView<little_endian>::size() const {
68   return length_;
69 }
70 
71 template <bool little_endian>
GetSubviewList(size_t begin,size_t end) const72 std::forward_list<View> PacketView<little_endian>::GetSubviewList(size_t begin, size_t end) const {
73   ASSERT(begin <= end);
74   ASSERT(end <= length_);
75 
76   std::forward_list<View> view_list;
77   std::forward_list<View>::iterator it = view_list.before_begin();
78   size_t length = end - begin;
79   for (const auto& fragment : fragments_) {
80     if (begin >= fragment.size()) {
81       begin -= fragment.size();
82     } else {
83       View view(fragment, begin, begin + std::min(length, fragment.size() - begin));
84       length -= view.size();
85       it = view_list.insert_after(it, view);
86       begin = 0;
87     }
88   }
89   return view_list;
90 }
91 
92 template <bool little_endian>
GetLittleEndianSubview(size_t begin,size_t end) const93 PacketView<true> PacketView<little_endian>::GetLittleEndianSubview(size_t begin, size_t end) const {
94   return PacketView<true>(GetSubviewList(begin, end));
95 }
96 
97 template <bool little_endian>
GetBigEndianSubview(size_t begin,size_t end) const98 PacketView<false> PacketView<little_endian>::GetBigEndianSubview(size_t begin, size_t end) const {
99   return PacketView<false>(GetSubviewList(begin, end));
100 }
101 
102 template <bool little_endian>
Append(PacketView to_add)103 void PacketView<little_endian>::Append(PacketView to_add) {
104   auto insertion_point = fragments_.begin();
105   size_t remaining_length = length_;
106   while (remaining_length > 0) {
107     remaining_length -= insertion_point->size();
108     if (remaining_length > 0) {
109       insertion_point++;
110     }
111   }
112   ASSERT(insertion_point != fragments_.end());
113   for (const auto& fragment : to_add.fragments_) {
114     fragments_.insert_after(insertion_point, fragment);
115     insertion_point++;
116   }
117   length_ += to_add.length_;
118 }
119 
120 // Explicit instantiations for both types of PacketViews.
121 template class PacketView<true>;
122 template class PacketView<false>;
123 }  // namespace packet
124 }  // namespace bluetooth
125