Avoid excessive heap memory reallocation when generating EMF
[wine] / dlls / dmloader / loaderstream.c
1 /* ILoaderStream Implementation
2  *
3  * Copyright (C) 2003 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #define NONAMELESSUNION
21 #define NONAMELESSSTRUCT
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "wingdi.h"
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30
31 #include "dmloader_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(dmloader);
34
35 /*****************************************************************************
36  * Custom functions:
37  */
38 HRESULT WINAPI ILoaderStream_Attach (ILoaderStream* This, LPCWSTR wzFile, IDirectMusicLoader *pLoader)
39 {
40         TRACE("(%p, %s, %p)\n", This, debugstr_w(wzFile), pLoader);
41         ILoaderStream_Detach (This);
42         This->hFile = CreateFileW (wzFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
43     if (This->hFile == INVALID_HANDLE_VALUE) {
44                 TRACE(": failed\n");
45         return E_FAIL;
46     }
47         /* create IDirectMusicGetLoader */
48     (LPDIRECTMUSICLOADER)This->pLoader = pLoader;
49     strncpyW (This->wzFileName, wzFile, MAX_PATH);
50         TRACE(": succeeded\n");
51         
52     return S_OK;
53 }
54
55 void WINAPI ILoaderStream_Detach (ILoaderStream* This)
56 {
57         if (This->hFile != INVALID_HANDLE_VALUE) {
58         CloseHandle(This->hFile);
59     }
60     This->wzFileName[0] = (L'\0');
61 }
62
63 /*****************************************************************************
64  * ILoaderStream IStream:
65  */
66 HRESULT WINAPI ILoaderStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj)
67 {
68         ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
69         
70         if (IsEqualIID (riid, &IID_IUnknown)
71                 || IsEqualIID (riid, &IID_IStream)) {
72                 *ppobj = (LPVOID)&This->StreamVtbl;
73                 ILoaderStream_IStream_AddRef (iface);
74                 return S_OK;
75         } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) {
76                 *ppobj = (LPVOID)&This->GetLoaderVtbl;
77                 ILoaderStream_IStream_AddRef (iface);           
78                 return S_OK;
79         }
80
81         WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
82         return E_NOINTERFACE;
83 }
84
85 ULONG WINAPI ILoaderStream_IStream_AddRef (LPSTREAM iface)
86 {
87         ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
88         TRACE("(%p) : AddRef from %ld\n", This, This->ref);
89         return ++(This->ref);
90 }
91
92 ULONG WINAPI ILoaderStream_IStream_Release (LPSTREAM iface)
93 {
94         ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
95         ULONG ref = --This->ref;
96         TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
97         if (ref == 0) {
98                 HeapFree(GetProcessHeap(), 0, This);
99         }
100         return ref;
101 }
102
103 HRESULT WINAPI ILoaderStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead)
104 {
105         ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
106     ULONG cbRead;
107
108     if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
109     if (pcbRead == NULL) pcbRead = &cbRead;
110     if (!ReadFile (This->hFile, pv, cb, pcbRead, NULL) || *pcbRead != cb) return E_FAIL;
111
112     return S_OK;
113 }
114
115 HRESULT WINAPI ILoaderStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
116 {
117         ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
118     LARGE_INTEGER liNewPos;
119
120         if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL;
121
122     liNewPos.s.HighPart = dlibMove.s.HighPart;
123     liNewPos.s.LowPart = SetFilePointer (This->hFile, dlibMove.s.LowPart, &liNewPos.s.HighPart, dwOrigin);
124
125     if (liNewPos.s.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) return E_FAIL;
126     if (plibNewPosition) plibNewPosition->QuadPart = liNewPos.QuadPart;
127     
128     return S_OK;
129 }
130
131 HRESULT WINAPI ILoaderStream_IStream_Clone (LPSTREAM iface, IStream** ppstm)
132 {
133         ICOM_THIS_MULTI(ILoaderStream, StreamVtbl, iface);
134         ILoaderStream* pOther = NULL;
135         HRESULT result;
136
137         TRACE("(%p, %p)\n", iface, ppstm);
138         result = DMUSIC_CreateLoaderStream ((LPSTREAM*)&pOther);
139         if (FAILED(result)) return result;
140         if (This->hFile != INVALID_HANDLE_VALUE) {
141                 ULARGE_INTEGER ullCurrentPosition;
142                 result = ILoaderStream_Attach (pOther, This->wzFileName, (LPDIRECTMUSICLOADER)This->pLoader);
143                 if (SUCCEEDED(result)) {
144                         LARGE_INTEGER liZero;
145                         liZero.QuadPart = 0;
146                         result = ILoaderStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */
147         }
148                 if (SUCCEEDED(result)) {
149                         LARGE_INTEGER liNewPosition;
150                         liNewPosition.QuadPart = ullCurrentPosition.QuadPart;
151                         result = ILoaderStream_IStream_Seek ((LPSTREAM)pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition);
152                 }
153                 if (FAILED(result)) {
154                         TRACE(": failed\n");
155                         ILoaderStream_IStream_Release ((LPSTREAM)pOther);
156                         return result;
157                 }
158         }
159         TRACE(": succeeded\n");
160         *ppstm = (IStream*)pOther;
161         return S_OK;
162 }
163
164 /* not needed*/
165 HRESULT WINAPI ILoaderStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten)
166 {
167         ERR(": should not be needed\n");
168         return E_NOTIMPL;
169 }
170
171 HRESULT WINAPI ILoaderStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize)
172 {
173         ERR(": should not be needed\n");
174     return E_NOTIMPL;
175 }
176
177 HRESULT WINAPI ILoaderStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
178 {
179         ERR(": should not be needed\n");
180     return E_NOTIMPL;
181 }
182
183 HRESULT WINAPI ILoaderStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags)
184 {
185         ERR(": should not be needed\n");
186     return E_NOTIMPL;
187 }
188
189 HRESULT WINAPI ILoaderStream_IStream_Revert (LPSTREAM iface)
190 {
191         ERR(": should not be needed\n");
192     return E_NOTIMPL;
193 }
194
195 HRESULT WINAPI ILoaderStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
196 {
197         ERR(": should not be needed\n");
198     return E_NOTIMPL;
199 }
200
201 HRESULT WINAPI ILoaderStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
202 {
203         ERR(": should not be needed\n");
204     return E_NOTIMPL;
205 }
206
207 HRESULT WINAPI ILoaderStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag)
208 {
209         ERR(": should not be needed\n");
210     return E_NOTIMPL;
211 }
212
213 ICOM_VTABLE(IStream) LoaderStream_Stream_Vtbl =
214 {
215     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
216         ILoaderStream_IStream_QueryInterface,
217         ILoaderStream_IStream_AddRef,
218         ILoaderStream_IStream_Release,
219         ILoaderStream_IStream_Read,
220         ILoaderStream_IStream_Write,
221         ILoaderStream_IStream_Seek,
222         ILoaderStream_IStream_SetSize,
223         ILoaderStream_IStream_CopyTo,
224         ILoaderStream_IStream_Commit,
225         ILoaderStream_IStream_Revert,
226         ILoaderStream_IStream_LockRegion,
227         ILoaderStream_IStream_UnlockRegion,
228         ILoaderStream_IStream_Stat,
229         ILoaderStream_IStream_Clone
230 };
231
232 /*****************************************************************************
233  * ILoaderStream IDirectMusicGetLoader:
234  */
235 HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj)
236 {
237         ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
238         return ILoaderStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj);
239 }
240
241 ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface)
242 {
243         ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
244         return ILoaderStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl);
245 }
246
247 ULONG WINAPI ILoaderStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface)
248 {
249         ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
250         return ILoaderStream_IStream_Release ((LPSTREAM)&This->StreamVtbl);
251 }
252
253 HRESULT WINAPI ILoaderStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader)
254 {
255         ICOM_THIS_MULTI(ILoaderStream, GetLoaderVtbl, iface);
256
257         TRACE("(%p, %p)\n", This, ppLoader);
258         *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader;
259         IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader);
260         
261         return S_OK;
262 }
263
264 ICOM_VTABLE(IDirectMusicGetLoader) LoaderStream_GetLoader_Vtbl =
265 {
266     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
267         ILoaderStream_IDirectMusicGetLoader_QueryInterface,
268         ILoaderStream_IDirectMusicGetLoader_AddRef,
269         ILoaderStream_IDirectMusicGetLoader_Release,
270         ILoaderStream_IDirectMusicGetLoader_GetLoader
271 };
272
273
274 HRESULT WINAPI DMUSIC_CreateLoaderStream (LPSTREAM* ppStream)
275 {
276         ILoaderStream *pStream;
277
278         TRACE("(%p)\n", ppStream);
279
280         pStream = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(ILoaderStream));
281         if (NULL == pStream) {
282                 *ppStream = (LPSTREAM)NULL;
283                 return E_OUTOFMEMORY;
284         }
285         pStream->StreamVtbl = &LoaderStream_Stream_Vtbl;
286         pStream->GetLoaderVtbl = &LoaderStream_GetLoader_Vtbl;
287         pStream->ref = 1;
288         
289         *ppStream = (LPSTREAM)pStream;
290         return S_OK;
291 }