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