1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef BASE_BIG_ENDIAN_H_
6 #define BASE_BIG_ENDIAN_H_
11 #include <type_traits>
13 #include "base/base_export.h"
14 #include "base/containers/span.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/strings/string_piece.h"
17 #include "base/sys_byteorder.h"
18 #include "build/build_config.h"
24 // ByteSwapIfLittleEndian performs ByteSwap if this platform is little-endian,
25 // otherwise it is a no-op.
27 #if defined(ARCH_CPU_LITTLE_ENDIAN)
30 inline auto ByteSwapIfLittleEndian(T val) -> decltype(ByteSwap(val)) {
36 // The use of decltype ensures this is only enabled for types for which
37 // ByteSwap() is defined, so the same set of overloads will work on both
38 // little-endian and big-endian platforms.
41 inline auto ByteSwapIfLittleEndian(T val) -> decltype(ByteSwap(val)) {
47 // We never need to byte-swap a single-byte value, but it's convenient to have
48 // this overload to avoid a special case.
49 inline uint8_t ByteSwapIfLittleEndian(uint8_t val) {
53 } // namespace internal
55 // Read an integer (signed or unsigned) from |buf| in Big Endian order.
56 // Note: this loop is unrolled with -O1 and above.
57 // NOTE(szym): glibc dns-canon.c use ntohs(*(uint16_t*)ptr) which is
58 // potentially unaligned.
59 // This would cause SIGBUS on ARMv5 or earlier and ARMv6-M.
61 inline void ReadBigEndian(const uint8_t buf[], T* out) {
62 static_assert(std::is_integral_v<T>, "T has to be an integral type.");
63 // Make an unsigned version of the output type to make shift possible
65 typename std::make_unsigned<T>::type raw;
66 memcpy(&raw, buf, sizeof(T));
67 *out = static_cast<T>(internal::ByteSwapIfLittleEndian(raw));
70 // Write an integer (signed or unsigned) |val| to |buf| in Big Endian order.
71 // Note: this loop is unrolled with -O1 and above.
73 inline void WriteBigEndian(char buf[], T val) {
74 static_assert(std::is_integral_v<T>, "T has to be an integral type.");
75 const auto unsigned_val =
76 static_cast<typename std::make_unsigned<T>::type>(val);
77 const auto raw = internal::ByteSwapIfLittleEndian(unsigned_val);
78 memcpy(buf, &raw, sizeof(T));
81 // Allows reading integers in network order (big endian) while iterating over
82 // an underlying buffer. All the reading functions advance the internal pointer.
83 class BASE_EXPORT BigEndianReader {
85 static BigEndianReader FromStringPiece(base::StringPiece string_piece);
87 BigEndianReader(const uint8_t* buf, size_t len);
88 explicit BigEndianReader(base::span<const uint8_t> buf);
90 const uint8_t* ptr() const { return ptr_; }
91 size_t remaining() const { return static_cast<size_t>(end_ - ptr_); }
93 bool Skip(size_t len);
94 bool ReadBytes(void* out, size_t len);
95 // Creates a StringPiece in |out| that points to the underlying buffer.
96 bool ReadPiece(base::StringPiece* out, size_t len);
97 bool ReadSpan(base::span<const uint8_t>* out, size_t len);
99 bool ReadU8(uint8_t* value);
100 bool ReadU16(uint16_t* value);
101 bool ReadU32(uint32_t* value);
102 bool ReadU64(uint64_t* value);
104 // Reads a length-prefixed region:
105 // 1. reads a big-endian length L from the buffer;
106 // 2. sets |*out| to a StringPiece over the next L many bytes
107 // of the buffer (beyond the end of the bytes encoding the length); and
108 // 3. skips the main reader past this L-byte substring.
110 // Fails if reading a U8 or U16 fails, or if the parsed length is greater
111 // than the number of bytes remaining in the stream.
113 // On failure, leaves the stream at the same position
114 // as before the call.
115 bool ReadU8LengthPrefixed(base::StringPiece* out);
116 bool ReadU16LengthPrefixed(base::StringPiece* out);
119 // Hidden to promote type safety.
122 template <typename T>
123 bool ReadLengthPrefixed(base::StringPiece* out);
129 // Allows writing integers in network order (big endian) while iterating over
130 // an underlying buffer. All the writing functions advance the internal pointer.
131 class BASE_EXPORT BigEndianWriter {
133 BigEndianWriter(char* buf, size_t len);
135 char* ptr() const { return ptr_; }
136 size_t remaining() const { return static_cast<size_t>(end_ - ptr_); }
138 bool Skip(size_t len);
139 bool WriteBytes(const void* buf, size_t len);
140 bool WriteU8(uint8_t value);
141 bool WriteU16(uint16_t value);
142 bool WriteU32(uint32_t value);
143 bool WriteU64(uint64_t value);
146 // Hidden to promote type safety.
150 raw_ptr<char, DanglingUntriaged | AllowPtrArithmetic> ptr_;
151 raw_ptr<char, DanglingUntriaged | AllowPtrArithmetic> end_;
156 #endif // BASE_BIG_ENDIAN_H_