Index: modules/App Framework/FileEx.cpp =================================================================== diff -u -N --- modules/App Framework/FileEx.cpp (revision 5d5f6e5b4a377c3b01a0ef17ad079770319f30ff) +++ modules/App Framework/FileEx.cpp (revision 0) @@ -1,917 +0,0 @@ -/************************************************************************ - Copy Handler 1.x - program for copying data in Microsoft Windows - systems. - Copyright (C) 2001-2003 Ixen Gerthannes (ixen@interia.pl) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*************************************************************************/ - -#include "stdafx.h" -#include "FileEx.h" -#include "crc32.h" -#ifndef DISABLE_CRYPT -#include "crypt.h" -#endif - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -#pragma warning( disable : 4127 ) - -// serialization buffer add on every reallocation -#define SERIALBUFFER_DELTA 4096UL - -/////////////////////////////////////////////////////////////// -// Opens file -// pszFilename [in] - name of the file to open -// dwAccess [in] - type of access to this file (R, W, RW, APPEND) -// dwBufferSize [in] - size of internal buffer when using buffered -// operations. -/////////////////////////////////////////////////////////////// -void CFileEx::Open(PCTSTR pszFilename, DWORD dwAccess, DWORD dwBufferSize) -{ - // check if this object is ready to open a file - if (m_hFile) - Close(); - - HANDLE hFile=NULL; - switch (dwAccess & FA_OPERATION) - { - case FA_READ: - hFile=CreateFile(pszFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - break; - case FA_WRITE: - hFile=CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - break; - case FA_RW: - case FA_APPEND: - hFile=CreateFile(pszFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - break; - default: - _ASSERT(false); // unknown File access value - } - - // check if operation succeeded - if (hFile == INVALID_HANDLE_VALUE) - THROW_FILEEXCEPTIONEX(_T("Cannot open the specified file (CreateFile failed)."), pszFilename, FERR_OPEN, GetLastError()); - else - { - // store hFile - m_hFile=hFile; - - // remember path of this file - m_pszFilename=new TCHAR[_tcslen(pszFilename)+1]; - _tcscpy(m_pszFilename, pszFilename); - - // remember the mode - m_dwMode=dwAccess; - - // is this buffered ? - SetBuffering((dwAccess & 0x8000) != 0, dwBufferSize); - } - - // if this is the "FA_APPEND" access mode - seek to end - if ((dwAccess & FA_OPERATION) == FA_APPEND) - InternalSeek(0, FILE_END); -} - -/////////////////////////////////////////////////////////////// -// Closes the file (could be used on non-opened files -/////////////////////////////////////////////////////////////// -void CFileEx::Close() -{ - // only if the file has been opened - if (m_hFile) - { - // flush all data - Flush(); - - // close da file - if (!CloseHandle(m_hFile)) - { - // error closing - THROW_FILEEXCEPTIONEX(_T("Cannot close the handle associated with a file (CloseHandle failed)."), m_pszFilename, FERR_CLOSE, GetLastError()); - } - else - m_hFile=NULL; - - // free strings and other data - delete [] m_pszFilename; - m_pszFilename=NULL; - delete [] m_pbyBuffer; - m_pbyBuffer=NULL; - } -} - -/////////////////////////////////////////////////////////////// -// Flushes internal buffers when using buffered operations -// may be used in non-buffered mode and for not opened files -// sets file pointer to the place resulting from position -// in internal buffer -/////////////////////////////////////////////////////////////// -void CFileEx::Flush() -{ - if (m_hFile && m_bBuffered && m_dwDataCount > 0) - { - if (m_bLastOperation) - { - // last operation - storing data - WritePacket(); - } - else - { - // last - reading data - // set file pointer to position current-(m_dwDataCount-m_dwCurrentPos) - InternalSeek(-(long)(m_dwDataCount-m_dwCurrentPos), FILE_CURRENT); - m_dwCurrentPos=0; - m_dwDataCount=0; - } - } -} - -/////////////////////////////////////////////////////////////// -// Reads some data from file (buffered or not) -// pBuffer [in/out] - buffer for data -// dwSize [in] - size of data to read -// Ret Value [out] - count of bytes read (could differ from -// dwSize) -/////////////////////////////////////////////////////////////// -DWORD CFileEx::ReadBuffer(void* pBuffer, DWORD dwSize) -{ - _ASSERT(m_hFile); // forgot to open the file ? - - // flush if needed - if (m_bLastOperation) - { - Flush(); - m_bLastOperation=false; - } - - if (!m_bBuffered) - { - // unbuffered operation (read what is needed) - DWORD dwRD=0; - if (!ReadFile(m_hFile, pBuffer, dwSize, &dwRD, NULL)) - THROW_FILEEXCEPTIONEX(_T("Cannot read data from file (ReadFile failed)."), m_pszFilename, FERR_READ, GetLastError()); - - return dwRD; // if 0 - eof (not treated as exception) - } - else - { - // reads must be done by packets - DWORD dwCurrPos=0; // position in external buffer - while (dwCurrPos 0); // couldn't use 0-sized internal buffer - - // flush - Flush(); - - // delete old buffer - if (m_bBuffered && (!bEnable || dwSize != m_dwBufferSize)) - { - delete [] m_pbyBuffer; - m_pbyBuffer=NULL; - } - - // alloc new buffer if needed - if (bEnable && (!m_bBuffered || dwSize != m_dwBufferSize)) - m_pbyBuffer=new BYTE[dwSize]; - - m_bBuffered=bEnable; - m_dwBufferSize=dwSize; -} - -/////////////////////////////////////////////////////////////// -// Changes current mode to unbuffered. If already unbuffered -// function returns doing nothing -/////////////////////////////////////////////////////////////// -void CFileEx::SwitchToUnbuffered() -{ - if (!m_bBuffered) - return; // it's already unbuffered - leave it as is - else - { - m_bRememberedState=true; // mark that we change state to a different one - SetBuffering(false, m_dwBufferSize); // do no change internal buffer size - } -} - -/////////////////////////////////////////////////////////////// -// Changes current mode to buffered. If already buffered -// function returns doing nothing -/////////////////////////////////////////////////////////////// -void CFileEx::SwitchToBuffered() -{ - if (m_bBuffered) - return; // already buffered - else - { - m_bRememberedState=true; - SetBuffering(true, m_dwBufferSize); - } -} - -/////////////////////////////////////////////////////////////// -// Function restores (un)buffered state previously remembered -// with SwitchToXXX. If SwitchToXXX doesn't change the state -// - this function also doesn't. -/////////////////////////////////////////////////////////////// -void CFileEx::RestoreState() -{ - // restore state only if changed - if (m_bRememberedState) - { - SetBuffering(!m_bBuffered, m_dwBufferSize); - m_bRememberedState=false; - } -} - -/////////////////////////////////////////////////////////////// -// (Internal) Reads next packet of data from file (when using -// buffered operations it cause next data of size of internal -// buffer to be read from file -// Ret Value [out] - Count of data that was read -/////////////////////////////////////////////////////////////// -DWORD CFileEx::ReadPacket() -{ - _ASSERT(m_hFile); - - // read data - DWORD dwRD=0; - if (!ReadFile(m_hFile, m_pbyBuffer, m_dwBufferSize, &dwRD, NULL)) - THROW_FILEEXCEPTIONEX(_T("Cannot read data from a file (ReadFile failed)."), m_pszFilename, FERR_READ, GetLastError()); - - // reset internal members - m_dwDataCount=dwRD; - m_dwCurrentPos=0; - - return dwRD; -} - -/////////////////////////////////////////////////////////////// -// (Internal) Function writes all data from internal buffer to -// a file. -// Ret Value [out] - count of bytes written -/////////////////////////////////////////////////////////////// -DWORD CFileEx::WritePacket() -{ - _ASSERT(m_hFile); - - DWORD dwWR=0; - if (!WriteFile(m_hFile, m_pbyBuffer, m_dwDataCount, &dwWR, NULL)) - THROW_FILEEXCEPTIONEX(_T("Cannot write data to a file (WriteFile failed)."), m_pszFilename, FERR_WRITE, GetLastError()); - - // reset internal members - m_dwDataCount=0; - m_dwCurrentPos=0; - - return dwWR; -} - -#ifndef DISABLE_CRYPT -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::SetPassword(PCTSTR pszPass) -{ - // delete the old password - if (m_pszPassword) - delete [] m_pszPassword; // delete old password - - // generate the SHA256 from this password - m_pszPassword=new TCHAR[64+1]; - StringToKey256(pszPass, m_pszPassword); -} - -#endif - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::BeginDataBlock(DWORD dwFlags) -{ - // do not call begin data block within another data block - _ASSERT(!m_bSerializing && m_pbySerialBuffer == NULL); - - // alloc the new buffer and insert there a header (a few bytes) - m_pbySerialBuffer=new BYTE[SERIALBUFFER_DELTA]; - m_dwSerialBufferSize=SERIALBUFFER_DELTA; - - // determine action from read or write flag - bool bWrite=false; - switch(m_dwMode & FA_OPERATION) - { - case FA_READ: - bWrite=false; - break; - case FA_WRITE: - bWrite=true; - break; - case FA_RW: - case FA_APPEND: - _ASSERT(FALSE); // cannot use serialization with files opened in rw mode - break; - } - - // action - if (bWrite) - { - // reserve some space for a header - m_dwSerialBufferPos=sizeof(SERIALIZEINFOHEADER); - } - else - { - // we need to read the block from a file - if (ReadBuffer(m_pbySerialBuffer, sizeof(SERIALIZEINFOHEADER)) != sizeof(SERIALIZEINFOHEADER)) - { - ClearSerialization(); - THROW_FILEEXCEPTIONEX(_T("Cannot read the specified amount of data from a file (reading serialization header)."), m_pszFilename, FERR_SERIALIZE, GetLastError()); - } - - // move forward - m_dwSerialBufferPos=sizeof(SERIALIZEINFOHEADER); - - // determine the size of the remaining data in file - SERIALIZEINFOHEADER* psih=(SERIALIZEINFOHEADER*)m_pbySerialBuffer; - DWORD dwSize=psih->dwToRead-sizeof(SERIALIZEINFOHEADER); - - // check the header crc - DWORD dwhc=icpf::crc32(m_pbySerialBuffer, sizeof(SERIALIZEINFOHEADER)-sizeof(DWORD)); - if (dwhc != psih->dwHeaderCRC32) - { - ClearSerialization(); - THROW_FILEEXCEPTIONEX(_T("Block corrupted. Header CRC check failed."), m_pszFilename, FERR_SERIALIZE, 0); - } - - // resize the buffer - ResizeSerialBuffer(psih->dwToRead); - - // refresh the psih - psih=(SERIALIZEINFOHEADER*)m_pbySerialBuffer; - - // read the remaining data - if (ReadBuffer(m_pbySerialBuffer+m_dwSerialBufferPos, dwSize) != dwSize) - { - ClearSerialization(); - THROW_FILEEXCEPTIONEX(_T("Cannot read specified amount of data from file (reading the after-header data)."), m_pszFilename, FERR_SERIALIZE, GetLastError()); - } - -#ifndef DISABLE_CRYPT - // decrypt the data - if (dwFlags & BF_ENCRYPTED) - { - if (AES256Decrypt(m_pbySerialBuffer+m_dwSerialBufferPos, dwSize, m_pszPassword, m_pbySerialBuffer+m_dwSerialBufferPos) < 0) - { - ClearSerialization(); - THROW_FILEEXCEPTIONEX(_T("Cannot decrypt the data read from the serialization file."), m_pszFilename, FERR_CRYPT, 0); - } - } -#endif - // NOTE: do not update the position - we need ptr at the beginning of data - - // now we are almost ready to retrieve data - only the crc check for the data - DWORD dwCRC=icpf::crc32(m_pbySerialBuffer+sizeof(SERIALIZEINFOHEADER), psih->dwDataSize-sizeof(SERIALIZEINFOHEADER)); - if (psih->dwCRC32 != dwCRC) - { - ClearSerialization(); - THROW_FILEEXCEPTIONEX(_T("CRC check of the data read from file failed."), m_pszFilename, FERR_SERIALIZE, GetLastError()); - } - } - - // make a mark - m_dwDataBlockFlags=dwFlags; - m_bSerializing=true; -} - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::EndDataBlock() -{ - // make sure everything is ok - _ASSERT(m_bSerializing && m_pbySerialBuffer != NULL); - - // type of operation - bool bWrite=false; - switch(m_dwMode & FA_OPERATION) - { - case FA_READ: - bWrite=false; - break; - case FA_WRITE: - bWrite=true; - break; - case FA_RW: - case FA_APPEND: - _ASSERT(FALSE); // cannot use serialization with files opened in rw mode - break; - } - - // when writing - make a header, ...; when reading - do nothing important - if (bWrite) - { - // check if there is any data - if (m_dwSerialBufferPos == sizeof(SERIALIZEINFOHEADER)) - return; // no data has been serialized - - // fill the header (real data information) - SERIALIZEINFOHEADER *psih=(SERIALIZEINFOHEADER*)m_pbySerialBuffer; - psih->dwDataSize=m_dwSerialBufferPos; - psih->dwCRC32=icpf::crc32(m_pbySerialBuffer+sizeof(SERIALIZEINFOHEADER), m_dwSerialBufferPos-sizeof(SERIALIZEINFOHEADER)); - -#ifndef DISABLE_CRYPT - // we could encrypt the data here if needed - if (m_dwDataBlockFlags & BF_ENCRYPTED) - { - int iRes=AES256Crypt(m_pbySerialBuffer+sizeof(SERIALIZEINFOHEADER), m_dwSerialBufferPos-sizeof(SERIALIZEINFOHEADER), m_pszPassword, m_pbySerialBuffer+sizeof(SERIALIZEINFOHEADER)); - if (iRes < 0) - { - ClearSerialization(); - THROW_FILEEXCEPTIONEX(_T("Cannot encrypt the data to store."), m_pszFilename, FERR_CRYPT, 0); - } - - // fill the header - psih->dwToRead=iRes+sizeof(SERIALIZEINFOHEADER); - } - else - { -#endif - // the rest of header - psih->dwToRead=m_dwSerialBufferPos; -#ifndef DISABLE_CRYPT - } -#endif - - // calc the header crc - psih->dwHeaderCRC32=icpf::crc32(m_pbySerialBuffer, sizeof(SERIALIZEINFOHEADER)-sizeof(DWORD)); - - // write the buffer - WriteBuffer(m_pbySerialBuffer, psih->dwToRead); - } - - // remove all the traces of serializing - ClearSerialization(); -} - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::SWrite(void* pData, DWORD dwSize) -{ - InternalAppendSerialBuffer(pData, dwSize); -} - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::SRead(void* pData, DWORD dwSize) -{ - InternalReadSerialBuffer(pData, dwSize); -} - -#ifdef _MFC_VER - -CFileEx& CFileEx::operator<<(CString strData) -{ - DWORD dwLen=strData.GetLength(); - SWrite(&dwLen, sizeof(DWORD)); - SWrite(strData.GetBuffer(1), dwLen); - strData.ReleaseBuffer(); - return *this; -} - -CFileEx& CFileEx::operator>>(CString& strData) -{ - DWORD dwLen; - SRead(&dwLen, sizeof(DWORD)); - PTSTR pszData=strData.GetBuffer(dwLen+1); - try - { - SRead(pszData, dwLen); - } - catch(...) - { - pszData[dwLen]=_T('\0'); - strData.ReleaseBuffer(); - throw; - } - - pszData[dwLen]=_T('\0'); - strData.ReleaseBuffer(); - return *this; -} - -#endif - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::ClearSerialization() -{ - // remove all the traces of serializing - delete [] m_pbySerialBuffer; - m_pbySerialBuffer=NULL; - m_dwSerialBufferSize=0; - m_dwSerialBufferPos=0; - m_bSerializing=false; -} - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::InternalReadSerialBuffer(void* pData, DWORD dwLen) -{ - // check if we are reading - _ASSERT((m_dwMode & FA_OPERATION) == FA_READ); - - // check the ranges - if (m_dwSerialBufferPos+dwLen > m_dwSerialBufferSize) - { - // throw an exception - read beyond the data range in a given object - THROW_FILEEXCEPTIONEX(_T("Trying to read the serialization data beyond the range."), m_pszFilename, FERR_MEMORY, GetLastError()); - } - - // read the data - memcpy(pData, m_pbySerialBuffer+m_dwSerialBufferPos, dwLen); - m_dwSerialBufferPos+=dwLen; -} - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::InternalAppendSerialBuffer(void* pData, DWORD dwCount) -{ - // check if we are writing - _ASSERT((m_dwMode & FA_OPERATION) == FA_WRITE); - - // check serial buffer size (if there is enough room for the data) - if (m_dwSerialBufferPos+dwCount > m_dwSerialBufferSize) - { - // we need a buffer reallocation - DWORD dwDelta=((dwCount/SERIALBUFFER_DELTA)+1)*SERIALBUFFER_DELTA; - - // alloc the new buffer - ResizeSerialBuffer(m_dwSerialBufferSize+dwDelta); - } - - // real storage of the data - if (dwCount > 0) - { - memcpy(m_pbySerialBuffer+m_dwSerialBufferPos, pData, dwCount); - m_dwSerialBufferPos+=dwCount; - } -} - -/////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////// -void CFileEx::ResizeSerialBuffer(DWORD dwNewLen) -{ - // alloc the new buffer - BYTE* pbyNewBuffer=new BYTE[dwNewLen]; - - // copy the old data into the new one - DWORD dwCount=min(m_dwSerialBufferPos, dwNewLen); - if (m_dwSerialBufferPos > 0) - memcpy(pbyNewBuffer, m_pbySerialBuffer, dwCount); - - // delete the old buffer - delete [] m_pbySerialBuffer; - - // set the new buffer inplace and update the internal size - m_pbySerialBuffer=pbyNewBuffer; - m_dwSerialBufferSize=dwNewLen; -} - -/////////////////////////////////////////////////////////////// -// (Internal) Functions reads line of text from text file -// Only for buffered operation -// pszStr [out] - string that was read from file -// dwMaxLen [in] - size of the string buffer -/////////////////////////////////////////////////////////////// -bool CFileEx::InternalReadString(TCHAR* pszStr, DWORD dwMaxLen) -{ - _ASSERT(m_hFile != NULL); // file wasn't opened - error opening or you've forgotten to do so ? - - // last time was writing - free buffer - if (m_bLastOperation) - { - Flush(); - m_bLastOperation=false; - } - - // zero all the string - memset(pszStr, 0, dwMaxLen*sizeof(TCHAR)); - - // additional vars - DWORD dwStrPos=0; // current pos in external buffer - bool bSecondPass=false; // if there is need to check data for 0x0a char - - // copy each char into pszString - while(true) - { - // if buffer is empty - fill it - if (m_dwDataCount == 0 || m_dwCurrentPos == m_dwDataCount) - { - if (ReadPacket() == 0) - return _tcslen(pszStr) != 0; - } - - // skipping 0x0a in second pass - if (bSecondPass) - { - if (m_pbyBuffer[m_dwCurrentPos] == 0x0a) - m_dwCurrentPos++; - return true; - } - - // now process chars - while (m_dwCurrentPos < m_dwDataCount) - { - if (m_pbyBuffer[m_dwCurrentPos] == 0x0d) - { - bSecondPass=true; - m_dwCurrentPos++; - break; - } - else if (m_pbyBuffer[m_dwCurrentPos] == 0x0a) - { - m_dwCurrentPos++; - return true; - } - else - { - if (dwStrPos < dwMaxLen-1) - pszStr[dwStrPos++]=m_pbyBuffer[m_dwCurrentPos]; - m_dwCurrentPos++; - } - } - } - - return false; -} - -/////////////////////////////////////////////////////////////// -// (Internal) Sets file pointer in a file -// llOffset [in] - position to move to -// uiFrom [in] - type of moving (see Platform SDK on -// SetFilePointer) -/////////////////////////////////////////////////////////////// -LONGLONG CFileEx::InternalSeek(LONGLONG llOffset, UINT uiFrom) -{ - LARGE_INTEGER li; - li.QuadPart = llOffset; - li.LowPart = SetFilePointer (m_hFile, li.LowPart, &li.HighPart, uiFrom); - - if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) - { - // error seeking - throw an exception - THROW_FILEEXCEPTIONEX(_T("Seek error."), m_pszFilename, FERR_SEEK, GetLastError()); - } - - return li.QuadPart; -}