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.

414 lines
10 KiB

  1. /*+---------------------------------------------------------------------------
  2. //
  3. // mapio.c - mapped file i/o routines
  4. //
  5. // History:
  6. // 9/4/97 DougP Create this header
  7. allow and deal with input map files of zero length
  8. 11/20/97 DougP Move these routines from misc.c to here
  9. Add option to spec codepage
  10. //
  11. // �1997 Microsoft Corporation
  12. //----------------------------------------------------------------------------*/
  13. #include <windows.h>
  14. #include <assert.h>
  15. #include "NLGlib.h"
  16. //#ifdef WINCE
  17. void Assert(x)
  18. {
  19. if (x)
  20. MessageBox(0,"assert","assert",MB_OK);
  21. }
  22. //#endif
  23. BOOL WINAPI CloseMapFile(PMFILE pmf)
  24. {
  25. if (pmf==NULL) {
  26. return FALSE;
  27. }
  28. // only unmap what existed - DougP
  29. if (pmf->pvMap && !UnmapViewOfFile(pmf->pvMap)) {
  30. return FALSE;
  31. }
  32. // ditto
  33. if (pmf->hFileMap && !CloseHandle(pmf->hFileMap)) {
  34. return FALSE;
  35. }
  36. if (!CloseHandle(pmf->hFile)) {
  37. return FALSE;
  38. }
  39. NLGFreeMemory(pmf);
  40. return TRUE;
  41. }
  42. PMFILE WINAPI OpenMapFileWorker(const WCHAR * pwszFileName,BOOL fDstUnicode)
  43. {
  44. PMFILE pmf;
  45. const WCHAR * pwszExt;
  46. if (!fNLGNewMemory(&pmf, sizeof(MFILE)))
  47. {
  48. goto Error;
  49. }
  50. pmf->fDstUnicode = fDstUnicode;
  51. #ifdef WINCE
  52. pmf->hFile = CreateFileForMapping(
  53. #else
  54. pmf->hFile = CMN_CreateFileW(
  55. #endif
  56. pwszFileName, GENERIC_READ, FILE_SHARE_READ,
  57. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  58. if (pmf->hFile == INVALID_HANDLE_VALUE)
  59. {
  60. goto Error;
  61. }
  62. pmf->cbSize1 = GetFileSize(pmf->hFile, &pmf->cbSize2);
  63. if (pmf->cbSize1 == 0xFFFFFFFF)
  64. {
  65. CMN_OutputSystemErrW(L"Can't get size for", pwszFileName);
  66. CloseHandle(pmf->hFile);
  67. goto Error;
  68. }
  69. else if (pmf->cbSize1 == 0)
  70. {
  71. // can't map a zero length file so mark this appropriately
  72. pmf->hFileMap = 0;
  73. pmf->pvMap = 0;
  74. pmf->fSrcUnicode = TRUE;
  75. }
  76. else
  77. {
  78. #ifdef WINCE
  79. pmf->hFileMap = CreateFileMapping(pmf->hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  80. #else
  81. pmf->hFileMap = CreateFileMappingA(pmf->hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  82. #endif
  83. if (pmf->hFileMap == NULL)
  84. {
  85. CMN_OutputSystemErrW(L"Can't Map", pwszFileName);
  86. CloseHandle(pmf->hFile);
  87. goto Error;
  88. }
  89. // Map the entire file starting at the first byte
  90. //
  91. pmf->pvMap = MapViewOfFile(pmf->hFileMap, FILE_MAP_READ, 0, 0, 0);
  92. if (pmf->pvMap == NULL)
  93. {
  94. CloseHandle(pmf->hFileMap);
  95. CloseHandle(pmf->hFile);
  96. goto Error;
  97. }
  98. // HACK: Since IsTextUnicode returns false for sorted stem files, preset
  99. // unicode status here based on utf file extension
  100. pwszExt = pwszFileName;
  101. while (*pwszExt && *pwszExt != L'.' ) pwszExt++;
  102. if (*pwszExt && !wcscmp(pwszExt, L".utf"))
  103. {
  104. pmf->fSrcUnicode = TRUE;
  105. }
  106. else if (pmf->cbSize1 >= 2 && *(WORD *)pmf->pvMap == 0xFEFF)
  107. {
  108. // Safe to assume that anything starting with a BOM is Unicode
  109. pmf->fSrcUnicode = TRUE;
  110. }
  111. else
  112. {
  113. #ifdef WINCE
  114. pmf->fSrcUnicode = TRUE;
  115. #else
  116. pmf->fSrcUnicode = IsTextUnicode(pmf->pvMap, pmf->cbSize1, NULL);
  117. #endif
  118. }
  119. if (pmf->fSrcUnicode)
  120. {
  121. pmf->pwsz = (WCHAR *)pmf->pvMap;
  122. }
  123. else
  124. {
  125. pmf->psz = (PSTR)pmf->pvMap;
  126. }
  127. }
  128. pmf->uCodePage = CP_ACP; // DWP - use default unless client specifies otherwise
  129. return pmf;
  130. Error:
  131. if (pmf)
  132. {
  133. NLGFreeMemory(pmf);
  134. }
  135. return NULL;
  136. }
  137. #ifndef WINCE
  138. PMFILE WINAPI OpenMapFileA(const char * pszFileName)
  139. {
  140. WCHAR * pwszFileName;
  141. DWORD cchFileNameLen;
  142. int iRet;
  143. cchFileNameLen = lstrlenA(pszFileName) + 1;
  144. if (!fNLGNewMemory(&pwszFileName, cchFileNameLen * sizeof(WCHAR)))
  145. {
  146. return NULL;
  147. }
  148. iRet = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszFileName, -1,
  149. pwszFileName, cchFileNameLen);
  150. if (iRet ==0)
  151. {
  152. NLGFreeMemory(pwszFileName);
  153. return NULL;
  154. }
  155. return (OpenMapFileWorker(pwszFileName, FALSE));
  156. }
  157. #endif
  158. BOOL WINAPI ResetMap(PMFILE pmf)
  159. {
  160. if (pmf == NULL) {
  161. return FALSE;
  162. }
  163. if (pmf->fSrcUnicode) {
  164. pmf->pwsz = (WCHAR*)pmf->pvMap;
  165. if (*pmf->pwsz == 0xFEFF) {
  166. pmf->pwsz++;
  167. }
  168. } else {
  169. pmf->psz = (CHAR*)pmf->pvMap;
  170. }
  171. return TRUE;
  172. }
  173. // Same side effect as GetMapLine (incrememnt map pointer) but without returning contents
  174. // in buffer. This is useful in situations where the line may be longer than the max cch and
  175. // when the buffer isn't actually needed (counting lines, etc.)
  176. //
  177. BOOL WINAPI NextMapLine(PMFILE pmf)
  178. {
  179. DWORD cbOffset;
  180. if (!pmf || !pmf->hFileMap) // check for zero length file
  181. return FALSE;
  182. if (pmf->fSrcUnicode)
  183. {
  184. WCHAR wch;
  185. cbOffset = (DWORD) ((PBYTE)pmf->pwsz - (PBYTE)pmf->pvMap);
  186. // test for EOF
  187. Assert (cbOffset <= pmf->cbSize1);
  188. if (cbOffset == pmf->cbSize1)
  189. return FALSE;
  190. while (cbOffset < pmf->cbSize1)
  191. {
  192. cbOffset += sizeof(WCHAR);
  193. wch = *pmf->pwsz++;
  194. // Break out if this is the newline or the control-Z
  195. if (wch == 0x001A || wch == L'\n')
  196. break;
  197. }
  198. }
  199. else
  200. {
  201. CHAR ch;
  202. cbOffset = (DWORD) ((PBYTE)pmf->psz - (PBYTE)pmf->pvMap);
  203. // test for EOF
  204. Assert (cbOffset <= pmf->cbSize1);
  205. if (cbOffset == pmf->cbSize1)
  206. return FALSE;
  207. while (cbOffset < pmf->cbSize1)
  208. {
  209. cbOffset += sizeof(CHAR);
  210. ch = *pmf->psz++;
  211. // Break out if this is the newline or the control-Z
  212. if (ch == 0x1A || ch == '\n')
  213. break;
  214. }
  215. }
  216. return TRUE;
  217. }
  218. PVOID WINAPI GetMapLine(PVOID pv0, DWORD cbMac, PMFILE pmf)
  219. {
  220. PVOID pv1;
  221. DWORD cbOffset, cbBuff;
  222. Assert(pv0);
  223. // Make sure that the buffer is at least as big as the caller says it is.
  224. // (If the buffer was allocated with the debug memory allocator, this access
  225. // should cause an exception if pv0 isn't at least cbMac bytes long.
  226. Assert(((char *)pv0)[cbMac-1] == ((char *)pv0)[cbMac-1]);
  227. if (!pmf || !pmf->hFileMap) // check for zero length file
  228. return NULL;
  229. if (pmf->fSrcUnicode != pmf->fDstUnicode)
  230. {
  231. if (!fNLGNewMemory(&pv1, cbMac))
  232. return NULL;
  233. cbBuff = cbMac;
  234. }
  235. else
  236. {
  237. pv1 = pv0;
  238. }
  239. if (pmf->fSrcUnicode)
  240. {
  241. WCHAR wch, *pwsz = pv1;
  242. cbOffset = (DWORD) ((PBYTE)pmf->pwsz - (PBYTE)pmf->pvMap);
  243. // test for EOF
  244. Assert (cbOffset <= pmf->cbSize1);
  245. if (cbOffset == pmf->cbSize1)
  246. goto Error;
  247. // don't want deal with odd-sized buffers
  248. if (cbMac % sizeof(WCHAR) != 0)
  249. cbMac -= (cbMac % sizeof(WCHAR));
  250. // reserve space for terminating 0
  251. //
  252. Assert (cbMac > 0);
  253. cbMac -= sizeof(WCHAR);
  254. while (cbOffset < pmf->cbSize1)
  255. {
  256. cbOffset += sizeof(WCHAR);
  257. wch = *pmf->pwsz++;
  258. switch (wch)
  259. {
  260. case L'\r':
  261. case L'\n': // end of line
  262. case 0xFEFF: // Unicode BOM
  263. break;
  264. case 0x001A: // ctrl-Z
  265. wch = L'\n'; // Replace it so that the last line can be read
  266. break;
  267. default:
  268. *pwsz++ = wch;
  269. cbMac -= sizeof(WCHAR);
  270. }
  271. // Break out if this is the newline or buffer is full
  272. if (wch == L'\n' || cbMac <= 0)
  273. break;
  274. }
  275. *pwsz = L'\0';
  276. }
  277. else
  278. {
  279. CHAR ch, *psz = pv1;
  280. cbOffset = (DWORD) ((PBYTE)pmf->psz - (PBYTE)pmf->pvMap);
  281. // test for EOF
  282. Assert (cbOffset <= pmf->cbSize1);
  283. if (cbOffset == pmf->cbSize1)
  284. goto Error;
  285. // reserve space for terminating 0
  286. //
  287. Assert (cbMac > 0);
  288. cbMac -= sizeof(CHAR);
  289. while (cbOffset < pmf->cbSize1)
  290. {
  291. cbOffset += sizeof(CHAR);
  292. ch = *pmf->psz++;
  293. switch (ch)
  294. {
  295. case '\r':
  296. case '\n': // end of line
  297. break;
  298. case 0x1A: // ctrl-Z
  299. ch = '\n'; // Replace it so that the last line can be read
  300. break;
  301. default:
  302. cbMac -= sizeof(CHAR);
  303. *psz++ = ch;
  304. }
  305. // Break out if this is the newline or buffer is full
  306. if (ch == '\n' || cbMac <= 0)
  307. break;
  308. }
  309. *psz = '\0';
  310. }
  311. if (pmf->fSrcUnicode != pmf->fDstUnicode)
  312. {
  313. DWORD cch = cbBuff; // our argument is a count of bytes
  314. if (pmf->fDstUnicode)
  315. {
  316. // MultiByteToWideChar wants the size of the destination in wide characters
  317. cch /= sizeof(WCHAR);
  318. cch = MultiByteToWideChar(pmf->uCodePage, MB_PRECOMPOSED,(PSTR)pv1,-1, (WCHAR *)pv0,cch);
  319. }
  320. else
  321. {
  322. cch = WideCharToMultiByte(pmf->uCodePage, 0, (WCHAR *)pv1, -1, (PSTR)pv0, cch, NULL, NULL);
  323. }
  324. if (cch == 0)
  325. {
  326. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  327. {
  328. // Ignore truncation (for consistency with no-conversion cases)
  329. //
  330. if (pmf->fDstUnicode)
  331. {
  332. ((WCHAR *)pv0)[(cbBuff / sizeof(WCHAR)) - 1] = 0;
  333. }
  334. else
  335. {
  336. ((CHAR *)pv0)[cbBuff - 1] = 0;
  337. }
  338. }
  339. else
  340. {
  341. // not a truncation error
  342. NLGFreeMemory(pv1);
  343. return NULL;
  344. }
  345. }
  346. NLGFreeMemory(pv1);
  347. }
  348. return(pv0);
  349. Error:
  350. if (pmf->fSrcUnicode != pmf->fDstUnicode)
  351. {
  352. NLGFreeMemory(pv1);
  353. }
  354. return NULL;
  355. }