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