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.

525 lines
15 KiB

  1. /* cf.c
  2. *
  3. * MMIO RIFF compound file functions.
  4. */
  5. #include <windows.h>
  6. #include "mmsystem.h"
  7. #include "mmiocf.h"
  8. #include "mmioi.h"
  9. /* @doc CFDOC
  10. @api HMMCF | mmioCFOpen | Open a RIFF compound file by name.
  11. @parm LPSTR | szFileName | The name of the RIFF compound file.
  12. @parm DWORD | dwFlags | Zero or more of the following flags:
  13. MMIO_READ, MMIO_WRITE, MMIO_READWRITE, MMIO_COMPAT, MMIO_EXCLUSIVE,
  14. MMIO_DENYWRITE, MMIO_DENYREAD, MMIO_DENYNONE, MMIO_CREATE.
  15. See <f mmioOpen> for a description of these flags.
  16. @rdesc Returns a handle to the open compound file. Returns NULL if the
  17. compound file could not be opened. If the compound file was already
  18. opened by this process, a handle to the compound file is returned,
  19. and the usage count of the compound file is incremented.
  20. @comm A RIFF compound file is any RIFF file that contains a 'CTOC'
  21. chunk (compound file table of contents) and a 'CGRP' chunk
  22. (compound file resource group). The RIFF compound file format
  23. is documented separately.
  24. If the MMIO_CREATE flag is specified, then:
  25. -- If the compound file is already open, the handle to that compound
  26. file is returned.
  27. -- If <p dwFlags> includes MMIO_WRITE, then the compound file will
  28. actually be opened for both reading and writing, since a compound
  29. file cannot be opened for writing alone.
  30. Every call to <f mmioCFOpen> must be matched by a call to
  31. <f mmioCFClose>.
  32. */
  33. HMMCF API
  34. mmioCFOpen(LPSTR szFileName, DWORD dwFlags)
  35. {
  36. /* TO DO */
  37. return NULL;
  38. }
  39. /* @doc CFDOC
  40. @api HMMCF | mmioCFAccess | Open a RIFF compound file by reading the
  41. 'CTOC' chunk (compound file table of contents) from a file that
  42. was opened by <f mmioOpen>.
  43. @parm HMMIO | hmmio | The open file handle returned by <f mmioOpen>.
  44. @parm LPMMCFINFO | lpmmcfinfo | Optional information used if
  45. <p dwFlags> if the compound file is to be created. <p lpmmcfinfo>
  46. may be NULL if default information is to be used.
  47. If <p lpmmcfinfo> is provided, then the following
  48. fields should be filled in. Note that all these fields, including
  49. the arrays, can be coded in a fixed C structure for a specific
  50. file format, for the purposes of creating a new compound file.
  51. However, note that if an existing compound file is opened, the
  52. caller should expect that additional (possibly unknown) "extra
  53. fields" may be present.
  54. @flag dwEntriesTotal | Should contain the initial number of
  55. (unused) entries in the table of contents (default 16).
  56. @flag dwHeaderFlags | Should contain zero.
  57. @flag wNameSize | The size of the <p achName> field of each
  58. CTOC entry (default 13).
  59. @flag wExHdrFields | The number of extra header fields to
  60. allocate at the end of the CTOC header (default 0).
  61. @flag wExEntFields | The number of extra entry fields
  62. at the end of each CTOC entry (default 0).
  63. @flag awExHdrFldUsage | Usage codes for extra header fields
  64. (default no usage code).
  65. @flag awExHdrEntUsage | Usage codes for extra entry fields
  66. (default no usage code).
  67. @flag adwExHdrField | Extra header field values
  68. (default no extra header field values).
  69. @parm DWORD | dwFlags | Zero or more of the following flags:
  70. @flag MMIO_CREATE | Create a compound file, i.e. create
  71. the 'CTOC' and 'CGRP' chunks.
  72. @flag MMIO_CTOCFIRST | Create the empty 'CTOC' chunk
  73. immediately and place it before the 'CGRP' chunk.
  74. If the 'CTOC' chunk gets too big, it may later have to
  75. be rewritten after the 'CGRP' chunk.
  76. This flag is ignored unless MMIO_CREATE is specified.
  77. @rdesc Returns a handle to the open compound file. Returns NULL if the
  78. compound file could not be opened.
  79. @comm This function will open a RIFF compound file, assuming that
  80. <p hmmio> has already been descended into the RIFF file
  81. (using <f mmioDescend>) and <p hmmio> points to the beginning
  82. of a chunk header. <p mmioCFAccess> scans through the file,
  83. looking for a 'CTOC' and 'CGRP' chunk. If these chunks are not
  84. found but MMIO_CREATE is specified, then a 'CTOC' chunk is created
  85. (if MMIO_CTOCFIRST is specified) then a 'CGRP' chunk is created.
  86. The CTOC is then maintained in memory until <f mmioCFClose>
  87. is called.
  88. Every call to <f mmioCFAccess> must be matched by a call to
  89. <f mmioCFClose>.
  90. */
  91. HMMCF API
  92. mmioCFAccess(HMMIO hmmio, LPMMCFINFO lpmmcfinfo, DWORD dwFlags)
  93. {
  94. /* TO DO */
  95. return NULL;
  96. }
  97. /* @doc CFDOC
  98. @api WORD | mmioCFClose | Close a compound file that was opened by
  99. <f mmioCFOpen> or <f mmioCFAccess>.
  100. @parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
  101. or <f mmioCFAccess>.
  102. @parm WORD | wFlags | Is not used and should be set to zero.
  103. @comm This function decrements the usage count of the compound file
  104. <p hmmcf>. If the usage count drops to zero, the compound file
  105. is closed. If the compound file was opened by <f mmioCFAccess>,
  106. then the <p hmmcf> information is deallocated but the HMMIO
  107. file handle associated with the compound file is not closed.
  108. */
  109. WORD API
  110. mmioCFClose(HMMCF hmmcf, WORD wFlags)
  111. {
  112. /* TO DO */
  113. return 0;
  114. }
  115. /* @doc CFDOC
  116. @api WORD | mmioCFCopy | Copy the 'CTOC' and 'CGRP' chunks from an open
  117. RIFF compound file to another file. The newly written 'CGRP' chunk
  118. will be compacted, i.e. it will have no deleted elements.
  119. @parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
  120. or <f mmioCFAccess>.
  121. @parm HMMIO | hmmio | An open file handle returned by <f mmioOpen>.
  122. The compound file is copied to <p hmmio>.
  123. @parm DWORD | dwFlags | Is not used and should be set to zero.
  124. @rdesc If the function succeeds, zero is returned. If the function fails,
  125. an error code is returned.
  126. @comm <f mmioCFCopy> assumes that the current file position of <p hmmio>
  127. is the end of a file, descended into a 'RIFF' chunk. <f mmioCFCopy>
  128. creates copies the 'CTOC' and 'CGRP' chunks from <p hmmcf> to
  129. <p hmmio>. A side effect of the copy operation is that the
  130. copy of the compound file is compacted, i.e. there are no deleted
  131. elements.
  132. */
  133. WORD API
  134. mmioCFCopy(HMMCF hmmcf, HMMIO hmmio, DWORD dwFlags)
  135. {
  136. /* TO DO */
  137. return 0;
  138. }
  139. /* @doc CFDOC
  140. @api DWORD | mmioCFGetInfo | Retrieve information from the CTOC header
  141. of an open RIFF compound file.
  142. @parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
  143. or <f mmioCFAccess>.
  144. @parm LPMMCFINFO | lpmmcfinfo | A caller-supplied buffer that will be
  145. filled in with the CTOC header.
  146. @parm DWORD | cb | The size of buffer <p lpmmcfinfo>. At most <p cb>
  147. bytes will be copied into <p lpmmcfinfo>.
  148. @rdesc Returns the number of bytes copied into <p lpmmcfinfo>.
  149. @comm The information that is copied to <p lpmmcfinfo> consists of
  150. an MMCFINFO structure followed by the variable-length arrays
  151. <p awExHdrFldUsage>, <p awExEntFldUsage>, and <p adwExHdrField>.
  152. See the definition of RIFF Compound Files for more information.
  153. To find out how big the RIFF CTOC header is (e.g. to allocate
  154. enough memory for the entire block), call <f mmioCFGetInfo>
  155. with <p cb> equal to the size of a DWORD, and the function will
  156. copy the first field of the MMCFINFO structure (i.e.
  157. <p dwHeaderSize>, the size of the CTOC header) into <p lpmmcfinfo>.
  158. */
  159. DWORD API
  160. mmioCFGetInfo(HMMCF hmmcf, LPMMCFINFO lpmmcfinfo, DWORD cb)
  161. {
  162. DWORD dwBytes;
  163. dwBytes = min(cb, PC(hmmcf)->pHeader->dwHeaderSize);
  164. MemCopy(lpmmcfinfo, PC(hmmcf)->pHeader, dwBytes);
  165. return dwBytes;
  166. }
  167. /* @doc CFDOC
  168. @api DWORD | mmioCFSetInfo | Modify information that is stored in the
  169. CTOC header of an open RIFF compound file.
  170. @parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
  171. or <f mmioCFAccess>.
  172. @parm LPMMCFINFO | lpmmcfinfo | A caller-supplied buffer that was filled
  173. in by <f mmioCFGetInfo> and then modified by the caller. Only
  174. the <p awExHdrFldUsage> and <p adwExHdrField> fields should be
  175. modified.
  176. @parm DWORD | cb | The size of buffer <p lpmmcfinfo>.
  177. @rdesc Returns the number of bytes copied from <p lpmmcfinfo>.
  178. @comm See <f mmioCFGetInfo> for more information.
  179. */
  180. DWORD API
  181. mmioCFSetInfo(HMMCF hmmcf, LPMMCFINFO lpmmcfinfo, DWORD cb)
  182. {
  183. /* TO DO:
  184. * Re-allocate CTOC header if necessary and copy <p lpmmcfinfo> to it.
  185. */
  186. return 0L;
  187. }
  188. /* @doc CFDOC
  189. @api LPMMCTOCENTRY | mmioCFFindEntry | Find an particular entry in an open
  190. RIFF compound file.
  191. @parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
  192. or <f mmioCFAccess>.
  193. @parm LPSTR | szName | Then name of the compound file element to look for.
  194. The search is case-insensitive. Flags in <p wFlags> can be set to
  195. specify that an element is to be searched for by some attribute other
  196. than name.
  197. @parm WORD | wFlags | Zero or more of the following flags:
  198. @flag MMIO_FINDFIRST | Find the first entry in the CTOC table.
  199. @flag MMIO_FINDNEXT | Find the next entry in the CTOC table
  200. after the entry <p lParam> (which should be an
  201. LPMMCTOCENTRY pointer returned by this function).
  202. Returns NULL if <p lParam> refers to the last entry.
  203. @flag MMIO_FINDUNUSED | Find the first entry in the CTOC table
  204. that is marked as "unused", i.e. the entry does not refer
  205. to any part of the compound file.
  206. @flag MMIO_FINDDELETED | Find the first entry in the CTOC table
  207. that is marked as "deleted", i.e. the entry refers to a
  208. compound file element that occupies space in the CGRP
  209. chunk but is currently unused.
  210. @parm LPARAM | lParam | Additional information (see <p wFlags> above).
  211. @rdesc Returns a pointer to the CTOC table entry that was found.
  212. If no entry was found, NULL is returned. Warning: assume that
  213. the returned pointer is invalid after the next call to any MMIO
  214. function.
  215. @comm MMIO_FINDFIRST and MMIO_FINDNEXT can be used to enumerate the entries
  216. in an open RIFF compound file.
  217. */
  218. LPMMCTOCENTRY API
  219. mmioCFFindEntry(HMMCF hmmcf, LPSTR szName, WORD wFlags, LPARAM lParam)
  220. {
  221. LPSTR pchEntry;
  222. DWORD dwElemNum;
  223. if (wFlags & MMIO_FINDFIRST)
  224. return (LPMMCTOCENTRY) PC(hmmcf)->pEntries;
  225. if (wFlags & MMIO_FINDNEXT)
  226. {
  227. pchEntry = (LPSTR) lParam + PC(hmmcf)->wEntrySize;
  228. if (pchEntry > PC(hmmcf)->pEntries
  229. + PC(hmmcf)->pHeader->dwEntriesTotal * PC(hmmcf)->wEntrySize)
  230. return NULL;
  231. else
  232. return (LPMMCTOCENTRY) pchEntry;
  233. }
  234. for (pchEntry = PC(hmmcf)->pEntries, dwElemNum = 0;
  235. dwElemNum < PC(hmmcf)->pHeader->dwEntriesTotal;
  236. pchEntry += PC(hmmcf)->wEntrySize, dwElemNum++)
  237. {
  238. BYTE bFlags;
  239. bFlags = *(BYTE FAR *) (pchEntry + PC(hmmcf)->wEntFlagsOffset);
  240. if ((wFlags & MMIO_FINDUNUSED) && (bFlags & CTOC_EF_UNUSED))
  241. return (LPMMCTOCENTRY) pchEntry;
  242. if ((wFlags & MMIO_FINDDELETED) && (bFlags & CTOC_EF_DELETED))
  243. return (LPMMCTOCENTRY) pchEntry;
  244. if (bFlags & (CTOC_EF_DELETED | CTOC_EF_UNUSED))
  245. continue;
  246. if (lstrcmpi(szName, pchEntry + PC(hmmcf)->wEntNameOffset) == 0)
  247. return (LPMMCTOCENTRY) pchEntry;
  248. }
  249. return NULL;
  250. }
  251. /* @doc INTERNAL
  252. @api LRESULT | mmioBNDIOProc | The 'BND' I/O procedure, which handles I/O
  253. on RIFF compound file elements (including BND files).
  254. @parm LPSTR | lpmmioinfo | A pointer to an MMIOINFO block that
  255. contains information about the open file.
  256. @parm WORD | wMsg | The message that the I/O procedure is being
  257. asked to execute.
  258. @parm LPARAM | lParam1 | Specifies additional message information.
  259. @parm LPARAM | lParam2 | Specifies additional message information.
  260. @rdesc Return value depends on <p wMsg>.
  261. */
  262. LRESULT CALLBACK
  263. mmioBNDIOProc(LPSTR lpmmioStr, WORD wMsg, LPARAM lParam1, LPARAM lParam2)
  264. {
  265. PMMIO pmmio = (PMMIO) (WORD) (LONG) lpmmioStr; // only in DLL!
  266. MMIOBNDINFO * pInfo = (MMIOBNDINFO *) pmmio->adwInfo;
  267. LPSTR szFileName = (LPSTR) lParam1;
  268. PMMCF pmmcf = PC(pInfo->hmmcf); // CF status block
  269. LPSTR szElemName; // name of CF element
  270. LONG lBytesLeft; // bytes left in file
  271. LONG lExpand; // how much element expanded by
  272. LONG lEndElement; // offset of end of element
  273. LONG lResult;
  274. LPSTR pch;
  275. switch (wMsg)
  276. {
  277. case MMIOM_OPEN:
  278. if (pmmcf == NULL)
  279. {
  280. /* expect <lParam1> is "...foo.bnd!element" */
  281. if ((pch = fstrrchr(szFileName, CFSEPCHAR)) == NULL)
  282. return (LRESULT) MMIOERR_CANNOTOPEN;
  283. *pch = 0; // temporarily zero the "!"
  284. if (pch[1] == 0) // is name of form "foo.bnd!"?
  285. return (LRESULT) MMIOERR_CANNOTOPEN;
  286. pInfo->hmmcf = mmioCFOpen(szFileName, (LONG) lParam2);
  287. pmmcf = (PMMCF) pInfo->hmmcf;
  288. *pch = CFSEPCHAR;
  289. if (pInfo->hmmcf == NULL)
  290. return (LRESULT) MMIOERR_CANNOTOPEN;
  291. szElemName = pch + 1;
  292. /* decrement the usage count, since the usage count
  293. * was incremented by mmioCFOpen() and will
  294. * be incremented below, but this MMIOM_OPEN
  295. * represents only a single usage
  296. */
  297. pmmcf->lUsage--;
  298. }
  299. else
  300. {
  301. /* expect <lParam1> is CF element name */
  302. szElemName = szFileName;
  303. }
  304. /* TO DO...
  305. * If compound file is opened for writing or create(truncate),
  306. * then make new entry at end (copying entry if required);
  307. */
  308. /* <pmmcf> is a handle to the compound file containing
  309. * the element, and <szElemName> is the name of the element
  310. */
  311. if ((pInfo->pEntry = mmioCFFindEntry(pInfo->hmmcf,
  312. szElemName, 0, 0L)) == NULL)
  313. {
  314. mmioCFClose(pInfo->hmmcf, 0);
  315. return (LRESULT) MMIOERR_CANNOTOPEN;
  316. }
  317. if (pmmio->dwFlags & MMIO_DELETE)
  318. {
  319. /* TO DO: delete element: mark as deleted, update
  320. * CTOC header, etc.
  321. */
  322. }
  323. if (pmmio->dwFlags & (MMIO_PARSE | MMIO_EXIST))
  324. {
  325. /* TO DO: qualify name
  326. */
  327. }
  328. return (LRESULT) 0;
  329. case MMIOM_CLOSE:
  330. mmioCFClose(pInfo->hmmcf, 0);
  331. return (LRESULT) 0;
  332. case MMIOM_READ:
  333. lBytesLeft = pInfo->pEntry->dwSize - pmmio->lDiskOffset;
  334. if ((LONG) lParam2 > lBytesLeft)
  335. (LONG) lParam2 = lBytesLeft;
  336. if (mmioSeek(pmmcf->hmmio, pmmio->lDiskOffset, SEEK_SET) == -1L)
  337. return (LRESULT) -1L;
  338. if ((lResult = mmioRead(pmmcf->hmmio,
  339. (HPSTR) lParam1, (LONG) lParam2)) == -1L)
  340. return (LRESULT) -1L;
  341. pmmio->lDiskOffset += lResult;
  342. return (LRESULT) lResult;
  343. case MMIOM_WRITE:
  344. case MMIOM_WRITEFLUSH: /* Note: flush not really handled! */
  345. lEndElement = pmmcf->lStartCGRPData + pInfo->pEntry->dwOffset
  346. + pInfo->pEntry->dwSize;
  347. if ((lEndElement != pmmcf->lEndCGRP) ||
  348. (pmmcf->lEndCGRP != pmmcf->lEndFile))
  349. {
  350. /* this CF element is not growable -- limit writing
  351. * to the current end of the CF element
  352. */
  353. lBytesLeft = pInfo->pEntry->dwSize - pmmio->lDiskOffset;
  354. if ((LONG) lParam2 > lBytesLeft)
  355. (LONG) lParam2 = lBytesLeft;
  356. }
  357. if ((lResult = mmioWrite(pmmcf->hmmio,
  358. (HPSTR) lParam1, (LONG) lParam2)) == -1L)
  359. return (LRESULT) -1L;
  360. pmmio->lDiskOffset += lResult;
  361. if ((lExpand = pmmio->lDiskOffset - pInfo->pEntry->dwSize) > 0)
  362. {
  363. pInfo->pEntry->dwSize += lExpand;
  364. pmmcf->lEndCGRP += lExpand;
  365. pmmcf->lEndFile += lExpand;
  366. pmmcf->lTotalExpand += lExpand;
  367. }
  368. return (LRESULT) lResult;
  369. case MMIOM_SEEK:
  370. /* calculate the new <lDiskOffset> (the current disk offset
  371. * relative to the beginning of the compound file); don't
  372. * bother seeking, since we'll have to seek again anyway
  373. * at the next read (since <pmmcf->hmmio> is shared between
  374. * all elements of the compound file)
  375. */
  376. switch ((int)(LONG) lParam2)
  377. {
  378. case SEEK_SET:
  379. pmmio->lDiskOffset = pmmcf->lStartCGRPData
  380. + pInfo->pEntry->dwOffset + (DWORD)lParam1;
  381. break;
  382. case SEEK_CUR:
  383. pmmio->lDiskOffset += lParam1;
  384. break;
  385. case SEEK_END:
  386. pmmio->lDiskOffset = pmmcf->lStartCGRPData +
  387. + pInfo->pEntry->dwOffset
  388. + pInfo->pEntry->dwSize - (DWORD)lParam1;
  389. break;
  390. }
  391. return (LRESULT) pmmio->lDiskOffset;
  392. case MMIOM_GETCF:
  393. return (LRESULT)(LONG)(WORD) pInfo->hmmcf;
  394. case MMIOM_GETCFENTRY:
  395. return (LRESULT) pInfo->pEntry;
  396. }
  397. return (LRESULT) 0;
  398. }