Stub for PathQualify32[A|W].
[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 "ole.h"
15 #include "ole2.h"
16 #include "debug.h"
17 #include "shlobj.h"
18 #include "shell.h"
19 #include "winerror.h"
20 #include "winnls.h"
21 #include "winproc.h"
22 #include "commctrl.h"
23 #include "winversion.h"
24 #include "shell32_main.h"
25
26 #include "pidl.h"
27
28 void pdump (LPCITEMIDLIST pidl)
29 {       DWORD type;
30         CHAR * szData;
31         LPITEMIDLIST pidltemp = pidl;
32         if (! pidltemp)
33         { TRACE(pidl,"-------- pidl = NULL (Root)\n");
34           return;
35         }
36         TRACE(pidl,"-------- pidl=%p \n", pidl);
37         if (pidltemp->mkid.cb)
38         { do
39           { type   = _ILGetDataPointer(pidltemp)->type;
40             szData = _ILGetTextPointer(type, _ILGetDataPointer(pidltemp));
41
42             TRACE(pidl,"---- pidl=%p size=%u type=%lx %s\n",pidltemp, pidltemp->mkid.cb,type,debugstr_a(szData));
43
44             pidltemp = ILGetNext(pidltemp);
45           } while (pidltemp->mkid.cb);
46           return;
47         }
48         else
49           TRACE(pidl,"empty pidl (Desktop)\n"); 
50 }
51 /*************************************************************************
52  * ILGetDisplayName                     [SHELL32.15]
53  */
54 BOOL32 WINAPI ILGetDisplayName(LPCITEMIDLIST pidl,LPSTR path)
55 {       FIXME(shell,"pidl=%p %p semi-stub\n",pidl,path);
56         return SHGetPathFromIDList32A(pidl, path);
57 }
58 /*************************************************************************
59  * ILFindLastID [SHELL32.16]
60  */
61 LPITEMIDLIST WINAPI ILFindLastID(LPITEMIDLIST pidl) 
62 {       LPITEMIDLIST   pidlLast = NULL;
63
64         TRACE(pidl,"(pidl=%p)\n",pidl);
65
66         if(pidl)
67         { while(pidl->mkid.cb)
68           { pidlLast = (LPITEMIDLIST)pidl;
69             pidl = ILGetNext(pidl);
70           }  
71         }
72         return pidlLast;                
73 }
74 /*************************************************************************
75  * ILRemoveLastID [SHELL32.17]
76  * NOTES
77  *  Removes the last item 
78  */
79 BOOL32 WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
80 {       TRACE(shell,"pidl=%p\n",pidl);
81         if (!pidl || !pidl->mkid.cb)
82           return 0;
83         ILFindLastID(pidl)->mkid.cb = 0;
84         return 1;
85 }
86
87 /*************************************************************************
88  * ILClone [SHELL32.18]
89  *
90  * NOTES
91  *    dupicate an idlist
92  */
93 LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
94 { DWORD    len;
95   LPITEMIDLIST  newpidl;
96
97   if (!pidl)
98     return NULL;
99     
100   len = ILGetSize(pidl);
101   newpidl = (LPITEMIDLIST)SHAlloc(len);
102   if (newpidl)
103     memcpy(newpidl,pidl,len);
104
105   TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
106   pdump(pidl);
107
108   return newpidl;
109 }
110 /*************************************************************************
111  * ILCloneFirst [SHELL32.19]
112  *
113  * NOTES
114  *  duplicates the first idlist of a complex pidl
115  */
116 LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
117 {       DWORD len;
118         LPITEMIDLIST newpidl=NULL;
119         
120         TRACE(pidl,"pidl=%p \n",pidl);
121         pdump(pidl);
122         
123         if (pidl)
124         { len = pidl->mkid.cb;  
125           newpidl = (LPITEMIDLIST) SHAlloc (len+2);
126           if (newpidl)
127           { memcpy(newpidl,pidl,len);
128             ILGetNext(newpidl)->mkid.cb = 0x00;
129           }
130         }
131         TRACE(pidl,"-- newpidl=%p\n",newpidl);
132
133         return newpidl;
134 }
135
136 /*************************************************************************
137  * SHCloneSpecialIDList [SHELL32.89]
138  * 
139  * PARAMETERS
140  *  hwndOwner   [in] 
141  *  nFolder     [in]    CSIDL_xxxxx ??
142  *
143  * RETURNS
144  *  pidl ??
145  * NOTES
146  *     exported by ordinal
147  */
148 LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND32 hwndOwner,DWORD nFolder,DWORD x3)
149 {       LPITEMIDLIST ppidl;
150         WARN(shell,"(hwnd=0x%x,csidl=0x%lx,0x%lx):semi-stub.\n",
151                                          hwndOwner,nFolder,x3);
152
153         SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
154
155         return ppidl;
156 }
157
158 /*************************************************************************
159  * ILGlobalClone [SHELL32.97]
160  *
161  */
162 LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
163 {       DWORD    len;
164         LPITEMIDLIST  newpidl;
165
166         if (!pidl)
167           return NULL;
168     
169         len = ILGetSize(pidl);
170         newpidl = (LPITEMIDLIST)pCOMCTL32_Alloc(len);
171         if (newpidl)
172           memcpy(newpidl,pidl,len);
173
174         TRACE(pidl,"pidl=%p newpidl=%p\n",pidl, newpidl);
175         pdump(pidl);
176
177         return newpidl;
178 }
179
180 /*************************************************************************
181  * ILIsEqual [SHELL32.21]
182  *
183  */
184 BOOL32 WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
185 {       LPPIDLDATA ppidldata;
186         CHAR * szData1;
187         CHAR * szData2;
188
189         LPITEMIDLIST pidltemp1 = pidl1;
190         LPITEMIDLIST pidltemp2 = pidl2;
191
192         TRACE(pidl,"pidl1=%p pidl2=%p\n",pidl1, pidl2);
193
194         pdump (pidl1);
195         pdump (pidl2);
196
197         if ( (!pidl1) || (!pidl2) )
198         { return FALSE;
199         }
200
201         if (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
202         { do
203           { ppidldata = _ILGetDataPointer(pidltemp1);
204             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
205             
206             ppidldata = _ILGetDataPointer(pidltemp2);    
207             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
208
209             if (strcmp ( szData1, szData2 )!=0 )
210               return FALSE;
211
212             pidltemp1 = ILGetNext(pidltemp1);
213             pidltemp2 = ILGetNext(pidltemp2);
214
215           } while (pidltemp1->mkid.cb && pidltemp2->mkid.cb);
216         }       
217         if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
218         { TRACE(shell, "--- equal\n");
219           return TRUE;
220         }
221
222         return FALSE;
223 }
224 /*************************************************************************
225  * ILIsParent [SHELL32.23]
226  *
227  */
228 DWORD WINAPI ILIsParent( DWORD x, DWORD y, DWORD z)
229 {       FIXME(pidl,"0x%08lx 0x%08lx 0x%08lx stub\n",x,y,z);
230         return 0;
231 }
232
233 /*************************************************************************
234  * ILFindChild [SHELL32.24]
235  *
236  * NOTES
237  *  Compares elements from pidl1 and pidl2.
238  *  When at least the first element is equal, it gives a pointer
239  *  to the first different element of pidl 2 back.
240  *  Returns 0 if pidl 2 is shorter.
241  */
242 LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
243 {       LPPIDLDATA ppidldata;
244         CHAR * szData1;
245         CHAR * szData2;
246
247         LPITEMIDLIST pidltemp1 = pidl1;
248         LPITEMIDLIST pidltemp2 = pidl2;
249         LPITEMIDLIST ret=NULL;
250
251         TRACE(pidl,"pidl1=%p pidl2=%p\n",pidl1, pidl2);
252
253         pdump (pidl1);
254         pdump (pidl2);
255
256         if ( !pidl1 || !pidl1->mkid.cb)         /* pidl 1 is desktop (root) */
257         { TRACE(shell, "--- %p\n", pidl2);
258           return pidl2;
259         }
260
261         if (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
262         { do
263           { ppidldata = _ILGetDataPointer(pidltemp1);
264             szData1 = _ILGetTextPointer(ppidldata->type, ppidldata);
265             
266             ppidldata = _ILGetDataPointer(pidltemp2);    
267             szData2 = _ILGetTextPointer(ppidldata->type, ppidldata);
268
269             pidltemp2 = ILGetNext(pidltemp2);   /* points behind the pidl2 */
270
271             if (strcmp(szData1,szData2) == 0)
272             { ret = pidltemp2;  /* found equal element */
273             }
274             else
275             { if (ret)          /* different element after equal -> break */
276               { ret = NULL;
277                 break;
278               }
279             }
280             pidltemp1 = ILGetNext(pidltemp1);
281           } while (pidltemp1->mkid.cb && pidltemp2->mkid.cb);
282         }       
283
284         if (!pidltemp2->mkid.cb)
285         { return NULL; /* complete equal or pidl 2 is shorter */
286         }
287
288         TRACE(shell, "--- %p\n", ret);
289         return ret; /* pidl 1 is shorter */
290 }
291
292 /*************************************************************************
293  * ILCombine [SHELL32.25]
294  *
295  * NOTES
296  *  Concatenates two complex idlists.
297  *  The pidl is the first one, pidlsub the next one
298  *  Does not destroy the passed in idlists!
299  */
300 LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
301 { DWORD    len1,len2;
302   LPITEMIDLIST  pidlNew;
303   
304   TRACE(pidl,"pidl=%p pidl=%p\n",pidl1,pidl2);
305
306   if(!pidl1 && !pidl2)
307   {  return NULL;
308   }
309
310   pdump (pidl1);
311   pdump (pidl2);
312  
313   if(!pidl1)
314   { pidlNew = ILClone(pidl2);
315     return pidlNew;
316   }
317
318   if(!pidl2)
319   { pidlNew = ILClone(pidl1);
320     return pidlNew;
321   }
322
323   len1  = ILGetSize(pidl1)-2;
324   len2  = ILGetSize(pidl2);
325   pidlNew  = SHAlloc(len1+len2);
326   
327   if (pidlNew)
328   { memcpy(pidlNew,pidl1,len1);
329     memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
330   }
331
332 /*  TRACE(pidl,"--new pidl=%p\n",pidlNew);*/
333   return pidlNew;
334 }
335 /*************************************************************************
336  *  SHGetRealIDL [SHELL32.98]
337  *
338  * NOTES
339  */
340 LPITEMIDLIST WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl, DWORD z)
341 {       FIXME(pidl,"sf=%p pidl=%p 0x%04lx\n",lpsf,pidl,z);
342         pdump (pidl);
343         return 0;
344 }
345
346 /*************************************************************************
347  *  SHLogILFromFSIL [SHELL32.95]
348  *
349  * NOTES
350  */
351 LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
352 {       FIXME(pidl,"(pidl=%p)\n",pidl);
353         pdump(pidl);
354         return 0;
355 }
356
357 /*************************************************************************
358  * ILGetSize [SHELL32.152]
359  *  gets the byte size of an idlist including zero terminator (pidl)
360  *
361  * PARAMETERS
362  *  pidl ITEMIDLIST
363  *
364  * RETURNS
365  *  size of pidl
366  *
367  * NOTES
368  *  exported by ordinal
369  */
370 DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
371 {       LPSHITEMID si = &(pidl->mkid);
372         DWORD  len=0;
373
374         if (pidl)
375         { while (si->cb) 
376           { len += si->cb;
377             si  = (LPSHITEMID)(((LPBYTE)si)+si->cb);
378           }
379           len += 2;
380         }
381         TRACE(pidl,"pidl=%p size=%lu\n",pidl, len);
382         return len;
383 }
384 /*************************************************************************
385  * ILGetNext [SHELL32.153]
386  *  gets the next simple pidl of a complex pidl
387  *
388  * PARAMETERS
389  *  pidl ITEMIDLIST
390  *
391  * RETURNS
392  *  pointer to next element
393  *
394  */
395 LPITEMIDLIST WINAPI ILGetNext(LPITEMIDLIST pidl)
396 {       LPITEMIDLIST nextpidl;
397
398         /* TRACE(pidl,"(pidl=%p)\n",pidl);*/
399         if(pidl)
400         { nextpidl = (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) + pidl->mkid.cb);
401           return nextpidl;
402         }
403         else
404         {  return (NULL);
405         }
406 }
407 /*************************************************************************
408  * ILAppend [SHELL32.154]
409  *
410  * NOTES
411  *  Adds the single item to the idlist indicated by pidl.
412  *  if bEnd is 0, adds the item to the front of the list,
413  *  otherwise adds the item to the end. (???)
414  *  Destroys the passed in idlist! (???)
415  */
416 LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL32 bEnd)
417 {       LPITEMIDLIST idlRet;
418         WARN(pidl,"(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd);
419         pdump (pidl);
420         pdump (item);
421         
422         if (_ILIsDesktop(pidl))
423         {  idlRet = ILClone(item);
424            if (pidl)
425              SHFree (pidl);
426            return idlRet;
427         }  
428         if (bEnd)
429         { idlRet=ILCombine(pidl,item);
430         }
431         else
432         { idlRet=ILCombine(item,pidl);
433         }
434         SHFree(pidl);
435         return idlRet;
436 }
437 /*************************************************************************
438  * ILFree [SHELL32.155]
439  *
440  * NOTES
441  *     free_check_ptr - frees memory (if not NULL)
442  *     allocated by SHMalloc allocator
443  *     exported by ordinal
444  */
445 DWORD WINAPI ILFree(LPITEMIDLIST pidl) 
446 {       TRACE(pidl,"(pidl=0x%08lx)\n",(DWORD)pidl);
447
448         if (!pidl)
449           return FALSE;
450
451         return SHFree(pidl);
452 }
453 /*************************************************************************
454  * ILGlobalFree [SHELL32.156]
455  *
456  */
457 DWORD WINAPI ILGlobalFree( LPITEMIDLIST pidl)
458 {       TRACE(pidl,"%p\n",pidl);
459
460         if (!pidl)
461           return FALSE;
462
463         return pCOMCTL32_Free (pidl);
464 }
465 /*************************************************************************
466  * ILCreateFromPath [SHELL32.157]
467  *
468  */
469 LPITEMIDLIST WINAPI ILCreateFromPath(LPVOID path) 
470 {       LPSHELLFOLDER shellfolder;
471         LPITEMIDLIST pidlnew;
472         WCHAR lpszDisplayName[MAX_PATH];
473         DWORD pchEaten;
474         
475         if ( !VERSION_OsIsUnicode())
476         { TRACE(pidl,"(path=%s)\n",(LPSTR)path);
477           LocalToWideChar32(lpszDisplayName, path, MAX_PATH);
478         }
479         else
480         { TRACE(pidl,"(path=L%s)\n",debugstr_w(path));
481           lstrcpy32W(lpszDisplayName, path);
482         }
483
484         if (SHGetDesktopFolder(&shellfolder)==S_OK)
485         { shellfolder->lpvtbl->fnParseDisplayName(shellfolder,0, NULL,lpszDisplayName,&pchEaten,&pidlnew,NULL);
486           shellfolder->lpvtbl->fnRelease(shellfolder);
487         }
488         return pidlnew;
489 }
490 /*************************************************************************
491  *  SHSimpleIDListFromPath [SHELL32.162]
492  *
493  */
494 LPITEMIDLIST WINAPI SHSimpleIDListFromPath32AW (LPVOID lpszPath)
495 {       LPCSTR  lpszElement;
496         char    lpszTemp[MAX_PATH];
497
498         if (!lpszPath)
499           return 0;
500
501         if ( VERSION_OsIsUnicode())
502         { TRACE(pidl,"(path=L%s)\n",debugstr_w((LPWSTR)lpszPath));
503           WideCharToLocal32(lpszTemp, lpszPath, MAX_PATH);
504         }
505         else
506         { TRACE(pidl,"(path=%s)\n",(LPSTR)lpszPath);
507           strcpy(lpszTemp, lpszPath);
508         }
509                 
510         lpszElement = PathFindFilename32A(lpszTemp);
511         if( GetFileAttributes32A(lpszTemp) & FILE_ATTRIBUTE_DIRECTORY )
512         { return _ILCreateFolder(lpszElement);
513         }
514         return _ILCreateValue(lpszElement);
515 }
516 /*************************************************************************
517  * SHGetDataFromIDListA [SHELL32.247]
518  *
519  */
520 HRESULT WINAPI SHGetDataFromIDList32A(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
521 {       FIXME(shell,"sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
522         switch (nFormat)
523         { case SHGDFIL_FINDDATA:
524           case SHGDFIL_NETRESOURCE:        
525           case SHGDFIL_DESCRIPTIONID:
526             break;
527           default:
528             ERR(shell,"Unknown SHGDFIL %i, please report\n", nFormat);
529         }
530         return E_INVALIDARG;
531 }
532 /*************************************************************************
533  * SHGetDataFromIDListW [SHELL32.247]
534  *
535  */
536 HRESULT WINAPI SHGetDataFromIDList32W(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, int nFormat, LPVOID dest, int len)
537 {       FIXME(shell,"sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len);
538         return SHGetDataFromIDList32A( psf, pidl, nFormat, dest, len);
539 }
540
541 /**************************************************************************
542 * internal functions
543 */
544
545 /**************************************************************************
546  *  _ILCreateDesktop()
547  *  _ILCreateMyComputer()
548  *  _ILCreateDrive()
549  *  _ILCreateFolder() 
550  *  _ILCreateValue()
551  */
552 LPITEMIDLIST WINAPI _ILCreateDesktop()
553 {       TRACE(pidl,"()\n");
554         return _ILCreate(PT_DESKTOP, NULL, 0);
555 }
556 LPITEMIDLIST WINAPI _ILCreateMyComputer()
557 {       TRACE(pidl,"()\n");
558         return _ILCreate(PT_MYCOMP, (void *)"My Computer", strlen ("My Computer")+1);
559 }
560 LPITEMIDLIST WINAPI _ILCreateDrive( LPCSTR lpszNew)
561 {       char sTemp[4];
562         strncpy (sTemp,lpszNew,4);
563         sTemp[2]='\\';
564         sTemp[3]=0x00;
565         TRACE(pidl,"(%s)\n",sTemp);
566         return _ILCreate(PT_DRIVE,(LPVOID)&sTemp[0],4);
567 }
568 LPITEMIDLIST WINAPI _ILCreateFolder( LPCSTR lpszNew)
569 {       TRACE(pidl,"(%s)\n",lpszNew);
570         return _ILCreate(PT_FOLDER, (LPVOID)lpszNew, strlen(lpszNew)+1);
571 }
572 LPITEMIDLIST WINAPI _ILCreateValue(LPCSTR lpszNew)
573 {       TRACE(pidl,"(%s)\n",lpszNew);
574         return _ILCreate(PT_VALUE, (LPVOID)lpszNew, strlen(lpszNew)+1);
575 }
576
577 /**************************************************************************
578  *  _ILGetDrive()
579  *
580  *  Gets the text for the drive eg. 'c:\'
581  *
582  * RETURNS
583  *  strlen (lpszText)
584  */
585 DWORD WINAPI _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT16 uSize)
586 {       TRACE(pidl,"(%p,%p,%u)\n",pidl,pOut,uSize);
587
588         if(_ILIsMyComputer(pidl))
589           pidl = ILGetNext(pidl);
590
591         if (pidl && _ILIsDrive(pidl))
592           return _ILGetData(PT_DRIVE, pidl, (LPVOID)pOut, uSize)-1;
593
594         return 0;
595 }
596 /**************************************************************************
597  *  _ILGetItemText()
598  *  Gets the text for only the first item
599  *
600  * RETURNS
601  *  strlen (lpszText)
602  */
603 DWORD WINAPI _ILGetItemText(LPCITEMIDLIST pidl, LPSTR lpszText, UINT16 uSize)
604 {       DWORD ret = 0;
605
606         TRACE(pidl,"(pidl=%p %p %d)\n",pidl,lpszText,uSize);
607         if (_ILIsMyComputer(pidl))
608         { ret = _ILGetData(PT_MYCOMP, pidl, (LPVOID)lpszText, uSize)-1;
609         }
610         else if (_ILIsDrive(pidl))
611         { ret = _ILGetData(PT_DRIVE, pidl, (LPVOID)lpszText, uSize)-1;
612         }
613         else if (_ILIsFolder (pidl))
614         { ret = _ILGetData(PT_FOLDER, pidl, (LPVOID)lpszText, uSize)-1;
615         }
616         else if (_ILIsValue (pidl))
617         { ret = _ILGetData(PT_VALUE, pidl, (LPVOID)lpszText, uSize)-1;
618         }
619         TRACE(pidl,"(-- %s)\n",debugstr_a(lpszText));
620         return ret;
621 }
622 /**************************************************************************
623  *  _ILIsDesktop()
624  *  _ILIsDrive()
625  *  _ILIsFolder()
626  *  _ILIsValue()
627  */
628 BOOL32 WINAPI _ILIsDesktop(LPCITEMIDLIST pidl)
629 {       TRACE(pidl,"(%p)\n",pidl);
630         return ( !pidl || (pidl && pidl->mkid.cb == 0x00) );
631 }
632
633 BOOL32 WINAPI _ILIsMyComputer(LPCITEMIDLIST pidl)
634 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
635         TRACE(pidl,"(%p)\n",pidl);
636         return (pidl && lpPData && PT_MYCOMP == lpPData->type);
637 }
638
639 BOOL32 WINAPI _ILIsDrive(LPCITEMIDLIST pidl)
640 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
641         TRACE(pidl,"(%p)\n",pidl);
642         return (pidl && lpPData && PT_DRIVE == lpPData->type);
643 }
644
645 BOOL32 WINAPI _ILIsFolder(LPCITEMIDLIST pidl)
646 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
647         TRACE(pidl,"(%p)\n",pidl);
648         return (pidl && lpPData && PT_FOLDER == lpPData->type);
649 }
650
651 BOOL32 WINAPI _ILIsValue(LPCITEMIDLIST pidl)
652 {       LPPIDLDATA lpPData = _ILGetDataPointer(pidl);
653         TRACE(pidl,"(%p)\n",pidl);
654         return (pidl && lpPData && PT_VALUE == lpPData->type);
655 }
656
657 /**************************************************************************
658  *  _ILGetFolderText()
659  *  Creates a Path string from a PIDL, filtering out the special Folders and values
660  *  There is no trailing backslash
661  *  When lpszPath is NULL the needed size is returned
662  * 
663  * RETURNS
664  *  strlen(lpszPath)
665  */
666 DWORD WINAPI _ILGetFolderText(LPCITEMIDLIST pidl,LPSTR lpszPath, DWORD dwSize)
667 {       LPITEMIDLIST    pidlTemp;
668         LPPIDLDATA      pData;
669         DWORD           dwCopied = 0;
670         LPSTR           pText;
671  
672         TRACE(pidl,"(%p path=%p)\n",pidl, lpszPath);
673  
674         if(!pidl)
675           return 0;
676
677         if(_ILIsMyComputer(pidl))
678         { pidlTemp = ILGetNext(pidl);
679           TRACE(pidl,"-- skip My Computer\n");
680         }
681         else
682         { pidlTemp = (LPITEMIDLIST)pidl;
683         }
684
685         if(lpszPath)
686           *lpszPath = 0;
687
688         pData = _ILGetDataPointer(pidlTemp);
689
690         while(pidlTemp->mkid.cb && !(PT_VALUE == pData->type))
691         { 
692           if (!(pText = _ILGetTextPointer(pData->type,pData)))
693             return 0;                           /* foreign pidl */
694                   
695           dwCopied += strlen(pText);
696
697           pidlTemp = ILGetNext(pidlTemp);
698           pData = _ILGetDataPointer(pidlTemp);
699
700           if (lpszPath)
701           { strcat(lpszPath, pText);
702
703             if (pidlTemp->mkid.cb               /* last element ? */
704                 && (pText[2] != '\\')           /* drive has own '\' */
705                 && (PT_VALUE != pData->type))   /* next element is value */
706             { lpszPath[dwCopied] = '\\';
707               lpszPath[dwCopied+1] = '\0';
708               dwCopied++;
709             }
710           }
711           else                                          /* only length */
712           { if (pidlTemp->mkid.cb 
713                 && (pText[2] != '\\')
714                 && (PT_VALUE != pData->type))
715               dwCopied++;                               /* backslash between elements */
716           }
717         }
718
719         TRACE(pidl,"-- (size=%lu path=%s)\n",dwCopied, debugstr_a(lpszPath));
720         return dwCopied;
721 }
722
723
724 /**************************************************************************
725  *  _ILGetValueText()
726  *  Gets the text for the last item in the list
727  */
728 DWORD WINAPI _ILGetValueText(LPCITEMIDLIST pidl, LPSTR lpszValue, DWORD dwSize)
729 {       LPITEMIDLIST  pidlTemp=pidl;
730         CHAR          szText[MAX_PATH];
731
732         TRACE(pidl,"(pidl=%p %p 0x%08lx)\n",pidl,lpszValue,dwSize);
733
734         if(!pidl)
735         { return 0;
736         }
737                 
738         while(pidlTemp->mkid.cb && !_ILIsValue(pidlTemp))
739         { pidlTemp = ILGetNext(pidlTemp);
740         }
741
742         if(!pidlTemp->mkid.cb)
743         { return 0;
744         }
745
746         _ILGetItemText( pidlTemp, szText, sizeof(szText));
747
748         if(!lpszValue)
749         { return strlen(szText);
750         }
751         
752         strcpy(lpszValue, szText);
753
754         TRACE(pidl,"-- (pidl=%p %p=%s 0x%08lx)\n",pidl,lpszValue,lpszValue,dwSize);
755         return strlen(lpszValue);
756 }
757
758 /**************************************************************************
759  *  _ILGetPidlPath()
760  *  Create a string that includes the Drive name, the folder text and 
761  *  the value text.
762  *
763  * RETURNS
764  *  strlen(lpszOut)
765  */
766 DWORD WINAPI _ILGetPidlPath( LPCITEMIDLIST pidl, LPSTR lpszOut, DWORD dwOutSize)
767 {       int     len = 0;
768         LPSTR   lpszTemp = lpszOut;
769         
770         TRACE(pidl,"(%p,%lu)\n",lpszOut,dwOutSize);
771
772         if(!lpszOut)
773         { return 0;
774         }
775
776         *lpszOut = 0;
777
778         len = _ILGetFolderText(pidl, lpszOut, dwOutSize);
779
780         lpszOut += len;
781         strcpy (lpszOut,"\\");
782         len++; lpszOut++; dwOutSize -= len;
783
784         len += _ILGetValueText(pidl, lpszOut, dwOutSize );
785
786         /*remove the last backslash if necessary */
787         if( lpszTemp[len-1]=='\\')
788         { lpszTemp[len-1] = 0;
789           len--;
790         }
791
792         TRACE(pidl,"-- (%p=%s,%u)\n",lpszTemp,lpszTemp,len);
793
794         return len;
795 }
796
797 /**************************************************************************
798  *  _ILCreate()
799  *  Creates a new PIDL
800  *  type = PT_DESKTOP | PT_DRIVE | PT_FOLDER | PT_VALUE
801  *  pIn = data
802  *  uInSize = size of data (raw)
803  */
804
805 LPITEMIDLIST WINAPI _ILCreate(PIDLTYPE type, LPVOID pIn, UINT16 uInSize)
806 {       LPITEMIDLIST   pidlOut=NULL;
807         UINT16         uSize;
808         LPITEMIDLIST   pidlTemp=NULL;
809         LPPIDLDATA     pData;
810         LPSTR   pszDest;
811         
812         TRACE(pidl,"(0x%02x %p %i)\n",type,pIn,uInSize);
813
814         if ( type == PT_DESKTOP)
815         { pidlOut = SHAlloc(2);
816           pidlOut->mkid.cb=0x0000;
817           return pidlOut;
818         }
819
820         if (! pIn)
821         { return NULL;
822         }       
823
824         /* the sizes of: cb(2), pidldata-1(26), szText+1, next cb(2) */
825         switch (type)
826         { case PT_DRIVE:
827             uSize = 4 + 9;
828             break;
829           default:
830             uSize = 4 + (sizeof(PIDLDATA)) + uInSize; 
831          }   
832         pidlOut = SHAlloc(uSize);
833         pidlTemp = pidlOut;
834         if(pidlOut)
835         { pidlTemp->mkid.cb = uSize - 2;
836           pData =_ILGetDataPointer(pidlTemp);
837           pszDest =  _ILGetTextPointer(type, pData);
838           pData->type = type;
839           switch(type)
840           { case PT_MYCOMP:
841               memcpy(pszDest, pIn, uInSize);
842               TRACE(pidl,"- create My Computer: %s\n",debugstr_a(pszDest));
843               break;
844             case PT_DRIVE:
845               memcpy(pszDest, pIn, uInSize);
846               TRACE(pidl,"- create Drive: %s\n",debugstr_a(pszDest));
847               break;
848             case PT_FOLDER:
849             case PT_VALUE:   
850               memcpy(pszDest, pIn, uInSize);
851               TRACE(pidl,"- create Value: %s\n",debugstr_a(pszDest));
852               break;
853             default: 
854               FIXME(pidl,"-- wrong argument\n");
855               break;
856           }
857    
858           pidlTemp = ILGetNext(pidlTemp);
859           pidlTemp->mkid.cb = 0x00;
860         }
861         TRACE(pidl,"-- (pidl=%p, size=%u)\n",pidlOut,uSize-2);
862         return pidlOut;
863 }
864 /**************************************************************************
865  *  _ILGetData(PIDLTYPE, LPCITEMIDLIST, LPVOID, UINT16)
866  *
867  * RETURNS
868  *  length of data (raw)
869  */
870 DWORD WINAPI _ILGetData(PIDLTYPE type, LPCITEMIDLIST pidl, LPVOID pOut, UINT32 uOutSize)
871 {       LPPIDLDATA  pData;
872         DWORD       dwReturn=0; 
873         LPSTR       pszSrc;
874         
875         TRACE(pidl,"(%x %p %p %x)\n",type,pidl,pOut,uOutSize);
876         
877         if(!pidl)
878         {  return 0;
879         }
880
881         *(LPSTR)pOut = 0;        
882
883         pData = _ILGetDataPointer(pidl);
884         if ( pData->type != type)
885         { ERR(pidl,"-- wrong type\n");
886           return 0;
887         }
888         pszSrc = _ILGetTextPointer(pData->type, pData);
889
890         switch(type)
891         { case PT_MYCOMP:
892             if(uOutSize < 1)
893               return 0;
894             strncpy((LPSTR)pOut, "My Computer", uOutSize);
895             dwReturn = strlen((LPSTR)pOut)+1;
896             break;
897
898           case PT_DRIVE:
899             if(uOutSize < 1)
900               return 0;
901             strncpy((LPSTR)pOut, pszSrc, uOutSize);
902             dwReturn = strlen((LPSTR)pOut)+1;
903             break;
904
905           case PT_FOLDER:
906           case PT_VALUE: 
907              strncpy((LPSTR)pOut, pszSrc, uOutSize);
908              dwReturn = strlen((LPSTR)pOut)+1;
909              break;
910           default:
911             ERR(pidl,"-- unknown type\n");
912             break;                                                                               
913         }
914         TRACE(pidl,"-- (%p=%s 0x%08lx)\n",pOut,(char*)pOut,dwReturn);
915         return dwReturn;
916 }
917
918
919 /**************************************************************************
920  *  _ILGetDataPointer()
921  */
922 LPPIDLDATA WINAPI _ILGetDataPointer(LPITEMIDLIST pidl)
923 {       if(pidl && pidl->mkid.cb != 0x00)
924           return (LPPIDLDATA)(&pidl->mkid.abID);
925         return NULL;
926 }
927 /**************************************************************************
928  *  _ILGetTextPointer()
929  * gets a pointer to the string stored in the pidl
930  */
931 LPSTR WINAPI _ILGetTextPointer(PIDLTYPE type, LPPIDLDATA pidldata)
932 {/*     TRACE(pidl,"(type=%x data=%p)\n", type, pidldata);*/
933
934         if(!pidldata)
935         { return NULL;
936         }
937         switch (type)
938         { case PT_DRIVE:
939             return (LPSTR)&(pidldata->u.drive.szDriveName);
940           case PT_MYCOMP:
941           case PT_FOLDER:
942           case PT_VALUE:
943             return (LPSTR)&(pidldata->u.file.szText);
944         }
945         return NULL;
946 }
947 BOOL32 WINAPI _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT32 uOutSize)
948 {       LPPIDLDATA pdata =_ILGetDataPointer(pidl);
949         FILETIME ft;
950         SYSTEMTIME time;
951
952         switch (pdata->type)
953         { case PT_DRIVE:
954           case PT_MYCOMP:
955             return FALSE;
956           case PT_FOLDER:
957             DosDateTimeToFileTime(pdata->u.folder.uFileDate, pdata->u.folder.uFileTime, &ft);
958             break;          
959           case PT_VALUE:
960             DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, &ft);
961             break;
962           default:
963             return FALSE;
964         }
965         FileTimeToSystemTime (&ft, &time);
966         return GetDateFormat32A(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL,  pOut, uOutSize);
967 }
968 BOOL32 WINAPI _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT32 uOutSize)
969 {       LPPIDLDATA pdata =_ILGetDataPointer(pidl);
970         char stemp[20]; /* for filesize */
971         
972         switch (pdata->type)
973         { case PT_DRIVE:
974           case PT_MYCOMP:
975           case PT_FOLDER:
976             return FALSE;
977           case PT_VALUE:
978             break;
979           default:
980             return FALSE;
981         }
982         StrFormatByteSize32A(pdata->u.file.dwFileSize, stemp, 20);
983         strncpy( pOut, stemp, 20);
984         return TRUE;
985 }
986
987 BOOL32 WINAPI _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT32 uOutSize)
988 {       char pTemp[MAX_PATH];
989         int i;
990
991         TRACE(pidl,"pidl=%p\n",pidl);
992
993         if ( ! _ILGetValueText(pidl, pTemp, MAX_PATH))
994         { return FALSE;
995         }
996
997         for (i=0; pTemp[i]!='.' && pTemp[i];i++);
998
999         if (!pTemp[i])
1000           return FALSE;
1001           
1002         strncpy(pOut, &pTemp[i], uOutSize);
1003         TRACE(pidl,"%s\n",pOut);
1004
1005         return TRUE;
1006 }
1007
1008 /**************************************************************************
1009  *  IDLList "Item ID List List"
1010  * 
1011  */
1012 static UINT32 WINAPI IDLList_GetState(LPIDLLIST this);
1013 static LPITEMIDLIST WINAPI IDLList_GetElement(LPIDLLIST this, UINT32 nIndex);
1014 static UINT32 WINAPI IDLList_GetCount(LPIDLLIST this);
1015 static BOOL32 WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl);
1016 static BOOL32 WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT32 cidl);
1017 static BOOL32 WINAPI IDLList_InitList(LPIDLLIST this);
1018 static void WINAPI IDLList_CleanList(LPIDLLIST this);
1019
1020 static IDLList_VTable idllvt = 
1021 {       IDLList_GetState,
1022         IDLList_GetElement,
1023         IDLList_GetCount,
1024         IDLList_StoreItem,
1025         IDLList_AddItems,
1026         IDLList_InitList,
1027         IDLList_CleanList
1028 };
1029
1030 LPIDLLIST IDLList_Constructor (UINT32 uStep)
1031 {       LPIDLLIST lpidll;
1032         if (!(lpidll = (LPIDLLIST)HeapAlloc(GetProcessHeap(),0,sizeof(IDLList))))
1033           return NULL;
1034
1035         lpidll->lpvtbl=&idllvt;
1036         lpidll->uStep=uStep;
1037         lpidll->dpa=NULL;
1038
1039         TRACE (shell,"(%p)\n",lpidll);
1040         return lpidll;
1041 }
1042 void IDLList_Destructor(LPIDLLIST this)
1043 {       TRACE (shell,"(%p)\n",this);
1044         IDLList_CleanList(this);
1045 }
1046  
1047 static UINT32 WINAPI IDLList_GetState(LPIDLLIST this)
1048 {       TRACE (shell,"(%p)->(uStep=%u dpa=%p)\n",this, this->uStep, this->dpa);
1049
1050         if (this->uStep == 0)
1051         { if (this->dpa)
1052             return(State_Init);
1053           return(State_OutOfMem);
1054         }
1055         return(State_UnInit);
1056 }
1057 static LPITEMIDLIST WINAPI IDLList_GetElement(LPIDLLIST this, UINT32 nIndex)
1058 {       TRACE (shell,"(%p)->(index=%u)\n",this, nIndex);
1059         return((LPITEMIDLIST)pDPA_GetPtr(this->dpa, nIndex));
1060 }
1061 static UINT32 WINAPI IDLList_GetCount(LPIDLLIST this)
1062 {       TRACE (shell,"(%p)\n",this);
1063         return(IDLList_GetState(this)==State_Init ? DPA_GetPtrCount(this->dpa) : 0);
1064 }
1065 static BOOL32 WINAPI IDLList_StoreItem(LPIDLLIST this, LPITEMIDLIST pidl)
1066 {       TRACE (shell,"(%p)->(pidl=%p)\n",this, pidl);
1067         if (pidl)
1068         { if (IDLList_InitList(this) && pDPA_InsertPtr(this->dpa, 0x7fff, (LPSTR)pidl)>=0)
1069             return(TRUE);
1070           ILFree(pidl);
1071         }
1072         IDLList_CleanList(this);
1073         return(FALSE);
1074 }
1075 static BOOL32 WINAPI IDLList_AddItems(LPIDLLIST this, LPITEMIDLIST *apidl, UINT32 cidl)
1076 {       INT32 i;
1077         TRACE (shell,"(%p)->(apidl=%p cidl=%u)\n",this, apidl, cidl);
1078
1079         for (i=0; i<cidl; ++i)
1080         { if (!IDLList_StoreItem(this, ILClone((LPCITEMIDLIST)apidl[i])))
1081             return(FALSE);
1082         }
1083         return(TRUE);
1084 }
1085 static BOOL32 WINAPI IDLList_InitList(LPIDLLIST this)
1086 {       TRACE (shell,"(%p)\n",this);
1087         switch (IDLList_GetState(this))
1088         { case State_Init:
1089             return(TRUE);
1090
1091           case State_OutOfMem:
1092             return(FALSE);
1093
1094           case State_UnInit:
1095           default:
1096             this->dpa = pDPA_Create(this->uStep);
1097             this->uStep = 0;
1098             return(IDLList_InitList(this));
1099         }
1100 }
1101 static void WINAPI IDLList_CleanList(LPIDLLIST this)
1102 {       INT32 i;
1103         TRACE (shell,"(%p)\n",this);
1104
1105         if (this->uStep != 0)
1106         { this->dpa = NULL;
1107           this->uStep = 0;
1108           return;
1109         }
1110
1111         if (!this->dpa)
1112         { return;
1113         }
1114
1115         for (i=DPA_GetPtrCount(this->dpa)-1; i>=0; --i)
1116         { ILFree(IDLList_GetElement(this,i));
1117         }
1118
1119         pDPA_Destroy(this->dpa);
1120         this->dpa=NULL;
1121 }