1 /*
2  * Copyright 2023 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 #pragma once
18 
19 #include <cassert>
20 #include <cstdint>
21 #include <memory>
22 #include <utility>
23 #include <vector>
24 
25 namespace pdl::packet {
26 
27 /// Representation of a raw packet slice.
28 /// The slice contains a shared pointer to the source packet bytes, and points
29 /// to a subrange within this byte buffer.
30 class slice {
31  public:
32   slice() = default;
33   slice(slice const&) = default;
slice(std::shared_ptr<const std::vector<uint8_t>> packet)34   slice(std::shared_ptr<const std::vector<uint8_t>> packet)
35       : packet_(std::move(packet)), offset_(0), size_(packet_->size()) {}
36 
slice(std::shared_ptr<const std::vector<uint8_t>> packet,size_t offset,size_t size)37   slice(std::shared_ptr<const std::vector<uint8_t>> packet, size_t offset,
38         size_t size)
39       : packet_(std::move(packet)), offset_(offset), size_(size) {}
40 
41   /// Return a new slice that contains the selected subrange within the
42   /// current slice. The range ['offset', 'offset' + 'slice') must be
43   /// contained within the bonuds of the current slice.
subrange(size_t offset,size_t size)44   slice subrange(size_t offset, size_t size) const {
45     assert((offset + size) <= size_);
46     return slice(packet_, offset_ + offset, size);
47   }
48 
49   /// Read a scalar value encoded in little-endian.
50   /// The bytes that are read from calling this function are consumed.
51   /// This function can be used to iterativaly extract values from a packet
52   /// slice.
53   template <typename T, size_t N = sizeof(T)>
read_le()54   T read_le() {
55     static_assert(N <= sizeof(T));
56     assert(N <= size_);
57     T value = 0;
58     for (size_t n = 0; n < N; n++) {
59       value |= (T)at(n) << (8 * n);
60     }
61     skip(N);
62     return value;
63   }
64 
65   /// Read a scalar value encoded in big-endian.
66   /// The bytes that are read from calling this function are consumed.
67   /// This function can be used to iterativaly extract values from a packet
68   /// slice.
69   template <typename T, size_t N = sizeof(T)>
read_be()70   T read_be() {
71     static_assert(N <= sizeof(T));
72     assert(N <= size_);
73     T value = 0;
74     for (size_t n = 0; n < N; n++) {
75       value = (value << 8) | (T)at(n);
76     }
77     skip(N);
78     return value;
79   }
80 
81   /// Return the value of the byte at the given offset.
82   /// `offset` must be within the bounds of the slice.
at(size_t offset)83   uint8_t at(size_t offset) const {
84     assert(offset <= size_);
85     return packet_->at(offset_ + offset);
86   }
87 
88   /// Skip `size` bytes at the front of the slice.
89   /// `size` must be lower than or equal to the slice size.
skip(size_t size)90   void skip(size_t size) {
91     assert(size <= size_);
92     offset_ += size;
93     size_ -= size;
94   }
95 
96   /// Empty the slice.
clear()97   void clear() { size_ = 0; }
98 
99   /// Return the size of the slice in bytes.
size()100   size_t size() const { return size_; }
101 
102   /// Return the contents of the slice as a byte vector.
bytes()103   std::vector<uint8_t> bytes() const {
104     return std::vector<uint8_t>(packet_->cbegin() + offset_,
105                                 packet_->cbegin() + offset_ + size_);
106   }
107 
108   bool operator==(slice const& other) const {
109     return size_ == other.size_ &&
110            std::equal(packet_->begin() + offset_,
111                       packet_->begin() + offset_ + size_,
112                       other.packet_->begin());
113   }
114 
115  private:
116   std::shared_ptr<const std::vector<uint8_t>> packet_;
117   size_t offset_{0};
118   size_t size_{0};
119 };
120 
121 /// Interface class for generated packet builders.
122 class Builder {
123  public:
124   virtual ~Builder() = default;
125 
126   /// Method implemented by generated packet builders.
127   /// The packet fields are concatenated to the output vector.
Serialize(std::vector<uint8_t> &)128   virtual void Serialize(std::vector<uint8_t>&) const {}
129 
130   /// Method implemented by generated packet builders.
131   /// Returns the size of the serialized packet in bytes.
GetSize()132   virtual size_t GetSize() const { return 0; }
133 
134   /// Write a scalar value encoded in little-endian.
135   template <typename T, size_t N = sizeof(T)>
write_le(std::vector<uint8_t> & output,T value)136   static void write_le(std::vector<uint8_t>& output, T value) {
137     static_assert(N <= sizeof(T));
138     for (size_t n = 0; n < N; n++) {
139       output.push_back(value >> (8 * n));
140     }
141   }
142 
143   /// Write a scalar value encoded in big-endian.
144   template <typename T, size_t N = sizeof(T)>
write_be(std::vector<uint8_t> & output,T value)145   static void write_be(std::vector<uint8_t>& output, T value) {
146     static_assert(N <= sizeof(T));
147     for (size_t n = 0; n < N; n++) {
148       output.push_back(value >> (8 * (N - 1 - n)));
149     }
150   }
151 
152   /// Helper method to serialize the packet to a byte vector.
SerializeToBytes()153   virtual std::vector<uint8_t> SerializeToBytes() const {
154     std::vector<uint8_t> output;
155     Serialize(output);
156     return output;
157   }
158 };
159 
160 }  // namespace pdl::packet
161