Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenclist.c
Go to the documentation of this file.
00001 /* 00002 * SHLWAPI DataBlock List functions 00003 * 00004 * Copyright 2002 Jon Griffiths 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 #include <stdarg.h> 00021 #include <string.h> 00022 00023 #define COBJMACROS 00024 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "winuser.h" 00028 #include "objbase.h" 00029 #include "shlobj.h" 00030 #include "wine/debug.h" 00031 00032 WINE_DEFAULT_DEBUG_CHANNEL(shell); 00033 00034 /* dwSignature for contained DATABLOCK_HEADER items */ 00035 #define CLIST_ID_CONTAINER (~0U) 00036 00037 /************************************************************************* 00038 * NextItem 00039 * 00040 * Internal helper: move a DataBlock pointer to the next item. 00041 */ 00042 static inline LPDATABLOCK_HEADER NextItem(LPDBLIST lpList) 00043 { 00044 char* address = (char*)lpList; 00045 address += lpList->cbSize; 00046 return (LPDATABLOCK_HEADER)address; 00047 } 00048 00049 /************************************************************************* 00050 * @ [SHLWAPI.20] 00051 * 00052 * Insert a new item into a DataBlock list. 00053 * 00054 * PARAMS 00055 * lppList [0] Pointer to the List 00056 * lpNewItem [I] The new item to add to the list 00057 * 00058 * RETURNS 00059 * Success: S_OK. The item is added to the list. 00060 * Failure: An HRESULT error code. 00061 * 00062 * NOTES 00063 * If the size of the element to be inserted is less than the size of a 00064 * DATABLOCK_HEADER node, or the Id for the item is CLIST_ID_CONTAINER, 00065 * the call returns S_OK but does not actually add the element. 00066 * See SHWriteDataBlockList. 00067 */ 00068 HRESULT WINAPI SHAddDataBlock(LPDBLIST* lppList, const DATABLOCK_HEADER *lpNewItem) 00069 { 00070 LPDATABLOCK_HEADER lpInsertAt = NULL; 00071 ULONG ulSize; 00072 00073 TRACE("(%p,%p)\n", lppList, lpNewItem); 00074 00075 if(!lppList || !lpNewItem ) 00076 return E_INVALIDARG; 00077 00078 if (lpNewItem->cbSize < sizeof(DATABLOCK_HEADER) || 00079 lpNewItem->dwSignature == CLIST_ID_CONTAINER) 00080 return S_OK; 00081 00082 ulSize = lpNewItem->cbSize; 00083 00084 if(ulSize & 0x3) 00085 { 00086 /* Tune size to a ULONG boundary, add space for container element */ 00087 ulSize = ((ulSize + 0x3) & 0xFFFFFFFC) + sizeof(DATABLOCK_HEADER); 00088 TRACE("Creating container item, new size = %d\n", ulSize); 00089 } 00090 00091 if(!*lppList) 00092 { 00093 /* An empty list. Allocate space for terminal ulSize also */ 00094 *lppList = LocalAlloc(LMEM_ZEROINIT, ulSize + sizeof(ULONG)); 00095 lpInsertAt = *lppList; 00096 } 00097 else 00098 { 00099 /* Append to the end of the list */ 00100 ULONG ulTotalSize = 0; 00101 LPDATABLOCK_HEADER lpIter = *lppList; 00102 00103 /* Iterate to the end of the list, calculating the total size */ 00104 while (lpIter->cbSize) 00105 { 00106 ulTotalSize += lpIter->cbSize; 00107 lpIter = NextItem(lpIter); 00108 } 00109 00110 /* Increase the size of the list */ 00111 lpIter = LocalReAlloc(*lppList, ulTotalSize + ulSize+sizeof(ULONG), 00112 LMEM_ZEROINIT | LMEM_MOVEABLE); 00113 if(lpIter) 00114 { 00115 *lppList = lpIter; 00116 lpInsertAt = (LPDATABLOCK_HEADER)((char*)lpIter + ulTotalSize); /* At end */ 00117 } 00118 } 00119 00120 if(lpInsertAt) 00121 { 00122 /* Copy in the new item */ 00123 LPDATABLOCK_HEADER lpDest = lpInsertAt; 00124 00125 if(ulSize != lpNewItem->cbSize) 00126 { 00127 lpInsertAt->cbSize = ulSize; 00128 lpInsertAt->dwSignature = CLIST_ID_CONTAINER; 00129 lpDest++; 00130 } 00131 memcpy(lpDest, lpNewItem, lpNewItem->cbSize); 00132 00133 /* Terminate the list */ 00134 lpInsertAt = NextItem(lpInsertAt); 00135 lpInsertAt->cbSize = 0; 00136 00137 return lpNewItem->cbSize; 00138 } 00139 return S_OK; 00140 } 00141 00142 /************************************************************************* 00143 * @ [SHLWAPI.17] 00144 * 00145 * Write a DataBlock list to an IStream object. 00146 * 00147 * PARAMS 00148 * lpStream [I] IStream object to write the list to 00149 * lpList [I] List of items to write 00150 * 00151 * RETURNS 00152 * Success: S_OK. The object is written to the stream. 00153 * Failure: An HRESULT error code 00154 * 00155 * NOTES 00156 * Ordinals 17,18,19,20,21 and 22 are related and together provide a compact 00157 * list structure (a "DataBlock List"), which may be stored and retrieved from 00158 * an IStream object. 00159 * 00160 * The exposed API consists of: 00161 * 00162 * - SHWriteDataBlockList() - Write a DataBlock list to a stream, 00163 * - SHReadDataBlockList() - Read and create a list from a stream, 00164 * - SHFreeDataBlockList() - Free a list, 00165 * - SHAddDataBlock() - Insert a new item into a list, 00166 * - SHRemoveDataBlock() - Remove an item from a list, 00167 * - SHFindDataBlock() - Find an item in a list. 00168 * 00169 * The DataBlock list is stored packed into a memory array. Each element has a 00170 * size and an associated ID. Elements must be less than 64k if the list is 00171 * to be subsequently read from a stream. 00172 * 00173 * Elements are aligned on DWORD boundaries. If an elements data size is not 00174 * a DWORD size multiple, the element is wrapped by inserting a surrounding 00175 * element with an Id of 0xFFFFFFFF, and size sufficient to pad to a DWORD boundary. 00176 * 00177 * These functions are slow for large objects and long lists. 00178 */ 00179 HRESULT WINAPI SHWriteDataBlockList(IStream* lpStream, LPDBLIST lpList) 00180 { 00181 ULONG ulSize; 00182 HRESULT hRet = S_OK; 00183 00184 TRACE("(%p,%p)\n", lpStream, lpList); 00185 00186 if(lpList) 00187 { 00188 while (lpList->cbSize) 00189 { 00190 LPDATABLOCK_HEADER lpItem = lpList; 00191 00192 if(lpList->dwSignature == CLIST_ID_CONTAINER) 00193 lpItem++; 00194 00195 hRet = IStream_Write(lpStream,lpItem,lpItem->cbSize,&ulSize); 00196 if (FAILED(hRet)) 00197 return hRet; 00198 00199 if(lpItem->cbSize != ulSize) 00200 return STG_E_MEDIUMFULL; 00201 00202 lpList = NextItem(lpList); 00203 } 00204 } 00205 00206 if(SUCCEEDED(hRet)) 00207 { 00208 ULONG ulDummy; 00209 ulSize = 0; 00210 00211 /* Write a terminating list entry with zero size */ 00212 hRet = IStream_Write(lpStream, &ulSize,sizeof(ulSize),&ulDummy); 00213 } 00214 00215 return hRet; 00216 } 00217 00218 /************************************************************************* 00219 * @ [SHLWAPI.18] 00220 * 00221 * Read and create a DataBlock list from an IStream object. 00222 * 00223 * PARAMS 00224 * lpStream [I] Stream to read the list from 00225 * lppList [0] Pointer to receive the new List 00226 * 00227 * RETURNS 00228 * Success: S_OK 00229 * Failure: An HRESULT error code 00230 * 00231 * NOTES 00232 * When read from a file, list objects are limited in size to 64k. 00233 * See SHWriteDataBlockList. 00234 */ 00235 HRESULT WINAPI SHReadDataBlockList(IStream* lpStream, LPDBLIST* lppList) 00236 { 00237 DATABLOCK_HEADER bBuff[128]; /* Temporary storage for new list item */ 00238 ULONG ulBuffSize = sizeof(bBuff); 00239 LPDATABLOCK_HEADER pItem = bBuff; 00240 ULONG ulRead, ulSize; 00241 HRESULT hRet = S_OK; 00242 00243 TRACE("(%p,%p)\n", lpStream, lppList); 00244 00245 if(*lppList) 00246 { 00247 /* Free any existing list */ 00248 LocalFree(*lppList); 00249 *lppList = NULL; 00250 } 00251 00252 do 00253 { 00254 /* Read the size of the next item */ 00255 hRet = IStream_Read(lpStream, &ulSize,sizeof(ulSize),&ulRead); 00256 00257 if(FAILED(hRet) || ulRead != sizeof(ulSize) || !ulSize) 00258 break; /* Read failed or read zero size (the end of the list) */ 00259 00260 if(ulSize > 0xFFFF) 00261 { 00262 LARGE_INTEGER liZero; 00263 ULARGE_INTEGER ulPos; 00264 00265 liZero.QuadPart = 0; 00266 00267 /* Back the stream up; this object is too big for the list */ 00268 if(SUCCEEDED(IStream_Seek(lpStream, liZero, STREAM_SEEK_CUR, &ulPos))) 00269 { 00270 liZero.QuadPart = ulPos.QuadPart - sizeof(ULONG); 00271 IStream_Seek(lpStream, liZero, STREAM_SEEK_SET, NULL); 00272 } 00273 break; 00274 } 00275 else if (ulSize >= sizeof(DATABLOCK_HEADER)) 00276 { 00277 /* Add this new item to the list */ 00278 if(ulSize > ulBuffSize) 00279 { 00280 /* We need more buffer space, allocate it */ 00281 LPDATABLOCK_HEADER lpTemp; 00282 00283 if (pItem == bBuff) 00284 lpTemp = LocalAlloc(LMEM_ZEROINIT, ulSize); 00285 else 00286 lpTemp = LocalReAlloc(pItem, ulSize, LMEM_ZEROINIT|LMEM_MOVEABLE); 00287 00288 if(!lpTemp) 00289 { 00290 hRet = E_OUTOFMEMORY; 00291 break; 00292 } 00293 ulBuffSize = ulSize; 00294 pItem = lpTemp; 00295 } 00296 00297 pItem->cbSize = ulSize; 00298 ulSize -= sizeof(pItem->cbSize); /* already read this member */ 00299 00300 /* Read the item Id and data */ 00301 hRet = IStream_Read(lpStream, &pItem->dwSignature, ulSize, &ulRead); 00302 00303 if(FAILED(hRet) || ulRead != ulSize) 00304 break; 00305 00306 SHAddDataBlock(lppList, pItem); /* Insert Item */ 00307 } 00308 } while(1); 00309 00310 /* If we allocated space, free it */ 00311 if(pItem != bBuff) 00312 LocalFree(pItem); 00313 00314 return hRet; 00315 } 00316 00317 /************************************************************************* 00318 * @ [SHLWAPI.19] 00319 * 00320 * Free a DataBlock list. 00321 * 00322 * PARAMS 00323 * lpList [I] List to free 00324 * 00325 * RETURNS 00326 * Nothing. 00327 * 00328 * NOTES 00329 * See SHWriteDataBlockList. 00330 */ 00331 VOID WINAPI SHFreeDataBlockList(LPDBLIST lpList) 00332 { 00333 TRACE("(%p)\n", lpList); 00334 00335 if (lpList) 00336 LocalFree(lpList); 00337 } 00338 00339 /************************************************************************* 00340 * @ [SHLWAPI.21] 00341 * 00342 * Remove an item from a DataBlock list. 00343 * 00344 * PARAMS 00345 * lppList [O] List to remove the item from 00346 * dwSignature [I] Id of item to remove 00347 * 00348 * RETURNS 00349 * Success: TRUE. 00350 * Failure: FALSE, If any parameters are invalid, or the item was not found. 00351 * 00352 * NOTES 00353 * See SHWriteDataBlockList. 00354 */ 00355 BOOL WINAPI SHRemoveDataBlock(LPDBLIST* lppList, DWORD dwSignature) 00356 { 00357 LPDATABLOCK_HEADER lpList = 0; 00358 LPDATABLOCK_HEADER lpItem = NULL; 00359 LPDATABLOCK_HEADER lpNext; 00360 ULONG ulNewSize; 00361 00362 TRACE("(%p,%d)\n", lppList, dwSignature); 00363 00364 if(lppList && (lpList = *lppList)) 00365 { 00366 /* Search for item in list */ 00367 while (lpList->cbSize) 00368 { 00369 if(lpList->dwSignature == dwSignature || 00370 (lpList->dwSignature == CLIST_ID_CONTAINER && lpList[1].dwSignature == dwSignature)) 00371 { 00372 lpItem = lpList; /* Found */ 00373 break; 00374 } 00375 lpList = NextItem(lpList); 00376 } 00377 } 00378 00379 if(!lpItem) 00380 return FALSE; 00381 00382 lpList = lpNext = NextItem(lpItem); 00383 00384 /* Locate the end of the list */ 00385 while (lpList->cbSize) 00386 lpList = NextItem(lpList); 00387 00388 /* Resize the list */ 00389 ulNewSize = LocalSize(*lppList) - lpItem->cbSize; 00390 00391 /* Copy following elements over lpItem */ 00392 memmove(lpItem, lpNext, (char *)lpList - (char *)lpNext + sizeof(ULONG)); 00393 00394 if(ulNewSize <= sizeof(ULONG)) 00395 { 00396 LocalFree(*lppList); 00397 *lppList = NULL; /* Removed the last element */ 00398 } 00399 else 00400 { 00401 lpList = LocalReAlloc(*lppList, ulNewSize, LMEM_ZEROINIT|LMEM_MOVEABLE); 00402 if(lpList) 00403 *lppList = lpList; 00404 } 00405 return TRUE; 00406 } 00407 00408 /************************************************************************* 00409 * @ [SHLWAPI.22] 00410 * 00411 * Find an item in a DataBlock list. 00412 * 00413 * PARAMS 00414 * lpList [I] List to search 00415 * dwSignature [I] Id of item to find 00416 * 00417 * RETURNS 00418 * Success: A pointer to the list item found 00419 * Failure: NULL 00420 * 00421 * NOTES 00422 * See SHWriteDataBlockList. 00423 */ 00424 DATABLOCK_HEADER* WINAPI SHFindDataBlock(LPDBLIST lpList, DWORD dwSignature) 00425 { 00426 TRACE("(%p,%d)\n", lpList, dwSignature); 00427 00428 if(lpList) 00429 { 00430 while(lpList->cbSize) 00431 { 00432 if(lpList->dwSignature == dwSignature) 00433 return lpList; /* Matched */ 00434 else if(lpList->dwSignature == CLIST_ID_CONTAINER && lpList[1].dwSignature == dwSignature) 00435 return lpList + 1; /* Contained item matches */ 00436 00437 lpList = NextItem(lpList); 00438 } 00439 } 00440 return NULL; 00441 } Generated on Sat May 26 2012 04:25:06 for ReactOS by
1.7.6.1
|