298 lines
7.3 KiB
C++
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;
|
|
}
|
|
|