326 lines
6 KiB
C++
326 lines
6 KiB
C++
/* DecMPA - simple MPEG Audio decoding library.
|
|
Copyright (C) 2002 Hauke Duden
|
|
|
|
This library 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; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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 library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
For more information look at the file License.txt in this package.
|
|
|
|
email: hazard_hd@users.sourceforge.net
|
|
*/
|
|
|
|
#include "DefInc.h"
|
|
#include "DecMPAFileAccess.h"
|
|
|
|
#include <memory.h>
|
|
|
|
CDecMPAFileAccess::CDecMPAFileAccess(const DecMPA_Callbacks& Callbacks,void* pContext)
|
|
{
|
|
m_Callbacks=Callbacks;
|
|
m_pCallbackContext=pContext;
|
|
|
|
m_nPosition=Callbacks.GetPosition(pContext);
|
|
if(m_nPosition<0)
|
|
m_nPosition=0;
|
|
|
|
m_bEOF=false;
|
|
|
|
m_pUndoBuffer=NULL;
|
|
m_nUndoBufferSize=0;
|
|
|
|
m_nUndoBufferFilled=0;
|
|
m_nUndoBufferPos=0;
|
|
|
|
m_nUndoRecordingCount=0;
|
|
|
|
m_LastError=DECMPA_OK;
|
|
|
|
m_pSkipBuffer=NULL;
|
|
m_nSkipBufferSize=0;
|
|
}
|
|
|
|
CDecMPAFileAccess::~CDecMPAFileAccess()
|
|
{
|
|
if(m_pUndoBuffer!=NULL)
|
|
delete[] m_pUndoBuffer;
|
|
|
|
if(m_pSkipBuffer!=NULL)
|
|
delete[] m_pSkipBuffer;
|
|
}
|
|
|
|
int CDecMPAFileAccess::Read(void* pDest,int nBytes)
|
|
{
|
|
long nResult=0;
|
|
long nRedoBytes=0;
|
|
|
|
nRedoBytes=m_nUndoBufferFilled-m_nUndoBufferPos;
|
|
if(nRedoBytes>0)
|
|
{
|
|
if(nRedoBytes>nBytes)
|
|
nRedoBytes=nBytes;
|
|
memcpy(pDest,m_pUndoBuffer+m_nUndoBufferPos,nRedoBytes);
|
|
m_nUndoBufferPos+=nRedoBytes;
|
|
nBytes-=nRedoBytes;
|
|
pDest=((char*)pDest)+nRedoBytes;
|
|
|
|
m_nPosition+=nRedoBytes;
|
|
|
|
if(m_nUndoBufferPos==m_nUndoBufferFilled && m_nUndoRecordingCount==0)
|
|
{
|
|
m_nUndoBufferFilled=0;
|
|
m_nUndoBufferPos=0;
|
|
}
|
|
|
|
nResult+=nRedoBytes;
|
|
}
|
|
|
|
if(nBytes>0)
|
|
{
|
|
long nRead;
|
|
|
|
nRead=m_Callbacks.Read(m_pCallbackContext,pDest,nBytes);
|
|
if(nRead>=0)
|
|
{
|
|
if(nRead!=nBytes)
|
|
m_bEOF=true;
|
|
m_nPosition+=nRead;
|
|
|
|
if(m_nUndoRecordingCount>0)
|
|
{
|
|
EnsureUndoBufferFree(nRead);
|
|
memcpy(m_pUndoBuffer+m_nUndoBufferPos,pDest,nRead);
|
|
m_nUndoBufferFilled+=nRead;
|
|
m_nUndoBufferPos+=nRead;
|
|
}
|
|
|
|
nResult+=nRead;
|
|
}
|
|
else
|
|
{
|
|
m_LastError=DECMPA_ERROR_READ;
|
|
nResult=-1;
|
|
}
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
long CDecMPAFileAccess::Skip(long nBytes)
|
|
{
|
|
long nResult=0;
|
|
long nRedoBytes=0;
|
|
bool bSeekFailed=false;
|
|
|
|
nRedoBytes=m_nUndoBufferFilled-m_nUndoBufferPos;
|
|
if(nRedoBytes>0)
|
|
{
|
|
if(nRedoBytes>nBytes)
|
|
nRedoBytes=nBytes;
|
|
m_nUndoBufferPos+=nRedoBytes;
|
|
nBytes-=nRedoBytes;
|
|
|
|
m_nPosition+=nRedoBytes;
|
|
|
|
if(m_nUndoBufferPos==m_nUndoBufferFilled && m_nUndoRecordingCount==0)
|
|
{
|
|
m_nUndoBufferFilled=0;
|
|
m_nUndoBufferPos=0;
|
|
}
|
|
|
|
nResult+=nRedoBytes;
|
|
}
|
|
|
|
if(nBytes>0)
|
|
{
|
|
//first try to skip using seek
|
|
|
|
if(nBytes>1024 && m_Callbacks.Seek!=NULL && m_nUndoRecordingCount==0)
|
|
{
|
|
long nLength=GetLength();
|
|
|
|
if(nLength!=-1)
|
|
{
|
|
long nToSkip=nBytes;
|
|
|
|
if(m_nPosition+nToSkip>nLength)
|
|
nToSkip=nLength-m_nPosition;
|
|
|
|
if(m_Callbacks.Seek(m_pCallbackContext,m_nPosition+nToSkip)!=0)
|
|
{
|
|
m_nPosition+=nToSkip;
|
|
nResult+=nToSkip;
|
|
nBytes-=nToSkip;
|
|
}
|
|
else
|
|
{
|
|
//seek failed - not critical, we can still try to skip
|
|
//using read.
|
|
bSeekFailed=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(nBytes>0)
|
|
{
|
|
int nToRead;
|
|
int nRead;
|
|
|
|
if(m_pSkipBuffer==NULL)
|
|
{
|
|
m_nSkipBufferSize=8192;
|
|
m_pSkipBuffer=new unsigned char[m_nSkipBufferSize];
|
|
}
|
|
|
|
while(nBytes>0 && !m_bEOF)
|
|
{
|
|
nToRead=(nBytes<=m_nSkipBufferSize) ? nBytes : m_nSkipBufferSize;
|
|
|
|
nRead=m_Callbacks.Read(m_pCallbackContext,m_pSkipBuffer,nToRead);
|
|
if(nRead>=0)
|
|
{
|
|
if(nRead!=nToRead)
|
|
m_bEOF=true;
|
|
m_nPosition+=nRead;
|
|
|
|
if(m_nUndoRecordingCount>0)
|
|
{
|
|
EnsureUndoBufferFree(nRead);
|
|
memcpy(m_pUndoBuffer+m_nUndoBufferPos,m_pSkipBuffer,nRead);
|
|
m_nUndoBufferFilled+=nRead;
|
|
m_nUndoBufferPos+=nRead;
|
|
}
|
|
|
|
nResult+=nRead;
|
|
nBytes-=nRead;
|
|
}
|
|
else
|
|
{
|
|
if(bSeekFailed)
|
|
{
|
|
//if seek also failed before we report a seek error
|
|
m_LastError=DECMPA_ERROR_SEEK;
|
|
}
|
|
else
|
|
m_LastError=DECMPA_ERROR_READ;
|
|
|
|
nResult=-1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
bool CDecMPAFileAccess::IsEndOfFile()
|
|
{
|
|
return m_bEOF;
|
|
}
|
|
|
|
bool CDecMPAFileAccess::Seek(long pos)
|
|
{
|
|
bool bResult=false;
|
|
|
|
if(pos==m_nPosition)
|
|
bResult=true;
|
|
else
|
|
{
|
|
if(m_nUndoRecordingCount==0)
|
|
{
|
|
if(m_Callbacks.Seek!=NULL)
|
|
{
|
|
if(m_Callbacks.Seek(m_pCallbackContext,pos)!=0)
|
|
{
|
|
m_nPosition=pos;
|
|
bResult=true;
|
|
}
|
|
else
|
|
m_LastError=DECMPA_ERROR_SEEK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
long CDecMPAFileAccess::GetPosition()
|
|
{
|
|
return m_nPosition;
|
|
}
|
|
|
|
long CDecMPAFileAccess::GetLength()
|
|
{
|
|
long nLength=-1;
|
|
|
|
if(m_Callbacks.GetLength!=NULL)
|
|
nLength=m_Callbacks.GetLength(m_pCallbackContext);
|
|
|
|
return nLength;
|
|
}
|
|
|
|
long CDecMPAFileAccess::StartUndoRecording()
|
|
{
|
|
m_nUndoRecordingCount++;
|
|
|
|
return m_nUndoBufferPos;
|
|
}
|
|
|
|
void CDecMPAFileAccess::EndUndoRecording(long ID,bool bUndo)
|
|
{
|
|
if(m_nUndoRecordingCount>0)
|
|
{
|
|
if(bUndo)
|
|
{
|
|
m_nPosition-=m_nUndoBufferPos-ID;
|
|
if(m_nUndoBufferPos!=ID)
|
|
m_bEOF=false;
|
|
|
|
m_nUndoBufferPos=ID;
|
|
}
|
|
|
|
m_nUndoRecordingCount--;
|
|
}
|
|
}
|
|
|
|
void CDecMPAFileAccess::EnsureUndoBufferFree(long nBytes)
|
|
{
|
|
if(m_nUndoBufferPos+nBytes>m_nUndoBufferSize)
|
|
{
|
|
unsigned char* pNew;
|
|
long nAdd=m_nUndoBufferPos+nBytes-m_nUndoBufferSize;
|
|
|
|
if((nAdd & 8191)!=0)
|
|
nAdd+=8192-(nAdd & 8191);
|
|
|
|
pNew=new unsigned char[m_nUndoBufferSize+nAdd];
|
|
memcpy(pNew,m_pUndoBuffer,m_nUndoBufferFilled);
|
|
m_nUndoBufferSize+=nAdd;
|
|
|
|
if(m_pUndoBuffer!=NULL)
|
|
delete[] m_pUndoBuffer;
|
|
m_pUndoBuffer=pNew;
|
|
}
|
|
}
|
|
|
|
int CDecMPAFileAccess::GetLastError()
|
|
{
|
|
return m_LastError;
|
|
}
|
|
|
|
bool CDecMPAFileAccess::CanSeek()
|
|
{
|
|
return (m_Callbacks.Seek!=NULL);
|
|
}
|
|
|