BufferReader.h (9206B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef BUFFER_READER_H_ 6 #define BUFFER_READER_H_ 7 8 #include <string.h> 9 10 #include "MediaData.h" 11 #include "MediaSpan.h" 12 #include "mozilla/EndianUtils.h" 13 #include "mozilla/Logging.h" 14 #include "mozilla/Result.h" 15 #include "nsTArray.h" 16 #include "nscore.h" 17 18 namespace mozilla { 19 20 extern mozilla::LazyLogModule gMP4MetadataLog; 21 22 class MOZ_RAII BufferReader { 23 public: 24 BufferReader() : mPtr(nullptr), mRemaining(0), mLength(0) {} 25 BufferReader(const uint8_t* aData, size_t aSize) 26 : mPtr(aData), mRemaining(aSize), mLength(aSize) {} 27 template <size_t S> 28 explicit BufferReader(const AutoTArray<uint8_t, S>& aData) 29 : mPtr(aData.Elements()), 30 mRemaining(aData.Length()), 31 mLength(aData.Length()) {} 32 explicit BufferReader(const nsTArray<uint8_t>& aData) 33 : mPtr(aData.Elements()), 34 mRemaining(aData.Length()), 35 mLength(aData.Length()) {} 36 explicit BufferReader(const mozilla::MediaByteBuffer* aData) 37 : mPtr(aData->Elements()), 38 mRemaining(aData->Length()), 39 mLength(aData->Length()) {} 40 explicit BufferReader(const mozilla::MediaSpan& aData) 41 : mPtr(aData.Elements()), 42 mRemaining(aData.Length()), 43 mLength(aData.Length()) {} 44 explicit BufferReader(const Span<const uint8_t>& aData) 45 : mPtr(aData.Elements()), 46 mRemaining(aData.Length()), 47 mLength(aData.Length()) {} 48 49 void SetData(const nsTArray<uint8_t>& aData) { 50 MOZ_ASSERT(!mPtr && !mRemaining); 51 mPtr = aData.Elements(); 52 mRemaining = aData.Length(); 53 mLength = mRemaining; 54 } 55 56 ~BufferReader() = default; 57 58 size_t Offset() const { return mLength - mRemaining; } 59 60 size_t Remaining() const { return mRemaining; } 61 62 mozilla::Result<uint8_t, nsresult> ReadU8() { 63 auto ptr = Read(1); 64 if (!ptr) { 65 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 66 ("%s: failure", __func__)); 67 return mozilla::Err(NS_ERROR_FAILURE); 68 } 69 return *ptr; 70 } 71 72 mozilla::Result<uint16_t, nsresult> ReadU16() { 73 auto ptr = Read(2); 74 if (!ptr) { 75 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 76 ("%s: failure", __func__)); 77 return mozilla::Err(NS_ERROR_FAILURE); 78 } 79 return mozilla::BigEndian::readUint16(ptr); 80 } 81 82 mozilla::Result<int16_t, nsresult> ReadLE16() { 83 auto ptr = Read(2); 84 if (!ptr) { 85 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 86 ("%s: failure", __func__)); 87 return mozilla::Err(NS_ERROR_FAILURE); 88 } 89 return mozilla::LittleEndian::readInt16(ptr); 90 } 91 92 mozilla::Result<uint32_t, nsresult> ReadU24() { 93 auto ptr = Read(3); 94 if (!ptr) { 95 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 96 ("%s: failure", __func__)); 97 return mozilla::Err(NS_ERROR_FAILURE); 98 } 99 return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; 100 } 101 102 mozilla::Result<int32_t, nsresult> Read24() { 103 return ReadU24().map([](uint32_t x) { return (int32_t)x; }); 104 } 105 106 mozilla::Result<int32_t, nsresult> ReadLE24() { 107 auto ptr = Read(3); 108 if (!ptr) { 109 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 110 ("%s: failure", __func__)); 111 return mozilla::Err(NS_ERROR_FAILURE); 112 } 113 int32_t result = int32_t(ptr[2] << 16 | ptr[1] << 8 | ptr[0]); 114 if (result & 0x00800000u) { 115 result -= 0x1000000; 116 } 117 return result; 118 } 119 120 mozilla::Result<uint32_t, nsresult> ReadU32() { 121 auto ptr = Read(4); 122 if (!ptr) { 123 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 124 ("%s: failure", __func__)); 125 return mozilla::Err(NS_ERROR_FAILURE); 126 } 127 return mozilla::BigEndian::readUint32(ptr); 128 } 129 130 mozilla::Result<int32_t, nsresult> Read32() { 131 auto ptr = Read(4); 132 if (!ptr) { 133 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 134 ("%s: failure", __func__)); 135 return mozilla::Err(NS_ERROR_FAILURE); 136 } 137 return mozilla::BigEndian::readInt32(ptr); 138 } 139 140 mozilla::Result<uint32_t, nsresult> ReadLEU32() { 141 auto ptr = Read(4); 142 if (!ptr) { 143 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 144 ("%s: failure", __func__)); 145 return mozilla::Err(NS_ERROR_FAILURE); 146 } 147 return mozilla::LittleEndian::readUint32(ptr); 148 } 149 150 mozilla::Result<uint64_t, nsresult> ReadU64() { 151 auto ptr = Read(8); 152 if (!ptr) { 153 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 154 ("%s: failure", __func__)); 155 return mozilla::Err(NS_ERROR_FAILURE); 156 } 157 return mozilla::BigEndian::readUint64(ptr); 158 } 159 160 mozilla::Result<int64_t, nsresult> Read64() { 161 auto ptr = Read(8); 162 if (!ptr) { 163 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 164 ("%s: failure", __func__)); 165 return mozilla::Err(NS_ERROR_FAILURE); 166 } 167 return mozilla::BigEndian::readInt64(ptr); 168 } 169 170 const uint8_t* Read(size_t aCount) { 171 if (aCount > mRemaining) { 172 mPtr += mRemaining; 173 mRemaining = 0; 174 return nullptr; 175 } 176 mRemaining -= aCount; 177 178 const uint8_t* result = mPtr; 179 mPtr += aCount; 180 181 return result; 182 } 183 184 const uint8_t* Rewind(size_t aCount) { 185 MOZ_ASSERT(aCount <= Offset()); 186 size_t rewind = Offset(); 187 if (aCount < rewind) { 188 rewind = aCount; 189 } 190 mRemaining += rewind; 191 mPtr -= rewind; 192 return mPtr; 193 } 194 195 mozilla::Result<uint8_t, nsresult> PeekU8() const { 196 auto ptr = Peek(1); 197 if (!ptr) { 198 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 199 ("%s: failure", __func__)); 200 return mozilla::Err(NS_ERROR_FAILURE); 201 } 202 return *ptr; 203 } 204 205 mozilla::Result<uint16_t, nsresult> PeekU16() const { 206 auto ptr = Peek(2); 207 if (!ptr) { 208 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 209 ("%s: failure", __func__)); 210 return mozilla::Err(NS_ERROR_FAILURE); 211 } 212 return mozilla::BigEndian::readUint16(ptr); 213 } 214 215 mozilla::Result<uint32_t, nsresult> PeekU24() const { 216 auto ptr = Peek(3); 217 if (!ptr) { 218 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 219 ("%s: failure", __func__)); 220 return mozilla::Err(NS_ERROR_FAILURE); 221 } 222 return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; 223 } 224 225 mozilla::Result<int32_t, nsresult> Peek24() const { 226 return PeekU24().map([](uint32_t x) { return (int32_t)x; }); 227 } 228 229 mozilla::Result<uint32_t, nsresult> PeekU32() { 230 auto ptr = Peek(4); 231 if (!ptr) { 232 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 233 ("%s: failure", __func__)); 234 return mozilla::Err(NS_ERROR_FAILURE); 235 } 236 return mozilla::BigEndian::readUint32(ptr); 237 } 238 239 const uint8_t* Peek(size_t aCount) const { 240 if (aCount > mRemaining) { 241 return nullptr; 242 } 243 return mPtr; 244 } 245 246 const uint8_t* Seek(size_t aOffset) { 247 if (aOffset >= mLength) { 248 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 249 ("%s: failure, offset: %zu", __func__, aOffset)); 250 return nullptr; 251 } 252 253 mPtr = mPtr - Offset() + aOffset; 254 mRemaining = mLength - aOffset; 255 return mPtr; 256 } 257 258 const uint8_t* Reset() { 259 mPtr -= Offset(); 260 mRemaining = mLength; 261 return mPtr; 262 } 263 264 uint32_t Align() const { return 4 - ((intptr_t)mPtr & 3); } 265 266 template <typename T> 267 bool CanReadType() const { 268 return mRemaining >= sizeof(T); 269 } 270 271 template <typename T> 272 T ReadType() { 273 auto ptr = Read(sizeof(T)); 274 if (!ptr) { 275 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 276 ("%s: failure", __func__)); 277 return 0; 278 } 279 // handle unaligned accesses by memcpying 280 T ret; 281 memcpy(&ret, ptr, sizeof(T)); 282 return ret; 283 } 284 285 template <typename T> 286 [[nodiscard]] bool ReadArray(nsTArray<T>& aDest, size_t aLength) { 287 auto ptr = Read(aLength * sizeof(T)); 288 if (!ptr) { 289 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 290 ("%s: failure", __func__)); 291 return false; 292 } 293 294 aDest.Clear(); 295 aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength); 296 return true; 297 } 298 299 template <typename T> 300 [[nodiscard]] bool ReadArray(FallibleTArray<T>& aDest, size_t aLength) { 301 auto ptr = Read(aLength * sizeof(T)); 302 if (!ptr) { 303 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 304 ("%s: failure", __func__)); 305 return false; 306 } 307 308 aDest.Clear(); 309 if (!aDest.SetCapacity(aLength, mozilla::fallible)) { 310 return false; 311 } 312 MOZ_ALWAYS_TRUE(aDest.AppendElements(reinterpret_cast<const T*>(ptr), 313 aLength, mozilla::fallible)); 314 return true; 315 } 316 317 template <typename T> 318 mozilla::Result<Span<const T>, nsresult> ReadSpan(size_t aLength) { 319 auto ptr = Read(aLength * sizeof(T)); 320 if (!ptr) { 321 MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error, 322 ("%s: failure", __func__)); 323 return mozilla::Err(NS_ERROR_FAILURE); 324 } 325 return Span(reinterpret_cast<const T*>(ptr), aLength); 326 } 327 328 private: 329 const uint8_t* mPtr; 330 size_t mRemaining; 331 size_t mLength; 332 }; 333 334 } // namespace mozilla 335 336 #endif