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