Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenstg_prop.c
Go to the documentation of this file.
00001 /* 00002 * Compound Storage (32 bit version) 00003 * Storage implementation 00004 * 00005 * This file contains the compound file implementation 00006 * of the storage interface. 00007 * 00008 * Copyright 1999 Francis Beaudet 00009 * Copyright 1999 Sylvain St-Germain 00010 * Copyright 1999 Thuy Nguyen 00011 * Copyright 2005 Mike McCormack 00012 * Copyright 2005 Juan Lang 00013 * 00014 * This library is free software; you can redistribute it and/or 00015 * modify it under the terms of the GNU Lesser General Public 00016 * License as published by the Free Software Foundation; either 00017 * version 2.1 of the License, or (at your option) any later version. 00018 * 00019 * This library is distributed in the hope that it will be useful, 00020 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00022 * Lesser General Public License for more details. 00023 * 00024 * You should have received a copy of the GNU Lesser General Public 00025 * License along with this library; if not, write to the Free Software 00026 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00027 * 00028 * TODO: 00029 * - I don't honor the maximum property set size. 00030 * - Certain bogus files could result in reading past the end of a buffer. 00031 * - Mac-generated files won't be read correctly, even if they're little 00032 * endian, because I disregard whether the generator was a Mac. This means 00033 * strings will probably be munged (as I don't understand Mac scripts.) 00034 * - Not all PROPVARIANT types are supported. 00035 * - User defined properties are not supported, see comment in 00036 * PropertyStorage_ReadFromStream 00037 */ 00038 00039 #include <assert.h> 00040 #include <stdarg.h> 00041 #include <stdio.h> 00042 #include <stdlib.h> 00043 #include <string.h> 00044 00045 #define COBJMACROS 00046 #define NONAMELESSUNION 00047 #define NONAMELESSSTRUCT 00048 00049 #include "windef.h" 00050 #include "winbase.h" 00051 #include "winnls.h" 00052 #include "winuser.h" 00053 #include "wine/unicode.h" 00054 #include "wine/debug.h" 00055 #include "dictionary.h" 00056 #include "storage32.h" 00057 #include "enumx.h" 00058 00059 WINE_DEFAULT_DEBUG_CHANNEL(storage); 00060 00061 static inline StorageImpl *impl_from_IPropertySetStorage( IPropertySetStorage *iface ) 00062 { 00063 return (StorageImpl *)((char*)iface - FIELD_OFFSET(StorageImpl, base.pssVtbl)); 00064 } 00065 00066 /* These are documented in MSDN, 00067 * but they don't seem to be in any header file. 00068 */ 00069 #define PROPSETHDR_BYTEORDER_MAGIC 0xfffe 00070 #define PROPSETHDR_OSVER_KIND_WIN16 0 00071 #define PROPSETHDR_OSVER_KIND_MAC 1 00072 #define PROPSETHDR_OSVER_KIND_WIN32 2 00073 00074 #define CP_UNICODE 1200 00075 00076 #define MAX_VERSION_0_PROP_NAME_LENGTH 256 00077 00078 #define CFTAG_WINDOWS (-1L) 00079 #define CFTAG_MACINTOSH (-2L) 00080 #define CFTAG_FMTID (-3L) 00081 #define CFTAG_NODATA 0L 00082 00083 typedef struct tagPROPERTYSETHEADER 00084 { 00085 WORD wByteOrder; /* always 0xfffe */ 00086 WORD wFormat; /* can be zero or one */ 00087 DWORD dwOSVer; /* OS version of originating system */ 00088 CLSID clsid; /* application CLSID */ 00089 DWORD reserved; /* always 1 */ 00090 } PROPERTYSETHEADER; 00091 00092 typedef struct tagFORMATIDOFFSET 00093 { 00094 FMTID fmtid; 00095 DWORD dwOffset; /* from beginning of stream */ 00096 } FORMATIDOFFSET; 00097 00098 typedef struct tagPROPERTYSECTIONHEADER 00099 { 00100 DWORD cbSection; 00101 DWORD cProperties; 00102 } PROPERTYSECTIONHEADER; 00103 00104 typedef struct tagPROPERTYIDOFFSET 00105 { 00106 DWORD propid; 00107 DWORD dwOffset; /* from beginning of section */ 00108 } PROPERTYIDOFFSET; 00109 00110 typedef struct tagPropertyStorage_impl PropertyStorage_impl; 00111 00112 /* Initializes the property storage from the stream (and undoes any uncommitted 00113 * changes in the process.) Returns an error if there is an error reading or 00114 * if the stream format doesn't match what's expected. 00115 */ 00116 static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *); 00117 00118 static HRESULT PropertyStorage_WriteToStream(PropertyStorage_impl *); 00119 00120 /* Creates the dictionaries used by the property storage. If successful, all 00121 * the dictionaries have been created. If failed, none has been. (This makes 00122 * it a bit easier to deal with destroying them.) 00123 */ 00124 static HRESULT PropertyStorage_CreateDictionaries(PropertyStorage_impl *); 00125 00126 static void PropertyStorage_DestroyDictionaries(PropertyStorage_impl *); 00127 00128 /* Copies from propvar to prop. If propvar's type is VT_LPSTR, copies the 00129 * string using PropertyStorage_StringCopy. 00130 */ 00131 static HRESULT PropertyStorage_PropVariantCopy(PROPVARIANT *prop, 00132 const PROPVARIANT *propvar, LCID targetCP, LCID srcCP); 00133 00134 /* Copies the string src, which is encoded using code page srcCP, and returns 00135 * it in *dst, in the code page specified by targetCP. The returned string is 00136 * allocated using CoTaskMemAlloc. 00137 * If srcCP is CP_UNICODE, src is in fact an LPCWSTR. Similarly, if targetCP 00138 * is CP_UNICODE, the returned string is in fact an LPWSTR. 00139 * Returns S_OK on success, something else on failure. 00140 */ 00141 static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, 00142 LCID targetCP); 00143 00144 static const IPropertyStorageVtbl IPropertyStorage_Vtbl; 00145 static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl; 00146 static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl; 00147 static HRESULT create_EnumSTATPROPSETSTG(StorageImpl *, IEnumSTATPROPSETSTG**); 00148 static HRESULT create_EnumSTATPROPSTG(PropertyStorage_impl *, IEnumSTATPROPSTG**); 00149 00150 /*********************************************************************** 00151 * Implementation of IPropertyStorage 00152 */ 00153 struct tagPropertyStorage_impl 00154 { 00155 IPropertyStorage IPropertyStorage_iface; 00156 LONG ref; 00157 CRITICAL_SECTION cs; 00158 IStream *stm; 00159 BOOL dirty; 00160 FMTID fmtid; 00161 CLSID clsid; 00162 WORD format; 00163 DWORD originatorOS; 00164 DWORD grfFlags; 00165 DWORD grfMode; 00166 UINT codePage; 00167 LCID locale; 00168 PROPID highestProp; 00169 struct dictionary *name_to_propid; 00170 struct dictionary *propid_to_name; 00171 struct dictionary *propid_to_prop; 00172 }; 00173 00174 static inline PropertyStorage_impl *impl_from_IPropertyStorage(IPropertyStorage *iface) 00175 { 00176 return CONTAINING_RECORD(iface, PropertyStorage_impl, IPropertyStorage_iface); 00177 } 00178 00179 /************************************************************************ 00180 * IPropertyStorage_fnQueryInterface (IPropertyStorage) 00181 */ 00182 static HRESULT WINAPI IPropertyStorage_fnQueryInterface( 00183 IPropertyStorage *iface, 00184 REFIID riid, 00185 void** ppvObject) 00186 { 00187 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00188 00189 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject); 00190 00191 if (!ppvObject) 00192 return E_INVALIDARG; 00193 00194 *ppvObject = 0; 00195 00196 if (IsEqualGUID(&IID_IUnknown, riid) || 00197 IsEqualGUID(&IID_IPropertyStorage, riid)) 00198 { 00199 IPropertyStorage_AddRef(iface); 00200 *ppvObject = iface; 00201 return S_OK; 00202 } 00203 00204 return E_NOINTERFACE; 00205 } 00206 00207 /************************************************************************ 00208 * IPropertyStorage_fnAddRef (IPropertyStorage) 00209 */ 00210 static ULONG WINAPI IPropertyStorage_fnAddRef( 00211 IPropertyStorage *iface) 00212 { 00213 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00214 return InterlockedIncrement(&This->ref); 00215 } 00216 00217 /************************************************************************ 00218 * IPropertyStorage_fnRelease (IPropertyStorage) 00219 */ 00220 static ULONG WINAPI IPropertyStorage_fnRelease( 00221 IPropertyStorage *iface) 00222 { 00223 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00224 ULONG ref; 00225 00226 ref = InterlockedDecrement(&This->ref); 00227 if (ref == 0) 00228 { 00229 TRACE("Destroying %p\n", This); 00230 if (This->dirty) 00231 IPropertyStorage_Commit(iface, STGC_DEFAULT); 00232 IStream_Release(This->stm); 00233 This->cs.DebugInfo->Spare[0] = 0; 00234 DeleteCriticalSection(&This->cs); 00235 PropertyStorage_DestroyDictionaries(This); 00236 HeapFree(GetProcessHeap(), 0, This); 00237 } 00238 return ref; 00239 } 00240 00241 static PROPVARIANT *PropertyStorage_FindProperty(PropertyStorage_impl *This, 00242 DWORD propid) 00243 { 00244 PROPVARIANT *ret = NULL; 00245 00246 dictionary_find(This->propid_to_prop, UlongToPtr(propid), (void **)&ret); 00247 TRACE("returning %p\n", ret); 00248 return ret; 00249 } 00250 00251 /* Returns NULL if name is NULL. */ 00252 static PROPVARIANT *PropertyStorage_FindPropertyByName( 00253 PropertyStorage_impl *This, LPCWSTR name) 00254 { 00255 PROPVARIANT *ret = NULL; 00256 void *propid; 00257 00258 if (!name) 00259 return NULL; 00260 if (This->codePage == CP_UNICODE) 00261 { 00262 if (dictionary_find(This->name_to_propid, name, &propid)) 00263 ret = PropertyStorage_FindProperty(This, PtrToUlong(propid)); 00264 } 00265 else 00266 { 00267 LPSTR ansiName; 00268 HRESULT hr = PropertyStorage_StringCopy((LPCSTR)name, CP_UNICODE, 00269 &ansiName, This->codePage); 00270 00271 if (SUCCEEDED(hr)) 00272 { 00273 if (dictionary_find(This->name_to_propid, ansiName, &propid)) 00274 ret = PropertyStorage_FindProperty(This, PtrToUlong(propid)); 00275 CoTaskMemFree(ansiName); 00276 } 00277 } 00278 TRACE("returning %p\n", ret); 00279 return ret; 00280 } 00281 00282 static LPWSTR PropertyStorage_FindPropertyNameById(PropertyStorage_impl *This, 00283 DWORD propid) 00284 { 00285 LPWSTR ret = NULL; 00286 00287 dictionary_find(This->propid_to_name, UlongToPtr(propid), (void **)&ret); 00288 TRACE("returning %p\n", ret); 00289 return ret; 00290 } 00291 00292 /************************************************************************ 00293 * IPropertyStorage_fnReadMultiple (IPropertyStorage) 00294 */ 00295 static HRESULT WINAPI IPropertyStorage_fnReadMultiple( 00296 IPropertyStorage* iface, 00297 ULONG cpspec, 00298 const PROPSPEC rgpspec[], 00299 PROPVARIANT rgpropvar[]) 00300 { 00301 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00302 HRESULT hr = S_OK; 00303 ULONG i; 00304 00305 TRACE("(%p, %d, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar); 00306 00307 if (!cpspec) 00308 return S_FALSE; 00309 if (!rgpspec || !rgpropvar) 00310 return E_INVALIDARG; 00311 EnterCriticalSection(&This->cs); 00312 for (i = 0; i < cpspec; i++) 00313 { 00314 PropVariantInit(&rgpropvar[i]); 00315 if (rgpspec[i].ulKind == PRSPEC_LPWSTR) 00316 { 00317 PROPVARIANT *prop = PropertyStorage_FindPropertyByName(This, 00318 rgpspec[i].u.lpwstr); 00319 00320 if (prop) 00321 PropertyStorage_PropVariantCopy(&rgpropvar[i], prop, GetACP(), 00322 This->codePage); 00323 } 00324 else 00325 { 00326 switch (rgpspec[i].u.propid) 00327 { 00328 case PID_CODEPAGE: 00329 rgpropvar[i].vt = VT_I2; 00330 rgpropvar[i].u.iVal = This->codePage; 00331 break; 00332 case PID_LOCALE: 00333 rgpropvar[i].vt = VT_I4; 00334 rgpropvar[i].u.lVal = This->locale; 00335 break; 00336 default: 00337 { 00338 PROPVARIANT *prop = PropertyStorage_FindProperty(This, 00339 rgpspec[i].u.propid); 00340 00341 if (prop) 00342 PropertyStorage_PropVariantCopy(&rgpropvar[i], prop, 00343 GetACP(), This->codePage); 00344 else 00345 hr = S_FALSE; 00346 } 00347 } 00348 } 00349 } 00350 LeaveCriticalSection(&This->cs); 00351 return hr; 00352 } 00353 00354 static HRESULT PropertyStorage_StringCopy(LPCSTR src, LCID srcCP, LPSTR *dst, 00355 LCID dstCP) 00356 { 00357 HRESULT hr = S_OK; 00358 int len; 00359 00360 TRACE("%s, %p, %d, %d\n", 00361 srcCP == CP_UNICODE ? debugstr_w((LPCWSTR)src) : debugstr_a(src), dst, 00362 dstCP, srcCP); 00363 assert(src); 00364 assert(dst); 00365 *dst = NULL; 00366 if (dstCP == srcCP) 00367 { 00368 size_t len; 00369 00370 if (dstCP == CP_UNICODE) 00371 len = (strlenW((LPCWSTR)src) + 1) * sizeof(WCHAR); 00372 else 00373 len = strlen(src) + 1; 00374 *dst = CoTaskMemAlloc(len * sizeof(WCHAR)); 00375 if (!*dst) 00376 hr = STG_E_INSUFFICIENTMEMORY; 00377 else 00378 memcpy(*dst, src, len); 00379 } 00380 else 00381 { 00382 if (dstCP == CP_UNICODE) 00383 { 00384 len = MultiByteToWideChar(srcCP, 0, src, -1, NULL, 0); 00385 *dst = CoTaskMemAlloc(len * sizeof(WCHAR)); 00386 if (!*dst) 00387 hr = STG_E_INSUFFICIENTMEMORY; 00388 else 00389 MultiByteToWideChar(srcCP, 0, src, -1, (LPWSTR)*dst, len); 00390 } 00391 else 00392 { 00393 LPCWSTR wideStr = NULL; 00394 LPWSTR wideStr_tmp = NULL; 00395 00396 if (srcCP == CP_UNICODE) 00397 wideStr = (LPCWSTR)src; 00398 else 00399 { 00400 len = MultiByteToWideChar(srcCP, 0, src, -1, NULL, 0); 00401 wideStr_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 00402 if (wideStr_tmp) 00403 { 00404 MultiByteToWideChar(srcCP, 0, src, -1, wideStr_tmp, len); 00405 wideStr = wideStr_tmp; 00406 } 00407 else 00408 hr = STG_E_INSUFFICIENTMEMORY; 00409 } 00410 if (SUCCEEDED(hr)) 00411 { 00412 len = WideCharToMultiByte(dstCP, 0, wideStr, -1, NULL, 0, 00413 NULL, NULL); 00414 *dst = CoTaskMemAlloc(len); 00415 if (!*dst) 00416 hr = STG_E_INSUFFICIENTMEMORY; 00417 else 00418 { 00419 BOOL defCharUsed = FALSE; 00420 00421 if (WideCharToMultiByte(dstCP, 0, wideStr, -1, *dst, len, 00422 NULL, &defCharUsed) == 0 || defCharUsed) 00423 { 00424 CoTaskMemFree(*dst); 00425 *dst = NULL; 00426 hr = HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION); 00427 } 00428 } 00429 } 00430 HeapFree(GetProcessHeap(), 0, wideStr_tmp); 00431 } 00432 } 00433 TRACE("returning 0x%08x (%s)\n", hr, 00434 dstCP == CP_UNICODE ? debugstr_w((LPCWSTR)*dst) : debugstr_a(*dst)); 00435 return hr; 00436 } 00437 00438 static HRESULT PropertyStorage_PropVariantCopy(PROPVARIANT *prop, 00439 const PROPVARIANT *propvar, LCID targetCP, LCID srcCP) 00440 { 00441 HRESULT hr = S_OK; 00442 00443 assert(prop); 00444 assert(propvar); 00445 if (propvar->vt == VT_LPSTR) 00446 { 00447 hr = PropertyStorage_StringCopy(propvar->u.pszVal, srcCP, 00448 &prop->u.pszVal, targetCP); 00449 if (SUCCEEDED(hr)) 00450 prop->vt = VT_LPSTR; 00451 } 00452 else 00453 PropVariantCopy(prop, propvar); 00454 return hr; 00455 } 00456 00457 /* Stores the property with id propid and value propvar into this property 00458 * storage. lcid is ignored if propvar's type is not VT_LPSTR. If propvar's 00459 * type is VT_LPSTR, converts the string using lcid as the source code page 00460 * and This->codePage as the target code page before storing. 00461 * As a side effect, may change This->format to 1 if the type of propvar is 00462 * a version 1-only property. 00463 */ 00464 static HRESULT PropertyStorage_StorePropWithId(PropertyStorage_impl *This, 00465 PROPID propid, const PROPVARIANT *propvar, LCID lcid) 00466 { 00467 HRESULT hr = S_OK; 00468 PROPVARIANT *prop = PropertyStorage_FindProperty(This, propid); 00469 00470 assert(propvar); 00471 if (propvar->vt & VT_BYREF || propvar->vt & VT_ARRAY) 00472 This->format = 1; 00473 switch (propvar->vt) 00474 { 00475 case VT_DECIMAL: 00476 case VT_I1: 00477 case VT_INT: 00478 case VT_UINT: 00479 case VT_VECTOR|VT_I1: 00480 This->format = 1; 00481 } 00482 TRACE("Setting 0x%08x to type %d\n", propid, propvar->vt); 00483 if (prop) 00484 { 00485 PropVariantClear(prop); 00486 hr = PropertyStorage_PropVariantCopy(prop, propvar, This->codePage, 00487 lcid); 00488 } 00489 else 00490 { 00491 prop = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 00492 sizeof(PROPVARIANT)); 00493 if (prop) 00494 { 00495 hr = PropertyStorage_PropVariantCopy(prop, propvar, This->codePage, 00496 lcid); 00497 if (SUCCEEDED(hr)) 00498 { 00499 dictionary_insert(This->propid_to_prop, UlongToPtr(propid), prop); 00500 if (propid > This->highestProp) 00501 This->highestProp = propid; 00502 } 00503 else 00504 HeapFree(GetProcessHeap(), 0, prop); 00505 } 00506 else 00507 hr = STG_E_INSUFFICIENTMEMORY; 00508 } 00509 return hr; 00510 } 00511 00512 /* Adds the name srcName to the name dictionaries, mapped to property ID id. 00513 * srcName is encoded in code page cp, and is converted to This->codePage. 00514 * If cp is CP_UNICODE, srcName is actually a unicode string. 00515 * As a side effect, may change This->format to 1 if srcName is too long for 00516 * a version 0 property storage. 00517 * Doesn't validate id. 00518 */ 00519 static HRESULT PropertyStorage_StoreNameWithId(PropertyStorage_impl *This, 00520 LPCSTR srcName, LCID cp, PROPID id) 00521 { 00522 LPSTR name; 00523 HRESULT hr; 00524 00525 assert(srcName); 00526 00527 hr = PropertyStorage_StringCopy(srcName, cp, &name, This->codePage); 00528 if (SUCCEEDED(hr)) 00529 { 00530 if (This->codePage == CP_UNICODE) 00531 { 00532 if (lstrlenW((LPWSTR)name) >= MAX_VERSION_0_PROP_NAME_LENGTH) 00533 This->format = 1; 00534 } 00535 else 00536 { 00537 if (strlen(name) >= MAX_VERSION_0_PROP_NAME_LENGTH) 00538 This->format = 1; 00539 } 00540 TRACE("Adding prop name %s, propid %d\n", 00541 This->codePage == CP_UNICODE ? debugstr_w((LPCWSTR)name) : 00542 debugstr_a(name), id); 00543 dictionary_insert(This->name_to_propid, name, UlongToPtr(id)); 00544 dictionary_insert(This->propid_to_name, UlongToPtr(id), name); 00545 } 00546 return hr; 00547 } 00548 00549 /************************************************************************ 00550 * IPropertyStorage_fnWriteMultiple (IPropertyStorage) 00551 */ 00552 static HRESULT WINAPI IPropertyStorage_fnWriteMultiple( 00553 IPropertyStorage* iface, 00554 ULONG cpspec, 00555 const PROPSPEC rgpspec[], 00556 const PROPVARIANT rgpropvar[], 00557 PROPID propidNameFirst) 00558 { 00559 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00560 HRESULT hr = S_OK; 00561 ULONG i; 00562 00563 TRACE("(%p, %d, %p, %p)\n", iface, cpspec, rgpspec, rgpropvar); 00564 00565 if (cpspec && (!rgpspec || !rgpropvar)) 00566 return E_INVALIDARG; 00567 if (!(This->grfMode & STGM_READWRITE)) 00568 return STG_E_ACCESSDENIED; 00569 EnterCriticalSection(&This->cs); 00570 This->dirty = TRUE; 00571 This->originatorOS = (DWORD)MAKELONG(LOWORD(GetVersion()), 00572 PROPSETHDR_OSVER_KIND_WIN32) ; 00573 for (i = 0; i < cpspec; i++) 00574 { 00575 if (rgpspec[i].ulKind == PRSPEC_LPWSTR) 00576 { 00577 PROPVARIANT *prop = PropertyStorage_FindPropertyByName(This, 00578 rgpspec[i].u.lpwstr); 00579 00580 if (prop) 00581 PropVariantCopy(prop, &rgpropvar[i]); 00582 else 00583 { 00584 /* Note that I don't do the special cases here that I do below, 00585 * because naming the special PIDs isn't supported. 00586 */ 00587 if (propidNameFirst < PID_FIRST_USABLE || 00588 propidNameFirst >= PID_MIN_READONLY) 00589 hr = STG_E_INVALIDPARAMETER; 00590 else 00591 { 00592 PROPID nextId = max(propidNameFirst, This->highestProp + 1); 00593 00594 hr = PropertyStorage_StoreNameWithId(This, 00595 (LPCSTR)rgpspec[i].u.lpwstr, CP_UNICODE, nextId); 00596 if (SUCCEEDED(hr)) 00597 hr = PropertyStorage_StorePropWithId(This, nextId, 00598 &rgpropvar[i], GetACP()); 00599 } 00600 } 00601 } 00602 else 00603 { 00604 switch (rgpspec[i].u.propid) 00605 { 00606 case PID_DICTIONARY: 00607 /* Can't set the dictionary */ 00608 hr = STG_E_INVALIDPARAMETER; 00609 break; 00610 case PID_CODEPAGE: 00611 /* Can only set the code page if nothing else has been set */ 00612 if (dictionary_num_entries(This->propid_to_prop) == 0 && 00613 rgpropvar[i].vt == VT_I2) 00614 { 00615 This->codePage = rgpropvar[i].u.iVal; 00616 if (This->codePage == CP_UNICODE) 00617 This->grfFlags &= ~PROPSETFLAG_ANSI; 00618 else 00619 This->grfFlags |= PROPSETFLAG_ANSI; 00620 } 00621 else 00622 hr = STG_E_INVALIDPARAMETER; 00623 break; 00624 case PID_LOCALE: 00625 /* Can only set the locale if nothing else has been set */ 00626 if (dictionary_num_entries(This->propid_to_prop) == 0 && 00627 rgpropvar[i].vt == VT_I4) 00628 This->locale = rgpropvar[i].u.lVal; 00629 else 00630 hr = STG_E_INVALIDPARAMETER; 00631 break; 00632 case PID_ILLEGAL: 00633 /* silently ignore like MSDN says */ 00634 break; 00635 default: 00636 if (rgpspec[i].u.propid >= PID_MIN_READONLY) 00637 hr = STG_E_INVALIDPARAMETER; 00638 else 00639 hr = PropertyStorage_StorePropWithId(This, 00640 rgpspec[i].u.propid, &rgpropvar[i], GetACP()); 00641 } 00642 } 00643 } 00644 if (This->grfFlags & PROPSETFLAG_UNBUFFERED) 00645 IPropertyStorage_Commit(iface, STGC_DEFAULT); 00646 LeaveCriticalSection(&This->cs); 00647 return hr; 00648 } 00649 00650 /************************************************************************ 00651 * IPropertyStorage_fnDeleteMultiple (IPropertyStorage) 00652 */ 00653 static HRESULT WINAPI IPropertyStorage_fnDeleteMultiple( 00654 IPropertyStorage* iface, 00655 ULONG cpspec, 00656 const PROPSPEC rgpspec[]) 00657 { 00658 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00659 ULONG i; 00660 HRESULT hr; 00661 00662 TRACE("(%p, %d, %p)\n", iface, cpspec, rgpspec); 00663 00664 if (cpspec && !rgpspec) 00665 return E_INVALIDARG; 00666 if (!(This->grfMode & STGM_READWRITE)) 00667 return STG_E_ACCESSDENIED; 00668 hr = S_OK; 00669 EnterCriticalSection(&This->cs); 00670 This->dirty = TRUE; 00671 for (i = 0; i < cpspec; i++) 00672 { 00673 if (rgpspec[i].ulKind == PRSPEC_LPWSTR) 00674 { 00675 void *propid; 00676 00677 if (dictionary_find(This->name_to_propid, rgpspec[i].u.lpwstr, &propid)) 00678 dictionary_remove(This->propid_to_prop, propid); 00679 } 00680 else 00681 { 00682 if (rgpspec[i].u.propid >= PID_FIRST_USABLE && 00683 rgpspec[i].u.propid < PID_MIN_READONLY) 00684 dictionary_remove(This->propid_to_prop, UlongToPtr(rgpspec[i].u.propid)); 00685 else 00686 hr = STG_E_INVALIDPARAMETER; 00687 } 00688 } 00689 if (This->grfFlags & PROPSETFLAG_UNBUFFERED) 00690 IPropertyStorage_Commit(iface, STGC_DEFAULT); 00691 LeaveCriticalSection(&This->cs); 00692 return hr; 00693 } 00694 00695 /************************************************************************ 00696 * IPropertyStorage_fnReadPropertyNames (IPropertyStorage) 00697 */ 00698 static HRESULT WINAPI IPropertyStorage_fnReadPropertyNames( 00699 IPropertyStorage* iface, 00700 ULONG cpropid, 00701 const PROPID rgpropid[], 00702 LPOLESTR rglpwstrName[]) 00703 { 00704 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00705 ULONG i; 00706 HRESULT hr = S_FALSE; 00707 00708 TRACE("(%p, %d, %p, %p)\n", iface, cpropid, rgpropid, rglpwstrName); 00709 00710 if (cpropid && (!rgpropid || !rglpwstrName)) 00711 return E_INVALIDARG; 00712 EnterCriticalSection(&This->cs); 00713 for (i = 0; i < cpropid && SUCCEEDED(hr); i++) 00714 { 00715 LPWSTR name = PropertyStorage_FindPropertyNameById(This, rgpropid[i]); 00716 00717 if (name) 00718 { 00719 size_t len = lstrlenW(name); 00720 00721 hr = S_OK; 00722 rglpwstrName[i] = CoTaskMemAlloc((len + 1) * sizeof(WCHAR)); 00723 if (rglpwstrName[i]) 00724 memcpy(rglpwstrName[i], name, (len + 1) * sizeof(WCHAR)); 00725 else 00726 hr = STG_E_INSUFFICIENTMEMORY; 00727 } 00728 else 00729 rglpwstrName[i] = NULL; 00730 } 00731 LeaveCriticalSection(&This->cs); 00732 return hr; 00733 } 00734 00735 /************************************************************************ 00736 * IPropertyStorage_fnWritePropertyNames (IPropertyStorage) 00737 */ 00738 static HRESULT WINAPI IPropertyStorage_fnWritePropertyNames( 00739 IPropertyStorage* iface, 00740 ULONG cpropid, 00741 const PROPID rgpropid[], 00742 const LPOLESTR rglpwstrName[]) 00743 { 00744 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00745 ULONG i; 00746 HRESULT hr; 00747 00748 TRACE("(%p, %d, %p, %p)\n", iface, cpropid, rgpropid, rglpwstrName); 00749 00750 if (cpropid && (!rgpropid || !rglpwstrName)) 00751 return E_INVALIDARG; 00752 if (!(This->grfMode & STGM_READWRITE)) 00753 return STG_E_ACCESSDENIED; 00754 hr = S_OK; 00755 EnterCriticalSection(&This->cs); 00756 This->dirty = TRUE; 00757 for (i = 0; SUCCEEDED(hr) && i < cpropid; i++) 00758 { 00759 if (rgpropid[i] != PID_ILLEGAL) 00760 hr = PropertyStorage_StoreNameWithId(This, (LPCSTR)rglpwstrName[i], 00761 CP_UNICODE, rgpropid[i]); 00762 } 00763 if (This->grfFlags & PROPSETFLAG_UNBUFFERED) 00764 IPropertyStorage_Commit(iface, STGC_DEFAULT); 00765 LeaveCriticalSection(&This->cs); 00766 return hr; 00767 } 00768 00769 /************************************************************************ 00770 * IPropertyStorage_fnDeletePropertyNames (IPropertyStorage) 00771 */ 00772 static HRESULT WINAPI IPropertyStorage_fnDeletePropertyNames( 00773 IPropertyStorage* iface, 00774 ULONG cpropid, 00775 const PROPID rgpropid[]) 00776 { 00777 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00778 ULONG i; 00779 HRESULT hr; 00780 00781 TRACE("(%p, %d, %p)\n", iface, cpropid, rgpropid); 00782 00783 if (cpropid && !rgpropid) 00784 return E_INVALIDARG; 00785 if (!(This->grfMode & STGM_READWRITE)) 00786 return STG_E_ACCESSDENIED; 00787 hr = S_OK; 00788 EnterCriticalSection(&This->cs); 00789 This->dirty = TRUE; 00790 for (i = 0; i < cpropid; i++) 00791 { 00792 LPWSTR name = NULL; 00793 00794 if (dictionary_find(This->propid_to_name, UlongToPtr(rgpropid[i]), (void **)&name)) 00795 { 00796 dictionary_remove(This->propid_to_name, UlongToPtr(rgpropid[i])); 00797 dictionary_remove(This->name_to_propid, name); 00798 } 00799 } 00800 if (This->grfFlags & PROPSETFLAG_UNBUFFERED) 00801 IPropertyStorage_Commit(iface, STGC_DEFAULT); 00802 LeaveCriticalSection(&This->cs); 00803 return hr; 00804 } 00805 00806 /************************************************************************ 00807 * IPropertyStorage_fnCommit (IPropertyStorage) 00808 */ 00809 static HRESULT WINAPI IPropertyStorage_fnCommit( 00810 IPropertyStorage* iface, 00811 DWORD grfCommitFlags) 00812 { 00813 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00814 HRESULT hr; 00815 00816 TRACE("(%p, 0x%08x)\n", iface, grfCommitFlags); 00817 00818 if (!(This->grfMode & STGM_READWRITE)) 00819 return STG_E_ACCESSDENIED; 00820 EnterCriticalSection(&This->cs); 00821 if (This->dirty) 00822 hr = PropertyStorage_WriteToStream(This); 00823 else 00824 hr = S_OK; 00825 LeaveCriticalSection(&This->cs); 00826 return hr; 00827 } 00828 00829 /************************************************************************ 00830 * IPropertyStorage_fnRevert (IPropertyStorage) 00831 */ 00832 static HRESULT WINAPI IPropertyStorage_fnRevert( 00833 IPropertyStorage* iface) 00834 { 00835 HRESULT hr; 00836 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00837 00838 TRACE("%p\n", iface); 00839 00840 EnterCriticalSection(&This->cs); 00841 if (This->dirty) 00842 { 00843 PropertyStorage_DestroyDictionaries(This); 00844 hr = PropertyStorage_CreateDictionaries(This); 00845 if (SUCCEEDED(hr)) 00846 hr = PropertyStorage_ReadFromStream(This); 00847 } 00848 else 00849 hr = S_OK; 00850 LeaveCriticalSection(&This->cs); 00851 return hr; 00852 } 00853 00854 /************************************************************************ 00855 * IPropertyStorage_fnEnum (IPropertyStorage) 00856 */ 00857 static HRESULT WINAPI IPropertyStorage_fnEnum( 00858 IPropertyStorage* iface, 00859 IEnumSTATPROPSTG** ppenum) 00860 { 00861 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00862 return create_EnumSTATPROPSTG(This, ppenum); 00863 } 00864 00865 /************************************************************************ 00866 * IPropertyStorage_fnSetTimes (IPropertyStorage) 00867 */ 00868 static HRESULT WINAPI IPropertyStorage_fnSetTimes( 00869 IPropertyStorage* iface, 00870 const FILETIME* pctime, 00871 const FILETIME* patime, 00872 const FILETIME* pmtime) 00873 { 00874 FIXME("\n"); 00875 return E_NOTIMPL; 00876 } 00877 00878 /************************************************************************ 00879 * IPropertyStorage_fnSetClass (IPropertyStorage) 00880 */ 00881 static HRESULT WINAPI IPropertyStorage_fnSetClass( 00882 IPropertyStorage* iface, 00883 REFCLSID clsid) 00884 { 00885 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00886 00887 TRACE("%p, %s\n", iface, debugstr_guid(clsid)); 00888 00889 if (!clsid) 00890 return E_INVALIDARG; 00891 if (!(This->grfMode & STGM_READWRITE)) 00892 return STG_E_ACCESSDENIED; 00893 This->clsid = *clsid; 00894 This->dirty = TRUE; 00895 if (This->grfFlags & PROPSETFLAG_UNBUFFERED) 00896 IPropertyStorage_Commit(iface, STGC_DEFAULT); 00897 return S_OK; 00898 } 00899 00900 /************************************************************************ 00901 * IPropertyStorage_fnStat (IPropertyStorage) 00902 */ 00903 static HRESULT WINAPI IPropertyStorage_fnStat( 00904 IPropertyStorage* iface, 00905 STATPROPSETSTG* statpsstg) 00906 { 00907 PropertyStorage_impl *This = impl_from_IPropertyStorage(iface); 00908 STATSTG stat; 00909 HRESULT hr; 00910 00911 TRACE("%p, %p\n", iface, statpsstg); 00912 00913 if (!statpsstg) 00914 return E_INVALIDARG; 00915 00916 hr = IStream_Stat(This->stm, &stat, STATFLAG_NONAME); 00917 if (SUCCEEDED(hr)) 00918 { 00919 statpsstg->fmtid = This->fmtid; 00920 statpsstg->clsid = This->clsid; 00921 statpsstg->grfFlags = This->grfFlags; 00922 statpsstg->mtime = stat.mtime; 00923 statpsstg->ctime = stat.ctime; 00924 statpsstg->atime = stat.atime; 00925 statpsstg->dwOSVersion = This->originatorOS; 00926 } 00927 return hr; 00928 } 00929 00930 static int PropertyStorage_PropNameCompare(const void *a, const void *b, 00931 void *extra) 00932 { 00933 PropertyStorage_impl *This = extra; 00934 00935 if (This->codePage == CP_UNICODE) 00936 { 00937 TRACE("(%s, %s)\n", debugstr_w(a), debugstr_w(b)); 00938 if (This->grfFlags & PROPSETFLAG_CASE_SENSITIVE) 00939 return lstrcmpW(a, b); 00940 else 00941 return lstrcmpiW(a, b); 00942 } 00943 else 00944 { 00945 TRACE("(%s, %s)\n", debugstr_a(a), debugstr_a(b)); 00946 if (This->grfFlags & PROPSETFLAG_CASE_SENSITIVE) 00947 return lstrcmpA(a, b); 00948 else 00949 return lstrcmpiA(a, b); 00950 } 00951 } 00952 00953 static void PropertyStorage_PropNameDestroy(void *k, void *d, void *extra) 00954 { 00955 CoTaskMemFree(k); 00956 } 00957 00958 static int PropertyStorage_PropCompare(const void *a, const void *b, 00959 void *extra) 00960 { 00961 TRACE("(%d, %d)\n", PtrToUlong(a), PtrToUlong(b)); 00962 return PtrToUlong(a) - PtrToUlong(b); 00963 } 00964 00965 static void PropertyStorage_PropertyDestroy(void *k, void *d, void *extra) 00966 { 00967 PropVariantClear(d); 00968 HeapFree(GetProcessHeap(), 0, d); 00969 } 00970 00971 #ifdef WORDS_BIGENDIAN 00972 /* Swaps each character in str to or from little endian; assumes the conversion 00973 * is symmetric, that is, that lendian16toh is equivalent to htole16. 00974 */ 00975 static void PropertyStorage_ByteSwapString(LPWSTR str, size_t len) 00976 { 00977 DWORD i; 00978 00979 /* Swap characters to host order. 00980 * FIXME: alignment? 00981 */ 00982 for (i = 0; i < len; i++) 00983 str[i] = lendian16toh(str[i]); 00984 } 00985 #else 00986 #define PropertyStorage_ByteSwapString(s, l) 00987 #endif 00988 00989 /* Reads the dictionary from the memory buffer beginning at ptr. Interprets 00990 * the entries according to the values of This->codePage and This->locale. 00991 * FIXME: there isn't any checking whether the read property extends past the 00992 * end of the buffer. 00993 */ 00994 static HRESULT PropertyStorage_ReadDictionary(PropertyStorage_impl *This, 00995 BYTE *ptr) 00996 { 00997 DWORD numEntries, i; 00998 HRESULT hr = S_OK; 00999 01000 assert(This->name_to_propid); 01001 assert(This->propid_to_name); 01002 01003 StorageUtl_ReadDWord(ptr, 0, &numEntries); 01004 TRACE("Reading %d entries:\n", numEntries); 01005 ptr += sizeof(DWORD); 01006 for (i = 0; SUCCEEDED(hr) && i < numEntries; i++) 01007 { 01008 PROPID propid; 01009 DWORD cbEntry; 01010 01011 StorageUtl_ReadDWord(ptr, 0, &propid); 01012 ptr += sizeof(PROPID); 01013 StorageUtl_ReadDWord(ptr, 0, &cbEntry); 01014 ptr += sizeof(DWORD); 01015 TRACE("Reading entry with ID 0x%08x, %d bytes\n", propid, cbEntry); 01016 /* Make sure the source string is NULL-terminated */ 01017 if (This->codePage != CP_UNICODE) 01018 ptr[cbEntry - 1] = '\0'; 01019 else 01020 *((LPWSTR)ptr + cbEntry / sizeof(WCHAR)) = '\0'; 01021 hr = PropertyStorage_StoreNameWithId(This, (char*)ptr, This->codePage, propid); 01022 if (This->codePage == CP_UNICODE) 01023 { 01024 /* Unicode entries are padded to DWORD boundaries */ 01025 if (cbEntry % sizeof(DWORD)) 01026 ptr += sizeof(DWORD) - (cbEntry % sizeof(DWORD)); 01027 } 01028 ptr += sizeof(DWORD) + cbEntry; 01029 } 01030 return hr; 01031 } 01032 01033 /* FIXME: there isn't any checking whether the read property extends past the 01034 * end of the buffer. 01035 */ 01036 static HRESULT PropertyStorage_ReadProperty(PropertyStorage_impl *This, 01037 PROPVARIANT *prop, const BYTE *data) 01038 { 01039 HRESULT hr = S_OK; 01040 01041 assert(prop); 01042 assert(data); 01043 StorageUtl_ReadDWord(data, 0, (DWORD *)&prop->vt); 01044 data += sizeof(DWORD); 01045 switch (prop->vt) 01046 { 01047 case VT_EMPTY: 01048 case VT_NULL: 01049 break; 01050 case VT_I1: 01051 prop->u.cVal = *(const char *)data; 01052 TRACE("Read char 0x%x ('%c')\n", prop->u.cVal, prop->u.cVal); 01053 break; 01054 case VT_UI1: 01055 prop->u.bVal = *data; 01056 TRACE("Read byte 0x%x\n", prop->u.bVal); 01057 break; 01058 case VT_I2: 01059 StorageUtl_ReadWord(data, 0, (WORD*)&prop->u.iVal); 01060 TRACE("Read short %d\n", prop->u.iVal); 01061 break; 01062 case VT_UI2: 01063 StorageUtl_ReadWord(data, 0, &prop->u.uiVal); 01064 TRACE("Read ushort %d\n", prop->u.uiVal); 01065 break; 01066 case VT_INT: 01067 case VT_I4: 01068 StorageUtl_ReadDWord(data, 0, (DWORD*)&prop->u.lVal); 01069 TRACE("Read long %d\n", prop->u.lVal); 01070 break; 01071 case VT_UINT: 01072 case VT_UI4: 01073 StorageUtl_ReadDWord(data, 0, &prop->u.ulVal); 01074 TRACE("Read ulong %d\n", prop->u.ulVal); 01075 break; 01076 case VT_LPSTR: 01077 { 01078 DWORD count; 01079 01080 StorageUtl_ReadDWord(data, 0, &count); 01081 if (This->codePage == CP_UNICODE && count / 2) 01082 { 01083 WARN("Unicode string has odd number of bytes\n"); 01084 hr = STG_E_INVALIDHEADER; 01085 } 01086 else 01087 { 01088 prop->u.pszVal = CoTaskMemAlloc(count); 01089 if (prop->u.pszVal) 01090 { 01091 memcpy(prop->u.pszVal, data + sizeof(DWORD), count); 01092 /* This is stored in the code page specified in This->codePage. 01093 * Don't convert it, the caller will just store it as-is. 01094 */ 01095 if (This->codePage == CP_UNICODE) 01096 { 01097 /* Make sure it's NULL-terminated */ 01098 prop->u.pszVal[count / sizeof(WCHAR) - 1] = '\0'; 01099 TRACE("Read string value %s\n", 01100 debugstr_w(prop->u.pwszVal)); 01101 } 01102 else 01103 { 01104 /* Make sure it's NULL-terminated */ 01105 prop->u.pszVal[count - 1] = '\0'; 01106 TRACE("Read string value %s\n", debugstr_a(prop->u.pszVal)); 01107 } 01108 } 01109 else 01110 hr = STG_E_INSUFFICIENTMEMORY; 01111 } 01112 break; 01113 } 01114 case VT_BLOB: 01115 { 01116 DWORD count; 01117 01118 StorageUtl_ReadDWord(data, 0, &count); 01119 prop->u.blob.cbSize = count; 01120 prop->u.blob.pBlobData = CoTaskMemAlloc(count); 01121 if (prop->u.blob.pBlobData) 01122 { 01123 memcpy(prop->u.blob.pBlobData, data + sizeof(DWORD), count); 01124 TRACE("Read blob value of size %d\n", count); 01125 } 01126 else 01127 hr = STG_E_INSUFFICIENTMEMORY; 01128 break; 01129 } 01130 case VT_LPWSTR: 01131 { 01132 DWORD count; 01133 01134 StorageUtl_ReadDWord(data, 0, &count); 01135 prop->u.pwszVal = CoTaskMemAlloc(count * sizeof(WCHAR)); 01136 if (prop->u.pwszVal) 01137 { 01138 memcpy(prop->u.pwszVal, data + sizeof(DWORD), 01139 count * sizeof(WCHAR)); 01140 /* make sure string is NULL-terminated */ 01141 prop->u.pwszVal[count - 1] = '\0'; 01142 PropertyStorage_ByteSwapString(prop->u.pwszVal, count); 01143 TRACE("Read string value %s\n", debugstr_w(prop->u.pwszVal)); 01144 } 01145 else 01146 hr = STG_E_INSUFFICIENTMEMORY; 01147 break; 01148 } 01149 case VT_FILETIME: 01150 StorageUtl_ReadULargeInteger(data, 0, 01151 (ULARGE_INTEGER *)&prop->u.filetime); 01152 break; 01153 case VT_CF: 01154 { 01155 DWORD len = 0, tag = 0; 01156 01157 StorageUtl_ReadDWord(data, 0, &len); 01158 StorageUtl_ReadDWord(data, 4, &tag); 01159 if (len > 8) 01160 { 01161 len -= 8; 01162 prop->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); 01163 prop->u.pclipdata->cbSize = len; 01164 prop->u.pclipdata->ulClipFmt = tag; 01165 prop->u.pclipdata->pClipData = CoTaskMemAlloc(len - sizeof(prop->u.pclipdata->ulClipFmt)); 01166 memcpy(prop->u.pclipdata->pClipData, data+8, len - sizeof(prop->u.pclipdata->ulClipFmt)); 01167 } 01168 else 01169 hr = STG_E_INVALIDPARAMETER; 01170 } 01171 break; 01172 default: 01173 FIXME("unsupported type %d\n", prop->vt); 01174 hr = STG_E_INVALIDPARAMETER; 01175 } 01176 return hr; 01177 } 01178 01179 static HRESULT PropertyStorage_ReadHeaderFromStream(IStream *stm, 01180 PROPERTYSETHEADER *hdr) 01181 { 01182 BYTE buf[sizeof(PROPERTYSETHEADER)]; 01183 ULONG count = 0; 01184 HRESULT hr; 01185 01186 assert(stm); 01187 assert(hdr); 01188 hr = IStream_Read(stm, buf, sizeof(buf), &count); 01189 if (SUCCEEDED(hr)) 01190 { 01191 if (count != sizeof(buf)) 01192 { 01193 WARN("read only %d\n", count); 01194 hr = STG_E_INVALIDHEADER; 01195 } 01196 else 01197 { 01198 StorageUtl_ReadWord(buf, offsetof(PROPERTYSETHEADER, wByteOrder), 01199 &hdr->wByteOrder); 01200 StorageUtl_ReadWord(buf, offsetof(PROPERTYSETHEADER, wFormat), 01201 &hdr->wFormat); 01202 StorageUtl_ReadDWord(buf, offsetof(PROPERTYSETHEADER, dwOSVer), 01203 &hdr->dwOSVer); 01204 StorageUtl_ReadGUID(buf, offsetof(PROPERTYSETHEADER, clsid), 01205 &hdr->clsid); 01206 StorageUtl_ReadDWord(buf, offsetof(PROPERTYSETHEADER, reserved), 01207 &hdr->reserved); 01208 } 01209 } 01210 TRACE("returning 0x%08x\n", hr); 01211 return hr; 01212 } 01213 01214 static HRESULT PropertyStorage_ReadFmtIdOffsetFromStream(IStream *stm, 01215 FORMATIDOFFSET *fmt) 01216 { 01217 BYTE buf[sizeof(FORMATIDOFFSET)]; 01218 ULONG count = 0; 01219 HRESULT hr; 01220 01221 assert(stm); 01222 assert(fmt); 01223 hr = IStream_Read(stm, buf, sizeof(buf), &count); 01224 if (SUCCEEDED(hr)) 01225 { 01226 if (count != sizeof(buf)) 01227 { 01228 WARN("read only %d\n", count); 01229 hr = STG_E_INVALIDHEADER; 01230 } 01231 else 01232 { 01233 StorageUtl_ReadGUID(buf, offsetof(FORMATIDOFFSET, fmtid), 01234 &fmt->fmtid); 01235 StorageUtl_ReadDWord(buf, offsetof(FORMATIDOFFSET, dwOffset), 01236 &fmt->dwOffset); 01237 } 01238 } 01239 TRACE("returning 0x%08x\n", hr); 01240 return hr; 01241 } 01242 01243 static HRESULT PropertyStorage_ReadSectionHeaderFromStream(IStream *stm, 01244 PROPERTYSECTIONHEADER *hdr) 01245 { 01246 BYTE buf[sizeof(PROPERTYSECTIONHEADER)]; 01247 ULONG count = 0; 01248 HRESULT hr; 01249 01250 assert(stm); 01251 assert(hdr); 01252 hr = IStream_Read(stm, buf, sizeof(buf), &count); 01253 if (SUCCEEDED(hr)) 01254 { 01255 if (count != sizeof(buf)) 01256 { 01257 WARN("read only %d\n", count); 01258 hr = STG_E_INVALIDHEADER; 01259 } 01260 else 01261 { 01262 StorageUtl_ReadDWord(buf, offsetof(PROPERTYSECTIONHEADER, 01263 cbSection), &hdr->cbSection); 01264 StorageUtl_ReadDWord(buf, offsetof(PROPERTYSECTIONHEADER, 01265 cProperties), &hdr->cProperties); 01266 } 01267 } 01268 TRACE("returning 0x%08x\n", hr); 01269 return hr; 01270 } 01271 01272 static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) 01273 { 01274 PROPERTYSETHEADER hdr; 01275 FORMATIDOFFSET fmtOffset; 01276 PROPERTYSECTIONHEADER sectionHdr; 01277 LARGE_INTEGER seek; 01278 ULONG i; 01279 STATSTG stat; 01280 HRESULT hr; 01281 BYTE *buf = NULL; 01282 ULONG count = 0; 01283 DWORD dictOffset = 0; 01284 01285 This->dirty = FALSE; 01286 This->highestProp = 0; 01287 hr = IStream_Stat(This->stm, &stat, STATFLAG_NONAME); 01288 if (FAILED(hr)) 01289 goto end; 01290 if (stat.cbSize.u.HighPart) 01291 { 01292 WARN("stream too big\n"); 01293 /* maximum size varies, but it can't be this big */ 01294 hr = STG_E_INVALIDHEADER; 01295 goto end; 01296 } 01297 if (stat.cbSize.u.LowPart == 0) 01298 { 01299 /* empty stream is okay */ 01300 hr = S_OK; 01301 goto end; 01302 } 01303 else if (stat.cbSize.u.LowPart < sizeof(PROPERTYSETHEADER) + 01304 sizeof(FORMATIDOFFSET)) 01305 { 01306 WARN("stream too small\n"); 01307 hr = STG_E_INVALIDHEADER; 01308 goto end; 01309 } 01310 seek.QuadPart = 0; 01311 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01312 if (FAILED(hr)) 01313 goto end; 01314 hr = PropertyStorage_ReadHeaderFromStream(This->stm, &hdr); 01315 /* I've only seen reserved == 1, but the article says I shouldn't disallow 01316 * higher values. 01317 */ 01318 if (hdr.wByteOrder != PROPSETHDR_BYTEORDER_MAGIC || hdr.reserved < 1) 01319 { 01320 WARN("bad magic in prop set header\n"); 01321 hr = STG_E_INVALIDHEADER; 01322 goto end; 01323 } 01324 if (hdr.wFormat != 0 && hdr.wFormat != 1) 01325 { 01326 WARN("bad format version %d\n", hdr.wFormat); 01327 hr = STG_E_INVALIDHEADER; 01328 goto end; 01329 } 01330 This->format = hdr.wFormat; 01331 This->clsid = hdr.clsid; 01332 This->originatorOS = hdr.dwOSVer; 01333 if (PROPSETHDR_OSVER_KIND(hdr.dwOSVer) == PROPSETHDR_OSVER_KIND_MAC) 01334 WARN("File comes from a Mac, strings will probably be screwed up\n"); 01335 hr = PropertyStorage_ReadFmtIdOffsetFromStream(This->stm, &fmtOffset); 01336 if (FAILED(hr)) 01337 goto end; 01338 if (fmtOffset.dwOffset > stat.cbSize.u.LowPart) 01339 { 01340 WARN("invalid offset %d (stream length is %d)\n", fmtOffset.dwOffset, 01341 stat.cbSize.u.LowPart); 01342 hr = STG_E_INVALIDHEADER; 01343 goto end; 01344 } 01345 /* wackiness alert: if the format ID is FMTID_DocSummaryInformation, there 01346 * follow not one, but two sections. The first is the standard properties 01347 * for the document summary information, and the second is user-defined 01348 * properties. This is the only case in which multiple sections are 01349 * allowed. 01350 * Reading the second stream isn't implemented yet. 01351 */ 01352 hr = PropertyStorage_ReadSectionHeaderFromStream(This->stm, §ionHdr); 01353 if (FAILED(hr)) 01354 goto end; 01355 /* The section size includes the section header, so check it */ 01356 if (sectionHdr.cbSection < sizeof(PROPERTYSECTIONHEADER)) 01357 { 01358 WARN("section header too small, got %d\n", sectionHdr.cbSection); 01359 hr = STG_E_INVALIDHEADER; 01360 goto end; 01361 } 01362 buf = HeapAlloc(GetProcessHeap(), 0, sectionHdr.cbSection - 01363 sizeof(PROPERTYSECTIONHEADER)); 01364 if (!buf) 01365 { 01366 hr = STG_E_INSUFFICIENTMEMORY; 01367 goto end; 01368 } 01369 hr = IStream_Read(This->stm, buf, sectionHdr.cbSection - 01370 sizeof(PROPERTYSECTIONHEADER), &count); 01371 if (FAILED(hr)) 01372 goto end; 01373 TRACE("Reading %d properties:\n", sectionHdr.cProperties); 01374 for (i = 0; SUCCEEDED(hr) && i < sectionHdr.cProperties; i++) 01375 { 01376 PROPERTYIDOFFSET *idOffset = (PROPERTYIDOFFSET *)(buf + 01377 i * sizeof(PROPERTYIDOFFSET)); 01378 01379 if (idOffset->dwOffset < sizeof(PROPERTYSECTIONHEADER) || 01380 idOffset->dwOffset > sectionHdr.cbSection - sizeof(DWORD)) 01381 hr = STG_E_INVALIDPOINTER; 01382 else 01383 { 01384 if (idOffset->propid >= PID_FIRST_USABLE && 01385 idOffset->propid < PID_MIN_READONLY && idOffset->propid > 01386 This->highestProp) 01387 This->highestProp = idOffset->propid; 01388 if (idOffset->propid == PID_DICTIONARY) 01389 { 01390 /* Don't read the dictionary yet, its entries depend on the 01391 * code page. Just store the offset so we know to read it 01392 * later. 01393 */ 01394 dictOffset = idOffset->dwOffset; 01395 TRACE("Dictionary offset is %d\n", dictOffset); 01396 } 01397 else 01398 { 01399 PROPVARIANT prop; 01400 01401 PropVariantInit(&prop); 01402 if (SUCCEEDED(PropertyStorage_ReadProperty(This, &prop, 01403 buf + idOffset->dwOffset - sizeof(PROPERTYSECTIONHEADER)))) 01404 { 01405 TRACE("Read property with ID 0x%08x, type %d\n", 01406 idOffset->propid, prop.vt); 01407 switch(idOffset->propid) 01408 { 01409 case PID_CODEPAGE: 01410 if (prop.vt == VT_I2) 01411 This->codePage = (UINT)prop.u.iVal; 01412 break; 01413 case PID_LOCALE: 01414 if (prop.vt == VT_I4) 01415 This->locale = (LCID)prop.u.lVal; 01416 break; 01417 case PID_BEHAVIOR: 01418 if (prop.vt == VT_I4 && prop.u.lVal) 01419 This->grfFlags |= PROPSETFLAG_CASE_SENSITIVE; 01420 /* The format should already be 1, but just in case */ 01421 This->format = 1; 01422 break; 01423 default: 01424 hr = PropertyStorage_StorePropWithId(This, 01425 idOffset->propid, &prop, This->codePage); 01426 } 01427 } 01428 PropVariantClear(&prop); 01429 } 01430 } 01431 } 01432 if (!This->codePage) 01433 { 01434 /* default to Unicode unless told not to, as specified on msdn */ 01435 if (This->grfFlags & PROPSETFLAG_ANSI) 01436 This->codePage = GetACP(); 01437 else 01438 This->codePage = CP_UNICODE; 01439 } 01440 if (!This->locale) 01441 This->locale = LOCALE_SYSTEM_DEFAULT; 01442 TRACE("Code page is %d, locale is %d\n", This->codePage, This->locale); 01443 if (dictOffset) 01444 hr = PropertyStorage_ReadDictionary(This, 01445 buf + dictOffset - sizeof(PROPERTYSECTIONHEADER)); 01446 01447 end: 01448 HeapFree(GetProcessHeap(), 0, buf); 01449 if (FAILED(hr)) 01450 { 01451 dictionary_destroy(This->name_to_propid); 01452 This->name_to_propid = NULL; 01453 dictionary_destroy(This->propid_to_name); 01454 This->propid_to_name = NULL; 01455 dictionary_destroy(This->propid_to_prop); 01456 This->propid_to_prop = NULL; 01457 } 01458 return hr; 01459 } 01460 01461 static void PropertyStorage_MakeHeader(PropertyStorage_impl *This, 01462 PROPERTYSETHEADER *hdr) 01463 { 01464 assert(hdr); 01465 StorageUtl_WriteWord((BYTE *)&hdr->wByteOrder, 0, 01466 PROPSETHDR_BYTEORDER_MAGIC); 01467 StorageUtl_WriteWord((BYTE *)&hdr->wFormat, 0, This->format); 01468 StorageUtl_WriteDWord((BYTE *)&hdr->dwOSVer, 0, This->originatorOS); 01469 StorageUtl_WriteGUID((BYTE *)&hdr->clsid, 0, &This->clsid); 01470 StorageUtl_WriteDWord((BYTE *)&hdr->reserved, 0, 1); 01471 } 01472 01473 static void PropertyStorage_MakeFmtIdOffset(PropertyStorage_impl *This, 01474 FORMATIDOFFSET *fmtOffset) 01475 { 01476 assert(fmtOffset); 01477 StorageUtl_WriteGUID((BYTE *)fmtOffset, 0, &This->fmtid); 01478 StorageUtl_WriteDWord((BYTE *)fmtOffset, offsetof(FORMATIDOFFSET, dwOffset), 01479 sizeof(PROPERTYSETHEADER) + sizeof(FORMATIDOFFSET)); 01480 } 01481 01482 static void PropertyStorage_MakeSectionHdr(DWORD cbSection, DWORD numProps, 01483 PROPERTYSECTIONHEADER *hdr) 01484 { 01485 assert(hdr); 01486 StorageUtl_WriteDWord((BYTE *)hdr, 0, cbSection); 01487 StorageUtl_WriteDWord((BYTE *)hdr, 01488 offsetof(PROPERTYSECTIONHEADER, cProperties), numProps); 01489 } 01490 01491 static void PropertyStorage_MakePropertyIdOffset(DWORD propid, DWORD dwOffset, 01492 PROPERTYIDOFFSET *propIdOffset) 01493 { 01494 assert(propIdOffset); 01495 StorageUtl_WriteDWord((BYTE *)propIdOffset, 0, propid); 01496 StorageUtl_WriteDWord((BYTE *)propIdOffset, 01497 offsetof(PROPERTYIDOFFSET, dwOffset), dwOffset); 01498 } 01499 01500 static inline HRESULT PropertStorage_WriteWStringToStream(IStream *stm, 01501 LPCWSTR str, DWORD len, DWORD *written) 01502 { 01503 #ifdef WORDS_BIGENDIAN 01504 WCHAR *leStr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 01505 HRESULT hr; 01506 01507 if (!leStr) 01508 return E_OUTOFMEMORY; 01509 memcpy(leStr, str, len * sizeof(WCHAR)); 01510 PropertyStorage_ByteSwapString(leStr, len); 01511 hr = IStream_Write(stm, leStr, len, written); 01512 HeapFree(GetProcessHeap(), 0, leStr); 01513 return hr; 01514 #else 01515 return IStream_Write(stm, str, len, written); 01516 #endif 01517 } 01518 01519 struct DictionaryClosure 01520 { 01521 HRESULT hr; 01522 DWORD bytesWritten; 01523 }; 01524 01525 static BOOL PropertyStorage_DictionaryWriter(const void *key, 01526 const void *value, void *extra, void *closure) 01527 { 01528 PropertyStorage_impl *This = extra; 01529 struct DictionaryClosure *c = closure; 01530 DWORD propid; 01531 ULONG count; 01532 01533 assert(key); 01534 assert(closure); 01535 StorageUtl_WriteDWord((LPBYTE)&propid, 0, PtrToUlong(value)); 01536 c->hr = IStream_Write(This->stm, &propid, sizeof(propid), &count); 01537 if (FAILED(c->hr)) 01538 goto end; 01539 c->bytesWritten += sizeof(DWORD); 01540 if (This->codePage == CP_UNICODE) 01541 { 01542 DWORD keyLen, pad = 0; 01543 01544 StorageUtl_WriteDWord((LPBYTE)&keyLen, 0, 01545 (lstrlenW((LPCWSTR)key) + 1) * sizeof(WCHAR)); 01546 c->hr = IStream_Write(This->stm, &keyLen, sizeof(keyLen), &count); 01547 if (FAILED(c->hr)) 01548 goto end; 01549 c->bytesWritten += sizeof(DWORD); 01550 c->hr = PropertStorage_WriteWStringToStream(This->stm, key, keyLen, 01551 &count); 01552 if (FAILED(c->hr)) 01553 goto end; 01554 c->bytesWritten += keyLen * sizeof(WCHAR); 01555 if (keyLen % sizeof(DWORD)) 01556 { 01557 c->hr = IStream_Write(This->stm, &pad, 01558 sizeof(DWORD) - keyLen % sizeof(DWORD), &count); 01559 if (FAILED(c->hr)) 01560 goto end; 01561 c->bytesWritten += sizeof(DWORD) - keyLen % sizeof(DWORD); 01562 } 01563 } 01564 else 01565 { 01566 DWORD keyLen; 01567 01568 StorageUtl_WriteDWord((LPBYTE)&keyLen, 0, strlen((LPCSTR)key) + 1); 01569 c->hr = IStream_Write(This->stm, &keyLen, sizeof(keyLen), &count); 01570 if (FAILED(c->hr)) 01571 goto end; 01572 c->bytesWritten += sizeof(DWORD); 01573 c->hr = IStream_Write(This->stm, key, keyLen, &count); 01574 if (FAILED(c->hr)) 01575 goto end; 01576 c->bytesWritten += keyLen; 01577 } 01578 end: 01579 return SUCCEEDED(c->hr); 01580 } 01581 01582 #define SECTIONHEADER_OFFSET sizeof(PROPERTYSETHEADER) + sizeof(FORMATIDOFFSET) 01583 01584 /* Writes the dictionary to the stream. Assumes without checking that the 01585 * dictionary isn't empty. 01586 */ 01587 static HRESULT PropertyStorage_WriteDictionaryToStream( 01588 PropertyStorage_impl *This, DWORD *sectionOffset) 01589 { 01590 HRESULT hr; 01591 LARGE_INTEGER seek; 01592 PROPERTYIDOFFSET propIdOffset; 01593 ULONG count; 01594 DWORD dwTemp; 01595 struct DictionaryClosure closure; 01596 01597 assert(sectionOffset); 01598 01599 /* The dictionary's always the first property written, so seek to its 01600 * spot. 01601 */ 01602 seek.QuadPart = SECTIONHEADER_OFFSET + sizeof(PROPERTYSECTIONHEADER); 01603 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01604 if (FAILED(hr)) 01605 goto end; 01606 PropertyStorage_MakePropertyIdOffset(PID_DICTIONARY, *sectionOffset, 01607 &propIdOffset); 01608 hr = IStream_Write(This->stm, &propIdOffset, sizeof(propIdOffset), &count); 01609 if (FAILED(hr)) 01610 goto end; 01611 01612 seek.QuadPart = SECTIONHEADER_OFFSET + *sectionOffset; 01613 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01614 if (FAILED(hr)) 01615 goto end; 01616 StorageUtl_WriteDWord((LPBYTE)&dwTemp, 0, 01617 dictionary_num_entries(This->name_to_propid)); 01618 hr = IStream_Write(This->stm, &dwTemp, sizeof(dwTemp), &count); 01619 if (FAILED(hr)) 01620 goto end; 01621 *sectionOffset += sizeof(dwTemp); 01622 01623 closure.hr = S_OK; 01624 closure.bytesWritten = 0; 01625 dictionary_enumerate(This->name_to_propid, PropertyStorage_DictionaryWriter, 01626 &closure); 01627 hr = closure.hr; 01628 if (FAILED(hr)) 01629 goto end; 01630 *sectionOffset += closure.bytesWritten; 01631 if (closure.bytesWritten % sizeof(DWORD)) 01632 { 01633 DWORD padding = sizeof(DWORD) - closure.bytesWritten % sizeof(DWORD); 01634 TRACE("adding %d bytes of padding\n", padding); 01635 *sectionOffset += padding; 01636 } 01637 01638 end: 01639 return hr; 01640 } 01641 01642 static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This, 01643 DWORD propNum, DWORD propid, const PROPVARIANT *var, DWORD *sectionOffset) 01644 { 01645 HRESULT hr; 01646 LARGE_INTEGER seek; 01647 PROPERTYIDOFFSET propIdOffset; 01648 ULONG count; 01649 DWORD dwType, bytesWritten; 01650 01651 assert(var); 01652 assert(sectionOffset); 01653 01654 TRACE("%p, %d, 0x%08x, (%d), (%d)\n", This, propNum, propid, var->vt, 01655 *sectionOffset); 01656 01657 seek.QuadPart = SECTIONHEADER_OFFSET + sizeof(PROPERTYSECTIONHEADER) + 01658 propNum * sizeof(PROPERTYIDOFFSET); 01659 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01660 if (FAILED(hr)) 01661 goto end; 01662 PropertyStorage_MakePropertyIdOffset(propid, *sectionOffset, &propIdOffset); 01663 hr = IStream_Write(This->stm, &propIdOffset, sizeof(propIdOffset), &count); 01664 if (FAILED(hr)) 01665 goto end; 01666 01667 seek.QuadPart = SECTIONHEADER_OFFSET + *sectionOffset; 01668 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01669 if (FAILED(hr)) 01670 goto end; 01671 StorageUtl_WriteDWord((LPBYTE)&dwType, 0, var->vt); 01672 hr = IStream_Write(This->stm, &dwType, sizeof(dwType), &count); 01673 if (FAILED(hr)) 01674 goto end; 01675 *sectionOffset += sizeof(dwType); 01676 01677 switch (var->vt) 01678 { 01679 case VT_EMPTY: 01680 case VT_NULL: 01681 bytesWritten = 0; 01682 break; 01683 case VT_I1: 01684 case VT_UI1: 01685 hr = IStream_Write(This->stm, &var->u.cVal, sizeof(var->u.cVal), 01686 &count); 01687 bytesWritten = count; 01688 break; 01689 case VT_I2: 01690 case VT_UI2: 01691 { 01692 WORD wTemp; 01693 01694 StorageUtl_WriteWord((LPBYTE)&wTemp, 0, var->u.iVal); 01695 hr = IStream_Write(This->stm, &wTemp, sizeof(wTemp), &count); 01696 bytesWritten = count; 01697 break; 01698 } 01699 case VT_I4: 01700 case VT_UI4: 01701 { 01702 DWORD dwTemp; 01703 01704 StorageUtl_WriteDWord((LPBYTE)&dwTemp, 0, var->u.lVal); 01705 hr = IStream_Write(This->stm, &dwTemp, sizeof(dwTemp), &count); 01706 bytesWritten = count; 01707 break; 01708 } 01709 case VT_LPSTR: 01710 { 01711 DWORD len, dwTemp; 01712 01713 if (This->codePage == CP_UNICODE) 01714 len = (lstrlenW(var->u.pwszVal) + 1) * sizeof(WCHAR); 01715 else 01716 len = lstrlenA(var->u.pszVal) + 1; 01717 StorageUtl_WriteDWord((LPBYTE)&dwTemp, 0, len); 01718 hr = IStream_Write(This->stm, &dwTemp, sizeof(dwTemp), &count); 01719 if (FAILED(hr)) 01720 goto end; 01721 hr = IStream_Write(This->stm, var->u.pszVal, len, &count); 01722 bytesWritten = count + sizeof(DWORD); 01723 break; 01724 } 01725 case VT_LPWSTR: 01726 { 01727 DWORD len = lstrlenW(var->u.pwszVal) + 1, dwTemp; 01728 01729 StorageUtl_WriteDWord((LPBYTE)&dwTemp, 0, len); 01730 hr = IStream_Write(This->stm, &dwTemp, sizeof(dwTemp), &count); 01731 if (FAILED(hr)) 01732 goto end; 01733 hr = IStream_Write(This->stm, var->u.pwszVal, len * sizeof(WCHAR), 01734 &count); 01735 bytesWritten = count + sizeof(DWORD); 01736 break; 01737 } 01738 case VT_FILETIME: 01739 { 01740 FILETIME temp; 01741 01742 StorageUtl_WriteULargeInteger((BYTE *)&temp, 0, 01743 (const ULARGE_INTEGER *)&var->u.filetime); 01744 hr = IStream_Write(This->stm, &temp, sizeof(FILETIME), &count); 01745 bytesWritten = count; 01746 break; 01747 } 01748 case VT_CF: 01749 { 01750 DWORD cf_hdr[2], len; 01751 01752 len = var->u.pclipdata->cbSize; 01753 StorageUtl_WriteDWord((LPBYTE)&cf_hdr[0], 0, len + 8); 01754 StorageUtl_WriteDWord((LPBYTE)&cf_hdr[1], 0, var->u.pclipdata->ulClipFmt); 01755 hr = IStream_Write(This->stm, cf_hdr, sizeof(cf_hdr), &count); 01756 if (FAILED(hr)) 01757 goto end; 01758 hr = IStream_Write(This->stm, var->u.pclipdata->pClipData, 01759 len - sizeof(var->u.pclipdata->ulClipFmt), &count); 01760 if (FAILED(hr)) 01761 goto end; 01762 bytesWritten = count + sizeof cf_hdr; 01763 break; 01764 } 01765 case VT_CLSID: 01766 { 01767 CLSID temp; 01768 01769 StorageUtl_WriteGUID((BYTE *)&temp, 0, var->u.puuid); 01770 hr = IStream_Write(This->stm, &temp, sizeof(temp), &count); 01771 bytesWritten = count; 01772 break; 01773 } 01774 default: 01775 FIXME("unsupported type: %d\n", var->vt); 01776 return STG_E_INVALIDPARAMETER; 01777 } 01778 01779 if (SUCCEEDED(hr)) 01780 { 01781 *sectionOffset += bytesWritten; 01782 if (bytesWritten % sizeof(DWORD)) 01783 { 01784 DWORD padding = sizeof(DWORD) - bytesWritten % sizeof(DWORD); 01785 TRACE("adding %d bytes of padding\n", padding); 01786 *sectionOffset += padding; 01787 } 01788 } 01789 01790 end: 01791 return hr; 01792 } 01793 01794 struct PropertyClosure 01795 { 01796 HRESULT hr; 01797 DWORD propNum; 01798 DWORD *sectionOffset; 01799 }; 01800 01801 static BOOL PropertyStorage_PropertiesWriter(const void *key, const void *value, 01802 void *extra, void *closure) 01803 { 01804 PropertyStorage_impl *This = extra; 01805 struct PropertyClosure *c = closure; 01806 01807 assert(key); 01808 assert(value); 01809 assert(extra); 01810 assert(closure); 01811 c->hr = PropertyStorage_WritePropertyToStream(This, c->propNum++, 01812 PtrToUlong(key), value, c->sectionOffset); 01813 return SUCCEEDED(c->hr); 01814 } 01815 01816 static HRESULT PropertyStorage_WritePropertiesToStream( 01817 PropertyStorage_impl *This, DWORD startingPropNum, DWORD *sectionOffset) 01818 { 01819 struct PropertyClosure closure; 01820 01821 assert(sectionOffset); 01822 closure.hr = S_OK; 01823 closure.propNum = startingPropNum; 01824 closure.sectionOffset = sectionOffset; 01825 dictionary_enumerate(This->propid_to_prop, PropertyStorage_PropertiesWriter, 01826 &closure); 01827 return closure.hr; 01828 } 01829 01830 static HRESULT PropertyStorage_WriteHeadersToStream(PropertyStorage_impl *This) 01831 { 01832 HRESULT hr; 01833 ULONG count = 0; 01834 LARGE_INTEGER seek = { {0} }; 01835 PROPERTYSETHEADER hdr; 01836 FORMATIDOFFSET fmtOffset; 01837 01838 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01839 if (FAILED(hr)) 01840 goto end; 01841 PropertyStorage_MakeHeader(This, &hdr); 01842 hr = IStream_Write(This->stm, &hdr, sizeof(hdr), &count); 01843 if (FAILED(hr)) 01844 goto end; 01845 if (count != sizeof(hdr)) 01846 { 01847 hr = STG_E_WRITEFAULT; 01848 goto end; 01849 } 01850 01851 PropertyStorage_MakeFmtIdOffset(This, &fmtOffset); 01852 hr = IStream_Write(This->stm, &fmtOffset, sizeof(fmtOffset), &count); 01853 if (FAILED(hr)) 01854 goto end; 01855 if (count != sizeof(fmtOffset)) 01856 { 01857 hr = STG_E_WRITEFAULT; 01858 goto end; 01859 } 01860 hr = S_OK; 01861 01862 end: 01863 return hr; 01864 } 01865 01866 static HRESULT PropertyStorage_WriteToStream(PropertyStorage_impl *This) 01867 { 01868 PROPERTYSECTIONHEADER sectionHdr; 01869 HRESULT hr; 01870 ULONG count; 01871 LARGE_INTEGER seek; 01872 DWORD numProps, prop, sectionOffset, dwTemp; 01873 PROPVARIANT var; 01874 01875 PropertyStorage_WriteHeadersToStream(This); 01876 01877 /* Count properties. Always at least one property, the code page */ 01878 numProps = 1; 01879 if (dictionary_num_entries(This->name_to_propid)) 01880 numProps++; 01881 if (This->locale != LOCALE_SYSTEM_DEFAULT) 01882 numProps++; 01883 if (This->grfFlags & PROPSETFLAG_CASE_SENSITIVE) 01884 numProps++; 01885 numProps += dictionary_num_entries(This->propid_to_prop); 01886 01887 /* Write section header with 0 bytes right now, I'll adjust it after 01888 * writing properties. 01889 */ 01890 PropertyStorage_MakeSectionHdr(0, numProps, §ionHdr); 01891 seek.QuadPart = SECTIONHEADER_OFFSET; 01892 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01893 if (FAILED(hr)) 01894 goto end; 01895 hr = IStream_Write(This->stm, §ionHdr, sizeof(sectionHdr), &count); 01896 if (FAILED(hr)) 01897 goto end; 01898 01899 prop = 0; 01900 sectionOffset = sizeof(PROPERTYSECTIONHEADER) + 01901 numProps * sizeof(PROPERTYIDOFFSET); 01902 01903 if (dictionary_num_entries(This->name_to_propid)) 01904 { 01905 prop++; 01906 hr = PropertyStorage_WriteDictionaryToStream(This, §ionOffset); 01907 if (FAILED(hr)) 01908 goto end; 01909 } 01910 01911 PropVariantInit(&var); 01912 01913 var.vt = VT_I2; 01914 var.u.iVal = This->codePage; 01915 hr = PropertyStorage_WritePropertyToStream(This, prop++, PID_CODEPAGE, 01916 &var, §ionOffset); 01917 if (FAILED(hr)) 01918 goto end; 01919 01920 if (This->locale != LOCALE_SYSTEM_DEFAULT) 01921 { 01922 var.vt = VT_I4; 01923 var.u.lVal = This->locale; 01924 hr = PropertyStorage_WritePropertyToStream(This, prop++, PID_LOCALE, 01925 &var, §ionOffset); 01926 if (FAILED(hr)) 01927 goto end; 01928 } 01929 01930 if (This->grfFlags & PROPSETFLAG_CASE_SENSITIVE) 01931 { 01932 var.vt = VT_I4; 01933 var.u.lVal = 1; 01934 hr = PropertyStorage_WritePropertyToStream(This, prop++, PID_BEHAVIOR, 01935 &var, §ionOffset); 01936 if (FAILED(hr)) 01937 goto end; 01938 } 01939 01940 hr = PropertyStorage_WritePropertiesToStream(This, prop, §ionOffset); 01941 if (FAILED(hr)) 01942 goto end; 01943 01944 /* Now write the byte count of the section */ 01945 seek.QuadPart = SECTIONHEADER_OFFSET; 01946 hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL); 01947 if (FAILED(hr)) 01948 goto end; 01949 StorageUtl_WriteDWord((LPBYTE)&dwTemp, 0, sectionOffset); 01950 hr = IStream_Write(This->stm, &dwTemp, sizeof(dwTemp), &count); 01951 01952 end: 01953 return hr; 01954 } 01955 01956 /*********************************************************************** 01957 * PropertyStorage_Construct 01958 */ 01959 static void PropertyStorage_DestroyDictionaries(PropertyStorage_impl *This) 01960 { 01961 dictionary_destroy(This->name_to_propid); 01962 This->name_to_propid = NULL; 01963 dictionary_destroy(This->propid_to_name); 01964 This->propid_to_name = NULL; 01965 dictionary_destroy(This->propid_to_prop); 01966 This->propid_to_prop = NULL; 01967 } 01968 01969 static HRESULT PropertyStorage_CreateDictionaries(PropertyStorage_impl *This) 01970 { 01971 HRESULT hr = S_OK; 01972 01973 This->name_to_propid = dictionary_create( 01974 PropertyStorage_PropNameCompare, PropertyStorage_PropNameDestroy, 01975 This); 01976 if (!This->name_to_propid) 01977 { 01978 hr = STG_E_INSUFFICIENTMEMORY; 01979 goto end; 01980 } 01981 This->propid_to_name = dictionary_create(PropertyStorage_PropCompare, 01982 NULL, This); 01983 if (!This->propid_to_name) 01984 { 01985 hr = STG_E_INSUFFICIENTMEMORY; 01986 goto end; 01987 } 01988 This->propid_to_prop = dictionary_create(PropertyStorage_PropCompare, 01989 PropertyStorage_PropertyDestroy, This); 01990 if (!This->propid_to_prop) 01991 { 01992 hr = STG_E_INSUFFICIENTMEMORY; 01993 goto end; 01994 } 01995 end: 01996 if (FAILED(hr)) 01997 PropertyStorage_DestroyDictionaries(This); 01998 return hr; 01999 } 02000 02001 static HRESULT PropertyStorage_BaseConstruct(IStream *stm, 02002 REFFMTID rfmtid, DWORD grfMode, PropertyStorage_impl **pps) 02003 { 02004 HRESULT hr = S_OK; 02005 02006 assert(pps); 02007 assert(rfmtid); 02008 *pps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof **pps); 02009 if (!*pps) 02010 return E_OUTOFMEMORY; 02011 02012 (*pps)->IPropertyStorage_iface.lpVtbl = &IPropertyStorage_Vtbl; 02013 (*pps)->ref = 1; 02014 InitializeCriticalSection(&(*pps)->cs); 02015 (*pps)->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PropertyStorage_impl.cs"); 02016 (*pps)->stm = stm; 02017 (*pps)->fmtid = *rfmtid; 02018 (*pps)->grfMode = grfMode; 02019 02020 hr = PropertyStorage_CreateDictionaries(*pps); 02021 if (FAILED(hr)) 02022 { 02023 IStream_Release(stm); 02024 (*pps)->cs.DebugInfo->Spare[0] = 0; 02025 DeleteCriticalSection(&(*pps)->cs); 02026 HeapFree(GetProcessHeap(), 0, *pps); 02027 *pps = NULL; 02028 } 02029 02030 return hr; 02031 } 02032 02033 static HRESULT PropertyStorage_ConstructFromStream(IStream *stm, 02034 REFFMTID rfmtid, DWORD grfMode, IPropertyStorage** pps) 02035 { 02036 PropertyStorage_impl *ps; 02037 HRESULT hr; 02038 02039 assert(pps); 02040 hr = PropertyStorage_BaseConstruct(stm, rfmtid, grfMode, &ps); 02041 if (SUCCEEDED(hr)) 02042 { 02043 hr = PropertyStorage_ReadFromStream(ps); 02044 if (SUCCEEDED(hr)) 02045 { 02046 *pps = &ps->IPropertyStorage_iface; 02047 TRACE("PropertyStorage %p constructed\n", ps); 02048 hr = S_OK; 02049 } 02050 else 02051 { 02052 PropertyStorage_DestroyDictionaries(ps); 02053 HeapFree(GetProcessHeap(), 0, ps); 02054 } 02055 } 02056 return hr; 02057 } 02058 02059 static HRESULT PropertyStorage_ConstructEmpty(IStream *stm, 02060 REFFMTID rfmtid, DWORD grfFlags, DWORD grfMode, IPropertyStorage** pps) 02061 { 02062 PropertyStorage_impl *ps; 02063 HRESULT hr; 02064 02065 assert(pps); 02066 hr = PropertyStorage_BaseConstruct(stm, rfmtid, grfMode, &ps); 02067 if (SUCCEEDED(hr)) 02068 { 02069 ps->format = 0; 02070 ps->grfFlags = grfFlags; 02071 if (ps->grfFlags & PROPSETFLAG_CASE_SENSITIVE) 02072 ps->format = 1; 02073 /* default to Unicode unless told not to, as specified on msdn */ 02074 if (ps->grfFlags & PROPSETFLAG_ANSI) 02075 ps->codePage = GetACP(); 02076 else 02077 ps->codePage = CP_UNICODE; 02078 ps->locale = LOCALE_SYSTEM_DEFAULT; 02079 TRACE("Code page is %d, locale is %d\n", ps->codePage, ps->locale); 02080 *pps = &ps->IPropertyStorage_iface; 02081 TRACE("PropertyStorage %p constructed\n", ps); 02082 hr = S_OK; 02083 } 02084 return hr; 02085 } 02086 02087 02088 /*********************************************************************** 02089 * Implementation of IPropertySetStorage 02090 */ 02091 02092 /************************************************************************ 02093 * IPropertySetStorage_fnQueryInterface (IUnknown) 02094 * 02095 * This method forwards to the common QueryInterface implementation 02096 */ 02097 static HRESULT WINAPI IPropertySetStorage_fnQueryInterface( 02098 IPropertySetStorage *ppstg, 02099 REFIID riid, 02100 void** ppvObject) 02101 { 02102 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02103 return IStorage_QueryInterface( (IStorage*)This, riid, ppvObject ); 02104 } 02105 02106 /************************************************************************ 02107 * IPropertySetStorage_fnAddRef (IUnknown) 02108 * 02109 * This method forwards to the common AddRef implementation 02110 */ 02111 static ULONG WINAPI IPropertySetStorage_fnAddRef( 02112 IPropertySetStorage *ppstg) 02113 { 02114 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02115 return IStorage_AddRef( (IStorage*)This ); 02116 } 02117 02118 /************************************************************************ 02119 * IPropertySetStorage_fnRelease (IUnknown) 02120 * 02121 * This method forwards to the common Release implementation 02122 */ 02123 static ULONG WINAPI IPropertySetStorage_fnRelease( 02124 IPropertySetStorage *ppstg) 02125 { 02126 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02127 return IStorage_Release( (IStorage*)This ); 02128 } 02129 02130 /************************************************************************ 02131 * IPropertySetStorage_fnCreate (IPropertySetStorage) 02132 */ 02133 static HRESULT WINAPI IPropertySetStorage_fnCreate( 02134 IPropertySetStorage *ppstg, 02135 REFFMTID rfmtid, 02136 const CLSID* pclsid, 02137 DWORD grfFlags, 02138 DWORD grfMode, 02139 IPropertyStorage** ppprstg) 02140 { 02141 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02142 WCHAR name[CCH_MAX_PROPSTG_NAME]; 02143 IStream *stm = NULL; 02144 HRESULT r; 02145 02146 TRACE("%p %s %08x %08x %p\n", This, debugstr_guid(rfmtid), grfFlags, 02147 grfMode, ppprstg); 02148 02149 /* be picky */ 02150 if (grfMode != (STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE)) 02151 { 02152 r = STG_E_INVALIDFLAG; 02153 goto end; 02154 } 02155 02156 if (!rfmtid) 02157 { 02158 r = E_INVALIDARG; 02159 goto end; 02160 } 02161 02162 /* FIXME: if (grfFlags & PROPSETFLAG_NONSIMPLE), we need to create a 02163 * storage, not a stream. For now, disallow it. 02164 */ 02165 if (grfFlags & PROPSETFLAG_NONSIMPLE) 02166 { 02167 FIXME("PROPSETFLAG_NONSIMPLE not supported\n"); 02168 r = STG_E_INVALIDFLAG; 02169 goto end; 02170 } 02171 02172 r = FmtIdToPropStgName(rfmtid, name); 02173 if (FAILED(r)) 02174 goto end; 02175 02176 r = IStorage_CreateStream( (IStorage*)This, name, grfMode, 0, 0, &stm ); 02177 if (FAILED(r)) 02178 goto end; 02179 02180 r = PropertyStorage_ConstructEmpty(stm, rfmtid, grfFlags, grfMode, ppprstg); 02181 02182 end: 02183 TRACE("returning 0x%08x\n", r); 02184 return r; 02185 } 02186 02187 /************************************************************************ 02188 * IPropertySetStorage_fnOpen (IPropertySetStorage) 02189 */ 02190 static HRESULT WINAPI IPropertySetStorage_fnOpen( 02191 IPropertySetStorage *ppstg, 02192 REFFMTID rfmtid, 02193 DWORD grfMode, 02194 IPropertyStorage** ppprstg) 02195 { 02196 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02197 IStream *stm = NULL; 02198 WCHAR name[CCH_MAX_PROPSTG_NAME]; 02199 HRESULT r; 02200 02201 TRACE("%p %s %08x %p\n", This, debugstr_guid(rfmtid), grfMode, ppprstg); 02202 02203 /* be picky */ 02204 if (grfMode != (STGM_READWRITE|STGM_SHARE_EXCLUSIVE) && 02205 grfMode != (STGM_READ|STGM_SHARE_EXCLUSIVE)) 02206 { 02207 r = STG_E_INVALIDFLAG; 02208 goto end; 02209 } 02210 02211 if (!rfmtid) 02212 { 02213 r = E_INVALIDARG; 02214 goto end; 02215 } 02216 02217 r = FmtIdToPropStgName(rfmtid, name); 02218 if (FAILED(r)) 02219 goto end; 02220 02221 r = IStorage_OpenStream((IStorage*) This, name, 0, grfMode, 0, &stm ); 02222 if (FAILED(r)) 02223 goto end; 02224 02225 r = PropertyStorage_ConstructFromStream(stm, rfmtid, grfMode, ppprstg); 02226 02227 end: 02228 TRACE("returning 0x%08x\n", r); 02229 return r; 02230 } 02231 02232 /************************************************************************ 02233 * IPropertySetStorage_fnDelete (IPropertySetStorage) 02234 */ 02235 static HRESULT WINAPI IPropertySetStorage_fnDelete( 02236 IPropertySetStorage *ppstg, 02237 REFFMTID rfmtid) 02238 { 02239 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02240 IStorage *stg = NULL; 02241 WCHAR name[CCH_MAX_PROPSTG_NAME]; 02242 HRESULT r; 02243 02244 TRACE("%p %s\n", This, debugstr_guid(rfmtid)); 02245 02246 if (!rfmtid) 02247 return E_INVALIDARG; 02248 02249 r = FmtIdToPropStgName(rfmtid, name); 02250 if (FAILED(r)) 02251 return r; 02252 02253 stg = (IStorage*) This; 02254 return IStorage_DestroyElement(stg, name); 02255 } 02256 02257 /************************************************************************ 02258 * IPropertySetStorage_fnEnum (IPropertySetStorage) 02259 */ 02260 static HRESULT WINAPI IPropertySetStorage_fnEnum( 02261 IPropertySetStorage *ppstg, 02262 IEnumSTATPROPSETSTG** ppenum) 02263 { 02264 StorageImpl *This = impl_from_IPropertySetStorage(ppstg); 02265 return create_EnumSTATPROPSETSTG(This, ppenum); 02266 } 02267 02268 /************************************************************************ 02269 * Implement IEnumSTATPROPSETSTG using enumx 02270 */ 02271 static HRESULT WINAPI IEnumSTATPROPSETSTG_fnQueryInterface( 02272 IEnumSTATPROPSETSTG *iface, 02273 REFIID riid, 02274 void** ppvObject) 02275 { 02276 return enumx_QueryInterface((enumx_impl*)iface, riid, ppvObject); 02277 } 02278 02279 static ULONG WINAPI IEnumSTATPROPSETSTG_fnAddRef( 02280 IEnumSTATPROPSETSTG *iface) 02281 { 02282 return enumx_AddRef((enumx_impl*)iface); 02283 } 02284 02285 static ULONG WINAPI IEnumSTATPROPSETSTG_fnRelease( 02286 IEnumSTATPROPSETSTG *iface) 02287 { 02288 return enumx_Release((enumx_impl*)iface); 02289 } 02290 02291 static HRESULT WINAPI IEnumSTATPROPSETSTG_fnNext( 02292 IEnumSTATPROPSETSTG *iface, 02293 ULONG celt, 02294 STATPROPSETSTG *rgelt, 02295 ULONG *pceltFetched) 02296 { 02297 return enumx_Next((enumx_impl*)iface, celt, rgelt, pceltFetched); 02298 } 02299 02300 static HRESULT WINAPI IEnumSTATPROPSETSTG_fnSkip( 02301 IEnumSTATPROPSETSTG *iface, 02302 ULONG celt) 02303 { 02304 return enumx_Skip((enumx_impl*)iface, celt); 02305 } 02306 02307 static HRESULT WINAPI IEnumSTATPROPSETSTG_fnReset( 02308 IEnumSTATPROPSETSTG *iface) 02309 { 02310 return enumx_Reset((enumx_impl*)iface); 02311 } 02312 02313 static HRESULT WINAPI IEnumSTATPROPSETSTG_fnClone( 02314 IEnumSTATPROPSETSTG *iface, 02315 IEnumSTATPROPSETSTG **ppenum) 02316 { 02317 return enumx_Clone((enumx_impl*)iface, (enumx_impl**)ppenum); 02318 } 02319 02320 static HRESULT create_EnumSTATPROPSETSTG( 02321 StorageImpl *This, 02322 IEnumSTATPROPSETSTG** ppenum) 02323 { 02324 IStorage *stg = (IStorage*) &This->base.lpVtbl; 02325 IEnumSTATSTG *penum = NULL; 02326 STATSTG stat; 02327 ULONG count; 02328 HRESULT r; 02329 STATPROPSETSTG statpss; 02330 enumx_impl *enumx; 02331 02332 TRACE("%p %p\n", This, ppenum); 02333 02334 enumx = enumx_allocate(&IID_IEnumSTATPROPSETSTG, 02335 &IEnumSTATPROPSETSTG_Vtbl, 02336 sizeof (STATPROPSETSTG)); 02337 02338 /* add all the property set elements into a list */ 02339 r = IStorage_EnumElements(stg, 0, NULL, 0, &penum); 02340 if (FAILED(r)) 02341 return E_OUTOFMEMORY; 02342 02343 while (1) 02344 { 02345 count = 0; 02346 r = IEnumSTATSTG_Next(penum, 1, &stat, &count); 02347 if (FAILED(r)) 02348 break; 02349 if (!count) 02350 break; 02351 if (!stat.pwcsName) 02352 continue; 02353 if (stat.pwcsName[0] == 5 && stat.type == STGTY_STREAM) 02354 { 02355 PropStgNameToFmtId(stat.pwcsName, &statpss.fmtid); 02356 TRACE("adding %s (%s)\n", debugstr_w(stat.pwcsName), 02357 debugstr_guid(&statpss.fmtid)); 02358 statpss.mtime = stat.mtime; 02359 statpss.atime = stat.atime; 02360 statpss.ctime = stat.ctime; 02361 statpss.grfFlags = stat.grfMode; 02362 statpss.clsid = stat.clsid; 02363 enumx_add_element(enumx, &statpss); 02364 } 02365 CoTaskMemFree(stat.pwcsName); 02366 } 02367 IEnumSTATSTG_Release(penum); 02368 02369 *ppenum = (IEnumSTATPROPSETSTG*) enumx; 02370 02371 return S_OK; 02372 } 02373 02374 /************************************************************************ 02375 * Implement IEnumSTATPROPSTG using enumx 02376 */ 02377 static HRESULT WINAPI IEnumSTATPROPSTG_fnQueryInterface( 02378 IEnumSTATPROPSTG *iface, 02379 REFIID riid, 02380 void** ppvObject) 02381 { 02382 return enumx_QueryInterface((enumx_impl*)iface, riid, ppvObject); 02383 } 02384 02385 static ULONG WINAPI IEnumSTATPROPSTG_fnAddRef( 02386 IEnumSTATPROPSTG *iface) 02387 { 02388 return enumx_AddRef((enumx_impl*)iface); 02389 } 02390 02391 static ULONG WINAPI IEnumSTATPROPSTG_fnRelease( 02392 IEnumSTATPROPSTG *iface) 02393 { 02394 return enumx_Release((enumx_impl*)iface); 02395 } 02396 02397 static HRESULT WINAPI IEnumSTATPROPSTG_fnNext( 02398 IEnumSTATPROPSTG *iface, 02399 ULONG celt, 02400 STATPROPSTG *rgelt, 02401 ULONG *pceltFetched) 02402 { 02403 return enumx_Next((enumx_impl*)iface, celt, rgelt, pceltFetched); 02404 } 02405 02406 static HRESULT WINAPI IEnumSTATPROPSTG_fnSkip( 02407 IEnumSTATPROPSTG *iface, 02408 ULONG celt) 02409 { 02410 return enumx_Skip((enumx_impl*)iface, celt); 02411 } 02412 02413 static HRESULT WINAPI IEnumSTATPROPSTG_fnReset( 02414 IEnumSTATPROPSTG *iface) 02415 { 02416 return enumx_Reset((enumx_impl*)iface); 02417 } 02418 02419 static HRESULT WINAPI IEnumSTATPROPSTG_fnClone( 02420 IEnumSTATPROPSTG *iface, 02421 IEnumSTATPROPSTG **ppenum) 02422 { 02423 return enumx_Clone((enumx_impl*)iface, (enumx_impl**)ppenum); 02424 } 02425 02426 static BOOL prop_enum_stat(const void *k, const void *v, void *extra, void *arg) 02427 { 02428 enumx_impl *enumx = arg; 02429 PROPID propid = PtrToUlong(k); 02430 const PROPVARIANT *prop = v; 02431 STATPROPSTG stat; 02432 02433 stat.lpwstrName = NULL; 02434 stat.propid = propid; 02435 stat.vt = prop->vt; 02436 02437 enumx_add_element(enumx, &stat); 02438 02439 return TRUE; 02440 } 02441 02442 static HRESULT create_EnumSTATPROPSTG( 02443 PropertyStorage_impl *This, 02444 IEnumSTATPROPSTG** ppenum) 02445 { 02446 enumx_impl *enumx; 02447 02448 TRACE("%p %p\n", This, ppenum); 02449 02450 enumx = enumx_allocate(&IID_IEnumSTATPROPSTG, 02451 &IEnumSTATPROPSTG_Vtbl, 02452 sizeof (STATPROPSTG)); 02453 02454 dictionary_enumerate(This->propid_to_prop, prop_enum_stat, enumx); 02455 02456 *ppenum = (IEnumSTATPROPSTG*) enumx; 02457 02458 return S_OK; 02459 } 02460 02461 /*********************************************************************** 02462 * vtables 02463 */ 02464 const IPropertySetStorageVtbl IPropertySetStorage_Vtbl = 02465 { 02466 IPropertySetStorage_fnQueryInterface, 02467 IPropertySetStorage_fnAddRef, 02468 IPropertySetStorage_fnRelease, 02469 IPropertySetStorage_fnCreate, 02470 IPropertySetStorage_fnOpen, 02471 IPropertySetStorage_fnDelete, 02472 IPropertySetStorage_fnEnum 02473 }; 02474 02475 static const IPropertyStorageVtbl IPropertyStorage_Vtbl = 02476 { 02477 IPropertyStorage_fnQueryInterface, 02478 IPropertyStorage_fnAddRef, 02479 IPropertyStorage_fnRelease, 02480 IPropertyStorage_fnReadMultiple, 02481 IPropertyStorage_fnWriteMultiple, 02482 IPropertyStorage_fnDeleteMultiple, 02483 IPropertyStorage_fnReadPropertyNames, 02484 IPropertyStorage_fnWritePropertyNames, 02485 IPropertyStorage_fnDeletePropertyNames, 02486 IPropertyStorage_fnCommit, 02487 IPropertyStorage_fnRevert, 02488 IPropertyStorage_fnEnum, 02489 IPropertyStorage_fnSetTimes, 02490 IPropertyStorage_fnSetClass, 02491 IPropertyStorage_fnStat, 02492 }; 02493 02494 static const IEnumSTATPROPSETSTGVtbl IEnumSTATPROPSETSTG_Vtbl = 02495 { 02496 IEnumSTATPROPSETSTG_fnQueryInterface, 02497 IEnumSTATPROPSETSTG_fnAddRef, 02498 IEnumSTATPROPSETSTG_fnRelease, 02499 IEnumSTATPROPSETSTG_fnNext, 02500 IEnumSTATPROPSETSTG_fnSkip, 02501 IEnumSTATPROPSETSTG_fnReset, 02502 IEnumSTATPROPSETSTG_fnClone, 02503 }; 02504 02505 static const IEnumSTATPROPSTGVtbl IEnumSTATPROPSTG_Vtbl = 02506 { 02507 IEnumSTATPROPSTG_fnQueryInterface, 02508 IEnumSTATPROPSTG_fnAddRef, 02509 IEnumSTATPROPSTG_fnRelease, 02510 IEnumSTATPROPSTG_fnNext, 02511 IEnumSTATPROPSTG_fnSkip, 02512 IEnumSTATPROPSTG_fnReset, 02513 IEnumSTATPROPSTG_fnClone, 02514 }; 02515 02516 /*********************************************************************** 02517 * Format ID <-> name conversion 02518 */ 02519 static const WCHAR szSummaryInfo[] = { 5,'S','u','m','m','a','r','y', 02520 'I','n','f','o','r','m','a','t','i','o','n',0 }; 02521 static const WCHAR szDocSummaryInfo[] = { 5,'D','o','c','u','m','e','n','t', 02522 'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0 }; 02523 02524 #define BITS_PER_BYTE 8 02525 #define CHARMASK 0x1f 02526 #define BITS_IN_CHARMASK 5 02527 #define NUM_ALPHA_CHARS 26 02528 02529 /*********************************************************************** 02530 * FmtIdToPropStgName [ole32.@] 02531 * Returns the storage name of the format ID rfmtid. 02532 * PARAMS 02533 * rfmtid [I] Format ID for which to return a storage name 02534 * str [O] Storage name associated with rfmtid. 02535 * 02536 * RETURNS 02537 * E_INVALIDARG if rfmtid or str i NULL, S_OK otherwise. 02538 * 02539 * NOTES 02540 * str must be at least CCH_MAX_PROPSTG_NAME characters in length. 02541 */ 02542 HRESULT WINAPI FmtIdToPropStgName(const FMTID *rfmtid, LPOLESTR str) 02543 { 02544 static const char fmtMap[] = "abcdefghijklmnopqrstuvwxyz012345"; 02545 02546 TRACE("%s, %p\n", debugstr_guid(rfmtid), str); 02547 02548 if (!rfmtid) return E_INVALIDARG; 02549 if (!str) return E_INVALIDARG; 02550 02551 if (IsEqualGUID(&FMTID_SummaryInformation, rfmtid)) 02552 lstrcpyW(str, szSummaryInfo); 02553 else if (IsEqualGUID(&FMTID_DocSummaryInformation, rfmtid)) 02554 lstrcpyW(str, szDocSummaryInfo); 02555 else if (IsEqualGUID(&FMTID_UserDefinedProperties, rfmtid)) 02556 lstrcpyW(str, szDocSummaryInfo); 02557 else 02558 { 02559 const BYTE *fmtptr; 02560 WCHAR *pstr = str; 02561 ULONG bitsRemaining = BITS_PER_BYTE; 02562 02563 *pstr++ = 5; 02564 for (fmtptr = (const BYTE *)rfmtid; fmtptr < (const BYTE *)rfmtid + sizeof(FMTID); ) 02565 { 02566 ULONG i = *fmtptr >> (BITS_PER_BYTE - bitsRemaining); 02567 02568 if (bitsRemaining >= BITS_IN_CHARMASK) 02569 { 02570 *pstr = (WCHAR)(fmtMap[i & CHARMASK]); 02571 if (bitsRemaining == BITS_PER_BYTE && *pstr >= 'a' && 02572 *pstr <= 'z') 02573 *pstr += 'A' - 'a'; 02574 pstr++; 02575 bitsRemaining -= BITS_IN_CHARMASK; 02576 if (bitsRemaining == 0) 02577 { 02578 fmtptr++; 02579 bitsRemaining = BITS_PER_BYTE; 02580 } 02581 } 02582 else 02583 { 02584 if (++fmtptr < (const BYTE *)rfmtid + sizeof(FMTID)) 02585 i |= *fmtptr << bitsRemaining; 02586 *pstr++ = (WCHAR)(fmtMap[i & CHARMASK]); 02587 bitsRemaining += BITS_PER_BYTE - BITS_IN_CHARMASK; 02588 } 02589 } 02590 *pstr = 0; 02591 } 02592 TRACE("returning %s\n", debugstr_w(str)); 02593 return S_OK; 02594 } 02595 02596 /*********************************************************************** 02597 * PropStgNameToFmtId [ole32.@] 02598 * Returns the format ID corresponding to the given name. 02599 * PARAMS 02600 * str [I] Storage name to convert to a format ID. 02601 * rfmtid [O] Format ID corresponding to str. 02602 * 02603 * RETURNS 02604 * E_INVALIDARG if rfmtid or str is NULL or if str can't be converted to 02605 * a format ID, S_OK otherwise. 02606 */ 02607 HRESULT WINAPI PropStgNameToFmtId(const LPOLESTR str, FMTID *rfmtid) 02608 { 02609 HRESULT hr = STG_E_INVALIDNAME; 02610 02611 TRACE("%s, %p\n", debugstr_w(str), rfmtid); 02612 02613 if (!rfmtid) return E_INVALIDARG; 02614 if (!str) return STG_E_INVALIDNAME; 02615 02616 if (!lstrcmpiW(str, szDocSummaryInfo)) 02617 { 02618 *rfmtid = FMTID_DocSummaryInformation; 02619 hr = S_OK; 02620 } 02621 else if (!lstrcmpiW(str, szSummaryInfo)) 02622 { 02623 *rfmtid = FMTID_SummaryInformation; 02624 hr = S_OK; 02625 } 02626 else 02627 { 02628 ULONG bits; 02629 BYTE *fmtptr = (BYTE *)rfmtid - 1; 02630 const WCHAR *pstr = str; 02631 02632 memset(rfmtid, 0, sizeof(*rfmtid)); 02633 for (bits = 0; bits < sizeof(FMTID) * BITS_PER_BYTE; 02634 bits += BITS_IN_CHARMASK) 02635 { 02636 ULONG bitsUsed = bits % BITS_PER_BYTE, bitsStored; 02637 WCHAR wc; 02638 02639 if (bitsUsed == 0) 02640 fmtptr++; 02641 wc = *++pstr - 'A'; 02642 if (wc > NUM_ALPHA_CHARS) 02643 { 02644 wc += 'A' - 'a'; 02645 if (wc > NUM_ALPHA_CHARS) 02646 { 02647 wc += 'a' - '0' + NUM_ALPHA_CHARS; 02648 if (wc > CHARMASK) 02649 { 02650 WARN("invalid character (%d)\n", *pstr); 02651 goto end; 02652 } 02653 } 02654 } 02655 *fmtptr |= wc << bitsUsed; 02656 bitsStored = min(BITS_PER_BYTE - bitsUsed, BITS_IN_CHARMASK); 02657 if (bitsStored < BITS_IN_CHARMASK) 02658 { 02659 wc >>= BITS_PER_BYTE - bitsUsed; 02660 if (bits + bitsStored == sizeof(FMTID) * BITS_PER_BYTE) 02661 { 02662 if (wc != 0) 02663 { 02664 WARN("extra bits\n"); 02665 goto end; 02666 } 02667 break; 02668 } 02669 fmtptr++; 02670 *fmtptr |= (BYTE)wc; 02671 } 02672 } 02673 hr = S_OK; 02674 } 02675 end: 02676 return hr; 02677 } Generated on Sun May 27 2012 04:25:40 for ReactOS by
1.7.6.1
|