ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

mmio.c
Go to the documentation of this file.
00001 /*
00002  * MMIO functions
00003  *
00004  * Copyright 1998 Andrew Taylor
00005  * Copyright 1998 Ove Kåven
00006  * Copyright 2000,2002 Eric Pouech
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 /* Still to be done:
00024  *  + correct handling of global/local IOProcs (and temporary IOProcs)
00025  *  + mode of mmio objects is not used (read vs write vs readwrite)
00026  *  + thread safeness
00027  *      + 32 A <=> W message mapping
00028  */
00029 
00030 
00031 #include <ctype.h>
00032 #include <stdarg.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <assert.h>
00037 
00038 #include "windef.h"
00039 #include "winbase.h"
00040 #include "winnls.h"
00041 #include "mmsystem.h"
00042 #include "winemm.h"
00043 
00044 #include "wine/debug.h"
00045 
00046 WINE_DEFAULT_DEBUG_CHANNEL(mmio);
00047 
00048 static WINE_MMIO *MMIOList;
00049 
00050 /**************************************************************************
00051  *                  mmioDosIOProc                   [internal]
00052  */
00053 static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage,
00054                       LPARAM lParam1, LPARAM lParam2)
00055 {
00056     LRESULT ret = MMSYSERR_NOERROR;
00057 
00058     TRACE("(%p, %X, 0x%lx, 0x%lx);\n", lpmmioinfo, uMessage, lParam1, lParam2);
00059 
00060     switch (uMessage) {
00061     case MMIOM_OPEN:
00062     {
00063         /* Parameters:
00064          * lParam1 = szFileName parameter from mmioOpen
00065          * lParam2 = reserved
00066          * Returns: zero on success, error code on error
00067          * NOTE: lDiskOffset automatically set to zero
00068          */
00069         LPCSTR      szFileName = (LPCSTR)lParam1;
00070 
00071         if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
00072         FIXME("MMIO_GETTEMP not implemented\n");
00073         return MMIOERR_CANNOTOPEN;
00074         }
00075 
00076         /* if filename NULL, assume open file handle in adwInfo[0] */
00077         if (szFileName) {
00078                 OFSTRUCT    ofs;
00079                 lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags & 0xFFFF);
00080             }
00081         if (lpmmioinfo->adwInfo[0] == (DWORD)HFILE_ERROR)
00082         ret = MMIOERR_CANNOTOPEN;
00083     }
00084     break;
00085 
00086     case MMIOM_CLOSE:
00087     /* Parameters:
00088      * lParam1 = wFlags parameter from mmioClose
00089      * lParam2 = unused
00090      * Returns: zero on success, error code on error
00091      */
00092     if (!(lParam1 & MMIO_FHOPEN))
00093         _lclose((HFILE)lpmmioinfo->adwInfo[0]);
00094     break;
00095 
00096     case MMIOM_READ:
00097     /* Parameters:
00098      * lParam1 = huge pointer to read buffer
00099      * lParam2 = number of bytes to read
00100      * Returns: number of bytes read, 0 for EOF, -1 for error (error code
00101      *     in wErrorRet)
00102      */
00103     ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
00104     if (ret != -1)
00105         lpmmioinfo->lDiskOffset += ret;
00106 
00107     break;
00108 
00109     case MMIOM_WRITE:
00110     case MMIOM_WRITEFLUSH:
00111     /* no internal buffering, so WRITEFLUSH handled same as WRITE */
00112 
00113     /* Parameters:
00114      * lParam1 = huge pointer to write buffer
00115      * lParam2 = number of bytes to write
00116      * Returns: number of bytes written, -1 for error (error code in
00117      *      wErrorRet)
00118      */
00119     ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
00120     if (ret != -1)
00121         lpmmioinfo->lDiskOffset += ret;
00122     break;
00123 
00124     case MMIOM_SEEK:
00125     /* Parameters:
00126      * lParam1 = new position
00127      * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
00128      * Returns: new file postion, -1 on error
00129      */
00130     ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2);
00131     if (ret != -1)
00132         lpmmioinfo->lDiskOffset = ret;
00133     return ret;
00134 
00135     case MMIOM_RENAME:
00136     /* Parameters:
00137      * lParam1 = old name
00138      * lParam2 = new name
00139      * Returns: zero on success, non-zero on failure
00140      */
00141      if (!MoveFileA((const char*)lParam1, (const char*)lParam2))
00142          ret = MMIOERR_FILENOTFOUND;
00143      break;
00144 
00145     default:
00146     FIXME("unexpected message %u\n", uMessage);
00147     return 0;
00148     }
00149 
00150     return ret;
00151 }
00152 
00153 /**************************************************************************
00154  *                  mmioMemIOProc                   [internal]
00155  */
00156 static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage,
00157                       LPARAM lParam1, LPARAM lParam2)
00158 {
00159     TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2);
00160 
00161     switch (uMessage) {
00162 
00163     case MMIOM_OPEN:
00164     /* Parameters:
00165      * lParam1 = filename (must be NULL)
00166      * lParam2 = reserved
00167      * Returns: zero on success, error code on error
00168      * NOTE: lDiskOffset automatically set to zero
00169      */
00170     /* FIXME: io proc shouldn't change it */
00171     if (!(lpmmioinfo->dwFlags & MMIO_CREATE))
00172         lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite;
00173         lpmmioinfo->adwInfo[0] = HFILE_ERROR;
00174     return 0;
00175 
00176     case MMIOM_CLOSE:
00177     /* Parameters:
00178      * lParam1 = wFlags parameter from mmioClose
00179      * lParam2 = unused
00180      * Returns: zero on success, error code on error
00181      */
00182     return 0;
00183 
00184     case MMIOM_READ:
00185     /* Parameters:
00186      * lParam1 = huge pointer to read buffer
00187      * lParam2 = number of bytes to read
00188      * Returns: number of bytes read, 0 for EOF, -1 for error (error code
00189      *     in wErrorRet)
00190      * NOTE: lDiskOffset should be updated
00191      */
00192     FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
00193     return 0;
00194 
00195     case MMIOM_WRITE:
00196     case MMIOM_WRITEFLUSH:
00197     /* no internal buffering, so WRITEFLUSH handled same as WRITE */
00198 
00199     /* Parameters:
00200      * lParam1 = huge pointer to write buffer
00201      * lParam2 = number of bytes to write
00202      * Returns: number of bytes written, -1 for error (error code in
00203      *      wErrorRet)
00204      * NOTE: lDiskOffset should be updated
00205      */
00206     FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
00207     return 0;
00208 
00209     case MMIOM_SEEK:
00210     /* Parameters:
00211      * lParam1 = new position
00212      * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
00213      * Returns: new file postion, -1 on error
00214      * NOTE: lDiskOffset should be updated
00215      */
00216     FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
00217     return -1;
00218 
00219     default:
00220     FIXME("unexpected message %u\n", uMessage);
00221     return 0;
00222     }
00223 }
00224 
00225 /* This array will be the entire list for most apps 
00226  * Note that temporary ioProcs will be stored with a 0 fourCC code
00227  */
00228 
00229 static struct IOProcList defaultProcs[] = {
00230     {&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, FALSE, 0},
00231     {NULL,             FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, FALSE, 0},
00232 };
00233 
00234 static struct IOProcList*   pIOProcListAnchor = &defaultProcs[0];
00235 
00236 /****************************************************************
00237  *          MMIO_FindProcNode           [INTERNAL]
00238  *
00239  * Finds the ProcList node associated with a given FOURCC code.
00240  */
00241 static struct IOProcList*   MMIO_FindProcNode(FOURCC fccIOProc)
00242 {
00243     struct IOProcList*  pListNode;
00244 
00245     for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) {
00246     if (pListNode->fourCC == fccIOProc) {
00247         return pListNode;
00248     }
00249     }
00250     return NULL;
00251 }
00252 
00253 /****************************************************************
00254  *          MMIO_InstallIOProc          [INTERNAL]
00255  */
00256 static LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc,
00257                                      DWORD dwFlags, BOOL is_unicode)
00258 {
00259     LPMMIOPROC          lpProc = NULL;
00260     struct IOProcList*  pListNode;
00261     struct IOProcList** ppListNode;
00262 
00263     TRACE("(%08x, %p, %08X, %s)\n", fccIOProc, pIOProc, dwFlags, is_unicode ? "unicode" : "ansi");
00264 
00265     if (dwFlags & MMIO_GLOBALPROC)
00266     FIXME("Global procedures not implemented\n");
00267 
00268     /* just handle the known procedures for now */
00269     switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
00270     case MMIO_INSTALLPROC:
00271     /* Create new entry for the IOProc list */
00272     pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode));
00273     if (pListNode) {
00274         /* Fill in this node */
00275         pListNode->fourCC = fccIOProc;
00276         pListNode->pIOProc = pIOProc;
00277         pListNode->is_unicode = is_unicode;
00278         pListNode->count = 0;
00279 
00280         /* Stick it on the end of the list */
00281         pListNode->pNext = pIOProcListAnchor;
00282         pIOProcListAnchor = pListNode;
00283 
00284         /* Return this IOProc - that's how the caller knows we succeeded */
00285         lpProc = pIOProc;
00286     }
00287     break;
00288 
00289     case MMIO_REMOVEPROC:
00290     /*
00291      * Search for the node that we're trying to remove
00292          * We search for a matching fourCC code if it's non null, or the proc
00293          * address otherwise
00294          * note that this method won't find the first item on the list, but
00295      * since the first two items on this list are ones we won't
00296      * let the user delete anyway, that's okay
00297      */
00298     ppListNode = &pIOProcListAnchor;
00299     while ((*ppListNode) && 
00300                ((fccIOProc != 0) ? 
00301                 (*ppListNode)->fourCC != fccIOProc : 
00302                 (*ppListNode)->pIOProc != pIOProc))
00303         ppListNode = &((*ppListNode)->pNext);
00304 
00305     if (*ppListNode) { /* found it */
00306         /* FIXME: what should be done if an open mmio object uses this proc ?
00307          * shall we return an error, nuke the mmio object ?
00308          */
00309         if ((*ppListNode)->count) {
00310         ERR("Cannot remove a mmIOProc while in use\n");
00311         break;
00312         }
00313         /* remove it, but only if it isn't builtin */
00314         if ((*ppListNode) >= defaultProcs &&
00315         (*ppListNode) < defaultProcs + sizeof(defaultProcs) / sizeof(defaultProcs[0])) {
00316         WARN("Tried to remove built-in mmio proc. Skipping\n");
00317         } else {
00318         /* Okay, nuke it */
00319         struct IOProcList*  ptmpNode = *ppListNode;
00320         lpProc = (*ppListNode)->pIOProc;
00321         *ppListNode = (*ppListNode)->pNext;
00322         HeapFree(GetProcessHeap(), 0, ptmpNode);
00323         }
00324     }
00325     break;
00326 
00327     case MMIO_FINDPROC:
00328     if ((pListNode = MMIO_FindProcNode(fccIOProc))) {
00329         lpProc = pListNode->pIOProc;
00330     }
00331     break;
00332     }
00333 
00334     return lpProc;
00335 }
00336 
00337 /****************************************************************
00338  *          send_message                [INTERNAL]
00339  */
00340 static LRESULT  send_message(struct IOProcList* ioProc, LPMMIOINFO mmioinfo,
00341                              DWORD wMsg, LPARAM lParam1,
00342                              LPARAM lParam2, BOOL is_unicode)
00343 {
00344     LRESULT         result = MMSYSERR_ERROR;
00345     LPARAM      lp1 = lParam1, lp2 = lParam2;
00346 
00347     if (!ioProc) {
00348     ERR("ioProc NULL\n");
00349     return MMSYSERR_INVALPARAM;
00350     }
00351 
00352     if (ioProc->is_unicode != is_unicode) {
00353         /* map (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */
00354         FIXME("NIY 32 A<=>W mapping\n");
00355     }
00356     result = (ioProc->pIOProc)((LPSTR)mmioinfo, wMsg, lp1, lp2);
00357 
00358 #if 0
00359     if (ioProc->is_unicode != is_unicode) {
00360         /* unmap (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */
00361     }
00362 #endif
00363 
00364     return result;
00365 }
00366 
00367 /**************************************************************************
00368  *                  MMIO_ParseExtA              [internal]
00369  *
00370  * Parses a filename for the extension.
00371  *
00372  * RETURNS
00373  *  The FOURCC code for the extension if found, else 0.
00374  */
00375 static FOURCC MMIO_ParseExtA(LPCSTR szFileName)
00376 {
00377     /* Filenames are of the form file.ext{+ABC}
00378        For now, we take the last '+' if present */
00379 
00380     FOURCC ret = 0;
00381 
00382     /* Note that ext{Start,End} point to the . and + respectively */
00383     LPSTR extEnd;
00384     LPSTR extStart;
00385 
00386     TRACE("(%s)\n", debugstr_a(szFileName));
00387 
00388     if (!szFileName)
00389     return ret;
00390 
00391     /* Find the last '.' */
00392     extStart = strrchr(szFileName,'.');
00393 
00394     if (!extStart) {
00395          ERR("No . in szFileName: %s\n", debugstr_a(szFileName));
00396     } else {
00397         CHAR ext[5];
00398 
00399         /* Find the '+' afterwards */
00400         extEnd = strchr(extStart,'+');
00401         if (extEnd) {
00402 
00403             if (extEnd - extStart - 1 > 4)
00404                 WARN("Extension length > 4\n");
00405             lstrcpynA(ext, extStart + 1, min(extEnd-extStart,5));
00406 
00407         } else {
00408             /* No + so just an extension */
00409             if (strlen(extStart) > 4) {
00410                 WARN("Extension length > 4\n");
00411             }
00412             lstrcpynA(ext, extStart + 1, 5);
00413         }
00414         TRACE("Got extension: %s\n", debugstr_a(ext));
00415 
00416         /* FOURCC codes identifying file-extensions must be uppercase */
00417         ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER);
00418     }
00419     return ret;
00420 }
00421 
00422 /**************************************************************************
00423  *              MMIO_Get            [internal]
00424  *
00425  * Retrieves the mmio object from current process
00426  */
00427 static LPWINE_MMIO      MMIO_Get(HMMIO h)
00428 {
00429     LPWINE_MMIO     wm = NULL;
00430 
00431     EnterCriticalSection(&WINMM_cs);
00432     for (wm = MMIOList; wm; wm = wm->lpNext) {
00433     if (wm->info.hmmio == h)
00434         break;
00435     }
00436     LeaveCriticalSection(&WINMM_cs);
00437     return wm;
00438 }
00439 
00440 /**************************************************************************
00441  *              MMIO_Create         [internal]
00442  *
00443  * Creates an internal representation for a mmio instance
00444  */
00445 static  LPWINE_MMIO     MMIO_Create(void)
00446 {
00447     static  WORD    MMIO_counter = 0;
00448     LPWINE_MMIO     wm;
00449 
00450     wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO));
00451     if (wm) {
00452     EnterCriticalSection(&WINMM_cs);
00453         /* lookup next unallocated WORD handle, with a non NULL value */
00454     while (++MMIO_counter == 0 || MMIO_Get((HMMIO)(ULONG_PTR)MMIO_counter));
00455     wm->info.hmmio = (HMMIO)(ULONG_PTR)MMIO_counter;
00456     wm->lpNext = MMIOList;
00457     MMIOList = wm;
00458     LeaveCriticalSection(&WINMM_cs);
00459     }
00460     return wm;
00461 }
00462 
00463 /**************************************************************************
00464  *              MMIO_Destroy            [internal]
00465  *-
00466  * Destroys an internal representation for a mmio instance
00467  */
00468 static  BOOL        MMIO_Destroy(LPWINE_MMIO wm)
00469 {
00470     LPWINE_MMIO*    m;
00471 
00472     EnterCriticalSection(&WINMM_cs);
00473     /* search for the matching one... */
00474     m = &MMIOList;
00475     while (*m && *m != wm) m = &(*m)->lpNext;
00476     /* ...and destroy */
00477     if (*m) {
00478     *m = (*m)->lpNext;
00479     HeapFree(GetProcessHeap(), 0, wm);
00480     wm = NULL;
00481     }
00482     LeaveCriticalSection(&WINMM_cs);
00483     return wm ? FALSE : TRUE;
00484 }
00485 
00486 /****************************************************************
00487  *              MMIO_Flush          [INTERNAL]
00488  */
00489 static  MMRESULT MMIO_Flush(WINE_MMIO* wm, UINT uFlags)
00490 {
00491     if (wm->info.cchBuffer && (wm->info.fccIOProc != FOURCC_MEM)) {
00492     /* not quite sure what to do here, but I'll guess */
00493     if (wm->info.dwFlags & MMIO_DIRTY) {
00494             /* FIXME: error handling */
00495         send_message(wm->ioProc, &wm->info, MMIOM_SEEK, wm->info.lBufOffset, SEEK_SET, FALSE);
00496         send_message(wm->ioProc, &wm->info, MMIOM_WRITE,
00497                          (LPARAM)wm->info.pchBuffer,
00498                          wm->info.pchNext - wm->info.pchBuffer, FALSE);
00499     }
00500     if (uFlags & MMIO_EMPTYBUF)
00501         wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer;
00502     }
00503     wm->info.dwFlags &= ~MMIO_DIRTY;
00504 
00505     return MMSYSERR_NOERROR;
00506 }
00507 
00508 /***************************************************************************
00509  *              MMIO_GrabNextBuffer         [INTERNAL]
00510  */
00511 static LONG MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read)
00512 {
00513     LONG    size = wm->info.cchBuffer;
00514 
00515     TRACE("bo=%x do=%x of=%lx\n",
00516       wm->info.lBufOffset, wm->info.lDiskOffset,
00517       send_message(wm->ioProc, &wm->info, MMIOM_SEEK, 0, SEEK_CUR, FALSE));
00518 
00519     wm->info.lBufOffset = wm->info.lDiskOffset;
00520     wm->info.pchNext = wm->info.pchBuffer;
00521     wm->info.pchEndRead = wm->info.pchBuffer;
00522     wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer;
00523 
00524     wm->bBufferLoaded = TRUE;
00525     if (for_read) {
00526     size = send_message(wm->ioProc, &wm->info, MMIOM_READ,
00527                             (LPARAM)wm->info.pchBuffer, size, FALSE);
00528     if (size > 0)
00529         wm->info.pchEndRead += size;
00530         else
00531             wm->bBufferLoaded = FALSE;
00532     }
00533 
00534     return size;
00535 }
00536 
00537 /***************************************************************************
00538  *              MMIO_SetBuffer              [INTERNAL]
00539  */
00540 static MMRESULT MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer,
00541                    UINT uFlags)
00542 {
00543     TRACE("(%p %p %d %u)\n", wm, pchBuffer, cchBuffer, uFlags);
00544 
00545     if (cchBuffer > 0xFFFF)
00546     WARN("Untested handling of huge mmio buffers (%d >= 64k)\n", cchBuffer);
00547 
00548     if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
00549     return MMIOERR_CANNOTWRITE;
00550 
00551     /* free previous buffer if allocated */
00552     if (wm->info.dwFlags & MMIO_ALLOCBUF) {
00553         HeapFree(GetProcessHeap(), 0, wm->info.pchBuffer);
00554         wm->info.pchBuffer = NULL;
00555     wm->info.dwFlags &= ~MMIO_ALLOCBUF;
00556     }
00557 
00558     if (pchBuffer) {
00559         wm->info.pchBuffer = pchBuffer;
00560     } else if (cchBuffer) {
00561     if (!(wm->info.pchBuffer = HeapAlloc(GetProcessHeap(), 0, cchBuffer)))
00562         return MMIOERR_OUTOFMEMORY;
00563     wm->info.dwFlags |= MMIO_ALLOCBUF;
00564     } else {
00565     wm->info.pchBuffer = NULL;
00566     }
00567 
00568     wm->info.cchBuffer = cchBuffer;
00569     wm->info.pchNext = wm->info.pchBuffer;
00570     wm->info.pchEndRead = wm->info.pchBuffer;
00571     wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer;
00572     wm->info.lBufOffset = wm->info.lDiskOffset;
00573     wm->bBufferLoaded = FALSE;
00574 
00575     return MMSYSERR_NOERROR;
00576 }
00577 
00578 /**************************************************************************
00579  *          MMIO_Open                   [internal]
00580  */
00581 static HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, DWORD dwOpenFlags, BOOL is_unicode)
00582 {
00583     LPWINE_MMIO     wm;
00584     MMIOINFO        mmioinfo;
00585 
00586     TRACE("('%s', %p, %08X, %s);\n", szFileName, refmminfo, dwOpenFlags, is_unicode ? "unicode" : "ansi");
00587 
00588     if (!refmminfo) {
00589         refmminfo = &mmioinfo;
00590 
00591     mmioinfo.fccIOProc = 0;
00592     mmioinfo.pIOProc = NULL;
00593     mmioinfo.pchBuffer = NULL;
00594     mmioinfo.cchBuffer = 0;
00595         is_unicode = FALSE;
00596     }
00597 
00598     if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) {
00599     char    buffer[MAX_PATH];
00600 
00601     if (!szFileName)
00602         return (HMMIO)FALSE;
00603     if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer))
00604         return (HMMIO)FALSE;
00605     if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES))
00606         return (HMMIO)FALSE;
00607     strcpy(szFileName, buffer);
00608     return (HMMIO)TRUE;
00609     }
00610 
00611     if ((wm = MMIO_Create()) == NULL)
00612     return 0;
00613 
00614     /* If both params are NULL, then parse the file name if available */
00615     if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) {
00616     wm->info.fccIOProc = MMIO_ParseExtA(szFileName);
00617     /* Handle any unhandled/error case. Assume DOS file */
00618     if (wm->info.fccIOProc == 0)
00619         wm->info.fccIOProc = FOURCC_DOS;
00620     if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) {
00621         /* If not found, retry with FOURCC_DOS */
00622         wm->info.fccIOProc = FOURCC_DOS;
00623         if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc)))
00624         goto error2;
00625     }
00626     wm->bTmpIOProc = FALSE;
00627     }
00628     /* if just the four character code is present, look up IO proc */
00629     else if (refmminfo->pIOProc == NULL) {
00630     wm->info.fccIOProc = refmminfo->fccIOProc;
00631     if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
00632     wm->bTmpIOProc = FALSE;
00633     }
00634     /* if IO proc specified, use it and specified four character code */
00635     else {
00636     wm->info.fccIOProc = refmminfo->fccIOProc;
00637     MMIO_InstallIOProc(wm->info.fccIOProc, refmminfo->pIOProc,
00638                            MMIO_INSTALLPROC, is_unicode);
00639     if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
00640     assert(wm->ioProc->pIOProc == refmminfo->pIOProc);
00641     wm->bTmpIOProc = TRUE;
00642     }
00643 
00644     wm->ioProc->count++;
00645     wm->info.dwFlags = dwOpenFlags;
00646 
00647     if (dwOpenFlags & MMIO_ALLOCBUF) {
00648     refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer,
00649         refmminfo->cchBuffer ? refmminfo->cchBuffer : MMIO_DEFAULTBUFFER, 0);
00650     if (refmminfo->wErrorRet != MMSYSERR_NOERROR)
00651         goto error1;
00652     } else {
00653         refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer, refmminfo->cchBuffer, 0);
00654     if (refmminfo->wErrorRet != MMSYSERR_NOERROR)
00655         goto error1;
00656     }
00657 
00658     if (wm->info.fccIOProc == FOURCC_MEM && !(wm->info.dwFlags & MMIO_ALLOCBUF))
00659         wm->bBufferLoaded = TRUE;
00660 
00661     /* see mmioDosIOProc for that one */
00662     wm->info.adwInfo[0] = refmminfo->adwInfo[0];
00663 
00664     /* call IO proc to actually open file */
00665     refmminfo->wErrorRet = send_message(wm->ioProc, &wm->info, MMIOM_OPEN,
00666                                         (LPARAM)szFileName, 0, FALSE);
00667 
00668     /* grab file size, when possible (FIXME: not 64 bit safe) */
00669     wm->dwFileSize = GetFileSize((HANDLE)(ULONG_PTR)wm->info.adwInfo[0], NULL);
00670 
00671     if (refmminfo->wErrorRet == 0)
00672     return wm->info.hmmio;
00673  error1:
00674     if (wm->ioProc) wm->ioProc->count--;
00675  error2:
00676     MMIO_Destroy(wm);
00677     return 0;
00678 }
00679 
00680 /**************************************************************************
00681  *              mmioOpenW               [WINMM.@]
00682  */
00683 HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo,
00684                DWORD dwOpenFlags)
00685 {
00686     HMMIO   ret;
00687     LPSTR   szFn = NULL;
00688 
00689     if (szFileName)
00690     {
00691         INT     len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL );
00692         szFn = HeapAlloc( GetProcessHeap(), 0, len );
00693         if (!szFn) return NULL;
00694         WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL );
00695     }
00696 
00697     ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, TRUE);
00698 
00699     HeapFree(GetProcessHeap(), 0, szFn);
00700     return ret;
00701 }
00702 
00703 /**************************************************************************
00704  *              mmioOpenA               [WINMM.@]
00705  */
00706 HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo,
00707                DWORD dwOpenFlags)
00708 {
00709     return  MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, FALSE);
00710 }
00711 
00712 /**************************************************************************
00713  *              mmioClose           [WINMM.@]
00714  */
00715 MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
00716 {
00717     LPWINE_MMIO wm;
00718     MMRESULT    result;
00719 
00720     TRACE("(%p, %04X);\n", hmmio, uFlags);
00721 
00722     if ((wm = MMIO_Get(hmmio)) == NULL)
00723     return MMSYSERR_INVALHANDLE;
00724 
00725     if ((result = MMIO_Flush(wm, 0)) != MMSYSERR_NOERROR)
00726     return result;
00727 
00728     result = send_message(wm->ioProc, &wm->info, MMIOM_CLOSE, uFlags, 0, FALSE);
00729 
00730     MMIO_SetBuffer(wm, NULL, 0, 0);
00731 
00732     wm->ioProc->count--;
00733 
00734     if (wm->bTmpIOProc)
00735     MMIO_InstallIOProc(wm->info.fccIOProc, wm->ioProc->pIOProc,
00736                            MMIO_REMOVEPROC, wm->ioProc->is_unicode);
00737 
00738     MMIO_Destroy(wm);
00739 
00740     return result;
00741 }
00742 
00743 /**************************************************************************
00744  *              mmioRead            [WINMM.@]
00745  */
00746 LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
00747 {
00748     LPWINE_MMIO wm;
00749     LONG    count;
00750 
00751     TRACE("(%p, %p, %d);\n", hmmio, pch, cch);
00752 
00753     if ((wm = MMIO_Get(hmmio)) == NULL)
00754     return -1;
00755 
00756     /* unbuffered case first */
00757     if (!wm->info.pchBuffer)
00758     return send_message(wm->ioProc, &wm->info, MMIOM_READ, (LPARAM)pch, cch, FALSE);
00759 
00760     /* first try from current buffer */
00761     if (wm->info.pchNext != wm->info.pchEndRead) {
00762     count = wm->info.pchEndRead - wm->info.pchNext;
00763     if (count > cch || count < 0) count = cch;
00764     memcpy(pch, wm->info.pchNext, count);
00765     wm->info.pchNext += count;
00766     pch += count;
00767     cch -= count;
00768     } else
00769     count = 0;
00770 
00771     if (cch && (wm->info.fccIOProc != FOURCC_MEM)) {
00772     assert(wm->info.cchBuffer);
00773 
00774     while (cch) {
00775         LONG size;
00776 
00777         size = MMIO_GrabNextBuffer(wm, TRUE);
00778         if (size <= 0) break;
00779         if (size > cch) size = cch;
00780         memcpy(pch, wm->info.pchBuffer, size);
00781         wm->info.pchNext += size;
00782         pch += size;
00783         cch -= size;
00784         count += size;
00785     }
00786     }
00787 
00788     TRACE("count=%d\n", count);
00789     return count;
00790 }
00791 
00792 /**************************************************************************
00793  *              mmioWrite           [WINMM.@]
00794  */
00795 LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
00796 {
00797     LPWINE_MMIO wm;
00798     LONG    count;
00799 
00800     TRACE("(%p, %p, %d);\n", hmmio, pch, cch);
00801 
00802     if ((wm = MMIO_Get(hmmio)) == NULL)
00803     return -1;
00804 
00805     if (wm->info.cchBuffer) {
00806     LONG    bytesW = 0;
00807 
00808         count = 0;
00809         while (cch) {
00810             if (wm->info.pchNext != wm->info.pchEndWrite) {
00811                 count = wm->info.pchEndWrite - wm->info.pchNext;
00812                 if (count > cch || count < 0) count = cch;
00813                 memcpy(wm->info.pchNext, pch, count);
00814                 wm->info.pchNext += count;
00815                 pch += count;
00816                 cch -= count;
00817                 bytesW += count;
00818                 wm->info.dwFlags |= MMIO_DIRTY;
00819         } else {
00820                 if (wm->info.fccIOProc == FOURCC_MEM) {
00821                     if (wm->info.adwInfo[0]) {
00822                         /* from where would we get the memory handle? */
00823                         FIXME("memory file expansion not implemented!\n");
00824                         break;
00825             } else break;
00826                 }
00827             }
00828 
00829             if (wm->info.pchNext == wm->info.pchEndWrite)
00830             {
00831                 MMIO_Flush(wm, MMIO_EMPTYBUF);
00832                 MMIO_GrabNextBuffer(wm, FALSE);
00833             }
00834             else break;
00835         }
00836     count = bytesW;
00837     } else {
00838     count = send_message(wm->ioProc, &wm->info, MMIOM_WRITE, (LPARAM)pch, cch, FALSE);
00839     wm->info.lBufOffset = wm->info.lDiskOffset;
00840     }
00841 
00842     TRACE("bytes written=%d\n", count);
00843     return count;
00844 }
00845 
00846 /**************************************************************************
00847  *              mmioSeek        [WINMM.@]
00848  */
00849 LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
00850 {
00851     LPWINE_MMIO wm;
00852     LONG    offset;
00853 
00854     TRACE("(%p, %08X, %d);\n", hmmio, lOffset, iOrigin);
00855 
00856     if ((wm = MMIO_Get(hmmio)) == NULL)
00857     return MMSYSERR_INVALHANDLE;
00858 
00859     /* not buffered, direct seek on file */
00860     if (!wm->info.pchBuffer)
00861     return send_message(wm->ioProc, &wm->info, MMIOM_SEEK, lOffset, iOrigin, FALSE);
00862 
00863     switch (iOrigin) {
00864     case SEEK_SET:
00865     offset = lOffset;
00866     break;
00867     case SEEK_CUR:
00868     offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset;
00869     break;
00870     case SEEK_END:
00871     offset = ((wm->info.fccIOProc == FOURCC_MEM)? wm->info.cchBuffer : wm->dwFileSize) - lOffset;
00872     break;
00873     default:
00874     return -1;
00875     }
00876 
00877     if (offset && offset >= wm->dwFileSize && wm->info.fccIOProc != FOURCC_MEM) {
00878         /* should check that write mode exists */
00879         if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
00880             return -1;
00881         wm->info.lBufOffset = offset;
00882         wm->info.pchEndRead = wm->info.pchBuffer;
00883         wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer;
00884         if ((wm->info.dwFlags & MMIO_RWMODE) == MMIO_READ) {
00885             wm->info.lDiskOffset = wm->dwFileSize;
00886         }
00887     } else if ((wm->info.cchBuffer > 0) &&
00888     ((offset < wm->info.lBufOffset) ||
00889      (offset >= wm->info.lBufOffset + wm->info.cchBuffer) ||
00890      !wm->bBufferLoaded)) {
00891         /* stay in same buffer ? */
00892         /* some memory mapped buffers are defined with -1 as a size */
00893 
00894     /* condition to change buffer */
00895     if ((wm->info.fccIOProc == FOURCC_MEM) ||
00896         MMIO_Flush(wm, 0) != MMSYSERR_NOERROR ||
00897         /* this also sets the wm->info.lDiskOffset field */
00898         send_message(wm->ioProc, &wm->info, MMIOM_SEEK,
00899                          (offset / wm->info.cchBuffer) * wm->info.cchBuffer,
00900                          SEEK_SET, FALSE) == -1)
00901         return -1;
00902     MMIO_GrabNextBuffer(wm, TRUE);
00903     }
00904 
00905     wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset);
00906 
00907     TRACE("=> %d\n", offset);
00908     return offset;
00909 }
00910 
00911 /**************************************************************************
00912  *              mmioGetInfo         [WINMM.@]
00913  */
00914 MMRESULT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags)
00915 {
00916     LPWINE_MMIO     wm;
00917 
00918     TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
00919 
00920     if ((wm = MMIO_Get(hmmio)) == NULL)
00921     return MMSYSERR_INVALHANDLE;
00922 
00923     *lpmmioinfo = wm->info;
00924 
00925     return MMSYSERR_NOERROR;
00926 }
00927 
00928 /**************************************************************************
00929  *              mmioSetInfo         [WINMM.@]
00930  */
00931 MMRESULT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO* lpmmioinfo, UINT uFlags)
00932 {
00933     LPWINE_MMIO     wm;
00934 
00935     TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
00936 
00937     if ((wm = MMIO_Get(hmmio)) == NULL)
00938     return MMSYSERR_INVALHANDLE;
00939 
00940     /* check pointers coherence */
00941     if (lpmmioinfo->pchNext < wm->info.pchBuffer ||
00942     lpmmioinfo->pchNext > wm->info.pchBuffer + wm->info.cchBuffer ||
00943     lpmmioinfo->pchEndRead < wm->info.pchBuffer ||
00944     lpmmioinfo->pchEndRead > wm->info.pchBuffer + wm->info.cchBuffer ||
00945     lpmmioinfo->pchEndWrite < wm->info.pchBuffer ||
00946     lpmmioinfo->pchEndWrite > wm->info.pchBuffer + wm->info.cchBuffer)
00947     return MMSYSERR_INVALPARAM;
00948 
00949     wm->info.pchNext = lpmmioinfo->pchNext;
00950     wm->info.pchEndRead = lpmmioinfo->pchEndRead;
00951 
00952     return MMSYSERR_NOERROR;
00953 }
00954 
00955 /**************************************************************************
00956 *               mmioSetBuffer       [WINMM.@]
00957 */
00958 MMRESULT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT uFlags)
00959 {
00960     LPWINE_MMIO     wm;
00961 
00962     TRACE("(hmmio=%p, pchBuf=%p, cchBuf=%d, uFlags=%#08x)\n",
00963       hmmio, pchBuffer, cchBuffer, uFlags);
00964 
00965     if ((wm = MMIO_Get(hmmio)) == NULL)
00966     return MMSYSERR_INVALHANDLE;
00967 
00968     return MMIO_SetBuffer(wm, pchBuffer, cchBuffer, uFlags);
00969 }
00970 
00971 /**************************************************************************
00972  *              mmioFlush           [WINMM.@]
00973  */
00974 MMRESULT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags)
00975 {
00976     LPWINE_MMIO     wm;
00977 
00978     TRACE("(%p, %04X)\n", hmmio, uFlags);
00979 
00980     if ((wm = MMIO_Get(hmmio)) == NULL)
00981     return MMSYSERR_INVALHANDLE;
00982 
00983     return MMIO_Flush(wm, uFlags);
00984 }
00985 
00986 /**************************************************************************
00987  *              mmioAdvance         [WINMM.@]
00988  */
00989 MMRESULT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags)
00990 {
00991     LPWINE_MMIO     wm;
00992 
00993     TRACE("hmmio=%p, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags);
00994 
00995     /* NOTE: mmioAdvance16 heavily relies on parameters from lpmmioinfo we're using
00996      * here. be sure if you change something here to check mmioAdvance16 as well
00997      */
00998     if ((wm = MMIO_Get(hmmio)) == NULL)
00999     return MMSYSERR_INVALHANDLE;
01000 
01001     if (!wm->info.cchBuffer)
01002     return MMIOERR_UNBUFFERED;
01003 
01004     if (uFlags != MMIO_READ && uFlags != MMIO_WRITE)
01005     return MMSYSERR_INVALPARAM;
01006 
01007     if (uFlags == MMIO_WRITE && (lpmmioinfo->dwFlags & MMIO_DIRTY))
01008     {
01009         send_message(wm->ioProc, &wm->info, MMIOM_SEEK, lpmmioinfo->lBufOffset, SEEK_SET, FALSE);
01010         send_message(wm->ioProc, &wm->info, MMIOM_WRITE, (LPARAM)lpmmioinfo->pchBuffer,
01011                      lpmmioinfo->pchNext - lpmmioinfo->pchBuffer, FALSE);
01012         lpmmioinfo->dwFlags &= ~MMIO_DIRTY;
01013     }
01014     if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
01015     return MMIOERR_CANNOTWRITE;
01016 
01017     if (lpmmioinfo) {
01018     wm->dwFileSize = max(wm->dwFileSize, lpmmioinfo->lBufOffset + 
01019                              (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer));
01020     }
01021     MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ);
01022 
01023     if (lpmmioinfo) {
01024     lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
01025     lpmmioinfo->pchEndRead  = lpmmioinfo->pchBuffer +
01026         (wm->info.pchEndRead - wm->info.pchBuffer);
01027     lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer +
01028         (wm->info.pchEndWrite - wm->info.pchBuffer);
01029     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset;
01030     lpmmioinfo->lBufOffset = wm->info.lBufOffset;
01031     }
01032     return MMSYSERR_NOERROR;
01033 }
01034 
01035 /**************************************************************************
01036  *              mmioStringToFOURCCA [WINMM.@]
01037  */
01038 FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags)
01039 {
01040     CHAR cc[4];
01041     int i = 0;
01042 
01043     for (i = 0; i < 4 && sz[i]; i++) {
01044     if (uFlags & MMIO_TOUPPER) {
01045         cc[i] = toupper(sz[i]);
01046     } else {
01047         cc[i] = sz[i];
01048     }
01049     }
01050 
01051     /* Pad with spaces */
01052     while (i < 4) cc[i++] = ' ';
01053 
01054     TRACE("Got '%.4s'\n",cc);
01055     return mmioFOURCC(cc[0],cc[1],cc[2],cc[3]);
01056 }
01057 
01058 /**************************************************************************
01059  *              mmioStringToFOURCCW [WINMM.@]
01060  */
01061 FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags)
01062 {
01063     char    szA[4];
01064 
01065     WideCharToMultiByte( CP_ACP, 0, sz, 4, szA, sizeof(szA), NULL, NULL );
01066     return mmioStringToFOURCCA(szA,uFlags);
01067 }
01068 
01069 /**************************************************************************
01070  *              mmioInstallIOProcA     [WINMM.@]
01071  */
01072 LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc,
01073                      LPMMIOPROC pIOProc, DWORD dwFlags)
01074 {
01075     return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, FALSE);
01076 }
01077 
01078 /**************************************************************************
01079  *              mmioInstallIOProcW     [WINMM.@]
01080  */
01081 LPMMIOPROC WINAPI mmioInstallIOProcW(FOURCC fccIOProc,
01082                      LPMMIOPROC pIOProc, DWORD dwFlags)
01083 {
01084     return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, TRUE);
01085 }
01086 
01087 /******************************************************************
01088  *      MMIO_SendMessage
01089  *
01090  *
01091  */
01092 static LRESULT  MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1,
01093                                  LPARAM lParam2, BOOL is_unicode)
01094 {
01095     LPWINE_MMIO     wm;
01096 
01097     TRACE("(%p, %u, %ld, %ld, %s)\n", hmmio, uMessage, lParam1, lParam2, is_unicode ? "unicode" : "ansi");
01098 
01099     if (uMessage < MMIOM_USER)
01100     return MMSYSERR_INVALPARAM;
01101 
01102     if ((wm = MMIO_Get(hmmio)) == NULL)
01103     return MMSYSERR_INVALHANDLE;
01104 
01105     return send_message(wm->ioProc, &wm->info, uMessage, lParam1, lParam2, is_unicode);
01106 }
01107 
01108 /**************************************************************************
01109  *              mmioSendMessage     [WINMM.@]
01110  */
01111 LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage,
01112                    LPARAM lParam1, LPARAM lParam2)
01113 {
01114     return MMIO_SendMessage(hmmio, uMessage, lParam1, lParam2, FALSE);
01115 }
01116 
01117 /**************************************************************************
01118  *              mmioDescend             [WINMM.@]
01119  */
01120 MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck,
01121                             const MMCKINFO* lpckParent, UINT uFlags)
01122 {
01123     DWORD       dwOldPos;
01124     FOURCC      srchCkId;
01125     FOURCC      srchType;
01126 
01127     TRACE("(%p, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags);
01128 
01129     if (lpck == NULL)
01130     return MMSYSERR_INVALPARAM;
01131 
01132     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
01133     TRACE("dwOldPos=%d\n", dwOldPos);
01134 
01135     if (lpckParent != NULL) {
01136     TRACE("seek inside parent at %d !\n", lpckParent->dwDataOffset);
01137     /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */
01138     if (dwOldPos < lpckParent->dwDataOffset ||
01139         dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) {
01140         WARN("outside parent chunk\n");
01141         return MMIOERR_CHUNKNOTFOUND;
01142     }
01143     }
01144 
01145     /* The SDK docu says 'ckid' is used for all cases. Real World
01146      * examples disagree -Marcus,990216.
01147      */
01148 
01149     srchCkId = 0;
01150     srchType = 0;
01151 
01152     /* find_chunk looks for 'ckid' */
01153     if (uFlags & MMIO_FINDCHUNK)
01154     srchCkId = lpck->ckid;
01155 
01156     /* find_riff and find_list look for 'fccType' */
01157     if (uFlags & MMIO_FINDLIST)
01158     {
01159     srchCkId = FOURCC_LIST;
01160         srchType = lpck->fccType;
01161     }
01162 
01163     if (uFlags & MMIO_FINDRIFF)
01164     {
01165     srchCkId = FOURCC_RIFF;
01166         srchType = lpck->fccType;
01167     }
01168 
01169     TRACE("searching for %4.4s.%4.4s\n",
01170           (LPCSTR)&srchCkId, srchType ? (LPCSTR)&srchType : "any");
01171 
01172     while (TRUE)
01173     {
01174         LONG ix;
01175 
01176         ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD));
01177         if (ix < 2*sizeof(DWORD))
01178         {
01179             mmioSeek(hmmio, dwOldPos, SEEK_SET);
01180             WARN("return ChunkNotFound\n");
01181             return MMIOERR_CHUNKNOTFOUND;
01182         }
01183 
01184         lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
01185         TRACE("ckid=%4.4s fcc=%4.4s cksize=%08X !\n",
01186               (LPCSTR)&lpck->ckid,
01187               srchType ? (LPCSTR)&lpck->fccType:"<na>",
01188               lpck->cksize);
01189         if ( (!srchCkId || (srchCkId == lpck->ckid)) &&
01190              (!srchType || (srchType == lpck->fccType)) )
01191             break;
01192 
01193         dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1);
01194         mmioSeek(hmmio, dwOldPos, SEEK_SET);
01195     }
01196 
01197     lpck->dwFlags = 0;
01198     /* If we were looking for RIFF/LIST chunks, the final file position
01199      * is after the chunkid. If we were just looking for the chunk
01200      * it is after the cksize. So add 4 in RIFF/LIST case.
01201      */
01202     if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
01203     mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET);
01204     else
01205     {
01206     mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET);
01207     lpck->fccType = 0;
01208     }
01209     TRACE("lpck: ckid=%.4s, cksize=%d, dwDataOffset=%d fccType=%08X (%.4s)!\n",
01210       (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset,
01211       lpck->fccType, srchType?(LPSTR)&lpck->fccType:"");
01212     return MMSYSERR_NOERROR;
01213 }
01214 
01215 /**************************************************************************
01216  *              mmioAscend          [WINMM.@]
01217  */
01218 MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags)
01219 {
01220     TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags);
01221 
01222     if (lpck->dwFlags & MMIO_DIRTY) {
01223     DWORD   dwOldPos, dwNewSize;
01224 
01225     TRACE("Chunk is dirty, checking if chunk's size is correct\n");
01226     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
01227     TRACE("dwOldPos=%d lpck->dwDataOffset = %d\n", dwOldPos, lpck->dwDataOffset);
01228     dwNewSize = dwOldPos - lpck->dwDataOffset;
01229     if (dwNewSize != lpck->cksize) {
01230         TRACE("Nope: lpck->cksize=%d dwNewSize=%d\n", lpck->cksize, dwNewSize);
01231         lpck->cksize = dwNewSize;
01232 
01233         /* pad odd size with 0 */
01234         if (dwNewSize & 1) {
01235         char ch = 0;
01236         mmioWrite(hmmio, &ch, 1);
01237         }
01238         mmioSeek(hmmio, lpck->dwDataOffset - sizeof(DWORD), SEEK_SET);
01239         mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD));
01240     }
01241     lpck->dwFlags = 0;
01242     }
01243 
01244     mmioSeek(hmmio, lpck->dwDataOffset + ((lpck->cksize + 1) & ~1), SEEK_SET);
01245 
01246     return MMSYSERR_NOERROR;
01247 }
01248 
01249 /**************************************************************************
01250  *          mmioCreateChunk             [WINMM.@]
01251  */
01252 MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO* lpck, UINT uFlags)
01253 {
01254     DWORD   dwOldPos;
01255     LONG    size;
01256     LONG    ix;
01257 
01258     TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags);
01259 
01260     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
01261     TRACE("dwOldPos=%d\n", dwOldPos);
01262 
01263     if (uFlags == MMIO_CREATELIST)
01264     lpck->ckid = FOURCC_LIST;
01265     else if (uFlags == MMIO_CREATERIFF)
01266     lpck->ckid = FOURCC_RIFF;
01267 
01268     TRACE("ckid=%.4s\n", (LPSTR)&lpck->ckid);
01269 
01270     size = 2 * sizeof(DWORD);
01271     lpck->dwDataOffset = dwOldPos + size;
01272 
01273     if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
01274     size += sizeof(DWORD);
01275     lpck->dwFlags = MMIO_DIRTY;
01276 
01277     ix = mmioWrite(hmmio, (LPSTR)lpck, size);
01278     TRACE("after mmioWrite ix = %d req = %d, errno = %d\n", ix, size, errno);
01279     if (ix < size) {
01280     mmioSeek(hmmio, dwOldPos, SEEK_SET);
01281     WARN("return CannotWrite\n");
01282     return MMIOERR_CANNOTWRITE;
01283     }
01284 
01285     return MMSYSERR_NOERROR;
01286 }
01287 
01288 /**************************************************************************
01289  *              mmioRenameA             [WINMM.@]
01290  */
01291 MMRESULT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName,
01292                             const MMIOINFO* lpmmioinfo, DWORD dwFlags)
01293 {
01294     struct IOProcList*  ioProc = NULL;
01295     struct IOProcList   tmp;
01296     FOURCC              fcc;
01297 
01298     TRACE("('%s', '%s', %p, %08X);\n",
01299       debugstr_a(szFileName), debugstr_a(szNewFileName), lpmmioinfo, dwFlags);
01300 
01301     /* If both params are NULL, then parse the file name */
01302     if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)
01303     {
01304     fcc = MMIO_ParseExtA(szFileName);
01305         if (fcc) ioProc = MMIO_FindProcNode(fcc);
01306     }
01307 
01308     /* Handle any unhandled/error case from above. Assume DOS file */
01309     if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL && ioProc == NULL))
01310     ioProc = MMIO_FindProcNode(FOURCC_DOS);
01311     /* if just the four character code is present, look up IO proc */
01312     else if (lpmmioinfo->pIOProc == NULL)
01313         ioProc = MMIO_FindProcNode(lpmmioinfo->fccIOProc);
01314     else /* use relevant ioProc */
01315     {
01316         ioProc = &tmp;
01317         tmp.fourCC = lpmmioinfo->fccIOProc;
01318         tmp.pIOProc = lpmmioinfo->pIOProc;
01319         tmp.is_unicode = FALSE;
01320         tmp.count = 1;
01321     }
01322 
01323     /* FIXME: should we actually pass lpmmioinfo down the drain ???
01324      * or make a copy of it because it's const ???
01325      */
01326     return send_message(ioProc, (MMIOINFO*)lpmmioinfo, MMIOM_RENAME,
01327                         (LPARAM)szFileName, (LPARAM)szNewFileName, FALSE);
01328 }
01329 
01330 /**************************************************************************
01331  *              mmioRenameW             [WINMM.@]
01332  */
01333 MMRESULT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName,
01334                             const MMIOINFO* lpmmioinfo, DWORD dwFlags)
01335 {
01336     LPSTR   szFn = NULL;
01337     LPSTR   sznFn = NULL;
01338     UINT    ret = MMSYSERR_NOMEM;
01339     INT         len;
01340 
01341     if (szFileName)
01342     {
01343         len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL );
01344         szFn = HeapAlloc( GetProcessHeap(), 0, len );
01345         if (!szFn) goto done;
01346         WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL );
01347     }
01348     if (szNewFileName)
01349     {
01350         len = WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, NULL, 0, NULL, NULL );
01351         sznFn = HeapAlloc( GetProcessHeap(), 0, len );
01352         if (!sznFn) goto done;
01353         WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, sznFn, len, NULL, NULL );
01354     }
01355 
01356     ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwFlags);
01357 
01358 done:
01359     HeapFree(GetProcessHeap(),0,szFn);
01360     HeapFree(GetProcessHeap(),0,sznFn);
01361     return ret;
01362 }

Generated on Sat May 26 2012 04:25:29 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.