Leaked source code of windows server 2003
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.

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