Coverage Report

Created: 2018-09-25 14:53

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