📄 cfilemap.cpp
字号:
/*! \file
\brief Implementation of AxPipe::CSourceFileMap and AxPipe::CSinkFileMap, memory mapped files
@(#) $Id: CFileMap.cpp,v 1.4 2004/06/28 19:43:01 svante Exp $
AxPipe - Binary Stream Framework
Copyright (C) 2003 Svante Seleborg/Axon Data, All rights reserved.
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., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
The author may be reached at mailto:axpipe@axondata.se and http://axpipe.sourceforge.net
Why is this framework released as GPL and not LGPL? See http://www.gnu.org/philosophy/why-not-lgpl.html
----
\verbatim
CFileMap.cpp Implementation of CSourceFileMap and CSinkFileMap, memory mapped files
E-mail YYYY-MM-DD Reason
axpipe@axondata.se 2003-12-01 Initial
\endverbatim
*/
#include "stdafx.h"
#include "CFileMap.h"
#include "AxAssert.h"
#define AXLIB_ASSERT_FILE "CFileMap.cpp"
namespace AxPipe {
/// \brief Map a view of a file to a given offset.
///
/// Ensure that the view is correctly aligned, but give the caller a convenient
/// pointer to the right place in the view.
/// \param hMapping An active file mapping
/// \param llOffset The offset in the file you want the view to start at
/// \param cbLen The length of the asked for view
/// \param ppvUserView A user-friendly pointer into the view, correctly offset.
/// \param dwAccess Access requested, FILE_MAP_READ or FILE_MAP_WRITE typeically
/// \return The actual view, NULL if error.
static void *
MapUserView(HANDLE hMapping, longlong llOffset, size_t cbLen, void **ppvUserView, DWORD dwAccess) {
static DWORD dwAllocationGranularity;
if (ppvUserView == NULL) {
return NULL;
}
// Get system allocation granularity to use with the memory mapping functions
if (!dwAllocationGranularity) {
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo); // No error return!
dwAllocationGranularity = SystemInfo.dwAllocationGranularity;
}
DWORD dwMisAlign = (DWORD)(llOffset % dwAllocationGranularity);
cbLen += dwMisAlign;
llOffset -= dwMisAlign;
void *vpView = MapViewOfFile(hMapping, dwAccess, (*(LARGE_INTEGER*)&llOffset).HighPart, (*(LARGE_INTEGER*)&llOffset).LowPart, cbLen);
ASSAPI(vpView != NULL);
*ppvUserView = (char *)vpView + dwMisAlign;
return vpView;
}
/// \brief Construct with Owner, size, buffer pointer, view, file pos and possibly readonly
/// \param pOwner An opaque value identifying the 'owner', probably a 'this' pointer.
/// \param cb The size of the provided memory mapped file segment
/// \param pv The pointer to the actual data to be used
/// \param pView The view pointer, pv may be offset from this due to alignment.
/// \param llPos The file pointer of this segment.
/// \param fReadOnly True if this is a read-only segment
CSegMap::CSegMap(void *pOwner, size_t cb, void *pv, void *pView, longlong llPos, bool fReadOnly) : CSeg(cb, pv, fReadOnly) {
m_pView = pView;
m_pOwner = pOwner;
m_llPos = llPos;
}
/// \brief Unmap the view, if any.
CSegMap::~CSegMap() {
if (m_pView) {
UnmapViewOfFile(m_pView);
m_pView = NULL;
}
}
/// \brief Get the corresponding file pointer
/// \return A position in the mapped file.
longlong
CSegMap::GetPos() {
return m_llPos;
}
/// \brief Compile time polymorphic type information
/// \see CSeg::ClassId()
void *
CSegMap::ClassId() {
static int i;
return &i;
}
/// \brief Run time polymorphic type information
/// \see CSeg::RTClassId()
void *
CSegMap::RTClassId() {
return ClassId();
}
/// \brief Check if the provided opaque pointer matches the owner given on construction.
/// \param pOwner An opaque pointer valute, probably a 'this' pointer
/// \return true if the same value was provided as owner on construction.
bool
CSegMap::IsOwner(void *pOwner) {
return m_pOwner == pOwner;
}
/// \brief Just initialize member variables
CSourceMemFile::CSourceMemFile() {
m_szFileName = NULL;
m_hFile = INVALID_HANDLE_VALUE;
m_hMapping = NULL;
}
/// \brief Additional destruction necessary...
CSourceMemFile::~CSourceMemFile() {
delete [] m_szFileName;
}
/// \brief Get the handle to the opened file
/// \return An operating system handle to the open file.
HANDLE
CSourceMemFile::GetHandle() {
return m_hFile;
}
/// \brief Set file and chunk size
/// \param szFileName The name of the file, it is copied and saved here.
/// \param cbChunk The size of the chunks we send downstream
/// \return A pointer to 'this' CSourceMemFile
CSourceMemFile *CSourceMemFile::Init(const _TCHAR *szFileName, size_t cbChunk) {
m_cbChunk = cbChunk;
size_t cbLen = lstrlen(szFileName);
CopyMemory(m_szFileName = new _TCHAR[cbLen+1], szFileName, (cbLen + 1) * sizeof (_TCHAR));
return this;
}
/// \brief Open the file and create a mapping
///
/// The filename is provided in the Init() call.
/// Check for error with GetErrorCode().
/// \return true if we are to propagate, which we do if no error occurred. false is not an error indication though.
bool CSourceMemFile::OutOpen() {
m_hFile = CreateFile(m_szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (m_hFile == INVALID_HANDLE_VALUE) {
SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::CSourceMemFile open error [%s]"), my_ptr<_TCHAR>(AxLib::APerror(m_szFileName)).get());
return false; // No point propagating if we already failed
}
((LARGE_INTEGER *)&m_cbFileSize)->LowPart =
GetFileSize(m_hFile, (LPDWORD)&(((LARGE_INTEGER *)&m_cbFileSize)->HighPart));
m_cbStreamPos = 0;
m_hMapping = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!m_hMapping) {
SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::CSourceMemFile failed to create file mapping [%s]"), my_ptr<_TCHAR>(AxLib::APerror(m_szFileName)).get());
return false; // No use propagating of we already failed.
}
return true;
}
/// \brief Close the file and the mapping
///
/// Check for error with GetErrorCode().
/// \return true if propagation of the close is recommended, which it is if no error. false is not error indication though.
bool CSourceMemFile::OutClose(void) {
if (m_hMapping) {
if (!CloseHandle(m_hMapping)) {
SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::Close failed to close mapping [%s]"), my_ptr<_TCHAR>(AxLib::APerror()).get());
return true;
}
m_hMapping = NULL;
}
if (m_hFile != INVALID_HANDLE_VALUE) {
if (!CloseHandle(m_hFile)) {
SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::Close failed to close file [%s]"), my_ptr<_TCHAR>(AxLib::APerror()).get());
return true;
}
m_hFile = INVALID_HANDLE_VALUE;
}
return true;
}
/// \brief Get the next chunk from the input file
///
/// The segment returned is actually a CSegMem, i.e. a mapping to the actual
/// file - we do not copy to a memory buffer.
///
/// Multiple calls on EOF conditions are allowed.
///
/// \return A chunk, or zero-length on End-Of-File, or NULL on error.
CSeg *CSourceMemFile::In() {
if (m_cbStreamPos == m_cbFileSize) {
return new CSeg; // Return a zero-sized segment.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -