/*+--------------------------------------------------------------------------- // // mapio.c - mapped file i/o routines // // History: // 9/4/97 DougP Create this header allow and deal with input map files of zero length 11/20/97 DougP Move these routines from misc.c to here Add option to spec codepage // // ©1997 Microsoft Corporation //----------------------------------------------------------------------------*/ #include #include #include "NLGlib.h" //#ifdef WINCE void Assert(x) { if (x) MessageBox(0,"assert","assert",MB_OK); } //#endif BOOL WINAPI CloseMapFile(PMFILE pmf) { if (pmf==NULL) { return FALSE; } // only unmap what existed - DougP if (pmf->pvMap && !UnmapViewOfFile(pmf->pvMap)) { return FALSE; } // ditto if (pmf->hFileMap && !CloseHandle(pmf->hFileMap)) { return FALSE; } if (!CloseHandle(pmf->hFile)) { return FALSE; } NLGFreeMemory(pmf); return TRUE; } PMFILE WINAPI OpenMapFileWorker(const WCHAR * pwszFileName,BOOL fDstUnicode) { PMFILE pmf; const WCHAR * pwszExt; if (!fNLGNewMemory(&pmf, sizeof(MFILE))) { goto Error; } pmf->fDstUnicode = fDstUnicode; #ifdef WINCE pmf->hFile = CreateFileForMapping( #else pmf->hFile = CMN_CreateFileW( #endif pwszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (pmf->hFile == INVALID_HANDLE_VALUE) { goto Error; } pmf->cbSize1 = GetFileSize(pmf->hFile, &pmf->cbSize2); if (pmf->cbSize1 == 0xFFFFFFFF) { CMN_OutputSystemErrW(L"Can't get size for", pwszFileName); CloseHandle(pmf->hFile); goto Error; } else if (pmf->cbSize1 == 0) { // can't map a zero length file so mark this appropriately pmf->hFileMap = 0; pmf->pvMap = 0; pmf->fSrcUnicode = TRUE; } else { #ifdef WINCE pmf->hFileMap = CreateFileMapping(pmf->hFile, NULL, PAGE_READONLY, 0, 0, NULL); #else pmf->hFileMap = CreateFileMappingA(pmf->hFile, NULL, PAGE_READONLY, 0, 0, NULL); #endif if (pmf->hFileMap == NULL) { CMN_OutputSystemErrW(L"Can't Map", pwszFileName); CloseHandle(pmf->hFile); goto Error; } // Map the entire file starting at the first byte // pmf->pvMap = MapViewOfFile(pmf->hFileMap, FILE_MAP_READ, 0, 0, 0); if (pmf->pvMap == NULL) { CloseHandle(pmf->hFileMap); CloseHandle(pmf->hFile); goto Error; } // HACK: Since IsTextUnicode returns false for sorted stem files, preset // unicode status here based on utf file extension pwszExt = pwszFileName; while (*pwszExt && *pwszExt != L'.' ) pwszExt++; if (*pwszExt && !wcscmp(pwszExt, L".utf")) { pmf->fSrcUnicode = TRUE; } else if (pmf->cbSize1 >= 2 && *(WORD *)pmf->pvMap == 0xFEFF) { // Safe to assume that anything starting with a BOM is Unicode pmf->fSrcUnicode = TRUE; } else { #ifdef WINCE pmf->fSrcUnicode = TRUE; #else pmf->fSrcUnicode = IsTextUnicode(pmf->pvMap, pmf->cbSize1, NULL); #endif } if (pmf->fSrcUnicode) { pmf->pwsz = (WCHAR *)pmf->pvMap; } else { pmf->psz = (PSTR)pmf->pvMap; } } pmf->uCodePage = CP_ACP; // DWP - use default unless client specifies otherwise return pmf; Error: if (pmf) { NLGFreeMemory(pmf); } return NULL; } #ifndef WINCE PMFILE WINAPI OpenMapFileA(const char * pszFileName) { WCHAR * pwszFileName; DWORD cchFileNameLen; int iRet; cchFileNameLen = lstrlenA(pszFileName) + 1; if (!fNLGNewMemory(&pwszFileName, cchFileNameLen * sizeof(WCHAR))) { return NULL; } iRet = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszFileName, -1, pwszFileName, cchFileNameLen); if (iRet ==0) { NLGFreeMemory(pwszFileName); return NULL; } return (OpenMapFileWorker(pwszFileName, FALSE)); } #endif BOOL WINAPI ResetMap(PMFILE pmf) { if (pmf == NULL) { return FALSE; } if (pmf->fSrcUnicode) { pmf->pwsz = (WCHAR*)pmf->pvMap; if (*pmf->pwsz == 0xFEFF) { pmf->pwsz++; } } else { pmf->psz = (CHAR*)pmf->pvMap; } return TRUE; } // Same side effect as GetMapLine (incrememnt map pointer) but without returning contents // in buffer. This is useful in situations where the line may be longer than the max cch and // when the buffer isn't actually needed (counting lines, etc.) // BOOL WINAPI NextMapLine(PMFILE pmf) { DWORD cbOffset; if (!pmf || !pmf->hFileMap) // check for zero length file return FALSE; if (pmf->fSrcUnicode) { WCHAR wch; cbOffset = (DWORD) ((PBYTE)pmf->pwsz - (PBYTE)pmf->pvMap); // test for EOF Assert (cbOffset <= pmf->cbSize1); if (cbOffset == pmf->cbSize1) return FALSE; while (cbOffset < pmf->cbSize1) { cbOffset += sizeof(WCHAR); wch = *pmf->pwsz++; // Break out if this is the newline or the control-Z if (wch == 0x001A || wch == L'\n') break; } } else { CHAR ch; cbOffset = (DWORD) ((PBYTE)pmf->psz - (PBYTE)pmf->pvMap); // test for EOF Assert (cbOffset <= pmf->cbSize1); if (cbOffset == pmf->cbSize1) return FALSE; while (cbOffset < pmf->cbSize1) { cbOffset += sizeof(CHAR); ch = *pmf->psz++; // Break out if this is the newline or the control-Z if (ch == 0x1A || ch == '\n') break; } } return TRUE; } PVOID WINAPI GetMapLine(PVOID pv0, DWORD cbMac, PMFILE pmf) { PVOID pv1; DWORD cbOffset, cbBuff; Assert(pv0); // Make sure that the buffer is at least as big as the caller says it is. // (If the buffer was allocated with the debug memory allocator, this access // should cause an exception if pv0 isn't at least cbMac bytes long. Assert(((char *)pv0)[cbMac-1] == ((char *)pv0)[cbMac-1]); if (!pmf || !pmf->hFileMap) // check for zero length file return NULL; if (pmf->fSrcUnicode != pmf->fDstUnicode) { if (!fNLGNewMemory(&pv1, cbMac)) return NULL; cbBuff = cbMac; } else { pv1 = pv0; } if (pmf->fSrcUnicode) { WCHAR wch, *pwsz = pv1; cbOffset = (DWORD) ((PBYTE)pmf->pwsz - (PBYTE)pmf->pvMap); // test for EOF Assert (cbOffset <= pmf->cbSize1); if (cbOffset == pmf->cbSize1) goto Error; // don't want deal with odd-sized buffers if (cbMac % sizeof(WCHAR) != 0) cbMac -= (cbMac % sizeof(WCHAR)); // reserve space for terminating 0 // Assert (cbMac > 0); cbMac -= sizeof(WCHAR); while (cbOffset < pmf->cbSize1) { cbOffset += sizeof(WCHAR); wch = *pmf->pwsz++; switch (wch) { case L'\r': case L'\n': // end of line case 0xFEFF: // Unicode BOM break; case 0x001A: // ctrl-Z wch = L'\n'; // Replace it so that the last line can be read break; default: *pwsz++ = wch; cbMac -= sizeof(WCHAR); } // Break out if this is the newline or buffer is full if (wch == L'\n' || cbMac <= 0) break; } *pwsz = L'\0'; } else { CHAR ch, *psz = pv1; cbOffset = (DWORD) ((PBYTE)pmf->psz - (PBYTE)pmf->pvMap); // test for EOF Assert (cbOffset <= pmf->cbSize1); if (cbOffset == pmf->cbSize1) goto Error; // reserve space for terminating 0 // Assert (cbMac > 0); cbMac -= sizeof(CHAR); while (cbOffset < pmf->cbSize1) { cbOffset += sizeof(CHAR); ch = *pmf->psz++; switch (ch) { case '\r': case '\n': // end of line break; case 0x1A: // ctrl-Z ch = '\n'; // Replace it so that the last line can be read break; default: cbMac -= sizeof(CHAR); *psz++ = ch; } // Break out if this is the newline or buffer is full if (ch == '\n' || cbMac <= 0) break; } *psz = '\0'; } if (pmf->fSrcUnicode != pmf->fDstUnicode) { DWORD cch = cbBuff; // our argument is a count of bytes if (pmf->fDstUnicode) { // MultiByteToWideChar wants the size of the destination in wide characters cch /= sizeof(WCHAR); cch = MultiByteToWideChar(pmf->uCodePage, MB_PRECOMPOSED,(PSTR)pv1,-1, (WCHAR *)pv0,cch); } else { cch = WideCharToMultiByte(pmf->uCodePage, 0, (WCHAR *)pv1, -1, (PSTR)pv0, cch, NULL, NULL); } if (cch == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Ignore truncation (for consistency with no-conversion cases) // if (pmf->fDstUnicode) { ((WCHAR *)pv0)[(cbBuff / sizeof(WCHAR)) - 1] = 0; } else { ((CHAR *)pv0)[cbBuff - 1] = 0; } } else { // not a truncation error NLGFreeMemory(pv1); return NULL; } } NLGFreeMemory(pv1); } return(pv0); Error: if (pmf->fSrcUnicode != pmf->fDstUnicode) { NLGFreeMemory(pv1); } return NULL; }