Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

CFileMap.cpp

Go to the documentation of this file.
00001 
00034 #include "stdafx.h"
00035 #include "CFileMap.h"
00036 
00037 namespace AxPipe {
00048     static void *
00049     MapUserView(HANDLE hMapping, longlong llOffset, size_t cbLen, void **ppvUserView, DWORD dwAccess) {
00050         static DWORD dwAllocationGranularity;
00051 
00052         if (ppvUserView == NULL) {
00053             return NULL;
00054         }
00055 
00056         // Get system allocation granularity to use with the memory mapping functions
00057         if (!dwAllocationGranularity) {
00058             SYSTEM_INFO SystemInfo;
00059             GetSystemInfo(&SystemInfo); // No error return!
00060             dwAllocationGranularity = SystemInfo.dwAllocationGranularity;
00061         }
00062 
00063         DWORD dwMisAlign = (DWORD)(llOffset % dwAllocationGranularity);
00064         cbLen += dwMisAlign;
00065         llOffset -= dwMisAlign;
00066 
00067         void *vpView = MapViewOfFile(hMapping, dwAccess, (*(LARGE_INTEGER*)&llOffset).HighPart, (*(LARGE_INTEGER*)&llOffset).LowPart, cbLen);
00068         ASSAPI(vpView != NULL);
00069         *ppvUserView = (char *)vpView + dwMisAlign;
00070         return vpView;
00071     }
00079     CSegMap::CSegMap(void *pOwner, size_t cb, void *pv, void *pView, longlong llPos, bool fReadOnly) : CSeg(cb, pv, fReadOnly) {
00080         m_pView = pView;
00081         m_pOwner = pOwner;
00082         m_llPos = llPos;
00083     }
00084 
00086     CSegMap::~CSegMap() {
00087         if (m_pView) {
00088             UnmapViewOfFile(m_pView);
00089             m_pView = NULL;
00090         }
00091     }
00092     
00095     longlong
00096     CSegMap::GetPos() {
00097         return m_llPos;
00098     }
00099 
00102     void *
00103     CSegMap::ClassId() {
00104         static int i;
00105         return &i;
00106     }
00107 
00110     void *
00111     CSegMap::RTClassId() {
00112         return ClassId();
00113     }
00114     
00118     bool
00119     CSegMap::IsOwner(void *pOwner) {
00120         return m_pOwner == pOwner;
00121     }
00122 
00124     CSourceMemFile::CSourceMemFile() {
00125         m_szFileName = NULL;
00126         m_hFile = INVALID_HANDLE_VALUE;
00127         m_hMapping = NULL;
00128     }
00129 
00132     HANDLE
00133     CSourceMemFile::GetHandle() {
00134         return m_hFile;
00135     }
00136 
00141     CSourceMemFile *CSourceMemFile::Init(const _TCHAR *szFileName, size_t cbChunk) {
00142         m_cbChunk = cbChunk;
00143         size_t cbLen = lstrlen(szFileName);
00144         CopyMemory(m_szFileName = new _TCHAR[cbLen+1], szFileName, (cbLen + 1) * sizeof (_TCHAR));
00145         return this;
00146     }
00147 
00153     bool CSourceMemFile::OutOpen() {
00154         m_hFile = CreateFile(m_szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
00155         if (m_hFile == INVALID_HANDLE_VALUE) {
00156             SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::CSourceMemFile failed to open %s"), m_szFileName);
00157             return false;                   // No point propagating if we already failed
00158         }
00159         ((LARGE_INTEGER *)&m_cbFileSize)->LowPart =
00160             GetFileSize(m_hFile, (LPDWORD)&(((LARGE_INTEGER *)&m_cbFileSize)->HighPart));
00161         m_cbStreamPos = 0;
00162         m_hMapping = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
00163         if (!m_hMapping) {
00164             SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::CSourceMemFile failed to create file mapping for %s"), m_szFileName);
00165             return false;                   // No use propagating of we already failed.
00166         }
00167         return true;
00168     }
00169 
00174     bool CSourceMemFile::OutClose(void) {
00175         if (m_hMapping) {
00176             if (!CloseHandle(m_hMapping)) {
00177                 SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::Close failed to close mapping"));
00178                 return true;
00179             }
00180             m_hMapping = NULL;
00181         }
00182         if (m_hFile != INVALID_HANDLE_VALUE) {
00183             if (!CloseHandle(m_hFile)) {
00184                 SetError(ERROR_CODE_GENERIC, _T("CSourceMemFile::Close failed to close file"));
00185                 return true;
00186             }
00187             m_hFile = INVALID_HANDLE_VALUE;
00188         }
00189         return true;
00190     }
00199     CSeg *CSourceMemFile::In() {
00200         if (m_cbStreamPos == m_cbFileSize) {
00201             return new CSeg;    // Return a zero-sized segment.
00202         }
00203         size_t cbThisChunk = m_cbChunk;
00204         if (m_cbStreamPos + cbThisChunk > m_cbFileSize) {
00205             cbThisChunk = (size_t)(m_cbFileSize - m_cbStreamPos);
00206         }
00207 
00208         void *pView, *pUserView;
00209         pView = MapUserView(m_hMapping, m_cbStreamPos, cbThisChunk, &pUserView, FILE_MAP_READ);
00210         CSeg *pSeg = new CSegMap(NULL, cbThisChunk, pUserView, pView, m_cbStreamPos, true);
00211         m_cbStreamPos += cbThisChunk;
00212         return pSeg;
00213     }
00214 
00216     CSinkMemFile::CSinkMemFile() {
00217         m_szFileName = NULL;
00218         m_hFile = INVALID_HANDLE_VALUE;
00219         m_hMapping = NULL;
00220         InitializeCriticalSection(&m_CritSect);
00221         m_cbOutPos = m_cbInPos = 0;
00222     }
00223 
00225     CSinkMemFile::~CSinkMemFile() {
00226         delete[] m_szFileName;
00227         DeleteCriticalSection(&m_CritSect);
00228     }
00229 
00232     HANDLE
00233     CSinkMemFile::GetHandle() {
00234         return m_hFile;
00235     }
00236 
00241     CSinkMemFile *
00242     CSinkMemFile::Init(const TCHAR *szFileName, size_t cbChunk) {
00243         m_cbChunk = cbChunk;
00244         size_t cbLen = lstrlen(szFileName);
00245         CopyMemory(m_szFileName = new _TCHAR[cbLen+1], szFileName, (cbLen + 1) * sizeof (_TCHAR));
00246         return this;
00247     }
00248 
00253     bool
00254     CSinkMemFile::OutClose() {
00255         if (m_hMapping) {
00256             do { // Once, poor mans try
00257                 if (!CloseHandle(m_hMapping)) {
00258                     SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Close failed to close mapping"));
00259                     break;
00260                 }
00261                 m_hMapping = NULL;
00262             } while (false);
00263         }
00264         if (m_hFile != INVALID_HANDLE_VALUE) {
00265             do { // Once
00266                 //
00267                 //  Set end of file pointer, this is determined by m_cbOutPos
00268                 //
00269                 if (SetFilePointer(m_hFile, ((LARGE_INTEGER *)&m_cbOutPos)->LowPart, &((LARGE_INTEGER *)&m_cbOutPos)->HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
00270                     SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Close set file pointer to end failed"));
00271                     break;
00272                 }
00273                 if (!SetEndOfFile(m_hFile)) {
00274                     DWORD dwErr = GetLastError();
00275                     SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Close can't set end of file"));
00276                     break;
00277                 }
00278                 if (!CloseHandle(m_hFile)) {
00279                     SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Close failed to close file"));
00280                     break;
00281                 }
00282                 m_hFile = INVALID_HANDLE_VALUE;
00283             } while (false);
00284         }
00285         return true;
00286     }
00300     CSeg *
00301     CSinkMemFile::OutGetSeg(size_t cb) {
00302         CSeg *pSeg;
00303 
00304         EnterCriticalSection(&m_CritSect);
00305         // We can only get a mapped segment if we have an open file already.
00306         longlong cbPos = m_cbInPos > m_cbOutPos ? m_cbInPos : m_cbOutPos;
00307         if (m_hFile != INVALID_HANDLE_VALUE) {
00308             if (cbPos + cb > m_cbMappingSize) {
00309                 m_cbMappingSize = cbPos + cb;
00310                 if (m_hMapping) {
00311                     // This actually works even if we have open views, the order
00312                     // of calls to unmapview and closehandle is not important.
00313                     if (!CloseHandle(m_hMapping)) {
00314                         SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::OutGetSeg failed to close mapping"));
00315                         LeaveCriticalSection(&m_CritSect);
00316                         return NULL;
00317                     }
00318                     m_hMapping = NULL;
00319                 }
00320             }
00321             if (!m_hMapping) {
00322                 // Now create a mapping that is large enough for the largest stream to date.
00323                 m_hMapping = CreateFileMapping(m_hFile, NULL, PAGE_READWRITE, ((LARGE_INTEGER *)&m_cbMappingSize)->HighPart, ((LARGE_INTEGER *)&m_cbMappingSize)->LowPart, NULL);
00324                 if (!m_hMapping) {
00325                     SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::OutGetSeg failed to create file mapping"));
00326                     LeaveCriticalSection(&m_CritSect);
00327                     return NULL;
00328                 }
00329             }
00330             void *pView, *pUserView;
00331             pView = MapUserView(m_hMapping, cbPos, cb, &pUserView, FILE_MAP_WRITE|FILE_MAP_READ);
00332             pSeg = new CSegMap(this, cb, pUserView, pView, cbPos);
00333         } else {
00334             pSeg = new CSeg(cb);
00335         }
00336         m_cbInPos = cbPos + cb;
00337         LeaveCriticalSection(&m_CritSect);
00338         return pSeg;
00339     }
00346     void
00347     CSinkMemFile::Out(CSeg *pSeg) {
00348         if (CSeg::IsSeg(pSeg)) {
00349             // We need to be in a critical section, since the previous section of
00350             // the pipe may be in a different thread and may request allocation from
00351             // OutGetSeg().
00352             EnterCriticalSection(&m_CritSect);
00353             if (pSeg->Len()) {
00354                 // If this is not a CSegMap, or if it is, we're not the owner then we allocate an output.
00355                 if ((pSeg->RTClassId() != CSegMap::ClassId()) || !((CSegMap *)pSeg)->IsOwner(this)) {
00356                     CSeg *pOutSeg = OutGetSeg(pSeg->Len());
00357                     if (!pOutSeg) {
00358                         SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Out() [OutGetSeg() returned NULL]"));
00359                     } else {
00360                         CopyMemory(pOutSeg->PtrWr(), pSeg->PtrRd(), pSeg->Len());
00361                         pOutSeg->Release();
00362                     }
00363                 } else {
00364                     // If we're 'short' of data in the output, we move the segment
00365                     // back. This can happen if an earlier requested segment was cut
00366                     // short before being output.
00367                     CSegMap *pSegMap = (CSegMap *)pSeg;
00368                     if (pSegMap->GetPos() > m_cbOutPos) {
00369                         void *pView, *pUserView;
00370                         pView = MapUserView(m_hMapping, m_cbOutPos, pSegMap->Len(), &pUserView, FILE_MAP_WRITE|FILE_MAP_READ);
00371                         if (!pView) {
00372                             SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Out() [MapUserView() returned NULL]"));
00373                         } else {
00374                             CopyMemory(pUserView, pSegMap->PtrRd(), pSegMap->Len());
00375                             if (!(UnmapViewOfFile(pView))) {
00376                                 SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Out() [UnmapViewOfFile() failed]"));
00377                             }
00378                         }
00379                     } else if (pSegMap->GetPos() < m_cbOutPos) {
00380                         // If we've already output into this segment, it's run over and
00381                         // we've violated the stream model. This can happen if a non-mapped
00382                         // segment is gotten, and then before it's 'output', a non-mapped
00383                         // segment is output. This is an error condition.
00384                         SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::Out() [Output sequence error]"));
00385                     }
00386                     // If (which is the normal case) the output-position is the same as the
00387                     // segment's start, everything is ok and we do nothing.
00388                 }
00389             }
00390             m_cbOutPos += pSeg->Len();
00391             pSeg->Release();
00392             LeaveCriticalSection(&m_CritSect);
00393         }
00394     }
00399     bool
00400     CSinkMemFile::OutOpen() {
00401         // If it's there, open for writing, otherwise create it.
00402         m_hFile = CreateFile(m_szFileName, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
00403         if (m_hFile == INVALID_HANDLE_VALUE) {
00404             SetError(ERROR_CODE_GENERIC, _T("CSinkMemFile::CSinkMemFile failed to open %s"), m_szFileName);
00405         }
00406         ((LARGE_INTEGER *)&m_cbMappingSize)->LowPart = GetFileSize(m_hFile, (LPDWORD)&(((LARGE_INTEGER *)&m_cbMappingSize)->HighPart));
00407         m_cbOutPos = m_cbInPos = 0;
00408         return true;
00409     }
00410 };

Generated on Mon Feb 2 13:19:18 2004 for AxPipe by doxygen 1.3.5