Compiler warnings fix.
[wine] / dlls / shell32 / pidl.c
1 /*
2  *      pidl Handling
3  *
4  *      Copyright 1998  Juergen Schmied
5  *
6  * NOTES
7  *  a pidl == NULL means desktop and is legal
8  *
9  */
10
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <assert.h>
15 #include "debugtools.h"
16 #include "shell.h"
17 #include "shlguid.h"
18 #include "winerror.h"
19 #include "winnls.h"
20 #include "winversion.h"
21 #include "shell32_main.h"
22
23 #include "pidl.h"
24
25 DECLARE_DEBUG_CHANNEL(pidl)
26 DECLARE_DEBUG_CHANNEL(shell)
27
28 static char * szMyComp = "My Computer"; /* for comparing */
29 static char * szNetHood = "Network Neighbourhood";      /* for comparing */
30
31 void pdump (LPCITEMIDLIST pidl)
32 {       DWORD type;
33         CHAR * szData;
34         CHAR * szShortName;
35         LPITEMIDLIST pidltemp = pidl;
36         if (! pidltemp)
37         { TRACE_(pidl)("-------- pidl = NULL (Root)\n");
38           return;
39         }
40         TRACE_(pidl)("-------- pidl=%p \n", pidl);
41         if (pidltemp->mkid.cb)
42         { do
43           { type   = _ILGetDataPointer(pidltemp)->type;
44             szData = _ILGetTextPointer(type, _ILGetDataPointer(pidltemp));
45             szShortName = _ILGetSTextPointer(type, _ILGetDataPointer(pidltemp));
46
47             TRACE_(pidl)("---- pidl=%p size=%u type=%lx %s, (%s)\n",
48                        pidltemp, pidltemp->mkid.cb,type,debugstr_a(szData), debugstr_a(szShortName));
49
50             pidltemp = ILGetNext(pidltemp);
51           } while (pidltemp->mkid.cb);
52           return;
53         }
54         else
55           TRACE_(pidl)("empty pidl (Desktop)\n");       
56 }
57 #define BYTES_PRINTED 32
58 BOOL pcheck (LPCITEMIDLIST pidl)
59 {       DWORD type, ret=TRUE;
60
61         LPITEMIDLIST pidltemp = pidl;
62
63         if (pidltemp && pidltemp->mkid.cb)
64         { do
65           { type   = _ILGetDataPointer(pidltemp)->type;
66             switch (type)
67             { case PT_DESKTOP:
68               case PT_MYCOMP:
69               case PT_SPECIAL:
70               case PT_DRIVE:
71               case PT_DRIVE1:
72               case PT_DRIVE2:
73               case PT_DRIVE3:
74               case PT_FOLDER:
75               case PT_VALUE:
76               case PT_FOLDER1:
77               case PT_WORKGRP:
78               case PT_COMP:
79               case PT_NETWORK:
80               case PT_SHARE:
81               case PT_IESPECIAL:
82                 break;
83               default:
84               {
85                 char szTemp[BYTES_PRINTED*4 + 1];
86                 int i;
87                 unsigned char c;
88
89                 memset(szTemp, ' ', BYTES_PRINTED*4 + 1);
90                 for ( i = 0; (i<pidltemp->mkid.cb) && (i<BYTES_PRINTED); i++)
91                 {
92                   c = ((unsigned char *)pidltemp)[i];
93
94                   szTemp[i*3+0] = ((c>>4)>9)? (c>>4)+55 : (c>>4)+48;
95                   szTemp[i*3+1] = ((0x0F&c)>9)? (0x0F&c)+55 : (0x0F&c)+48;
96                   szTemp[i*3+2] = ' ';
97                   szTemp[i+BYTES_PRINTED*3]  =  (c>=0x20 && c <=0x80) ? c : '.';
98                 }
99                 szTemp[BYTES_PRINTED*4] = 0x00;
100                 ERR_(pidl)("unknown IDLIST type size=%u type=%lx\n%s\n",pidltemp->mkid.cb,type, szTemp);
101                 ret = FALSE;
102               }
103             }
104             pidltemp = ILGetNext(pidltemp);
105           } while (pidltemp->mkid.cb);
106         }
107         return ret;
108 }
109
110 /*************************************************************************
111  * ILGetDisplayName                     [SHELL32.15]
112  */
113 BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl,LPSTR path)
114 {       TRACE_(shell)("pidl=%p %p semi-stub\n",pidl,path);
115         return SHGetPathFromIDListA(pidl, path);
116 }
117 /*************************************************************************
118  * ILFindLastID [SHELL32.16]
119  */
120 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl) 
121 {       LPITEMIDLIST   pidlLast = NULL;
122
123         TRACE_(pidl)("(pidl=%p)\n",pidl);
124
125         while (pidl->mkid.cb)
126         { pidlLast = pidl;
127           pidl = ILGetNext(pidl);
128         }
129         return pidlLast;                
130 }
131 /*************************************************************************
132  * ILRemoveLastID [SHELL32.17]
133  * NOTES
134  *  Removes the last item 
135  */
136 BOOL WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
137 {       TRACE_(shell)("pidl=%p\n",pidl);
138         if (!pidl || !pidl->mkid.cb)
139           return 0;
140         ILFindLastID(pidl)->mkid.cb = 0;
141         return 1;
142 }
143
144 /*************************************************************************
145  * ILClone [SHELL32.18]
146  *
147  * NOTES
148  *    dupicate an idlist
149  */
150 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
151 { DWORD    len;
152   LPITEMIDLIST  newpidl;
153
154   if (!pidl)
155     return NULL;
156     
157   len = ILGetSize(pidl);
158   newpidl = (LPITEMIDLIST)SHAlloc(len);
159   if (newpidl)
160     memcpy(newpidl,pidl,len);
161
162   TRACE_(pidl)("pidl=%p newpidl=%p\n",pidl, newpidl);
163   pdump(pidl);
164
165   return newpidl;
166 }
167 /*************************************************************************
168  * ILCloneFirst [SHELL32.19]
169  *
170  * NOTES
171  *  duplicates the first idlist of a complex pidl
172  */
173 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
174 {       DWORD len;
175         LPITEMIDLIST newpidl=NULL;
176         
177         TRACE_(pidl)("pidl=%p \n",pidl);
178         pdump(pidl);
179         
180         if (pidl)
181         { len = pidl->mkid.cb;  
182           newpidl = (LPITEMIDLIST) SHAlloc (len+2);
183           if (newpidl)
184           { memcpy(newpidl,pidl,len);
185             ILGetNext(newpidl)->mkid.cb = 0x00;
186           }
187         }
188         TRACE_(pidl)("-- newpidl=%p\n",newpidl);
189
190         return newpidl;
191 }
192 /*************************************************************************
193  * ILLoadFromStream
194  *
195  * NOTES
196  *   the first two bytes are the len, the pidl is following then
197  */
198 HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
199 {       WORD            wLen = 0;
200         DWORD           dwBytesRead;
201         HRESULT         ret = E_FAIL;
202         
203
204         TRACE_(shell)("%p %p\n", pStream ,  ppPidl);
205
206         if (*ppPidl)
207         { SHFree(*ppPidl);
208           *ppPidl = NULL;
209         }
210         
211         IStream_AddRef (pStream);
212
213         if (SUCCEEDED(IStream_Read(pStream, (LPVOID)&wLen, 2, &dwBytesRead)))
214         { *ppPidl = SHAlloc (wLen);
215           if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead)))
216           { ret = S_OK;
217           }
218           else
219           { SHFree(*ppPidl);
220             *ppPidl = NULL;
221           }
222         }
223         
224         /* we are not jet fully compatible */
225         if (!pcheck(*ppPidl))
226         { SHFree(*ppPidl);
227           *ppPidl = NULL;
228         }
229         
230
231         IStream_Release (pStream);
232
233         return ret;
234 }
235 /*************************************************************************
236  * SHILCreateFromPath   [SHELL32.28]
237  *
238  * NOTES
239  *   wraper for IShellFolder::ParseDisplayName()
240  */
241 HRESULT WINAPI SHILCreateFromPathA (LPSTR path, LPITEMIDLIST * ppidl, DWORD attributes)
242 {       LPSHELLFOLDER sf;
243         WCHAR lpszDisplayName[MAX_PATH];
244         DWORD pchEaten;
245         HRESULT ret = E_FAIL;
246         
247         TRACE_(shell)("%s %p 0x%08lx\n",path,ppidl,attributes);
248
249         LocalToWideChar(lpszDisplayName, path, MAX_PATH);
250
251         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
252         { ret = sf->lpvtbl->fnParseDisplayName(sf,0, NULL,lpszDisplayName,&pchEaten,ppidl,&attributes);
253           sf->lpvtbl->fnRelease(sf);
254         }
255         return ret;     
256 }
257 HRESULT WINAPI SHILCreateFromPathW (LPWSTR path, LPITEMIDLIST * ppidl, DWORD attributes)
258 {       LPSHELLFOLDER sf;
259         DWORD pchEaten;
260         HRESULT ret = E_FAIL;
261         
262         TRACE_(shell)("%s %p 0x%08lx\n",debugstr_w(path),ppidl,attributes);
263
264         if (SUCCEEDED (SHGetDesktopFolder(&sf)))
265         { ret = sf->lpvtbl->fnParseDisplayName(sf,0, NULL, path, &pchEaten, ppidl, &attributes);
266           sf->lpvtbl->fnRelease(sf);
267         }
268         return ret;
269 }
270 HRESULT WINAPI SHILCreateFromPathAW (LPVOID path, LPITEMIDLIST * ppidl, DWORD attributes)
271 {
272         if ( VERSION_OsIsUnicode())
273           return SHILCreateFromPathW (path, ppidl, attributes);
274         return SHILCreateFromPathA (path, ppidl, attributes);
275 }
276
277 /*************************************************************************
278  * SHCloneSpecialIDList [SHELL32.89]
279  * 
280  * PARAMETERS
281  *  hwndOwner   [in] 
282  *  nFolder     [in]    CSIDL_xxxxx ??
283  *
284  * RETURNS
285  *  pidl ??
286  * NOTES
287  *     exported by ordinal
288  */
289 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner,DWORD nFolder,DWORD x3)
290 {       LPITEMIDLIST ppidl;
291         WARN_(shell)("(hwnd=0x%x,csidl=0x%lx,0x%lx):semi-stub.\n",
292                                          hwndOwner,nFolder,x3);
293
294         SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
295
296         return ppidl;
297 }
298
299 /*************************************************************************
300  * ILGlobalClone [SHELL32.97]
301  *
302  */
303 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
304 {       DWORD    len;
305         LPITEMIDLIST  newpidl;
306
307         if (!pidl)
308           return NULL;
309     
310         len = ILGetSize(pidl);
311         newpidl = (LPITEMIDLIST)pCOMCTL32_Alloc(len);
312         if (newpidl)
313           memcpy(newpidl,pidl,len);
314
315         TRACE_(pidl)("pidl=%p newpidl=%p\n",pidl, newpidl);
316         pdump(pidl);
317
318         return newpidl;
319 }
320
321 /*************************************************************************
322  * ILIsEqual [SHELL32.21]
323  *
324  */
325 BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
326 {       LPPIDLDATA ppidldata;
327         CHAR * szData1;
328         CHAR * szData2;
329
330         LPITEMIDLIST pidltemp1 = pidl1;
331         LPITEMIDLIST pidltemp2 = pidl2;
332
333         TRACE_(pidl)("pidl1=%p pidl2=%p\n",pidl1, pidl2);
334
335         /* explorer reads from registry directly (StreamMRU),
336            so we can only check here */
337         if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
338           return FALSE;
339
340         pdump (pidl1);
341         pdump (pidl2);
342
343         if ( (!pidl1) || (!pidl2) )
344         { return FALSE;
345         }
346         
347         if (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
348         { do
349           { ppidldata = _ILGetDataPointer(pidltemp1);
350             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
351             
352             ppidldata = _ILGetDataPointer(pidltemp2);    
353             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
354
355             if (!szData1 || !szData2)
356             { FIXME_(pidl)("Failure getting text pointer");
357               return FALSE;
358             }
359             
360             if (strcmp ( szData1, szData2 )!=0 )
361               return FALSE;
362
363             pidltemp1 = ILGetNext(pidltemp1);
364             pidltemp2 = ILGetNext(pidltemp2);
365
366           } while (pidltemp1->mkid.cb && pidltemp2->mkid.cb);
367         }       
368         if (!pidltemp1 && !pidltemp2)
369         { TRACE_(shell)("--- equal\n");
370           return TRUE;
371         }
372
373         return FALSE;
374 }
375 /*************************************************************************
376  * ILIsParent [SHELL32.23]
377  *
378  * parent=a/b   child=a/b/c -> true, c is in folder a/b
379  *              child=a/b/c/d -> false if bImmediate is true, d is not in folder a/b
380  *              child=a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
381  */
382 BOOL WINAPI ILIsParent( LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
383 {
384         LPPIDLDATA ppidldata;
385         CHAR * szData1;
386         CHAR * szData2;
387
388         LPITEMIDLIST pParent = pidlParent;
389         LPITEMIDLIST pChild = pidlChild;
390         
391         TRACE_(pidl)("%p %p %x\n", pidlParent, pidlChild, bImmediate);
392
393         if (pParent->mkid.cb && pChild->mkid.cb)
394         { do
395           { ppidldata = _ILGetDataPointer(pParent);
396             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
397             
398             ppidldata = _ILGetDataPointer(pChild);    
399             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
400
401             if (!szData1 || !szData2)
402             { FIXME_(pidl)("Failure getting text pointer");
403               return FALSE;
404             }
405             
406             if (strcmp ( szData1, szData2 )!=0 )
407               return FALSE;
408
409             pParent = ILGetNext(pParent);
410             pChild = ILGetNext(pChild);
411
412           } while (pParent->mkid.cb && pChild->mkid.cb);
413         }       
414         
415         if ( pParent->mkid.cb || ! pChild->mkid.cb)     /* child shorter or has equal length to parent */
416           return FALSE;
417         
418         if ( ILGetNext(pChild)->mkid.cb && bImmediate)  /* not immediate descent */
419           return FALSE;
420         
421         return TRUE;
422 }
423
424 /*************************************************************************
425  * ILFindChild [SHELL32.24]
426  *
427  * NOTES
428  *  Compares elements from pidl1 and pidl2.
429  *  When at least the first element is equal, it gives a pointer
430  *  to the first different element of pidl 2 back.
431  *  Returns 0 if pidl 2 is shorter.
432  */
433 LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
434 {       LPPIDLDATA ppidldata;
435         CHAR * szData1;
436         CHAR * szData2;
437
438         LPITEMIDLIST pidltemp1 = pidl1;
439         LPITEMIDLIST pidltemp2 = pidl2;
440         LPITEMIDLIST ret=NULL;
441
442         TRACE_(pidl)("pidl1=%p pidl2=%p\n",pidl1, pidl2);
443
444         /* explorer reads from registry directly (StreamMRU),
445            so we can only check here */
446         if ((!pcheck (pidl1)) || (!pcheck (pidl2)))
447           return FALSE;
448
449         pdump (pidl1);
450         pdump (pidl2);
451
452         if ( !pidl1 || !pidl1->mkid.cb)         /* pidl 1 is desktop (root) */
453         { TRACE_(shell)("--- %p\n", pidl2);
454           return pidl2;
455         }
456
457         if (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
458         { do
459           { ppidldata = _ILGetDataPointer(pidltemp1);
460             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
461             
462             ppidldata = _ILGetDataPointer(pidltemp2);    
463             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
464
465             pidltemp2 = ILGetNext(pidltemp2);   /* points behind the pidl2 */
466
467             if (strcmp(szData1,szData2) == 0)
468             { ret = pidltemp2;  /* found equal element */
469             }
470             else
471             { if (ret)          /* different element after equal -> break */
472               { ret = NULL;
473                 break;
474               }
475             }
476             pidltemp1 = ILGetNext(pidltemp1);
477           } while (pidltemp1->mkid.cb && pidltemp2->mkid.cb);
478         }       
479
480         if (!pidltemp2->mkid.cb)
481         { return NULL; /* complete equal or pidl 2 is shorter */
482         }
483
484         TRACE_(shell)("--- %p\n", ret);
485         return ret; /* pidl 1 is shorter */
486 }
487
488 /*************************************************************************
489  * ILCombine [SHELL32.25]
490  *
491  * NOTES
492  *  Concatenates two complex idlists.
493  *  The pidl is the first one, pidlsub the next one
494  *  Does not destroy the passed in idlists!
495  */
496 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
497 { DWORD    len1,len2;
498   LPITEMIDLIST  pidlNew;
499   
500   TRACE_(pidl)("pidl=%p pidl=%p\n",pidl1,pidl2);
501
502   if(!pidl1 && !pidl2)
503   {  return NULL;
504   }
505
506   pdump (pidl1);
507   pdump (pidl2);
508  
509   if(!pidl1)
510   { pidlNew = ILClone(pidl2);
511     return pidlNew;
512   }
513
514   if(!pidl2)
515   { pidlNew = ILClone(pidl1);
516     return pidlNew;
517   }
518
519   len1  = ILGetSize(pidl1)-2;
520   len2  = ILGetSize(pidl2);
521   pidlNew  = SHAlloc(len1+len2);
522   
523   if (pidlNew)
524   { memcpy(pidlNew,pidl1,len1);
525     memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
526   }
527
528 /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
529   return pidlNew;
530 }
531 /*************************************************************************
532  *  SHGetRealIDL [SHELL32.98]
533  *
534  * NOTES
535  */
536 LPITEMIDLIST WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl, DWORD z)
537 {       FIXME_(pidl)("sf=%p pidl=%p 0x%04lx\n",lpsf,pidl,z);
538         pdump (pidl);
539         return 0;
540 }
541
542 /*************************************************************************
543  *  SHLogILFromFSIL [SHELL32.95]
544  *
545  * NOTES
546  */
547 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
548 {       FIXME_(pidl)("(pidl=%p)\n",pidl);
549         pdump(pidl);
550         return 0;
551 }
552
553 /*************************************************************************
554  * ILGetSize [SHELL32.152]
555  *  gets the byte size of an idlist including zero terminator (pidl)
556  *
557  * PARAMETERS
558  *  pidl ITEMIDLIST
559  *
560  * RETURNS
561  *  size of pidl
562  *
563  * NOTES
564  *  exported by ordinal
565  */
566 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
567 {       LPSHITEMID si = &(pidl->mkid);
568         DWORD  len=0;
569
570         if (pidl)
571         { while (si->cb) 
572           { len += si->cb;
573             si  = (LPSHITEMID)(((LPBYTE)si)+si->cb);
574           }
575           len += 2;
576         }
577         TRACE_(pidl)("pidl=%p size=%lu\n",pidl, len);
578         return len;
579 }
580 /*************************************************************************
581  * ILGetNext [SHELL32.153]
582  *  gets the next simple pidl of a complex pidl
583  *
584  * PARAMETERS
585  *  pidl ITEMIDLIST
586  *
587  * RETURNS
588  *  pointer to next element
589  *  NULL when last element ist reached
590  *
591  */
592 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
593 {       LPITEMIDLIST nextpidl;
594         WORD len;
595         
596         TRACE_(pidl)("(pidl=%p)\n",pidl);
597         if(pidl)
598         { len =  pidl->mkid.cb;
599           if (len)
600           { nextpidl = (LPITEMIDLIST) (((LPBYTE)pidl)+len);
601             return nextpidl;
602           }
603         }
604         return NULL;
605 }
606 /*************************************************************************
607  * ILAppend [SHELL32.154]
608  *
609  * NOTES
610  *  Adds the single item to the idlist indicated by pidl.
611  *  if bEnd is 0, adds the item to the front of the list,
612  *  otherwise adds the item to the end. (???)
613  *  Destroys the passed in idlist! (???)
614  */
615 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL bEnd)
616 {       LPITEMIDLIST idlRet;
617         WARN_(pidl)("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
618         pdump (pidl);
619         pdump (item);
620         
621         if (_ILIsDesktop(pidl))
622         {  idlRet = ILClone(item);
623            if (pidl)
624              SHFree (pidl);
625            return idlRet;
626         }  
627         if (bEnd)
628         { idlRet=ILCombine(pidl,item);
629         }
630         else
631         { idlRet=ILCombine(item,pidl);
632         }
633         SHFree(pidl);
634         return idlRet;
635 }
636 /*************************************************************************
637  * ILFree [SHELL32.155]
638  *
639  * NOTES
640  *     free_check_ptr - frees memory (if not NULL)
641  *     allocated by SHMalloc allocator
642  *     exported by ordinal
643  */
644 DWORD WINAPI ILFree(LPITEMIDLIST pidl) 
645 {       TRACE_(pidl)("(pidl=0x%08lx)\n",(DWORD)pidl);
646
647         if (!pidl)
648           return FALSE;
649
650         return SHFree(pidl);
651 }
652 /*************************************************************************
653  * ILGlobalFree [SHELL32.156]
654  *
655  */
656 DWORD WINAPI ILGlobalFree( LPITEMIDLIST pidl)
657 {       TRACE_(pidl)("%p\n",pidl);
658
659         if (!pidl)
660           return FALSE;
661
662         return pCOMCTL32_Free (pidl);
663 }
664 /*************************************************************************
665  * ILCreateFromPath [SHELL32.157]
666  *
667  */
668 LPITEMIDLIST WINAPI ILCreateFromPathA (LPSTR path) 
669 {       LPITEMIDLIST pidlnew;
670
671         TRACE_(shell)("%s\n",path);
672         if (SUCCEEDED (SHILCreateFromPathA (path, &pidlnew, 0)))
673           return pidlnew;
674         return FALSE;
675 }
676 LPITEMIDLIST WINAPI ILCreateFromPathW (LPWSTR path) 
677 {       LPITEMIDLIST pidlnew;
678
679         TRACE_(shell)("%s\n",debugstr_w(path));
680
681         if (SUCCEEDED (SHILCreateFromPathW (path, &pidlnew, 0)))
682           return pidlnew;
683         return FALSE;
684 }
685 LPITEMIDLIST WINAPI ILCreateFromPathAW (LPVOID path) 
686 {
687         if ( VERSION_OsIsUnicode())
688           return ILCreateFromPathW (path);
689         return ILCreateFromPathA (path);
690 }
691 /*************************************************************************
692  *  SHSimpleIDListFromPath [SHELL32.162]
693  *
694  */
695 LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW (LPVOID lpszPath)
696 {       LPCSTR  lpszElement;
697         char    lpszTemp[MAX_PATH];
698
699         if (!lpszPath)
700           return 0;
701
702         if ( VERSION_OsIsUnicode())
703         { TRACE_(pidl)("(path=L%s)\n",debugstr_w((LPWSTR)lpszPath));
704           WideCharToLocal(lpszTemp, lpszPath, MAX_PATH);
705         }
706         else
707         { TRACE_(pidl)("(path=%s)\n",(LPSTR)lpszPath);
708           strcpy(lpszTemp, lpszPath);
709         }
710                 
711         lpszElement = PathFindFilenameA(lpszTemp);
712         if( GetFileAttributesA(lpszTemp) & FILE_ATTRIBUTE_DIRECTORY )
713         { return _ILCreateFolder(NULL, lpszElement);    /*FIXME: fill shortname */
714         }
715         return _ILCreateValue(NULL, lpszElement);       /*FIXME: fill shortname */
716 }
717 /*************************************************************************
718  * SHGetDataFromIDListA [SHELL32.247]
719  *
720  */
721 HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
722 {       TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
723         
724         if (! psf || !dest )
725           return E_INVALIDARG;
726
727         switch (nFormat)
728         { case SHGDFIL_FINDDATA:
729             {  WIN32_FIND_DATAA * pfd = dest;
730                STRRET   lpName;
731                CHAR     pszPath[MAX_PATH];
732                HANDLE handle;
733
734                if ( len < sizeof (WIN32_FIND_DATAA))
735                  return E_INVALIDARG;
736
737                psf->lpvtbl->fnAddRef(psf);
738                psf->lpvtbl->fnGetDisplayNameOf( psf, pidl, SHGDN_FORPARSING, &lpName);
739                psf->lpvtbl->fnRelease(psf);
740
741                strcpy(pszPath,lpName.u.cStr);
742                if ((handle  = FindFirstFileA ( pszPath, pfd)))
743                  FindClose (handle);
744             }
745             break;
746           case SHGDFIL_NETRESOURCE:
747           case SHGDFIL_DESCRIPTIONID:
748             FIXME_(shell)("SHGDFIL %i stub\n", nFormat);
749             break;
750           default:
751             ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat);
752         }
753         return E_INVALIDARG;
754 }
755 /*************************************************************************
756  * SHGetDataFromIDListW [SHELL32.247]
757  *
758  */
759 HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
760 {       FIXME_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
761         return SHGetDataFromIDListA( psf, pidl, nFormat, dest, len);
762 }
763
764 /**************************************************************************
765 * internal functions
766 */
767
768 /**************************************************************************
769  *  _ILCreateDesktop()
770  *  _ILCreateMyComputer()
771  *  _ILCreateDrive()
772  *  _ILCreateFolder() 
773  *  _ILCreateValue()
774  */
775 LPITEMIDLIST WINAPI _ILCreateDesktop()
776 {       TRACE_(pidl)("()\n");
777         return _ILCreate(PT_DESKTOP, NULL, 0);
778 }
779 LPITEMIDLIST WINAPI _ILCreateMyComputer()
780 {       TRACE_(pidl)("()\n");
781         return _ILCreate(PT_MYCOMP, &IID_MyComputer, sizeof(GUID));
782 }
783 LPITEMIDLIST WINAPI _ILCreateDrive( LPCSTR lpszNew)
784 {       char sTemp[4];
785         strncpy (sTemp,lpszNew,4);
786         sTemp[2]='\\';
787         sTemp[3]=0x00;
788         TRACE_(pidl)("(%s)\n",sTemp);
789         return _ILCreate(PT_DRIVE,(LPVOID)&sTemp[0],4);
790 }
791 LPITEMIDLIST WINAPI _ILCreateFolder( LPCSTR lpszShortName, LPCSTR lpszName)
792 {       char    buff[MAX_PATH];
793         char *  pbuff = buff;
794         ULONG   len, len1;
795         
796         TRACE_(pidl)("(%s, %s)\n",lpszShortName, lpszName);
797
798         len = strlen (lpszName)+1;
799         memcpy (pbuff, lpszName, len);
800         pbuff += len;
801
802         if (lpszShortName)
803         { len1 = strlen (lpszShortName)+1;
804           memcpy (pbuff, lpszShortName, len1);
805         }
806         else
807         { len1 = 1;
808           *pbuff = 0x00;
809         }
810         return _ILCreate(PT_FOLDER, (LPVOID)buff, len + len1);
811 }
812 LPITEMIDLIST WINAPI _ILCreateValue(LPCSTR lpszShortName, LPCSTR lpszName)
813 {       char    buff[MAX_PATH];
814         char *  pbuff = buff;
815         ULONG   len, len1;
816         
817         TRACE_(pidl)("(%s, %s)\n", lpszShortName, lpszName);
818
819         len = strlen (lpszName)+1;
820         memcpy (pbuff, lpszName, len);
821         pbuff += len;
822
823         if (lpszShortName)
824         { len1 = strlen (lpszShortName)+1;
825           memcpy (pbuff, lpszShortName, len1);
826         }
827         else
828         { len1 = 1;
829           *pbuff = 0x00;
830         }
831         return _ILCreate(PT_VALUE, (LPVOID)buff, len + len1);
832 }
833
834 /**************************************************************************
835  *  _ILGetDrive()
836  *
837  *  Gets the text for the drive eg. 'c:\'
838  *
839  * RETURNS
840  *  strlen (lpszText)
841  */
842 DWORD WINAPI _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT16 uSize)
843 {       TRACE_(pidl)("(%p,%p,%u)\n",pidl,pOut,uSize);
844
845         if(_ILIsMyComputer(pidl))
846           pidl = ILGetNext(pidl);
847
848         if (pidl && _ILIsDrive(pidl))
849           return _ILGetData(PT_DRIVE, pidl, (LPVOID)pOut, uSize)-1;
850
851         return 0;
852 }
853 /**************************************************************************
854  *  _ILGetItemText()
855  *  Gets the text for only the first item
856  *
857  * RETURNS
858  *  strlen (lpszText)
859  */
860 DWORD WINAPI _ILGetItemText(LPCITEMIDLIST pidl, LPSTR lpszText, UINT16 uSize)
861 {       DWORD ret = 0;
862
863         TRACE_(pidl)("(pidl=%p %p %d)\n",pidl,lpszText,uSize);
864         if (_ILIsMyComputer(pidl))
865         { ret = _ILGetData(PT_MYCOMP, pidl, (LPVOID)lpszText, uSize)-1;
866         }
867         else if (_ILIsDrive(pidl))
868         { ret = _ILGetData(PT_DRIVE, pidl, (LPVOID)lpszText, uSize)-1;
869         }
870         else if (_ILIsFolder (pidl))
871         { ret = _ILGetData(PT_FOLDER, pidl, (LPVOID)lpszText, uSize)-1;
872         }
873         else if (_ILIsValue (pidl))
874         { ret = _ILGetData(PT_VALUE, pidl, (LPVOID)lpszText, uSize)-1;
875         }
876         TRACE_(pidl)("(-- %s)\n",debugstr_a(lpszText));
877         return ret;
878 }
879 /**************************************************************************
880  *  _ILIsDesktop()
881  *  _ILIsDrive()
882  *  _ILIsFolder()
883  *  _ILIsValue()
884  */
885 BOOL WINAPI _ILIsDesktop(LPCITEMIDLIST pidl)
886 {       TRACE_(pidl)("(%p)\n",pidl);
887         return ( !pidl || (pidl && pidl->mkid.cb == 0x00) );
888 }
889
890 BOOL WINAPI _ILIsMyComputer(LPCITEMIDLIST pidl)
891 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
892         TRACE_(pidl)("(%p)\n",pidl);
893         return (pidl && lpPData && PT_MYCOMP == lpPData->type);
894 }
895
896 BOOL WINAPI _ILIsDrive(LPCITEMIDLIST pidl)
897 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
898         TRACE_(pidl)("(%p)\n",pidl);
899         return (pidl && lpPData && (PT_DRIVE == lpPData->type ||
900                                     PT_DRIVE1 == lpPData->type ||
901                                     PT_DRIVE2 == lpPData->type ||
902                                     PT_DRIVE3 == lpPData->type));
903 }
904
905 BOOL WINAPI _ILIsFolder(LPCITEMIDLIST pidl)
906 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
907         TRACE_(pidl)("(%p)\n",pidl);
908         return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type));
909 }
910
911 BOOL WINAPI _ILIsValue(LPCITEMIDLIST pidl)
912 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
913         TRACE_(pidl)("(%p)\n",pidl);
914         return (pidl && lpPData && PT_VALUE == lpPData->type);
915 }
916
917 /**************************************************************************
918  *  _ILGetFolderText()
919  *  Creates a Path string from a PIDL, filtering out the special Folders and values
920  *  There is no trailing backslash
921  *  When lpszPath is NULL the needed size is returned
922  * 
923  * RETURNS
924  *  strlen(lpszPath)
925  */
926 DWORD WINAPI _ILGetFolderText(LPCITEMIDLIST pidl,LPSTR lpszPath, DWORD dwSize)
927 {       LPITEMIDLIST    pidlTemp;
928         LPPIDLDATA      pData;
929         DWORD           dwCopied = 0;
930         LPSTR           pText;
931  
932         TRACE_(pidl)("(%p path=%p)\n",pidl, lpszPath);
933  
934         if(!pidl)
935           return 0;
936
937         if(_ILIsMyComputer(pidl))
938         { pidlTemp = ILGetNext(pidl);
939           TRACE_(pidl)("-- skip My Computer\n");
940         }
941         else
942         { pidlTemp = (LPITEMIDLIST)pidl;
943         }
944
945         if(lpszPath)
946           *lpszPath = 0;
947
948         pData = _ILGetDataPointer(pidlTemp);
949
950         while(pidlTemp->mkid.cb && !(PT_VALUE == pData->type))
951         { 
952           if (!(pText = _ILGetTextPointer(pData->type,pData)))
953             return 0;                           /* foreign pidl */
954                   
955           dwCopied += strlen(pText);
956
957           pidlTemp = ILGetNext(pidlTemp);
958           pData = _ILGetDataPointer(pidlTemp);
959
960           if (lpszPath)
961           { strcat(lpszPath, pText);
962
963             if (pidlTemp->mkid.cb               /* last element ? */
964                 && (pText[2] != '\\')           /* drive has own '\' */
965                 && (PT_VALUE != pData->type))   /* next element is value */
966             { lpszPath[dwCopied] = '\\';
967               lpszPath[dwCopied+1] = '\0';
968               dwCopied++;
969             }
970           }
971           else                                          /* only length */
972           { if (pidlTemp->mkid.cb 
973                 && (pText[2] != '\\')
974                 && (PT_VALUE != pData->type))
975               dwCopied++;                               /* backslash between elements */
976           }
977         }
978
979         TRACE_(pidl)("-- (size=%lu path=%s)\n",dwCopied, debugstr_a(lpszPath));
980         return dwCopied;
981 }
982
983
984 /**************************************************************************
985  *  _ILGetValueText()
986  *  Gets the text for the last item in the list
987  */
988 DWORD WINAPI _ILGetValueText(LPCITEMIDLIST pidl, LPSTR lpszValue, DWORD dwSize)
989 {       LPITEMIDLIST  pidlTemp=pidl;
990         CHAR          szText[MAX_PATH];
991
992         TRACE_(pidl)("(pidl=%p %p 0x%08lx)\n",pidl,lpszValue,dwSize);
993
994         if(!pidl)
995         { return 0;
996         }
997                 
998         while(pidlTemp->mkid.cb && !_ILIsValue(pidlTemp))
999         { pidlTemp = ILGetNext(pidlTemp);
1000         }
1001
1002         if(!pidlTemp->mkid.cb)
1003         { return 0;
1004         }
1005
1006         _ILGetItemText( pidlTemp, szText, sizeof(szText));
1007
1008         if(!lpszValue)
1009         { return strlen(szText);
1010         }
1011         
1012         strcpy(lpszValue, szText);
1013
1014         TRACE_(pidl)("-- (pidl=%p %p=%s 0x%08lx)\n",pidl,lpszValue,lpszValue,dwSize);
1015         return strlen(lpszValue);
1016 }
1017
1018 /**************************************************************************
1019  *  _ILGetPidlPath()
1020  *  Create a string that includes the Drive name, the folder text and 
1021  *  the value text.
1022  *
1023  * RETURNS
1024  *  strlen(lpszOut)
1025  */
1026 DWORD WINAPI _ILGetPidlPath( LPCITEMIDLIST pidl, LPSTR lpszOut, DWORD dwOutSize)
1027 {       int     len = 0;
1028         LPSTR   lpszTemp = lpszOut;
1029         
1030         TRACE_(pidl)("(%p,%lu)\n",lpszOut,dwOutSize);
1031
1032         if(!lpszOut)
1033         { return 0;
1034         }
1035
1036         *lpszOut = 0;
1037
1038         len = _ILGetFolderText(pidl, lpszOut, dwOutSize);
1039
1040         lpszOut += len;
1041         strcpy (lpszOut,"\\");
1042         len++; lpszOut++; dwOutSize -= len;
1043
1044         len += _ILGetValueText(pidl, lpszOut, dwOutSize );
1045
1046         /*remove the last backslash if necessary */
1047         if( lpszTemp[len-1]=='\\')
1048         { lpszTemp[len-1] = 0;
1049           len--;
1050         }
1051
1052         TRACE_(pidl)("-- (%p=%s,%u)\n",lpszTemp,lpszTemp,len);
1053
1054         return len;
1055 }
1056
1057 /**************************************************************************
1058  *  _ILCreate()
1059  *  Creates a new PIDL
1060  *  type = PT_DESKTOP | PT_DRIVE | PT_FOLDER | PT_VALUE
1061  *  pIn = data
1062  *  uInSize = size of data (raw)
1063  */
1064
1065 LPITEMIDLIST WINAPI _ILCreate(PIDLTYPE type, LPCVOID pIn, UINT16 uInSize)
1066 {       LPITEMIDLIST   pidlOut = NULL, pidlTemp = NULL;
1067         LPPIDLDATA     pData;
1068         UINT16         uSize = 0;
1069         LPSTR   pszDest;
1070         
1071         TRACE_(pidl)("(0x%02x %p %i)\n",type,pIn,uInSize);
1072
1073         switch (type)
1074         { case PT_DESKTOP:
1075             uSize = 0;
1076             pidlOut = SHAlloc(uSize + 2);
1077             pidlOut->mkid.cb = uSize;
1078             TRACE_(pidl)("- create Desktop\n");
1079             break;
1080
1081           case PT_MYCOMP:
1082             uSize = 2 + 2 + sizeof(GUID);
1083             pidlOut = SHAlloc(uSize + 2);
1084             pidlOut->mkid.cb = uSize;
1085             pData =_ILGetDataPointer(pidlOut);
1086             pData->type = type;
1087             memcpy(&(pData->u.mycomp.guid), pIn, uInSize);
1088             TRACE_(pidl)("- create My Computer\n");
1089             break;
1090
1091           case PT_DRIVE:
1092             uSize = 2 + 23;
1093             pidlOut = SHAlloc(uSize + 2);
1094             pidlOut->mkid.cb = uSize;
1095             pData =_ILGetDataPointer(pidlOut);
1096             pData->type = type;
1097             pszDest =  _ILGetTextPointer(type, pData);
1098             memcpy(pszDest, pIn, uInSize);
1099             TRACE_(pidl)("- create Drive: %s\n",debugstr_a(pszDest));
1100             break;
1101
1102           case PT_FOLDER:
1103           case PT_VALUE:   
1104             uSize = 2 + 12 + uInSize;
1105             pidlOut = SHAlloc(uSize + 2);
1106             pidlOut->mkid.cb = uSize;
1107             pData =_ILGetDataPointer(pidlOut);
1108             pData->type = type;
1109             pszDest =  _ILGetTextPointer(type, pData);
1110             memcpy(pszDest, pIn, uInSize);
1111             TRACE_(pidl)("- create Value: %s\n",debugstr_a(pszDest));
1112             break;
1113         }
1114         
1115         pidlTemp = ILGetNext(pidlOut);
1116         if (pidlTemp)
1117           pidlTemp->mkid.cb = 0x00;
1118
1119         TRACE_(pidl)("-- (pidl=%p, size=%u)\n", pidlOut, uSize);
1120         return pidlOut;
1121 }
1122 /**************************************************************************
1123  *  _ILGetData(PIDLTYPE, LPCITEMIDLIST, LPVOID, UINT16)
1124  *
1125  * RETURNS
1126  *  length of data (raw)
1127  */
1128 DWORD WINAPI _ILGetData(PIDLTYPE type, LPCITEMIDLIST pidl, LPVOID pOut, UINT uOutSize)
1129 {       LPPIDLDATA  pData;
1130         DWORD       dwReturn=0; 
1131         LPSTR       pszSrc;
1132         
1133         TRACE_(pidl)("(%x %p %p %x)\n",type,pidl,pOut,uOutSize);
1134         
1135         if( (!pidl) || (!pOut) || (uOutSize < 1))
1136         {  return 0;
1137         }
1138
1139         *(LPSTR)pOut = 0;
1140
1141         pData = _ILGetDataPointer(pidl);
1142
1143         assert ( pData->type == type);
1144
1145         pszSrc = _ILGetTextPointer(pData->type, pData);
1146
1147         if (pszSrc)
1148         { strncpy((LPSTR)pOut, pszSrc, uOutSize);
1149           dwReturn = strlen((LPSTR)pOut)+1;
1150         }
1151         else
1152         { ERR_(pidl)("-- no data\n");
1153         }
1154
1155         TRACE_(pidl)("-- (%p=%s 0x%08lx)\n",pOut,(char*)pOut,dwReturn);
1156         return dwReturn;
1157 }
1158
1159
1160 /**************************************************************************
1161  *  _ILGetDataPointer()
1162  */
1163 LPPIDLDATA WINAPI _ILGetDataPointer(LPITEMIDLIST pidl)
1164 {       if(pidl && pidl->mkid.cb != 0x00)
1165           return (LPPIDLDATA)(&pidl->mkid.abID);
1166         return NULL;
1167 }
1168 /**************************************************************************
1169  *  _ILGetTextPointer()
1170  * gets a pointer to the long filename string stored in the pidl
1171  */
1172 LPSTR WINAPI _ILGetTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
1173 {/*     TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
1174
1175         if(!pidldata)
1176         { return NULL;
1177         }
1178
1179         switch (type)
1180         { case PT_DRIVE:
1181           case PT_DRIVE1:
1182           case PT_DRIVE2:
1183           case PT_DRIVE3:
1184             return (LPSTR)&(pidldata->u.drive.szDriveName);
1185
1186           case PT_MYCOMP:
1187             return szMyComp;
1188
1189           case PT_SPECIAL:
1190             return szNetHood;
1191
1192           case PT_FOLDER:
1193           case PT_FOLDER1:
1194           case PT_VALUE:
1195           case PT_IESPECIAL:
1196             return (LPSTR)&(pidldata->u.file.szNames);
1197
1198           case PT_WORKGRP:
1199           case PT_COMP:
1200           case PT_NETWORK:
1201           case PT_SHARE:
1202             return (LPSTR)&(pidldata->u.network.szNames);
1203         }
1204         return NULL;
1205 }
1206 /**************************************************************************
1207  *  _ILGetSTextPointer()
1208  * gets a pointer to the long filename string stored in the pidl
1209  */
1210 LPSTR WINAPI _ILGetSTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
1211 {/*     TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
1212
1213         if(!pidldata)
1214         { return NULL;
1215         }
1216         switch (type)
1217         { case PT_FOLDER:
1218           case PT_VALUE:
1219           case PT_IESPECIAL:
1220             return (LPSTR)(pidldata->u.file.szNames + strlen (pidldata->u.file.szNames) + 1);
1221           case PT_WORKGRP:
1222             return (LPSTR)(pidldata->u.network.szNames + strlen (pidldata->u.network.szNames) + 1);
1223         }
1224         return NULL;
1225 }
1226 BOOL WINAPI _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1227 {       LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1228         FILETIME ft;
1229         SYSTEMTIME time;
1230
1231         switch (pdata->type)
1232         { case PT_FOLDER:
1233             DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, &ft);
1234             break;          
1235           case PT_VALUE:
1236             DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, &ft);
1237             break;
1238           default:
1239             return FALSE;
1240         }
1241         FileTimeToSystemTime (&ft, &time);
1242         return GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize);
1243 }
1244 BOOL WINAPI _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1245 {       LPPIDLDATA pdata =_ILGetDataPointer(pidl);
1246         char stemp[20]; /* for filesize */
1247         
1248         switch (pdata->type)
1249         { case PT_VALUE:
1250             break;
1251           default:
1252             return FALSE;
1253         }
1254         StrFormatByteSizeA(pdata->u.file.dwFileSize, stemp, 20);
1255         strncpy( pOut, stemp, 20);
1256         return TRUE;
1257 }
1258
1259 BOOL WINAPI _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize)
1260 {       char pTemp[MAX_PATH];
1261         const char * pPoint;
1262
1263         TRACE_(pidl)("pidl=%p\n",pidl);
1264
1265         if ( ! _ILGetValueText(pidl, pTemp, MAX_PATH))
1266         { return FALSE;
1267         }
1268
1269         pPoint = PathFindExtensionA(pTemp);
1270
1271         if (! *pPoint)
1272           return FALSE;
1273
1274         pPoint++;
1275         strncpy(pOut, pPoint, uOutSize);
1276         TRACE_(pidl)("%s\n",pOut);
1277
1278         return TRUE;
1279 }