xref: /aosp_15_r20/external/openscreen/util/big_endian.h (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #ifndef UTIL_BIG_ENDIAN_H_
6*3f982cf4SFabien Sanglard #define UTIL_BIG_ENDIAN_H_
7*3f982cf4SFabien Sanglard 
8*3f982cf4SFabien Sanglard #include <stdint.h>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include <cstring>
11*3f982cf4SFabien Sanglard #include <type_traits>
12*3f982cf4SFabien Sanglard 
13*3f982cf4SFabien Sanglard namespace openscreen {
14*3f982cf4SFabien Sanglard 
15*3f982cf4SFabien Sanglard ////////////////////////////////////////////////////////////////////////////////
16*3f982cf4SFabien Sanglard // Note: All of the functions here are defined inline, as any half-decent
17*3f982cf4SFabien Sanglard // compiler will optimize them to a single integer constant or single
18*3f982cf4SFabien Sanglard // instruction on most architectures.
19*3f982cf4SFabien Sanglard ////////////////////////////////////////////////////////////////////////////////
20*3f982cf4SFabien Sanglard 
21*3f982cf4SFabien Sanglard // Returns true if this code is running on a big-endian architecture.
IsBigEndianArchitecture()22*3f982cf4SFabien Sanglard inline bool IsBigEndianArchitecture() {
23*3f982cf4SFabien Sanglard   const uint16_t kTestWord = 0x0100;
24*3f982cf4SFabien Sanglard   uint8_t bytes[sizeof(kTestWord)];
25*3f982cf4SFabien Sanglard   memcpy(bytes, &kTestWord, sizeof(bytes));
26*3f982cf4SFabien Sanglard   return !!bytes[0];
27*3f982cf4SFabien Sanglard }
28*3f982cf4SFabien Sanglard 
29*3f982cf4SFabien Sanglard namespace internal {
30*3f982cf4SFabien Sanglard 
31*3f982cf4SFabien Sanglard template <int size>
32*3f982cf4SFabien Sanglard struct MakeSizedUnsignedInteger;
33*3f982cf4SFabien Sanglard 
34*3f982cf4SFabien Sanglard template <>
35*3f982cf4SFabien Sanglard struct MakeSizedUnsignedInteger<1> {
36*3f982cf4SFabien Sanglard   using type = uint8_t;
37*3f982cf4SFabien Sanglard };
38*3f982cf4SFabien Sanglard 
39*3f982cf4SFabien Sanglard template <>
40*3f982cf4SFabien Sanglard struct MakeSizedUnsignedInteger<2> {
41*3f982cf4SFabien Sanglard   using type = uint16_t;
42*3f982cf4SFabien Sanglard };
43*3f982cf4SFabien Sanglard 
44*3f982cf4SFabien Sanglard template <>
45*3f982cf4SFabien Sanglard struct MakeSizedUnsignedInteger<4> {
46*3f982cf4SFabien Sanglard   using type = uint32_t;
47*3f982cf4SFabien Sanglard };
48*3f982cf4SFabien Sanglard 
49*3f982cf4SFabien Sanglard template <>
50*3f982cf4SFabien Sanglard struct MakeSizedUnsignedInteger<8> {
51*3f982cf4SFabien Sanglard   using type = uint64_t;
52*3f982cf4SFabien Sanglard };
53*3f982cf4SFabien Sanglard 
54*3f982cf4SFabien Sanglard template <int size>
55*3f982cf4SFabien Sanglard inline typename MakeSizedUnsignedInteger<size>::type ByteSwap(
56*3f982cf4SFabien Sanglard     typename MakeSizedUnsignedInteger<size>::type x) {
57*3f982cf4SFabien Sanglard   static_assert(size <= 8,
58*3f982cf4SFabien Sanglard                 "ByteSwap() specialization missing in " __FILE__
59*3f982cf4SFabien Sanglard                 ". "
60*3f982cf4SFabien Sanglard                 "Are you trying to use an integer larger than 64 bits?");
61*3f982cf4SFabien Sanglard }
62*3f982cf4SFabien Sanglard 
63*3f982cf4SFabien Sanglard template <>
64*3f982cf4SFabien Sanglard inline uint8_t ByteSwap<1>(uint8_t x) {
65*3f982cf4SFabien Sanglard   return x;
66*3f982cf4SFabien Sanglard }
67*3f982cf4SFabien Sanglard 
68*3f982cf4SFabien Sanglard #if defined(__clang__) || defined(__GNUC__)
69*3f982cf4SFabien Sanglard 
70*3f982cf4SFabien Sanglard template <>
71*3f982cf4SFabien Sanglard inline uint64_t ByteSwap<8>(uint64_t x) {
72*3f982cf4SFabien Sanglard   return __builtin_bswap64(x);
73*3f982cf4SFabien Sanglard }
74*3f982cf4SFabien Sanglard template <>
75*3f982cf4SFabien Sanglard inline uint32_t ByteSwap<4>(uint32_t x) {
76*3f982cf4SFabien Sanglard   return __builtin_bswap32(x);
77*3f982cf4SFabien Sanglard }
78*3f982cf4SFabien Sanglard template <>
79*3f982cf4SFabien Sanglard inline uint16_t ByteSwap<2>(uint16_t x) {
80*3f982cf4SFabien Sanglard   return __builtin_bswap16(x);
81*3f982cf4SFabien Sanglard }
82*3f982cf4SFabien Sanglard 
83*3f982cf4SFabien Sanglard #elif defined(_MSC_VER)
84*3f982cf4SFabien Sanglard 
85*3f982cf4SFabien Sanglard template <>
86*3f982cf4SFabien Sanglard inline uint64_t ByteSwap<8>(uint64_t x) {
87*3f982cf4SFabien Sanglard   return _byteswap_uint64(x);
88*3f982cf4SFabien Sanglard }
89*3f982cf4SFabien Sanglard template <>
90*3f982cf4SFabien Sanglard inline uint32_t ByteSwap<4>(uint32_t x) {
91*3f982cf4SFabien Sanglard   return _byteswap_ulong(x);
92*3f982cf4SFabien Sanglard }
93*3f982cf4SFabien Sanglard template <>
94*3f982cf4SFabien Sanglard inline uint16_t ByteSwap<2>(uint16_t x) {
95*3f982cf4SFabien Sanglard   return _byteswap_ushort(x);
96*3f982cf4SFabien Sanglard }
97*3f982cf4SFabien Sanglard 
98*3f982cf4SFabien Sanglard #else
99*3f982cf4SFabien Sanglard 
100*3f982cf4SFabien Sanglard #include <byteswap.h>
101*3f982cf4SFabien Sanglard 
102*3f982cf4SFabien Sanglard template <>
103*3f982cf4SFabien Sanglard inline uint64_t ByteSwap<8>(uint64_t x) {
104*3f982cf4SFabien Sanglard   return bswap_64(x);
105*3f982cf4SFabien Sanglard }
106*3f982cf4SFabien Sanglard template <>
107*3f982cf4SFabien Sanglard inline uint32_t ByteSwap<4>(uint32_t x) {
108*3f982cf4SFabien Sanglard   return bswap_32(x);
109*3f982cf4SFabien Sanglard }
110*3f982cf4SFabien Sanglard template <>
111*3f982cf4SFabien Sanglard inline uint16_t ByteSwap<2>(uint16_t x) {
112*3f982cf4SFabien Sanglard   return bswap_16(x);
113*3f982cf4SFabien Sanglard }
114*3f982cf4SFabien Sanglard 
115*3f982cf4SFabien Sanglard #endif
116*3f982cf4SFabien Sanglard 
117*3f982cf4SFabien Sanglard }  // namespace internal
118*3f982cf4SFabien Sanglard 
119*3f982cf4SFabien Sanglard // Returns the bytes of |x| in reverse order. This is only defined for 16-, 32-,
120*3f982cf4SFabien Sanglard // and 64-bit unsigned integers.
121*3f982cf4SFabien Sanglard template <typename Integer>
122*3f982cf4SFabien Sanglard inline std::enable_if_t<std::is_unsigned<Integer>::value, Integer> ByteSwap(
123*3f982cf4SFabien Sanglard     Integer x) {
124*3f982cf4SFabien Sanglard   return internal::ByteSwap<sizeof(Integer)>(x);
125*3f982cf4SFabien Sanglard }
126*3f982cf4SFabien Sanglard 
127*3f982cf4SFabien Sanglard // Read a POD integer from |src| in big-endian byte order, returning the integer
128*3f982cf4SFabien Sanglard // in native byte order.
129*3f982cf4SFabien Sanglard template <typename Integer>
130*3f982cf4SFabien Sanglard inline Integer ReadBigEndian(const void* src) {
131*3f982cf4SFabien Sanglard   Integer result;
132*3f982cf4SFabien Sanglard   memcpy(&result, src, sizeof(result));
133*3f982cf4SFabien Sanglard   if (!IsBigEndianArchitecture()) {
134*3f982cf4SFabien Sanglard     result = ByteSwap<typename std::make_unsigned<Integer>::type>(result);
135*3f982cf4SFabien Sanglard   }
136*3f982cf4SFabien Sanglard   return result;
137*3f982cf4SFabien Sanglard }
138*3f982cf4SFabien Sanglard 
139*3f982cf4SFabien Sanglard // Write a POD integer |val| to |dest| in big-endian byte order.
140*3f982cf4SFabien Sanglard template <typename Integer>
141*3f982cf4SFabien Sanglard inline void WriteBigEndian(Integer val, void* dest) {
142*3f982cf4SFabien Sanglard   if (!IsBigEndianArchitecture()) {
143*3f982cf4SFabien Sanglard     val = ByteSwap<typename std::make_unsigned<Integer>::type>(val);
144*3f982cf4SFabien Sanglard   }
145*3f982cf4SFabien Sanglard   memcpy(dest, &val, sizeof(val));
146*3f982cf4SFabien Sanglard }
147*3f982cf4SFabien Sanglard 
148*3f982cf4SFabien Sanglard template <class T>
149*3f982cf4SFabien Sanglard class BigEndianBuffer {
150*3f982cf4SFabien Sanglard  public:
151*3f982cf4SFabien Sanglard   class Cursor {
152*3f982cf4SFabien Sanglard    public:
153*3f982cf4SFabien Sanglard     explicit Cursor(BigEndianBuffer* buffer)
154*3f982cf4SFabien Sanglard         : buffer_(buffer), origin_(buffer_->current_) {}
155*3f982cf4SFabien Sanglard     Cursor(const Cursor& other) = delete;
156*3f982cf4SFabien Sanglard     Cursor(Cursor&& other) = delete;
157*3f982cf4SFabien Sanglard     ~Cursor() { buffer_->current_ = origin_; }
158*3f982cf4SFabien Sanglard 
159*3f982cf4SFabien Sanglard     Cursor& operator=(const Cursor& other) = delete;
160*3f982cf4SFabien Sanglard     Cursor& operator=(Cursor&& other) = delete;
161*3f982cf4SFabien Sanglard 
162*3f982cf4SFabien Sanglard     void Commit() { origin_ = buffer_->current_; }
163*3f982cf4SFabien Sanglard 
164*3f982cf4SFabien Sanglard     T* origin() { return origin_; }
165*3f982cf4SFabien Sanglard     size_t delta() { return buffer_->current_ - origin_; }
166*3f982cf4SFabien Sanglard 
167*3f982cf4SFabien Sanglard    private:
168*3f982cf4SFabien Sanglard     BigEndianBuffer* buffer_;
169*3f982cf4SFabien Sanglard     T* origin_;
170*3f982cf4SFabien Sanglard   };
171*3f982cf4SFabien Sanglard 
172*3f982cf4SFabien Sanglard   bool Skip(size_t length) {
173*3f982cf4SFabien Sanglard     if (current_ + length > end_) {
174*3f982cf4SFabien Sanglard       return false;
175*3f982cf4SFabien Sanglard     }
176*3f982cf4SFabien Sanglard     current_ += length;
177*3f982cf4SFabien Sanglard     return true;
178*3f982cf4SFabien Sanglard   }
179*3f982cf4SFabien Sanglard 
180*3f982cf4SFabien Sanglard   T* begin() const { return begin_; }
181*3f982cf4SFabien Sanglard   T* current() const { return current_; }
182*3f982cf4SFabien Sanglard   T* end() const { return end_; }
183*3f982cf4SFabien Sanglard   size_t length() const { return end_ - begin_; }
184*3f982cf4SFabien Sanglard   size_t remaining() const { return end_ - current_; }
185*3f982cf4SFabien Sanglard   size_t offset() const { return current_ - begin_; }
186*3f982cf4SFabien Sanglard 
187*3f982cf4SFabien Sanglard   BigEndianBuffer(T* buffer, size_t length)
188*3f982cf4SFabien Sanglard       : begin_(buffer), current_(buffer), end_(buffer + length) {}
189*3f982cf4SFabien Sanglard   BigEndianBuffer(const BigEndianBuffer&) = delete;
190*3f982cf4SFabien Sanglard   BigEndianBuffer& operator=(const BigEndianBuffer&) = delete;
191*3f982cf4SFabien Sanglard 
192*3f982cf4SFabien Sanglard  private:
193*3f982cf4SFabien Sanglard   T* begin_;
194*3f982cf4SFabien Sanglard   T* current_;
195*3f982cf4SFabien Sanglard   T* end_;
196*3f982cf4SFabien Sanglard };
197*3f982cf4SFabien Sanglard 
198*3f982cf4SFabien Sanglard class BigEndianReader : public BigEndianBuffer<const uint8_t> {
199*3f982cf4SFabien Sanglard  public:
200*3f982cf4SFabien Sanglard   BigEndianReader(const uint8_t* buffer, size_t length);
201*3f982cf4SFabien Sanglard 
202*3f982cf4SFabien Sanglard   template <typename T>
203*3f982cf4SFabien Sanglard   bool Read(T* out) {
204*3f982cf4SFabien Sanglard     const uint8_t* read_position = current();
205*3f982cf4SFabien Sanglard     if (Skip(sizeof(T))) {
206*3f982cf4SFabien Sanglard       *out = ReadBigEndian<T>(read_position);
207*3f982cf4SFabien Sanglard       return true;
208*3f982cf4SFabien Sanglard     }
209*3f982cf4SFabien Sanglard     return false;
210*3f982cf4SFabien Sanglard   }
211*3f982cf4SFabien Sanglard 
212*3f982cf4SFabien Sanglard   bool Read(size_t length, void* out);
213*3f982cf4SFabien Sanglard };
214*3f982cf4SFabien Sanglard 
215*3f982cf4SFabien Sanglard class BigEndianWriter : public BigEndianBuffer<uint8_t> {
216*3f982cf4SFabien Sanglard  public:
217*3f982cf4SFabien Sanglard   BigEndianWriter(uint8_t* buffer, size_t length);
218*3f982cf4SFabien Sanglard 
219*3f982cf4SFabien Sanglard   template <typename T>
220*3f982cf4SFabien Sanglard   bool Write(T value) {
221*3f982cf4SFabien Sanglard     uint8_t* write_position = current();
222*3f982cf4SFabien Sanglard     if (Skip(sizeof(T))) {
223*3f982cf4SFabien Sanglard       WriteBigEndian<T>(value, write_position);
224*3f982cf4SFabien Sanglard       return true;
225*3f982cf4SFabien Sanglard     }
226*3f982cf4SFabien Sanglard     return false;
227*3f982cf4SFabien Sanglard   }
228*3f982cf4SFabien Sanglard 
229*3f982cf4SFabien Sanglard   bool Write(const void* buffer, size_t length);
230*3f982cf4SFabien Sanglard };
231*3f982cf4SFabien Sanglard 
232*3f982cf4SFabien Sanglard }  // namespace openscreen
233*3f982cf4SFabien Sanglard 
234*3f982cf4SFabien Sanglard #endif  // UTIL_BIG_ENDIAN_H_
235