summaryrefslogtreecommitdiff
path: root/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp')
-rw-r--r--libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp689
1 files changed, 689 insertions, 0 deletions
diff --git a/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp b/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp
new file mode 100644
index 0000000000..c8a93d2756
--- /dev/null
+++ b/libs/appleutility/CoreAudio/AudioFile/AFPublic/DataSource.cpp
@@ -0,0 +1,689 @@
+/*
+ File: DataSource.cpp
+ Abstract: DataSource.h
+ Version: 1.1
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
+ Inc. ("Apple") in consideration of your agreement to the following
+ terms, and your use, installation, modification or redistribution of
+ this Apple software constitutes acceptance of these terms. If you do
+ not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and
+ subject to these terms, Apple grants you a personal, non-exclusive
+ license, under Apple's copyrights in this original Apple software (the
+ "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ Software, with or without modifications, in source and/or binary forms;
+ provided that if you redistribute the Apple Software in its entirety and
+ without modifications, you must retain this notice and the following
+ text and disclaimers in all such redistributions of the Apple Software.
+ Neither the name, trademarks, service marks or logos of Apple Inc. may
+ be used to endorse or promote products derived from the Apple Software
+ without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or
+ implied, are granted by Apple herein, including but not limited to any
+ patent rights that may be infringed by your derivative works or by other
+ works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
+ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ Copyright (C) 2014 Apple Inc. All Rights Reserved.
+
+*/
+#include "DataSource.h"
+#if TARGET_OS_WIN32
+ #include <io.h>
+#else
+ #include <unistd.h>
+ #include <fcntl.h>
+#endif
+#include <sys/stat.h>
+#include <algorithm>
+
+#define VERBOSE 0
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+const UInt16 kPositionModeMask = 3;
+
+DataSource::DataSource(Boolean inCloseOnDelete)
+ : mCloseOnDelete(inCloseOnDelete)
+{
+}
+
+DataSource::~DataSource()
+{
+}
+
+SInt64 DataSource::CalcOffset( UInt16 positionMode,
+ SInt64 positionOffset,
+ SInt64 currentOffset,
+ SInt64 size)
+{
+ SInt64 newOffset = 0;
+ switch (positionMode & kPositionModeMask) {
+ //case fsAtMark : newOffset = currentOffset; break;
+ case SEEK_SET : newOffset = positionOffset; break;
+ case SEEK_END : newOffset = size + positionOffset; break;
+ case SEEK_CUR : newOffset = positionOffset + currentOffset; break;
+ }
+ return newOffset;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+
+MacFile_DataSource::MacFile_DataSource( FSIORefNum inForkRefNum, SInt8 inPermissions, Boolean inCloseOnDelete)
+ : DataSource(inCloseOnDelete), mFileNum(inForkRefNum), mPermissions(inPermissions)
+{
+}
+
+MacFile_DataSource::~MacFile_DataSource()
+{
+ if (mCloseOnDelete) FSCloseFork(mFileNum);
+}
+
+
+OSStatus MacFile_DataSource::GetSize(SInt64& outSize)
+{
+ outSize = -1; // in case of error
+ OSStatus err = FSGetForkSize(mFileNum, &outSize);
+ return err;
+}
+
+OSStatus MacFile_DataSource::GetPos(SInt64& outPos) const
+{
+ return FSGetForkPosition(mFileNum, &outPos);
+}
+
+OSStatus MacFile_DataSource::SetSize(SInt64 inSize)
+{
+ return FSSetForkSize(mFileNum, SEEK_SET, inSize);
+}
+
+
+OSStatus MacFile_DataSource::ReadBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ void *buffer,
+ UInt32* actualCount)
+{
+ if (actualCount) *actualCount = 0;
+ if (!buffer) return kAudio_ParamError;
+ ByteCount bc_actualCount = 0;
+ OSStatus err = FSReadFork(mFileNum, positionMode, positionOffset, requestCount, buffer, &bc_actualCount);
+ if (actualCount) *actualCount = (UInt32)bc_actualCount;
+ return err;
+}
+
+OSStatus MacFile_DataSource::WriteBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ const void *buffer,
+ UInt32* actualCount)
+{
+ if (!buffer) return kAudio_ParamError;
+ ByteCount bc_actualCount = 0;
+ OSStatus err = FSWriteFork(mFileNum, positionMode, positionOffset, requestCount, buffer, &bc_actualCount);
+ if (actualCount) *actualCount = (UInt32)bc_actualCount;
+ return err;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#define kAudioFileNoCacheMask 0x20
+
+UnixFile_DataSource::UnixFile_DataSource( int inFD, SInt8 inPermissions, Boolean inCloseOnDelete)
+ : DataSource(inCloseOnDelete), mFileD(inFD), mPermissions(inPermissions), mNoCache(0), mCachedSize(-1), mFilePointer(0)
+{
+}
+
+UnixFile_DataSource::~UnixFile_DataSource()
+{
+ if (mCloseOnDelete) close(mFileD);
+}
+
+OSStatus UnixFile_DataSource::GetSize(SInt64& outSize)
+{
+#if 0 // 6764274 using the cached file size causes a regression for apps that play a file while writing to it.
+ if (mCachedSize >= 0) {
+ outSize = mCachedSize;
+ return noErr;
+ }
+#endif
+ outSize = -1; // in case of error
+ struct stat stbuf;
+ if (fstat (mFileD, &stbuf) == -1) return kAudio_FileNotFoundError;
+ outSize = mCachedSize = stbuf.st_size;
+ return noErr;
+}
+
+OSStatus UnixFile_DataSource::SetSize(SInt64 inSize)
+{
+ mCachedSize = -1;
+#if TARGET_OS_WIN32
+ if (chsize (mFileD, inSize)) return kAudioFilePermissionsError;
+#else
+ if (ftruncate (mFileD, inSize) == -1) return kAudioFilePermissionsError;
+#endif
+ mCachedSize = inSize;
+ return noErr;
+}
+
+
+OSStatus UnixFile_DataSource::GetPos(SInt64& outPos) const
+{
+ outPos = mFilePointer;
+ return noErr;
+}
+
+SInt64 UnixFile_DataSource::UFCurrentOffset (UInt16 positionMode,
+ SInt64 positionOffset)
+{
+ SInt64 offset = -1;
+ switch (positionMode & kPositionModeMask)
+ {
+ /*case fsAtMark :
+ {
+ SInt64 pos;
+ OSStatus result = GetPos (pos);
+ if (result) return result;
+ offset = pos;
+ break;
+ }*/
+ case SEEK_SET :
+ {
+ offset = positionOffset;
+ break;
+ }
+ case SEEK_END :
+ {
+ SInt64 size;
+ OSStatus result = GetSize (size);
+ if (result) return result;
+ offset = size + positionOffset;
+ break;
+ }
+ case SEEK_CUR :
+ {
+ SInt64 pos;
+ OSStatus result = GetPos (pos);
+ if (result) return result;
+ offset = positionOffset + pos;
+ break;
+ }
+ }
+ return offset;
+}
+
+OSStatus UnixFile_DataSource::ReadBytes( UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ void *buffer,
+ UInt32* actualCount)
+{
+ if (actualCount) *actualCount = 0;
+ if (!buffer) return kAudio_ParamError;
+
+ // can't use current offset as we need to go to the disk too much
+ SInt64 offset = UFCurrentOffset (positionMode, positionOffset);
+ if (offset < 0) return kAudioFilePositionError;
+
+#if 0 // 6571050 fstat-ing the file every read causes a performance regression
+ // 5931571 check that read may exceed eof and curtail it.
+ do {
+ SInt64 size;
+ OSStatus serr = GetSize(size);
+ if (serr) break;
+ SInt64 remain = size - offset;
+ if (remain < 0) requestCount = 0;
+ else if (requestCount > remain) requestCount = remain;
+ } while (false);
+#endif
+
+ if (requestCount <= 0) {
+ if (actualCount) *actualCount = 0;
+ return noErr;
+ }
+
+#if !TARGET_OS_WIN32
+ UInt32 noCache = positionMode & kAudioFileNoCacheMask ? 1 : 0;
+ if (noCache != mNoCache) {
+ mNoCache = noCache;
+ fcntl(mFileD, F_NOCACHE, mNoCache);
+ }
+#endif
+
+ size_t readBytes = requestCount;
+#if TARGET_OS_WIN32
+ lseek(mFileD, offset, SEEK_SET);
+ int numBytes = read (mFileD, buffer, readBytes);
+#else
+ ssize_t numBytes = pread (mFileD, buffer, readBytes, offset);
+#endif
+ if (numBytes == -1) return kAudioFilePositionError;
+ mFilePointer = offset + numBytes;
+
+ if (actualCount) *actualCount = (UInt32)numBytes;
+ return noErr;
+}
+
+OSStatus UnixFile_DataSource::WriteBytes(UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ const void *buffer,
+ UInt32* actualCount)
+{
+ if (!buffer) return kAudio_ParamError;
+
+ // can't use current offset as we need to go to the disk too much
+ SInt64 offset = UFCurrentOffset (positionMode, positionOffset);
+ if (offset < 0) return kAudioFilePositionError;
+
+ mCachedSize = -1;
+
+ size_t writeBytes = requestCount;
+
+#if !TARGET_OS_WIN32
+ UInt32 noCache = positionMode & kAudioFileNoCacheMask ? 1 : 0;
+ if (noCache != mNoCache) {
+ mNoCache = noCache;
+ fcntl(mFileD, F_NOCACHE, mNoCache);
+ }
+#endif
+
+#if TARGET_OS_WIN32
+ lseek(mFileD, offset, SEEK_SET);
+ int numBytes = write (mFileD, buffer, writeBytes);
+#else
+ ssize_t numBytes = pwrite (mFileD, buffer, writeBytes, offset);
+#endif
+ if (numBytes == -1) return kAudioFilePositionError;
+ mFilePointer = offset + numBytes;
+
+ if (actualCount) *actualCount = (UInt32)numBytes;
+ return noErr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#define NO_CACHE 0
+
+OSStatus Cached_DataSource::ReadFromHeaderCache(
+ SInt64 offset,
+ UInt32 requestCount,
+ void *buffer,
+ UInt32* actualCount)
+{
+ if (actualCount) *actualCount = 0;
+ OSStatus err = noErr;
+ ByteCount theActualCount = 0;
+
+#if VERBOSE
+ printf("read from header %lld %lu %lld %lu\n", offset, requestCount, 0LL, mHeaderCacheSize);
+#endif
+
+ if (!mHeaderCache())
+ {
+ mHeaderCache.allocBytes(mHeaderCacheSize, true);
+ err = mDataSource->ReadBytes(SEEK_SET, 0, mHeaderCacheSize, mHeaderCache(), &mHeaderCacheSize);
+ if (err == kAudioFileEndOfFileError) err = noErr;
+ if (err) return err;
+ }
+
+ ByteCount firstPart = std::min((ByteCount)requestCount, (ByteCount)(mHeaderCacheSize - offset));
+ ByteCount secondPart = requestCount - firstPart;
+
+ memcpy(buffer, mHeaderCache + (ByteCount)offset, firstPart);
+ theActualCount = firstPart;
+
+ if (secondPart) {
+ UInt32 secondPartActualCount = 0;
+ err = mDataSource->ReadBytes(SEEK_SET, mHeaderCacheSize, static_cast<UInt32>(secondPart), (char*)buffer + firstPart, &secondPartActualCount);
+ theActualCount += secondPartActualCount;
+ }
+
+ if (actualCount) *actualCount = (UInt32)theActualCount;
+ mOffset = offset + theActualCount;
+
+ return err;
+}
+
+OSStatus Cached_DataSource::ReadBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ void *buffer,
+ UInt32* actualCount)
+{
+ if (actualCount) *actualCount = 0;
+ OSStatus err = noErr;
+ SInt64 size;
+ UInt32 theActualCount = 0;
+
+ if (!buffer) return kAudio_ParamError;
+
+ if ((positionMode & kPositionModeMask) != SEEK_END) size = 0; // not used in this case
+ else
+ {
+ err = GetSize(size);
+ if (err) return err;
+ }
+
+ SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
+ if (offset < 0) return kAudioFilePositionError;
+
+ if (offset < mHeaderCacheSize) {
+ return ReadFromHeaderCache(offset, requestCount, buffer, actualCount);
+ }
+
+#if NO_CACHE
+ err = mDataSource->ReadBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount);
+ mOffset = offset + theActualCount;
+#else
+
+ SInt64 cacheEnd = mBodyCacheOffset + mBodyCacheCurSize;
+ if (mBodyCache() && requestCount < mBodyCacheSize && offset >= mBodyCacheOffset && offset < cacheEnd)
+ {
+ if (offset + requestCount <= cacheEnd)
+ {
+ // request is entirely within cache
+#if VERBOSE
+ printf("request is entirely within cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
+#endif
+ memcpy(buffer, mBodyCache + (size_t)(offset - mBodyCacheOffset), requestCount);
+ theActualCount = requestCount;
+ }
+ else
+ {
+ // part of request is within cache. copy, read next cache block, copy.
+#if VERBOSE
+ printf("part of request is within cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
+#endif
+
+ // copy first part.
+ ByteCount firstPart = (ByteCount)(cacheEnd - offset);
+ ByteCount secondPart = requestCount - firstPart;
+#if VERBOSE
+ printf("memcpy offset %lld mBodyCacheOffset %lld offset - mBodyCacheOffset %lld firstPart %lu requestCount %lu\n",
+ offset, mBodyCacheOffset, offset - mBodyCacheOffset, firstPart, requestCount);
+#endif
+ memcpy(buffer, mBodyCache + (size_t)(offset - mBodyCacheOffset), firstPart);
+
+ theActualCount = static_cast<UInt32>(firstPart);
+
+ // read new block
+ SInt64 nextOffset = mBodyCacheOffset + mBodyCacheCurSize;
+ err = mDataSource->ReadBytes(SEEK_SET, nextOffset, mBodyCacheSize, mBodyCache(), &mBodyCacheCurSize);
+
+ if (err == kAudioFileEndOfFileError) err = noErr;
+ if (err) goto leave;
+
+ mBodyCacheOffset = nextOffset;
+
+ // copy second part
+ secondPart = std::min(secondPart, (ByteCount)mBodyCacheCurSize);
+ if (secondPart) memcpy((char*)buffer + firstPart, mBodyCache(), secondPart);
+ theActualCount = static_cast<UInt32>(firstPart + secondPart);
+ }
+ }
+ else
+ {
+ if (requestCount > mBodyCacheSize)
+ {
+#if VERBOSE
+ printf("large request %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
+#endif
+ // the request is larger than we normally cache, just do a read and don't cache.
+ err = mDataSource->ReadBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount);
+ mOffset = offset + theActualCount;
+ }
+ else
+ {
+ // request is outside cache. read new block.
+#if VERBOSE
+ printf("request is outside cache %lld %lu %lld %lu\n", offset, requestCount, mBodyCacheOffset, mBodyCacheCurSize);
+#endif
+ if (!mBodyCache())
+ {
+ mBodyCache.allocBytes(mBodyCacheSize, true);
+#if VERBOSE
+ printf("alloc mBodyCache %08X\n", mBodyCache());
+#endif
+ }
+ mBodyCacheOffset = offset;
+ err = mDataSource->ReadBytes(SEEK_SET, mBodyCacheOffset, mBodyCacheSize, mBodyCache(), &mBodyCacheCurSize);
+#if VERBOSE
+ printf("read %08X %d mBodyCacheOffset %lld %lu %lu\n", err, err, mBodyCacheOffset, mBodyCacheSize, mBodyCacheCurSize);
+#endif
+ if (err == kAudioFileEndOfFileError) err = noErr;
+ if (err) return err;
+
+ theActualCount = std::min(requestCount, mBodyCacheCurSize);
+ memcpy(buffer, mBodyCache(), theActualCount);
+ }
+
+ }
+
+leave:
+#endif
+ if (actualCount) *actualCount = (UInt32)theActualCount;
+#if VERBOSE
+ printf("<<read err %d actualCount %lu\n", err, *actualCount);
+#endif
+ return err;
+}
+
+OSStatus Cached_DataSource::WriteBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ const void *buffer,
+ UInt32* actualCount)
+{
+ OSStatus err = noErr;
+ SInt64 size;
+
+ if (!buffer) return kAudio_ParamError;
+
+ if ((positionMode & kPositionModeMask) != SEEK_END) size = 0; // not used in this case
+ else
+ {
+ err = GetSize(size);
+ if (err) return err;
+ }
+
+ SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
+ if (offset < 0) return kAudioFilePositionError;
+
+ if (mHeaderCache() && offset < mHeaderCacheSize)
+ {
+ // header cache write through
+ ByteCount firstPart = std::min((ByteCount)requestCount, (ByteCount)(mHeaderCacheSize - offset));
+#if VERBOSE
+ printf("header cache write through %lu %lu\n", mHeaderCacheSize, firstPart);
+#endif
+ memcpy(mHeaderCache + (size_t)offset, buffer, firstPart);
+ }
+
+#if VERBOSE
+ printf("write %lld %lu %lld %d %lld\n", offset, requestCount, mOffset, positionMode, positionOffset);
+#endif
+
+ SInt64 cacheEnd = mBodyCacheOffset + mBodyCacheCurSize;
+ if (mBodyCache() && offset >= mBodyCacheOffset && offset < cacheEnd)
+ {
+ // body cache write through
+ ByteCount firstPart = std::min((SInt64)requestCount, cacheEnd - offset);
+#if VERBOSE
+ printf("body cache write through %lld %lu %lld %lu\n", mBodyCacheOffset, mBodyCacheCurSize, offset, firstPart);
+#endif
+ memcpy(mBodyCache + (offset - mBodyCacheOffset), buffer, firstPart);
+ }
+
+ UInt32 theActualCount;
+ err = mDataSource->WriteBytes(positionMode, positionOffset, requestCount, buffer, &theActualCount);
+
+ mOffset = offset + theActualCount;
+ if (actualCount) *actualCount = (UInt32)theActualCount;
+
+ return err;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+Seekable_DataSource::Seekable_DataSource( void * inClientData,
+ AudioFile_ReadProc inReadFunc,
+ AudioFile_WriteProc inWriteFunc,
+ AudioFile_GetSizeProc inGetSizeFunc,
+ AudioFile_SetSizeProc inSetSizeFunc)
+ : DataSource(false), mClientData(inClientData), mReadFunc(inReadFunc), mWriteFunc(inWriteFunc),
+ mSizeFunc(inGetSizeFunc), mSetSizeFunc(inSetSizeFunc)
+{
+}
+
+Seekable_DataSource::~Seekable_DataSource()
+{
+}
+
+
+OSStatus Seekable_DataSource::GetSize(SInt64& outSize)
+{
+ if (!mSizeFunc) {
+ outSize = LLONG_MAX;
+ } else {
+ outSize = (*mSizeFunc)(mClientData);
+ }
+ return noErr;
+}
+
+OSStatus Seekable_DataSource::SetSize(SInt64 inSize)
+{
+ if (!mSetSizeFunc) return kAudioFileOperationNotSupportedError;
+ return (*mSetSizeFunc)(mClientData, inSize);
+}
+
+OSStatus Seekable_DataSource::ReadBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ void *buffer,
+ UInt32* actualCount)
+{
+ OSStatus err;
+
+ if (actualCount) *actualCount = 0;
+ if (!mReadFunc) return kAudioFileOperationNotSupportedError;
+ if (!buffer) return kAudio_ParamError;
+
+ positionMode &= kPositionModeMask;
+
+ SInt64 size;
+ err = GetSize(size);
+ if (err) return err;
+
+ SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
+
+ // request is outside bounds of file
+ if (offset < 0)
+ return kAudioFilePositionError;
+ if (offset >= size)
+ return kAudioFileEndOfFileError;
+
+ // reduce request if it exceeds the amount available
+ requestCount = static_cast<UInt32>(std::min((SInt64)requestCount, size - offset));
+
+ UInt32 theActualCount = 0;
+ err = (*mReadFunc)(mClientData, offset, requestCount, buffer, &theActualCount);
+ if (actualCount) *actualCount = theActualCount;
+ mOffset = offset + theActualCount;
+ return err;
+}
+
+
+OSStatus Seekable_DataSource::WriteBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ const void *buffer,
+ UInt32* actualCount)
+{
+ OSStatus err;
+
+ if (!mWriteFunc) return kAudioFileOperationNotSupportedError;
+ if (!buffer) return kAudio_ParamError;
+
+ SInt64 size;
+ positionMode &= kPositionModeMask;
+ if (positionMode != SEEK_END) size = 0; // not used in this case
+ else
+ {
+ err = GetSize(size);
+ if (err) return err;
+ }
+
+ SInt64 offset = CalcOffset(positionMode, positionOffset, mOffset, size);
+ if (offset < 0) return kAudioFilePositionError;
+
+ UInt32 theActualCount;
+ err = (*mWriteFunc)(mClientData, offset, requestCount, buffer, &theActualCount);
+ if (err) return err;
+ if (actualCount) *actualCount = theActualCount;
+ mOffset = offset + theActualCount;
+ return noErr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+OSStatus Buffer_DataSource::ReadBytes(
+ UInt16 positionMode,
+ SInt64 positionOffset,
+ UInt32 requestCount,
+ void *buffer,
+ UInt32* actualCount)
+{
+ if (actualCount) *actualCount = 0;
+ SInt64 offsetWithinBuffer = CalcOffset(positionMode, positionOffset, mOffset, mDataByteSize + mStartOffset) - mStartOffset;
+ if (offsetWithinBuffer < 0 || offsetWithinBuffer >= mDataByteSize) return kAudioFilePositionError;
+
+ SInt64 bytesAfterOffset = mDataByteSize - offsetWithinBuffer;
+ SInt64 theActualCount = std::min(bytesAfterOffset, (SInt64)requestCount);
+
+ if (theActualCount <= 0) {
+ if (actualCount) *actualCount = 0;
+ return kAudio_ParamError;
+ }
+
+ memcpy(buffer, mData + offsetWithinBuffer, theActualCount);
+
+ if (actualCount) *actualCount = static_cast<UInt32>(theActualCount);
+ mOffset = offsetWithinBuffer + theActualCount;
+
+ return noErr;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////