aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/libmp4v2/mp4file_io.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/libmp4v2/mp4file_io.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/external_dependencies/libmp4v2/mp4file_io.cpp')
-rw-r--r--Src/external_dependencies/libmp4v2/mp4file_io.cpp655
1 files changed, 655 insertions, 0 deletions
diff --git a/Src/external_dependencies/libmp4v2/mp4file_io.cpp b/Src/external_dependencies/libmp4v2/mp4file_io.cpp
new file mode 100644
index 00000000..688470ac
--- /dev/null
+++ b/Src/external_dependencies/libmp4v2/mp4file_io.cpp
@@ -0,0 +1,655 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is MPEG4IP.
+ *
+ * The Initial Developer of the Original Code is Cisco Systems Inc.
+ * Portions created by Cisco Systems Inc. are
+ * Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Mackie dmackie@cisco.com
+ */
+
+#include "mp4common.h"
+
+// MP4File low level IO support
+
+u_int64_t MP4File::GetPosition(FILE* pFile)
+{
+ if (m_memoryBuffer == NULL) {
+ if (pFile == NULL) {
+ ASSERT(m_pFile);
+ u_int64_t fpos;
+ if (m_virtual_IO->GetPosition(m_pFile, &fpos) != 0) {
+ throw new MP4Error("getting position via Virtual I/O", "MP4GetPosition");
+ }
+ return fpos;
+ } else {
+ fpos_t fpos;
+ if (fgetpos(pFile, &fpos) < 0) {
+ throw new MP4Error(errno, "MP4GetPosition");
+ }
+ uint64_t ret;
+ FPOS_TO_VAR(fpos, uint64_t, ret);
+ return ret;
+ }
+ } else {
+ return m_memoryBufferPosition;
+ }
+}
+
+void MP4File::SetPosition(u_int64_t pos, FILE* pFile)
+{
+ if (m_memoryBuffer == NULL) {
+ if (pFile == NULL) {
+ ASSERT(m_pFile);
+ if (m_virtual_IO->SetPosition(m_pFile, pos) != 0) {
+ throw new MP4Error("setting position via Virtual I/O", "MP4SetPosition");
+ }
+ } else {
+ fpos_t fpos;
+ VAR_TO_FPOS(fpos, pos);
+ if (fsetpos(pFile, &fpos) < 0) {
+ throw new MP4Error(errno, "MP4SetPosition");
+ }
+ }
+ } else {
+ if (pos >= m_memoryBufferSize) {
+ // abort();
+ throw new MP4Error("position out of range", "MP4SetPosition");
+ }
+ m_memoryBufferPosition = pos;
+ }
+}
+
+u_int64_t MP4File::GetSize()
+{
+ if (m_mode == 'w') {
+ // we're always positioned at the end of file in write mode
+ // except for short intervals in ReadSample and FinishWrite routines
+ // so we rely on the faster approach of GetPosition()
+ // instead of flushing to disk, and then stat'ing the file
+ m_fileSize = GetPosition();
+ } // else read mode, fileSize was determined at Open()
+
+ return m_fileSize;
+}
+
+void MP4File::ReadBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile)
+{
+ // handle degenerate cases
+ if (numBytes == 0) {
+ return;
+ }
+
+ ASSERT(pBytes);
+ WARNING(m_numReadBits > 0);
+
+ if (m_memoryBuffer == NULL) {
+ if (pFile == NULL) {
+ ASSERT(m_pFile);
+ if (m_virtual_IO->Read(m_pFile, pBytes, numBytes) != numBytes) {
+ throw new MP4Error("not enough bytes, reached end-of-file", "MP4ReadBytes");
+ }
+ } else {
+ if (fread(pBytes, 1, numBytes, pFile) != numBytes) {
+ if (feof(pFile)) {
+ throw new MP4Error(
+ "not enough bytes, reached end-of-file",
+ "MP4ReadBytes");
+ } else {
+ throw new MP4Error(errno, "MP4ReadBytes");
+ }
+ }
+ }
+ } else {
+ if (m_memoryBufferPosition + numBytes > m_memoryBufferSize) {
+ throw new MP4Error(
+ "not enough bytes, reached end-of-memory",
+ "MP4ReadBytes");
+ }
+ memcpy(pBytes, &m_memoryBuffer[m_memoryBufferPosition], numBytes);
+ m_memoryBufferPosition += numBytes;
+ }
+ return;
+}
+
+void MP4File::PeekBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile)
+{
+ u_int64_t pos = GetPosition(pFile);
+ ReadBytes(pBytes, numBytes, pFile);
+ SetPosition(pos, pFile);
+}
+
+void MP4File::EnableMemoryBuffer(u_int8_t* pBytes, u_int64_t numBytes)
+{
+ ASSERT(m_memoryBuffer == NULL);
+
+ if (pBytes) {
+ m_memoryBuffer = pBytes;
+ m_memoryBufferSize = numBytes;
+ } else {
+ if (numBytes) {
+ m_memoryBufferSize = numBytes;
+ } else {
+ m_memoryBufferSize = 4096;
+ }
+ m_memoryBuffer = (u_int8_t*)MP4Malloc(m_memoryBufferSize);
+ }
+ m_memoryBufferPosition = 0;
+}
+
+void MP4File::DisableMemoryBuffer(u_int8_t** ppBytes, u_int64_t* pNumBytes)
+{
+ ASSERT(m_memoryBuffer != NULL);
+
+ if (ppBytes) {
+ *ppBytes = m_memoryBuffer;
+ }
+ if (pNumBytes) {
+ *pNumBytes = m_memoryBufferPosition;
+ }
+
+ m_memoryBuffer = NULL;
+ m_memoryBufferSize = 0;
+ m_memoryBufferPosition = 0;
+}
+
+void MP4File::WriteBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile)
+{
+ ASSERT(m_numWriteBits == 0 || m_numWriteBits >= 8);
+
+ if (pBytes == NULL || numBytes == 0) {
+ return;
+ }
+
+ if (m_memoryBuffer == NULL) {
+ if (pFile == NULL) {
+ ASSERT(m_pFile);
+ if (m_virtual_IO->Write(m_pFile, pBytes, numBytes) != numBytes) {
+ throw new MP4Error("error writing bytes via virtual I/O", "MP4WriteBytes");
+ }
+ } else {
+ u_int32_t rc = (u_int32_t)fwrite(pBytes, 1, numBytes, pFile);
+ if (rc != numBytes) {
+ throw new MP4Error(errno, "MP4WriteBytes");
+ }
+ }
+ } else {
+ if (m_memoryBufferPosition + numBytes > m_memoryBufferSize) {
+ m_memoryBufferSize = 2 * (m_memoryBufferSize + numBytes);
+ m_memoryBuffer = (u_int8_t*)
+ MP4Realloc(m_memoryBuffer, m_memoryBufferSize);
+ }
+ memcpy(&m_memoryBuffer[m_memoryBufferPosition], pBytes, numBytes);
+ m_memoryBufferPosition += numBytes;
+ }
+}
+
+u_int64_t MP4File::ReadUInt(u_int8_t size)
+{
+ switch (size) {
+ case 1:
+ return ReadUInt8();
+ case 2:
+ return ReadUInt16();
+ case 3:
+ return ReadUInt24();
+ case 4:
+ return ReadUInt32();
+ case 8:
+ return ReadUInt64();
+ default:
+ ASSERT(false);
+ return 0;
+ }
+}
+
+void MP4File::WriteUInt(u_int64_t val, u_int8_t size)
+{
+ switch (size) {
+ case 1:
+ WriteUInt8((u_int8_t)val);
+ break;
+ case 2:
+ WriteUInt16((u_int16_t)val);
+ break;
+ case 3:
+ WriteUInt24((u_int32_t)val);
+ break;
+ case 4:
+ WriteUInt32((u_int32_t)val);
+ break;
+ case 8:
+ WriteUInt64((u_int64_t)val);
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+}
+
+#if 0
+void MP4File::WriteUInt(u_int64_t value, u_int8_t size)
+{
+ switch (size) {
+ case 1:
+ WriteUInt8(value);
+ case 2:
+ WriteUInt16(value);
+ case 3:
+ WriteUInt24(value);
+ case 4:
+ WriteUInt32(value);
+ case 8:
+ WriteUInt64(value);
+ default:
+ ASSERT(false);
+ }
+}
+#endif
+
+u_int8_t MP4File::ReadUInt8()
+{
+ u_int8_t data;
+ ReadBytes(&data, 1);
+ return data;
+}
+
+void MP4File::WriteUInt8(u_int8_t value)
+{
+ WriteBytes(&value, 1);
+}
+
+u_int16_t MP4File::ReadUInt16()
+{
+ u_int8_t data[2];
+ ReadBytes(&data[0], 2);
+ return ((data[0] << 8) | data[1]);
+}
+
+void MP4File::WriteUInt16(u_int16_t value)
+{
+ u_int8_t data[2];
+ data[0] = (value >> 8) & 0xFF;
+ data[1] = value & 0xFF;
+ WriteBytes(data, 2);
+}
+
+u_int32_t MP4File::ReadUInt24()
+{
+ u_int8_t data[3];
+ ReadBytes(&data[0], 3);
+ return ((data[0] << 16) | (data[1] << 8) | data[2]);
+}
+
+void MP4File::WriteUInt24(u_int32_t value)
+{
+ u_int8_t data[3];
+ data[0] = (value >> 16) & 0xFF;
+ data[1] = (value >> 8) & 0xFF;
+ data[2] = value & 0xFF;
+ WriteBytes(data, 3);
+}
+
+u_int32_t MP4File::ReadUInt32()
+{
+ u_int8_t data[4];
+ ReadBytes(&data[0], 4);
+ return ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]);
+}
+
+void MP4File::WriteUInt32(u_int32_t value)
+{
+ u_int8_t data[4];
+ data[0] = (value >> 24) & 0xFF;
+ data[1] = (value >> 16) & 0xFF;
+ data[2] = (value >> 8) & 0xFF;
+ data[3] = value & 0xFF;
+ WriteBytes(data, 4);
+}
+
+u_int64_t MP4File::ReadUInt64()
+{
+ u_int8_t data[8];
+ u_int64_t result = 0;
+ u_int64_t temp;
+
+ ReadBytes(&data[0], 8);
+
+ for (int i = 0; i < 8; i++) {
+ temp = data[i];
+ result |= temp << ((7 - i) * 8);
+ }
+ return result;
+}
+
+void MP4File::WriteUInt64(u_int64_t value)
+{
+ u_int8_t data[8];
+
+ for (int i = 7; i >= 0; i--) {
+ data[i] = value & 0xFF;
+ value >>= 8;
+ }
+ WriteBytes(data, 8);
+}
+
+float MP4File::ReadFixed16()
+{
+ u_int8_t iPart = ReadUInt8();
+ u_int8_t fPart = ReadUInt8();
+
+ return iPart + (((float)fPart) / 0x100);
+}
+
+void MP4File::WriteFixed16(float value)
+{
+ if (value >= 0x100) {
+ throw new MP4Error(ERANGE, "MP4WriteFixed16");
+ }
+
+ u_int8_t iPart = (u_int8_t)value;
+ u_int8_t fPart = (u_int8_t)((value - iPart) * 0x100);
+
+ WriteUInt8(iPart);
+ WriteUInt8(fPart);
+}
+
+float MP4File::ReadFixed32()
+{
+ u_int16_t iPart = ReadUInt16();
+ u_int16_t fPart = ReadUInt16();
+
+ return iPart + (((float)fPart) / 0x10000);
+}
+
+void MP4File::WriteFixed32(float value)
+{
+ if (value >= 0x10000) {
+ throw new MP4Error(ERANGE, "MP4WriteFixed32");
+ }
+
+ u_int16_t iPart = (u_int16_t)value;
+ u_int16_t fPart = (u_int16_t)((value - iPart) * 0x10000);
+
+ WriteUInt16(iPart);
+ WriteUInt16(fPart);
+}
+
+float MP4File::ReadFloat()
+{
+ union {
+ float f;
+ u_int32_t i;
+ } u;
+
+ u.i = ReadUInt32();
+ return u.f;
+}
+
+void MP4File::WriteFloat(float value)
+{
+ union {
+ float f;
+ u_int32_t i;
+ } u;
+
+ u.f = value;
+ WriteUInt32(u.i);
+}
+
+char* MP4File::ReadString()
+{
+ uint32_t readSize=1;
+ u_int32_t length = 0;
+ u_int32_t alloced = 64;
+ uint8_t* data = (uint8_t*)MP4Malloc(alloced);
+
+ ReadBytes((u_int8_t*)&data[length++], 1);
+ if (data[0] == 0xFF || data[0] == 0xFE)
+ {
+ ReadBytes((u_int8_t*)&data[length++], 1);
+ if ((data[0] == 0xFF && data[1] == 0xFE)
+ || (data[0] == 0xFE && data[1] == 0xFF))
+ readSize=2; // Unicode
+ }
+
+ while (1)
+ {
+ if (readSize == 1 && data[length - 1] == 0)
+ break;
+ if (readSize == 2)
+ {
+ uint16_t *utf16 = (uint16_t *)data;
+ if (utf16[length/2 - 1] == 0)
+ break;
+ }
+
+ if (length == alloced) {
+ data = (uint8_t*)MP4Realloc(data, alloced * 2);
+ if (data == NULL) return NULL;
+ alloced *= 2;
+ }
+ ReadBytes((u_int8_t*)&data[length], readSize);
+ length+=readSize;
+ }
+
+ data = (uint8_t*)MP4Realloc(data, length);
+ return (char *)data;
+}
+
+uint16_t *MP4File::ReadUnicodeString()
+{
+ u_int32_t length = 0;
+ u_int32_t alloced = 64;
+ uint16_t *data = (uint16_t *)MP4Malloc(alloced*sizeof(uint16_t));
+
+ do {
+ if (length == alloced) {
+ data = (uint16_t *)MP4Realloc(data, (alloced * 2)*sizeof(uint16_t));
+ if (data == NULL) return NULL;
+ alloced *= 2;
+ }
+ ReadBytes((u_int8_t *)&data[length], 2);
+ length++;
+ } while (data[length - 1] != 0);
+
+ data = (uint16_t *)MP4Realloc(data, length*sizeof(uint16_t));
+ return data;
+}
+
+void MP4File::WriteString(char* string)
+{
+ if (string == NULL) {
+ u_int8_t zero = 0;
+ WriteBytes(&zero, 1);
+ } else {
+ WriteBytes((u_int8_t*)string, (u_int32_t)strlen(string) + 1);
+ }
+}
+
+void MP4File::WriteUnicodeString(const uint16_t *string)
+{
+ if (string == NULL) {
+ u_int8_t zero = 0;
+ WriteBytes(&zero, 1);
+ } else {
+ const uint16_t *itr = string;
+ int len=0;
+ while (*itr)
+ {
+ itr++;
+ len++;
+ }
+ WriteBytes((u_int8_t*)string, (len + 1)*sizeof(uint16_t));
+ }
+}
+
+char* MP4File::ReadCountedString(u_int8_t charSize, bool allowExpandedCount)
+{
+ u_int32_t charLength;
+ if (allowExpandedCount) {
+ u_int8_t b;
+ uint ix = 0;
+ charLength = 0;
+ do {
+ b = ReadUInt8();
+ charLength += b;
+ ix++;
+ if (ix > 25)
+ throw new MP4Error(ERANGE,
+ "Counted string too long 25 * 255");
+ } while (b == 255);
+ } else {
+ charLength = ReadUInt8();
+ }
+
+ u_int32_t byteLength = charLength * charSize;
+ char* data = (char*)MP4Malloc(byteLength + 1);
+ if (byteLength > 0) {
+ ReadBytes((u_int8_t*)data, byteLength);
+ }
+ data[byteLength] = '\0';
+ return data;
+}
+
+void MP4File::WriteCountedString(char* string,
+ u_int8_t charSize, bool allowExpandedCount)
+{
+ u_int32_t byteLength;
+ if (string) {
+ byteLength = (u_int32_t)strlen(string);
+ } else {
+ byteLength = 0;
+ }
+ u_int32_t charLength = byteLength / charSize;
+
+ if (allowExpandedCount) {
+ while (charLength >= 0xFF) {
+ WriteUInt8(0xFF);
+ charLength -= 0xFF;
+ }
+ WriteUInt8(charLength);
+ } else {
+ if (charLength > 255) {
+ throw new MP4Error(ERANGE, "Length is %d", "MP4WriteCountedString", charLength);
+ }
+ WriteUInt8(charLength);
+ }
+
+ if (byteLength > 0) {
+ WriteBytes((u_int8_t*)string, byteLength);
+ }
+}
+
+u_int64_t MP4File::ReadBits(u_int8_t numBits)
+{
+ ASSERT(numBits > 0);
+ ASSERT(numBits <= 64);
+
+ u_int64_t bits = 0;
+
+ for (u_int8_t i = numBits; i > 0; i--) {
+ if (m_numReadBits == 0) {
+ ReadBytes(&m_bufReadBits, 1);
+ m_numReadBits = 8;
+ }
+ bits = (bits << 1) | ((m_bufReadBits >> (--m_numReadBits)) & 1);
+ }
+
+ return bits;
+}
+
+void MP4File::FlushReadBits()
+{
+ // eat any remaining bits in the read buffer
+ m_numReadBits = 0;
+}
+
+void MP4File::WriteBits(u_int64_t bits, u_int8_t numBits)
+{
+ ASSERT(numBits <= 64);
+
+ for (u_int8_t i = numBits; i > 0; i--) {
+ m_bufWriteBits |=
+ (((bits >> (i - 1)) & 1) << (8 - ++m_numWriteBits));
+
+ if (m_numWriteBits == 8) {
+ FlushWriteBits();
+ }
+ }
+}
+
+void MP4File::PadWriteBits(u_int8_t pad)
+{
+ if (m_numWriteBits) {
+ WriteBits(pad ? 0xFF : 0x00, 8 - m_numWriteBits);
+ }
+}
+
+void MP4File::FlushWriteBits()
+{
+ if (m_numWriteBits > 0) {
+ WriteBytes(&m_bufWriteBits, 1);
+ m_numWriteBits = 0;
+ m_bufWriteBits = 0;
+ }
+}
+
+u_int32_t MP4File::ReadMpegLength()
+{
+ u_int32_t length = 0;
+ u_int8_t numBytes = 0;
+ u_int8_t b;
+
+ do {
+ b = ReadUInt8();
+ length = (length << 7) | (b & 0x7F);
+ numBytes++;
+ } while ((b & 0x80) && numBytes < 4);
+
+ return length;
+}
+
+void MP4File::WriteMpegLength(u_int32_t value, bool compact)
+{
+ if (value > 0x0FFFFFFF) {
+ throw new MP4Error(ERANGE, "MP4WriteMpegLength");
+ }
+
+ int8_t numBytes;
+
+ if (compact) {
+ if (value <= 0x7F) {
+ numBytes = 1;
+ } else if (value <= 0x3FFF) {
+ numBytes = 2;
+ } else if (value <= 0x1FFFFF) {
+ numBytes = 3;
+ } else {
+ numBytes = 4;
+ }
+ } else {
+ numBytes = 4;
+ }
+
+ int8_t i = numBytes;
+ do {
+ i--;
+ u_int8_t b = (value >> (i * 7)) & 0x7F;
+ if (i > 0) {
+ b |= 0x80;
+ }
+ WriteUInt8(b);
+ } while (i > 0);
+}