|
|
|||
File indexing completed on 2026-05-10 08:44:27
0001 //===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 0009 #ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H 0010 #define LLVM_SUPPORT_BINARYSTREAMREADER_H 0011 0012 #include "llvm/ADT/ArrayRef.h" 0013 #include "llvm/ADT/StringRef.h" 0014 #include "llvm/Support/Alignment.h" 0015 #include "llvm/Support/BinaryStreamArray.h" 0016 #include "llvm/Support/BinaryStreamRef.h" 0017 #include "llvm/Support/ConvertUTF.h" 0018 #include "llvm/Support/Endian.h" 0019 #include "llvm/Support/Error.h" 0020 #include <type_traits> 0021 0022 namespace llvm { 0023 0024 /// Provides read only access to a subclass of `BinaryStream`. Provides 0025 /// bounds checking and helpers for writing certain common data types such as 0026 /// null-terminated strings, integers in various flavors of endianness, etc. 0027 /// Can be subclassed to provide reading of custom datatypes, although no 0028 /// are overridable. 0029 class BinaryStreamReader { 0030 public: 0031 BinaryStreamReader() = default; 0032 explicit BinaryStreamReader(BinaryStreamRef Ref); 0033 explicit BinaryStreamReader(BinaryStream &Stream); 0034 explicit BinaryStreamReader(ArrayRef<uint8_t> Data, llvm::endianness Endian); 0035 explicit BinaryStreamReader(StringRef Data, llvm::endianness Endian); 0036 0037 BinaryStreamReader(const BinaryStreamReader &Other) = default; 0038 0039 BinaryStreamReader &operator=(const BinaryStreamReader &Other) = default; 0040 0041 virtual ~BinaryStreamReader() = default; 0042 0043 /// Read as much as possible from the underlying string at the current offset 0044 /// without invoking a copy, and set \p Buffer to the resulting data slice. 0045 /// Updates the stream's offset to point after the newly read data. 0046 /// 0047 /// \returns a success error code if the data was successfully read, otherwise 0048 /// returns an appropriate error code. 0049 Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer); 0050 0051 /// Read \p Size bytes from the underlying stream at the current offset and 0052 /// and set \p Buffer to the resulting data slice. Whether a copy occurs 0053 /// depends on the implementation of the underlying stream. Updates the 0054 /// stream's offset to point after the newly read data. 0055 /// 0056 /// \returns a success error code if the data was successfully read, otherwise 0057 /// returns an appropriate error code. 0058 Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size); 0059 0060 /// Read an integer of the specified endianness into \p Dest and update the 0061 /// stream's offset. The data is always copied from the stream's underlying 0062 /// buffer into \p Dest. Updates the stream's offset to point after the newly 0063 /// read data. 0064 /// 0065 /// \returns a success error code if the data was successfully read, otherwise 0066 /// returns an appropriate error code. 0067 template <typename T> Error readInteger(T &Dest) { 0068 static_assert(std::is_integral_v<T>, 0069 "Cannot call readInteger with non-integral value!"); 0070 0071 ArrayRef<uint8_t> Bytes; 0072 if (auto EC = readBytes(Bytes, sizeof(T))) 0073 return EC; 0074 0075 Dest = llvm::support::endian::read<T>(Bytes.data(), Stream.getEndian()); 0076 return Error::success(); 0077 } 0078 0079 /// Similar to readInteger. 0080 template <typename T> Error readEnum(T &Dest) { 0081 static_assert(std::is_enum<T>::value, 0082 "Cannot call readEnum with non-enum value!"); 0083 std::underlying_type_t<T> N; 0084 if (auto EC = readInteger(N)) 0085 return EC; 0086 Dest = static_cast<T>(N); 0087 return Error::success(); 0088 } 0089 0090 /// Read an unsigned LEB128 encoded value. 0091 /// 0092 /// \returns a success error code if the data was successfully read, otherwise 0093 /// returns an appropriate error code. 0094 Error readULEB128(uint64_t &Dest); 0095 0096 /// Read a signed LEB128 encoded value. 0097 /// 0098 /// \returns a success error code if the data was successfully read, otherwise 0099 /// returns an appropriate error code. 0100 Error readSLEB128(int64_t &Dest); 0101 0102 /// Read a null terminated string from \p Dest. Whether a copy occurs depends 0103 /// on the implementation of the underlying stream. Updates the stream's 0104 /// offset to point after the newly read data. 0105 /// 0106 /// \returns a success error code if the data was successfully read, otherwise 0107 /// returns an appropriate error code. 0108 Error readCString(StringRef &Dest); 0109 0110 /// Similar to readCString, however read a null-terminated UTF16 string 0111 /// instead. 0112 /// 0113 /// \returns a success error code if the data was successfully read, otherwise 0114 /// returns an appropriate error code. 0115 Error readWideString(ArrayRef<UTF16> &Dest); 0116 0117 /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends 0118 /// on the implementation of the underlying stream. Updates the stream's 0119 /// offset to point after the newly read data. 0120 /// 0121 /// \returns a success error code if the data was successfully read, otherwise 0122 /// returns an appropriate error code. 0123 Error readFixedString(StringRef &Dest, uint32_t Length); 0124 0125 /// Read the entire remainder of the underlying stream into \p Ref. This is 0126 /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the 0127 /// stream's offset to point to the end of the stream. Never causes a copy. 0128 /// 0129 /// \returns a success error code if the data was successfully read, otherwise 0130 /// returns an appropriate error code. 0131 Error readStreamRef(BinaryStreamRef &Ref); 0132 0133 /// Read \p Length bytes from the underlying stream into \p Ref. This is 0134 /// equivalent to calling getUnderlyingStream().slice(Offset, Length). 0135 /// Updates the stream's offset to point after the newly read object. Never 0136 /// causes a copy. 0137 /// 0138 /// \returns a success error code if the data was successfully read, otherwise 0139 /// returns an appropriate error code. 0140 Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length); 0141 0142 /// Read \p Length bytes from the underlying stream into \p Ref. This is 0143 /// equivalent to calling getUnderlyingStream().slice(Offset, Length). 0144 /// Updates the stream's offset to point after the newly read object. Never 0145 /// causes a copy. 0146 /// 0147 /// \returns a success error code if the data was successfully read, otherwise 0148 /// returns an appropriate error code. 0149 Error readSubstream(BinarySubstreamRef &Ref, uint32_t Length); 0150 0151 /// Get a pointer to an object of type T from the underlying stream, as if by 0152 /// memcpy, and store the result into \p Dest. It is up to the caller to 0153 /// ensure that objects of type T can be safely treated in this manner. 0154 /// Updates the stream's offset to point after the newly read object. Whether 0155 /// a copy occurs depends upon the implementation of the underlying 0156 /// stream. 0157 /// 0158 /// \returns a success error code if the data was successfully read, otherwise 0159 /// returns an appropriate error code. 0160 template <typename T> Error readObject(const T *&Dest) { 0161 ArrayRef<uint8_t> Buffer; 0162 if (auto EC = readBytes(Buffer, sizeof(T))) 0163 return EC; 0164 Dest = reinterpret_cast<const T *>(Buffer.data()); 0165 return Error::success(); 0166 } 0167 0168 /// Get a reference to a \p NumElements element array of objects of type T 0169 /// from the underlying stream as if by memcpy, and store the resulting array 0170 /// slice into \p array. It is up to the caller to ensure that objects of 0171 /// type T can be safely treated in this manner. Updates the stream's offset 0172 /// to point after the newly read object. Whether a copy occurs depends upon 0173 /// the implementation of the underlying stream. 0174 /// 0175 /// \returns a success error code if the data was successfully read, otherwise 0176 /// returns an appropriate error code. 0177 template <typename T> 0178 Error readArray(ArrayRef<T> &Array, uint32_t NumElements) { 0179 ArrayRef<uint8_t> Bytes; 0180 if (NumElements == 0) { 0181 Array = ArrayRef<T>(); 0182 return Error::success(); 0183 } 0184 0185 if (NumElements > UINT32_MAX / sizeof(T)) 0186 return make_error<BinaryStreamError>( 0187 stream_error_code::invalid_array_size); 0188 0189 if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) 0190 return EC; 0191 0192 assert(isAddrAligned(Align::Of<T>(), Bytes.data()) && 0193 "Reading at invalid alignment!"); 0194 0195 Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements); 0196 return Error::success(); 0197 } 0198 0199 /// Read a VarStreamArray of size \p Size bytes and store the result into 0200 /// \p Array. Updates the stream's offset to point after the newly read 0201 /// array. Never causes a copy (although iterating the elements of the 0202 /// VarStreamArray may, depending upon the implementation of the underlying 0203 /// stream). 0204 /// 0205 /// \returns a success error code if the data was successfully read, otherwise 0206 /// returns an appropriate error code. 0207 template <typename T, typename U> 0208 Error readArray(VarStreamArray<T, U> &Array, uint32_t Size, 0209 uint32_t Skew = 0) { 0210 BinaryStreamRef S; 0211 if (auto EC = readStreamRef(S, Size)) 0212 return EC; 0213 Array.setUnderlyingStream(S, Skew); 0214 return Error::success(); 0215 } 0216 0217 /// Read a FixedStreamArray of \p NumItems elements and store the result into 0218 /// \p Array. Updates the stream's offset to point after the newly read 0219 /// array. Never causes a copy (although iterating the elements of the 0220 /// FixedStreamArray may, depending upon the implementation of the underlying 0221 /// stream). 0222 /// 0223 /// \returns a success error code if the data was successfully read, otherwise 0224 /// returns an appropriate error code. 0225 template <typename T> 0226 Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) { 0227 if (NumItems == 0) { 0228 Array = FixedStreamArray<T>(); 0229 return Error::success(); 0230 } 0231 0232 if (NumItems > UINT32_MAX / sizeof(T)) 0233 return make_error<BinaryStreamError>( 0234 stream_error_code::invalid_array_size); 0235 0236 BinaryStreamRef View; 0237 if (auto EC = readStreamRef(View, NumItems * sizeof(T))) 0238 return EC; 0239 0240 Array = FixedStreamArray<T>(View); 0241 return Error::success(); 0242 } 0243 0244 bool empty() const { return bytesRemaining() == 0; } 0245 void setOffset(uint64_t Off) { Offset = Off; } 0246 uint64_t getOffset() const { return Offset; } 0247 uint64_t getLength() const { return Stream.getLength(); } 0248 uint64_t bytesRemaining() const { return getLength() - getOffset(); } 0249 0250 /// Advance the stream's offset by \p Amount bytes. 0251 /// 0252 /// \returns a success error code if at least \p Amount bytes remain in the 0253 /// stream, otherwise returns an appropriate error code. 0254 Error skip(uint64_t Amount); 0255 0256 /// Examine the next byte of the underlying stream without advancing the 0257 /// stream's offset. If the stream is empty the behavior is undefined. 0258 /// 0259 /// \returns the next byte in the stream. 0260 uint8_t peek() const; 0261 0262 Error padToAlignment(uint32_t Align); 0263 0264 std::pair<BinaryStreamReader, BinaryStreamReader> 0265 split(uint64_t Offset) const; 0266 0267 private: 0268 BinaryStreamRef Stream; 0269 uint64_t Offset = 0; 0270 }; 0271 } // namespace llvm 0272 0273 #endif // LLVM_SUPPORT_BINARYSTREAMREADER_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|