Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
7.3 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. dbcsfchk.cpp
  5. Abstract:
  6. Does some simple checking to see if the
  7. file is a valid DBCS file and counts
  8. the number of DBCS characters
  9. Author:
  10. Vijay Jayaseelan (vijayj) Oct-18-2000
  11. Revision History:
  12. None
  13. --*/
  14. #include <iostream>
  15. #include <string>
  16. #include <windows.h>
  17. #include <tchar.h>
  18. #include <mbctype.h>
  19. //
  20. // Usage format
  21. //
  22. std::wstring Usage(L"Usage: dbcsfchk.exe filename codepage");
  23. //
  24. // Helper dump operators
  25. //
  26. std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
  27. FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
  28. fwprintf(OutStream, str.c_str());
  29. return os;
  30. }
  31. //
  32. // Abstracts a Win32 error
  33. //
  34. struct W32Error{
  35. DWORD ErrorCode;
  36. W32Error(DWORD ErrCode) : ErrorCode(ErrCode){}
  37. void Dump(std::ostream &os) {
  38. WCHAR MsgBuffer[4096];
  39. MsgBuffer[0] = UNICODE_NULL;
  40. DWORD CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  41. NULL,
  42. ErrorCode,
  43. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  44. MsgBuffer,
  45. sizeof(MsgBuffer)/sizeof(WCHAR),
  46. NULL);
  47. if (CharCount) {
  48. std::wstring Msg(MsgBuffer);
  49. os << Msg;
  50. } else {
  51. os << std::hex << ErrorCode;
  52. }
  53. }
  54. };
  55. //
  56. // Parses the arguments
  57. //
  58. BOOL
  59. ParseArguments(
  60. IN INT Argc,
  61. IN TCHAR *Argv[],
  62. OUT TCHAR *FileName,
  63. OUT ULONG &CodePage
  64. )
  65. {
  66. BOOL Result = FALSE;
  67. if (FileName && (Argc > 2)) {
  68. _tcscpy(FileName, Argv[1]);
  69. CodePage = atol(Argv[2]);
  70. Result = TRUE;
  71. }
  72. return Result;
  73. }
  74. BOOL
  75. ValidateDbcsData(
  76. IN const TCHAR *Data,
  77. IN ULONG Length,
  78. OUT ULONG &LineNumber,
  79. OUT ULONG &Offset,
  80. OUT ULONG &ValidDbcsChars
  81. )
  82. {
  83. BOOL Result = FALSE;
  84. const TCHAR *CurrPtr = Data;
  85. Offset = 0;
  86. ValidDbcsChars = 0;
  87. while (Offset < Length) {
  88. if (_ismbblead(*(UCHAR*)CurrPtr)) {
  89. Offset++;
  90. if (_ismbbtrail(*(UCHAR *)(CurrPtr + 1))) {
  91. Offset++;
  92. CurrPtr += 2;
  93. ValidDbcsChars++;
  94. continue;
  95. } else {
  96. break;
  97. }
  98. }
  99. if (*CurrPtr == '\n') {
  100. LineNumber++;
  101. } else if ((*CurrPtr == '\r') && (*(CurrPtr+1) == '\n')) {
  102. LineNumber++;
  103. Offset++;
  104. CurrPtr++;
  105. }
  106. Offset++;
  107. CurrPtr++;
  108. }
  109. Result = (Offset == Length);
  110. if (Result) {
  111. LineNumber = 0;
  112. }
  113. return Result;
  114. }
  115. //
  116. // Main entry point
  117. //
  118. INT
  119. __cdecl
  120. _tmain(
  121. IN INT Argc,
  122. IN TCHAR *Argv[]
  123. )
  124. {
  125. INT Result = 1;
  126. try {
  127. TCHAR FileName[MAX_PATH] = {0};
  128. ULONG CodePage = 0;
  129. //
  130. // Parse the arguments
  131. //
  132. if (ParseArguments(Argc, Argv, FileName, CodePage)) {
  133. //
  134. // Set the code page
  135. //
  136. if (!_setmbcp(CodePage)) {
  137. std::cout << "Using Code Page : " << _getmbcp() << std::endl;
  138. //
  139. // Open the file
  140. //
  141. HANDLE FileHandle = CreateFile(FileName,
  142. GENERIC_READ,
  143. 0,
  144. NULL,
  145. OPEN_EXISTING,
  146. FILE_ATTRIBUTE_NORMAL,
  147. NULL);
  148. if (FileHandle == INVALID_HANDLE_VALUE) {
  149. throw new W32Error(GetLastError());
  150. }
  151. //
  152. // Map the file in memory (as readonly)
  153. //
  154. HANDLE FileMapHandle = CreateFileMapping(FileHandle,
  155. NULL,
  156. PAGE_READONLY,
  157. 0,
  158. 0,
  159. NULL);
  160. if (!FileMapHandle) {
  161. DWORD Error = GetLastError();
  162. CloseHandle(FileHandle);
  163. throw new W32Error(Error);
  164. }
  165. TCHAR *Data = (TCHAR *)MapViewOfFile(FileMapHandle,
  166. FILE_MAP_READ,
  167. 0,
  168. 0,
  169. 0);
  170. if (!Data) {
  171. DWORD Error = GetLastError();
  172. CloseHandle(FileMapHandle);
  173. CloseHandle(FileHandle);
  174. throw new W32Error(Error);
  175. }
  176. //
  177. // Get the length of the file
  178. //
  179. BY_HANDLE_FILE_INFORMATION FileInfo = {0};
  180. if (!GetFileInformationByHandle(FileHandle,
  181. &FileInfo)) {
  182. DWORD Error = GetLastError();
  183. UnmapViewOfFile(Data);
  184. CloseHandle(FileMapHandle);
  185. CloseHandle(FileHandle);
  186. throw new W32Error(Error);
  187. }
  188. ULONG LineNumber = 0;
  189. ULONG ErrorOffset = 0;
  190. ULONG DbcsCount = 0;
  191. //
  192. // Validate the Data
  193. //
  194. BOOL Result = ValidateDbcsData(Data,
  195. FileInfo.nFileSizeLow,
  196. LineNumber,
  197. ErrorOffset,
  198. DbcsCount);
  199. if (!Result) {
  200. std::cout << "Character not valid at line number : "
  201. << std::dec << LineNumber
  202. << " offset : " << std::dec << ErrorOffset
  203. << std::endl;
  204. } else {
  205. Result = 0; // no errors\
  206. std::cout << FileName << " is valid DBCS file with "
  207. << std::dec << DbcsCount << " DBCS char(s)" << std::endl;
  208. }
  209. //
  210. // Clean up
  211. //
  212. UnmapViewOfFile(Data);
  213. CloseHandle(FileMapHandle);
  214. CloseHandle(FileHandle);
  215. } else {
  216. std::cout << "Error in setting Code Page to : "
  217. << std::dec << CodePage << std::endl;
  218. }
  219. } else {
  220. std::cout << Usage << std::endl;
  221. }
  222. }
  223. catch(W32Error *Error) {
  224. Error->Dump(std::cout);
  225. delete Error;
  226. }
  227. catch(...) {
  228. std::cout << "Internal error" << std::endl;
  229. }
  230. return Result;
  231. }