/* * DataHandlerCallback.cpp * * DataHandlerCallback.cpp - file I/O for libebml. * * * Copyright (c) 2006 David Conrad * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "DataHandlerCallback.h" #include #include "ebml/Debug.h" #include "ebml/EbmlConfig.h" using namespace std; CRTError::CRTError(int nError, const std::string & Description) :std::runtime_error(Description+": "+strerror(nError)) ,Error(Error) { } CRTError::CRTError(const std::string & Description,int nError) :std::runtime_error(Description+": "+strerror(nError)) ,Error(Error) { } DataHBuffer::DataHBuffer(size_t bufferSize) { buffer = new uint8_t[bufferSize]; allocatedSize = bufferSize; fileOffset = -1; dataSize = 0; } DataHBuffer::~DataHBuffer() { if (buffer) delete[] buffer; } void DataHBuffer::Realloc(size_t bufferSize) { if (buffer) delete[] buffer; buffer = new uint8_t[bufferSize]; allocatedSize = bufferSize; fileOffset = -1; dataSize = 0; } bool DataHBuffer::ContainsOffset(uint64_t offset) { return offset >= fileOffset && offset < fileOffset + dataSize; } uint8_t * DataHBuffer::GetBuffer(uint64_t offset, size_t size) { if (size > allocatedSize) Realloc(size); fileOffset = offset; dataSize = size; return buffer; } size_t DataHBuffer::Read(uint64_t offset, size_t size, uint8_t *store) { if (!ContainsOffset(offset)) return 0; uint8_t *dataStart = buffer + (offset - fileOffset); size_t amountToRead = MIN(fileOffset + dataSize - offset, size); memcpy(store, dataStart, amountToRead); return amountToRead; } DataHandlerCallback::DataHandlerCallback(ComponentInstance dataHandler, const open_mode aMode) { Initialize(aMode); switch (aMode) { case MODE_READ: case MODE_WRITE: this->dataHandler = dataHandler; break; default: throw 0; break; } // figure out if we support wide offesets getFileSize(); } DataHandlerCallback::DataHandlerCallback(Handle dataRef, OSType dataRefType, const open_mode aMode) { ComponentResult err = noErr; Component dataHComponent = NULL; Initialize(aMode); if (aMode == MODE_READ) dataHComponent = GetDataHandler(dataRef, dataRefType, kDataHCanRead); else if (aMode == MODE_WRITE) dataHComponent = GetDataHandler(dataRef, dataRefType, kDataHCanWrite); else throw 0; err = OpenAComponent(dataHComponent, &dataHandler); if (err) { throw CRTError("Error opening data handler component", err); } err = DataHSetDataRef(dataHandler, dataRef); if (err) { throw CRTError("Error setting data handler ref", err); } if (aMode == MODE_READ) { err = DataHOpenForRead(dataHandler); if (err) { throw CRTError("Error opening data handler for read", err); } } else if (aMode == MODE_WRITE) { err = DataHOpenForWrite(dataHandler); if (err) { throw CRTError("Error opening data handler for write", err); } } else { throw 0; } closeHandler = true; // figure out if we support wide offesets getFileSize(); } void DataHandlerCallback::Initialize(const open_mode aMode) { closeHandler = false; supportsWideOffsets = true; this->dataHandler = NULL; mCurrentPosition = 0; filesize = 0; this->aMode = aMode; } DataHandlerCallback::~DataHandlerCallback() throw() { close(); } uint32 DataHandlerCallback::read(void *buffer, size_t size) { ComponentResult err = noErr; size_t amountRead = 0; uint64_t oldPos = mCurrentPosition; uint8_t *internalBuffer, *myBuffer = (uint8_t *)buffer; if (size < 1 || mCurrentPosition > filesize) return 0; if (mCurrentPosition + size > filesize) size = filesize - mCurrentPosition; while (size > 0) { if (dataBuffer.ContainsOffset(mCurrentPosition)) { amountRead = dataBuffer.Read(mCurrentPosition, size, myBuffer); myBuffer += amountRead; mCurrentPosition += amountRead; size -= amountRead; } if (size <= 0) break; internalBuffer = dataBuffer.GetBuffer(mCurrentPosition, READ_SIZE); if (supportsWideOffsets) { wide wideOffset = SInt64ToWide(mCurrentPosition); err = DataHScheduleData64(dataHandler, (Ptr)internalBuffer, &wideOffset, READ_SIZE, 0, NULL, NULL); } else { err = DataHScheduleData(dataHandler, (Ptr)internalBuffer, mCurrentPosition, READ_SIZE, 0, NULL, NULL); } if (err) { throw CRTError("Error reading data", err); } } return mCurrentPosition - oldPos; } void DataHandlerCallback::setFilePointer(int64 Offset, seek_mode Mode) { switch ( Mode ) { case SEEK_CUR: mCurrentPosition += Offset; break; case SEEK_END: // I think this is what seeking this way does (was ftell(File)) mCurrentPosition = getFileSize() + Offset; break; case SEEK_SET: mCurrentPosition = Offset; break; } } size_t DataHandlerCallback::write(const void *Buffer, size_t Size) { ComponentResult err = noErr; if (supportsWideOffsets) { wide wideOffset = SInt64ToWide(mCurrentPosition); err = DataHWrite64(dataHandler, (Ptr)Buffer, &wideOffset, Size, NULL, 0); } else { err = DataHWrite(dataHandler, (Ptr)Buffer, mCurrentPosition, Size, NULL, 0); } if (err) { throw CRTError("Error writing data", err); } mCurrentPosition += Size; // does QT tell us how much it writes? return Size; } uint64 DataHandlerCallback::getFilePointer() { return mCurrentPosition; } void DataHandlerCallback::close() { if (closeHandler) { if (aMode == MODE_READ) DataHCloseForRead(dataHandler); else if (aMode == MODE_WRITE) DataHCloseForWrite(dataHandler); dataHandler = NULL; } } SInt64 DataHandlerCallback::getFileSize() { ComponentResult err = noErr; wide wideFilesize; if (filesize > 0) return filesize; err = DataHGetFileSize64(dataHandler, &wideFilesize); if (err == noErr) { supportsWideOffsets = true; filesize = WideToSInt64(wideFilesize); } else { long size32; supportsWideOffsets = false; DataHGetFileSize(dataHandler, &size32); filesize = size32; } return filesize; }