d3d9: Remove the fog vs sRGB test.
[wine] / dlls / ole32 / filelockbytes.c
1 /******************************************************************************
2  *
3  * File-based ILockBytes implementation
4  *
5  * Copyright 1999 Thuy Nguyen
6  * Copyright 2010 Vincent Povirk for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <limits.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winuser.h"
37 #include "winerror.h"
38 #include "objbase.h"
39 #include "ole2.h"
40
41 #include "storage32.h"
42
43 #include "wine/debug.h"
44 #include "wine/unicode.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(storage);
47
48 typedef struct FileLockBytesImpl
49 {
50     const ILockBytesVtbl *lpVtbl;
51     LONG ref;
52     ULARGE_INTEGER filesize;
53     HANDLE hfile;
54     DWORD flProtect;
55     LPWSTR pwcsName;
56 } FileLockBytesImpl;
57
58 static const ILockBytesVtbl FileLockBytesImpl_Vtbl;
59
60 /***********************************************************
61  * Prototypes for private methods
62  */
63
64 /* Note that this evaluates a and b multiple times, so don't
65  * pass expressions with side effects. */
66 #define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
67
68 /****************************************************************************
69  *      GetProtectMode
70  *
71  * This function will return a protection mode flag for a file-mapping object
72  * from the open flags of a file.
73  */
74 static DWORD GetProtectMode(DWORD openFlags)
75 {
76     switch(STGM_ACCESS_MODE(openFlags))
77     {
78     case STGM_WRITE:
79     case STGM_READWRITE:
80         return PAGE_READWRITE;
81     }
82     return PAGE_READONLY;
83 }
84
85 /******************************************************************************
86  *      FileLockBytesImpl_Construct
87  *
88  * Initialize a big block object supported by a file.
89  */
90 HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes)
91 {
92   FileLockBytesImpl *This;
93   WCHAR fullpath[MAX_PATH];
94
95   if (hFile == INVALID_HANDLE_VALUE)
96     return E_FAIL;
97
98   This = HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl));
99
100   if (!This)
101     return E_OUTOFMEMORY;
102
103   This->lpVtbl = &FileLockBytesImpl_Vtbl;
104   This->ref = 1;
105   This->hfile = hFile;
106   This->filesize.u.LowPart = GetFileSize(This->hfile,
107                                          &This->filesize.u.HighPart);
108   This->flProtect = GetProtectMode(openFlags);
109
110   if(pwcsName) {
111     if (!GetFullPathNameW(pwcsName, MAX_PATH, fullpath, NULL))
112     {
113       lstrcpynW(fullpath, pwcsName, MAX_PATH);
114     }
115     This->pwcsName = HeapAlloc(GetProcessHeap(), 0,
116                               (lstrlenW(fullpath)+1)*sizeof(WCHAR));
117     if (!This->pwcsName)
118     {
119        HeapFree(GetProcessHeap(), 0, This);
120        return E_OUTOFMEMORY;
121     }
122     strcpyW(This->pwcsName, fullpath);
123   }
124   else
125     This->pwcsName = NULL;
126
127   TRACE("file len %u\n", This->filesize.u.LowPart);
128
129   *pLockBytes = (ILockBytes*)This;
130
131   return S_OK;
132 }
133
134 /* ILockByte Interfaces */
135
136 static HRESULT WINAPI FileLockBytesImpl_QueryInterface(ILockBytes *iface, REFIID riid,
137     void **ppvObject)
138 {
139     if (IsEqualIID(riid, &IID_ILockBytes) || IsEqualIID(riid, &IID_ILockBytes))
140         *ppvObject = iface;
141     else
142     {
143         *ppvObject = NULL;
144         return E_NOINTERFACE;
145     }
146
147     IUnknown_AddRef((IUnknown*)*ppvObject);
148
149     return S_OK;
150 }
151
152 static ULONG WINAPI FileLockBytesImpl_AddRef(ILockBytes *iface)
153 {
154     FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
155     return InterlockedIncrement(&This->ref);
156 }
157
158 static ULONG WINAPI FileLockBytesImpl_Release(ILockBytes *iface)
159 {
160     FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
161     ULONG ref;
162
163     ref = InterlockedDecrement(&This->ref);
164
165     if (ref == 0)
166     {
167         CloseHandle(This->hfile);
168         HeapFree(GetProcessHeap(), 0, This->pwcsName);
169         HeapFree(GetProcessHeap(), 0, This);
170     }
171
172     return ref;
173 }
174
175 /******************************************************************************
176  * This method is part of the ILockBytes interface.
177  *
178  * It reads a block of information from the byte array at the specified
179  * offset.
180  *
181  * See the documentation of ILockBytes for more info.
182  */
183 static HRESULT WINAPI FileLockBytesImpl_ReadAt(
184       ILockBytes* iface,
185       ULARGE_INTEGER ulOffset,  /* [in] */
186       void*          pv,        /* [length_is][size_is][out] */
187       ULONG          cb,        /* [in] */
188       ULONG*         pcbRead)   /* [out] */
189 {
190     FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
191     ULONG bytes_left = cb;
192     LPBYTE readPtr = pv;
193     BOOL ret;
194     LARGE_INTEGER offset;
195     ULONG cbRead;
196
197     TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead);
198
199     /* verify a sane environment */
200     if (!This) return E_FAIL;
201
202     if (pcbRead)
203         *pcbRead = 0;
204
205     offset.QuadPart = ulOffset.QuadPart;
206
207     ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
208
209     if (!ret)
210         return STG_E_READFAULT;
211
212     while (bytes_left)
213     {
214         ret = ReadFile(This->hfile, readPtr, bytes_left, &cbRead, NULL);
215
216         if (!ret || cbRead == 0)
217             return STG_E_READFAULT;
218
219         if (pcbRead)
220             *pcbRead += cbRead;
221
222         bytes_left -= cbRead;
223         readPtr += cbRead;
224     }
225
226     TRACE("finished\n");
227     return S_OK;
228 }
229
230 /******************************************************************************
231  * This method is part of the ILockBytes interface.
232  *
233  * It writes the specified bytes at the specified offset.
234  * position. If the file is too small, it will be resized.
235  *
236  * See the documentation of ILockBytes for more info.
237  */
238 static HRESULT WINAPI FileLockBytesImpl_WriteAt(
239       ILockBytes* iface,
240       ULARGE_INTEGER ulOffset,    /* [in] */
241       const void*    pv,          /* [size_is][in] */
242       ULONG          cb,          /* [in] */
243       ULONG*         pcbWritten)  /* [out] */
244 {
245     FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
246     ULONG size_needed = ulOffset.u.LowPart + cb;
247     ULONG bytes_left = cb;
248     const BYTE *writePtr = pv;
249     BOOL ret;
250     LARGE_INTEGER offset;
251     ULONG cbWritten;
252
253     TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten);
254
255     /* verify a sane environment */
256     if (!This) return E_FAIL;
257
258     if (This->flProtect != PAGE_READWRITE)
259         return STG_E_ACCESSDENIED;
260
261     if (pcbWritten)
262         *pcbWritten = 0;
263
264     if (size_needed > This->filesize.u.LowPart)
265     {
266         ULARGE_INTEGER newSize;
267         newSize.u.HighPart = 0;
268         newSize.u.LowPart = size_needed;
269         ILockBytes_SetSize(iface, newSize);
270     }
271
272     offset.QuadPart = ulOffset.QuadPart;
273
274     ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN);
275
276     if (!ret)
277         return STG_E_READFAULT;
278
279     while (bytes_left)
280     {
281         ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL);
282
283         if (!ret)
284             return STG_E_READFAULT;
285
286         if (pcbWritten)
287             *pcbWritten += cbWritten;
288
289         bytes_left -= cbWritten;
290         writePtr += cbWritten;
291     }
292
293     TRACE("finished\n");
294     return S_OK;
295 }
296
297 static HRESULT WINAPI FileLockBytesImpl_Flush(ILockBytes* iface)
298 {
299     return S_OK;
300 }
301
302 /******************************************************************************
303  *      ILockBytes_SetSize
304  *
305  * Sets the size of the file.
306  *
307  */
308 static HRESULT WINAPI FileLockBytesImpl_SetSize(ILockBytes* iface, ULARGE_INTEGER newSize)
309 {
310     FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
311     HRESULT hr = S_OK;
312     LARGE_INTEGER newpos;
313
314     if (This->filesize.u.LowPart == newSize.u.LowPart)
315         return hr;
316
317     TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart);
318
319     newpos.QuadPart = newSize.QuadPart;
320     if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN))
321     {
322         SetEndOfFile(This->hfile);
323     }
324
325     This->filesize = newSize;
326     return hr;
327 }
328
329 static HRESULT WINAPI FileLockBytesImpl_LockRegion(ILockBytes* iface,
330     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
331 {
332     FIXME("stub\n");
333     return E_NOTIMPL;
334 }
335
336 static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(ILockBytes* iface,
337     ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
338 {
339     FIXME("stub\n");
340     return E_NOTIMPL;
341 }
342
343 static HRESULT WINAPI FileLockBytesImpl_Stat(ILockBytes* iface,
344     STATSTG *pstatstg, DWORD grfStatFlag)
345 {
346     FileLockBytesImpl* This = (FileLockBytesImpl*)iface;
347
348     if (!(STATFLAG_NONAME & grfStatFlag) && This->pwcsName)
349     {
350         pstatstg->pwcsName =
351           CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
352
353         strcpyW(pstatstg->pwcsName, This->pwcsName);
354     }
355     else
356         pstatstg->pwcsName = NULL;
357
358     pstatstg->type = STGTY_LOCKBYTES;
359     pstatstg->cbSize = This->filesize;
360     /* FIXME: If the implementation is exported, we'll need to set other fields. */
361
362     return S_OK;
363 }
364
365 static const ILockBytesVtbl FileLockBytesImpl_Vtbl = {
366     FileLockBytesImpl_QueryInterface,
367     FileLockBytesImpl_AddRef,
368     FileLockBytesImpl_Release,
369     FileLockBytesImpl_ReadAt,
370     FileLockBytesImpl_WriteAt,
371     FileLockBytesImpl_Flush,
372     FileLockBytesImpl_SetSize,
373     FileLockBytesImpl_LockRegion,
374     FileLockBytesImpl_UnlockRegion,
375     FileLockBytesImpl_Stat
376 };