/***************************************************************** | | AP4 - Byte Stream support | | Copyright 2002-2008 Axiomatic Systems, LLC | | | This file is part of Bento4/AP4 (MP4 Atom Processing Library). | | Unless you have obtained Bento4 under a difference license, | this version of Bento4 is Bento4|GPL. | Bento4|GPL is free software; you can redistribute it and/or modify | it under the terms of the GNU General Public License as published by | the Free Software Foundation; either version 2, or (at your option) | any later version. | | Bento4|GPL is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with Bento4|GPL; see the file COPYING. If not, write to the | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA | 02111-1307, USA. | ****************************************************************/ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "Ap4ByteStream.h" #include "Ap4Utils.h" #include "Ap4Debug.h" #include "Ap4String.h" /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ const int AP4_BYTE_STREAM_COPY_BUFFER_SIZE = 65536; /*---------------------------------------------------------------------- | AP4_ByteStream::Read +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::Read(void* buffer, AP4_Size bytes_to_read) { // shortcut if (bytes_to_read == 0) return AP4_SUCCESS; // read until failure AP4_Size bytes_read; while (bytes_to_read) { AP4_Result result = ReadPartial(buffer, bytes_to_read, bytes_read); if (AP4_FAILED(result)) return result; if (bytes_read == 0) return AP4_ERROR_INTERNAL; AP4_ASSERT(bytes_read <= bytes_to_read); bytes_to_read -= bytes_read; buffer = (void*)(((AP4_Byte*)buffer)+bytes_read); } return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_Stream::Write +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::Write(const void* buffer, AP4_Size bytes_to_write) { // shortcut if (bytes_to_write == 0) return AP4_SUCCESS; // write until failure AP4_Size bytes_written; while (bytes_to_write) { AP4_Result result = WritePartial(buffer, bytes_to_write, bytes_written); if (AP4_FAILED(result)) return result; if (bytes_written == 0) return AP4_ERROR_INTERNAL; AP4_ASSERT(bytes_written <= bytes_to_write); bytes_to_write -= bytes_written; buffer = (const void*)(((const AP4_Byte*)buffer)+bytes_written); } return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteString +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteString(const char* buffer) { if (buffer == NULL) return AP4_SUCCESS; AP4_Size string_length = static_cast(strlen(buffer)); if (string_length == 0) return AP4_SUCCESS; // write the string return Write((const void*)buffer, string_length); } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteDouble +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteDouble(double value) { unsigned char buffer[8]; // convert value to bytes AP4_BytesFromDoubleBE(buffer, value); // write bytes to the stream return Write((void*)buffer, 8); } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteUI64 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteUI64(AP4_UI64 value) { unsigned char buffer[8]; // convert value to bytes AP4_BytesFromUInt64BE(buffer, value); // write bytes to the stream return Write((void*)buffer, 8); } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteUI32 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteUI32(AP4_UI32 value) { unsigned char buffer[4]; // convert value to bytes AP4_BytesFromUInt32BE(buffer, value); // write bytes to the stream return Write((void*)buffer, 4); } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteUI24 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteUI24(AP4_UI32 value) { unsigned char buffer[3]; // convert value to bytes AP4_BytesFromUInt24BE(buffer, value); // write bytes to the stream return Write((void*)buffer, 3); } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteUI16 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteUI16(AP4_UI16 value) { unsigned char buffer[2]; // convert value to bytes AP4_BytesFromUInt16BE(buffer, value); // write bytes to the stream return Write((void*)buffer, 2); } /*---------------------------------------------------------------------- | AP4_ByteStream::WriteUI08 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::WriteUI08(AP4_UI08 value) { return Write((void*)&value, 1); } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadUI64 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadUI64(AP4_UI64& value) { unsigned char buffer[8]; // read bytes from the stream AP4_Result result; result = Read((void*)buffer, 8); if (AP4_FAILED(result)) { value = 0; return result; } // convert bytes to value value = AP4_BytesToUInt64BE(buffer); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadDouble +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadDouble(double& value) { unsigned char buffer[8]; // read bytes from the stream AP4_Result result; result = Read((void*)buffer, 8); if (AP4_FAILED(result)) { value = 0; return result; } // convert bytes to value value = AP4_BytesToDoubleBE(buffer); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadUI32 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadUI32(AP4_UI32& value) { unsigned char buffer[4]; // read bytes from the stream AP4_Result result; result = Read((void*)buffer, 4); if (AP4_FAILED(result)) { value = 0; return result; } // convert bytes to value value = AP4_BytesToUInt32BE(buffer); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadUI24 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadUI24(AP4_UI32& value) { unsigned char buffer[3]; // read bytes from the stream AP4_Result result; result = Read((void*)buffer, 3); if (AP4_FAILED(result)) { value = 0; return result; } // convert bytes to value value = AP4_BytesToUInt24BE(buffer); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadUI16 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadUI16(AP4_UI16& value) { unsigned char buffer[2]; // read bytes from the stream AP4_Result result; result = Read((void*)buffer, 2); if (AP4_FAILED(result)) { value = 0; return result; } // convert bytes to value value = AP4_BytesToUInt16BE(buffer); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadUI08 +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadUI08(AP4_UI08& value) { unsigned char buffer[1]; // read bytes from the stream AP4_Result result; result = Read((void*)buffer, 1); if (AP4_FAILED(result)) { value = 0; return result; } // convert bytes to value value = buffer[0]; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadString +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadString(char* buffer, AP4_Size size) { if (buffer == NULL || size == 0) { return AP4_ERROR_INVALID_PARAMETERS; } AP4_Size bytes_read = 0; while (bytes_read < size-1) { AP4_Result result; result = Read(&buffer[bytes_read], 1); if (AP4_FAILED(result)) { buffer[bytes_read] = '\0'; return result; } if (buffer[bytes_read] == '\0') { // end of string return AP4_SUCCESS; } bytes_read++; } // the string was not null terminated, terminate it buffer[size-1] = '\0'; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::ReadNullTerminatedString +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::ReadNullTerminatedString(AP4_String& string) { AP4_DataBuffer buffer; unsigned int size = 0; AP4_UI08 c = 0; do { AP4_Result result = ReadUI08(c); if (AP4_FAILED(result)) return result; buffer.SetDataSize(size+1); buffer.UseData()[size] = c; ++size; } while (c); AP4_ASSERT(size); string.Assign((const char*)buffer.GetData(), size - 1); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_ByteStream::CopyTo +---------------------------------------------------------------------*/ AP4_Result AP4_ByteStream::CopyTo(AP4_ByteStream& stream, AP4_LargeSize size) { unsigned char buffer[AP4_BYTE_STREAM_COPY_BUFFER_SIZE]; while (size) { AP4_Size bytes_read; AP4_Size bytes_to_read; AP4_Result result; // decide how much to read if (size >= sizeof(buffer)) { bytes_to_read = sizeof(buffer); } else { bytes_to_read = (AP4_Size)size; } // read up to one buffer full result = ReadPartial(buffer, bytes_to_read, bytes_read); if (AP4_FAILED(result)) return result; // copy to destination if (bytes_read != 0) { result = stream.Write(buffer, bytes_read); if (AP4_FAILED(result)) return result; } // update the size size -= bytes_read; } return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_SubStream::AP4_SubStream +---------------------------------------------------------------------*/ AP4_SubStream::AP4_SubStream(AP4_ByteStream& container, AP4_Position offset, AP4_LargeSize size) : m_Container(container), m_Offset(offset), m_Size(size), m_Position(0), m_ReferenceCount(1) { m_Container.AddReference(); } /*---------------------------------------------------------------------- | AP4_SubStream::~AP4_SubStream +---------------------------------------------------------------------*/ AP4_SubStream::~AP4_SubStream() { m_Container.Release(); } /*---------------------------------------------------------------------- | AP4_SubStream::ReadPartial +---------------------------------------------------------------------*/ AP4_Result AP4_SubStream::ReadPartial(void* buffer, AP4_Size bytes_to_read, AP4_Size& bytes_read) { // default values bytes_read = 0; // shortcut if (bytes_to_read == 0) { return AP4_SUCCESS; } // clamp to range if (m_Position+bytes_to_read > m_Size) { bytes_to_read = (AP4_Size)(m_Size - m_Position); } // check for end of substream if (bytes_to_read == 0) { return AP4_ERROR_EOS; } // seek inside container AP4_Result result; result = m_Container.Seek(m_Offset+m_Position); if (AP4_FAILED(result)) { return result; } // read from the container result = m_Container.ReadPartial(buffer, bytes_to_read, bytes_read); if (AP4_SUCCEEDED(result)) { m_Position += bytes_read; } return result; } /*---------------------------------------------------------------------- | AP4_SubStream::WritePartial +---------------------------------------------------------------------*/ AP4_Result AP4_SubStream::WritePartial(const void* buffer, AP4_Size bytes_to_write, AP4_Size& bytes_written) { // default values bytes_written = 0; // shortcut if (bytes_to_write == 0) { return AP4_SUCCESS; } // clamp to range if (m_Position+bytes_to_write > m_Size) { bytes_to_write = (AP4_Size)(m_Size - m_Position); } // check for end of substream if (bytes_to_write == 0) { return AP4_ERROR_EOS; } // seek inside container AP4_Result result; result = m_Container.Seek(m_Offset+m_Position); if (AP4_FAILED(result)) return result; // write to container result = m_Container.WritePartial(buffer, bytes_to_write, bytes_written); if (AP4_SUCCEEDED(result)) { m_Position += bytes_written; } return result; } /*---------------------------------------------------------------------- | AP4_SubStream::Seek +---------------------------------------------------------------------*/ AP4_Result AP4_SubStream::Seek(AP4_Position position) { if (position == m_Position) return AP4_SUCCESS; if (position > m_Size) return AP4_FAILURE; m_Position = position; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_SubStream::AddReference +---------------------------------------------------------------------*/ void AP4_SubStream::AddReference() { m_ReferenceCount++; } /*---------------------------------------------------------------------- | AP4_SubStream::Release +---------------------------------------------------------------------*/ void AP4_SubStream::Release() { if (--m_ReferenceCount == 0) { delete this; } } /*---------------------------------------------------------------------- | AP4_DupStream::AP4_DupStream +---------------------------------------------------------------------*/ AP4_DupStream::AP4_DupStream(AP4_ByteStream& original_stream) : m_OriginalStream(original_stream), m_Position(0), m_ReferenceCount(1) { m_OriginalStream.AddReference(); } /*---------------------------------------------------------------------- | AP4_DupStream::~AP4_DupStream +---------------------------------------------------------------------*/ AP4_DupStream::~AP4_DupStream() { m_OriginalStream.Release(); } /*---------------------------------------------------------------------- | AP4_DupStream::ReadPartial +---------------------------------------------------------------------*/ AP4_Result AP4_DupStream::ReadPartial(void* buffer, AP4_Size bytes_to_read, AP4_Size& bytes_read) { // default values bytes_read = 0; // shortcut if (bytes_to_read == 0) { return AP4_SUCCESS; } // seek to the right position in the original stream m_OriginalStream.Seek(m_Position); // read AP4_Result result = m_OriginalStream.ReadPartial(buffer, bytes_to_read, bytes_read); // adjust our position if (AP4_SUCCEEDED(result)) { m_Position += bytes_read; } return result; } /*---------------------------------------------------------------------- | AP4_DupStream::WritePartial +---------------------------------------------------------------------*/ AP4_Result AP4_DupStream::WritePartial(const void* buffer, AP4_Size bytes_to_write, AP4_Size& bytes_written) { // default values bytes_written = 0; // shortcut if (bytes_to_write == 0) { return AP4_SUCCESS; } // seek to the right position in the original stream m_OriginalStream.Seek(m_Position); // read AP4_Result result = m_OriginalStream.WritePartial(buffer, bytes_to_write, bytes_written); // adjust our position if (AP4_SUCCEEDED(result)) { m_Position += bytes_written; } return result; } /*---------------------------------------------------------------------- | AP4_DupStream::Seek +---------------------------------------------------------------------*/ AP4_Result AP4_DupStream::Seek(AP4_Position position) { if (position == m_Position) return AP4_SUCCESS; AP4_Result result = m_OriginalStream.Seek(position); if (AP4_SUCCEEDED(result)) { m_Position = position; } return result; } /*---------------------------------------------------------------------- | AP4_DupStream::AddReference +---------------------------------------------------------------------*/ void AP4_DupStream::AddReference() { m_ReferenceCount++; } /*---------------------------------------------------------------------- | AP4_DupStream::Release +---------------------------------------------------------------------*/ void AP4_DupStream::Release() { if (--m_ReferenceCount == 0) { delete this; } } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::AP4_MemoryByteStream +---------------------------------------------------------------------*/ AP4_MemoryByteStream::AP4_MemoryByteStream(AP4_Size size) : m_BufferIsLocal(true), m_Position(0), m_ReferenceCount(1) { m_Buffer = new AP4_DataBuffer(size); AP4_SetMemory(m_Buffer->UseData(), 0, size); m_Buffer->SetDataSize(size); } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::AP4_MemoryByteStream +---------------------------------------------------------------------*/ AP4_MemoryByteStream::AP4_MemoryByteStream(const AP4_UI08* buffer, AP4_Size size) : m_BufferIsLocal(true), m_Position(0), m_ReferenceCount(1) { m_Buffer = new AP4_DataBuffer(buffer, size); } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::AP4_MemoryByteStream +---------------------------------------------------------------------*/ AP4_MemoryByteStream::AP4_MemoryByteStream(AP4_DataBuffer& data_buffer) : m_Buffer(&data_buffer), m_BufferIsLocal(false), m_Position(0), m_ReferenceCount(1) { } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::AP4_MemoryByteStream +---------------------------------------------------------------------*/ AP4_MemoryByteStream::AP4_MemoryByteStream(AP4_DataBuffer* data_buffer) : m_Buffer(data_buffer), m_BufferIsLocal(true), m_Position(0), m_ReferenceCount(1) { } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::~AP4_MemoryByteStream +---------------------------------------------------------------------*/ AP4_MemoryByteStream::~AP4_MemoryByteStream() { if (m_BufferIsLocal) { delete m_Buffer; } } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::ReadPartial +---------------------------------------------------------------------*/ AP4_Result AP4_MemoryByteStream::ReadPartial(void* buffer, AP4_Size bytes_to_read, AP4_Size& bytes_read) { // default values bytes_read = 0; // shortcut if (bytes_to_read == 0) { return AP4_SUCCESS; } // clamp to range if (m_Position+bytes_to_read > m_Buffer->GetDataSize()) { bytes_to_read = (AP4_Size)(m_Buffer->GetDataSize() - m_Position); } // check for end of stream if (bytes_to_read == 0) { return AP4_ERROR_EOS; } // read from the memory AP4_CopyMemory(buffer, m_Buffer->GetData()+m_Position, bytes_to_read); m_Position += bytes_to_read; bytes_read = bytes_to_read; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::WritePartial +---------------------------------------------------------------------*/ AP4_Result AP4_MemoryByteStream::WritePartial(const void* buffer, AP4_Size bytes_to_write, AP4_Size& bytes_written) { // default values bytes_written = 0; // shortcut if (bytes_to_write == 0) { return AP4_SUCCESS; } // reserve space in the buffer AP4_Size space_needed = (AP4_Size)(m_Position+bytes_to_write); AP4_Result result = m_Buffer->Reserve(space_needed); if (AP4_SUCCEEDED(result)) { if (space_needed > m_Buffer->GetDataSize()) { // the buffer must grow m_Buffer->SetDataSize(space_needed); } } else { // failed to reserve, most likely caused by a buffer that has // external storage if (m_Position+bytes_to_write > m_Buffer->GetDataSize()) { bytes_to_write = (AP4_Size)(m_Buffer->GetDataSize() - m_Position); } } // check for end of stream if (bytes_to_write == 0) { return AP4_ERROR_EOS; } // write to memory AP4_CopyMemory((void*)(m_Buffer->UseData()+m_Position), buffer, bytes_to_write); m_Position += bytes_to_write; bytes_written = bytes_to_write; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::Seek +---------------------------------------------------------------------*/ AP4_Result AP4_MemoryByteStream::Seek(AP4_Position position) { if (position > m_Buffer->GetDataSize()) return AP4_FAILURE; m_Position = position; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::AddReference +---------------------------------------------------------------------*/ void AP4_MemoryByteStream::AddReference() { m_ReferenceCount++; } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::Release +---------------------------------------------------------------------*/ void AP4_MemoryByteStream::Release() { if (--m_ReferenceCount == 0) { delete this; } } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::AP4_BufferedInputStream +---------------------------------------------------------------------*/ AP4_BufferedInputStream::AP4_BufferedInputStream(AP4_ByteStream& source, AP4_Size buffer_size, AP4_Size seek_as_read_threshold) : m_Buffer(buffer_size), m_BufferPosition(0), m_Source(source), m_SourcePosition(0), m_SeekAsReadThreshold(seek_as_read_threshold), m_ReferenceCount(1) { source.AddReference(); } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::Refill +---------------------------------------------------------------------*/ AP4_Result AP4_BufferedInputStream::Refill() { m_BufferPosition = 0; AP4_Size bytes_read = 0; AP4_Result result = m_Source.ReadPartial(m_Buffer.UseData(), m_Buffer.GetBufferSize(), bytes_read); if (AP4_FAILED(result)) { m_Buffer.SetDataSize(0); return result; } assert(bytes_read); m_Buffer.SetDataSize(bytes_read); m_SourcePosition += bytes_read; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::ReadPartial +---------------------------------------------------------------------*/ AP4_Result AP4_BufferedInputStream::ReadPartial(void* buffer, AP4_Size bytes_to_read, AP4_Size& bytes_read) { // check for shortcut if (bytes_to_read == 0) { bytes_read = 0; return AP4_SUCCESS; } // compute how much data is available in the buffer assert(m_BufferPosition <= m_Buffer.GetDataSize()); AP4_Size available = m_Buffer.GetDataSize()-m_BufferPosition; // refill the buffer if it is empty if (available == 0) { AP4_Result result = Refill(); if (AP4_FAILED(result)) { bytes_read = 0; return result; } assert(m_BufferPosition == 0); assert(m_Buffer.GetDataSize() != 0); available = m_Buffer.GetDataSize()-m_BufferPosition; } // clamp the number of bytes to read to what's available if (bytes_to_read > available) bytes_to_read = available; bytes_read = bytes_to_read; // copy the buffered data AP4_CopyMemory(buffer, m_Buffer.GetData()+m_BufferPosition, bytes_to_read); m_BufferPosition += bytes_to_read; assert(m_BufferPosition <= m_Buffer.GetDataSize()); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::WritePartial +---------------------------------------------------------------------*/ AP4_Result AP4_BufferedInputStream::WritePartial(const void* /*buffer*/, AP4_Size /*bytes_to_write*/, AP4_Size& /*bytes_written*/) { return AP4_ERROR_NOT_SUPPORTED; } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::Seek +---------------------------------------------------------------------*/ AP4_Result AP4_BufferedInputStream::Seek(AP4_Position position) { assert(m_SourcePosition >= m_Buffer.GetDataSize()); assert(m_BufferPosition <= m_Buffer.GetDataSize()); if (position < m_SourcePosition-m_Buffer.GetDataSize() || position > m_SourcePosition) { // out of buffer m_BufferPosition = 0; m_Buffer.SetDataSize(0); // seek in the source if (position > m_SourcePosition && (position-m_SourcePosition <= m_SeekAsReadThreshold)) { char* discard = new char[4096]; AP4_Size to_skip = (AP4_Size)(position-m_SourcePosition); while (to_skip) { AP4_Size chunk = 4096; if (chunk > to_skip) chunk = to_skip; AP4_Result result = m_Source.Read(discard, chunk); if (AP4_FAILED(result)) { delete[] discard; return result; } m_SourcePosition += chunk; to_skip -= chunk; } delete[] discard; return AP4_SUCCESS; } else { m_SourcePosition = position; return m_Source.Seek(position); } } // compute the buffer position m_BufferPosition = (AP4_Size)(position-(m_SourcePosition-m_Buffer.GetDataSize())); return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::Tell +---------------------------------------------------------------------*/ AP4_Result AP4_BufferedInputStream::Tell(AP4_Position& position) { assert(m_SourcePosition >= m_Buffer.GetDataSize()); assert(m_BufferPosition <= m_Buffer.GetDataSize()); position = m_SourcePosition-m_Buffer.GetDataSize()+m_BufferPosition; return AP4_SUCCESS; } /*---------------------------------------------------------------------- | AP4_BufferedInputStream::AddReference +---------------------------------------------------------------------*/ void AP4_BufferedInputStream::AddReference() { m_ReferenceCount++; } /*---------------------------------------------------------------------- | AP4_MemoryByteStream::Release +---------------------------------------------------------------------*/ void AP4_BufferedInputStream::Release() { if (--m_ReferenceCount == 0) { delete this; } }