1 /*
2  *    IEnumIDList
3  *
4  *    Copyright 1998    Juergen Schmied <juergen.schmied@metronet.de>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(shell);
24 
25 CEnumIDListBase::CEnumIDListBase() :
26     mpFirst(NULL),
27     mpLast(NULL),
28     mpCurrent(NULL)
29 {
30 }
31 
32 CEnumIDListBase::~CEnumIDListBase()
33 {
34     DeleteList();
35 }
36 
37 /**************************************************************************
38  *  AddToEnumList()
39  */
40 BOOL CEnumIDListBase::AddToEnumList(LPITEMIDLIST pidl)
41 {
42     ENUMLIST *pNew;
43 
44     TRACE("(%p)->(pidl=%p)\n", this, pidl);
45 
46     if (!pidl)
47         return FALSE;
48 
49     pNew = static_cast<ENUMLIST *>(SHAlloc(sizeof(ENUMLIST)));
50     if (pNew)
51     {
52       /*set the next pointer */
53       pNew->pNext = NULL;
54       pNew->pidl = pidl;
55 
56       /*is This the first item in the list? */
57       if (!mpFirst)
58       {
59         mpFirst = pNew;
60         mpCurrent = pNew;
61       }
62 
63       if (mpLast)
64       {
65         /*add the new item to the end of the list */
66         mpLast->pNext = pNew;
67       }
68 
69       /*update the last item pointer */
70       mpLast = pNew;
71       TRACE("-- (%p)->(first=%p, last=%p)\n", this, mpFirst, mpLast);
72       return TRUE;
73     }
74     return FALSE;
75 }
76 
77 /**************************************************************************
78 *   DeleteList()
79 */
80 BOOL CEnumIDListBase::DeleteList()
81 {
82     ENUMLIST                    *pDelete;
83 
84     TRACE("(%p)->()\n", this);
85 
86     while (mpFirst)
87     {
88         pDelete = mpFirst;
89         mpFirst = pDelete->pNext;
90         SHFree(pDelete->pidl);
91         SHFree(pDelete);
92     }
93     mpFirst = NULL;
94     mpLast = NULL;
95     mpCurrent = NULL;
96     return TRUE;
97 }
98 
99 /**************************************************************************
100  *  HasItemWithCLSID()
101  */
102 BOOL CEnumIDListBase::HasItemWithCLSID(LPITEMIDLIST pidl)
103 {
104     ENUMLIST *pCur;
105     IID *ptr = _ILGetGUIDPointer(pidl);
106 
107     if (ptr)
108     {
109         REFIID refid = *ptr;
110         pCur = mpFirst;
111 
112         while(pCur)
113         {
114             LPGUID curid = _ILGetGUIDPointer(pCur->pidl);
115             if (curid && IsEqualGUID(*curid, refid))
116             {
117                 return TRUE;
118             }
119             pCur = pCur->pNext;
120         }
121     }
122 
123     return FALSE;
124 }
125 
126 HRESULT CEnumIDListBase::AppendItemsFromEnumerator(IEnumIDList* pEnum)
127 {
128     LPITEMIDLIST pidl;
129     DWORD dwFetched;
130 
131     if (!pEnum)
132         return E_INVALIDARG;
133 
134     pEnum->Reset();
135 
136     while((S_OK == pEnum->Next(1, &pidl, &dwFetched)) && dwFetched)
137         AddToEnumList(pidl);
138 
139     return S_OK;
140 }
141 
142 /**************************************************************************
143  *  IEnumIDList_fnNext
144  */
145 
146 HRESULT WINAPI CEnumIDListBase::Next(
147     ULONG celt,
148     LPITEMIDLIST * rgelt,
149     ULONG *pceltFetched)
150 {
151     ULONG    i;
152     HRESULT  hr = S_OK;
153     LPITEMIDLIST  temp;
154 
155     TRACE("(%p)->(%d,%p, %p)\n", this, celt, rgelt, pceltFetched);
156 
157 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
158  * subsystems actually use it (and so may a third party browser)
159  */
160     if(pceltFetched)
161       *pceltFetched = 0;
162 
163     *rgelt=0;
164 
165     if(celt > 1 && !pceltFetched)
166     { return E_INVALIDARG;
167     }
168 
169     if(celt > 0 && !mpCurrent)
170     { return S_FALSE;
171     }
172 
173     for(i = 0; i < celt; i++)
174     { if(!mpCurrent)
175         break;
176 
177       temp = ILClone(mpCurrent->pidl);
178       rgelt[i] = temp;
179       mpCurrent = mpCurrent->pNext;
180     }
181     if(pceltFetched)
182     {  *pceltFetched = i;
183     }
184 
185     return hr;
186 }
187 
188 /**************************************************************************
189 *  IEnumIDList_fnSkip
190 */
191 HRESULT WINAPI CEnumIDListBase::Skip(
192     ULONG celt)
193 {
194     DWORD    dwIndex;
195     HRESULT  hr = S_OK;
196 
197     TRACE("(%p)->(%u)\n", this, celt);
198 
199     for(dwIndex = 0; dwIndex < celt; dwIndex++)
200     { if(!mpCurrent)
201       { hr = S_FALSE;
202         break;
203       }
204       mpCurrent = mpCurrent->pNext;
205     }
206     return hr;
207 }
208 
209 /**************************************************************************
210 *  IEnumIDList_fnReset
211 */
212 HRESULT WINAPI CEnumIDListBase::Reset()
213 {
214     TRACE("(%p)\n", this);
215     mpCurrent = mpFirst;
216     return S_OK;
217 }
218 
219 /**************************************************************************
220 *  IEnumIDList_fnClone
221 */
222 HRESULT WINAPI CEnumIDListBase::Clone(LPENUMIDLIST *ppenum)
223 {
224     TRACE("(%p)->() to (%p)->() E_NOTIMPL\n", this, ppenum);
225     return E_NOTIMPL;
226 }
227 
228 /**************************************************************************
229  *  IEnumIDList_Folder_Constructor
230  *
231  */
232 HRESULT IEnumIDList_Constructor(IEnumIDList **enumerator)
233 {
234     return ShellObjectCreator<CEnumIDListBase>(IID_PPV_ARG(IEnumIDList, enumerator));
235 }
236