windows-nt/Source/XPSP1/NT/base/ntsetup/tools/dbcsfchk/dbcsfchk.cpp
2020-09-26 16:20:57 +08:00

298 lines
7.3 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
dbcsfchk.cpp
Abstract:
Does some simple checking to see if the
file is a valid DBCS file and counts
the number of DBCS characters
Author:
Vijay Jayaseelan (vijayj) Oct-18-2000
Revision History:
None
--*/
#include <iostream>
#include <string>
#include <windows.h>
#include <tchar.h>
#include <mbctype.h>
//
// Usage format
//
std::wstring Usage(L"Usage: dbcsfchk.exe filename codepage");
//
// Helper dump operators
//
std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
fwprintf(OutStream, str.c_str());
return os;
}
//
// Abstracts a Win32 error
//
struct W32Error{
DWORD ErrorCode;
W32Error(DWORD ErrCode) : ErrorCode(ErrCode){}
void Dump(std::ostream &os) {
WCHAR MsgBuffer[4096];
MsgBuffer[0] = UNICODE_NULL;
DWORD CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
MsgBuffer,
sizeof(MsgBuffer)/sizeof(WCHAR),
NULL);
if (CharCount) {
std::wstring Msg(MsgBuffer);
os << Msg;
} else {
os << std::hex << ErrorCode;
}
}
};
//
// Parses the arguments
//
BOOL
ParseArguments(
IN INT Argc,
IN TCHAR *Argv[],
OUT TCHAR *FileName,
OUT ULONG &CodePage
)
{
BOOL Result = FALSE;
if (FileName && (Argc > 2)) {
_tcscpy(FileName, Argv[1]);
CodePage = atol(Argv[2]);
Result = TRUE;
}
return Result;
}
BOOL
ValidateDbcsData(
IN const TCHAR *Data,
IN ULONG Length,
OUT ULONG &LineNumber,
OUT ULONG &Offset,
OUT ULONG &ValidDbcsChars
)
{
BOOL Result = FALSE;
const TCHAR *CurrPtr = Data;
Offset = 0;
ValidDbcsChars = 0;
while (Offset < Length) {
if (_ismbblead(*(UCHAR*)CurrPtr)) {
Offset++;
if (_ismbbtrail(*(UCHAR *)(CurrPtr + 1))) {
Offset++;
CurrPtr += 2;
ValidDbcsChars++;
continue;
} else {
break;
}
}
if (*CurrPtr == '\n') {
LineNumber++;
} else if ((*CurrPtr == '\r') && (*(CurrPtr+1) == '\n')) {
LineNumber++;
Offset++;
CurrPtr++;
}
Offset++;
CurrPtr++;
}
Result = (Offset == Length);
if (Result) {
LineNumber = 0;
}
return Result;
}
//
// Main entry point
//
INT
__cdecl
_tmain(
IN INT Argc,
IN TCHAR *Argv[]
)
{
INT Result = 1;
try {
TCHAR FileName[MAX_PATH] = {0};
ULONG CodePage = 0;
//
// Parse the arguments
//
if (ParseArguments(Argc, Argv, FileName, CodePage)) {
//
// Set the code page
//
if (!_setmbcp(CodePage)) {
std::cout << "Using Code Page : " << _getmbcp() << std::endl;
//
// Open the file
//
HANDLE FileHandle = CreateFile(FileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE) {
throw new W32Error(GetLastError());
}
//
// Map the file in memory (as readonly)
//
HANDLE FileMapHandle = CreateFileMapping(FileHandle,
NULL,
PAGE_READONLY,
0,
0,
NULL);
if (!FileMapHandle) {
DWORD Error = GetLastError();
CloseHandle(FileHandle);
throw new W32Error(Error);
}
TCHAR *Data = (TCHAR *)MapViewOfFile(FileMapHandle,
FILE_MAP_READ,
0,
0,
0);
if (!Data) {
DWORD Error = GetLastError();
CloseHandle(FileMapHandle);
CloseHandle(FileHandle);
throw new W32Error(Error);
}
//
// Get the length of the file
//
BY_HANDLE_FILE_INFORMATION FileInfo = {0};
if (!GetFileInformationByHandle(FileHandle,
&FileInfo)) {
DWORD Error = GetLastError();
UnmapViewOfFile(Data);
CloseHandle(FileMapHandle);
CloseHandle(FileHandle);
throw new W32Error(Error);
}
ULONG LineNumber = 0;
ULONG ErrorOffset = 0;
ULONG DbcsCount = 0;
//
// Validate the Data
//
BOOL Result = ValidateDbcsData(Data,
FileInfo.nFileSizeLow,
LineNumber,
ErrorOffset,
DbcsCount);
if (!Result) {
std::cout << "Character not valid at line number : "
<< std::dec << LineNumber
<< " offset : " << std::dec << ErrorOffset
<< std::endl;
} else {
Result = 0; // no errors\
std::cout << FileName << " is valid DBCS file with "
<< std::dec << DbcsCount << " DBCS char(s)" << std::endl;
}
//
// Clean up
//
UnmapViewOfFile(Data);
CloseHandle(FileMapHandle);
CloseHandle(FileHandle);
} else {
std::cout << "Error in setting Code Page to : "
<< std::dec << CodePage << std::endl;
}
} else {
std::cout << Usage << std::endl;
}
}
catch(W32Error *Error) {
Error->Dump(std::cout);
delete Error;
}
catch(...) {
std::cout << "Internal error" << std::endl;
}
return Result;
}