415 lines
10 KiB
C
415 lines
10 KiB
C
/*+---------------------------------------------------------------------------
|
|
//
|
|
// 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 <windows.h>
|
|
#include <assert.h>
|
|
#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;
|
|
}
|