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.

1118 lines
34 KiB

  1. /* MMIOTest.c
  2. *
  3. * Test the MMIO library.
  4. */
  5. #include "mmiot32.h" // (Win32)
  6. /* constants */
  7. #define MMIOM_ANSWER (MMIOM_USER + 1) // get answer to the universe
  8. /* globals */
  9. char gszAppName[] = "MMIOTest"; // for title bar etc.
  10. HANDLE ghInst; // program instance handle
  11. /* prototypes */
  12. void PASCAL AppPaint(HWND hwnd, HDC hdc);
  13. BOOL FAR PASCAL AppAbout(HWND hDlg, UINT uMessage,
  14. DWORD dwParam, LONG lParam);
  15. BOOL PASCAL AppInit(HANDLE hInst, HANDLE hPrev);
  16. LONG FAR PASCAL AppWndProc(HWND hwnd, UINT uMessage,
  17. DWORD dwParam, LONG lParam);
  18. int WINAPI WinMain(HANDLE hInst, HANDLE hPrev, LPSTR lpszCmdLine, int iCmdShow);
  19. void NEAR PASCAL Test1(HWND hwnd);
  20. void NEAR PASCAL TestHelloWorld(HMMIO hmmio, LONG lBufSize);
  21. MMIOPROC RCDIOProc;
  22. void NEAR PASCAL Test2(HWND hwnd);
  23. void NEAR PASCAL Test2Helper(BOOL fMemFile);
  24. void NEAR PASCAL FillBufferedFile(HMMIO hmmio, LONG lLongs);
  25. void NEAR PASCAL Test3(HWND hwnd);
  26. void NEAR PASCAL TestRIFF(HMMIO hmmio, BOOL fReadable);
  27. LPSTR NEAR PASCAL lstrrchr(LPSTR szSrc, char ch);
  28. #ifdef OMIT
  29. void NEAR PASCAL lmemset(void far *pDst, BYTE bSrc, long cDst);
  30. #endif //OMIT
  31. /* AppPaint(hwnd, hdc)
  32. *
  33. * This function is called whenever the application windows needs to be
  34. * redrawn.
  35. */
  36. void PASCAL
  37. AppPaint(
  38. HWND hwnd, // window painting into
  39. HDC hdc) // display context to paint to
  40. {
  41. }
  42. /* AppAbout(hDlg, uMessage, dwParam, lParam)
  43. *
  44. * This function handles messages belonging to the "About" dialog box.
  45. * The only message that it looks for is WM_COMMAND, indicating the use
  46. * has pressed the "OK" button. When this happens, it takes down
  47. * the dialog box.
  48. */
  49. BOOL FAR PASCAL // TRUE iff message has been processed
  50. AppAbout(
  51. HWND hDlg, // window handle of "about" dialog box
  52. UINT uMessage, // message number
  53. DWORD dwParam, // message-dependent parameter
  54. LONG lParam) // message-dependent parameter
  55. {
  56. switch (uMessage)
  57. {
  58. case WM_COMMAND:
  59. if (dwParam == IDOK)
  60. EndDialog(hDlg, TRUE);
  61. break;
  62. case WM_INITDIALOG:
  63. return TRUE;
  64. }
  65. return FALSE;
  66. }
  67. /* AppInit(hInst, hPrev)
  68. *
  69. * This is called when the application is first loaded into memory.
  70. * It performs all initialization that doesn't need to be done once
  71. * per instance.
  72. */
  73. BOOL PASCAL // returns TRUE iff successful
  74. AppInit(
  75. HANDLE hInst, // instance handle of current instance
  76. HANDLE hPrev) // instance handle of previous instance
  77. {
  78. WNDCLASS wndclass;
  79. #if DBG
  80. #if BOGUS //Laurie
  81. wpfGetDebugLevel(gszAppName);
  82. #endif
  83. #endif
  84. if (!hPrev)
  85. {
  86. /* Register a class for the main application window */
  87. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  88. wndclass.hIcon = LoadIcon(hInst, "AppIcon");
  89. wndclass.lpszMenuName = "AppMenu";
  90. wndclass.lpszClassName = gszAppName;
  91. /* wndclass.hbrBackground = (HBRUSH) COLOR_WINDOW + 1; */
  92. wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
  93. wndclass.hInstance = hInst; // (Win32)
  94. wndclass.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
  95. wndclass.lpfnWndProc = (WNDPROC)AppWndProc;
  96. wndclass.cbWndExtra = 0;
  97. wndclass.cbClsExtra = 0;
  98. if (!RegisterClass(&wndclass))
  99. return FALSE;
  100. }
  101. return TRUE;
  102. }
  103. /* WinMain(hInst, hPrev, lpszCmdLine, cmdShow)
  104. *
  105. * The main procedure for the App. After initializing, it just goes
  106. * into a message-processing loop until it gets a WM_QUIT message
  107. * (meaning the app was closed).
  108. */
  109. int WINAPI // returns exit code specified in WM_QUIT
  110. WinMain(
  111. HANDLE hInst, // instance handle of current instance
  112. HANDLE hPrev, // instance handle of previous instance
  113. LPSTR lpszCmdLine, // null-terminated command line
  114. int iCmdShow) // how window should be initially displayed
  115. {
  116. MSG msg; // message from queue
  117. HWND hwnd; // handle to app's window
  118. /* save instance handle for dialog boxes */
  119. ghInst = hInst;
  120. /* call initialization procedure */
  121. if (!AppInit(hInst, hPrev))
  122. return FALSE;
  123. /* create the application's window */
  124. hwnd = CreateWindow
  125. (
  126. gszAppName, // window class
  127. gszAppName, // window caption
  128. WS_OVERLAPPEDWINDOW, // window style
  129. CW_USEDEFAULT, 0, // initial position
  130. CW_USEDEFAULT, 0, // initial size
  131. NULL, // parent window handle
  132. NULL, // window menu handle
  133. hInst, // program instance handle
  134. NULL // create parameters
  135. );
  136. ShowWindow(hwnd, iCmdShow);
  137. /* get messages from event queue and dispatch them */
  138. while (GetMessage(&msg, NULL, 0, 0))
  139. {
  140. TranslateMessage(&msg);
  141. DispatchMessage(&msg);
  142. }
  143. return msg.wParam; /* Note: wParam is a DWORD in NT */
  144. }
  145. /* AppWndProc(hwnd, uMessage, dwParam, lParam)
  146. *
  147. * The window proc for the app's main window. This processes all
  148. * of the parent window's messages.
  149. */
  150. LONG FAR PASCAL // returns 0 iff processed message
  151. AppWndProc(
  152. HWND hwnd, // window's handle
  153. UINT uMessage, // message number
  154. DWORD dwParam, // message-dependent parameter
  155. LONG lParam) // message-dependent parameter
  156. {
  157. #ifdef WIN16
  158. FARPROC fpfn;
  159. #endif
  160. PAINTSTRUCT ps;
  161. BOOL fAllTests = FALSE;
  162. switch (uMessage)
  163. {
  164. case WM_COMMAND:
  165. switch (dwParam)
  166. {
  167. case IDM_ABOUT:
  168. /* request to display "About" dialog box */
  169. #ifdef WIN16
  170. fpfn = MakeProcInstance((FARPROC) AppAbout, ghInst);
  171. DialogBox(ghInst, MAKEINTRESOURCE(ABOUTBOX),
  172. hwnd, fpfn);
  173. FreeProcInstance(fpfn);
  174. #else
  175. DialogBox(ghInst, MAKEINTRESOURCE(ABOUTBOX),
  176. hwnd, (DLGPROC)AppAbout);
  177. #endif
  178. break;
  179. case IDM_EXIT:
  180. /* request to exit this program */
  181. PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
  182. break;
  183. case IDM_ALLTESTS:
  184. fAllTests = TRUE;
  185. /* fall through */
  186. case IDM_TEST1:
  187. dprintf("\n--------------- Test1 ---------------\n");
  188. Test1(hwnd);
  189. dprintf("Done Test1.\n");
  190. if (!fAllTests)
  191. break;
  192. case IDM_TEST2:
  193. dprintf("\n--------------- Test2 ---------------\n");
  194. Test2(hwnd);
  195. dprintf("Done Test2.\n");
  196. if (!fAllTests)
  197. break;
  198. case IDM_TEST3:
  199. dprintf("\n--------------- Test3 ---------------\n");
  200. Test3(hwnd);
  201. dprintf("Done Test3.\n");
  202. if (!fAllTests)
  203. break;
  204. dprintf("Done All Tests.\n");
  205. break;
  206. }
  207. return 0L;
  208. case WM_DESTROY:
  209. /* exit this program */
  210. PostQuitMessage(0);
  211. break;
  212. case WM_PAINT:
  213. /* set up a paint structure, and call AppPaint() */
  214. BeginPaint(hwnd, &ps);
  215. AppPaint(hwnd, ps.hdc);
  216. EndPaint(hwnd, &ps);
  217. return 0;
  218. }
  219. return (LONG)DefWindowProc(hwnd, uMessage, dwParam, lParam);
  220. }
  221. void NEAR PASCAL
  222. Test1(HWND hwnd)
  223. {
  224. HMMIO hmmio;
  225. char achMemFile[100];
  226. MMIOINFO mmioinfo;
  227. HMMIO hmmioMF; // memory file handle
  228. long lBufSize;
  229. int fh;
  230. FARPROC farproc; // Added to make it compile. LKG
  231. dprintf("HelloWorld tests...\n");
  232. /* open "hello.txt" unbuffered -- assume it contains
  233. * "hello world\r\n" (13 bytes) -- and run the TestHelloWorld test
  234. */
  235. WinEval((hmmio = mmioOpen("hello.txt", NULL, 0)) != NULL);
  236. dprintf("TestHelloWorld() with no buffer\n");
  237. TestHelloWorld(hmmio, 0);
  238. for (lBufSize = 1; lBufSize <= 15; lBufSize++)
  239. {
  240. /* re-run test for various buffer sizes */
  241. WinEval(mmioSetBuffer(hmmio, NULL, lBufSize, 0) == 0);
  242. WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
  243. dprintf("TestHelloWorld() with %ld-byte buffer\n",
  244. lBufSize);
  245. TestHelloWorld(hmmio, lBufSize);
  246. }
  247. /* copy file into a memory block, set up memory block
  248. * as a memory file, and re-run the test
  249. */
  250. WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
  251. WinEval(mmioRead(hmmio, achMemFile, 13L) == 13L);
  252. memset(&mmioinfo, 0, sizeof(mmioinfo));
  253. mmioinfo.fccIOProc = FOURCC_MEM;
  254. mmioinfo.pchBuffer = achMemFile;
  255. mmioinfo.cchBuffer = 13L;
  256. WinEval((hmmioMF = mmioOpen(NULL, &mmioinfo, 0)) != NULL);
  257. dprintf("TestHelloWorld() with memory file\n");
  258. TestHelloWorld(hmmioMF, 13L);
  259. /* close the open files */
  260. WinEval(mmioClose(hmmio, 0) == 0);
  261. WinEval(mmioClose(hmmioMF, 0) == 0);
  262. /* open file and pass file handle to mmioOpen() */
  263. WinEval((fh = _lopen("hello.txt", READ)) >= 0);
  264. memset(&mmioinfo, 0, sizeof(mmioinfo));
  265. mmioinfo.adwInfo[0] = fh;
  266. WinEval((hmmio = mmioOpen((LPSTR) NULL, &mmioinfo, MMIO_ALLOCBUF))
  267. != NULL);
  268. dprintf("TestHelloWorld() with file handle passed to mmioOpen()\n");
  269. TestHelloWorld(hmmio, 0);
  270. WinEval(mmioClose(hmmio, 0) == 0);
  271. /* "hello.txt" is stored as an RCDATA resource named "Hello" --
  272. * use this to try out the custom I/O procedure stuff
  273. */
  274. dprintf("register Win3 RCDATA custom I/O procedure\n");
  275. #define FOURCC_RCD mmioFOURCC('R', 'C', 'D', ' ')
  276. WinEval( (farproc = (FARPROC) RCDIOProc) != NULL );
  277. /* installing it twice should just mean it has to be removed twice */
  278. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  279. MMIO_FINDPROC) == NULL);
  280. WinEval(mmioInstallIOProc(FOURCC_RCD, (LPMMIOPROC) farproc,
  281. MMIO_INSTALLPROC) == (LPMMIOPROC) farproc);
  282. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  283. MMIO_FINDPROC) == (LPMMIOPROC) farproc);
  284. WinEval(mmioInstallIOProc(FOURCC_RCD, (LPMMIOPROC) farproc,
  285. MMIO_INSTALLPROC) == (LPMMIOPROC) farproc);
  286. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  287. MMIO_FINDPROC) == (LPMMIOPROC) farproc);
  288. /* run the test without an I/O buffer */
  289. dprintf("TestHelloWorld() unbuffered, with custom I/O procedure\n");
  290. WinEval((hmmio = mmioOpen("mmiotest.rcd+Hello", NULL, 0)) != NULL); // changed ! to + LKG
  291. TestHelloWorld(hmmio, 0);
  292. WinEval(mmioClose(hmmio, 0) == 0);
  293. /* run the test with a standard-size I/O buffer */
  294. dprintf("TestHelloWorld() buffered, with custom I/O procedure\n");
  295. WinEval((hmmio = mmioOpen("mmiotest.rcd+Hello", NULL, MMIO_ALLOCBUF))
  296. != NULL);
  297. TestHelloWorld(hmmio, MMIO_DEFAULTBUFFER);
  298. WinEval(mmioClose(hmmio, 0) == 0);
  299. /* remove the custom I/O procedure (it was installed twice above) */
  300. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  301. MMIO_FINDPROC) == (LPMMIOPROC) farproc);
  302. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  303. MMIO_REMOVEPROC) == (LPMMIOPROC) farproc);
  304. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  305. MMIO_FINDPROC) == (LPMMIOPROC) farproc);
  306. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  307. MMIO_REMOVEPROC) == (LPMMIOPROC) farproc);
  308. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  309. MMIO_FINDPROC) == NULL);
  310. WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
  311. MMIO_REMOVEPROC) == NULL);
  312. /* make sure the I/O procedure got removed */
  313. WinEval(mmioOpen("mmiotest.rcd+Hello", NULL, 0) == NULL);
  314. }
  315. void NEAR PASCAL
  316. TestHelloWorld(HMMIO hmmio, LONG lBufSize)
  317. {
  318. MMIOINFO mmioinfo;
  319. char ach[100];
  320. long lOffset;
  321. static NPSTR szHello = "hello world\r\n"; // contents of file
  322. long lAnswer;
  323. strcpy(ach, "Recognisable garbage!");
  324. /* send the I/O procedure a custom message */
  325. lAnswer = mmioSendMessage(hmmio, MMIOM_ANSWER, 20L, 22L);
  326. dprintf("answer %ld, ", lAnswer);
  327. /* expect to be at offset 0 now */
  328. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0L);
  329. if (lBufSize > 0)
  330. {
  331. /* access buffer directly starting at "hello" */
  332. WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
  333. WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_READ) == 0);
  334. WinEval(lstrncmp(mmioinfo.pchNext, szHello,
  335. min((int) lBufSize, 13)) == 0);
  336. if (lBufSize >= 2)
  337. {
  338. WinAssert((mmioinfo.pchEndWrite - mmioinfo.pchNext)
  339. >= 2);
  340. mmioinfo.pchNext += 2;
  341. }
  342. WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
  343. /* expect to be at offset 2 now */
  344. if (lBufSize >= 2)
  345. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 2L);
  346. /* access buffer directly starting at "world" */
  347. WinEval(mmioSeek(hmmio, 6L, SEEK_SET) == 6L);
  348. WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
  349. WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_READ) == 0);
  350. WinEval(lstrncmp(mmioinfo.pchNext, szHello + 6,
  351. min((int) lBufSize, 13 - 6)) == 0);
  352. WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
  353. /* expect to still be at offset 6 */
  354. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 6L);
  355. }
  356. /* go to offset 2 */
  357. WinEval(mmioSeek(hmmio, 2L, SEEK_SET) == 2L);
  358. /* read "llo" */
  359. strcpy(ach, "Recognisable garbage!");
  360. WinEval(mmioRead(hmmio, ach, 3) == 3);
  361. WinEval(lstrncmp(ach, "llo", 3) == 0);
  362. /* read " wor" */
  363. WinEval(mmioRead(hmmio, ach, 4) == 4);
  364. if (lstrncmp(ach, " wor", 4) != 0)
  365. { printf("ach = <%s>, expected < wor>", ach);
  366. }
  367. WinEval(lstrncmp(ach, " wor", 4) == 0);
  368. /* expect to be at offset 9 now */
  369. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 9L);
  370. /* read "ld\r\n" -- ask for 7 bytes, but only expect 4 */
  371. WinEval(mmioRead(hmmio, ach, 7) == 4);
  372. WinEval(lstrncmp(ach, "ld\r\n", 4) == 0);
  373. /* expect to be at end of file now */
  374. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 13L);
  375. /* test seeking and reading for each offset in the file */
  376. dprintf("reading from offset");
  377. for (lOffset = 0; lOffset <= 11; lOffset++)
  378. {
  379. dprintf(" %ld", lOffset);
  380. WinEval(mmioSeek(hmmio, lOffset, SEEK_SET) == lOffset);
  381. WinEval(mmioRead(hmmio, ach, 2) == 2);
  382. WinEval(lstrncmp(ach, "hello world\r\n" + lOffset, 2) == 0);
  383. }
  384. dprintf(".\n");
  385. /* check more seeking */
  386. OutputDebugString("SEEK_SET\n");
  387. WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
  388. WinEval(mmioSeek(hmmio, 13L, SEEK_SET) == 13L);
  389. OutputDebugString("SEEK_CUR\n");
  390. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 13L);
  391. WinEval(mmioSeek(hmmio, -2L, SEEK_CUR) == 11L);
  392. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 11L);
  393. WinEval(mmioSeek(hmmio, -11L, SEEK_CUR) == 0L);
  394. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0L);
  395. OutputDebugString("SEEK_END\n");
  396. WinEval(mmioSeek(hmmio, 11L, SEEK_END) == 2L);
  397. OutputDebugString("SEEK_CUR\n");
  398. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 2L);
  399. /* measure the length of the file */
  400. OutputDebugString("SEEK_END\n");
  401. WinEval(mmioSeek(hmmio, 0L, SEEK_END) == 13L);
  402. } /* TestHelloWorld */
  403. /* 'RCD' I/O Procedure
  404. *
  405. * I/O procedure that will open e.g. "foo.rcd+bar" but it's a con.
  406. * It will chech that what's between the . and + is rcd, it will
  407. * check that bar is in fact "hello" and that foo is "mmiotest"
  408. * It then has a spoof "file" containing "hello world\r\n"
  409. */
  410. typedef struct _MMIORCDINFO // How RCD IOProc uses MMIO.adwInfo[]
  411. {
  412. int fh; // DOS file handle
  413. long lOffset; // offset of start of resource
  414. long lSize; // size of resource (bytes)
  415. } MMIORCDINFO;
  416. LONG FAR PASCAL
  417. RCDIOProc(
  418. LPSTR lpmmioStr, // I/O status block (cast to LPSTR)
  419. UINT uMsg, // message number
  420. LONG lParam1,
  421. LONG lParam2) // message-specific parameters
  422. {
  423. LPMMIOINFO pmmio = (LPMMIOINFO) lpmmioStr;
  424. MMIORCDINFO FAR *pInfo = (MMIORCDINFO FAR *) pmmio->adwInfo;
  425. LPSTR szFileName = (LPSTR) lParam1;
  426. HANDLE hModule; // handle to module
  427. HANDLE hResInfo; // handle to resource information
  428. LONG lBytesLeft; // bytes left in res. after current pos.
  429. WORD wBytesAsk; // bytes asked to read
  430. WORD wBytes; // bytes actually read
  431. LONG lBytesTotal; // accum. bytes actually read
  432. LPSTR pchPlus; // pointer to '+'
  433. LPSTR pchDot; // pointer to '.rcd'
  434. LONG lNewOffset;
  435. static LPSTR lpData = "hello world\r\n"; // actual data
  436. switch (uMsg)
  437. {
  438. case MMIOM_OPEN:
  439. if (0 != stricmp(szFileName,"mmiotest.rcd+hello"))
  440. return MMIOERR_CANNOTOPEN;
  441. pInfo->lSize = strlen(lpData);
  442. pInfo->lOffset = 0;
  443. pmmio->lDiskOffset = 0L;
  444. return 0L;
  445. case MMIOM_CLOSE:
  446. return 0L;
  447. case MMIOM_READ:
  448. /* lParam2 = number of bytes to read */
  449. /* lParam1 = address to deliver them to */
  450. lBytesLeft = pInfo->lSize - pmmio->lDiskOffset;
  451. if (lParam2 > lBytesLeft)
  452. lParam2 = lBytesLeft;
  453. // memcpy((LPSTR)lParam1, lpData[pmmio->lDiskOffset], lParam2); but it trapped!
  454. { int i;
  455. for (i=0; i<lParam2; ++i) {
  456. ((LPSTR)lParam1)[i] = lpData[pmmio->lDiskOffset++];
  457. }
  458. }
  459. return lParam2;
  460. case MMIOM_WRITE:
  461. /* Windows resources are read-only */
  462. return -1;
  463. case MMIOM_SEEK:
  464. /* calculate <lNewOffset>, the new offset (relative to the
  465. * beginning of the resource)
  466. */
  467. switch ((int) lParam2)
  468. {
  469. case SEEK_SET:
  470. lNewOffset = lParam1;
  471. break;
  472. case SEEK_CUR:
  473. lNewOffset = pmmio->lDiskOffset + lParam1;
  474. break;
  475. case SEEK_END:
  476. lNewOffset = pInfo->lSize - lParam1;
  477. break;
  478. }
  479. if (lNewOffset<0)
  480. { dprintf("Seek to before start of rcd");
  481. return -1;
  482. }
  483. if (lNewOffset>pInfo->lSize)
  484. { dprintf("Seek to after end of rcd");
  485. return -1;
  486. }
  487. pmmio->lDiskOffset = lNewOffset;
  488. return lNewOffset;
  489. case MMIOM_ANSWER:
  490. /* this I/O procedure knows the answer to the universe */
  491. return lParam1 + lParam2;
  492. }
  493. return 0L;
  494. }
  495. void NEAR PASCAL
  496. Test2(
  497. HWND hwnd)
  498. {
  499. dprintf("Test2 using a DOS file...\n");
  500. Test2Helper(FALSE);
  501. dprintf("Test2 using a memory file...\n");
  502. Test2Helper(TRUE);
  503. }
  504. void NEAR PASCAL
  505. Test2Helper(
  506. BOOL fMemFile)
  507. {
  508. HMMIO hmmio;
  509. HPSTR pchCallerData = NULL;
  510. long lBytesToRead;
  511. long lOffset;
  512. long lBufSize;
  513. long lMemFileBufSize;
  514. BOOL fBuffered;
  515. MMIOINFO mmioinfo;
  516. dprintf("creating 540000-byte file\n");
  517. if (fMemFile)
  518. {
  519. /* create a memory file */
  520. memset(&mmioinfo, 0, sizeof(mmioinfo));
  521. mmioinfo.fccIOProc = FOURCC_MEM;
  522. mmioinfo.pchBuffer = NULL;
  523. mmioinfo.cchBuffer = 12344L; // initial size
  524. mmioinfo.adwInfo[0] = 76543L; // grow by this much
  525. WinEval((hmmio = mmioOpen(NULL, &mmioinfo,
  526. MMIO_CREATE | MMIO_READWRITE)) != NULL);
  527. }
  528. else
  529. {
  530. /* open "test2.tmp" for reading and writing */
  531. WinEval((hmmio = mmioOpen("test2.tmp", NULL,
  532. MMIO_CREATE | MMIO_READWRITE | MMIO_ALLOCBUF)) != NULL);
  533. }
  534. /* create a file that's big enough so we do the following reads:
  535. * 40000, 60000, 80000, 100000, 120000, 140000 (sum 540000)
  536. */
  537. FillBufferedFile(hmmio, 540000L / 4L);
  538. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 540000L);
  539. dprintf("create huge a buffer that's not segment boundary aligned\n");
  540. /* we'll read stuff into the buffer at offset 12345, to try out
  541. * reading into the buffer across segment offsets
  542. */
  543. if ((pchCallerData = GAllocPtr(140000L + 12345L)) == NULL)
  544. {
  545. dprintf("test program problem: can't allocate caller buffer\n");
  546. WinAssert(FALSE);
  547. }
  548. lMemFileBufSize = 540000L;
  549. for (fBuffered = fMemFile; fBuffered <= TRUE; fBuffered++)
  550. {
  551. /* seek back */
  552. dprintf("seek back, do 40000-140000 byte %s reads,"
  553. " and check file contents\n",
  554. (LPSTR) (fBuffered ? "buffered" : "unbuffered"));
  555. WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
  556. /* read the file in varying large and huge reads, and at the
  557. * same time verify that the file was written to correctly
  558. */
  559. for (lOffset = 0L, lBytesToRead = 40000L, lBufSize = 100000L;
  560. lBytesToRead <= 140000L;
  561. lOffset += lBytesToRead, lBytesToRead += 20000L,
  562. lBufSize -= 10000L)
  563. {
  564. long lLongs;
  565. long huge * pl;
  566. long lOffsetCheck;
  567. MMIOINFO mmioinfo;
  568. if (fMemFile)
  569. {
  570. /* juggle the memory file buffer around, but
  571. * don't truncate the data
  572. */
  573. if (lMemFileBufSize == 540000L)
  574. lMemFileBufSize = 678901L;
  575. else
  576. lMemFileBufSize = 540000L;
  577. WinEval(mmioSetBuffer(hmmio, NULL,
  578. lMemFileBufSize, 0) == 0);
  579. }
  580. else
  581. if (fBuffered)
  582. {
  583. /* just to be nasty, let's play around with the
  584. * buffer size while all this is going on
  585. */
  586. WinEval(mmioSetBuffer(hmmio, NULL, lBufSize, 0)
  587. == 0);
  588. WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
  589. WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_READ)
  590. == 0);
  591. WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
  592. }
  593. else
  594. {
  595. /* no buffer */
  596. WinEval(mmioSetBuffer(hmmio, NULL, 0, 0)
  597. == 0);
  598. }
  599. /* read the next <lBytesToRead> */
  600. WinEval(mmioRead(hmmio, pchCallerData + 12345L,
  601. lBytesToRead) == lBytesToRead);
  602. lLongs = lBytesToRead / 4L, pl =
  603. (long huge *) (pchCallerData + 12345L);
  604. lOffsetCheck = lOffset;
  605. while (lLongs-- > 0)
  606. {
  607. WinEval(*pl++ == lOffsetCheck);
  608. lOffsetCheck += 4;
  609. }
  610. }
  611. WinAssert(mmioSeek(hmmio, 0L, SEEK_CUR) == 540000L);
  612. WinAssert(mmioSeek(hmmio, 0L, SEEK_END) == 540000L);
  613. WinEval(mmioRead(hmmio, pchCallerData + 12345L, 17L) == 0L);
  614. }
  615. if (pchCallerData != NULL)
  616. GFreePtr(pchCallerData);
  617. /* close "test2.tmp" */
  618. WinEval(mmioClose(hmmio, 0) == 0);
  619. if (!fMemFile)
  620. {
  621. dprintf("delete the test file using MMIO_DELETE\n");
  622. WinEval(mmioOpen("test2.tmp", NULL, MMIO_DELETE)
  623. == (HANDLE) TRUE);
  624. }
  625. }
  626. void NEAR PASCAL
  627. FillBufferedFile(
  628. HMMIO hmmio,
  629. LONG lLongs)
  630. {
  631. MMIOINFO mmioinfo;
  632. long lOffset = 0;
  633. /* fill buffered file <hmmio> with <lLongs> binary long integers,
  634. * where offset X (such that X % 4 == 0) contains long integer X
  635. */
  636. /* begin direct access of the I/O buffer */
  637. WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
  638. for( ; ; )
  639. {
  640. long lAvail; // bytes available in buffer
  641. lAvail = mmioinfo.pchEndWrite - mmioinfo.pchNext;
  642. for( ; ; )
  643. {
  644. if ((lAvail -= sizeof(lOffset)) < 0)
  645. break;
  646. if (lLongs-- <= 0)
  647. goto EXIT_FUNCTION;
  648. *((long *) mmioinfo.pchNext) = lOffset;
  649. mmioinfo.pchNext = (long)mmioinfo.pchNext + sizeof(long); // bypass compiler bug
  650. lOffset += sizeof(lOffset);
  651. }
  652. /* flush the I/O buffer */
  653. mmioinfo.dwFlags |= MMIO_DIRTY;
  654. WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_WRITE) == 0);
  655. WinAssert((mmioinfo.pchNext + sizeof(lOffset))
  656. <= mmioinfo.pchEndWrite);
  657. }
  658. EXIT_FUNCTION:
  659. /* end direct access of the I/O buffer */
  660. mmioinfo.dwFlags |= MMIO_DIRTY;
  661. WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
  662. /* make sure we're where we think we should be */
  663. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == lOffset);
  664. }
  665. void NEAR PASCAL
  666. Test3(
  667. HWND hwnd)
  668. {
  669. HMMIO hmmio;
  670. DWORD dwFlags;
  671. MMIOINFO mmioinfo;
  672. for (dwFlags = 0; dwFlags <= MMIO_ALLOCBUF; dwFlags += MMIO_ALLOCBUF)
  673. {
  674. WinEval((hmmio = mmioOpen("test3.tmp", NULL,
  675. dwFlags | MMIO_CREATE | MMIO_WRITE)) != NULL);
  676. dprintf("TestRIFF(), %s, MMIO_WRITE: ",
  677. (LPSTR) (dwFlags == 0 ? "unbuffered" : "buffered"));
  678. TestRIFF(hmmio, FALSE);
  679. WinEval(mmioClose(hmmio, 0) == 0);
  680. WinEval((hmmio = mmioOpen("test3.tmp", NULL,
  681. dwFlags | MMIO_CREATE | MMIO_READWRITE)) != NULL);
  682. dprintf("TestRIFF(), %s, MMIO_READWRITE: ",
  683. (LPSTR) (dwFlags == 0 ? "unbuffered" : "buffered"));
  684. TestRIFF(hmmio, TRUE);
  685. WinEval(mmioClose(hmmio, 0) == 0);
  686. }
  687. /* create a memory file */
  688. memset(&mmioinfo, 0, sizeof(mmioinfo));
  689. mmioinfo.fccIOProc = FOURCC_MEM;
  690. mmioinfo.pchBuffer = NULL;
  691. mmioinfo.cchBuffer = 1L; // initial size
  692. mmioinfo.adwInfo[0] = 1L; // grow by this much
  693. WinEval((hmmio = mmioOpen(NULL, &mmioinfo,
  694. MMIO_CREATE | MMIO_READWRITE)) != NULL);
  695. dprintf("TestRIFF() with memory file: ");
  696. TestRIFF(hmmio, TRUE);
  697. WinEval(mmioClose(hmmio, 0) == 0);
  698. dprintf("delete the test file using MMIO_DELETE\n");
  699. WinEval(mmioOpen("test3.tmp", NULL, MMIO_DELETE) == (HANDLE) TRUE);
  700. }
  701. /* Output from TestRIFF():
  702. *
  703. * 00000000 RIFF (0001E32A) 'foo '
  704. * 0000000C abc1 (00000001)
  705. * 00000016 abc2 (00000002)
  706. * 00000020 abc3 (00000003)
  707. * 0000002C abc4 (00000004)
  708. * 00000038 abc5 (00000005)
  709. * 00000046 abc6 (00000006)
  710. * 00000054 abc7 (00000007)
  711. * 00000064 LIST (0000007E) 'data'
  712. * 00000070 num1 (00000001)
  713. * 0000007A num2 (00000002)
  714. * 00000084 num3 (00000003)
  715. * 00000090 num4 (00000004)
  716. * 0000009C num5 (00000005)
  717. * 000000AA num6 (00000006)
  718. * 000000B8 num7 (00000007)
  719. * 000000C8 num8 (00000008)
  720. * 000000D8 num9 (00000009)
  721. * 000000EA xyz (0001E240)
  722. * 0001E332
  723. */
  724. void NEAR PASCAL
  725. TestRIFF(
  726. HMMIO hmmio,
  727. BOOL fReadable)
  728. {
  729. MMCKINFO ckRIFF;
  730. MMCKINFO ckLIST;
  731. MMCKINFO ck;
  732. HPSTR pchBuf, pchStart;
  733. int huge * pi;
  734. int i;
  735. #define FOURCC_FOO mmioFOURCC('f', 'o', 'o', ' ')
  736. #define FOURCC_ABC mmioFOURCC('a', 'b', 'c', ' ')
  737. #define FOURCC_DATA mmioFOURCC('d', 'a', 't', 'a')
  738. #define FOURCC_NUM mmioFOURCC('n', 'u', 'm', ' ')
  739. #define FOURCC_XYZ mmioFOURCC('x', 'y', 'z', ' ')
  740. dprintf("write file");
  741. /* create 'RIFF' chunk, formtype ' */
  742. ckRIFF.cksize = 0L;
  743. ckRIFF.fccType = FOURCC_FOO;
  744. WinEval(mmioCreateChunk(hmmio, &ckRIFF, MMIO_CREATERIFF) == 0);
  745. /* create chunks 'abc1' ... 'abc7' -- the data for the i-th chunk
  746. * is the first i uppercase letters of the alphabet
  747. */
  748. for (i = 1; i <= 7; i++)
  749. {
  750. MMCKINFO ck;
  751. ck.ckid = FOURCC_ABC;
  752. ((NPSTR) (&ck.ckid))[3] = (CHAR)'0' + (CHAR)i;
  753. ck.cksize = 8 + i;
  754. WinEval(mmioCreateChunk(hmmio, &ck, 0) == 0);
  755. WinEval(mmioWrite(hmmio, "ABCDEFG", (LONG) i) == (LONG) i);
  756. WinEval(mmioAscend(hmmio, &ck, 0) == 0);
  757. }
  758. /* create a LIST chunk with list type 'data' */
  759. ckLIST.cksize = 0L;
  760. ckLIST.fccType = FOURCC_DATA;
  761. WinEval(mmioCreateChunk(hmmio, &ckLIST, MMIO_CREATELIST) == 0);
  762. /* create chunks 'num1' ... 'num9' -- the data for the i-th chunk
  763. * is the first i positive numbers
  764. */
  765. for (i = 1; i <= 9; i++)
  766. {
  767. ck.ckid = FOURCC_NUM;
  768. ((NPSTR) (&ck.ckid))[3] = (CHAR)'0' + (CHAR)i;
  769. ck.cksize = 77; // make medAscend() work for a living
  770. WinEval(mmioCreateChunk(hmmio, &ck, 0) == 0);
  771. WinEval(mmioWrite(hmmio, "123456789", (LONG) i) == (LONG) i);
  772. WinEval(mmioAscend(hmmio, &ck, 0) == 0);
  773. }
  774. /* ascend from the LIST chunk */
  775. WinEval(mmioAscend(hmmio, &ckLIST, 0) == 0);
  776. /* write 'xyz' chunk to contain 123456 bytes that are filled with
  777. * short integers 0 to 123456/2 - 1; make the buffer misaligned
  778. * by 32768 bytes
  779. */
  780. if ((pchBuf = GAllocPtr(123456L + 32768L)) == NULL)
  781. {
  782. dprintf("test program problem: out of memory\n");
  783. WinAssert(FALSE);
  784. }
  785. pchStart = pchBuf + 32768L;
  786. for (pi = (int huge *) pchStart, i = 0; i < (int) (123456L / sizeof(int)); // (Win32)
  787. pi++, i++)
  788. *pi = i;
  789. ck.ckid = FOURCC_XYZ;
  790. WinEval(mmioCreateChunk(hmmio, &ck, 0) == 0);
  791. WinEval(mmioWrite(hmmio, pchStart, 123456L) == 123456L);
  792. WinEval(mmioAscend(hmmio, &ck, 0) == 0);
  793. /* ascend from the RIFF chunk */
  794. WinEval(mmioAscend(hmmio, &ckRIFF, 0) == 0);
  795. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0001E332L);
  796. /* destroy data in <pchStart>, <ck>, etc. to ensure a
  797. * valid test
  798. */
  799. #ifdef OMIT
  800. lmemset(pchStart, 12, 123456L);
  801. #else
  802. memset(pchStart, 12, 123456L);
  803. #endif //OMIT
  804. memset(&ckRIFF, 34, sizeof(ckRIFF));
  805. memset(&ckLIST, 56, sizeof(ckLIST));
  806. memset(&ck, 78, sizeof(ck));
  807. if (fReadable)
  808. {
  809. dprintf(", read file");
  810. /* seek back */
  811. WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
  812. /* descend into RIFF chunk */
  813. WinEval(mmioDescend(hmmio, &ckRIFF, NULL, 0) == 0);
  814. WinAssert(ckRIFF.ckid == FOURCC_RIFF);
  815. WinAssert(ckRIFF.cksize == 0x0001E32AL);
  816. WinAssert(ckRIFF.fccType == FOURCC_FOO);
  817. WinAssert(ckRIFF.dwDataOffset == 0x00000000L + 8L);
  818. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0000000CL);
  819. /* find all the 'abc' chunks */
  820. for (i = 1; i <= 7; i++)
  821. {
  822. MMCKINFO ck;
  823. char ach[10];
  824. /* seek back to start of RIFF chunk data */
  825. WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
  826. ck.ckid = FOURCC_ABC;
  827. ((NPSTR) (&ck.ckid))[3] = (CHAR)'0' + (CHAR)i;
  828. WinEval(mmioDescend(hmmio, &ck, &ckRIFF,
  829. MMIO_FINDCHUNK) == 0);
  830. WinAssert(ck.cksize == (UINT)i);
  831. WinAssert(ck.fccType == 0);
  832. WinEval(mmioRead(hmmio, ach, (LONG) i) == (LONG) i);
  833. WinEval(lstrncmp(ach, "ABCDEFG", i) == 0);
  834. if (i != 7)
  835. WinEval(mmioAscend(hmmio, &ck, 0) == 0);
  836. }
  837. /* we're down two levels -- ascend to end of RIFF chunk */
  838. WinEval(mmioAscend(hmmio, &ckRIFF, 0) == 0);
  839. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0001E332L);
  840. /* seek back to start of RIFF chunk data */
  841. WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
  842. /* make sure we cannot find 'num1' chunk */
  843. ck.ckid = mmioFOURCC('n', 'u', 'm', '1');
  844. WinEval(mmioDescend(hmmio, &ck, &ckRIFF, MMIO_FINDCHUNK)
  845. == MMIOERR_CHUNKNOTFOUND);
  846. /* seek back to start of RIFF chunk data */
  847. WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
  848. /* make sure we can find 'data' list */
  849. ckLIST.fccType = FOURCC_DATA;
  850. WinEval(mmioDescend(hmmio, &ckLIST, &ckRIFF, MMIO_FINDLIST)
  851. == 0);
  852. WinAssert(ckLIST.ckid == FOURCC_LIST);
  853. WinAssert(ckLIST.fccType == FOURCC_DATA);
  854. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x00000064L + 12L);
  855. /* descend into each of the 'num' chunks */
  856. for (i = 1; i <= 9; i++)
  857. {
  858. FOURCC fcc;
  859. MMCKINFO ck;
  860. char ach[10];
  861. fcc = FOURCC_ABC;
  862. ((NPSTR) (&fcc))[3] = (CHAR)'0' + (CHAR)i;
  863. WinEval(mmioDescend(hmmio, &ck, &ckLIST, 0) == 0);
  864. WinAssert(ck.cksize == (UINT)i);
  865. WinAssert(ck.fccType == 0);
  866. WinEval(mmioRead(hmmio, ach, (LONG) i) == (LONG) i);
  867. WinEval(lstrncmp(ach, "123456789", i) == 0);
  868. WinEval(mmioAscend(hmmio, &ck, 0) == 0);
  869. }
  870. /* make sure we cannot go any further */
  871. WinEval(mmioDescend(hmmio, &ck, &ckLIST, 0)
  872. == MMIOERR_CHUNKNOTFOUND);
  873. /* seek back to start of RIFF chunk data */
  874. WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
  875. /* seek to the 'xyz' chunk */
  876. ck.ckid = FOURCC_XYZ;
  877. WinEval(mmioDescend(hmmio, &ck, &ckRIFF, MMIO_FINDCHUNK) == 0);
  878. WinAssert(ck.ckid == FOURCC_XYZ);
  879. WinAssert(ck.fccType == 0);
  880. WinEval(mmioRead(hmmio, pchStart, 123456L) == 123456L);
  881. WinEval(mmioAscend(hmmio, &ck, 0) == 0);
  882. /* ascend from the RIFF chunk */
  883. WinEval(mmioAscend(hmmio, &ckRIFF, 0) == 0);
  884. WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0001E332L);
  885. /* check the contents of the 'xyz' chunk */
  886. for (pi = (int huge *) pchStart, i = 0; i < (int) (123456L / sizeof(int)); // (Win32)
  887. pi++, i++)
  888. {
  889. WinAssert(*pi == i);
  890. }
  891. }
  892. GFreePtr(pchBuf);
  893. dprintf(", done.\n");
  894. }
  895. /* sz = lstrrchr(szSrc, ch)
  896. *
  897. * Find the last occurence <sz> (NULL if not found) of <p ch> in <p szSrc>.
  898. */
  899. LPSTR NEAR PASCAL
  900. lstrrchr(
  901. LPSTR szSrc,
  902. char ch)
  903. {
  904. LPSTR szLast = NULL;
  905. do
  906. {
  907. if (*szSrc == ch)
  908. szLast = szSrc;
  909. } while (*szSrc++ != 0);
  910. return szLast;
  911. }
  912. #ifdef OMIT
  913. /* lmemset(pDst, bSrc, cDst)
  914. *
  915. * Set all <cDest> bytes in memory block <pDst> to a byte value <bSrc>.
  916. */
  917. void NEAR PASCAL
  918. lmemset(
  919. void far *pDst,
  920. BYTE bSrc,
  921. long cDst)
  922. {
  923. while (cDst-- > 0)
  924. *((BYTE huge *) pDst)++ = bSrc;
  925. }
  926. #endif //OMIT
  927.