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.

1541 lines
39 KiB

  1. /****************************************************************************
  2. *
  3. * WAVEFILE.C
  4. *
  5. * An implementation in C of an AVI File Handler to read standard windows
  6. * WAV files as if they were an AVI file with one audio stream.
  7. *
  8. ***************************************************************************/
  9. /**************************************************************************
  10. *
  11. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  12. * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13. * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  14. * PURPOSE.
  15. *
  16. * Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved.
  17. *
  18. **************************************************************************/
  19. #include <win32.h>
  20. #ifndef _WIN32
  21. #include <ole2.h>
  22. #endif
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <malloc.h>
  26. #include <ctype.h>
  27. #include <vfw.h>
  28. #include "extra.h"
  29. #include "wavefile.h"
  30. #define formtypeWAVE mmioFOURCC('W', 'A', 'V', 'E')
  31. #define ckidWAVEFORMAT mmioFOURCC('f', 'm', 't', ' ')
  32. #define ckidWAVEDATA mmioFOURCC('d', 'a', 't', 'a')
  33. #ifndef _WIN32
  34. #define LPCOLESTR LPCSTR
  35. #define LPOLESTR LPSTR
  36. #endif
  37. typedef struct {
  38. /*
  39. ** This implementation of a file handler is done in C, not C++, so a few
  40. ** things work differently than in C++. Our structure contains Vtbls
  41. ** (pointer to function tables) for three interfaces... Unknown, AVIStream,
  42. ** and AVIFile, as well as our private data we need to implement the
  43. ** handler.
  44. **
  45. */
  46. IAVIStreamVtbl FAR *AVIStream;
  47. IAVIFileVtbl FAR *AVIFile;
  48. IUnknownVtbl FAR *Unknown;
  49. IPersistFileVtbl FAR *Persist;
  50. // This is our controlling object.
  51. IUnknown FAR* pUnknownOuter;
  52. //
  53. // WaveFile instance data
  54. //
  55. HSHFILE hshfile; // file I/O
  56. MMCKINFO ckData;
  57. LONG refs; // for UNKNOWN
  58. AVISTREAMINFOW avistream; // for STREAM
  59. LPWAVEFORMATEX lpFormat; // stream format
  60. LONG cbFormat;
  61. BOOL fDirty;
  62. UINT mode;
  63. EXTRA extra;
  64. AVIFILEINFOW avihdr;
  65. } WAVESTUFF, FAR *LPWAVESTUFF;
  66. /*
  67. ** Whenever a function is called with a pointer to one of our Vtbls, we need
  68. ** to back up and get a pointer to the beginning of our structure. Depending
  69. ** on which pointer we are passed, we need to back up a different number of
  70. ** bytes. C++ would make this easier, by declaring backpointers.
  71. */
  72. WAVESTUFF ws;
  73. #define WAVESTUFF_FROM_UNKNOWN(pu) (LPWAVESTUFF)((LPBYTE)(pu) - ((LPBYTE)&ws.Unknown - (LPBYTE)&ws))
  74. #define WAVESTUFF_FROM_FILE(pf) (LPWAVESTUFF)((LPBYTE)(pf) - ((LPBYTE)&ws.AVIFile - (LPBYTE)&ws))
  75. #define WAVESTUFF_FROM_STREAM(ps) (LPWAVESTUFF)((LPBYTE)(ps) - ((LPBYTE)&ws.AVIStream - (LPBYTE)&ws))
  76. #define WAVESTUFF_FROM_PERSIST(ppf) (LPWAVESTUFF)((LPBYTE)(ppf) - ((LPBYTE)&ws.Persist - (LPBYTE)&ws))
  77. extern HINSTANCE ghMod;
  78. LPTSTR FAR FileName( LPCTSTR lszPath);
  79. extern LPTSTR FAR lstrzcpy (LPTSTR pszTgt, LPCTSTR pszSrc, size_t cch);
  80. extern LPSTR FAR lstrzcpyA (LPSTR pszTgt, LPCSTR pszSrc, size_t cch);
  81. extern LPWSTR FAR lstrzcpyW (LPWSTR pszTgt, LPCWSTR pszSrc, size_t cch);
  82. extern LPWSTR FAR lstrzcpyAtoW (LPWSTR pszTgt, LPCSTR pszSrc, size_t cch);
  83. extern LPSTR FAR lstrzcpyWtoA (LPSTR pszTgt, LPCWSTR pszSrc, size_t cch);
  84. //
  85. // Function prototypes and Vtbl for the Unknown interface
  86. //
  87. STDMETHODIMP WaveUnknownQueryInterface(LPUNKNOWN pu, REFIID iid, void FAR* FAR* ppv);
  88. STDMETHODIMP_(ULONG) WaveUnknownAddRef(LPUNKNOWN pu);
  89. STDMETHODIMP_(ULONG) WaveUnknownRelease(LPUNKNOWN pu);
  90. IUnknownVtbl UnknownVtbl = {
  91. WaveUnknownQueryInterface,
  92. WaveUnknownAddRef,
  93. WaveUnknownRelease
  94. };
  95. //
  96. // Function prototypes and Vtbl for the AVIFile interface
  97. //
  98. STDMETHODIMP WaveFileQueryInterface(PAVIFILE pf, REFIID iid, void FAR* FAR* ppv);
  99. STDMETHODIMP_(ULONG) WaveFileAddRef(PAVIFILE pf);
  100. STDMETHODIMP_(ULONG) WaveFileRelease(PAVIFILE pf);
  101. #ifndef _WIN32
  102. STDMETHODIMP WaveFileOpen(PAVIFILE pf, LPCSTR szFile, UINT mode);
  103. #endif
  104. STDMETHODIMP WaveFileInfo(PAVIFILE pf, AVIFILEINFOW FAR * pfi, LONG lSize);
  105. STDMETHODIMP WaveFileGetStream(PAVIFILE pf, PAVISTREAM FAR * ppavi, DWORD fccType, LONG lParam);
  106. STDMETHODIMP WaveFileCreateStream(PAVIFILE pf, PAVISTREAM FAR *ppstream, AVISTREAMINFOW FAR *psi);
  107. #ifndef _WIN32
  108. STDMETHODIMP WaveFileSave(PAVIFILE pf, LPCSTR szFile, AVICOMPRESSOPTIONS FAR *lpOptions, AVISAVECALLBACK lpfnCallback);
  109. #endif
  110. STDMETHODIMP WaveFileWriteData(PAVIFILE pf, DWORD ckid, LPVOID lpData, LONG cbData);
  111. STDMETHODIMP WaveFileReadData(PAVIFILE pf, DWORD ckid, LPVOID lpData, LONG FAR *lpcbData);
  112. STDMETHODIMP WaveFileEndRecord(PAVIFILE pf);
  113. #ifdef _WIN32
  114. STDMETHODIMP WaveFileDeleteStream(PAVIFILE pf, DWORD fccType, LONG lParam);
  115. #else
  116. STDMETHODIMP WaveFileReserved(PAVIFILE pf);
  117. #endif
  118. IAVIFileVtbl FileVtbl = {
  119. WaveFileQueryInterface,
  120. WaveFileAddRef,
  121. WaveFileRelease,
  122. #ifndef _WIN32
  123. WaveFileOpen,
  124. #endif
  125. WaveFileInfo,
  126. WaveFileGetStream,
  127. WaveFileCreateStream,
  128. #ifndef _WIN32
  129. WaveFileSave,
  130. #endif
  131. WaveFileWriteData,
  132. WaveFileReadData,
  133. WaveFileEndRecord,
  134. #ifdef _WIN32
  135. WaveFileDeleteStream
  136. #else
  137. WaveFileReserved,
  138. WaveFileReserved,
  139. WaveFileReserved,
  140. WaveFileReserved,
  141. WaveFileReserved
  142. #endif
  143. };
  144. STDMETHODIMP WavePersistQueryInterface(LPPERSISTFILE pf, REFIID iid, void FAR* FAR* ppv);
  145. STDMETHODIMP_(ULONG) WavePersistAddRef(LPPERSISTFILE pf);
  146. STDMETHODIMP_(ULONG) WavePersistRelease(LPPERSISTFILE pf);
  147. STDMETHODIMP WavePersistGetClassID (LPPERSISTFILE ppf, LPCLSID lpClassID);
  148. STDMETHODIMP WavePersistIsDirty (LPPERSISTFILE ppf);
  149. STDMETHODIMP WavePersistLoad (LPPERSISTFILE ppf,
  150. LPCOLESTR lpszFileName, DWORD grfMode);
  151. STDMETHODIMP WavePersistSave (LPPERSISTFILE ppf,
  152. LPCOLESTR lpszFileName, BOOL fRemember);
  153. STDMETHODIMP WavePersistSaveCompleted (LPPERSISTFILE ppf,
  154. LPCOLESTR lpszFileName);
  155. STDMETHODIMP WavePersistGetCurFile (LPPERSISTFILE ppf,
  156. LPOLESTR FAR * lplpszFileName);
  157. IPersistFileVtbl PersistVtbl = {
  158. WavePersistQueryInterface,
  159. WavePersistAddRef,
  160. WavePersistRelease,
  161. WavePersistGetClassID,
  162. WavePersistIsDirty,
  163. WavePersistLoad,
  164. WavePersistSave,
  165. WavePersistSaveCompleted,
  166. WavePersistGetCurFile
  167. };
  168. //
  169. // Function prototypes and Vtbl for the AVIStream interface
  170. //
  171. STDMETHODIMP WaveStreamQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID FAR* ppvObj);
  172. STDMETHODIMP WaveStreamCreate(PAVISTREAM ps, LPARAM lParam1, LPARAM lParam2);
  173. STDMETHODIMP_(ULONG) WaveStreamAddRef(PAVISTREAM ps);
  174. STDMETHODIMP_(ULONG) WaveStreamRelease(PAVISTREAM ps);
  175. STDMETHODIMP WaveStreamInfo(PAVISTREAM ps, AVISTREAMINFOW FAR * psi, LONG lSize);
  176. STDMETHODIMP_(LONG) WaveStreamFindSample(PAVISTREAM ps, LONG lPos, LONG lFlags);
  177. STDMETHODIMP WaveStreamReadFormat(PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat);
  178. STDMETHODIMP WaveStreamSetFormat(PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat);
  179. STDMETHODIMP WaveStreamRead(PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG FAR * plBytes,LONG FAR * plSamples);
  180. STDMETHODIMP WaveStreamWrite(PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpData, LONG cbData, DWORD dwFlags, LONG FAR *plSampWritten, LONG FAR *plBytesWritten);
  181. STDMETHODIMP WaveStreamDelete(PAVISTREAM ps, LONG lStart, LONG lSamples);
  182. STDMETHODIMP WaveStreamReadData(PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG FAR *lpcb);
  183. STDMETHODIMP WaveStreamWriteData(PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG cb);
  184. #ifdef _WIN32
  185. STDMETHODIMP WaveStreamSetInfo(PAVISTREAM ps, AVISTREAMINFOW FAR * psi, LONG lSize);
  186. #else
  187. STDMETHODIMP WaveStreamReserved(PAVISTREAM ps);
  188. #endif
  189. IAVIStreamVtbl StreamVtbl = {
  190. WaveStreamQueryInterface,
  191. WaveStreamAddRef,
  192. WaveStreamRelease,
  193. WaveStreamCreate,
  194. WaveStreamInfo,
  195. WaveStreamFindSample,
  196. WaveStreamReadFormat,
  197. WaveStreamSetFormat,
  198. WaveStreamRead,
  199. WaveStreamWrite,
  200. WaveStreamDelete,
  201. WaveStreamReadData,
  202. WaveStreamWriteData,
  203. #ifdef _WIN32
  204. WaveStreamSetInfo
  205. #else
  206. WaveStreamReserved,
  207. WaveStreamReserved,
  208. WaveStreamReserved,
  209. WaveStreamReserved,
  210. WaveStreamReserved
  211. #endif
  212. };
  213. #if defined _WIN32 && !defined UNICODE
  214. int LoadUnicodeString(HINSTANCE hinst, UINT wID, LPWSTR lpBuffer, int cchBuffer)
  215. {
  216. char ach[256];
  217. int i;
  218. i = LoadString(hinst, wID, ach, NUMELMS(ach));
  219. if (i > 0)
  220. MultiByteToWideChar(CP_ACP, 0, ach, -1, lpBuffer, cchBuffer);
  221. return i;
  222. }
  223. #else
  224. #define LoadUnicodeString LoadString
  225. #endif
  226. ///////////////////////////////////////////////////////////////////////////
  227. ///////////////////////////////////////////////////////////////////////////
  228. ///////////////////////////////////////////////////////////////////////////
  229. /* - - - - - - - - */
  230. UINT uUseCount; // the reference count for our objects
  231. UINT uLockCount; // our lock count for LockServer
  232. /* - - - - - - - - */
  233. //
  234. // Create a new instance. Since this is a C implementation we have to
  235. // allocate space for our structure ourselves.
  236. //
  237. HRESULT WaveFileCreate(
  238. IUnknown FAR* pUnknownOuter,
  239. REFIID riid,
  240. void FAR* FAR* ppv)
  241. {
  242. IUnknown FAR* pUnknown;
  243. LPWAVESTUFF pWaveStuff;
  244. HRESULT hresult;
  245. // Allocate space for our structure
  246. pWaveStuff = (LPWAVESTUFF)GlobalAllocPtr(GMEM_MOVEABLE,
  247. sizeof(WAVESTUFF));
  248. if (!pWaveStuff)
  249. return ResultFromScode(E_OUTOFMEMORY);
  250. // Initialize the Vtbls
  251. pWaveStuff->AVIFile = &FileVtbl;
  252. pWaveStuff->AVIStream = &StreamVtbl;
  253. pWaveStuff->Unknown = &UnknownVtbl;
  254. pWaveStuff->Persist = &PersistVtbl;
  255. // Set up our controlling object
  256. pUnknown = (IUnknown FAR *)&pWaveStuff->Unknown;
  257. if (pUnknownOuter)
  258. pWaveStuff->pUnknownOuter = pUnknownOuter;
  259. else
  260. pWaveStuff->pUnknownOuter =(IUnknown FAR *)&pWaveStuff->Unknown;
  261. // Initial the things in our structure
  262. pWaveStuff->refs = 0;
  263. pWaveStuff->hshfile = NULL;
  264. pWaveStuff->lpFormat = NULL;
  265. pWaveStuff->cbFormat = 0L;
  266. pWaveStuff->fDirty = FALSE;
  267. pWaveStuff->extra.lp = NULL;
  268. pWaveStuff->extra.cb = 0L;
  269. // Call our Query interface to increment our ref count and get a
  270. // pointer to our interface to return.
  271. hresult = pUnknown->lpVtbl->QueryInterface(pUnknown, riid, ppv);
  272. if (FAILED(GetScode(hresult)))
  273. GlobalFreePtr(pWaveStuff);
  274. return hresult;
  275. }
  276. /* - - - - - - - - */
  277. //
  278. // Query interface from all three interfaces comes here. We support the
  279. // Unknown interface, AVIStream and AVIFile.
  280. //
  281. STDMETHODIMP WaveUnknownQueryInterface(
  282. LPUNKNOWN pu,
  283. REFIID iid,
  284. void FAR* FAR* ppv)
  285. {
  286. // Get a pointer to our structure
  287. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_UNKNOWN(pu);
  288. if (IsEqualIID(iid, &IID_IUnknown))
  289. *ppv = (LPVOID)&pWaveStuff->Unknown;
  290. else if (IsEqualIID(iid, &IID_IAVIFile))
  291. *ppv = (LPVOID)&pWaveStuff->AVIFile;
  292. else if (IsEqualIID(iid, &IID_IAVIStream))
  293. *ppv = (LPVOID)&pWaveStuff->AVIStream;
  294. else if (IsEqualIID(iid, &IID_IPersistFile))
  295. *ppv = (LPVOID)&pWaveStuff->Persist;
  296. else
  297. return ResultFromScode(E_NOINTERFACE);
  298. pu->lpVtbl->AddRef(pu);
  299. return NOERROR;
  300. }
  301. /* - - - - - - - - */
  302. //
  303. // Increase our reference count. AddRef for all three interfaces comes here.
  304. //
  305. STDMETHODIMP_(ULONG) WaveUnknownAddRef(
  306. LPUNKNOWN pu)
  307. {
  308. // Get a pointer to our structure
  309. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_UNKNOWN(pu);
  310. uUseCount++;
  311. return ++pWaveStuff->refs;
  312. }
  313. /* - - - - - - - - */
  314. //
  315. // Decrease our reference count. Release for all three interfaces comes here.
  316. //
  317. STDMETHODIMP_(ULONG) WaveUnknownRelease(
  318. LPUNKNOWN pu)
  319. {
  320. // Get a pointer to our structure
  321. LPWAVESTUFF p = WAVESTUFF_FROM_UNKNOWN(pu);
  322. uUseCount--;
  323. //
  324. // Ref count is zero. Close the file. If we've been writing to it, it's
  325. // clean-up time!
  326. //
  327. if (!--p->refs) {
  328. LONG lRet = AVIERR_OK;
  329. if (p->fDirty) {
  330. MMCKINFO ckRIFF;
  331. MMCKINFO ck;
  332. shfileSeek(p->hshfile, 0, SEEK_SET);
  333. /* create the output file RIFF chunk of form type 'WAVE' */
  334. ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  335. ckRIFF.cksize = 0L; // let MMIO figure out ck. size
  336. if (shfileCreateChunk(p->hshfile, &ckRIFF, MMIO_CREATERIFF) != 0)
  337. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  338. ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
  339. ck.cksize = p->cbFormat; // we know the size of this ck.
  340. if (shfileCreateChunk(p->hshfile, &ck, 0) != 0)
  341. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  342. if (shfileWrite(p->hshfile, (HPSTR) p->lpFormat, p->cbFormat) != p->cbFormat)
  343. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  344. /* ascend out of the 'fmt' chunk, back into 'RIFF' chunk */
  345. if (shfileAscend(p->hshfile, &ck, 0) != 0)
  346. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  347. // If there was extra stuff here, we need to fill it!
  348. if (shfileSeek(p->hshfile, 0, SEEK_CUR)
  349. + 2 * (LRESULT)sizeof(DWORD)
  350. != (LRESULT) p->ckData.dwDataOffset) {
  351. /* create the 'data' chunk that holds the waveform samples */
  352. ck.ckid = mmioFOURCC('J', 'U', 'N', 'K');
  353. ck.cksize = 0;
  354. if (shfileCreateChunk(p->hshfile, &ck, 0) != 0)
  355. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  356. shfileSeek(p->hshfile,
  357. p->ckData.dwDataOffset - 2 * sizeof(DWORD),
  358. SEEK_SET);
  359. if (shfileAscend(p->hshfile, &ck, 0) != 0)
  360. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  361. }
  362. /* create the 'data' chunk that holds the waveform samples */
  363. ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
  364. ck.cksize = p->ckData.cksize;
  365. if (shfileCreateChunk(p->hshfile, &ck, 0) != 0)
  366. goto ERROR_CANNOT_WRITE; // cannot write file, probably
  367. shfileSeek(p->hshfile, p->ckData.cksize, SEEK_CUR);
  368. shfileAscend(p->hshfile, &ck, 0);
  369. if (p->extra.cb) {
  370. if (shfileWrite(p->hshfile, (HPSTR) p->extra.lp, p->extra.cb) != p->extra.cb)
  371. goto ERROR_CANNOT_WRITE;
  372. }
  373. if (shfileAscend(p->hshfile, &ckRIFF, 0) != 0)
  374. goto ERROR_CANNOT_WRITE;
  375. if (shfileFlush(p->hshfile, 0) != 0)
  376. goto ERROR_CANNOT_WRITE;
  377. }
  378. goto success;
  379. ERROR_CANNOT_WRITE:
  380. lRet = AVIERR_FILEWRITE;
  381. success:
  382. if (p->hshfile)
  383. shfileClose(p->hshfile, 0);
  384. if (p->lpFormat)
  385. GlobalFreePtr(p->lpFormat);
  386. // Free the memory for our structure.
  387. GlobalFreePtr(p);
  388. return 0;
  389. }
  390. return p->refs;
  391. }
  392. //
  393. // Use our controlling object to call QueryInterface on Unknown
  394. //
  395. STDMETHODIMP WaveFileQueryInterface(
  396. PAVIFILE pf,
  397. REFIID iid,
  398. void FAR* FAR* ppv)
  399. {
  400. // Get a pointer to our structure
  401. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_FILE(pf);
  402. return pWaveStuff->pUnknownOuter->lpVtbl->QueryInterface(
  403. pWaveStuff->pUnknownOuter, iid, ppv);
  404. }
  405. /* - - - - - - - - */
  406. //
  407. // Use our controlling object to call AddRef on Unknown
  408. //
  409. STDMETHODIMP_(ULONG) WaveFileAddRef(
  410. PAVIFILE pf)
  411. {
  412. // Get a pointer to our structure
  413. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_FILE(pf);
  414. return pWaveStuff->pUnknownOuter->lpVtbl->AddRef(
  415. pWaveStuff->pUnknownOuter);
  416. }
  417. /* - - - - - - - - */
  418. //
  419. // Use our controlling object to call Release on Unknown
  420. //
  421. STDMETHODIMP_(ULONG) WaveFileRelease(
  422. PAVIFILE pf)
  423. {
  424. // Get a pointer to our structure
  425. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_FILE(pf);
  426. return pWaveStuff->pUnknownOuter->lpVtbl->Release(
  427. pWaveStuff->pUnknownOuter);
  428. }
  429. /* - - - - - - - - */
  430. //
  431. // Use our controlling object to call QueryInterface on Unknown
  432. //
  433. STDMETHODIMP WavePersistQueryInterface(
  434. LPPERSISTFILE ppf,
  435. REFIID iid,
  436. void FAR* FAR* ppv)
  437. {
  438. // Get a pointer to our structure
  439. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_PERSIST(ppf);
  440. return pWaveStuff->pUnknownOuter->lpVtbl->QueryInterface(
  441. pWaveStuff->pUnknownOuter, iid, ppv);
  442. }
  443. /* - - - - - - - - */
  444. //
  445. // Use our controlling object to call AddRef on Unknown
  446. //
  447. STDMETHODIMP_(ULONG) WavePersistAddRef(
  448. LPPERSISTFILE ppf)
  449. {
  450. // Get a pointer to our structure
  451. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_PERSIST(ppf);
  452. return pWaveStuff->pUnknownOuter->lpVtbl->AddRef(
  453. pWaveStuff->pUnknownOuter);
  454. }
  455. /* - - - - - - - - */
  456. //
  457. // Use our controlling object to call Release on Unknown
  458. //
  459. STDMETHODIMP_(ULONG) WavePersistRelease(
  460. LPPERSISTFILE ppf)
  461. {
  462. // Get a pointer to our structure
  463. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_PERSIST(ppf);
  464. return pWaveStuff->pUnknownOuter->lpVtbl->Release(
  465. pWaveStuff->pUnknownOuter);
  466. }
  467. /* - - - - - - - - */
  468. //
  469. // Use our controlling object to call QueryInterface on Unknown
  470. //
  471. STDMETHODIMP WaveStreamQueryInterface(
  472. PAVISTREAM ps,
  473. REFIID iid,
  474. void FAR* FAR* ppv)
  475. {
  476. // Get a pointer to our structure
  477. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_STREAM(ps);
  478. return pWaveStuff->pUnknownOuter->lpVtbl->QueryInterface(
  479. pWaveStuff->pUnknownOuter, iid, ppv);
  480. }
  481. /* - - - - - - - - */
  482. //
  483. // Use our controlling object to call AddRef on Unknown
  484. //
  485. STDMETHODIMP_(ULONG) WaveStreamAddRef(
  486. PAVISTREAM ps)
  487. {
  488. // Get a pointer to our structure
  489. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_STREAM(ps);
  490. return pWaveStuff->pUnknownOuter->lpVtbl->AddRef(
  491. pWaveStuff->pUnknownOuter);
  492. }
  493. /* - - - - - - - - */
  494. //
  495. // Use our controlling object to call Release on Unknown
  496. //
  497. STDMETHODIMP_(ULONG) WaveStreamRelease(
  498. PAVISTREAM ps)
  499. {
  500. // Get a pointer to our structure
  501. LPWAVESTUFF pWaveStuff = WAVESTUFF_FROM_STREAM(ps);
  502. return pWaveStuff->pUnknownOuter->lpVtbl->Release(
  503. pWaveStuff->pUnknownOuter);
  504. }
  505. /* - - - - - - - - */
  506. #define SLASH(c) ((c) == TEXT('/') || (c) == TEXT('\\'))
  507. /*--------------------------------------------------------------+
  508. | FileName - return a pointer to the filename part of szPath |
  509. | with no preceding path. |
  510. | note: perhaps we should use GetFullPathName |
  511. +--------------------------------------------------------------*/
  512. LPTSTR FAR FileName(
  513. LPCTSTR lszPath)
  514. {
  515. LPCTSTR lszCur;
  516. for (lszCur = lszPath + lstrlen(lszPath); lszCur > lszPath && !SLASH(*lszCur) && *lszCur != ':';)
  517. lszCur = CharPrev(lszPath, lszCur);
  518. if (lszCur == lszPath)
  519. return (LPTSTR)lszCur;
  520. else
  521. return (LPTSTR)(lszCur + 1);
  522. }
  523. STDMETHODIMP ParseAUFile(LPWAVESTUFF p);
  524. /* - - - - - - - - */
  525. STDMETHODIMP ParseWaveFile(LPWAVESTUFF p)
  526. {
  527. MMCKINFO ck;
  528. MMCKINFO ckRIFF;
  529. /* Read RIFF chunk */
  530. if (shfileDescend(p->hshfile, &ckRIFF, NULL, 0) != 0)
  531. goto error;
  532. if (ckRIFF.ckid != FOURCC_RIFF || ckRIFF.fccType != formtypeWAVE)
  533. return ParseAUFile(p);
  534. /* Read WAVE format chunk */
  535. ck.ckid = ckidWAVEFORMAT;
  536. if (FindChunkAndKeepExtras(&p->extra, p->hshfile, &ck, &ckRIFF, MMIO_FINDCHUNK))
  537. goto error;
  538. p->cbFormat = ck.cksize;
  539. p->lpFormat = (LPWAVEFORMATEX) GlobalAllocPtr(GMEM_MOVEABLE, ck.cksize);
  540. if (p->lpFormat == NULL)
  541. goto error;
  542. if (shfileRead(p->hshfile,
  543. (HPSTR) p->lpFormat,
  544. (LONG)ck.cksize) != (LONG)ck.cksize)
  545. goto error;
  546. /* Ascend out of stream header */
  547. if (shfileAscend(p->hshfile, &ck, 0) != 0)
  548. goto error;
  549. /* Find big data chunk */
  550. p->ckData.ckid = ckidWAVEDATA;
  551. if (FindChunkAndKeepExtras(&p->extra, p->hshfile, &p->ckData, &ckRIFF, MMIO_FINDCHUNK))
  552. goto error;
  553. p->fDirty = FALSE;
  554. p->avistream.fccType = streamtypeAUDIO;
  555. p->avistream.fccHandler = 0;
  556. p->avistream.dwFlags = 0;
  557. p->avistream.wPriority = 0;
  558. p->avistream.wLanguage = 0;
  559. p->avistream.dwInitialFrames = 0;
  560. p->avistream.dwScale = p->lpFormat->nBlockAlign;
  561. p->avistream.dwRate = p->lpFormat->nAvgBytesPerSec;
  562. p->avistream.dwStart = 0;
  563. p->avistream.dwLength = p->ckData.cksize / p->lpFormat->nBlockAlign;
  564. p->avistream.dwSuggestedBufferSize = 0;
  565. p->avistream.dwSampleSize = p->lpFormat->nBlockAlign;
  566. #ifdef FPSHACK
  567. p->avihdr.dwLength = muldiv32(p->avistream.dwLength,
  568. p->avistream.dwScale * FPSHACK,
  569. p->avistream.dwRate);
  570. #else
  571. p->avihdr.dwScale = 1;
  572. p->avihdr.dwRate = p->lpFormat->nSamplesPerSec;
  573. p->avihdr.dwLength = muldiv32(p->ckData.cksize,
  574. p->lpFormat->nSamplesPerSec,
  575. p->lpFormat->nAvgBytesPerSec);
  576. #endif
  577. shfileAscend(p->hshfile, &p->ckData, 0);
  578. // Read extra data at end of file....
  579. if (FindChunkAndKeepExtras(&p->extra, p->hshfile, &ckRIFF, &ck, 0) != AVIERR_OK)
  580. goto error;
  581. return ResultFromScode(0); // success
  582. error:
  583. return ResultFromScode(AVIERR_FILEREAD);
  584. }
  585. //
  586. // The Open Method for our File interface - Open a WAVE file
  587. //
  588. STDMETHODIMP WaveFileOpen(
  589. PAVIFILE pf,
  590. LPCTSTR szFile,
  591. UINT mode)
  592. {
  593. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  594. UINT ui;
  595. TCHAR ach[80];
  596. HRESULT hr = NOERROR;
  597. // !!! Assumptions about the AVIFILE.DLL (which calls us):
  598. // We will only see READWRITE mode, never only WRITE mode.
  599. // if it ain't broke, don't fix it
  600. #if 0
  601. // force the share flags to the 'correct' values
  602. // If we're writing, use Exclusive mode. If we're reading, use DenyWrite.
  603. if (mode & OF_READWRITE) {
  604. mode = (mode & ~(MMIO_SHAREMODE)) | OF_SHARE_EXCLUSIVE;
  605. } else {
  606. mode = (mode & ~(MMIO_SHAREMODE)) | OF_SHARE_DENY_WRITE;
  607. }
  608. #endif
  609. //
  610. // try to open the actual file, first with share, then without.
  611. // You may need to use specific flags in order to open a file
  612. // that's already open by somebody else.
  613. //
  614. // If the first attempt fails, no system error box, please.
  615. ui = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  616. p->hshfile = shfileOpen((LPTSTR) szFile, NULL, MMIO_ALLOCBUF | mode);
  617. if (!p->hshfile && ((mode & MMIO_RWMODE) == OF_READ)) {
  618. // if the open fails, try again without the share flags.
  619. mode &= ~(MMIO_SHAREMODE);
  620. p->hshfile = shfileOpen((LPTSTR) szFile, NULL, MMIO_ALLOCBUF | mode);
  621. }
  622. SetErrorMode(ui);
  623. //
  624. // Now set up our structure
  625. //
  626. p->mode = mode;
  627. if (!p->hshfile)
  628. goto error;
  629. _fmemset(&p->avistream, 0, sizeof(p->avistream));
  630. // If this is defined, we pretend that the data is at FPSHACK "frames"
  631. // per second in the main header, otherwise we use the sample
  632. // rate of the audio, which looks somewhat strange in MPlayer.
  633. #define FPSHACK 1000
  634. _fmemset(&p->avihdr, 0, sizeof(p->avihdr));
  635. #ifdef FPSHACK
  636. //
  637. // Initialize our AVIFILEHEADER
  638. //
  639. p->avihdr.dwRate = FPSHACK;
  640. p->avihdr.dwScale = 1;
  641. #endif
  642. p->avihdr.dwStreams = 1;
  643. LoadUnicodeString(ghMod, IDS_FILETYPE, p->avihdr.szFileType,
  644. NUMELMS(p->avihdr.szFileType));
  645. //
  646. // Initialize our AVISTREAMHEADER
  647. //
  648. LoadString(ghMod, IDS_STREAMNAME, ach, NUMELMS(ach));
  649. {
  650. TCHAR achTemp[MAX_PATH];
  651. wsprintf(achTemp, ach, FileName(szFile));
  652. #ifdef UNICODE
  653. lstrzcpy (p->avistream.szName,achTemp,NUMELMS(p->avistream.szName));
  654. #else
  655. lstrzcpyAtoW (p->avistream.szName,achTemp,NUMELMS(p->avistream.szName));
  656. #endif
  657. }
  658. if (mode & OF_CREATE) { // Brand new file
  659. p->avistream.fccType = streamtypeAUDIO;
  660. p->avistream.fccHandler = 0;
  661. p->avistream.dwFlags = 0;
  662. p->avistream.wPriority = 0;
  663. p->avistream.wLanguage = 0;
  664. p->avistream.dwInitialFrames = 0;
  665. p->avistream.dwScale = 0;
  666. p->avistream.dwRate = 0;
  667. p->avistream.dwStart = 0;
  668. p->avistream.dwLength = 0;
  669. p->avistream.dwSuggestedBufferSize = 0;
  670. p->avistream.dwSampleSize = 0;
  671. p->fDirty = TRUE;
  672. } else { // read the existing file to get info
  673. hr = ParseWaveFile(p);
  674. }
  675. return hr;
  676. error:
  677. return ResultFromScode(AVIERR_FILEREAD);
  678. }
  679. typedef struct {
  680. DWORD magic; /* magic number SND_MAGIC */
  681. DWORD dataLocation; /* offset or poDWORDer to the data */
  682. DWORD dataSize; /* number of bytes of data */
  683. DWORD dataFormat; /* the data format code */
  684. DWORD samplingRate; /* the sampling rate */
  685. DWORD channelCount; /* the number of channels */
  686. DWORD fccInfo; /* optional text information */
  687. } SNDSoundStruct;
  688. #define SND_FORMAT_MULAW_8 1 // 8-bit mu-law samples
  689. #define SND_FORMAT_LINEAR_8 2 // 8-bit linear samples
  690. #define SWAP(x,y) ( (x)^=(y), (y)^=(x), (x)^=(y) )
  691. void _inline SwapDWORD( DWORD FAR * pdw )
  692. {
  693. SWAP(((BYTE FAR *)pdw)[0],((BYTE FAR *)pdw)[3]);
  694. SWAP(((BYTE FAR *)pdw)[1],((BYTE FAR *)pdw)[2]);
  695. }
  696. STDMETHODIMP ParseAUFile(LPWAVESTUFF p)
  697. {
  698. SNDSoundStruct header;
  699. shfileSeek(p->hshfile, 0, SEEK_SET);
  700. if (shfileRead(p->hshfile, (HPSTR) &header, sizeof(header)) != sizeof(header))
  701. goto error;
  702. // validate header
  703. // !!!
  704. if (header.magic != mmioFOURCC('.', 's', 'n', 'd'))
  705. goto error;
  706. SwapDWORD(&header.dataFormat);
  707. SwapDWORD(&header.dataLocation);
  708. SwapDWORD(&header.dataSize);
  709. SwapDWORD(&header.samplingRate);
  710. SwapDWORD(&header.channelCount);
  711. p->cbFormat = sizeof(WAVEFORMATEX);
  712. p->lpFormat = (LPWAVEFORMATEX) GlobalAllocPtr(GHND, p->cbFormat);
  713. if (p->lpFormat == NULL)
  714. goto error;
  715. p->mode = OF_READ | OF_SHARE_DENY_WRITE;
  716. // fill in wave format fields
  717. if (header.dataFormat == SND_FORMAT_MULAW_8) {
  718. p->lpFormat->wFormatTag = WAVE_FORMAT_MULAW;
  719. p->lpFormat->wBitsPerSample = 8;
  720. // !!! HACK: if the sampling rate is almost 8KHz, make it be
  721. // exactly 8KHz, so that more sound cards will play it right.
  722. if (header.samplingRate > 7980 && header.samplingRate < 8020)
  723. header.samplingRate = 8000;
  724. } else if (header.dataFormat == SND_FORMAT_LINEAR_8) {
  725. p->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
  726. p->lpFormat->wBitsPerSample = 8;
  727. // Could support LINEAR_16, but would have to byte-swap everything....
  728. } else
  729. goto error;
  730. p->lpFormat->nChannels = (UINT) header.channelCount;
  731. p->lpFormat->nSamplesPerSec = header.samplingRate;
  732. p->lpFormat->nAvgBytesPerSec = header.samplingRate * p->lpFormat->nChannels;
  733. p->lpFormat->nBlockAlign = 1;
  734. /* Tell rest of handler where data is */
  735. p->ckData.dwDataOffset = header.dataLocation;
  736. p->ckData.cksize = header.dataSize;
  737. p->fDirty = FALSE;
  738. p->avistream.fccType = streamtypeAUDIO;
  739. p->avistream.fccHandler = 0;
  740. p->avistream.dwFlags = 0;
  741. p->avistream.wPriority = 0;
  742. p->avistream.wLanguage = 0;
  743. p->avistream.dwInitialFrames = 0;
  744. p->avistream.dwScale = p->lpFormat->nBlockAlign;
  745. p->avistream.dwRate = p->lpFormat->nAvgBytesPerSec;
  746. p->avistream.dwStart = 0;
  747. p->avistream.dwLength = p->ckData.cksize / p->lpFormat->nBlockAlign;
  748. p->avistream.dwSuggestedBufferSize = 0;
  749. p->avistream.dwSampleSize = p->lpFormat->nBlockAlign;
  750. #ifdef FPSHACK
  751. p->avihdr.dwLength = muldiv32(p->avistream.dwLength,
  752. p->avistream.dwScale * FPSHACK,
  753. p->avistream.dwRate);
  754. #else
  755. p->avihdr.dwScale = 1;
  756. p->avihdr.dwRate = p->lpFormat->nSamplesPerSec;
  757. p->avihdr.dwLength = muldiv32(p->ckData.cksize,
  758. p->lpFormat->nSamplesPerSec,
  759. p->lpFormat->nAvgBytesPerSec);
  760. #endif
  761. return ResultFromScode(0); // success
  762. error:
  763. return ResultFromScode(AVIERR_FILEREAD);
  764. }
  765. //
  766. // Get a stream from the file... Each WAVE file has exactly 1 audio stream.
  767. //
  768. STDMETHODIMP WaveFileGetStream(
  769. PAVIFILE pf,
  770. PAVISTREAM FAR * ppavi,
  771. DWORD fccType,
  772. LONG lParam)
  773. {
  774. int iStreamWant;
  775. // Get a pointer to our structure
  776. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  777. iStreamWant = (int)lParam;
  778. if (p->lpFormat == NULL)
  779. return ResultFromScode(AVIERR_BADPARAM);
  780. // We only support one stream
  781. if (iStreamWant != 0)
  782. return ResultFromScode(AVIERR_BADPARAM);
  783. // We only support audio streams
  784. if (fccType && fccType != streamtypeAUDIO)
  785. return ResultFromScode(AVIERR_BADPARAM);
  786. // increase the reference count
  787. p->AVIStream->AddRef((PAVISTREAM)&p->AVIStream);
  788. // Return a pointer to our stream Vtbl
  789. *ppavi = (PAVISTREAM) &(p->AVIStream);
  790. return ResultFromScode(AVIERR_OK);
  791. }
  792. STDMETHODIMP WaveFileDeleteStream(PAVIFILE pf, DWORD fccType, LONG lParam)
  793. {
  794. int iStreamWant;
  795. // Get a pointer to our structure
  796. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  797. iStreamWant = (int)lParam;
  798. if (p->lpFormat == NULL)
  799. return ResultFromScode(AVIERR_BADPARAM);
  800. // We only support one stream
  801. if (iStreamWant != 0)
  802. return ResultFromScode(AVIERR_BADPARAM);
  803. // We only support audio streams
  804. if (fccType && fccType != streamtypeAUDIO)
  805. return ResultFromScode(AVIERR_BADPARAM);
  806. GlobalFreePtr(p->lpFormat);
  807. p->lpFormat = NULL;
  808. return NOERROR;
  809. }
  810. //
  811. // We don't support the Save Method of the File Interface (We don't save)
  812. //
  813. STDMETHODIMP WaveFileSave(
  814. PAVIFILE pf,
  815. LPCSTR szFile,
  816. AVICOMPRESSOPTIONS FAR *lpOptions,
  817. AVISAVECALLBACK lpfnCallback)
  818. {
  819. return ResultFromScode(AVIERR_UNSUPPORTED);
  820. }
  821. //
  822. // Method to create a stream in a WAVE file. We only support this for blank
  823. // WAVE files.
  824. //
  825. STDMETHODIMP WaveFileCreateStream(
  826. PAVIFILE pf,
  827. PAVISTREAM FAR *ppstream,
  828. AVISTREAMINFOW FAR *psi)
  829. {
  830. // Get a pointer to our structure
  831. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  832. // We can't add a second stream to a file
  833. if (p->lpFormat)
  834. return ResultFromScode(AVIERR_UNSUPPORTED);
  835. // We only like audio....
  836. if (psi->fccType != streamtypeAUDIO)
  837. return ResultFromScode(AVIERR_UNSUPPORTED);
  838. // Increase our reference count.
  839. p->AVIStream->AddRef((PAVISTREAM)&p->AVIStream);
  840. p->cbFormat = 0;
  841. p->lpFormat = NULL;
  842. // Return a pointer to our stream Vtbl.
  843. *ppstream = (PAVISTREAM) &(p->AVIStream);
  844. return ResultFromScode(AVIERR_OK);
  845. }
  846. //
  847. // The WriteData Method of the File interface
  848. //
  849. STDMETHODIMP WaveFileWriteData(
  850. PAVIFILE pf,
  851. DWORD ckid,
  852. LPVOID lpData,
  853. LONG cbData)
  854. {
  855. // Get a pointer to our structure
  856. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  857. // Write the data in the Wave File.
  858. return ResultFromScode(WriteExtra(&p->extra, ckid, lpData, cbData));
  859. }
  860. //
  861. // The ReadData Method of the File interface
  862. //
  863. STDMETHODIMP WaveFileReadData(
  864. PAVIFILE pf,
  865. DWORD ckid,
  866. LPVOID lpData,
  867. LONG FAR *lpcbData)
  868. {
  869. // Get a pointer to our structure
  870. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  871. // Read the data from the file
  872. return ResultFromScode(ReadExtra(&p->extra, ckid, lpData, lpcbData));
  873. }
  874. //
  875. // The EndRecord Method of the File interface.. this doesn't need to do
  876. // anything.. (no concept of interleaving or packaging streams)
  877. //
  878. STDMETHODIMP WaveFileEndRecord(
  879. PAVIFILE pf)
  880. {
  881. return ResultFromScode(AVIERR_OK);
  882. }
  883. //
  884. // The Info Method of the File interface
  885. //
  886. STDMETHODIMP WaveFileInfo(
  887. PAVIFILE pf,
  888. AVIFILEINFOW FAR * pfi,
  889. LONG lSize)
  890. {
  891. // Get a pointer to our structure
  892. LPWAVESTUFF p = WAVESTUFF_FROM_FILE(pf);
  893. // Return an AVIFILEHEADER.
  894. hmemcpy(pfi, &p->avihdr, min(lSize, sizeof(p->avihdr)));
  895. return 0;
  896. }
  897. //
  898. // The Create Method of the Stream interface. We can't create streams that
  899. // aren't attached to the file.
  900. //
  901. STDMETHODIMP WaveStreamCreate(
  902. PAVISTREAM ps,
  903. LPARAM lParam1,
  904. LPARAM lParam2)
  905. {
  906. return ResultFromScode(AVIERR_UNSUPPORTED);
  907. }
  908. //
  909. // The FindSample Method of the Stream interface
  910. //
  911. STDMETHODIMP_(LONG) WaveStreamFindSample(
  912. PAVISTREAM ps,
  913. LONG lPos, LONG lFlags)
  914. {
  915. if (lFlags & FIND_FORMAT) {
  916. if ((lFlags & FIND_NEXT) && lPos > 0)
  917. return -1;
  918. else
  919. return 0;
  920. }
  921. return lPos;
  922. }
  923. //
  924. // The ReadFormat Method of the Stream interface
  925. //
  926. STDMETHODIMP WaveStreamReadFormat(
  927. PAVISTREAM ps,
  928. LONG lPos,
  929. LPVOID lpFormat,
  930. LONG FAR *lpcbFormat)
  931. {
  932. // Get a pointer to our structure
  933. LPWAVESTUFF p = WAVESTUFF_FROM_STREAM(ps);
  934. // No buffer to fill in, this means return the size needed.
  935. if (lpFormat == NULL || *lpcbFormat == 0) {
  936. *lpcbFormat = p->cbFormat;
  937. return 0;
  938. }
  939. // Give them the WAVE format.
  940. hmemcpy(lpFormat, p->lpFormat, min(*lpcbFormat, p->cbFormat));
  941. // Our buffer is too small
  942. if (*lpcbFormat < p->cbFormat)
  943. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  944. *lpcbFormat = p->cbFormat;
  945. return 0;
  946. }
  947. //
  948. // The Info Method of the Stream interface
  949. //
  950. STDMETHODIMP WaveStreamInfo(
  951. PAVISTREAM ps,
  952. AVISTREAMINFOW FAR * psi,
  953. LONG lSize)
  954. {
  955. // Get a pointer to our structure
  956. LPWAVESTUFF p = WAVESTUFF_FROM_STREAM(ps);
  957. // give them an AVISTREAMINFO
  958. hmemcpy(psi, &p->avistream, min(lSize, sizeof(p->avistream)));
  959. return 0;
  960. }
  961. STDMETHODIMP WaveStreamSetInfo(PAVISTREAM ps, AVISTREAMINFOW FAR * psi, LONG lSize)
  962. {
  963. return ResultFromScode(AVIERR_UNSUPPORTED);
  964. }
  965. ///////////////////////////////////////////////////////////////////////////
  966. ///////////////////////////////////////////////////////////////////////////
  967. /*
  968. invalid lPos return error
  969. if lPos + lSamples is invalid trim lSamples to fit.
  970. lpBuffer == NULL
  971. cbBuffer == 0 && lSamples > 0
  972. return size of lSamples sample.
  973. else
  974. return the exactly the number of bytes and sample
  975. you would have read if lpBuffer was not zero.
  976. NOTE return means fill in *plBytes and *plSamples.
  977. lpBuffer != NULL
  978. lSamples == -1 read convenient amount (just fill buffer)
  979. lSamples == 0 fill buffer with as many samples that will fit.
  980. lSamples > 0 read lSamples (or as much will fit in cbBuffer)
  981. fill in *plBytes with bytes actualy read
  982. fill in *plSamples with samples actualy read
  983. */
  984. //
  985. // The Read Method for the Stream Interface - Read some wave data
  986. STDMETHODIMP WaveStreamRead(
  987. PAVISTREAM ps,
  988. LONG lStart,
  989. LONG lSamples,
  990. LPVOID lpBuffer,
  991. LONG cbBuffer,
  992. LONG FAR * plBytes,
  993. LONG FAR * plSamples)
  994. {
  995. // Get a pointer to our structure
  996. LPWAVESTUFF p = WAVESTUFF_FROM_STREAM(ps);
  997. LONG lSampleSize;
  998. LONG lSeek;
  999. LONG lRead;
  1000. // Invalid position
  1001. if (lStart < 0 || lStart > (LONG) p->avistream.dwLength) {
  1002. ack:
  1003. if (plBytes)
  1004. *plBytes = 0;
  1005. if (plSamples)
  1006. *plSamples = 0;
  1007. return 0;
  1008. }
  1009. // Can't read quite this much data
  1010. if (lSamples + lStart > (LONG) p->avistream.dwLength)
  1011. lSamples = p->avistream.dwLength - lStart;
  1012. lSampleSize = p->avistream.dwSampleSize;
  1013. // We have fixed-length samples
  1014. if (lpBuffer == NULL) {
  1015. if (cbBuffer > 0 && lSamples > 0)
  1016. // Trim how many samples we'd really be able to read
  1017. lSamples = min(lSamples, cbBuffer / lSampleSize);
  1018. else if (lSamples <= 0)
  1019. // Use as many as will fit
  1020. lSamples = cbBuffer / lSampleSize;
  1021. } else {
  1022. if (lSamples > 0)
  1023. // Trim how many samples we'd really be able to read
  1024. lSamples = min(lSamples, cbBuffer / lSampleSize);
  1025. else
  1026. // Use as many as will fit
  1027. lSamples = cbBuffer / lSampleSize;
  1028. }
  1029. //
  1030. // a NULL buffer means return the size buffer needed to read
  1031. // the given sample.
  1032. //
  1033. if (lpBuffer == NULL || cbBuffer == 0) {
  1034. if (plBytes)
  1035. *plBytes = lSamples * lSampleSize;;
  1036. if (plSamples)
  1037. *plSamples = lSamples;
  1038. return 0;
  1039. }
  1040. // Buffer too small!
  1041. if (cbBuffer < lSampleSize)
  1042. goto ack;
  1043. // Seek and read
  1044. cbBuffer = lSamples * lSampleSize;
  1045. lSeek = p->ckData.dwDataOffset + lSampleSize * lStart;
  1046. lRead = lSamples * lSampleSize;
  1047. if (shfileSeek(p->hshfile, lSeek, SEEK_SET) != lSeek)
  1048. goto ack;
  1049. if (shfileRead(p->hshfile, (HPSTR) lpBuffer, lRead) != lRead)
  1050. goto ack;
  1051. //
  1052. // success return number of bytes and number of samples read
  1053. //
  1054. if (plBytes)
  1055. *plBytes = lRead;
  1056. if (plSamples)
  1057. *plSamples = lSamples;
  1058. return ResultFromScode(AVIERR_OK);
  1059. }
  1060. //
  1061. // The SetFormat Method of the Stream interface - called on an empty WAVE file
  1062. // before writing data to it.
  1063. //
  1064. STDMETHODIMP WaveStreamSetFormat(
  1065. PAVISTREAM ps,
  1066. LONG lPos,
  1067. LPVOID lpFormat,
  1068. LONG cbFormat)
  1069. {
  1070. // Get a pointer to our structure
  1071. LPWAVESTUFF p = WAVESTUFF_FROM_STREAM(ps);
  1072. // We can only do this to an empty wave file
  1073. if (p->lpFormat) {
  1074. if (cbFormat != p->cbFormat ||
  1075. _fmemcmp(lpFormat, p->lpFormat, (int) cbFormat))
  1076. return ResultFromScode(AVIERR_UNSUPPORTED);
  1077. return NOERROR;
  1078. }
  1079. // Go ahead and set the format!
  1080. p->cbFormat = cbFormat;
  1081. p->lpFormat = (LPWAVEFORMATEX) GlobalAllocPtr(GMEM_MOVEABLE, cbFormat);
  1082. if (p->lpFormat == NULL)
  1083. return ResultFromScode(AVIERR_MEMORY);
  1084. hmemcpy(p->lpFormat, lpFormat, cbFormat);
  1085. p->ckData.dwDataOffset = cbFormat + 7 * sizeof(DWORD);
  1086. p->ckData.cksize = 0;
  1087. p->avistream.dwScale = p->lpFormat->nBlockAlign;
  1088. p->avistream.dwRate = p->lpFormat->nAvgBytesPerSec;
  1089. p->avistream.dwLength = 0;
  1090. p->avistream.dwSampleSize = p->lpFormat->nBlockAlign;
  1091. #ifndef FPSHACK
  1092. p->avihdr.dwScale = 1;
  1093. p->avihdr.dwRate = p->lpFormat->nSamplesPerSec;
  1094. #endif
  1095. return ResultFromScode(AVIERR_OK);
  1096. }
  1097. //
  1098. // The Write Method of the Stream interface - write some wave data
  1099. //
  1100. STDMETHODIMP WaveStreamWrite(
  1101. PAVISTREAM ps,
  1102. LONG lStart,
  1103. LONG lSamples,
  1104. LPVOID lpData,
  1105. LONG cbData,
  1106. DWORD dwFlags,
  1107. LONG FAR *plSampWritten,
  1108. LONG FAR *plBytesWritten)
  1109. {
  1110. // Get a pointer to our structure
  1111. LPWAVESTUFF p = WAVESTUFF_FROM_STREAM(ps);
  1112. if ((p->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1113. return ResultFromScode(AVIERR_READONLY);
  1114. // < 0 means "at end"
  1115. if (lStart < 0)
  1116. // !!!
  1117. lStart = p->avistream.dwStart + p->avistream.dwLength;
  1118. #if 0 // !!! don't check for too long - why not?
  1119. if (lStart > (LONG) (p->avistream.dwStart + p->avistream.dwLength))
  1120. return ResultFromScode(AVIERR_BADPARAM);
  1121. #endif
  1122. p->fDirty = TRUE;
  1123. shfileSeek(p->hshfile,
  1124. p->ckData.dwDataOffset +
  1125. lStart * p->avistream.dwSampleSize,
  1126. SEEK_SET);
  1127. if (shfileWrite(p->hshfile, (HPSTR) lpData, cbData) != cbData)
  1128. return ResultFromScode(AVIERR_FILEWRITE);
  1129. p->avistream.dwLength = max((LONG) p->avistream.dwLength,
  1130. lStart + lSamples);
  1131. p->ckData.cksize = max(p->ckData.cksize,
  1132. lStart * p->avistream.dwSampleSize + cbData);
  1133. #ifdef FPSHACK
  1134. p->avihdr.dwLength = muldiv32(p->avistream.dwLength * FPSHACK,
  1135. p->avistream.dwScale,
  1136. p->avistream.dwRate);
  1137. #else
  1138. p->avihdr.dwLength = muldiv32(p->ckData.cksize,
  1139. p->lpFormat->nSamplesPerSec,
  1140. p->lpFormat->nAvgBytesPerSec);
  1141. #endif
  1142. if (plSampWritten)
  1143. *plSampWritten = lSamples;
  1144. if (plBytesWritten)
  1145. *plBytesWritten = cbData;
  1146. return ResultFromScode(AVIERR_OK);
  1147. }
  1148. //
  1149. // The Delete Method of the Stream interface - we don't cut from wave files
  1150. //
  1151. STDMETHODIMP WaveStreamDelete(
  1152. PAVISTREAM ps,
  1153. LONG lStart,
  1154. LONG lSamples)
  1155. {
  1156. return ResultFromScode(AVIERR_UNSUPPORTED);
  1157. }
  1158. //
  1159. // We also don't support ReadData and WriteData for the Stream Interface
  1160. //
  1161. STDMETHODIMP WaveStreamReadData(
  1162. PAVISTREAM ps,
  1163. DWORD fcc,
  1164. LPVOID lp,
  1165. LONG FAR *lpcb)
  1166. {
  1167. return ResultFromScode(AVIERR_UNSUPPORTED);
  1168. }
  1169. STDMETHODIMP WaveStreamWriteData(
  1170. PAVISTREAM ps,
  1171. DWORD fcc,
  1172. LPVOID lp,
  1173. LONG cb)
  1174. {
  1175. return ResultFromScode(AVIERR_UNSUPPORTED);
  1176. }
  1177. STDMETHODIMP WaveFileReserved(
  1178. PAVIFILE pf)
  1179. {
  1180. return ResultFromScode(AVIERR_UNSUPPORTED);
  1181. }
  1182. STDMETHODIMP WaveStreamReserved(
  1183. PAVISTREAM ps)
  1184. {
  1185. return ResultFromScode(AVIERR_UNSUPPORTED);
  1186. }
  1187. /* - - - - - - - - */
  1188. // *** IPersist methods ***
  1189. STDMETHODIMP WavePersistGetClassID (LPPERSISTFILE ppf, LPCLSID lpClassID)
  1190. {
  1191. // Get a pointer to our structure
  1192. LPWAVESTUFF pfile = WAVESTUFF_FROM_PERSIST(ppf);
  1193. // hmemcpy(lpClassID, &CLSID_AVIWaveFileReader, sizeof(CLSID));
  1194. return NOERROR;
  1195. }
  1196. // *** IPersistFile methods ***
  1197. STDMETHODIMP WavePersistIsDirty (LPPERSISTFILE ppf)
  1198. {
  1199. // Get a pointer to our structure
  1200. LPWAVESTUFF pfile = WAVESTUFF_FROM_PERSIST(ppf);
  1201. return pfile->fDirty ? NOERROR : ResultFromScode(S_FALSE);
  1202. }
  1203. STDMETHODIMP WavePersistLoad (LPPERSISTFILE ppf,
  1204. LPCOLESTR lpszFileName, DWORD grfMode)
  1205. {
  1206. // Get a pointer to our structure
  1207. LPWAVESTUFF pfile = WAVESTUFF_FROM_PERSIST(ppf);
  1208. #if defined _WIN32 && !defined UNICODE
  1209. char achTemp[256];
  1210. // Internally, we're using ANSI, but this interface is defined
  1211. // to always accept UNICODE under _WIN32, so we have to convert.
  1212. lstrzcpyWtoA (achTemp, lpszFileName, NUMELMS(achTemp));
  1213. #else
  1214. #define achTemp lpszFileName
  1215. #endif
  1216. return WaveFileOpen((PAVIFILE) &pfile->AVIFile, achTemp, (UINT) grfMode);
  1217. }
  1218. STDMETHODIMP WavePersistSave (LPPERSISTFILE ppf,
  1219. LPCOLESTR lpszFileName, BOOL fRemember)
  1220. {
  1221. // Get a pointer to our structure
  1222. LPWAVESTUFF pfile = WAVESTUFF_FROM_PERSIST(ppf);
  1223. return ResultFromScode(E_FAIL);
  1224. }
  1225. STDMETHODIMP WavePersistSaveCompleted (LPPERSISTFILE ppf,
  1226. LPCOLESTR lpszFileName)
  1227. {
  1228. // Get a pointer to our structure
  1229. LPWAVESTUFF pfile = WAVESTUFF_FROM_PERSIST(ppf);
  1230. return NOERROR;
  1231. }
  1232. STDMETHODIMP WavePersistGetCurFile (LPPERSISTFILE ppf,
  1233. LPOLESTR FAR * lplpszFileName)
  1234. {
  1235. // Get a pointer to our structure
  1236. LPWAVESTUFF pfile = WAVESTUFF_FROM_PERSIST(ppf);
  1237. return ResultFromScode(E_FAIL);
  1238. }