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.
 
 
 
 
 
 

1119 lines
34 KiB

/* MMIOTest.c
*
* Test the MMIO library.
*/
#include "mmiot32.h" // (Win32)
/* constants */
#define MMIOM_ANSWER (MMIOM_USER + 1) // get answer to the universe
/* globals */
char gszAppName[] = "MMIOTest"; // for title bar etc.
HANDLE ghInst; // program instance handle
/* prototypes */
void PASCAL AppPaint(HWND hwnd, HDC hdc);
BOOL FAR PASCAL AppAbout(HWND hDlg, UINT uMessage,
DWORD dwParam, LONG lParam);
BOOL PASCAL AppInit(HANDLE hInst, HANDLE hPrev);
LONG FAR PASCAL AppWndProc(HWND hwnd, UINT uMessage,
DWORD dwParam, LONG lParam);
int WINAPI WinMain(HANDLE hInst, HANDLE hPrev, LPSTR lpszCmdLine, int iCmdShow);
void NEAR PASCAL Test1(HWND hwnd);
void NEAR PASCAL TestHelloWorld(HMMIO hmmio, LONG lBufSize);
MMIOPROC RCDIOProc;
void NEAR PASCAL Test2(HWND hwnd);
void NEAR PASCAL Test2Helper(BOOL fMemFile);
void NEAR PASCAL FillBufferedFile(HMMIO hmmio, LONG lLongs);
void NEAR PASCAL Test3(HWND hwnd);
void NEAR PASCAL TestRIFF(HMMIO hmmio, BOOL fReadable);
LPSTR NEAR PASCAL lstrrchr(LPSTR szSrc, char ch);
#ifdef OMIT
void NEAR PASCAL lmemset(void far *pDst, BYTE bSrc, long cDst);
#endif //OMIT
/* AppPaint(hwnd, hdc)
*
* This function is called whenever the application windows needs to be
* redrawn.
*/
void PASCAL
AppPaint(
HWND hwnd, // window painting into
HDC hdc) // display context to paint to
{
}
/* AppAbout(hDlg, uMessage, dwParam, lParam)
*
* This function handles messages belonging to the "About" dialog box.
* The only message that it looks for is WM_COMMAND, indicating the use
* has pressed the "OK" button. When this happens, it takes down
* the dialog box.
*/
BOOL FAR PASCAL // TRUE iff message has been processed
AppAbout(
HWND hDlg, // window handle of "about" dialog box
UINT uMessage, // message number
DWORD dwParam, // message-dependent parameter
LONG lParam) // message-dependent parameter
{
switch (uMessage)
{
case WM_COMMAND:
if (dwParam == IDOK)
EndDialog(hDlg, TRUE);
break;
case WM_INITDIALOG:
return TRUE;
}
return FALSE;
}
/* AppInit(hInst, hPrev)
*
* This is called when the application is first loaded into memory.
* It performs all initialization that doesn't need to be done once
* per instance.
*/
BOOL PASCAL // returns TRUE iff successful
AppInit(
HANDLE hInst, // instance handle of current instance
HANDLE hPrev) // instance handle of previous instance
{
WNDCLASS wndclass;
#if DBG
#if BOGUS //Laurie
wpfGetDebugLevel(gszAppName);
#endif
#endif
if (!hPrev)
{
/* Register a class for the main application window */
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(hInst, "AppIcon");
wndclass.lpszMenuName = "AppMenu";
wndclass.lpszClassName = gszAppName;
/* wndclass.hbrBackground = (HBRUSH) COLOR_WINDOW + 1; */
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.hInstance = hInst; // (Win32)
wndclass.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = (WNDPROC)AppWndProc;
wndclass.cbWndExtra = 0;
wndclass.cbClsExtra = 0;
if (!RegisterClass(&wndclass))
return FALSE;
}
return TRUE;
}
/* WinMain(hInst, hPrev, lpszCmdLine, cmdShow)
*
* The main procedure for the App. After initializing, it just goes
* into a message-processing loop until it gets a WM_QUIT message
* (meaning the app was closed).
*/
int WINAPI // returns exit code specified in WM_QUIT
WinMain(
HANDLE hInst, // instance handle of current instance
HANDLE hPrev, // instance handle of previous instance
LPSTR lpszCmdLine, // null-terminated command line
int iCmdShow) // how window should be initially displayed
{
MSG msg; // message from queue
HWND hwnd; // handle to app's window
/* save instance handle for dialog boxes */
ghInst = hInst;
/* call initialization procedure */
if (!AppInit(hInst, hPrev))
return FALSE;
/* create the application's window */
hwnd = CreateWindow
(
gszAppName, // window class
gszAppName, // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, 0, // initial position
CW_USEDEFAULT, 0, // initial size
NULL, // parent window handle
NULL, // window menu handle
hInst, // program instance handle
NULL // create parameters
);
ShowWindow(hwnd, iCmdShow);
/* get messages from event queue and dispatch them */
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam; /* Note: wParam is a DWORD in NT */
}
/* AppWndProc(hwnd, uMessage, dwParam, lParam)
*
* The window proc for the app's main window. This processes all
* of the parent window's messages.
*/
LONG FAR PASCAL // returns 0 iff processed message
AppWndProc(
HWND hwnd, // window's handle
UINT uMessage, // message number
DWORD dwParam, // message-dependent parameter
LONG lParam) // message-dependent parameter
{
#ifdef WIN16
FARPROC fpfn;
#endif
PAINTSTRUCT ps;
BOOL fAllTests = FALSE;
switch (uMessage)
{
case WM_COMMAND:
switch (dwParam)
{
case IDM_ABOUT:
/* request to display "About" dialog box */
#ifdef WIN16
fpfn = MakeProcInstance((FARPROC) AppAbout, ghInst);
DialogBox(ghInst, MAKEINTRESOURCE(ABOUTBOX),
hwnd, fpfn);
FreeProcInstance(fpfn);
#else
DialogBox(ghInst, MAKEINTRESOURCE(ABOUTBOX),
hwnd, (DLGPROC)AppAbout);
#endif
break;
case IDM_EXIT:
/* request to exit this program */
PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
break;
case IDM_ALLTESTS:
fAllTests = TRUE;
/* fall through */
case IDM_TEST1:
dprintf("\n--------------- Test1 ---------------\n");
Test1(hwnd);
dprintf("Done Test1.\n");
if (!fAllTests)
break;
case IDM_TEST2:
dprintf("\n--------------- Test2 ---------------\n");
Test2(hwnd);
dprintf("Done Test2.\n");
if (!fAllTests)
break;
case IDM_TEST3:
dprintf("\n--------------- Test3 ---------------\n");
Test3(hwnd);
dprintf("Done Test3.\n");
if (!fAllTests)
break;
dprintf("Done All Tests.\n");
break;
}
return 0L;
case WM_DESTROY:
/* exit this program */
PostQuitMessage(0);
break;
case WM_PAINT:
/* set up a paint structure, and call AppPaint() */
BeginPaint(hwnd, &ps);
AppPaint(hwnd, ps.hdc);
EndPaint(hwnd, &ps);
return 0;
}
return (LONG)DefWindowProc(hwnd, uMessage, dwParam, lParam);
}
void NEAR PASCAL
Test1(HWND hwnd)
{
HMMIO hmmio;
char achMemFile[100];
MMIOINFO mmioinfo;
HMMIO hmmioMF; // memory file handle
long lBufSize;
int fh;
FARPROC farproc; // Added to make it compile. LKG
dprintf("HelloWorld tests...\n");
/* open "hello.txt" unbuffered -- assume it contains
* "hello world\r\n" (13 bytes) -- and run the TestHelloWorld test
*/
WinEval((hmmio = mmioOpen("hello.txt", NULL, 0)) != NULL);
dprintf("TestHelloWorld() with no buffer\n");
TestHelloWorld(hmmio, 0);
for (lBufSize = 1; lBufSize <= 15; lBufSize++)
{
/* re-run test for various buffer sizes */
WinEval(mmioSetBuffer(hmmio, NULL, lBufSize, 0) == 0);
WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
dprintf("TestHelloWorld() with %ld-byte buffer\n",
lBufSize);
TestHelloWorld(hmmio, lBufSize);
}
/* copy file into a memory block, set up memory block
* as a memory file, and re-run the test
*/
WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
WinEval(mmioRead(hmmio, achMemFile, 13L) == 13L);
memset(&mmioinfo, 0, sizeof(mmioinfo));
mmioinfo.fccIOProc = FOURCC_MEM;
mmioinfo.pchBuffer = achMemFile;
mmioinfo.cchBuffer = 13L;
WinEval((hmmioMF = mmioOpen(NULL, &mmioinfo, 0)) != NULL);
dprintf("TestHelloWorld() with memory file\n");
TestHelloWorld(hmmioMF, 13L);
/* close the open files */
WinEval(mmioClose(hmmio, 0) == 0);
WinEval(mmioClose(hmmioMF, 0) == 0);
/* open file and pass file handle to mmioOpen() */
WinEval((fh = _lopen("hello.txt", READ)) >= 0);
memset(&mmioinfo, 0, sizeof(mmioinfo));
mmioinfo.adwInfo[0] = fh;
WinEval((hmmio = mmioOpen((LPSTR) NULL, &mmioinfo, MMIO_ALLOCBUF))
!= NULL);
dprintf("TestHelloWorld() with file handle passed to mmioOpen()\n");
TestHelloWorld(hmmio, 0);
WinEval(mmioClose(hmmio, 0) == 0);
/* "hello.txt" is stored as an RCDATA resource named "Hello" --
* use this to try out the custom I/O procedure stuff
*/
dprintf("register Win3 RCDATA custom I/O procedure\n");
#define FOURCC_RCD mmioFOURCC('R', 'C', 'D', ' ')
WinEval( (farproc = (FARPROC) RCDIOProc) != NULL );
/* installing it twice should just mean it has to be removed twice */
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_FINDPROC) == NULL);
WinEval(mmioInstallIOProc(FOURCC_RCD, (LPMMIOPROC) farproc,
MMIO_INSTALLPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_FINDPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, (LPMMIOPROC) farproc,
MMIO_INSTALLPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_FINDPROC) == (LPMMIOPROC) farproc);
/* run the test without an I/O buffer */
dprintf("TestHelloWorld() unbuffered, with custom I/O procedure\n");
WinEval((hmmio = mmioOpen("mmiotest.rcd+Hello", NULL, 0)) != NULL); // changed ! to + LKG
TestHelloWorld(hmmio, 0);
WinEval(mmioClose(hmmio, 0) == 0);
/* run the test with a standard-size I/O buffer */
dprintf("TestHelloWorld() buffered, with custom I/O procedure\n");
WinEval((hmmio = mmioOpen("mmiotest.rcd+Hello", NULL, MMIO_ALLOCBUF))
!= NULL);
TestHelloWorld(hmmio, MMIO_DEFAULTBUFFER);
WinEval(mmioClose(hmmio, 0) == 0);
/* remove the custom I/O procedure (it was installed twice above) */
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_FINDPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_REMOVEPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_FINDPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_REMOVEPROC) == (LPMMIOPROC) farproc);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_FINDPROC) == NULL);
WinEval(mmioInstallIOProc(FOURCC_RCD, NULL,
MMIO_REMOVEPROC) == NULL);
/* make sure the I/O procedure got removed */
WinEval(mmioOpen("mmiotest.rcd+Hello", NULL, 0) == NULL);
}
void NEAR PASCAL
TestHelloWorld(HMMIO hmmio, LONG lBufSize)
{
MMIOINFO mmioinfo;
char ach[100];
long lOffset;
static NPSTR szHello = "hello world\r\n"; // contents of file
long lAnswer;
strcpy(ach, "Recognisable garbage!");
/* send the I/O procedure a custom message */
lAnswer = mmioSendMessage(hmmio, MMIOM_ANSWER, 20L, 22L);
dprintf("answer %ld, ", lAnswer);
/* expect to be at offset 0 now */
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0L);
if (lBufSize > 0)
{
/* access buffer directly starting at "hello" */
WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_READ) == 0);
WinEval(lstrncmp(mmioinfo.pchNext, szHello,
min((int) lBufSize, 13)) == 0);
if (lBufSize >= 2)
{
WinAssert((mmioinfo.pchEndWrite - mmioinfo.pchNext)
>= 2);
mmioinfo.pchNext += 2;
}
WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
/* expect to be at offset 2 now */
if (lBufSize >= 2)
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 2L);
/* access buffer directly starting at "world" */
WinEval(mmioSeek(hmmio, 6L, SEEK_SET) == 6L);
WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_READ) == 0);
WinEval(lstrncmp(mmioinfo.pchNext, szHello + 6,
min((int) lBufSize, 13 - 6)) == 0);
WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
/* expect to still be at offset 6 */
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 6L);
}
/* go to offset 2 */
WinEval(mmioSeek(hmmio, 2L, SEEK_SET) == 2L);
/* read "llo" */
strcpy(ach, "Recognisable garbage!");
WinEval(mmioRead(hmmio, ach, 3) == 3);
WinEval(lstrncmp(ach, "llo", 3) == 0);
/* read " wor" */
WinEval(mmioRead(hmmio, ach, 4) == 4);
if (lstrncmp(ach, " wor", 4) != 0)
{ printf("ach = <%s>, expected < wor>", ach);
}
WinEval(lstrncmp(ach, " wor", 4) == 0);
/* expect to be at offset 9 now */
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 9L);
/* read "ld\r\n" -- ask for 7 bytes, but only expect 4 */
WinEval(mmioRead(hmmio, ach, 7) == 4);
WinEval(lstrncmp(ach, "ld\r\n", 4) == 0);
/* expect to be at end of file now */
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 13L);
/* test seeking and reading for each offset in the file */
dprintf("reading from offset");
for (lOffset = 0; lOffset <= 11; lOffset++)
{
dprintf(" %ld", lOffset);
WinEval(mmioSeek(hmmio, lOffset, SEEK_SET) == lOffset);
WinEval(mmioRead(hmmio, ach, 2) == 2);
WinEval(lstrncmp(ach, "hello world\r\n" + lOffset, 2) == 0);
}
dprintf(".\n");
/* check more seeking */
OutputDebugString("SEEK_SET\n");
WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
WinEval(mmioSeek(hmmio, 13L, SEEK_SET) == 13L);
OutputDebugString("SEEK_CUR\n");
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 13L);
WinEval(mmioSeek(hmmio, -2L, SEEK_CUR) == 11L);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 11L);
WinEval(mmioSeek(hmmio, -11L, SEEK_CUR) == 0L);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0L);
OutputDebugString("SEEK_END\n");
WinEval(mmioSeek(hmmio, 11L, SEEK_END) == 2L);
OutputDebugString("SEEK_CUR\n");
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 2L);
/* measure the length of the file */
OutputDebugString("SEEK_END\n");
WinEval(mmioSeek(hmmio, 0L, SEEK_END) == 13L);
} /* TestHelloWorld */
/* 'RCD' I/O Procedure
*
* I/O procedure that will open e.g. "foo.rcd+bar" but it's a con.
* It will chech that what's between the . and + is rcd, it will
* check that bar is in fact "hello" and that foo is "mmiotest"
* It then has a spoof "file" containing "hello world\r\n"
*/
typedef struct _MMIORCDINFO // How RCD IOProc uses MMIO.adwInfo[]
{
int fh; // DOS file handle
long lOffset; // offset of start of resource
long lSize; // size of resource (bytes)
} MMIORCDINFO;
LONG FAR PASCAL
RCDIOProc(
LPSTR lpmmioStr, // I/O status block (cast to LPSTR)
UINT uMsg, // message number
LONG lParam1,
LONG lParam2) // message-specific parameters
{
LPMMIOINFO pmmio = (LPMMIOINFO) lpmmioStr;
MMIORCDINFO FAR *pInfo = (MMIORCDINFO FAR *) pmmio->adwInfo;
LPSTR szFileName = (LPSTR) lParam1;
HANDLE hModule; // handle to module
HANDLE hResInfo; // handle to resource information
LONG lBytesLeft; // bytes left in res. after current pos.
WORD wBytesAsk; // bytes asked to read
WORD wBytes; // bytes actually read
LONG lBytesTotal; // accum. bytes actually read
LPSTR pchPlus; // pointer to '+'
LPSTR pchDot; // pointer to '.rcd'
LONG lNewOffset;
static LPSTR lpData = "hello world\r\n"; // actual data
switch (uMsg)
{
case MMIOM_OPEN:
if (0 != stricmp(szFileName,"mmiotest.rcd+hello"))
return MMIOERR_CANNOTOPEN;
pInfo->lSize = strlen(lpData);
pInfo->lOffset = 0;
pmmio->lDiskOffset = 0L;
return 0L;
case MMIOM_CLOSE:
return 0L;
case MMIOM_READ:
/* lParam2 = number of bytes to read */
/* lParam1 = address to deliver them to */
lBytesLeft = pInfo->lSize - pmmio->lDiskOffset;
if (lParam2 > lBytesLeft)
lParam2 = lBytesLeft;
// memcpy((LPSTR)lParam1, lpData[pmmio->lDiskOffset], lParam2); but it trapped!
{ int i;
for (i=0; i<lParam2; ++i) {
((LPSTR)lParam1)[i] = lpData[pmmio->lDiskOffset++];
}
}
return lParam2;
case MMIOM_WRITE:
/* Windows resources are read-only */
return -1;
case MMIOM_SEEK:
/* calculate <lNewOffset>, the new offset (relative to the
* beginning of the resource)
*/
switch ((int) lParam2)
{
case SEEK_SET:
lNewOffset = lParam1;
break;
case SEEK_CUR:
lNewOffset = pmmio->lDiskOffset + lParam1;
break;
case SEEK_END:
lNewOffset = pInfo->lSize - lParam1;
break;
}
if (lNewOffset<0)
{ dprintf("Seek to before start of rcd");
return -1;
}
if (lNewOffset>pInfo->lSize)
{ dprintf("Seek to after end of rcd");
return -1;
}
pmmio->lDiskOffset = lNewOffset;
return lNewOffset;
case MMIOM_ANSWER:
/* this I/O procedure knows the answer to the universe */
return lParam1 + lParam2;
}
return 0L;
}
void NEAR PASCAL
Test2(
HWND hwnd)
{
dprintf("Test2 using a DOS file...\n");
Test2Helper(FALSE);
dprintf("Test2 using a memory file...\n");
Test2Helper(TRUE);
}
void NEAR PASCAL
Test2Helper(
BOOL fMemFile)
{
HMMIO hmmio;
HPSTR pchCallerData = NULL;
long lBytesToRead;
long lOffset;
long lBufSize;
long lMemFileBufSize;
BOOL fBuffered;
MMIOINFO mmioinfo;
dprintf("creating 540000-byte file\n");
if (fMemFile)
{
/* create a memory file */
memset(&mmioinfo, 0, sizeof(mmioinfo));
mmioinfo.fccIOProc = FOURCC_MEM;
mmioinfo.pchBuffer = NULL;
mmioinfo.cchBuffer = 12344L; // initial size
mmioinfo.adwInfo[0] = 76543L; // grow by this much
WinEval((hmmio = mmioOpen(NULL, &mmioinfo,
MMIO_CREATE | MMIO_READWRITE)) != NULL);
}
else
{
/* open "test2.tmp" for reading and writing */
WinEval((hmmio = mmioOpen("test2.tmp", NULL,
MMIO_CREATE | MMIO_READWRITE | MMIO_ALLOCBUF)) != NULL);
}
/* create a file that's big enough so we do the following reads:
* 40000, 60000, 80000, 100000, 120000, 140000 (sum 540000)
*/
FillBufferedFile(hmmio, 540000L / 4L);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 540000L);
dprintf("create huge a buffer that's not segment boundary aligned\n");
/* we'll read stuff into the buffer at offset 12345, to try out
* reading into the buffer across segment offsets
*/
if ((pchCallerData = GAllocPtr(140000L + 12345L)) == NULL)
{
dprintf("test program problem: can't allocate caller buffer\n");
WinAssert(FALSE);
}
lMemFileBufSize = 540000L;
for (fBuffered = fMemFile; fBuffered <= TRUE; fBuffered++)
{
/* seek back */
dprintf("seek back, do 40000-140000 byte %s reads,"
" and check file contents\n",
(LPSTR) (fBuffered ? "buffered" : "unbuffered"));
WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
/* read the file in varying large and huge reads, and at the
* same time verify that the file was written to correctly
*/
for (lOffset = 0L, lBytesToRead = 40000L, lBufSize = 100000L;
lBytesToRead <= 140000L;
lOffset += lBytesToRead, lBytesToRead += 20000L,
lBufSize -= 10000L)
{
long lLongs;
long huge * pl;
long lOffsetCheck;
MMIOINFO mmioinfo;
if (fMemFile)
{
/* juggle the memory file buffer around, but
* don't truncate the data
*/
if (lMemFileBufSize == 540000L)
lMemFileBufSize = 678901L;
else
lMemFileBufSize = 540000L;
WinEval(mmioSetBuffer(hmmio, NULL,
lMemFileBufSize, 0) == 0);
}
else
if (fBuffered)
{
/* just to be nasty, let's play around with the
* buffer size while all this is going on
*/
WinEval(mmioSetBuffer(hmmio, NULL, lBufSize, 0)
== 0);
WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_READ)
== 0);
WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
}
else
{
/* no buffer */
WinEval(mmioSetBuffer(hmmio, NULL, 0, 0)
== 0);
}
/* read the next <lBytesToRead> */
WinEval(mmioRead(hmmio, pchCallerData + 12345L,
lBytesToRead) == lBytesToRead);
lLongs = lBytesToRead / 4L, pl =
(long huge *) (pchCallerData + 12345L);
lOffsetCheck = lOffset;
while (lLongs-- > 0)
{
WinEval(*pl++ == lOffsetCheck);
lOffsetCheck += 4;
}
}
WinAssert(mmioSeek(hmmio, 0L, SEEK_CUR) == 540000L);
WinAssert(mmioSeek(hmmio, 0L, SEEK_END) == 540000L);
WinEval(mmioRead(hmmio, pchCallerData + 12345L, 17L) == 0L);
}
if (pchCallerData != NULL)
GFreePtr(pchCallerData);
/* close "test2.tmp" */
WinEval(mmioClose(hmmio, 0) == 0);
if (!fMemFile)
{
dprintf("delete the test file using MMIO_DELETE\n");
WinEval(mmioOpen("test2.tmp", NULL, MMIO_DELETE)
== (HANDLE) TRUE);
}
}
void NEAR PASCAL
FillBufferedFile(
HMMIO hmmio,
LONG lLongs)
{
MMIOINFO mmioinfo;
long lOffset = 0;
/* fill buffered file <hmmio> with <lLongs> binary long integers,
* where offset X (such that X % 4 == 0) contains long integer X
*/
/* begin direct access of the I/O buffer */
WinEval(mmioGetInfo(hmmio, &mmioinfo, 0) == 0);
for( ; ; )
{
long lAvail; // bytes available in buffer
lAvail = mmioinfo.pchEndWrite - mmioinfo.pchNext;
for( ; ; )
{
if ((lAvail -= sizeof(lOffset)) < 0)
break;
if (lLongs-- <= 0)
goto EXIT_FUNCTION;
*((long *) mmioinfo.pchNext) = lOffset;
mmioinfo.pchNext = (long)mmioinfo.pchNext + sizeof(long); // bypass compiler bug
lOffset += sizeof(lOffset);
}
/* flush the I/O buffer */
mmioinfo.dwFlags |= MMIO_DIRTY;
WinEval(mmioAdvance(hmmio, &mmioinfo, MMIO_WRITE) == 0);
WinAssert((mmioinfo.pchNext + sizeof(lOffset))
<= mmioinfo.pchEndWrite);
}
EXIT_FUNCTION:
/* end direct access of the I/O buffer */
mmioinfo.dwFlags |= MMIO_DIRTY;
WinEval(mmioSetInfo(hmmio, &mmioinfo, 0) == 0);
/* make sure we're where we think we should be */
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == lOffset);
}
void NEAR PASCAL
Test3(
HWND hwnd)
{
HMMIO hmmio;
DWORD dwFlags;
MMIOINFO mmioinfo;
for (dwFlags = 0; dwFlags <= MMIO_ALLOCBUF; dwFlags += MMIO_ALLOCBUF)
{
WinEval((hmmio = mmioOpen("test3.tmp", NULL,
dwFlags | MMIO_CREATE | MMIO_WRITE)) != NULL);
dprintf("TestRIFF(), %s, MMIO_WRITE: ",
(LPSTR) (dwFlags == 0 ? "unbuffered" : "buffered"));
TestRIFF(hmmio, FALSE);
WinEval(mmioClose(hmmio, 0) == 0);
WinEval((hmmio = mmioOpen("test3.tmp", NULL,
dwFlags | MMIO_CREATE | MMIO_READWRITE)) != NULL);
dprintf("TestRIFF(), %s, MMIO_READWRITE: ",
(LPSTR) (dwFlags == 0 ? "unbuffered" : "buffered"));
TestRIFF(hmmio, TRUE);
WinEval(mmioClose(hmmio, 0) == 0);
}
/* create a memory file */
memset(&mmioinfo, 0, sizeof(mmioinfo));
mmioinfo.fccIOProc = FOURCC_MEM;
mmioinfo.pchBuffer = NULL;
mmioinfo.cchBuffer = 1L; // initial size
mmioinfo.adwInfo[0] = 1L; // grow by this much
WinEval((hmmio = mmioOpen(NULL, &mmioinfo,
MMIO_CREATE | MMIO_READWRITE)) != NULL);
dprintf("TestRIFF() with memory file: ");
TestRIFF(hmmio, TRUE);
WinEval(mmioClose(hmmio, 0) == 0);
dprintf("delete the test file using MMIO_DELETE\n");
WinEval(mmioOpen("test3.tmp", NULL, MMIO_DELETE) == (HANDLE) TRUE);
}
/* Output from TestRIFF():
*
* 00000000 RIFF (0001E32A) 'foo '
* 0000000C abc1 (00000001)
* 00000016 abc2 (00000002)
* 00000020 abc3 (00000003)
* 0000002C abc4 (00000004)
* 00000038 abc5 (00000005)
* 00000046 abc6 (00000006)
* 00000054 abc7 (00000007)
* 00000064 LIST (0000007E) 'data'
* 00000070 num1 (00000001)
* 0000007A num2 (00000002)
* 00000084 num3 (00000003)
* 00000090 num4 (00000004)
* 0000009C num5 (00000005)
* 000000AA num6 (00000006)
* 000000B8 num7 (00000007)
* 000000C8 num8 (00000008)
* 000000D8 num9 (00000009)
* 000000EA xyz (0001E240)
* 0001E332
*/
void NEAR PASCAL
TestRIFF(
HMMIO hmmio,
BOOL fReadable)
{
MMCKINFO ckRIFF;
MMCKINFO ckLIST;
MMCKINFO ck;
HPSTR pchBuf, pchStart;
int huge * pi;
int i;
#define FOURCC_FOO mmioFOURCC('f', 'o', 'o', ' ')
#define FOURCC_ABC mmioFOURCC('a', 'b', 'c', ' ')
#define FOURCC_DATA mmioFOURCC('d', 'a', 't', 'a')
#define FOURCC_NUM mmioFOURCC('n', 'u', 'm', ' ')
#define FOURCC_XYZ mmioFOURCC('x', 'y', 'z', ' ')
dprintf("write file");
/* create 'RIFF' chunk, formtype ' */
ckRIFF.cksize = 0L;
ckRIFF.fccType = FOURCC_FOO;
WinEval(mmioCreateChunk(hmmio, &ckRIFF, MMIO_CREATERIFF) == 0);
/* create chunks 'abc1' ... 'abc7' -- the data for the i-th chunk
* is the first i uppercase letters of the alphabet
*/
for (i = 1; i <= 7; i++)
{
MMCKINFO ck;
ck.ckid = FOURCC_ABC;
((NPSTR) (&ck.ckid))[3] = (CHAR)'0' + (CHAR)i;
ck.cksize = 8 + i;
WinEval(mmioCreateChunk(hmmio, &ck, 0) == 0);
WinEval(mmioWrite(hmmio, "ABCDEFG", (LONG) i) == (LONG) i);
WinEval(mmioAscend(hmmio, &ck, 0) == 0);
}
/* create a LIST chunk with list type 'data' */
ckLIST.cksize = 0L;
ckLIST.fccType = FOURCC_DATA;
WinEval(mmioCreateChunk(hmmio, &ckLIST, MMIO_CREATELIST) == 0);
/* create chunks 'num1' ... 'num9' -- the data for the i-th chunk
* is the first i positive numbers
*/
for (i = 1; i <= 9; i++)
{
ck.ckid = FOURCC_NUM;
((NPSTR) (&ck.ckid))[3] = (CHAR)'0' + (CHAR)i;
ck.cksize = 77; // make medAscend() work for a living
WinEval(mmioCreateChunk(hmmio, &ck, 0) == 0);
WinEval(mmioWrite(hmmio, "123456789", (LONG) i) == (LONG) i);
WinEval(mmioAscend(hmmio, &ck, 0) == 0);
}
/* ascend from the LIST chunk */
WinEval(mmioAscend(hmmio, &ckLIST, 0) == 0);
/* write 'xyz' chunk to contain 123456 bytes that are filled with
* short integers 0 to 123456/2 - 1; make the buffer misaligned
* by 32768 bytes
*/
if ((pchBuf = GAllocPtr(123456L + 32768L)) == NULL)
{
dprintf("test program problem: out of memory\n");
WinAssert(FALSE);
}
pchStart = pchBuf + 32768L;
for (pi = (int huge *) pchStart, i = 0; i < (int) (123456L / sizeof(int)); // (Win32)
pi++, i++)
*pi = i;
ck.ckid = FOURCC_XYZ;
WinEval(mmioCreateChunk(hmmio, &ck, 0) == 0);
WinEval(mmioWrite(hmmio, pchStart, 123456L) == 123456L);
WinEval(mmioAscend(hmmio, &ck, 0) == 0);
/* ascend from the RIFF chunk */
WinEval(mmioAscend(hmmio, &ckRIFF, 0) == 0);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0001E332L);
/* destroy data in <pchStart>, <ck>, etc. to ensure a
* valid test
*/
#ifdef OMIT
lmemset(pchStart, 12, 123456L);
#else
memset(pchStart, 12, 123456L);
#endif //OMIT
memset(&ckRIFF, 34, sizeof(ckRIFF));
memset(&ckLIST, 56, sizeof(ckLIST));
memset(&ck, 78, sizeof(ck));
if (fReadable)
{
dprintf(", read file");
/* seek back */
WinEval(mmioSeek(hmmio, 0L, SEEK_SET) == 0L);
/* descend into RIFF chunk */
WinEval(mmioDescend(hmmio, &ckRIFF, NULL, 0) == 0);
WinAssert(ckRIFF.ckid == FOURCC_RIFF);
WinAssert(ckRIFF.cksize == 0x0001E32AL);
WinAssert(ckRIFF.fccType == FOURCC_FOO);
WinAssert(ckRIFF.dwDataOffset == 0x00000000L + 8L);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0000000CL);
/* find all the 'abc' chunks */
for (i = 1; i <= 7; i++)
{
MMCKINFO ck;
char ach[10];
/* seek back to start of RIFF chunk data */
WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
ck.ckid = FOURCC_ABC;
((NPSTR) (&ck.ckid))[3] = (CHAR)'0' + (CHAR)i;
WinEval(mmioDescend(hmmio, &ck, &ckRIFF,
MMIO_FINDCHUNK) == 0);
WinAssert(ck.cksize == (UINT)i);
WinAssert(ck.fccType == 0);
WinEval(mmioRead(hmmio, ach, (LONG) i) == (LONG) i);
WinEval(lstrncmp(ach, "ABCDEFG", i) == 0);
if (i != 7)
WinEval(mmioAscend(hmmio, &ck, 0) == 0);
}
/* we're down two levels -- ascend to end of RIFF chunk */
WinEval(mmioAscend(hmmio, &ckRIFF, 0) == 0);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0001E332L);
/* seek back to start of RIFF chunk data */
WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
/* make sure we cannot find 'num1' chunk */
ck.ckid = mmioFOURCC('n', 'u', 'm', '1');
WinEval(mmioDescend(hmmio, &ck, &ckRIFF, MMIO_FINDCHUNK)
== MMIOERR_CHUNKNOTFOUND);
/* seek back to start of RIFF chunk data */
WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
/* make sure we can find 'data' list */
ckLIST.fccType = FOURCC_DATA;
WinEval(mmioDescend(hmmio, &ckLIST, &ckRIFF, MMIO_FINDLIST)
== 0);
WinAssert(ckLIST.ckid == FOURCC_LIST);
WinAssert(ckLIST.fccType == FOURCC_DATA);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x00000064L + 12L);
/* descend into each of the 'num' chunks */
for (i = 1; i <= 9; i++)
{
FOURCC fcc;
MMCKINFO ck;
char ach[10];
fcc = FOURCC_ABC;
((NPSTR) (&fcc))[3] = (CHAR)'0' + (CHAR)i;
WinEval(mmioDescend(hmmio, &ck, &ckLIST, 0) == 0);
WinAssert(ck.cksize == (UINT)i);
WinAssert(ck.fccType == 0);
WinEval(mmioRead(hmmio, ach, (LONG) i) == (LONG) i);
WinEval(lstrncmp(ach, "123456789", i) == 0);
WinEval(mmioAscend(hmmio, &ck, 0) == 0);
}
/* make sure we cannot go any further */
WinEval(mmioDescend(hmmio, &ck, &ckLIST, 0)
== MMIOERR_CHUNKNOTFOUND);
/* seek back to start of RIFF chunk data */
WinEval(mmioSeek(hmmio, 12L, SEEK_SET) == 12L);
/* seek to the 'xyz' chunk */
ck.ckid = FOURCC_XYZ;
WinEval(mmioDescend(hmmio, &ck, &ckRIFF, MMIO_FINDCHUNK) == 0);
WinAssert(ck.ckid == FOURCC_XYZ);
WinAssert(ck.fccType == 0);
WinEval(mmioRead(hmmio, pchStart, 123456L) == 123456L);
WinEval(mmioAscend(hmmio, &ck, 0) == 0);
/* ascend from the RIFF chunk */
WinEval(mmioAscend(hmmio, &ckRIFF, 0) == 0);
WinEval(mmioSeek(hmmio, 0L, SEEK_CUR) == 0x0001E332L);
/* check the contents of the 'xyz' chunk */
for (pi = (int huge *) pchStart, i = 0; i < (int) (123456L / sizeof(int)); // (Win32)
pi++, i++)
{
WinAssert(*pi == i);
}
}
GFreePtr(pchBuf);
dprintf(", done.\n");
}
/* sz = lstrrchr(szSrc, ch)
*
* Find the last occurence <sz> (NULL if not found) of <p ch> in <p szSrc>.
*/
LPSTR NEAR PASCAL
lstrrchr(
LPSTR szSrc,
char ch)
{
LPSTR szLast = NULL;
do
{
if (*szSrc == ch)
szLast = szSrc;
} while (*szSrc++ != 0);
return szLast;
}
#ifdef OMIT
/* lmemset(pDst, bSrc, cDst)
*
* Set all <cDest> bytes in memory block <pDst> to a byte value <bSrc>.
*/
void NEAR PASCAL
lmemset(
void far *pDst,
BYTE bSrc,
long cDst)
{
while (cDst-- > 0)
*((BYTE huge *) pDst)++ = bSrc;
}
#endif //OMIT