Fix the bounds checking in SHGetPathFromIDListA/W.
[wine] / dlls / shell32 / folders.c
1 /*
2  *      Copyright 1997  Marcus Meissner
3  *      Copyright 1998  Juergen Schmied
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "undocshell.h"
32 #include "shlguid.h"
33
34 #include "wine/debug.h"
35 #include "winerror.h"
36
37 #include "pidl.h"
38 #include "shell32_main.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41
42 /***********************************************************************
43 *   IExtractIconW implementation
44 */
45 typedef struct
46 {
47         ICOM_VFIELD(IExtractIconW);
48         DWORD   ref;
49         ICOM_VTABLE(IPersistFile)*      lpvtblPersistFile;
50         ICOM_VTABLE(IExtractIconA)*     lpvtblExtractIconA;
51         LPITEMIDLIST    pidl;
52 } IExtractIconWImpl;
53
54 static struct ICOM_VTABLE(IExtractIconA) eiavt;
55 static struct ICOM_VTABLE(IExtractIconW) eivt;
56 static struct ICOM_VTABLE(IPersistFile) pfvt;
57
58 #define _IPersistFile_Offset ((int)(&(((IExtractIconWImpl*)0)->lpvtblPersistFile)))
59 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
60
61 #define _IExtractIconA_Offset ((int)(&(((IExtractIconWImpl*)0)->lpvtblExtractIconA)))
62 #define _ICOM_THIS_From_IExtractIconA(class, name) class* This = (class*)(((char*)name)-_IExtractIconA_Offset);
63
64 /**************************************************************************
65 *  IExtractIconW_Constructor
66 */
67 IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl)
68 {
69         IExtractIconWImpl* ei;
70         
71         TRACE("%p\n", pidl);
72
73         ei = (IExtractIconWImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IExtractIconWImpl));
74         ei->ref=1;
75         ei->lpVtbl = &eivt;
76         ei->lpvtblPersistFile = &pfvt;
77         ei->lpvtblExtractIconA = &eiavt;
78         ei->pidl=ILClone(pidl);
79
80         pdump(pidl);
81
82         TRACE("(%p)\n", ei);
83         return (IExtractIconW *)ei;
84 }
85 /**************************************************************************
86  *  IExtractIconW_QueryInterface
87  */
88 static HRESULT WINAPI IExtractIconW_fnQueryInterface(IExtractIconW *iface, REFIID riid, LPVOID *ppvObj)
89 {
90         ICOM_THIS(IExtractIconWImpl, iface);
91
92         TRACE("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid(riid), ppvObj);
93
94         *ppvObj = NULL;
95
96         if (IsEqualIID(riid, &IID_IUnknown))                            /*IUnknown*/
97         {
98           *ppvObj = This;
99         }
100         else if (IsEqualIID(riid, &IID_IPersistFile))   /*IExtractIcon*/
101         {
102           *ppvObj = (IPersistFile*)&(This->lpvtblPersistFile);
103         }
104         else if (IsEqualIID(riid, &IID_IExtractIconA))  /*IExtractIcon*/
105         {
106           *ppvObj = (IExtractIconA*)&(This->lpvtblExtractIconA);
107         }
108         else if (IsEqualIID(riid, &IID_IExtractIconW))  /*IExtractIcon*/
109         {
110           *ppvObj = (IExtractIconW*)This;
111         }
112
113         if(*ppvObj)
114         {
115           IExtractIconW_AddRef((IExtractIconW*) *ppvObj);
116           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
117           return S_OK;
118         }
119         TRACE("-- Interface: E_NOINTERFACE\n");
120         return E_NOINTERFACE;
121 }
122
123 /**************************************************************************
124 *  IExtractIconW_AddRef
125 */
126 static ULONG WINAPI IExtractIconW_fnAddRef(IExtractIconW * iface)
127 {
128         ICOM_THIS(IExtractIconWImpl, iface);
129
130         TRACE("(%p)->(count=%lu)\n",This, This->ref );
131
132         return ++(This->ref);
133 }
134 /**************************************************************************
135 *  IExtractIconW_Release
136 */
137 static ULONG WINAPI IExtractIconW_fnRelease(IExtractIconW * iface)
138 {
139         ICOM_THIS(IExtractIconWImpl, iface);
140
141         TRACE("(%p)->()\n",This);
142
143         if (!--(This->ref))
144         {
145           TRACE(" destroying IExtractIcon(%p)\n",This);
146           SHFree(This->pidl);
147           HeapFree(GetProcessHeap(),0,This);
148           return 0;
149         }
150         return This->ref;
151 }
152
153 WCHAR swShell32Name[MAX_PATH];
154 char sShell32Name[MAX_PATH];
155
156 /**************************************************************************
157 *  IExtractIconW_GetIconLocation
158 *
159 * mapping filetype to icon
160 */
161 static HRESULT WINAPI IExtractIconW_fnGetIconLocation(
162         IExtractIconW * iface,
163         UINT uFlags,            /* GIL_ flags */
164         LPWSTR szIconFile,
165         UINT cchMax,
166         int * piIndex,
167         UINT * pwFlags)         /* returned GIL_ flags */
168 {
169         ICOM_THIS(IExtractIconWImpl, iface);
170
171         char    sTemp[MAX_PATH];
172         DWORD   dwNr;
173         GUID const * riid;
174         LPITEMIDLIST    pSimplePidl = ILFindLastID(This->pidl);
175
176         TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
177
178         if (pwFlags)
179           *pwFlags = 0;
180
181         if (_ILIsDesktop(pSimplePidl))
182         {
183           lstrcpynW(szIconFile, swShell32Name, cchMax);
184           *piIndex = 34;
185         }
186
187         /* my computer and other shell extensions */
188         else if ((riid = _ILGetGUIDPointer(pSimplePidl)))
189         {
190           char xriid[50];
191
192           sprintf(xriid, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
193                   riid->Data1, riid->Data2, riid->Data3,
194                   riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
195                   riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
196
197           if (HCR_GetDefaultIconA(xriid, sTemp, MAX_PATH, &dwNr))
198           {
199             MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
200             *piIndex = dwNr;
201           }
202           else
203           {
204             lstrcpynW(szIconFile, swShell32Name, cchMax);
205             *piIndex = 15;
206           }
207         }
208
209         else if (_ILIsDrive (pSimplePidl))
210         {
211           if (HCR_GetDefaultIconA("Drive", sTemp, MAX_PATH, &dwNr))
212           {
213             MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
214             *piIndex = dwNr;
215           }
216           else
217           {
218             lstrcpynW(szIconFile, swShell32Name, cchMax);
219             *piIndex = 8;
220           }
221         }
222         else if (_ILIsFolder (pSimplePidl))
223         {
224           if (HCR_GetDefaultIconA("Folder", sTemp, MAX_PATH, &dwNr))
225           {
226             MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
227           }
228           else
229           {
230             lstrcpynW(szIconFile, swShell32Name, cchMax);
231             dwNr = 3;
232           }
233           *piIndex = (uFlags & GIL_OPENICON) ? dwNr + 1 : dwNr;
234         }
235         else    /* object is file */
236         {
237           if (_ILGetExtension(pSimplePidl, sTemp, MAX_PATH)
238               && HCR_MapTypeToValueA(sTemp, sTemp, MAX_PATH, TRUE)
239               && HCR_GetDefaultIconA(sTemp, sTemp, MAX_PATH, &dwNr))
240           {
241             if (!lstrcmpA("%1", sTemp))         /* icon is in the file */
242             {
243               SHGetPathFromIDListW(This->pidl, szIconFile);
244               *piIndex = 0;
245             }
246             else
247             {
248               MultiByteToWideChar(CP_ACP, 0, sTemp, -1, szIconFile, cchMax);
249               *piIndex = dwNr;
250             }
251           }
252           else                                  /* default icon */
253           {
254             lstrcpynW(szIconFile, swShell32Name, cchMax);
255             *piIndex = 0;
256           }
257         }
258
259         TRACE("-- %s %x\n", debugstr_w(szIconFile), *piIndex);
260         return NOERROR;
261 }
262 /**************************************************************************
263 *  IExtractIconW_Extract
264 */
265 static HRESULT WINAPI IExtractIconW_fnExtract(IExtractIconW * iface, LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
266 {
267         ICOM_THIS(IExtractIconWImpl, iface);
268
269         FIXME("(%p) (file=%p index=%u %p %p size=%u) semi-stub\n", This, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize);
270
271         if (phiconLarge)
272           *phiconLarge = ImageList_GetIcon(ShellBigIconList, nIconIndex, ILD_TRANSPARENT);
273
274         if (phiconSmall)
275           *phiconSmall = ImageList_GetIcon(ShellSmallIconList, nIconIndex, ILD_TRANSPARENT);
276
277         return S_OK;
278 }
279
280 static struct ICOM_VTABLE(IExtractIconW) eivt =
281 {
282         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
283         IExtractIconW_fnQueryInterface,
284         IExtractIconW_fnAddRef,
285         IExtractIconW_fnRelease,
286         IExtractIconW_fnGetIconLocation,
287         IExtractIconW_fnExtract
288 };
289
290 /**************************************************************************
291 *  IExtractIconA_Constructor
292 */
293 IExtractIconA* IExtractIconA_Constructor(LPCITEMIDLIST pidl)
294 {
295         ICOM_THIS(IExtractIconWImpl, IExtractIconW_Constructor(pidl));
296         IExtractIconA *eia = (IExtractIconA *)&This->lpvtblExtractIconA;
297         
298         TRACE("(%p)->(%p)\n", This, eia);
299         return eia;
300 }
301 /**************************************************************************
302  *  IExtractIconA_QueryInterface
303  */
304 static HRESULT WINAPI IExtractIconA_fnQueryInterface(IExtractIconA * iface, REFIID riid, LPVOID *ppvObj)
305 {
306         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
307
308         return IExtractIconW_QueryInterface(This, riid, ppvObj);
309 }
310
311 /**************************************************************************
312 *  IExtractIconA_AddRef
313 */
314 static ULONG WINAPI IExtractIconA_fnAddRef(IExtractIconA * iface)
315 {
316         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
317
318         return IExtractIconW_AddRef(This);
319 }
320 /**************************************************************************
321 *  IExtractIconA_Release
322 */
323 static ULONG WINAPI IExtractIconA_fnRelease(IExtractIconA * iface)
324 {
325         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
326
327         return IExtractIconW_AddRef(This);
328 }
329 /**************************************************************************
330 *  IExtractIconA_GetIconLocation
331 *
332 * mapping filetype to icon
333 */
334 static HRESULT WINAPI IExtractIconA_fnGetIconLocation(
335         IExtractIconA * iface,
336         UINT uFlags,
337         LPSTR szIconFile,
338         UINT cchMax,
339         int * piIndex,
340         UINT * pwFlags)
341 {
342         HRESULT ret;
343         LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
344         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
345         
346         TRACE("(%p) (flags=%u %p %u %p %p)\n", This, uFlags, szIconFile, cchMax, piIndex, pwFlags);
347
348         ret = IExtractIconW_GetIconLocation(This, uFlags, lpwstrFile, cchMax, piIndex, pwFlags);
349         WideCharToMultiByte(CP_ACP, 0, lpwstrFile, -1, szIconFile, cchMax, NULL, NULL);
350         HeapFree(GetProcessHeap(), 0, lpwstrFile);
351
352         TRACE("-- %s %x\n", szIconFile, *piIndex);
353         return ret;
354 }
355 /**************************************************************************
356 *  IExtractIconA_Extract
357 */
358 static HRESULT WINAPI IExtractIconA_fnExtract(IExtractIconA * iface, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
359 {
360         HRESULT ret;
361         INT len = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
362         LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
363         _ICOM_THIS_From_IExtractIconA(IExtractIconW, iface);
364
365         TRACE("(%p) (file=%p index=%u %p %p size=%u)\n", This, pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
366
367         MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwstrFile, len);
368         ret = IExtractIconW_Extract(This, lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
369         HeapFree(GetProcessHeap(), 0, lpwstrFile);
370         return ret;
371 }
372
373 static struct ICOM_VTABLE(IExtractIconA) eiavt =
374 {
375         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
376         IExtractIconA_fnQueryInterface,
377         IExtractIconA_fnAddRef,
378         IExtractIconA_fnRelease,
379         IExtractIconA_fnGetIconLocation,
380         IExtractIconA_fnExtract
381 };
382
383 /************************************************************************
384  * IEIPersistFile_QueryInterface (IUnknown)
385  */
386 static HRESULT WINAPI IEIPersistFile_fnQueryInterface(
387         IPersistFile    *iface,
388         REFIID          iid,
389         LPVOID          *ppvObj)
390 {
391         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
392
393         return IExtractIconW_QueryInterface(This, iid, ppvObj);
394 }
395
396 /************************************************************************
397  * IEIPersistFile_AddRef (IUnknown)
398  */
399 static ULONG WINAPI IEIPersistFile_fnAddRef(
400         IPersistFile    *iface)
401 {
402         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
403
404         return IExtractIconW_AddRef(This);
405 }
406
407 /************************************************************************
408  * IEIPersistFile_Release (IUnknown)
409  */
410 static ULONG WINAPI IEIPersistFile_fnRelease(
411         IPersistFile    *iface)
412 {
413         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
414
415         return IExtractIconW_Release(This);
416 }
417
418 /************************************************************************
419  * IEIPersistFile_GetClassID (IPersist)
420  */
421 static HRESULT WINAPI IEIPersistFile_fnGetClassID(
422         IPersistFile    *iface,
423         LPCLSID         lpClassId)
424 {
425         CLSID StdFolderID = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
426
427         if (lpClassId==NULL)
428           return E_POINTER;
429
430         memcpy(lpClassId, &StdFolderID, sizeof(StdFolderID));
431
432         return S_OK;
433 }
434
435 /************************************************************************
436  * IEIPersistFile_Load (IPersistFile)
437  */
438 static HRESULT WINAPI IEIPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
439 {
440         _ICOM_THIS_From_IPersistFile(IExtractIconW, iface);
441         FIXME("%p\n", This);
442         return E_NOTIMPL;
443
444 }
445
446 static struct ICOM_VTABLE(IPersistFile) pfvt =
447 {
448         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
449         IEIPersistFile_fnQueryInterface,
450         IEIPersistFile_fnAddRef,
451         IEIPersistFile_fnRelease,
452         IEIPersistFile_fnGetClassID,
453         (void *) 0xdeadbeef /* IEIPersistFile_fnIsDirty */,
454         IEIPersistFile_fnLoad,
455         (void *) 0xdeadbeef /* IEIPersistFile_fnSave */,
456         (void *) 0xdeadbeef /* IEIPersistFile_fnSaveCompleted */,
457         (void *) 0xdeadbeef /* IEIPersistFile_fnGetCurFile */
458 };