Leaked source code of windows server 2003
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.

485 lines
12 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module RTFLOG.CPP - RichEdit RTF log
  5. *
  6. * Contains the code for the RTFLog class which can be used
  7. * to log the number of times RTF tags are read by the RTF reader
  8. * for use in coverage testing. TODO: Implement RTF tag logging for the Mac
  9. *
  10. * Authors:<nl>
  11. * Created for RichEdit 2.0: Brad Olenick
  12. *
  13. * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
  14. */
  15. #include "_common.h"
  16. #include "_rtflog.h"
  17. #include "tokens.h"
  18. extern INT cKeywords;
  19. extern const KEYWORD rgKeyword[];
  20. #if defined(DEBUG) && !defined(NOFULLDEBUG)
  21. /*
  22. * CRTFRead::TestParserCoverage()
  23. *
  24. * @mfunc
  25. * A debug routine used to test the coverage of HandleToken. The routine
  26. * puts the routine into a debug mode and then determines:
  27. *
  28. * 1. Dead tokens - (T & !S & !P)
  29. * Here, token:
  30. * a) is defined in token.h (T)
  31. * b) does not have a corresponding keyword (not scanned) (!S)
  32. * c) is not processed by HandleToken (!P)
  33. * 2. Tokens that are parsed but not scanned - (T & !S & P)
  34. * Here, token:
  35. * a) is defined in token.h (T)
  36. * b) does not have a corresponding keyword (not scanned) (!S}
  37. * c) is processed by HandleToken (P)
  38. * 3. Tokens that are scanned but not parsed - (T & S & !P)
  39. * Here, token:
  40. * a) is defined in token.h (T)
  41. * b) does have a corresponding keyword (is scanned) (S)
  42. * c) is not processed by HandleToken (!P)
  43. */
  44. void CRTFRead::TestParserCoverage()
  45. {
  46. int i;
  47. char *rgpszKeyword[tokenMax - tokenMin];
  48. BOOL rgfParsed[tokenMax - tokenMin];
  49. char szBuf[256];
  50. // Put HandleToken in debug mode
  51. _fTestingParserCoverage = TRUE;
  52. // Gather info about tokens/keywords
  53. for(i = 0; i < tokenMax - tokenMin; i++)
  54. {
  55. _token = (TOKEN)(i + tokenMin);
  56. rgpszKeyword[i] = PszKeywordFromToken(_token);
  57. rgfParsed[i] = HandleToken() == ecNoError;
  58. }
  59. // Reset HandleToken to non-debug mode
  60. _fTestingParserCoverage = FALSE;
  61. // Should coverage check include those we know will fail test, but
  62. // which we've examined and know why they fail?
  63. BOOL fExcuseCheckedToks = TRUE;
  64. if(GetProfileIntA("RICHEDIT DEBUG", "RTFCOVERAGESTRICT", 0))
  65. fExcuseCheckedToks = FALSE;
  66. // (T & !S & !P) (1. above)
  67. for(i = 0; i < tokenMax - tokenMin; i++)
  68. {
  69. if(rgpszKeyword[i] || rgfParsed[i])
  70. continue;
  71. TOKEN tok = (TOKEN)(i + tokenMin);
  72. // Token does not correspond to a keyword, but still may be scanned
  73. // check list of individual symbols which are scanned
  74. if(FTokIsSymbol(tok))
  75. continue;
  76. // Check list of tokens which have been checked and fail
  77. // the sanity check for some known reason (see FTokFailsCoverageTest def'n)
  78. if(fExcuseCheckedToks && FTokFailsCoverageTest(tok))
  79. continue;
  80. sprintf(szBuf, "CRTFRead::TestParserCoverage(): Token neither scanned nor parsed - token = %d", tok);
  81. AssertSz(0, szBuf);
  82. }
  83. // (T & !S & P) (2. above)
  84. for(i = 0; i < tokenMax - tokenMin; i++)
  85. {
  86. if(rgpszKeyword[i] || !rgfParsed[i])
  87. continue;
  88. TOKEN tok = (TOKEN)(i + tokenMin);
  89. // Token does not correspond to a keyword, but still may be scanned
  90. // check list of individual symbols which are scanned
  91. if(FTokIsSymbol(tok))
  92. continue;
  93. // Check list of tokens which have been checked and fail
  94. // the sanity check for some known reason (see FTokFailsCoverageTest def'n)
  95. if(fExcuseCheckedToks && FTokFailsCoverageTest(tok))
  96. continue;
  97. sprintf(szBuf, "CRTFRead::TestParserCoverage(): Token parsed but not scanned - token = %d", tok);
  98. AssertSz(0, szBuf);
  99. }
  100. // (T & S & !P) (3. above)
  101. for(i = 0; i < tokenMax - tokenMin; i++)
  102. {
  103. if(!rgpszKeyword[i] || rgfParsed[i])
  104. continue;
  105. TOKEN tok = (TOKEN)(i + tokenMin);
  106. // Check list of tokens which have been checked and fail
  107. // the sanity check for some known reason (see FTokFailsCoverageTest def'n)
  108. if(fExcuseCheckedToks && FTokFailsCoverageTest(tok))
  109. continue;
  110. sprintf(szBuf, "CRTFRead::TestParserCoverage(): Token scanned but not parsed - token = %d, tag = \\%s", tok, rgpszKeyword[i]);
  111. AssertSz(0, szBuf);
  112. }
  113. }
  114. /*
  115. * CRTFRead::PszKeywordFromToken()
  116. *
  117. * @mfunc
  118. * Searches the array of keywords and returns the keyword
  119. * string corresponding to the token supplied
  120. *
  121. * @rdesc
  122. * returns a pointer to the keyword string if one exists
  123. * and NULL otherwise
  124. */
  125. CHAR *CRTFRead::PszKeywordFromToken(TOKEN token)
  126. {
  127. for(int i = 0; i < cKeywords; i++)
  128. {
  129. if(rgKeyword[i].token == token)
  130. return rgKeyword[i].szKeyword;
  131. }
  132. return NULL;
  133. }
  134. /*
  135. * CRTFRead::FTokIsSymbol(TOKEN tok)
  136. *
  137. * @mfunc
  138. * Returns a BOOL indicating whether the token, tok, corresponds to an RTF symbol
  139. * (that is, one of a list of single characters that are scanned in the
  140. * RTF reader)
  141. *
  142. * @rdesc
  143. * BOOL - indicates whether the token corresponds to an RTF symbol
  144. */
  145. BOOL CRTFRead::FTokIsSymbol(TOKEN tok)
  146. {
  147. const BYTE *pbSymbol = NULL;
  148. extern const BYTE szSymbolKeywords[];
  149. extern const TOKEN tokenSymbol[];
  150. // check list of individual symbols which are scanned
  151. for(pbSymbol = szSymbolKeywords; *pbSymbol; pbSymbol++)
  152. {
  153. if(tokenSymbol[pbSymbol - szSymbolKeywords] == tok)
  154. return TRUE;
  155. }
  156. return FALSE;
  157. }
  158. /*
  159. * CRTFRead::FTokFailsCoverageTest(TOKEN tok)
  160. *
  161. * @mfunc
  162. * Returns a BOOL indicating whether the token, tok, is known to fail the
  163. * RTF parser coverage test. These tokens are those that have been checked
  164. * and either:
  165. * 1) have been implemented correctly, but just elude the coverage test
  166. * 2) have yet to be implemented, and have been recognized as such
  167. *
  168. * @rdesc
  169. * BOOL - indicates whether the token has been checked and fails the
  170. * the parser coverage test for some known reason
  171. */
  172. BOOL CRTFRead::FTokFailsCoverageTest(TOKEN tok)
  173. {
  174. switch(tok)
  175. {
  176. // (T & !S & !P) (1. in TestParserCoverage)
  177. // these really aren't tokens per se, but signal ending conditions for the parse
  178. case tokenError:
  179. case tokenEOF:
  180. // (T & !S & P) (2. in TestParserCoverage)
  181. // emitted by scanner, but don't correspond to recognized RTF keyword
  182. case tokenUnknownKeyword:
  183. case tokenText:
  184. case tokenASCIIText:
  185. // recognized directly (before the scanner is called)
  186. case tokenStartGroup:
  187. case tokenEndGroup:
  188. // recognized using context information (before the scanner is called)
  189. case tokenObjectDataValue:
  190. case tokenPictureDataValue:
  191. // (T & S & !P) (3. in TestParserCoverage)
  192. // None
  193. return TRUE;
  194. }
  195. return FALSE;
  196. }
  197. #endif // DEBUG
  198. /*
  199. * CRTFLog::CRTFLog()
  200. *
  201. * @mfunc
  202. * Constructor -
  203. * 1. Opens a file mapping to log hit counts, creating
  204. * the backing file if neccessary
  205. * 2. Map a view of the file mapping into memory
  206. * 3. Register a windows message for change notifications
  207. *
  208. */
  209. CRTFLog::CRTFLog() : _rgdwHits(NULL), _hfm(NULL), _hfile(NULL)
  210. {
  211. #ifndef NOFULLDEBUG
  212. const char cstrMappingName[] = "RTFLOG";
  213. const char cstrWM[] = "RTFLOGWM";
  214. const int cbMappingSize = sizeof(ELEMENT) * ISize();
  215. BOOL fNewFile = FALSE;
  216. // Check for existing file mapping
  217. if(!(_hfm = OpenFileMappingA(FILE_MAP_ALL_ACCESS,
  218. TRUE,
  219. cstrMappingName)))
  220. {
  221. // No existing file mapping
  222. // Get the file with which to create the file mapping
  223. // first, attempt to open an existing file
  224. if(!(_hfile = CreateFileA(LpcstrLogFilename(),
  225. GENERIC_READ | GENERIC_WRITE,
  226. 0,
  227. NULL,
  228. OPEN_EXISTING,
  229. FILE_ATTRIBUTE_NORMAL,
  230. NULL)))
  231. {
  232. // No existing file, attempt to create new
  233. if(!(_hfile = CreateFileA(LpcstrLogFilename(),
  234. GENERIC_READ | GENERIC_WRITE,
  235. 0,
  236. NULL,
  237. OPEN_ALWAYS,
  238. FILE_ATTRIBUTE_NORMAL,
  239. NULL)))
  240. {
  241. return;
  242. }
  243. fNewFile = TRUE;
  244. }
  245. _hfm = CreateFileMappingA(_hfile, NULL, PAGE_READWRITE, 0,
  246. cbMappingSize, cstrMappingName);
  247. if(!_hfm)
  248. return;
  249. }
  250. LPVOID lpv = MapViewOfFile(_hfm, FILE_MAP_ALL_ACCESS, 0, 0, cbMappingSize);
  251. if(!lpv)
  252. return;
  253. // Register windows message for change notifications
  254. SideAssert(_uMsg = RegisterWindowMessageA(cstrWM));
  255. // Memory-mapped file is now mapped to _rgdwHits
  256. _rgdwHits = (PELEMENT)lpv;
  257. // Zero the memory-mapped file if we created it new
  258. // (Win95 gives us a new file w/ garbage in it for some reason)
  259. if(fNewFile)
  260. Reset();
  261. #endif
  262. }
  263. /*
  264. * CRTFLog::Reset()
  265. *
  266. * @mfunc
  267. * Resets the hitcount of each element in the log to 0
  268. *
  269. */
  270. void CRTFLog::Reset()
  271. {
  272. if(!FInit())
  273. return;
  274. for(INDEX i = 0; i < ISize(); i++)
  275. (*this)[i] = 0;
  276. // notify clients of change
  277. ChangeNotifyAll();
  278. }
  279. /*
  280. * CRTFLog::UGetWindowMsg
  281. *
  282. * @mdesc
  283. * Returns the window message id used for change notifications
  284. *
  285. * @rdesc
  286. * UINT window message id
  287. *
  288. * @devnote
  289. * This should be inline, but the AssertSz macro doesn't compile
  290. * properly on the Mac if its placed in a header file
  291. *
  292. */
  293. UINT CRTFLog::UGetWindowMsg() const
  294. {
  295. AssertSz(FInit(), "CRTFLog::UGetWindowMsg(): CRTFLog not initialized properly");
  296. return _uMsg;
  297. }
  298. /*
  299. * CRTFLog::operator[]
  300. *
  301. * @mdesc
  302. * Returns reference to element i of RTF log (l-value)
  303. *
  304. * @rdesc
  305. * ELEMENT & reference to element i of log
  306. *
  307. * @devnote
  308. * This should be inline, but the AssertSz macro doesn't compile
  309. * properly on the Mac if its placed in a header file
  310. *
  311. */
  312. CRTFLog::ELEMENT &CRTFLog::operator[](INDEX i)
  313. {
  314. AssertSz(i < ISize(), "CRTFLog::operator[]: index out of range");
  315. AssertSz(FInit(), "CRTFLog::operator[]: CRTFLog not initialized properly");
  316. return _rgdwHits[i];
  317. }
  318. /*
  319. * CRTFLog::operator[]
  320. *
  321. * @mdesc
  322. * Returns reference to element i of RTF log (r-value)
  323. *
  324. * @rdesc
  325. * const ELEMENT & reference to element i of log
  326. *
  327. * @devnote
  328. * This should be inline, but the AssertSz macro doesn't compile
  329. * properly on the Mac if its placed in a header file
  330. *
  331. */
  332. const CRTFLog::ELEMENT &CRTFLog::operator[](INDEX i) const
  333. {
  334. AssertSz(i < ISize(), "CRTFLog::operator[]: index out of range");
  335. AssertSz(FInit(), "CRTFLog::operator[]: CRTFLog not initialized properly");
  336. return _rgdwHits[i];
  337. }
  338. /*
  339. * CRTFLog::LpcstrLogFilename()
  340. *
  341. * @mfunc
  342. * Returns name of file to be used for log
  343. *
  344. * @rdesc
  345. * LPCSTR pointer to static buffer containing file name
  346. */
  347. LPCSTR CRTFLog::LpcstrLogFilename() const
  348. {
  349. static char szBuf[MAX_PATH] = "";
  350. #ifndef NOFULLDEBUG
  351. const char cstrLogFilename[] = "RTFLOG";
  352. if(!szBuf[0])
  353. {
  354. DWORD cchLength;
  355. char szBuf2[MAX_PATH];
  356. SideAssert(cchLength = GetTempPathA(MAX_PATH, szBuf2));
  357. // append trailing backslash if neccessary
  358. if(szBuf2[cchLength - 1] != '\\')
  359. {
  360. szBuf2[cchLength] = '\\';
  361. szBuf2[cchLength + 1] = 0;
  362. }
  363. wsprintfA(szBuf, "%s%s", szBuf2, cstrLogFilename);
  364. }
  365. #endif
  366. return szBuf;
  367. }
  368. /*
  369. * CRTFLog::IIndexOfKeyword(LPCSTR lpcstrKeyword, PINDEX piIndex)
  370. *
  371. * @mfunc
  372. * Returns the index of the log element which corresponds to
  373. * the RTF keyword, lpcstrKeyword
  374. *
  375. * @rdesc
  376. * BOOL flag indicating whether index was found
  377. */
  378. BOOL CRTFLog::IIndexOfKeyword(LPCSTR lpcstrKeyword, PINDEX piIndex) const
  379. {
  380. INDEX i;
  381. for(i = 0; i < ISize(); i++)
  382. {
  383. if(strcmp(lpcstrKeyword, rgKeyword[i].szKeyword) == 0)
  384. break;
  385. }
  386. if(i == ISize())
  387. return FALSE;
  388. if(piIndex)
  389. *piIndex = i;
  390. return TRUE;
  391. }
  392. /*
  393. * CRTFLog::IIndexOfToken(TOKEN token, PINDEX piIndex)
  394. *
  395. * @mfunc
  396. * Returns the index of the log element which corresponds to
  397. * the RTF token, token
  398. *
  399. * @rdesc
  400. * BOOL flag indicating whether index was found
  401. */
  402. BOOL CRTFLog::IIndexOfToken(TOKEN token, PINDEX piIndex) const
  403. {
  404. INDEX i;
  405. for(i = 0; i < ISize(); i++)
  406. {
  407. if(token == rgKeyword[i].token)
  408. break;
  409. }
  410. if(i == ISize())
  411. return FALSE;
  412. if(piIndex)
  413. *piIndex = i;
  414. return TRUE;
  415. }