summaryrefslogtreecommitdiffstats
path: root/dom/media/BufferReader.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/BufferReader.h')
-rw-r--r--dom/media/BufferReader.h320
1 files changed, 320 insertions, 0 deletions
diff --git a/dom/media/BufferReader.h b/dom/media/BufferReader.h
new file mode 100644
index 0000000000..6cd332de53
--- /dev/null
+++ b/dom/media/BufferReader.h
@@ -0,0 +1,320 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BUFFER_READER_H_
+#define BUFFER_READER_H_
+
+#include <string.h>
+#include "mozilla/EndianUtils.h"
+#include "nscore.h"
+#include "nsTArray.h"
+#include "MediaData.h"
+#include "MediaSpan.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Result.h"
+
+namespace mozilla {
+
+extern mozilla::LazyLogModule gMP4MetadataLog;
+
+class MOZ_RAII BufferReader {
+ public:
+ BufferReader() : mPtr(nullptr), mRemaining(0), mLength(0) {}
+ BufferReader(const uint8_t* aData, size_t aSize)
+ : mPtr(aData), mRemaining(aSize), mLength(aSize) {}
+ template <size_t S>
+ explicit BufferReader(const AutoTArray<uint8_t, S>& aData)
+ : mPtr(aData.Elements()),
+ mRemaining(aData.Length()),
+ mLength(aData.Length()) {}
+ explicit BufferReader(const nsTArray<uint8_t>& aData)
+ : mPtr(aData.Elements()),
+ mRemaining(aData.Length()),
+ mLength(aData.Length()) {}
+ explicit BufferReader(const mozilla::MediaByteBuffer* aData)
+ : mPtr(aData->Elements()),
+ mRemaining(aData->Length()),
+ mLength(aData->Length()) {}
+ explicit BufferReader(const mozilla::MediaSpan& aData)
+ : mPtr(aData.Elements()),
+ mRemaining(aData.Length()),
+ mLength(aData.Length()) {}
+
+ void SetData(const nsTArray<uint8_t>& aData) {
+ MOZ_ASSERT(!mPtr && !mRemaining);
+ mPtr = aData.Elements();
+ mRemaining = aData.Length();
+ mLength = mRemaining;
+ }
+
+ ~BufferReader() = default;
+
+ size_t Offset() const { return mLength - mRemaining; }
+
+ size_t Remaining() const { return mRemaining; }
+
+ mozilla::Result<uint8_t, nsresult> ReadU8() {
+ auto ptr = Read(1);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return *ptr;
+ }
+
+ mozilla::Result<uint16_t, nsresult> ReadU16() {
+ auto ptr = Read(2);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readUint16(ptr);
+ }
+
+ mozilla::Result<int16_t, nsresult> ReadLE16() {
+ auto ptr = Read(2);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::LittleEndian::readInt16(ptr);
+ }
+
+ mozilla::Result<uint32_t, nsresult> ReadU24() {
+ auto ptr = Read(3);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+ }
+
+ mozilla::Result<int32_t, nsresult> Read24() {
+ return ReadU24().map([](uint32_t x) { return (int32_t)x; });
+ }
+
+ mozilla::Result<int32_t, nsresult> ReadLE24() {
+ auto ptr = Read(3);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ int32_t result = int32_t(ptr[2] << 16 | ptr[1] << 8 | ptr[0]);
+ if (result & 0x00800000u) {
+ result -= 0x1000000;
+ }
+ return result;
+ }
+
+ mozilla::Result<uint32_t, nsresult> ReadU32() {
+ auto ptr = Read(4);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readUint32(ptr);
+ }
+
+ mozilla::Result<int32_t, nsresult> Read32() {
+ auto ptr = Read(4);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readInt32(ptr);
+ }
+
+ mozilla::Result<uint32_t, nsresult> ReadLEU32() {
+ auto ptr = Read(4);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::LittleEndian::readUint32(ptr);
+ }
+
+ mozilla::Result<uint64_t, nsresult> ReadU64() {
+ auto ptr = Read(8);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readUint64(ptr);
+ }
+
+ mozilla::Result<int64_t, nsresult> Read64() {
+ auto ptr = Read(8);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readInt64(ptr);
+ }
+
+ const uint8_t* Read(size_t aCount) {
+ if (aCount > mRemaining) {
+ mPtr += mRemaining;
+ mRemaining = 0;
+ return nullptr;
+ }
+ mRemaining -= aCount;
+
+ const uint8_t* result = mPtr;
+ mPtr += aCount;
+
+ return result;
+ }
+
+ const uint8_t* Rewind(size_t aCount) {
+ MOZ_ASSERT(aCount <= Offset());
+ size_t rewind = Offset();
+ if (aCount < rewind) {
+ rewind = aCount;
+ }
+ mRemaining += rewind;
+ mPtr -= rewind;
+ return mPtr;
+ }
+
+ mozilla::Result<uint8_t, nsresult> PeekU8() const {
+ auto ptr = Peek(1);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return *ptr;
+ }
+
+ mozilla::Result<uint16_t, nsresult> PeekU16() const {
+ auto ptr = Peek(2);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readUint16(ptr);
+ }
+
+ mozilla::Result<uint32_t, nsresult> PeekU24() const {
+ auto ptr = Peek(3);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+ }
+
+ mozilla::Result<int32_t, nsresult> Peek24() const {
+ return PeekU24().map([](uint32_t x) { return (int32_t)x; });
+ }
+
+ mozilla::Result<uint32_t, nsresult> PeekU32() {
+ auto ptr = Peek(4);
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return mozilla::Err(NS_ERROR_FAILURE);
+ }
+ return mozilla::BigEndian::readUint32(ptr);
+ }
+
+ const uint8_t* Peek(size_t aCount) const {
+ if (aCount > mRemaining) {
+ return nullptr;
+ }
+ return mPtr;
+ }
+
+ const uint8_t* Seek(size_t aOffset) {
+ if (aOffset >= mLength) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure, offset: %zu", __func__, aOffset));
+ return nullptr;
+ }
+
+ mPtr = mPtr - Offset() + aOffset;
+ mRemaining = mLength - aOffset;
+ return mPtr;
+ }
+
+ const uint8_t* Reset() {
+ mPtr -= Offset();
+ mRemaining = mLength;
+ return mPtr;
+ }
+
+ uint32_t Align() const { return 4 - ((intptr_t)mPtr & 3); }
+
+ template <typename T>
+ bool CanReadType() const {
+ return mRemaining >= sizeof(T);
+ }
+
+ template <typename T>
+ T ReadType() {
+ auto ptr = Read(sizeof(T));
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return 0;
+ }
+ // handle unaligned accesses by memcpying
+ T ret;
+ memcpy(&ret, ptr, sizeof(T));
+ return ret;
+ }
+
+ template <typename T>
+ [[nodiscard]] bool ReadArray(nsTArray<T>& aDest, size_t aLength) {
+ auto ptr = Read(aLength * sizeof(T));
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return false;
+ }
+
+ aDest.Clear();
+ aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength);
+ return true;
+ }
+
+ template <typename T>
+ [[nodiscard]] bool ReadArray(FallibleTArray<T>& aDest, size_t aLength) {
+ auto ptr = Read(aLength * sizeof(T));
+ if (!ptr) {
+ MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
+ ("%s: failure", __func__));
+ return false;
+ }
+
+ aDest.Clear();
+ if (!aDest.SetCapacity(aLength, mozilla::fallible)) {
+ return false;
+ }
+ MOZ_ALWAYS_TRUE(aDest.AppendElements(reinterpret_cast<const T*>(ptr),
+ aLength, mozilla::fallible));
+ return true;
+ }
+
+ private:
+ const uint8_t* mPtr;
+ size_t mRemaining;
+ size_t mLength;
+};
+
+} // namespace mozilla
+
+#endif