// ========================================================================== // Class Implementation : COXCompressedFile // ========================================================================== // Source file : oxcmpfl.cpp // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// #include "stdafx.h" // standard MFC include #include "oxcmpfl.h" // class specification #include // for SHRT_MAX #pragma warning (disable : 4702) #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNAMIC(COXCompressedFile, CFile) #define new DEBUG_NEW #define COMPRESS_BIT 0x8000 #define TRUE_LENGTH 0x4000 #define ACTUAL_LENGTH 0x3FFF #define min0(a,b) __max(0,__min( (a) , (b) ) ) ///////////////////////////////////////////////////////////////////////////// // Definition of static members const WORD COXCompressedFile::m_wBufferLength = 1024; // Data members ------------------------------------------------------------- // protected: // BOOL m_bEOF // --- if false, value of m_lFileLength is not valid // BOOL m_bOpenedForRead; // --- Whether the file has been opened for Read // BOOL m_bOpenedForWrite; // --- Whether the file has been opened for Write // int m_nFirstBufferLength // --- length of first buffer, is null when no reading has taken place // long m_lPosition // --- vitual filepointer // long m_lFileLength // --- virtual file length, calculated in GetFinalPos() // long m_lPrevLengthPos // --- disk position of the coded length of a buffer // UINT m_nExpandedLength // --- Length after reading from disk (decoded if needed) // UINT m_nInternalPos // --- current position in m_pInternalBuf // unsigned char *m_pInternalBuf // --- processing buffer between inputbuffer and information on disk // WORD m_wReadHeaderLength // --- real length of header on disk // WORD m_wLastBufferLength // --- length of last buffer read // static const WORD m_wBufferLength // --- length of m_pInternalBuf and helpbuffers // CWordArray m_BufLenArray // --- Array to hold all buferlengths already read // CFile* m_pDelegateToFile // --- The next transformation in the transformation chain // private: // Member functions --------------------------------------------------------- // public: COXCompressedFile::COXCompressedFile(UINT nHeaderLength) : m_bEOF(FALSE), m_bOpenedForRead(FALSE), m_bOpenedForWrite(FALSE), m_lPosition(0), m_lFileLength(0), m_nInternalPos(0), m_lPrevLengthPos(0), m_nExpandedLength(0), m_wLastBufferLength(0), m_nFirstBufferLength(0), m_wReadHeaderLength(0), m_nHeaderLength(nHeaderLength), m_pDelegateToFile(NULL) { m_pInternalBuf = new unsigned char[m_wBufferLength]; } COXCompressedFile::COXCompressedFile(LPCTSTR pszFilename, UINT nOpenFlags, UINT nHeaderLength) : m_bEOF(FALSE), m_bOpenedForRead(FALSE), m_bOpenedForWrite(FALSE), m_lPosition(0), m_lFileLength(0), m_nInternalPos(0), m_lPrevLengthPos(0), m_nExpandedLength(0), m_wLastBufferLength(0), m_nFirstBufferLength(0), m_wReadHeaderLength(0), m_nHeaderLength(nHeaderLength), m_pDelegateToFile(NULL) { m_pInternalBuf = new unsigned char[m_wBufferLength]; CFileException* pxFile = NULL; if (!Open(pszFilename,nOpenFlags,pxFile)) AfxThrowFileException(pxFile->m_cause); } CFile* COXCompressedFile::Duplicate() const { AfxThrowNotSupportedException(); return NULL; } BOOL COXCompressedFile::Open(LPCTSTR pszFileName, UINT nOpenFlags, CFileException* pException /* = NULL */) { ASSERT(m_nHeaderLength < m_wBufferLength); ASSERT(m_pDelegateToFile == NULL); // reading and writing together not allowed if (nOpenFlags & CFile::modeReadWrite) { if (pException != NULL) pException->m_cause = CFileException::accessDenied; return FALSE; } // ... Store open flag m_bEOF = FALSE; m_bOpenedForWrite = (nOpenFlags & CFile::modeWrite); m_bOpenedForRead = TRUE; // Read always permitted CFile::modeRead == 0x0000, m_nExpandedLength = 0; m_nInternalPos = 0; m_lPosition = 0; // ... Call base class implementation return CFile::Open(pszFileName, nOpenFlags, pException); } BOOL COXCompressedFile::DelegateOpen(CFile* pDelegateToFile, UINT nOpenFlags) { ASSERT_VALID(this); ASSERT(pDelegateToFile != NULL); // reading and writing together not allowed if (nOpenFlags & CFile::modeReadWrite) return FALSE; // ... Store open flag m_bOpenedForWrite = (nOpenFlags & CFile::modeWrite); m_bOpenedForRead = TRUE; // Read always permitted CFile::modeRead == 0x0000, m_bEOF = FALSE; m_lPosition = 0; m_lFileLength = 0; m_nInternalPos = 0; m_lPrevLengthPos = 0; m_nExpandedLength = 0; m_wLastBufferLength = 0; m_nFirstBufferLength = 0; m_wReadHeaderLength = 0; // setup the chain m_pDelegateToFile = pDelegateToFile; ASSERT_VALID(this); return TRUE; } BOOL COXCompressedFile::UnDelegateOpen() { m_pDelegateToFile = NULL; m_bOpenedForWrite = FALSE; m_bOpenedForRead = FALSE; m_bEOF = FALSE; m_lPosition = 0; m_lFileLength = 0; m_nInternalPos = 0; m_lPrevLengthPos = 0; m_nExpandedLength = 0; m_wLastBufferLength = 0; m_nFirstBufferLength = 0; m_wReadHeaderLength = 0; return TRUE; } UINT COXCompressedFile::Read(void FAR* lpBuf, UINT nCount) { if (m_bOpenedForWrite || !m_bOpenedForRead) AfxThrowFileException(CFileException::accessDenied); UINT nBytesRead = 0; int nAllocatebleBytes = 0; WORD wCodedReadLength = 0; char* lpBuffer = (char*)lpBuf; // processing header info nBytesRead = ReadHeader(lpBuffer, nCount); int pos(0); if (m_pDelegateToFile != NULL) pos = (int) m_pDelegateToFile->GetPosition(); else pos = (int) CFile::GetPosition(); // processing compressed info while(nBytesRead < nCount) { // nAllocatebleBytes is number of bytes processed, before a new buffer is read it's first // bytes are transferred till final position reached nAllocatebleBytes = min0((signed)nCount - (signed)nBytesRead, (signed)m_nExpandedLength - (signed)m_nInternalPos); memcpy(&lpBuffer[nBytesRead], &m_pInternalBuf[m_nInternalPos], nAllocatebleBytes); nBytesRead += nAllocatebleBytes; m_nInternalPos += nAllocatebleBytes; m_lPosition += nAllocatebleBytes; // when not finished reading if (nCount > nBytesRead) { // if read failes, EOF is reached if (m_pDelegateToFile != NULL) { if (m_pDelegateToFile->Read(&wCodedReadLength, sizeof(WORD)) != sizeof(WORD)) break; } else { if (CFile::Read(&wCodedReadLength, sizeof(WORD)) != sizeof(WORD)) break; } if (wCodedReadLength & TRUE_LENGTH) // this coded length was the length of the last buffer so // skip true length to read the actual compressed data { WORD wTrueLength; // if read failes, EOF is reached if (m_pDelegateToFile != NULL) { if (m_pDelegateToFile->Read(&wTrueLength, sizeof(WORD)) != sizeof(WORD)) break; } else { if (CFile::Read(&wTrueLength, sizeof(WORD)) != sizeof(WORD)) break; } } if (m_pDelegateToFile != NULL) m_lPrevLengthPos = (long) __max(m_lPrevLengthPos,m_pDelegateToFile->Seek(0, CFile::current) - (int)sizeof(WORD)); else m_lPrevLengthPos = (long) __max(m_lPrevLengthPos,CFile::Seek(0, CFile::current) - (int)sizeof(WORD)); m_wLastBufferLength = (WORD)InternalRead(wCodedReadLength); m_nInternalPos = 0; } } return nBytesRead; } void COXCompressedFile::Write(const void FAR* lpBuf, UINT nCount) { if (!m_bOpenedForWrite) AfxThrowFileException(CFileException::accessDenied); UINT nBytesWritten = 0; UINT nAllocatebleBytes = 0; LPCTSTR lpBuffer = (LPCTSTR)lpBuf; // processing header information nBytesWritten = WriteHeader(lpBuffer, nCount); // processing information while(nBytesWritten < nCount) { nAllocatebleBytes = min0(nCount - nBytesWritten, m_wBufferLength - m_nInternalPos); ASSERT(nAllocatebleBytes >= 0 && nAllocatebleBytes <= m_wBufferLength); // transfer lpBuf to internal buffer memcpy(&m_pInternalBuf[m_nInternalPos], &lpBuffer[nBytesWritten], nAllocatebleBytes); nBytesWritten += nAllocatebleBytes; m_nInternalPos += nAllocatebleBytes; ASSERT(m_nInternalPos <= m_wBufferLength); m_lPosition += nAllocatebleBytes; // write when position in internal buffer equals length (end) of internal buffer if (m_nInternalPos == m_wBufferLength) { InternalWrite(); m_nInternalPos = 0; } } } #if _MFC_VER >= 0x0700 ULONGLONG COXCompressedFile::GetPosition() const #else DWORD COXCompressedFile::GetPosition() const #endif { return m_lPosition; } void COXCompressedFile::Flush() { TRACE(_T("In COXCompressedFile::Flush : Trying to flush a compressed file. This is not allowed\n")); AfxThrowNotSupportedException(); } void COXCompressedFile::Close() { if (!m_bOpenedForRead) { TRACE(_T("In COXCompressedFile::Close : Trying to close a file that hasn't been opened yet.\n")); return; } AutoFlush(TRUE); if (m_pDelegateToFile == NULL) CFile::Close(); // ... Re-init the read/write flags m_bOpenedForRead = FALSE; m_bOpenedForWrite = FALSE; } void COXCompressedFile::Abort() { // ... Call base class implementation if (m_pDelegateToFile != NULL) m_pDelegateToFile->Abort(); else CFile::Abort(); // ... Re-init the read/write flags m_bOpenedForRead = FALSE; m_bOpenedForWrite = FALSE; } void COXCompressedFile::LockRange(DWORD dwPos, DWORD dwCount) { dwPos; dwCount; AfxThrowNotSupportedException(); } void COXCompressedFile::UnlockRange(DWORD dwPos, DWORD dwCount) { dwPos; dwCount; AfxThrowNotSupportedException(); } void COXCompressedFile::SetLength(DWORD dwNewLen) { dwNewLen; AfxThrowNotSupportedException(); } ULONGLONG COXCompressedFile::GetLength() { long lLastFilePointerPos; if (m_pDelegateToFile != NULL) lLastFilePointerPos = (long) m_pDelegateToFile->Seek(0,CFile::current); else lLastFilePointerPos = (long) CFile::Seek(0,CFile::current); GetFinalPos(); if (m_pDelegateToFile != NULL) m_pDelegateToFile->Seek(lLastFilePointerPos,CFile::begin); else CFile::Seek(lLastFilePointerPos,CFile::begin); return m_lFileLength; } LONG COXCompressedFile::Seek(LONG lOff, UINT nFrom) { if (m_bOpenedForWrite) AfxThrowFileException(CFileException::invalidFile); long lBytesSought = 0; if(m_bOpenedForWrite) return 0; if (nFrom == CFile::begin) { m_lPosition = 0; m_nInternalPos = 0; m_nExpandedLength = 0; m_nFirstBufferLength = 0; // Force a reload of the header if the sought element falls in it. m_wReadHeaderLength = 0; } //trying to position before BOF if(m_lPosition + lOff < 0 && nFrom != CFile::end) AfxThrowFileException(CFileException::badSeek); // trying to position after EOF if (lOff > 0 && nFrom == CFile::end) AfxThrowFileException(CFileException::endOfFile); switch(nFrom) { case CFile::begin: if (m_pDelegateToFile != NULL) m_pDelegateToFile->Seek(0,CFile::begin); else CFile::Seek(0,CFile::begin); break; case CFile::current: if ((LONG)m_nInternalPos + lOff <= 0) { Seek(m_lPosition + lOff, CFile::begin); return m_lPosition; } break; case CFile::end: if (!m_bEOF) GetFinalPos(); if (m_lFileLength + lOff >= 0) { Seek(m_lFileLength + lOff, CFile::begin); return m_lPosition; } else //trying to position before BOF AfxThrowFileException(CFileException::badSeek); default: break; } // seek happens in header itself, no seeking in internal buffer if (m_lPosition + lOff <= (long)m_nHeaderLength) { if (m_wReadHeaderLength == 0) { if (m_pDelegateToFile != NULL) { m_pDelegateToFile->Seek(0,CFile::begin); m_wReadHeaderLength = (WORD)m_pDelegateToFile->Read(m_pInternalBuf,m_nHeaderLength); } else { CFile::Seek(0,CFile::begin); m_wReadHeaderLength = (WORD)CFile::Read(m_pInternalBuf,m_nHeaderLength); } } // seek possible, in header only if (m_lPosition + lOff <= (LONG)m_wReadHeaderLength) { m_lPosition += lOff; m_nInternalPos += lOff; return m_lPosition; } else // seeking after EOF { if (m_pDelegateToFile != NULL) { m_lPosition = (long) m_pDelegateToFile->GetPosition(); m_nInternalPos = (UINT) m_pDelegateToFile->GetPosition(); } else { m_lPosition = (long) CFile::GetPosition(); m_nInternalPos = (UINT) CFile::GetPosition(); } AfxThrowFileException(CFileException::endOfFile); } } else { // if positioned in header and seeking outside header move m_lPosition after header if (m_lPosition < (long)m_nHeaderLength) { // if m_wReadHeaderLength is not known yet, get the real length of the header if (m_wReadHeaderLength == 0) { if (m_pDelegateToFile != NULL) { m_pDelegateToFile->Seek(0,CFile::begin); m_wReadHeaderLength = (WORD)m_pDelegateToFile->Read(m_pInternalBuf,m_nHeaderLength); } else { CFile::Seek(0,CFile::begin); m_wReadHeaderLength = (WORD)CFile::Read(m_pInternalBuf,m_nHeaderLength); } } // if header is smaller than fixed m_nHeaderLength if (m_wReadHeaderLength < m_nHeaderLength) { if (m_pDelegateToFile != NULL) m_lPrevLengthPos = (long) m_pDelegateToFile->Seek(m_wReadHeaderLength, CFile::begin); else m_lPrevLengthPos = (long) CFile::Seek(m_wReadHeaderLength, CFile::begin); m_lPosition = m_wReadHeaderLength; m_nInternalPos = m_wReadHeaderLength; m_nFirstBufferLength = m_wReadHeaderLength; return m_lPosition; } // position on end of header else { if (m_pDelegateToFile != NULL) m_lPrevLengthPos = (long) m_pDelegateToFile->Seek(m_nHeaderLength, CFile::begin); else m_lPrevLengthPos = (long) CFile::Seek(m_nHeaderLength, CFile::begin); lBytesSought = m_nHeaderLength; m_lPosition = m_nHeaderLength; m_nFirstBufferLength = m_nHeaderLength; // The part of the offset already skipped is the diference between the total // headerlength and the internal pos (the last position of the virtual filepointer) lOff -= m_nHeaderLength - m_nInternalPos; m_nInternalPos = 0; } } } if (m_nInternalPos != 0) // Seek started somewhere within a buffer { if (lOff >= 0) { if ((long)(m_wBufferLength - m_nInternalPos) > lOff) // offset stays within current buffer { m_lPosition += lOff; m_nInternalPos += lOff; lOff = 0; return m_lPosition; } else { m_lPosition += m_wBufferLength - m_nInternalPos; lOff -= m_wBufferLength - m_nInternalPos; m_nInternalPos = 0; } } else { if ((long)m_nInternalPos > labs(lOff)) { m_lPosition += lOff; m_nInternalPos += lOff; lOff = 0; return m_lPosition; } } } MoveFromBufferBoundaries(m_lPosition / m_wBufferLength, lOff); return m_lPosition; } // Diagnostics ------------------------------------------------------------------ #ifdef _DEBUG void COXCompressedFile::Dump(CDumpContext& dc) const { if (m_pDelegateToFile != NULL) m_pDelegateToFile->Dump(dc); else CFile::Dump(dc); dc << "\nm_bOpenedForRead : " << (WORD)m_bOpenedForRead; dc << "\nm_bOpenedForWrite : " << (WORD)m_bOpenedForWrite; } void COXCompressedFile::AssertValid() const { if (m_pDelegateToFile != NULL) m_pDelegateToFile->AssertValid(); else CFile::AssertValid(); } #endif COXCompressedFile::~COXCompressedFile() { if (m_pDelegateToFile != NULL) Close(); delete [] m_pInternalBuf; } // protected: UINT COXCompressedFile::ReadHeader(char* lpBuffer, UINT nCount) // In : nCount , the number af characters to be read in // Out : lpBuffer, a character buffer containing the header // Returns : number of characters read // Effect : reading a number of header bytes { UINT nBytesRead = 0; // when positioned in header if (m_lPosition < (long)m_nHeaderLength) { if (m_pDelegateToFile != NULL) { m_pDelegateToFile->Seek(0, CFile::begin); m_wLastBufferLength = m_wReadHeaderLength = (WORD)m_pDelegateToFile->Read(m_pInternalBuf,m_nHeaderLength); } else { CFile::Seek(0, CFile::begin); m_wLastBufferLength = m_wReadHeaderLength = (WORD)CFile::Read(m_pInternalBuf,m_nHeaderLength); } // reading rest of header if (m_lPosition + nCount >= m_wReadHeaderLength) { memcpy(&lpBuffer[nBytesRead], &m_pInternalBuf[m_nInternalPos], m_wReadHeaderLength - m_lPosition); nBytesRead = m_wReadHeaderLength - m_lPosition; m_lPosition += m_wReadHeaderLength - m_lPosition; m_nInternalPos = 0; } // read header in one time else { memcpy(&lpBuffer[nBytesRead], &m_pInternalBuf[m_nInternalPos], nCount); nBytesRead = nCount; m_lPosition += nCount; m_nInternalPos += nCount; } } return nBytesRead; } int COXCompressedFile::InternalRead(WORD wCodedReadLength) // In : wCodedReadLength, the coded length of the buffer on disk // Out : // Returns : the decoded length of the buffer on disk // Effect : reads the information from disk (can be compressed) and puts it into m_pInternalBuf { unsigned char pReadBuffer[m_wBufferLength]; WORD wReadLength; wReadLength = (WORD)(wCodedReadLength & ACTUAL_LENGTH); if (wReadLength > m_wBufferLength) { TRACE0("In COXCompressedFile::InternalRead : Length to read is bigger than buffer length\n"); AfxThrowFileException(CFileException::endOfFile); } // if the highest bit of wCodedReadLength is one bit the file is compressed if (wCodedReadLength & COMPRESS_BIT) { if (m_pDelegateToFile != NULL) m_pDelegateToFile->Read(pReadBuffer,wReadLength); else CFile::Read(pReadBuffer,wReadLength); m_nExpandedLength = m_Convert.Expand(pReadBuffer,wReadLength,m_pInternalBuf,m_wBufferLength); } else { if (m_pDelegateToFile != NULL) m_nExpandedLength = m_pDelegateToFile->Read(m_pInternalBuf,wReadLength); else m_nExpandedLength = CFile::Read(m_pInternalBuf,wReadLength); } ASSERT(m_nExpandedLength <= m_wBufferLength); m_wLastBufferLength = (WORD)m_nExpandedLength; return m_nExpandedLength; } UINT COXCompressedFile::WriteHeader(LPCTSTR lpBuffer, UINT &nCount) // In : lpBuffer, the header bytes to be written // nCount, the number of bytes to be written // Out : // Returns : number of bytes written // Effect : puts header bytes from character buffer on disk { UINT nBytesWritten = 0; // when positioned in header if (m_lPosition < (long)m_nHeaderLength) { memcpy(&m_pInternalBuf[m_nInternalPos], &lpBuffer[nBytesWritten], __min(nCount, m_nHeaderLength - m_nInternalPos)); // when writing after header filling up rest of header if (m_lPosition + nCount >= m_nHeaderLength) { if (m_pDelegateToFile != NULL) m_pDelegateToFile->Write(m_pInternalBuf,m_nHeaderLength); else CFile::Write(m_pInternalBuf,m_nHeaderLength); nBytesWritten = m_nHeaderLength - m_lPosition; m_lPosition += m_nHeaderLength - m_lPosition; m_nInternalPos = 0; } else { nBytesWritten = nCount; m_lPosition += nCount; m_nInternalPos += nCount; } } return nBytesWritten; } void COXCompressedFile::InternalWrite(BOOL bLast /* = FALSE */) // In : // Out // Returns // Effect puts information from m_pInternalBuf on disk, compresses if compressed length > non // compressed length { int nCompressedLength; WORD wWriteLength; // ... Buffer may become larger when we try to compress it // In this case we will use the original data, but we still need to // allocate enough memory for the larger compressed buffer (therefore + 1) unsigned char pCompressedBuffer[m_wBufferLength + 1]; nCompressedLength = m_Convert.Compress(m_pInternalBuf,m_nInternalPos,pCompressedBuffer,m_wBufferLength); // when compressed length exceeds original length, a non compressed buffer is written if (nCompressedLength == -1 || (UINT)nCompressedLength >= m_nInternalPos) { if (m_pDelegateToFile != NULL) { m_pDelegateToFile->Write(&m_nInternalPos,sizeof(WORD)); m_pDelegateToFile->Write(m_pInternalBuf,m_nInternalPos); } else { CFile::Write(&m_nInternalPos,sizeof(WORD)); CFile::Write(m_pInternalBuf,m_nInternalPos); } } else { wWriteLength = (WORD)(COMPRESS_BIT | nCompressedLength); // When writing the last buffer, set an extra identification bit if (bLast) wWriteLength |= TRUE_LENGTH; if (m_pDelegateToFile != NULL) { m_pDelegateToFile->Write(&wWriteLength,sizeof(WORD)); // When writing the last buffer an extra identification bit has been set to notify // a extra length ( = the true length = expanded length ) of this buffer is written if (bLast) m_pDelegateToFile->Write(&m_nInternalPos,sizeof(WORD)); m_pDelegateToFile->Write(pCompressedBuffer,nCompressedLength); } else { CFile::Write(&wWriteLength,sizeof(WORD)); // When writing the last buffer an extra identification bit has been set to notify // a extra length ( = the true length = expanded length ) of this buffer is written if (bLast) CFile::Write(&m_nInternalPos,sizeof(WORD)); CFile::Write(pCompressedBuffer,nCompressedLength); } } } void COXCompressedFile::GetFinalPos() { if (m_bEOF) return; char cTempHeaderBuffer[m_wBufferLength]; // calculate begin position if (m_pDelegateToFile != NULL) m_pDelegateToFile->Seek(0,CFile::begin); else CFile::Seek(0,CFile::begin); m_lPosition = 0; m_nInternalPos = 0; m_nExpandedLength = 0; m_nFirstBufferLength = 0; m_wReadHeaderLength = 0; if (m_pDelegateToFile != NULL) m_wReadHeaderLength = (WORD)m_pDelegateToFile->Read(cTempHeaderBuffer, m_nHeaderLength); else m_wReadHeaderLength = (WORD)CFile::Read(cTempHeaderBuffer, m_nHeaderLength); m_lPosition = m_wReadHeaderLength; if (m_wReadHeaderLength == m_nHeaderLength) { // Move until EOF is reached, the starting index is 0 because we're just behind the header // ready to read the first block MoveFromBufferBoundaries(0, -1); } m_lFileLength = m_lPosition; m_bEOF = TRUE; } void COXCompressedFile::AutoFlush(BOOL bLast /* = FALSE */) { if (m_bOpenedForRead && !m_bOpenedForWrite) { TRACE(_T("In COXCompressedFile::Flush : Autoflushing a file that has been opened for read.\n")); return; } if (m_bOpenedForWrite) { if (m_lPosition > (long)m_nHeaderLength) { if (m_nInternalPos > 0) InternalWrite(bLast); } else { if (m_pDelegateToFile != NULL) m_pDelegateToFile->Write(m_pInternalBuf,m_lPosition); else CFile::Write(m_pInternalBuf,m_lPosition); } } } DWORD COXCompressedFile::MoveFromBufferBoundaries(DWORD dwStartBufferIndex, long lOffset) // In : dwStartBufferIndex, zero based index of block to begin move from // lOffset : How far to move starting from dwStartBufferIndex // if lOffset is equal to -1 we loop the file until EOF // Out : // Returns : the moved length // Effect : moves the virtual filepointer with an offset of lOffset starting from a buffer // boundary. { // Must be on a buffer boundary and behind the header ASSERT(m_nInternalPos == 0); ASSERT(m_lPosition >= m_wReadHeaderLength); WORD wCompressedLength = 0; long lSkipLength = 0; WORD wCompLengthCorrection = 0; WORD wTrueLengthCorrection = 0; DWORD dwDistance = 0; BOOL bEOF = FALSE; UINT nNumBuffers; UINT nOffsetInBuffer; // Initialize the while loop if (lOffset == -1) { nNumBuffers = 1; nOffsetInBuffer = 0; } else { nNumBuffers = lOffset / m_wBufferLength; nOffsetInBuffer = lOffset % m_wBufferLength; } while(nNumBuffers != 0 && !bEOF) { wCompLengthCorrection = sizeof(WORD); ASSERT((DWORD)m_BufLenArray.GetSize() >= dwStartBufferIndex); // dwStartBufferIndex is zero based m_wLastBufferLength = m_wBufferLength; if ((DWORD)m_BufLenArray.GetSize() == dwStartBufferIndex) // The length of this buffer is not yet available in the list { // Execute the previous seeklength, because this is not a length we found in the array // and we need to position the true filepointer exactly before the length to be read if (m_pDelegateToFile != NULL) m_lPrevLengthPos = (long) m_pDelegateToFile->Seek(lSkipLength, CFile::current); else m_lPrevLengthPos = (long) CFile::Seek(lSkipLength, CFile::current); // Read the length UINT nRead(0); if (m_pDelegateToFile != NULL) nRead = m_pDelegateToFile->Read(&wCompressedLength, sizeof(WORD)); else nRead = CFile::Read(&wCompressedLength, sizeof(WORD)); if (nRead != sizeof(WORD)) // Could not read a whole word, probably end of file { bEOF = TRUE; } else { // Store the length in the array m_BufLenArray.SetAtGrow(dwStartBufferIndex, wCompressedLength); m_wLastBufferLength = m_wBufferLength; // Is it the last buffer length we're reading here if (wCompressedLength & TRUE_LENGTH) { if (m_pDelegateToFile != NULL) m_pDelegateToFile->Read(&m_wLastBufferLength, sizeof(WORD)); else CFile::Read(&m_wLastBufferLength, sizeof(WORD)); } // By reading the length the true filepointer already placed itself behind the length wCompLengthCorrection = 0; wTrueLengthCorrection = 0; lSkipLength = 0; } } if (!bEOF) { // Move the true filepointer just at the begining of the next buffer length wCompressedLength = m_BufLenArray.GetAt(dwStartBufferIndex); if ((wCompressedLength & TRUE_LENGTH) && wCompLengthCorrection != 0) // the TRUE_LENGTH bit is detected and we haven't added a new length to the // array so the true filepointer hasn't moved yet after the lengths. // Add those lengths therefore to the skiplength. { wTrueLengthCorrection = sizeof(WORD); } lSkipLength += (wCompressedLength & ACTUAL_LENGTH) + wCompLengthCorrection + wTrueLengthCorrection; // Adjust the internals to this new position m_nInternalPos = 0; dwDistance += m_wLastBufferLength; m_lPosition += m_wLastBufferLength; // Adjust the counters dwStartBufferIndex++; if (lOffset != -1) // the loop is not meant to be until EOF nNumBuffers--; } } if (!bEOF) { if (lSkipLength != 0) { // There is still some length to be skipped if (m_pDelegateToFile != NULL) m_lPrevLengthPos = (long) m_pDelegateToFile->Seek(lSkipLength, CFile::current); else m_lPrevLengthPos = (long) CFile::Seek(lSkipLength, CFile::current); } ASSERT((DWORD)m_BufLenArray.GetSize() >= dwStartBufferIndex); // dwStartBufferIndex is zero based wCompLengthCorrection = sizeof(WORD); if ((DWORD)m_BufLenArray.GetSize() == dwStartBufferIndex) // The length of this buffer is not yet available in the list { // Read the length UINT nRead(0); if (m_pDelegateToFile != NULL) nRead = m_pDelegateToFile->Read(&wCompressedLength, sizeof(WORD)); else nRead = CFile::Read(&wCompressedLength, sizeof(WORD)); if (nRead != sizeof(WORD)) // Could not read a whole word, probably end of file { bEOF = TRUE; } else { // Store the length in the array m_BufLenArray.SetAtGrow(dwStartBufferIndex, wCompressedLength); m_wLastBufferLength = m_wBufferLength; // Is it the last buffer length we're reading here if (wCompressedLength & TRUE_LENGTH) { if (m_pDelegateToFile != NULL) m_pDelegateToFile->Read(&m_wLastBufferLength, sizeof(WORD)); else CFile::Read(&m_wLastBufferLength, sizeof(WORD)); } // By reading the length the true filepointer already placed itself behind the length wCompLengthCorrection = 0; } } if (!bEOF) { // Get the length and move after it wCompressedLength = m_BufLenArray.GetAt(dwStartBufferIndex); // Is it the last buffer length we're reading here if ((wCompressedLength & TRUE_LENGTH) && wCompLengthCorrection != 0) // the TRUE_LENGTH bit is detected and we haven't added a new length to the // array so the true filepointer hasn't moved yet after the lengths. // Add those lengths therefore to the skiplength. { wCompLengthCorrection += sizeof(WORD); } if (m_pDelegateToFile != NULL) m_pDelegateToFile->Seek(wCompLengthCorrection, CFile::current); else CFile::Seek(wCompLengthCorrection, CFile::current); // Read the buffer where the element to be sougth resides m_wLastBufferLength = (WORD)InternalRead(wCompressedLength); // Adjust the internals to this new position int nTrueOffset = (nOffsetInBuffer < m_wLastBufferLength ? nOffsetInBuffer : m_wLastBufferLength); m_nInternalPos = nTrueOffset; dwDistance += nTrueOffset; m_lPosition += nTrueOffset; } } return dwDistance; } // private: // Message handlers --------------------------------------------------------- // ==========================================================================