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