- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# BaseSplitterFile.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  */
    00021
    00022 #include "StdAfx.h"
    00023 #include "BaseSplitterFile.h"
    00024
    00025 //
    00026 // CBaseSplitterFile
    00027 //
    00028
    00029 CBaseSplitterFile::CBaseSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr, int cachelen)
    00030         : m_pAsyncReader(pAsyncReader)
    00031         , m_fStreaming(false)
    00032         , m_pos(0), m_len(0)
    00033         , m_bitbuff(0), m_bitlen(0)
    00034         , m_cachepos(0), m_cachelen(0)
    00035 {
    00036         if(!m_pAsyncReader) {hr = E_UNEXPECTED; return;}
    00037
    00038         LONGLONG total = 0, available;
    00039         hr = m_pAsyncReader->Length(&total, &available);
    00040
    00041         m_fStreaming = total == 0 && available > 0;
    00042         m_len = available;
    00043
    00044         if(FAILED(hr) || !m_fStreaming && total != available || total < 0)
    00045         {
    00046                 hr = E_FAIL;
    00047                 return;
    00048         }
    00049
    00050         if(!SetCacheSize(cachelen))
    00051         {
    00052                 hr = E_OUTOFMEMORY;
    00053                 return;
    00054         }
    00055
    00056         hr = S_OK;
    00057 }
    00058
    00059 bool CBaseSplitterFile::SetCacheSize(int cachelen)
    00060 {
    00061         m_pCache.Free();
    00062         m_cachetotal = 0;
    00063         m_pCache.Allocate((size_t)cachelen);
    00064         if(!m_pCache) return false;
    00065         m_cachetotal = cachelen;
    00066         m_cachelen = 0;
    00067         return true;
    00068 }
    00069
    00070 __int64 CBaseSplitterFile::GetPos()
    00071 {
    00072         return m_pos - (m_bitlen>>3);
    00073 }
    00074
    00075 __int64 CBaseSplitterFile::GetLength()
    00076 {
    00077         if(m_fStreaming)
    00078         {
    00079                 LONGLONG total, available = 0;
    00080                 if(SUCCEEDED(m_pAsyncReader->Length(&total, &available))) m_len = available;
    00081         }
    00082
    00083         return m_len;
    00084 }
    00085
    00086 void CBaseSplitterFile::Seek(__int64 pos)
    00087 {
    00088         __int64 len = GetLength();
    00089         m_pos = min(max(pos, 0), len);
    00090         BitFlush();
    00091 }
    00092
    00093 HRESULT CBaseSplitterFile::Read(BYTE* pData, __int64 len)
    00094 {
    00095         CheckPointer(m_pAsyncReader, E_NOINTERFACE);
    00096
    00097         HRESULT hr = S_OK;
    00098
    00099         if(m_cachetotal == 0 || !m_pCache)
    00100         {
    00101                 hr = m_pAsyncReader->SyncRead(m_pos, (long)len, pData);
    00102                 m_pos += len;
    00103                 return hr;
    00104         }
    00105
    00106         BYTE* pCache = m_pCache;
    00107
    00108         if(m_cachepos <= m_pos && m_pos < m_cachepos + m_cachelen)
    00109         {
    00110                 __int64 minlen = min(len, m_cachelen - (m_pos - m_cachepos));
    00111
    00112                 memcpy(pData, &pCache[m_pos - m_cachepos], (size_t)minlen);
    00113
    00114                 len -= minlen;
    00115                 m_pos += minlen;
    00116                 pData += minlen;
    00117         }
    00118
    00119         while(len > m_cachetotal)
    00120         {
    00121                 hr = m_pAsyncReader->SyncRead(m_pos, (long)m_cachetotal, pData);
    00122                 if(S_OK != hr) return hr;
    00123
    00124                 len -= m_cachetotal;
    00125                 m_pos += m_cachetotal;
    00126                 pData += m_cachetotal;
    00127         }
    00128
    00129         while(len > 0)
    00130         {
    00131                 __int64 tmplen = GetLength();
    00132                 __int64 maxlen = min(tmplen - m_pos, m_cachetotal);
    00133                 __int64 minlen = min(len, maxlen);
    00134                 if(minlen <= 0) return S_FALSE;
    00135
    00136                 hr = m_pAsyncReader->SyncRead(m_pos, (long)maxlen, pCache);
    00137                 if(S_OK != hr) return hr;
    00138
    00139                 m_cachepos = m_pos;
    00140                 m_cachelen = maxlen;
    00141
    00142                 memcpy(pData, pCache, (size_t)minlen);
    00143
    00144                 len -= minlen;
    00145                 m_pos += minlen;
    00146                 pData += minlen;
    00147         }
    00148
    00149         return hr;
    00150 }
    00151
    00152 UINT64 CBaseSplitterFile::BitRead(int nBits, bool fPeek)
    00153 {
    00154         ASSERT(nBits >= 0 && nBits <= 64);
    00155
    00156         while(m_bitlen < nBits)
    00157         {
    00158                 m_bitbuff <<= 8;
    00159                 if(S_OK != Read((BYTE*)&m_bitbuff, 1)) {return 0;} // EOF? // ASSERT(0);
    00160                 m_bitlen += 8;
    00161         }
    00162
    00163         int bitlen = m_bitlen - nBits;
    00164
    00165         UINT64 ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1);
    00166
    00167         if(!fPeek)
    00168         {
    00169                 m_bitbuff &= ((1ui64 << bitlen) - 1);
    00170                 m_bitlen = bitlen;
    00171         }
    00172
    00173         return ret;
    00174 }
    00175
    00176 void CBaseSplitterFile::BitByteAlign()
    00177 {
    00178         m_bitlen &= ~7;
    00179 }
    00180
    00181 void CBaseSplitterFile::BitFlush()
    00182 {
    00183         m_bitlen = 0;
    00184 }
    00185
    00186 HRESULT CBaseSplitterFile::ByteRead(BYTE* pData, __int64 len)
    00187 {
    00188     Seek(GetPos());
    00189         return Read(pData, len);
    00190 }
    00191
    00192 UINT64 CBaseSplitterFile::UExpGolombRead()
    00193 {
    00194         int n = -1;
    00195         for(BYTE b = 0; !b; n++) b = BitRead(1);
    00196         return (1ui64 << n) - 1 + BitRead(n);
    00197 }
    00198
    00199 INT64 CBaseSplitterFile::SExpGolombRead()
    00200 {
    00201         UINT64 k = UExpGolombRead();
    00202         return ((k&1) ? 1 : -1) * ((k + 1) >> 1);
    00203 }
    00204
    00205 HRESULT CBaseSplitterFile::HasMoreData(__int64 len, DWORD ms)
    00206 {
    00207         __int64 available = GetLength() - GetPos();
    00208
    00209         if(!m_fStreaming)
    00210         {
    00211                 return available < 1 ? E_FAIL : S_OK;
    00212         }
    00213
    00214         if(available < len)
    00215         {
    00216                 if(ms > 0) Sleep(ms);
    00217                 return S_FALSE;
    00218         }
    00219
    00220         return S_OK;
    00221 }
    00222