source: trunk/src/ole32/storage32.c@ 5280

Last change on this file since 5280 was 5026, checked in by sandervl, 25 years ago

Wine resync

File size: 185.9 KB
Line 
1/*
2 * Compound Storage (32 bit version)
3 * Storage implementation
4 *
5 * This file contains the compound file implementation
6 * of the storage interface.
7 *
8 * Copyright 1999 Francis Beaudet
9 * Copyright 1999 Sylvain St-Germain
10 * Copyright 1999 Thuy Nguyen
11 */
12
13#ifdef __WIN32OS2__
14#define WINE_LARGE_INTEGER
15
16#include <odin.h>
17#include "ole32.h"
18#include "heapstring.h"
19
20#endif
21
22#include <assert.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "winbase.h" /* for lstrlenW() and the likes */
28#include "winnls.h"
29#include "wine/unicode.h"
30#include "debugtools.h"
31
32#include "storage32.h"
33#include "ole2.h" /* For Write/ReadClassStm */
34
35#include "winreg.h"
36#include "wine/wingdi16.h"
37
38DEFAULT_DEBUG_CHANNEL(storage);
39
40#define FILE_BEGIN 0
41
42
43/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
44#define OLESTREAM_ID 0x501
45#define OLESTREAM_MAX_STR_LEN 255
46
47static const char rootPropertyName[] = "Root Entry";
48
49
50/* OLESTREAM memory structure to use for Get and Put Routines */
51/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
52typedef struct
53{
54 DWORD dwOleID;
55 DWORD dwTypeID;
56 DWORD dwOleTypeNameLength;
57 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
58 CHAR *pstrOleObjFileName;
59 DWORD dwOleObjFileNameLength;
60 DWORD dwMetaFileWidth;
61 DWORD dwMetaFileHeight;
62 CHAR strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */
63 DWORD dwDataLength;
64 BYTE *pData;
65}OLECONVERT_OLESTREAM_DATA;
66
67/* CompObj Stream structure */
68/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
69typedef struct
70{
71 BYTE byUnknown1[12];
72 CLSID clsid;
73 DWORD dwCLSIDNameLength;
74 CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
75 DWORD dwOleTypeNameLength;
76 CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
77 DWORD dwProgIDNameLength;
78 CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
79 BYTE byUnknown2[16];
80}OLECONVERT_ISTORAGE_COMPOBJ;
81
82
83/* Ole Presention Stream structure */
84/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
85typedef struct
86{
87 BYTE byUnknown1[28];
88 DWORD dwExtentX;
89 DWORD dwExtentY;
90 DWORD dwSize;
91 BYTE *pData;
92}OLECONVERT_ISTORAGE_OLEPRES;
93
94
95
96/***********************************************************************
97 * Forward declaration of internal functions used by the method DestroyElement
98 */
99static HRESULT deleteStorageProperty(
100 StorageImpl *parentStorage,
101 ULONG foundPropertyIndexToDelete,
102 StgProperty propertyToDelete);
103
104static HRESULT deleteStreamProperty(
105 StorageImpl *parentStorage,
106 ULONG foundPropertyIndexToDelete,
107 StgProperty propertyToDelete);
108
109static HRESULT findPlaceholder(
110 StorageImpl *storage,
111 ULONG propertyIndexToStore,
112 ULONG storagePropertyIndex,
113 INT typeOfRelation);
114
115static HRESULT adjustPropertyChain(
116 StorageImpl *This,
117 StgProperty propertyToDelete,
118 StgProperty parentProperty,
119 ULONG parentPropertyId,
120 INT typeOfRelation);
121
122/***********************************************************************
123 * Declaration of the functions used to manipulate StgProperty
124 */
125
126static ULONG getFreeProperty(
127 StorageImpl *storage);
128
129static void updatePropertyChain(
130 StorageImpl *storage,
131 ULONG newPropertyIndex,
132 StgProperty newProperty);
133
134static LONG propertyNameCmp(
135 OLECHAR *newProperty,
136 OLECHAR *currentProperty);
137
138
139/***********************************************************************
140 * Declaration of miscellaneous functions...
141 */
142static HRESULT validateSTGM(DWORD stgmValue);
143
144static DWORD GetShareModeFromSTGM(DWORD stgm);
145static DWORD GetAccessModeFromSTGM(DWORD stgm);
146static DWORD GetCreationModeFromSTGM(DWORD stgm);
147
148/*
149 * Virtual function table for the IStorage32Impl class.
150 */
151static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
152{
153 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
154 StorageBaseImpl_QueryInterface,
155 StorageBaseImpl_AddRef,
156 StorageBaseImpl_Release,
157 StorageBaseImpl_CreateStream,
158 StorageBaseImpl_OpenStream,
159 StorageImpl_CreateStorage,
160 StorageBaseImpl_OpenStorage,
161 StorageImpl_CopyTo,
162 StorageImpl_MoveElementTo,
163 StorageImpl_Commit,
164 StorageImpl_Revert,
165 StorageBaseImpl_EnumElements,
166 StorageImpl_DestroyElement,
167 StorageBaseImpl_RenameElement,
168 StorageImpl_SetElementTimes,
169 StorageBaseImpl_SetClass,
170 StorageImpl_SetStateBits,
171 StorageBaseImpl_Stat
172};
173
174/*
175 * Virtual function table for the Storage32InternalImpl class.
176 */
177static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
178 {
179 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
180 StorageBaseImpl_QueryInterface,
181 StorageBaseImpl_AddRef,
182 StorageBaseImpl_Release,
183 StorageBaseImpl_CreateStream,
184 StorageBaseImpl_OpenStream,
185 StorageImpl_CreateStorage,
186 StorageBaseImpl_OpenStorage,
187 StorageImpl_CopyTo,
188 StorageImpl_MoveElementTo,
189 StorageInternalImpl_Commit,
190 StorageInternalImpl_Revert,
191 StorageBaseImpl_EnumElements,
192 StorageImpl_DestroyElement,
193 StorageBaseImpl_RenameElement,
194 StorageImpl_SetElementTimes,
195 StorageBaseImpl_SetClass,
196 StorageImpl_SetStateBits,
197 StorageBaseImpl_Stat
198};
199
200/*
201 * Virtual function table for the IEnumSTATSTGImpl class.
202 */
203static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
204{
205 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
206 IEnumSTATSTGImpl_QueryInterface,
207 IEnumSTATSTGImpl_AddRef,
208 IEnumSTATSTGImpl_Release,
209 IEnumSTATSTGImpl_Next,
210 IEnumSTATSTGImpl_Skip,
211 IEnumSTATSTGImpl_Reset,
212 IEnumSTATSTGImpl_Clone
213};
214
215
216
217
218
219/************************************************************************
220** Storage32BaseImpl implementatiion
221*/
222
223/************************************************************************
224 * Storage32BaseImpl_QueryInterface (IUnknown)
225 *
226 * This method implements the common QueryInterface for all IStorage32
227 * implementations contained in this file.
228 *
229 * See Windows documentation for more details on IUnknown methods.
230 */
231HRESULT WINAPI StorageBaseImpl_QueryInterface(
232 IStorage* iface,
233 REFIID riid,
234 void** ppvObject)
235{
236 ICOM_THIS(StorageBaseImpl,iface);
237 /*
238 * Perform a sanity check on the parameters.
239 */
240 if ( (This==0) || (ppvObject==0) )
241 return E_INVALIDARG;
242
243 /*
244 * Initialize the return parameter.
245 */
246 *ppvObject = 0;
247
248 /*
249 * Compare the riid with the interface IDs implemented by this object.
250 */
251 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
252 {
253 *ppvObject = (IStorage*)This;
254 }
255 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0)
256 {
257 *ppvObject = (IStorage*)This;
258 }
259
260 /*
261 * Check that we obtained an interface.
262 */
263 if ((*ppvObject)==0)
264 return E_NOINTERFACE;
265
266 /*
267 * Query Interface always increases the reference count by one when it is
268 * successful
269 */
270 StorageBaseImpl_AddRef(iface);
271
272 return S_OK;
273}
274
275/************************************************************************
276 * Storage32BaseImpl_AddRef (IUnknown)
277 *
278 * This method implements the common AddRef for all IStorage32
279 * implementations contained in this file.
280 *
281 * See Windows documentation for more details on IUnknown methods.
282 */
283ULONG WINAPI StorageBaseImpl_AddRef(
284 IStorage* iface)
285{
286 ICOM_THIS(StorageBaseImpl,iface);
287 This->ref++;
288
289 return This->ref;
290}
291
292/************************************************************************
293 * Storage32BaseImpl_Release (IUnknown)
294 *
295 * This method implements the common Release for all IStorage32
296 * implementations contained in this file.
297 *
298 * See Windows documentation for more details on IUnknown methods.
299 */
300ULONG WINAPI StorageBaseImpl_Release(
301 IStorage* iface)
302{
303 ICOM_THIS(StorageBaseImpl,iface);
304 /*
305 * Decrease the reference count on this object.
306 */
307 This->ref--;
308
309 /*
310 * If the reference count goes down to 0, perform suicide.
311 */
312 if (This->ref==0)
313 {
314 /*
315 * Since we are using a system of base-classes, we want to call the
316 * destructor of the appropriate derived class. To do this, we are
317 * using virtual functions to implement the destructor.
318 */
319 This->v_destructor(This);
320
321 return 0;
322 }
323
324 return This->ref;
325}
326
327/************************************************************************
328 * Storage32BaseImpl_OpenStream (IStorage)
329 *
330 * This method will open the specified stream object from the current storage.
331 *
332 * See Windows documentation for more details on IStorage methods.
333 */
334HRESULT WINAPI StorageBaseImpl_OpenStream(
335 IStorage* iface,
336 const OLECHAR* pwcsName, /* [string][in] */
337 void* reserved1, /* [unique][in] */
338 DWORD grfMode, /* [in] */
339 DWORD reserved2, /* [in] */
340 IStream** ppstm) /* [out] */
341{
342 ICOM_THIS(StorageBaseImpl,iface);
343 IEnumSTATSTGImpl* propertyEnumeration;
344 StgStreamImpl* newStream;
345 StgProperty currentProperty;
346 ULONG foundPropertyIndex;
347
348 TRACE("(%p, %s, %p, %lx, %ld, %p)\n",
349 iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
350
351 /*
352 * Perform a sanity check on the parameters.
353 */
354 if ( (pwcsName==NULL) || (ppstm==0) )
355 return E_INVALIDARG;
356
357 /*
358 * Initialize the out parameter
359 */
360 *ppstm = 0;
361
362 /*
363 * Validate the STGM flags
364 */
365 if ( FAILED( validateSTGM(grfMode) ))
366 return STG_E_INVALIDFLAG;
367
368 /*
369 * As documented.
370 */
371 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
372 (grfMode & STGM_DELETEONRELEASE) ||
373 (grfMode & STGM_TRANSACTED) )
374 return STG_E_INVALIDFUNCTION;
375
376 /*
377 * Create a property enumeration to search the properties
378 */
379 propertyEnumeration = IEnumSTATSTGImpl_Construct(
380 This->ancestorStorage,
381 This->rootPropertySetIndex);
382
383 /*
384 * Search the enumeration for the property with the given name
385 */
386 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
387 propertyEnumeration,
388 pwcsName,
389 &currentProperty);
390
391 /*
392 * Delete the property enumeration since we don't need it anymore
393 */
394 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
395
396 /*
397 * If it was found, construct the stream object and return a pointer to it.
398 */
399 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
400 (currentProperty.propertyType==PROPTYPE_STREAM) )
401 {
402 newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
403
404 if (newStream!=0)
405 {
406 newStream->grfMode = grfMode;
407 *ppstm = (IStream*)newStream;
408
409 /*
410 * Since we are returning a pointer to the interface, we have to
411 * nail down the reference.
412 */
413 StgStreamImpl_AddRef(*ppstm);
414
415 return S_OK;
416 }
417
418 return E_OUTOFMEMORY;
419 }
420
421 return STG_E_FILENOTFOUND;
422}
423
424/************************************************************************
425 * Storage32BaseImpl_OpenStorage (IStorage)
426 *
427 * This method will open a new storage object from the current storage.
428 *
429 * See Windows documentation for more details on IStorage methods.
430 */
431HRESULT WINAPI StorageBaseImpl_OpenStorage(
432 IStorage* iface,
433 const OLECHAR* pwcsName, /* [string][unique][in] */
434 IStorage* pstgPriority, /* [unique][in] */
435 DWORD grfMode, /* [in] */
436 SNB snbExclude, /* [unique][in] */
437 DWORD reserved, /* [in] */
438 IStorage** ppstg) /* [out] */
439{
440 ICOM_THIS(StorageBaseImpl,iface);
441 StorageInternalImpl* newStorage;
442 IEnumSTATSTGImpl* propertyEnumeration;
443 StgProperty currentProperty;
444 ULONG foundPropertyIndex;
445
446 TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n",
447 iface, debugstr_w(pwcsName), pstgPriority,
448 grfMode, snbExclude, reserved, ppstg);
449
450 /*
451 * Perform a sanity check on the parameters.
452 */
453 if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
454 return E_INVALIDARG;
455
456 /*
457 * Validate the STGM flags
458 */
459 if ( FAILED( validateSTGM(grfMode) ))
460 return STG_E_INVALIDFLAG;
461
462 /*
463 * As documented.
464 */
465 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
466 (grfMode & STGM_DELETEONRELEASE) ||
467 (grfMode & STGM_PRIORITY) )
468 return STG_E_INVALIDFUNCTION;
469
470 /*
471 * Initialize the out parameter
472 */
473 *ppstg = 0;
474
475 /*
476 * Create a property enumeration to search the properties
477 */
478 propertyEnumeration = IEnumSTATSTGImpl_Construct(
479 This->ancestorStorage,
480 This->rootPropertySetIndex);
481
482 /*
483 * Search the enumeration for the property with the given name
484 */
485 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
486 propertyEnumeration,
487 pwcsName,
488 &currentProperty);
489
490 /*
491 * Delete the property enumeration since we don't need it anymore
492 */
493 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
494
495 /*
496 * If it was found, construct the stream object and return a pointer to it.
497 */
498 if ( (foundPropertyIndex!=PROPERTY_NULL) &&
499 (currentProperty.propertyType==PROPTYPE_STORAGE) )
500 {
501 /*
502 * Construct a new Storage object
503 */
504 newStorage = StorageInternalImpl_Construct(
505 This->ancestorStorage,
506 foundPropertyIndex);
507
508 if (newStorage != 0)
509 {
510 *ppstg = (IStorage*)newStorage;
511
512 /*
513 * Since we are returning a pointer to the interface,
514 * we have to nail down the reference.
515 */
516 StorageBaseImpl_AddRef(*ppstg);
517
518 return S_OK;
519 }
520
521 return STG_E_INSUFFICIENTMEMORY;
522 }
523
524 return STG_E_FILENOTFOUND;
525}
526
527/************************************************************************
528 * Storage32BaseImpl_EnumElements (IStorage)
529 *
530 * This method will create an enumerator object that can be used to
531 * retrieve informatino about all the properties in the storage object.
532 *
533 * See Windows documentation for more details on IStorage methods.
534 */
535HRESULT WINAPI StorageBaseImpl_EnumElements(
536 IStorage* iface,
537 DWORD reserved1, /* [in] */
538 void* reserved2, /* [size_is][unique][in] */
539 DWORD reserved3, /* [in] */
540 IEnumSTATSTG** ppenum) /* [out] */
541{
542 ICOM_THIS(StorageBaseImpl,iface);
543 IEnumSTATSTGImpl* newEnum;
544
545 TRACE("(%p, %ld, %p, %ld, %p)\n",
546 iface, reserved1, reserved2, reserved3, ppenum);
547
548 /*
549 * Perform a sanity check on the parameters.
550 */
551 if ( (This==0) || (ppenum==0))
552 return E_INVALIDARG;
553
554 /*
555 * Construct the enumerator.
556 */
557 newEnum = IEnumSTATSTGImpl_Construct(
558 This->ancestorStorage,
559 This->rootPropertySetIndex);
560
561 if (newEnum!=0)
562 {
563 *ppenum = (IEnumSTATSTG*)newEnum;
564
565 /*
566 * Don't forget to nail down a reference to the new object before
567 * returning it.
568 */
569 IEnumSTATSTGImpl_AddRef(*ppenum);
570
571 return S_OK;
572 }
573
574 return E_OUTOFMEMORY;
575}
576
577/************************************************************************
578 * Storage32BaseImpl_Stat (IStorage)
579 *
580 * This method will retrieve information about this storage object.
581 *
582 * See Windows documentation for more details on IStorage methods.
583 */
584HRESULT WINAPI StorageBaseImpl_Stat(
585 IStorage* iface,
586 STATSTG* pstatstg, /* [out] */
587 DWORD grfStatFlag) /* [in] */
588{
589 ICOM_THIS(StorageBaseImpl,iface);
590 StgProperty curProperty;
591 BOOL readSuccessful;
592
593 TRACE("(%p, %p, %lx)\n",
594 iface, pstatstg, grfStatFlag);
595
596 /*
597 * Perform a sanity check on the parameters.
598 */
599 if ( (This==0) || (pstatstg==0))
600 return E_INVALIDARG;
601
602 /*
603 * Read the information from the property.
604 */
605 readSuccessful = StorageImpl_ReadProperty(
606 This->ancestorStorage,
607 This->rootPropertySetIndex,
608 &curProperty);
609
610 if (readSuccessful)
611 {
612 StorageUtl_CopyPropertyToSTATSTG(
613 pstatstg,
614 &curProperty,
615 grfStatFlag);
616
617 return S_OK;
618 }
619
620 return E_FAIL;
621}
622
623/************************************************************************
624 * Storage32BaseImpl_RenameElement (IStorage)
625 *
626 * This method will rename the specified element.
627 *
628 * See Windows documentation for more details on IStorage methods.
629 *
630 * Implementation notes: The method used to rename consists of creating a clone
631 * of the deleted StgProperty object setting it with the new name and to
632 * perform a DestroyElement of the old StgProperty.
633 */
634HRESULT WINAPI StorageBaseImpl_RenameElement(
635 IStorage* iface,
636 const OLECHAR* pwcsOldName, /* [in] */
637 const OLECHAR* pwcsNewName) /* [in] */
638{
639 ICOM_THIS(StorageBaseImpl,iface);
640 IEnumSTATSTGImpl* propertyEnumeration;
641 StgProperty currentProperty;
642 ULONG foundPropertyIndex;
643
644 TRACE("(%p, %s, %s)\n",
645 iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
646
647 /*
648 * Create a property enumeration to search the properties
649 */
650 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
651 This->rootPropertySetIndex);
652
653 /*
654 * Search the enumeration for the new property name
655 */
656 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
657 pwcsNewName,
658 &currentProperty);
659
660 if (foundPropertyIndex != PROPERTY_NULL)
661 {
662 /*
663 * There is already a property with the new name
664 */
665 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
666 return STG_E_FILEALREADYEXISTS;
667 }
668
669 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
670
671 /*
672 * Search the enumeration for the old property name
673 */
674 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
675 pwcsOldName,
676 &currentProperty);
677
678 /*
679 * Delete the property enumeration since we don't need it anymore
680 */
681 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
682
683 if (foundPropertyIndex != PROPERTY_NULL)
684 {
685 StgProperty renamedProperty;
686 ULONG renamedPropertyIndex;
687
688 /*
689 * Setup a new property for the renamed property
690 */
691 renamedProperty.sizeOfNameString =
692 ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
693
694 if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
695 return STG_E_INVALIDNAME;
696
697 strcpyW(renamedProperty.name, pwcsNewName);
698
699 renamedProperty.propertyType = currentProperty.propertyType;
700 renamedProperty.startingBlock = currentProperty.startingBlock;
701 renamedProperty.size.s.LowPart = currentProperty.size.s.LowPart;
702 renamedProperty.size.s.HighPart = currentProperty.size.s.HighPart;
703
704 renamedProperty.previousProperty = PROPERTY_NULL;
705 renamedProperty.nextProperty = PROPERTY_NULL;
706
707 /*
708 * Bring the dirProperty link in case it is a storage and in which
709 * case the renamed storage elements don't require to be reorganized.
710 */
711 renamedProperty.dirProperty = currentProperty.dirProperty;
712
713 /* call CoFileTime to get the current time
714 renamedProperty.timeStampS1
715 renamedProperty.timeStampD1
716 renamedProperty.timeStampS2
717 renamedProperty.timeStampD2
718 renamedProperty.propertyUniqueID
719 */
720
721 /*
722 * Obtain a free property in the property chain
723 */
724 renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
725
726 /*
727 * Save the new property into the new property spot
728 */
729 StorageImpl_WriteProperty(
730 This->ancestorStorage,
731 renamedPropertyIndex,
732 &renamedProperty);
733
734 /*
735 * Find a spot in the property chain for our newly created property.
736 */
737 updatePropertyChain(
738 (StorageImpl*)This,
739 renamedPropertyIndex,
740 renamedProperty);
741
742 /*
743 * At this point the renamed property has been inserted in the tree,
744 * now, before to Destroy the old property we must zeroed it's dirProperty
745 * otherwise the DestroyProperty below will zap it all and we do not want
746 * this to happen.
747 * Also, we fake that the old property is a storage so the DestroyProperty
748 * will not do a SetSize(0) on the stream data.
749 *
750 * This means that we need to tweek the StgProperty if it is a stream or a
751 * non empty storage.
752 */
753 StorageImpl_ReadProperty(This->ancestorStorage,
754 foundPropertyIndex,
755 &currentProperty);
756
757 currentProperty.dirProperty = PROPERTY_NULL;
758 currentProperty.propertyType = PROPTYPE_STORAGE;
759 StorageImpl_WriteProperty(
760 This->ancestorStorage,
761 foundPropertyIndex,
762 &currentProperty);
763
764 /*
765 * Invoke Destroy to get rid of the ole property and automatically redo
766 * the linking of it's previous and next members...
767 */
768 StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName);
769
770 }
771 else
772 {
773 /*
774 * There is no property with the old name
775 */
776 return STG_E_FILENOTFOUND;
777 }
778
779 return S_OK;
780}
781
782/************************************************************************
783 * Storage32BaseImpl_CreateStream (IStorage)
784 *
785 * This method will create a stream object within this storage
786 *
787 * See Windows documentation for more details on IStorage methods.
788 */
789HRESULT WINAPI StorageBaseImpl_CreateStream(
790 IStorage* iface,
791 const OLECHAR* pwcsName, /* [string][in] */
792 DWORD grfMode, /* [in] */
793 DWORD reserved1, /* [in] */
794 DWORD reserved2, /* [in] */
795 IStream** ppstm) /* [out] */
796{
797 ICOM_THIS(StorageBaseImpl,iface);
798 IEnumSTATSTGImpl* propertyEnumeration;
799 StgStreamImpl* newStream;
800 StgProperty currentProperty, newStreamProperty;
801 ULONG foundPropertyIndex, newPropertyIndex;
802
803 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
804 iface, debugstr_w(pwcsName), grfMode,
805 reserved1, reserved2, ppstm);
806
807 /*
808 * Validate parameters
809 */
810 if (ppstm == 0)
811 return STG_E_INVALIDPOINTER;
812
813 if (pwcsName == 0)
814 return STG_E_INVALIDNAME;
815
816 /*
817 * Validate the STGM flags
818 */
819 if ( FAILED( validateSTGM(grfMode) ))
820 return STG_E_INVALIDFLAG;
821
822 /*
823 * As documented.
824 */
825 if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
826 (grfMode & STGM_DELETEONRELEASE) ||
827 (grfMode & STGM_TRANSACTED) )
828 return STG_E_INVALIDFUNCTION;
829
830 /*
831 * Initialize the out parameter
832 */
833 *ppstm = 0;
834
835 /*
836 * Create a property enumeration to search the properties
837 */
838 propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
839 This->rootPropertySetIndex);
840
841 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
842 pwcsName,
843 &currentProperty);
844
845 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
846
847 if (foundPropertyIndex != PROPERTY_NULL)
848 {
849 /*
850 * An element with this name already exists
851 */
852 if (grfMode & STGM_CREATE)
853 {
854 IStorage_DestroyElement(iface, pwcsName);
855 }
856 else
857 return STG_E_FILEALREADYEXISTS;
858 }
859
860 /*
861 * memset the empty property
862 */
863 memset(&newStreamProperty, 0, sizeof(StgProperty));
864
865 newStreamProperty.sizeOfNameString =
866 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
867
868 if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
869 return STG_E_INVALIDNAME;
870
871 strcpyW(newStreamProperty.name, pwcsName);
872
873 newStreamProperty.propertyType = PROPTYPE_STREAM;
874 newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
875 newStreamProperty.size.s.LowPart = 0;
876 newStreamProperty.size.s.HighPart = 0;
877
878 newStreamProperty.previousProperty = PROPERTY_NULL;
879 newStreamProperty.nextProperty = PROPERTY_NULL;
880 newStreamProperty.dirProperty = PROPERTY_NULL;
881
882 /* call CoFileTime to get the current time
883 newStreamProperty.timeStampS1
884 newStreamProperty.timeStampD1
885 newStreamProperty.timeStampS2
886 newStreamProperty.timeStampD2
887 */
888
889 /* newStreamProperty.propertyUniqueID */
890
891 /*
892 * Get a free property or create a new one
893 */
894 newPropertyIndex = getFreeProperty(This->ancestorStorage);
895
896 /*
897 * Save the new property into the new property spot
898 */
899 StorageImpl_WriteProperty(
900 This->ancestorStorage,
901 newPropertyIndex,
902 &newStreamProperty);
903
904 /*
905 * Find a spot in the property chain for our newly created property.
906 */
907 updatePropertyChain(
908 (StorageImpl*)This,
909 newPropertyIndex,
910 newStreamProperty);
911
912 /*
913 * Open the stream to return it.
914 */
915 newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
916
917 if (newStream != 0)
918 {
919 *ppstm = (IStream*)newStream;
920
921 /*
922 * Since we are returning a pointer to the interface, we have to nail down
923 * the reference.
924 */
925 StgStreamImpl_AddRef(*ppstm);
926 }
927 else
928 {
929 return STG_E_INSUFFICIENTMEMORY;
930 }
931
932 return S_OK;
933}
934
935/************************************************************************
936 * Storage32BaseImpl_SetClass (IStorage)
937 *
938 * This method will write the specified CLSID in the property of this
939 * storage.
940 *
941 * See Windows documentation for more details on IStorage methods.
942 */
943HRESULT WINAPI StorageBaseImpl_SetClass(
944 IStorage* iface,
945 REFCLSID clsid) /* [in] */
946{
947 ICOM_THIS(StorageBaseImpl,iface);
948 HRESULT hRes = E_FAIL;
949 StgProperty curProperty;
950 BOOL success;
951
952 TRACE("(%p, %p)\n", iface, clsid);
953
954 success = StorageImpl_ReadProperty(This->ancestorStorage,
955 This->rootPropertySetIndex,
956 &curProperty);
957 if (success)
958 {
959 curProperty.propertyUniqueID = *clsid;
960
961 success = StorageImpl_WriteProperty(This->ancestorStorage,
962 This->rootPropertySetIndex,
963 &curProperty);
964 if (success)
965 hRes = S_OK;
966 }
967
968 return hRes;
969}
970
971/************************************************************************
972** Storage32Impl implementation
973*/
974
975/************************************************************************
976 * Storage32Impl_CreateStorage (IStorage)
977 *
978 * This method will create the storage object within the provided storage.
979 *
980 * See Windows documentation for more details on IStorage methods.
981 */
982HRESULT WINAPI StorageImpl_CreateStorage(
983 IStorage* iface,
984 const OLECHAR *pwcsName, /* [string][in] */
985 DWORD grfMode, /* [in] */
986 DWORD reserved1, /* [in] */
987 DWORD reserved2, /* [in] */
988 IStorage **ppstg) /* [out] */
989{
990 StorageImpl* const This=(StorageImpl*)iface;
991
992 IEnumSTATSTGImpl *propertyEnumeration;
993 StgProperty currentProperty;
994 StgProperty newProperty;
995 ULONG foundPropertyIndex;
996 ULONG newPropertyIndex;
997 HRESULT hr;
998
999 TRACE("(%p, %s, %lx, %ld, %ld, %p)\n",
1000 iface, debugstr_w(pwcsName), grfMode,
1001 reserved1, reserved2, ppstg);
1002
1003 /*
1004 * Validate parameters
1005 */
1006 if (ppstg == 0)
1007 return STG_E_INVALIDPOINTER;
1008
1009 if (pwcsName == 0)
1010 return STG_E_INVALIDNAME;
1011
1012 /*
1013 * Validate the STGM flags
1014 */
1015 if ( FAILED( validateSTGM(grfMode) ) ||
1016 (grfMode & STGM_DELETEONRELEASE) )
1017 return STG_E_INVALIDFLAG;
1018
1019 /*
1020 * Initialize the out parameter
1021 */
1022 *ppstg = 0;
1023
1024 /*
1025 * Create a property enumeration and search the properties
1026 */
1027 propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
1028 This->rootPropertySetIndex);
1029
1030 foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
1031 pwcsName,
1032 &currentProperty);
1033 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1034
1035 if (foundPropertyIndex != PROPERTY_NULL)
1036 {
1037 /*
1038 * An element with this name already exists
1039 */
1040 if (grfMode & STGM_CREATE)
1041 IStorage_DestroyElement(iface, pwcsName);
1042 else
1043 return STG_E_FILEALREADYEXISTS;
1044 }
1045
1046 /*
1047 * memset the empty property
1048 */
1049 memset(&newProperty, 0, sizeof(StgProperty));
1050
1051 newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
1052
1053 if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
1054 return STG_E_INVALIDNAME;
1055
1056 strcpyW(newProperty.name, pwcsName);
1057
1058 newProperty.propertyType = PROPTYPE_STORAGE;
1059 newProperty.startingBlock = BLOCK_END_OF_CHAIN;
1060 newProperty.size.s.LowPart = 0;
1061 newProperty.size.s.HighPart = 0;
1062
1063 newProperty.previousProperty = PROPERTY_NULL;
1064 newProperty.nextProperty = PROPERTY_NULL;
1065 newProperty.dirProperty = PROPERTY_NULL;
1066
1067 /* call CoFileTime to get the current time
1068 newProperty.timeStampS1
1069 newProperty.timeStampD1
1070 newProperty.timeStampS2
1071 newProperty.timeStampD2
1072 */
1073
1074 /* newStorageProperty.propertyUniqueID */
1075
1076 /*
1077 * Obtain a free property in the property chain
1078 */
1079 newPropertyIndex = getFreeProperty(This->ancestorStorage);
1080
1081 /*
1082 * Save the new property into the new property spot
1083 */
1084 StorageImpl_WriteProperty(
1085 This->ancestorStorage,
1086 newPropertyIndex,
1087 &newProperty);
1088
1089 /*
1090 * Find a spot in the property chain for our newly created property.
1091 */
1092 updatePropertyChain(
1093 This,
1094 newPropertyIndex,
1095 newProperty);
1096
1097 /*
1098 * Open it to get a pointer to return.
1099 */
1100 hr = IStorage_OpenStorage(
1101 iface,
1102 (OLECHAR*)pwcsName,
1103 0,
1104 grfMode,
1105 0,
1106 0,
1107 ppstg);
1108
1109 if( (hr != S_OK) || (*ppstg == NULL))
1110 {
1111 return hr;
1112 }
1113
1114
1115 return S_OK;
1116}
1117
1118
1119/***************************************************************************
1120 *
1121 * Internal Method
1122 *
1123 * Get a free property or create a new one.
1124 */
1125static ULONG getFreeProperty(
1126 StorageImpl *storage)
1127{
1128 ULONG currentPropertyIndex = 0;
1129 ULONG newPropertyIndex = PROPERTY_NULL;
1130 BOOL readSuccessful = TRUE;
1131 StgProperty currentProperty;
1132
1133 do
1134 {
1135 /*
1136 * Start by reading the root property
1137 */
1138 readSuccessful = StorageImpl_ReadProperty(storage->ancestorStorage,
1139 currentPropertyIndex,
1140 &currentProperty);
1141 if (readSuccessful)
1142 {
1143 if (currentProperty.sizeOfNameString == 0)
1144 {
1145 /*
1146 * The property existis and is available, we found it.
1147 */
1148 newPropertyIndex = currentPropertyIndex;
1149 }
1150 }
1151 else
1152 {
1153 /*
1154 * We exhausted the property list, we will create more space below
1155 */
1156 newPropertyIndex = currentPropertyIndex;
1157 }
1158 currentPropertyIndex++;
1159
1160 } while (newPropertyIndex == PROPERTY_NULL);
1161
1162 /*
1163 * grow the property chain
1164 */
1165 if (! readSuccessful)
1166 {
1167 StgProperty emptyProperty;
1168 ULARGE_INTEGER newSize;
1169 ULONG propertyIndex;
1170 ULONG lastProperty = 0;
1171 ULONG blockCount = 0;
1172
1173 /*
1174 * obtain the new count of property blocks
1175 */
1176 blockCount = BlockChainStream_GetCount(
1177 storage->ancestorStorage->rootBlockChain)+1;
1178
1179 /*
1180 * initialize the size used by the property stream
1181 */
1182 newSize.s.HighPart = 0;
1183 newSize.s.LowPart = storage->bigBlockSize * blockCount;
1184
1185 /*
1186 * add a property block to the property chain
1187 */
1188 BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
1189
1190 /*
1191 * memset the empty property in order to initialize the unused newly
1192 * created property
1193 */
1194 memset(&emptyProperty, 0, sizeof(StgProperty));
1195
1196 /*
1197 * initialize them
1198 */
1199 lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount;
1200
1201 for(
1202 propertyIndex = newPropertyIndex;
1203 propertyIndex < lastProperty;
1204 propertyIndex++)
1205 {
1206 StorageImpl_WriteProperty(
1207 storage->ancestorStorage,
1208 propertyIndex,
1209 &emptyProperty);
1210 }
1211 }
1212
1213 return newPropertyIndex;
1214}
1215
1216/****************************************************************************
1217 *
1218 * Internal Method
1219 *
1220 * Case insensitive comparaison of StgProperty.name by first considering
1221 * their size.
1222 *
1223 * Returns <0 when newPrpoerty < currentProperty
1224 * >0 when newPrpoerty > currentProperty
1225 * 0 when newPrpoerty == currentProperty
1226 */
1227static LONG propertyNameCmp(
1228 OLECHAR *newProperty,
1229 OLECHAR *currentProperty)
1230{
1231 LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty);
1232
1233 if (diff == 0)
1234 {
1235 /*
1236 * We compare the string themselves only when they are of the same lenght
1237 */
1238 diff = lstrcmpiW( newProperty, currentProperty);
1239 }
1240
1241 return diff;
1242}
1243
1244/****************************************************************************
1245 *
1246 * Internal Method
1247 *
1248 * Properly link this new element in the property chain.
1249 */
1250static void updatePropertyChain(
1251 StorageImpl *storage,
1252 ULONG newPropertyIndex,
1253 StgProperty newProperty)
1254{
1255 StgProperty currentProperty;
1256
1257 /*
1258 * Read the root property
1259 */
1260 StorageImpl_ReadProperty(storage->ancestorStorage,
1261 storage->rootPropertySetIndex,
1262 &currentProperty);
1263
1264 if (currentProperty.dirProperty != PROPERTY_NULL)
1265 {
1266 /*
1267 * The root storage contains some element, therefore, start the research
1268 * for the appropriate location.
1269 */
1270 BOOL found = 0;
1271 ULONG current, next, previous, currentPropertyId;
1272
1273 /*
1274 * Keep the StgProperty sequence number of the storage first property
1275 */
1276 currentPropertyId = currentProperty.dirProperty;
1277
1278 /*
1279 * Read
1280 */
1281 StorageImpl_ReadProperty(storage->ancestorStorage,
1282 currentProperty.dirProperty,
1283 &currentProperty);
1284
1285 previous = currentProperty.previousProperty;
1286 next = currentProperty.nextProperty;
1287 current = currentPropertyId;
1288
1289 while (found == 0)
1290 {
1291 LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
1292
1293 if (diff < 0)
1294 {
1295 if (previous != PROPERTY_NULL)
1296 {
1297 StorageImpl_ReadProperty(storage->ancestorStorage,
1298 previous,
1299 &currentProperty);
1300 current = previous;
1301 }
1302 else
1303 {
1304 currentProperty.previousProperty = newPropertyIndex;
1305 StorageImpl_WriteProperty(storage->ancestorStorage,
1306 current,
1307 &currentProperty);
1308 found = 1;
1309 }
1310 }
1311 else if (diff > 0)
1312 {
1313 if (next != PROPERTY_NULL)
1314 {
1315 StorageImpl_ReadProperty(storage->ancestorStorage,
1316 next,
1317 &currentProperty);
1318 current = next;
1319 }
1320 else
1321 {
1322 currentProperty.nextProperty = newPropertyIndex;
1323 StorageImpl_WriteProperty(storage->ancestorStorage,
1324 current,
1325 &currentProperty);
1326 found = 1;
1327 }
1328 }
1329 else
1330 {
1331 /*
1332 * Trying to insert an item with the same name in the
1333 * subtree structure.
1334 */
1335 assert(FALSE);
1336 }
1337
1338 previous = currentProperty.previousProperty;
1339 next = currentProperty.nextProperty;
1340 }
1341 }
1342 else
1343 {
1344 /*
1345 * The root storage is empty, link the new property to it's dir property
1346 */
1347 currentProperty.dirProperty = newPropertyIndex;
1348 StorageImpl_WriteProperty(storage->ancestorStorage,
1349 storage->rootPropertySetIndex,
1350 &currentProperty);
1351 }
1352}
1353
1354
1355/*************************************************************************
1356 * CopyTo (IStorage)
1357 */
1358HRESULT WINAPI StorageImpl_CopyTo(
1359 IStorage* iface,
1360 DWORD ciidExclude, /* [in] */
1361 const IID* rgiidExclude, /* [size_is][unique][in] */
1362 SNB snbExclude, /* [unique][in] */
1363 IStorage* pstgDest) /* [unique][in] */
1364{
1365 IEnumSTATSTG *elements = 0;
1366 STATSTG curElement, strStat;
1367 HRESULT hr;
1368 IStorage *pstgTmp, *pstgChild;
1369 IStream *pstrTmp, *pstrChild;
1370
1371 if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
1372 FIXME("Exclude option not implemented\n");
1373
1374 TRACE("(%p, %ld, %p, %p, %p)\n",
1375 iface, ciidExclude, rgiidExclude,
1376 snbExclude, pstgDest);
1377
1378 /*
1379 * Perform a sanity check
1380 */
1381 if ( pstgDest == 0 )
1382 return STG_E_INVALIDPOINTER;
1383
1384 /*
1385 * Enumerate the elements
1386 */
1387 hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
1388
1389 if ( hr != S_OK )
1390 return hr;
1391
1392 /*
1393 * set the class ID
1394 */
1395 IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
1396 IStorage_SetClass( pstgDest, &curElement.clsid );
1397
1398 do
1399 {
1400 /*
1401 * Obtain the next element
1402 */
1403 hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
1404
1405 if ( hr == S_FALSE )
1406 {
1407 hr = S_OK; /* done, every element has been copied */
1408 break;
1409 }
1410
1411 if (curElement.type == STGTY_STORAGE)
1412 {
1413 /*
1414 * open child source storage
1415 */
1416 hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
1417 STGM_READ|STGM_SHARE_EXCLUSIVE,
1418 NULL, 0, &pstgChild );
1419
1420 if (hr != S_OK)
1421 break;
1422
1423 /*
1424 * Check if destination storage is not a child of the source
1425 * storage, which will cause an infinite loop
1426 */
1427 if (pstgChild == pstgDest)
1428 {
1429 IEnumSTATSTG_Release(elements);
1430
1431 return STG_E_ACCESSDENIED;
1432 }
1433
1434 /*
1435 * create a new storage in destination storage
1436 */
1437 hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
1438 STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1439 0, 0,
1440 &pstgTmp );
1441 /*
1442 * if it already exist, don't create a new one use this one
1443 */
1444 if (hr == STG_E_FILEALREADYEXISTS)
1445 {
1446 hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
1447 STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1448 NULL, 0, &pstgTmp );
1449 }
1450
1451 if (hr != S_OK)
1452 break;
1453
1454
1455 /*
1456 * do the copy recursively
1457 */
1458 hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
1459 snbExclude, pstgTmp );
1460
1461 IStorage_Release( pstgTmp );
1462 IStorage_Release( pstgChild );
1463 }
1464 else if (curElement.type == STGTY_STREAM)
1465 {
1466 /*
1467 * create a new stream in destination storage. If the stream already
1468 * exist, it will be deleted and a new one will be created.
1469 */
1470 hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
1471 STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
1472 0, 0, &pstrTmp );
1473
1474 if (hr != S_OK)
1475 break;
1476
1477 /*
1478 * open child stream storage
1479 */
1480 hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
1481 STGM_READ|STGM_SHARE_EXCLUSIVE,
1482 0, &pstrChild );
1483
1484 if (hr != S_OK)
1485 break;
1486
1487 /*
1488 * Get the size of the source stream
1489 */
1490 IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1491
1492 /*
1493 * Set the size of the destination stream.
1494 */
1495 IStream_SetSize(pstrTmp, strStat.cbSize);
1496
1497 /*
1498 * do the copy
1499 */
1500 hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1501 NULL, NULL );
1502
1503 IStream_Release( pstrTmp );
1504 IStream_Release( pstrChild );
1505 }
1506 else
1507 {
1508 WARN("unknown element type: %ld\n", curElement.type);
1509 }
1510
1511 } while (hr == S_OK);
1512
1513 /*
1514 * Clean-up
1515 */
1516 IEnumSTATSTG_Release(elements);
1517
1518 return hr;
1519}
1520
1521/*************************************************************************
1522 * MoveElementTo (IStorage)
1523 */
1524HRESULT WINAPI StorageImpl_MoveElementTo(
1525 IStorage* iface,
1526 const OLECHAR *pwcsName, /* [string][in] */
1527 IStorage *pstgDest, /* [unique][in] */
1528 const OLECHAR *pwcsNewName,/* [string][in] */
1529 DWORD grfFlags) /* [in] */
1530{
1531 FIXME("not implemented!\n");
1532 return E_NOTIMPL;
1533}
1534
1535/*************************************************************************
1536 * Commit (IStorage)
1537 */
1538HRESULT WINAPI StorageImpl_Commit(
1539 IStorage* iface,
1540 DWORD grfCommitFlags)/* [in] */
1541{
1542 FIXME("(%ld): stub!\n", grfCommitFlags);
1543 return S_OK;
1544}
1545
1546/*************************************************************************
1547 * Revert (IStorage)
1548 */
1549HRESULT WINAPI StorageImpl_Revert(
1550 IStorage* iface)
1551{
1552 FIXME("not implemented!\n");
1553 return E_NOTIMPL;
1554}
1555
1556/*************************************************************************
1557 * DestroyElement (IStorage)
1558 *
1559 * Stategy: This implementation is build this way for simplicity not for speed.
1560 * I always delete the top most element of the enumeration and adjust
1561 * the deleted element pointer all the time. This takes longer to
1562 * do but allow to reinvoke DestroyElement whenever we encounter a
1563 * storage object. The optimisation reside in the usage of another
1564 * enumeration stategy that would give all the leaves of a storage
1565 * first. (postfix order)
1566 */
1567HRESULT WINAPI StorageImpl_DestroyElement(
1568 IStorage* iface,
1569 const OLECHAR *pwcsName)/* [string][in] */
1570{
1571 StorageImpl* const This=(StorageImpl*)iface;
1572
1573 IEnumSTATSTGImpl* propertyEnumeration;
1574 HRESULT hr = S_OK;
1575 BOOL res;
1576 StgProperty propertyToDelete;
1577 StgProperty parentProperty;
1578 ULONG foundPropertyIndexToDelete;
1579 ULONG typeOfRelation;
1580 ULONG parentPropertyId;
1581
1582 TRACE("(%p, %s)\n",
1583 iface, debugstr_w(pwcsName));
1584
1585 /*
1586 * Perform a sanity check on the parameters.
1587 */
1588 if (pwcsName==NULL)
1589 return STG_E_INVALIDPOINTER;
1590
1591 /*
1592 * Create a property enumeration to search the property with the given name
1593 */
1594 propertyEnumeration = IEnumSTATSTGImpl_Construct(
1595 This->ancestorStorage,
1596 This->rootPropertySetIndex);
1597
1598 foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
1599 propertyEnumeration,
1600 pwcsName,
1601 &propertyToDelete);
1602
1603 IEnumSTATSTGImpl_Destroy(propertyEnumeration);
1604
1605 if ( foundPropertyIndexToDelete == PROPERTY_NULL )
1606 {
1607 return STG_E_FILENOTFOUND;
1608 }
1609
1610 /*
1611 * Find the parent property of the property to delete (the one that
1612 * link to it). If This->dirProperty == foundPropertyIndexToDelete,
1613 * the parent is This. Otherwise, the parent is one of it's sibling...
1614 */
1615
1616 /*
1617 * First, read This's StgProperty..
1618 */
1619 res = StorageImpl_ReadProperty(
1620 This->ancestorStorage,
1621 This->rootPropertySetIndex,
1622 &parentProperty);
1623
1624 assert(res==TRUE);
1625
1626 /*
1627 * Second, check to see if by any chance the actual storage (This) is not
1628 * the parent of the property to delete... We never know...
1629 */
1630 if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
1631 {
1632 /*
1633 * Set data as it would have been done in the else part...
1634 */
1635 typeOfRelation = PROPERTY_RELATION_DIR;
1636 parentPropertyId = This->rootPropertySetIndex;
1637 }
1638 else
1639 {
1640 /*
1641 * Create a property enumeration to search the parent properties, and
1642 * delete it once done.
1643 */
1644 IEnumSTATSTGImpl* propertyEnumeration2;
1645
1646 propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
1647 This->ancestorStorage,
1648 This->rootPropertySetIndex);
1649
1650 typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
1651 propertyEnumeration2,
1652 foundPropertyIndexToDelete,
1653 &parentProperty,
1654 &parentPropertyId);
1655
1656 IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
1657 }
1658
1659 if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
1660 {
1661 hr = deleteStorageProperty(
1662 This,
1663 foundPropertyIndexToDelete,
1664 propertyToDelete);
1665 }
1666 else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
1667 {
1668 hr = deleteStreamProperty(
1669 This,
1670 foundPropertyIndexToDelete,
1671 propertyToDelete);
1672 }
1673
1674 if (hr!=S_OK)
1675 return hr;
1676
1677 /*
1678 * Adjust the property chain
1679 */
1680 hr = adjustPropertyChain(
1681 This,
1682 propertyToDelete,
1683 parentProperty,
1684 parentPropertyId,
1685 typeOfRelation);
1686
1687 return hr;
1688}
1689
1690
1691/*********************************************************************
1692 *
1693 * Internal Method
1694 *
1695 * Perform the deletion of a complete storage node
1696 *
1697 */
1698static HRESULT deleteStorageProperty(
1699 StorageImpl *parentStorage,
1700 ULONG indexOfPropertyToDelete,
1701 StgProperty propertyToDelete)
1702{
1703 IEnumSTATSTG *elements = 0;
1704 IStorage *childStorage = 0;
1705 STATSTG currentElement;
1706 HRESULT hr;
1707 HRESULT destroyHr = S_OK;
1708
1709 /*
1710 * Open the storage and enumerate it
1711 */
1712 hr = StorageBaseImpl_OpenStorage(
1713 (IStorage*)parentStorage,
1714 propertyToDelete.name,
1715 0,
1716 STGM_SHARE_EXCLUSIVE,
1717 0,
1718 0,
1719 &childStorage);
1720
1721 if (hr != S_OK)
1722 {
1723 return hr;
1724 }
1725
1726 /*
1727 * Enumerate the elements
1728 */
1729 IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
1730
1731 do
1732 {
1733 /*
1734 * Obtain the next element
1735 */
1736 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
1737 if (hr==S_OK)
1738 {
1739 destroyHr = StorageImpl_DestroyElement(
1740 (IStorage*)childStorage,
1741 (OLECHAR*)currentElement.pwcsName);
1742
1743 CoTaskMemFree(currentElement.pwcsName);
1744 }
1745
1746 /*
1747 * We need to Reset the enumeration every time because we delete elements
1748 * and the enumeration could be invalid
1749 */
1750 IEnumSTATSTG_Reset(elements);
1751
1752 } while ((hr == S_OK) && (destroyHr == S_OK));
1753
1754 /*
1755 * Invalidate the property by zeroing it's name member.
1756 */
1757 propertyToDelete.sizeOfNameString = 0;
1758
1759 StorageImpl_WriteProperty(parentStorage->ancestorStorage,
1760 indexOfPropertyToDelete,
1761 &propertyToDelete);
1762
1763 IStorage_Release(childStorage);
1764 IEnumSTATSTG_Release(elements);
1765
1766 return destroyHr;
1767}
1768
1769/*********************************************************************
1770 *
1771 * Internal Method
1772 *
1773 * Perform the deletion of a stream node
1774 *
1775 */
1776static HRESULT deleteStreamProperty(
1777 StorageImpl *parentStorage,
1778 ULONG indexOfPropertyToDelete,
1779 StgProperty propertyToDelete)
1780{
1781 IStream *pis;
1782 HRESULT hr;
1783 ULARGE_INTEGER size;
1784
1785 size.s.HighPart = 0;
1786 size.s.LowPart = 0;
1787
1788 hr = StorageBaseImpl_OpenStream(
1789 (IStorage*)parentStorage,
1790 (OLECHAR*)propertyToDelete.name,
1791 NULL,
1792 STGM_WRITE | STGM_SHARE_EXCLUSIVE,
1793 0,
1794 &pis);
1795
1796 if (hr!=S_OK)
1797 {
1798 return(hr);
1799 }
1800
1801 /*
1802 * Zap the stream
1803 */
1804 hr = IStream_SetSize(pis, size);
1805
1806 if(hr != S_OK)
1807 {
1808 return hr;
1809 }
1810
1811 /*
1812 * Release the stream object.
1813 */
1814 IStream_Release(pis);
1815
1816 /*
1817 * Invalidate the property by zeroing it's name member.
1818 */
1819 propertyToDelete.sizeOfNameString = 0;
1820
1821 /*
1822 * Here we should re-read the property so we get the updated pointer
1823 * but since we are here to zap it, I don't do it...
1824 */
1825 StorageImpl_WriteProperty(
1826 parentStorage->ancestorStorage,
1827 indexOfPropertyToDelete,
1828 &propertyToDelete);
1829
1830 return S_OK;
1831}
1832
1833/*********************************************************************
1834 *
1835 * Internal Method
1836 *
1837 * Finds a placeholder for the StgProperty within the Storage
1838 *
1839 */
1840static HRESULT findPlaceholder(
1841 StorageImpl *storage,
1842 ULONG propertyIndexToStore,
1843 ULONG storePropertyIndex,
1844 INT typeOfRelation)
1845{
1846 StgProperty storeProperty;
1847 HRESULT hr = S_OK;
1848 BOOL res = TRUE;
1849
1850 /*
1851 * Read the storage property
1852 */
1853 res = StorageImpl_ReadProperty(
1854 storage->ancestorStorage,
1855 storePropertyIndex,
1856 &storeProperty);
1857
1858 if(! res)
1859 {
1860 return E_FAIL;
1861 }
1862
1863 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1864 {
1865 if (storeProperty.previousProperty != PROPERTY_NULL)
1866 {
1867 return findPlaceholder(
1868 storage,
1869 propertyIndexToStore,
1870 storeProperty.previousProperty,
1871 typeOfRelation);
1872 }
1873 else
1874 {
1875 storeProperty.previousProperty = propertyIndexToStore;
1876 }
1877 }
1878 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1879 {
1880 if (storeProperty.nextProperty != PROPERTY_NULL)
1881 {
1882 return findPlaceholder(
1883 storage,
1884 propertyIndexToStore,
1885 storeProperty.nextProperty,
1886 typeOfRelation);
1887 }
1888 else
1889 {
1890 storeProperty.nextProperty = propertyIndexToStore;
1891 }
1892 }
1893 else if (typeOfRelation == PROPERTY_RELATION_DIR)
1894 {
1895 if (storeProperty.dirProperty != PROPERTY_NULL)
1896 {
1897 return findPlaceholder(
1898 storage,
1899 propertyIndexToStore,
1900 storeProperty.dirProperty,
1901 typeOfRelation);
1902 }
1903 else
1904 {
1905 storeProperty.dirProperty = propertyIndexToStore;
1906 }
1907 }
1908
1909 hr = StorageImpl_WriteProperty(
1910 storage->ancestorStorage,
1911 storePropertyIndex,
1912 &storeProperty);
1913
1914 if(! hr)
1915 {
1916 return E_FAIL;
1917 }
1918
1919 return S_OK;
1920}
1921
1922/*************************************************************************
1923 *
1924 * Internal Method
1925 *
1926 * This method takes the previous and the next property link of a property
1927 * to be deleted and find them a place in the Storage.
1928 */
1929static HRESULT adjustPropertyChain(
1930 StorageImpl *This,
1931 StgProperty propertyToDelete,
1932 StgProperty parentProperty,
1933 ULONG parentPropertyId,
1934 INT typeOfRelation)
1935{
1936 ULONG newLinkProperty = PROPERTY_NULL;
1937 BOOL needToFindAPlaceholder = FALSE;
1938 ULONG storeNode = PROPERTY_NULL;
1939 ULONG toStoreNode = PROPERTY_NULL;
1940 INT relationType = 0;
1941 HRESULT hr = S_OK;
1942 BOOL res = TRUE;
1943
1944 if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
1945 {
1946 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1947 {
1948 /*
1949 * Set the parent previous to the property to delete previous
1950 */
1951 newLinkProperty = propertyToDelete.previousProperty;
1952
1953 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1954 {
1955 /*
1956 * We also need to find a storage for the other link, setup variables
1957 * to do this at the end...
1958 */
1959 needToFindAPlaceholder = TRUE;
1960 storeNode = propertyToDelete.previousProperty;
1961 toStoreNode = propertyToDelete.nextProperty;
1962 relationType = PROPERTY_RELATION_NEXT;
1963 }
1964 }
1965 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
1966 {
1967 /*
1968 * Set the parent previous to the property to delete next
1969 */
1970 newLinkProperty = propertyToDelete.nextProperty;
1971 }
1972
1973 /*
1974 * Link it for real...
1975 */
1976 parentProperty.previousProperty = newLinkProperty;
1977
1978 }
1979 else if (typeOfRelation == PROPERTY_RELATION_NEXT)
1980 {
1981 if (propertyToDelete.previousProperty != PROPERTY_NULL)
1982 {
1983 /*
1984 * Set the parent next to the property to delete next previous
1985 */
1986 newLinkProperty = propertyToDelete.previousProperty;
1987
1988 if (propertyToDelete.nextProperty != PROPERTY_NULL)
1989 {
1990 /*
1991 * We also need to find a storage for the other link, setup variables
1992 * to do this at the end...
1993 */
1994 needToFindAPlaceholder = TRUE;
1995 storeNode = propertyToDelete.previousProperty;
1996 toStoreNode = propertyToDelete.nextProperty;
1997 relationType = PROPERTY_RELATION_NEXT;
1998 }
1999 }
2000 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2001 {
2002 /*
2003 * Set the parent next to the property to delete next
2004 */
2005 newLinkProperty = propertyToDelete.nextProperty;
2006 }
2007
2008 /*
2009 * Link it for real...
2010 */
2011 parentProperty.nextProperty = newLinkProperty;
2012 }
2013 else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
2014 {
2015 if (propertyToDelete.previousProperty != PROPERTY_NULL)
2016 {
2017 /*
2018 * Set the parent dir to the property to delete previous
2019 */
2020 newLinkProperty = propertyToDelete.previousProperty;
2021
2022 if (propertyToDelete.nextProperty != PROPERTY_NULL)
2023 {
2024 /*
2025 * We also need to find a storage for the other link, setup variables
2026 * to do this at the end...
2027 */
2028 needToFindAPlaceholder = TRUE;
2029 storeNode = propertyToDelete.previousProperty;
2030 toStoreNode = propertyToDelete.nextProperty;
2031 relationType = PROPERTY_RELATION_NEXT;
2032 }
2033 }
2034 else if (propertyToDelete.nextProperty != PROPERTY_NULL)
2035 {
2036 /*
2037 * Set the parent dir to the property to delete next
2038 */
2039 newLinkProperty = propertyToDelete.nextProperty;
2040 }
2041
2042 /*
2043 * Link it for real...
2044 */
2045 parentProperty.dirProperty = newLinkProperty;
2046 }
2047
2048 /*
2049 * Write back the parent property
2050 */
2051 res = StorageImpl_WriteProperty(
2052 This->ancestorStorage,
2053 parentPropertyId,
2054 &parentProperty);
2055 if(! res)
2056 {
2057 return E_FAIL;
2058 }
2059
2060 /*
2061 * If a placeholder is required for the other link, then, find one and
2062 * get out of here...
2063 */
2064 if (needToFindAPlaceholder)
2065 {
2066 hr = findPlaceholder(
2067 This,
2068 toStoreNode,
2069 storeNode,
2070 relationType);
2071 }
2072
2073 return hr;
2074}
2075
2076
2077/******************************************************************************
2078 * SetElementTimes (IStorage)
2079 */
2080HRESULT WINAPI StorageImpl_SetElementTimes(
2081 IStorage* iface,
2082 const OLECHAR *pwcsName,/* [string][in] */
2083 const FILETIME *pctime, /* [in] */
2084 const FILETIME *patime, /* [in] */
2085 const FILETIME *pmtime) /* [in] */
2086{
2087 FIXME("not implemented!\n");
2088 return E_NOTIMPL;
2089}
2090
2091/******************************************************************************
2092 * SetStateBits (IStorage)
2093 */
2094HRESULT WINAPI StorageImpl_SetStateBits(
2095 IStorage* iface,
2096 DWORD grfStateBits,/* [in] */
2097 DWORD grfMask) /* [in] */
2098{
2099 FIXME("not implemented!\n");
2100 return E_NOTIMPL;
2101}
2102
2103HRESULT StorageImpl_Construct(
2104 StorageImpl* This,
2105 HANDLE hFile,
2106 ILockBytes* pLkbyt,
2107 DWORD openFlags,
2108 BOOL fileBased,
2109 BOOL fileCreate)
2110{
2111 HRESULT hr = S_OK;
2112 StgProperty currentProperty;
2113 BOOL readSuccessful;
2114 ULONG currentPropertyIndex;
2115
2116 if ( FAILED( validateSTGM(openFlags) ))
2117 return STG_E_INVALIDFLAG;
2118
2119 memset(This, 0, sizeof(StorageImpl));
2120
2121 /*
2122 * Initialize the virtual fgunction table.
2123 */
2124 ICOM_VTBL(This) = &Storage32Impl_Vtbl;
2125 This->v_destructor = &StorageImpl_Destroy;
2126
2127 /*
2128 * This is the top-level storage so initialize the ancester pointer
2129 * to this.
2130 */
2131 This->ancestorStorage = This;
2132
2133 /*
2134 * Initialize the physical support of the storage.
2135 */
2136 This->hFile = hFile;
2137
2138 /*
2139 * Initialize the big block cache.
2140 */
2141 This->bigBlockSize = DEF_BIG_BLOCK_SIZE;
2142 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
2143 This->bigBlockFile = BIGBLOCKFILE_Construct(hFile,
2144 pLkbyt,
2145 openFlags,
2146 This->bigBlockSize,
2147 fileBased);
2148
2149 if (This->bigBlockFile == 0)
2150 return E_FAIL;
2151
2152 if (fileCreate)
2153 {
2154 ULARGE_INTEGER size;
2155 BYTE* bigBlockBuffer;
2156
2157 /*
2158 * Initialize all header variables:
2159 * - The big block depot consists of one block and it is at block 0
2160 * - The properties start at block 1
2161 * - There is no small block depot
2162 */
2163 memset( This->bigBlockDepotStart,
2164 BLOCK_UNUSED,
2165 sizeof(This->bigBlockDepotStart));
2166
2167 This->bigBlockDepotCount = 1;
2168 This->bigBlockDepotStart[0] = 0;
2169 This->rootStartBlock = 1;
2170 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
2171 This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS;
2172 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
2173 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
2174 This->extBigBlockDepotCount = 0;
2175
2176 StorageImpl_SaveFileHeader(This);
2177
2178 /*
2179 * Add one block for the big block depot and one block for the properties
2180 */
2181 size.s.HighPart = 0;
2182 size.s.LowPart = This->bigBlockSize * 3;
2183 BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
2184
2185 /*
2186 * Initialize the big block depot
2187 */
2188 bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
2189 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2190 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
2191 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
2192 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
2193 }
2194 else
2195 {
2196 /*
2197 * Load the header for the file.
2198 */
2199 hr = StorageImpl_LoadFileHeader(This);
2200
2201 if (FAILED(hr))
2202 {
2203 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2204
2205 return hr;
2206 }
2207 }
2208
2209 /*
2210 * There is no block depot cached yet.
2211 */
2212 This->indexBlockDepotCached = 0xFFFFFFFF;
2213
2214 /*
2215 * Start searching for free blocks with block 0.
2216 */
2217 This->prevFreeBlock = 0;
2218
2219 /*
2220 * Create the block chain abstractions.
2221 */
2222 This->rootBlockChain =
2223 BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
2224
2225 This->smallBlockDepotChain = BlockChainStream_Construct(
2226 This,
2227 &This->smallBlockDepotStart,
2228 PROPERTY_NULL);
2229
2230 /*
2231 * Write the root property
2232 */
2233 if (fileCreate)
2234 {
2235 StgProperty rootProp;
2236 /*
2237 * Initialize the property chain
2238 */
2239 memset(&rootProp, 0, sizeof(rootProp));
2240 MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name,
2241 sizeof(rootProp.name)/sizeof(WCHAR) );
2242 rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR);
2243 rootProp.propertyType = PROPTYPE_ROOT;
2244 rootProp.previousProperty = PROPERTY_NULL;
2245 rootProp.nextProperty = PROPERTY_NULL;
2246 rootProp.dirProperty = PROPERTY_NULL;
2247 rootProp.startingBlock = BLOCK_END_OF_CHAIN;
2248 rootProp.size.s.HighPart = 0;
2249 rootProp.size.s.LowPart = 0;
2250
2251 StorageImpl_WriteProperty(This, 0, &rootProp);
2252 }
2253
2254 /*
2255 * Find the ID of the root int he property sets.
2256 */
2257 currentPropertyIndex = 0;
2258
2259 do
2260 {
2261 readSuccessful = StorageImpl_ReadProperty(
2262 This,
2263 currentPropertyIndex,
2264 &currentProperty);
2265
2266 if (readSuccessful)
2267 {
2268 if ( (currentProperty.sizeOfNameString != 0 ) &&
2269 (currentProperty.propertyType == PROPTYPE_ROOT) )
2270 {
2271 This->rootPropertySetIndex = currentPropertyIndex;
2272 }
2273 }
2274
2275 currentPropertyIndex++;
2276
2277 } while (readSuccessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
2278
2279 if (!readSuccessful)
2280 {
2281 /* TODO CLEANUP */
2282 return E_FAIL;
2283 }
2284
2285 /*
2286 * Create the block chain abstraction for the small block root chain.
2287 */
2288 This->smallBlockRootChain = BlockChainStream_Construct(
2289 This,
2290 NULL,
2291 This->rootPropertySetIndex);
2292
2293 return hr;
2294}
2295
2296void StorageImpl_Destroy(
2297 StorageImpl* This)
2298{
2299 TRACE("(%p)\n", This);
2300
2301 BlockChainStream_Destroy(This->smallBlockRootChain);
2302 BlockChainStream_Destroy(This->rootBlockChain);
2303 BlockChainStream_Destroy(This->smallBlockDepotChain);
2304
2305 BIGBLOCKFILE_Destructor(This->bigBlockFile);
2306 return;
2307}
2308
2309/******************************************************************************
2310 * Storage32Impl_GetNextFreeBigBlock
2311 *
2312 * Returns the index of the next free big block.
2313 * If the big block depot is filled, this method will enlarge it.
2314 *
2315 */
2316ULONG StorageImpl_GetNextFreeBigBlock(
2317 StorageImpl* This)
2318{
2319 ULONG depotBlockIndexPos;
2320 void *depotBuffer;
2321 ULONG depotBlockOffset;
2322 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
2323 ULONG nextBlockIndex = BLOCK_SPECIAL;
2324 int depotIndex = 0;
2325 ULONG freeBlock = BLOCK_UNUSED;
2326
2327 depotIndex = This->prevFreeBlock / blocksPerDepot;
2328 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
2329
2330 /*
2331 * Scan the entire big block depot until we find a block marked free
2332 */
2333 while (nextBlockIndex != BLOCK_UNUSED)
2334 {
2335 if (depotIndex < COUNT_BBDEPOTINHEADER)
2336 {
2337 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
2338
2339 /*
2340 * Grow the primary depot.
2341 */
2342 if (depotBlockIndexPos == BLOCK_UNUSED)
2343 {
2344 depotBlockIndexPos = depotIndex*blocksPerDepot;
2345
2346 /*
2347 * Add a block depot.
2348 */
2349 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2350 This->bigBlockDepotCount++;
2351 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
2352
2353 /*
2354 * Flag it as a block depot.
2355 */
2356 StorageImpl_SetNextBlockInChain(This,
2357 depotBlockIndexPos,
2358 BLOCK_SPECIAL);
2359
2360 /* Save new header information.
2361 */
2362 StorageImpl_SaveFileHeader(This);
2363 }
2364 }
2365 else
2366 {
2367 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
2368
2369 if (depotBlockIndexPos == BLOCK_UNUSED)
2370 {
2371 /*
2372 * Grow the extended depot.
2373 */
2374 ULONG extIndex = BLOCK_UNUSED;
2375 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2376 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
2377
2378 if (extBlockOffset == 0)
2379 {
2380 /* We need an extended block.
2381 */
2382 extIndex = Storage32Impl_AddExtBlockDepot(This);
2383 This->extBigBlockDepotCount++;
2384 depotBlockIndexPos = extIndex + 1;
2385 }
2386 else
2387 depotBlockIndexPos = depotIndex * blocksPerDepot;
2388
2389 /*
2390 * Add a block depot and mark it in the extended block.
2391 */
2392 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
2393 This->bigBlockDepotCount++;
2394 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
2395
2396 /* Flag the block depot.
2397 */
2398 StorageImpl_SetNextBlockInChain(This,
2399 depotBlockIndexPos,
2400 BLOCK_SPECIAL);
2401
2402 /* If necessary, flag the extended depot block.
2403 */
2404 if (extIndex != BLOCK_UNUSED)
2405 StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
2406
2407 /* Save header information.
2408 */
2409 StorageImpl_SaveFileHeader(This);
2410 }
2411 }
2412
2413 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2414
2415 if (depotBuffer != 0)
2416 {
2417 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
2418 ( nextBlockIndex != BLOCK_UNUSED))
2419 {
2420 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2421
2422 if (nextBlockIndex == BLOCK_UNUSED)
2423 {
2424 freeBlock = (depotIndex * blocksPerDepot) +
2425 (depotBlockOffset/sizeof(ULONG));
2426 }
2427
2428 depotBlockOffset += sizeof(ULONG);
2429 }
2430
2431 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2432 }
2433
2434 depotIndex++;
2435 depotBlockOffset = 0;
2436 }
2437
2438 This->prevFreeBlock = freeBlock;
2439
2440 return freeBlock;
2441}
2442
2443/******************************************************************************
2444 * Storage32Impl_AddBlockDepot
2445 *
2446 * This will create a depot block, essentially it is a block initialized
2447 * to BLOCK_UNUSEDs.
2448 */
2449void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
2450{
2451 BYTE* blockBuffer;
2452
2453 blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
2454
2455 /*
2456 * Initialize blocks as free
2457 */
2458 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
2459
2460 StorageImpl_ReleaseBigBlock(This, blockBuffer);
2461}
2462
2463/******************************************************************************
2464 * Storage32Impl_GetExtDepotBlock
2465 *
2466 * Returns the index of the block that corresponds to the specified depot
2467 * index. This method is only for depot indexes equal or greater than
2468 * COUNT_BBDEPOTINHEADER.
2469 */
2470ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
2471{
2472 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2473 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2474 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2475 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2476 ULONG blockIndex = BLOCK_UNUSED;
2477 ULONG extBlockIndex = This->extBigBlockDepotStart;
2478
2479 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2480
2481 if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
2482 return BLOCK_UNUSED;
2483
2484 while (extBlockCount > 0)
2485 {
2486 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2487 extBlockCount--;
2488 }
2489
2490 if (extBlockIndex != BLOCK_UNUSED)
2491 {
2492 BYTE* depotBuffer;
2493
2494 depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
2495
2496 if (depotBuffer != 0)
2497 {
2498 StorageUtl_ReadDWord(depotBuffer,
2499 extBlockOffset * sizeof(ULONG),
2500 &blockIndex);
2501
2502 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2503 }
2504 }
2505
2506 return blockIndex;
2507}
2508
2509/******************************************************************************
2510 * Storage32Impl_SetExtDepotBlock
2511 *
2512 * Associates the specified block index to the specified depot index.
2513 * This method is only for depot indexes equal or greater than
2514 * COUNT_BBDEPOTINHEADER.
2515 */
2516void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
2517 ULONG depotIndex,
2518 ULONG blockIndex)
2519{
2520 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
2521 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
2522 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
2523 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
2524 ULONG extBlockIndex = This->extBigBlockDepotStart;
2525
2526 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
2527
2528 while (extBlockCount > 0)
2529 {
2530 extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
2531 extBlockCount--;
2532 }
2533
2534 if (extBlockIndex != BLOCK_UNUSED)
2535 {
2536 BYTE* depotBuffer;
2537
2538 depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
2539
2540 if (depotBuffer != 0)
2541 {
2542 StorageUtl_WriteDWord(depotBuffer,
2543 extBlockOffset * sizeof(ULONG),
2544 blockIndex);
2545
2546 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2547 }
2548 }
2549}
2550
2551/******************************************************************************
2552 * Storage32Impl_AddExtBlockDepot
2553 *
2554 * Creates an extended depot block.
2555 */
2556ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
2557{
2558 ULONG numExtBlocks = This->extBigBlockDepotCount;
2559 ULONG nextExtBlock = This->extBigBlockDepotStart;
2560 BYTE* depotBuffer = NULL;
2561 ULONG index = BLOCK_UNUSED;
2562 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
2563 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
2564 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
2565
2566 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
2567 blocksPerDepotBlock;
2568
2569 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
2570 {
2571 /*
2572 * The first extended block.
2573 */
2574 This->extBigBlockDepotStart = index;
2575 }
2576 else
2577 {
2578 int i;
2579 /*
2580 * Follow the chain to the last one.
2581 */
2582 for (i = 0; i < (numExtBlocks - 1); i++)
2583 {
2584 nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
2585 }
2586
2587 /*
2588 * Add the new extended block to the chain.
2589 */
2590 depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
2591 StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
2592 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2593 }
2594
2595 /*
2596 * Initialize this block.
2597 */
2598 depotBuffer = StorageImpl_GetBigBlock(This, index);
2599 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
2600 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2601
2602 return index;
2603}
2604
2605/******************************************************************************
2606 * Storage32Impl_FreeBigBlock
2607 *
2608 * This method will flag the specified block as free in the big block depot.
2609 */
2610void StorageImpl_FreeBigBlock(
2611 StorageImpl* This,
2612 ULONG blockIndex)
2613{
2614 StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
2615
2616 if (blockIndex < This->prevFreeBlock)
2617 This->prevFreeBlock = blockIndex;
2618}
2619
2620/************************************************************************
2621 * Storage32Impl_GetNextBlockInChain
2622 *
2623 * This method will retrieve the block index of the next big block in
2624 * in the chain.
2625 *
2626 * Params: This - Pointer to the Storage object.
2627 * blockIndex - Index of the block to retrieve the chain
2628 * for.
2629 *
2630 * Returns: This method returns the index of the next block in the chain.
2631 * It will return the constants:
2632 * BLOCK_SPECIAL - If the block given was not part of a
2633 * chain.
2634 * BLOCK_END_OF_CHAIN - If the block given was the last in
2635 * a chain.
2636 * BLOCK_UNUSED - If the block given was not past of a chain
2637 * and is available.
2638 * BLOCK_EXTBBDEPOT - This block is part of the extended
2639 * big block depot.
2640 *
2641 * See Windows documentation for more details on IStorage methods.
2642 */
2643ULONG StorageImpl_GetNextBlockInChain(
2644 StorageImpl* This,
2645 ULONG blockIndex)
2646{
2647 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2648 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2649 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2650 ULONG nextBlockIndex = BLOCK_SPECIAL;
2651 void* depotBuffer;
2652 ULONG depotBlockIndexPos;
2653
2654 assert(depotBlockCount < This->bigBlockDepotCount);
2655
2656 /*
2657 * Cache the currently accessed depot block.
2658 */
2659 if (depotBlockCount != This->indexBlockDepotCached)
2660 {
2661 This->indexBlockDepotCached = depotBlockCount;
2662
2663 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2664 {
2665 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2666 }
2667 else
2668 {
2669 /*
2670 * We have to look in the extended depot.
2671 */
2672 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2673 }
2674
2675 depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
2676
2677 if (depotBuffer!=0)
2678 {
2679 int index;
2680
2681 for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
2682 {
2683 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &nextBlockIndex);
2684 This->blockDepotCached[index] = nextBlockIndex;
2685 }
2686
2687 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2688 }
2689 }
2690
2691 nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
2692
2693 return nextBlockIndex;
2694}
2695
2696/******************************************************************************
2697 * Storage32Impl_GetNextExtendedBlock
2698 *
2699 * Given an extended block this method will return the next extended block.
2700 *
2701 * NOTES:
2702 * The last ULONG of an extended block is the block index of the next
2703 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
2704 * depot.
2705 *
2706 * Return values:
2707 * - The index of the next extended block
2708 * - BLOCK_UNUSED: there is no next extended block.
2709 * - Any other return values denotes failure.
2710 */
2711ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
2712{
2713 ULONG nextBlockIndex = BLOCK_SPECIAL;
2714 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
2715 void* depotBuffer;
2716
2717 depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
2718
2719 if (depotBuffer!=0)
2720 {
2721 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
2722
2723 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2724 }
2725
2726 return nextBlockIndex;
2727}
2728
2729/******************************************************************************
2730 * Storage32Impl_SetNextBlockInChain
2731 *
2732 * This method will write the index of the specified block's next block
2733 * in the big block depot.
2734 *
2735 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
2736 * do the following
2737 *
2738 * Storage32Impl_SetNextBlockInChain(This, 3, 1);
2739 * Storage32Impl_SetNextBlockInChain(This, 1, 7);
2740 * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
2741 *
2742 */
2743void StorageImpl_SetNextBlockInChain(
2744 StorageImpl* This,
2745 ULONG blockIndex,
2746 ULONG nextBlock)
2747{
2748 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
2749 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
2750 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
2751 ULONG depotBlockIndexPos;
2752 void* depotBuffer;
2753
2754 assert(depotBlockCount < This->bigBlockDepotCount);
2755 assert(blockIndex != nextBlock);
2756
2757 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
2758 {
2759 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
2760 }
2761 else
2762 {
2763 /*
2764 * We have to look in the extended depot.
2765 */
2766 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
2767 }
2768
2769 depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
2770
2771 if (depotBuffer!=0)
2772 {
2773 StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
2774 StorageImpl_ReleaseBigBlock(This, depotBuffer);
2775 }
2776
2777 /*
2778 * Update the cached block depot, if necessary.
2779 */
2780 if (depotBlockCount == This->indexBlockDepotCached)
2781 {
2782 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
2783 }
2784}
2785
2786/******************************************************************************
2787 * Storage32Impl_LoadFileHeader
2788 *
2789 * This method will read in the file header, i.e. big block index -1.
2790 */
2791HRESULT StorageImpl_LoadFileHeader(
2792 StorageImpl* This)
2793{
2794 HRESULT hr = STG_E_FILENOTFOUND;
2795 void* headerBigBlock = NULL;
2796 int index;
2797
2798 /*
2799 * Get a pointer to the big block of data containing the header.
2800 */
2801 headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
2802
2803 /*
2804 * Extract the information from the header.
2805 */
2806 if (headerBigBlock!=0)
2807 {
2808 /*
2809 * Check for the "magic number" signature and return an error if it is not
2810 * found.
2811 */
2812 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2813 {
2814 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2815 return STG_E_OLDFORMAT;
2816 }
2817
2818 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2819 {
2820 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2821 return STG_E_INVALIDHEADER;
2822 }
2823
2824 StorageUtl_ReadWord(
2825 headerBigBlock,
2826 OFFSET_BIGBLOCKSIZEBITS,
2827 &This->bigBlockSizeBits);
2828
2829 StorageUtl_ReadWord(
2830 headerBigBlock,
2831 OFFSET_SMALLBLOCKSIZEBITS,
2832 &This->smallBlockSizeBits);
2833
2834 StorageUtl_ReadDWord(
2835 headerBigBlock,
2836 OFFSET_BBDEPOTCOUNT,
2837 &This->bigBlockDepotCount);
2838
2839 StorageUtl_ReadDWord(
2840 headerBigBlock,
2841 OFFSET_ROOTSTARTBLOCK,
2842 &This->rootStartBlock);
2843
2844 StorageUtl_ReadDWord(
2845 headerBigBlock,
2846 OFFSET_SBDEPOTSTART,
2847 &This->smallBlockDepotStart);
2848
2849 StorageUtl_ReadDWord(
2850 headerBigBlock,
2851 OFFSET_EXTBBDEPOTSTART,
2852 &This->extBigBlockDepotStart);
2853
2854 StorageUtl_ReadDWord(
2855 headerBigBlock,
2856 OFFSET_EXTBBDEPOTCOUNT,
2857 &This->extBigBlockDepotCount);
2858
2859 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2860 {
2861 StorageUtl_ReadDWord(
2862 headerBigBlock,
2863 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2864 &(This->bigBlockDepotStart[index]));
2865 }
2866
2867 /*
2868 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2869 */
2870 if ((1 << 2) == 4)
2871 {
2872 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2873 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2874 }
2875 else
2876 {
2877 This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
2878 This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
2879 }
2880
2881 /*
2882 * Right now, the code is making some assumptions about the size of the
2883 * blocks, just make sure they are what we're expecting.
2884 */
2885 assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) &&
2886 (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
2887
2888 /*
2889 * Release the block.
2890 */
2891 StorageImpl_ReleaseBigBlock(This, headerBigBlock);
2892
2893 hr = S_OK;
2894 }
2895
2896 return hr;
2897}
2898
2899/******************************************************************************
2900 * Storage32Impl_SaveFileHeader
2901 *
2902 * This method will save to the file the header, i.e. big block -1.
2903 */
2904void StorageImpl_SaveFileHeader(
2905 StorageImpl* This)
2906{
2907 BYTE headerBigBlock[BIG_BLOCK_SIZE];
2908 int index;
2909 BOOL success;
2910
2911 /*
2912 * Get a pointer to the big block of data containing the header.
2913 */
2914 success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
2915
2916 /*
2917 * If the block read failed, the file is probably new.
2918 */
2919 if (!success)
2920 {
2921 /*
2922 * Initialize for all unknown fields.
2923 */
2924 memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
2925
2926 /*
2927 * Initialize the magic number.
2928 */
2929 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
2930
2931 /*
2932 * And a bunch of things we don't know what they mean
2933 */
2934 StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b);
2935 StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3);
2936 StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2);
2937 StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
2938 StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
2939 }
2940
2941 /*
2942 * Write the information to the header.
2943 */
2944 if (headerBigBlock!=0)
2945 {
2946 StorageUtl_WriteWord(
2947 headerBigBlock,
2948 OFFSET_BIGBLOCKSIZEBITS,
2949 This->bigBlockSizeBits);
2950
2951 StorageUtl_WriteWord(
2952 headerBigBlock,
2953 OFFSET_SMALLBLOCKSIZEBITS,
2954 This->smallBlockSizeBits);
2955
2956 StorageUtl_WriteDWord(
2957 headerBigBlock,
2958 OFFSET_BBDEPOTCOUNT,
2959 This->bigBlockDepotCount);
2960
2961 StorageUtl_WriteDWord(
2962 headerBigBlock,
2963 OFFSET_ROOTSTARTBLOCK,
2964 This->rootStartBlock);
2965
2966 StorageUtl_WriteDWord(
2967 headerBigBlock,
2968 OFFSET_SBDEPOTSTART,
2969 This->smallBlockDepotStart);
2970
2971 StorageUtl_WriteDWord(
2972 headerBigBlock,
2973 OFFSET_EXTBBDEPOTSTART,
2974 This->extBigBlockDepotStart);
2975
2976 StorageUtl_WriteDWord(
2977 headerBigBlock,
2978 OFFSET_EXTBBDEPOTCOUNT,
2979 This->extBigBlockDepotCount);
2980
2981 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2982 {
2983 StorageUtl_WriteDWord(
2984 headerBigBlock,
2985 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2986 (This->bigBlockDepotStart[index]));
2987 }
2988 }
2989
2990 /*
2991 * Write the big block back to the file.
2992 */
2993 StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
2994}
2995
2996/******************************************************************************
2997 * Storage32Impl_ReadProperty
2998 *
2999 * This method will read the specified property from the property chain.
3000 */
3001BOOL StorageImpl_ReadProperty(
3002 StorageImpl* This,
3003 ULONG index,
3004 StgProperty* buffer)
3005{
3006 BYTE currentProperty[PROPSET_BLOCK_SIZE];
3007 ULARGE_INTEGER offsetInPropSet;
3008 BOOL readSuccessful;
3009 ULONG bytesRead;
3010
3011 offsetInPropSet.s.HighPart = 0;
3012 offsetInPropSet.s.LowPart = index * PROPSET_BLOCK_SIZE;
3013
3014 readSuccessful = BlockChainStream_ReadAt(
3015 This->rootBlockChain,
3016 offsetInPropSet,
3017 PROPSET_BLOCK_SIZE,
3018 currentProperty,
3019 &bytesRead);
3020
3021 if (readSuccessful)
3022 {
3023 memset(buffer->name, 0, sizeof(buffer->name));
3024 memcpy(
3025 buffer->name,
3026 currentProperty+OFFSET_PS_NAME,
3027 PROPERTY_NAME_BUFFER_LEN );
3028
3029 memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
3030
3031 StorageUtl_ReadWord(
3032 currentProperty,
3033 OFFSET_PS_NAMELENGTH,
3034 &buffer->sizeOfNameString);
3035
3036 StorageUtl_ReadDWord(
3037 currentProperty,
3038 OFFSET_PS_PREVIOUSPROP,
3039 &buffer->previousProperty);
3040
3041 StorageUtl_ReadDWord(
3042 currentProperty,
3043 OFFSET_PS_NEXTPROP,
3044 &buffer->nextProperty);
3045
3046 StorageUtl_ReadDWord(
3047 currentProperty,
3048 OFFSET_PS_DIRPROP,
3049 &buffer->dirProperty);
3050
3051 StorageUtl_ReadGUID(
3052 currentProperty,
3053 OFFSET_PS_GUID,
3054 &buffer->propertyUniqueID);
3055
3056 StorageUtl_ReadDWord(
3057 currentProperty,
3058 OFFSET_PS_TSS1,
3059 &buffer->timeStampS1);
3060
3061 StorageUtl_ReadDWord(
3062 currentProperty,
3063 OFFSET_PS_TSD1,
3064 &buffer->timeStampD1);
3065
3066 StorageUtl_ReadDWord(
3067 currentProperty,
3068 OFFSET_PS_TSS2,
3069 &buffer->timeStampS2);
3070
3071 StorageUtl_ReadDWord(
3072 currentProperty,
3073 OFFSET_PS_TSD2,
3074 &buffer->timeStampD2);
3075
3076 StorageUtl_ReadDWord(
3077 currentProperty,
3078 OFFSET_PS_STARTBLOCK,
3079 &buffer->startingBlock);
3080
3081 StorageUtl_ReadDWord(
3082 currentProperty,
3083 OFFSET_PS_SIZE,
3084 &buffer->size.s.LowPart);
3085
3086 buffer->size.s.HighPart = 0;
3087 }
3088
3089 return readSuccessful;
3090}
3091
3092/*********************************************************************
3093 * Write the specified property into the property chain
3094 */
3095BOOL StorageImpl_WriteProperty(
3096 StorageImpl* This,
3097 ULONG index,
3098 StgProperty* buffer)
3099{
3100 BYTE currentProperty[PROPSET_BLOCK_SIZE];
3101 ULARGE_INTEGER offsetInPropSet;
3102 BOOL writeSuccessful;
3103 ULONG bytesWritten;
3104
3105 offsetInPropSet.s.HighPart = 0;
3106 offsetInPropSet.s.LowPart = index * PROPSET_BLOCK_SIZE;
3107
3108 memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
3109
3110 memcpy(
3111 currentProperty + OFFSET_PS_NAME,
3112 buffer->name,
3113 PROPERTY_NAME_BUFFER_LEN );
3114
3115 memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
3116
3117 StorageUtl_WriteWord(
3118 currentProperty,
3119 OFFSET_PS_NAMELENGTH,
3120 buffer->sizeOfNameString);
3121
3122 StorageUtl_WriteDWord(
3123 currentProperty,
3124 OFFSET_PS_PREVIOUSPROP,
3125 buffer->previousProperty);
3126
3127 StorageUtl_WriteDWord(
3128 currentProperty,
3129 OFFSET_PS_NEXTPROP,
3130 buffer->nextProperty);
3131
3132 StorageUtl_WriteDWord(
3133 currentProperty,
3134 OFFSET_PS_DIRPROP,
3135 buffer->dirProperty);
3136
3137 StorageUtl_WriteGUID(
3138 currentProperty,
3139 OFFSET_PS_GUID,
3140 &buffer->propertyUniqueID);
3141
3142 StorageUtl_WriteDWord(
3143 currentProperty,
3144 OFFSET_PS_TSS1,
3145 buffer->timeStampS1);
3146
3147 StorageUtl_WriteDWord(
3148 currentProperty,
3149 OFFSET_PS_TSD1,
3150 buffer->timeStampD1);
3151
3152 StorageUtl_WriteDWord(
3153 currentProperty,
3154 OFFSET_PS_TSS2,
3155 buffer->timeStampS2);
3156
3157 StorageUtl_WriteDWord(
3158 currentProperty,
3159 OFFSET_PS_TSD2,
3160 buffer->timeStampD2);
3161
3162 StorageUtl_WriteDWord(
3163 currentProperty,
3164 OFFSET_PS_STARTBLOCK,
3165 buffer->startingBlock);
3166
3167 StorageUtl_WriteDWord(
3168 currentProperty,
3169 OFFSET_PS_SIZE,
3170 buffer->size.s.LowPart);
3171
3172 writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain,
3173 offsetInPropSet,
3174 PROPSET_BLOCK_SIZE,
3175 currentProperty,
3176 &bytesWritten);
3177 return writeSuccessful;
3178}
3179
3180BOOL StorageImpl_ReadBigBlock(
3181 StorageImpl* This,
3182 ULONG blockIndex,
3183 void* buffer)
3184{
3185 void* bigBlockBuffer;
3186
3187 bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
3188
3189 if (bigBlockBuffer!=0)
3190 {
3191 memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
3192
3193 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3194
3195 return TRUE;
3196 }
3197
3198 return FALSE;
3199}
3200
3201BOOL StorageImpl_WriteBigBlock(
3202 StorageImpl* This,
3203 ULONG blockIndex,
3204 void* buffer)
3205{
3206 void* bigBlockBuffer;
3207
3208 bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
3209
3210 if (bigBlockBuffer!=0)
3211 {
3212 memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
3213
3214 StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
3215
3216 return TRUE;
3217 }
3218
3219 return FALSE;
3220}
3221
3222void* StorageImpl_GetROBigBlock(
3223 StorageImpl* This,
3224 ULONG blockIndex)
3225{
3226 return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
3227}
3228
3229void* StorageImpl_GetBigBlock(
3230 StorageImpl* This,
3231 ULONG blockIndex)
3232{
3233 return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
3234}
3235
3236void StorageImpl_ReleaseBigBlock(
3237 StorageImpl* This,
3238 void* pBigBlock)
3239{
3240 BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
3241}
3242
3243/******************************************************************************
3244 * Storage32Impl_SmallBlocksToBigBlocks
3245 *
3246 * This method will convert a small block chain to a big block chain.
3247 * The small block chain will be destroyed.
3248 */
3249BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
3250 StorageImpl* This,
3251 SmallBlockChainStream** ppsbChain)
3252{
3253 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3254 ULARGE_INTEGER size, offset;
3255 ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
3256 ULONG propertyIndex;
3257 BOOL successRead, successWrite;
3258 StgProperty chainProperty;
3259 BYTE *buffer;
3260 BlockChainStream *bbTempChain = NULL;
3261 BlockChainStream *bigBlockChain = NULL;
3262
3263 /*
3264 * Create a temporary big block chain that doesn't have
3265 * an associated property. This temporary chain will be
3266 * used to copy data from small blocks to big blocks.
3267 */
3268 bbTempChain = BlockChainStream_Construct(This,
3269 &bbHeadOfChain,
3270 PROPERTY_NULL);
3271
3272 /*
3273 * Grow the big block chain.
3274 */
3275 size = SmallBlockChainStream_GetSize(*ppsbChain);
3276 BlockChainStream_SetSize(bbTempChain, size);
3277
3278 /*
3279 * Copy the contents of the small block chain to the big block chain
3280 * by small block size increments.
3281 */
3282 offset.s.LowPart = 0;
3283 offset.s.HighPart = 0;
3284 cbTotalRead = 0;
3285 cbTotalWritten = 0;
3286
3287 buffer = (BYTE *) HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE);
3288 do
3289 {
3290 successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3291 offset,
3292 DEF_SMALL_BLOCK_SIZE,
3293 buffer,
3294 &cbRead);
3295 cbTotalRead += cbRead;
3296
3297 successWrite = BlockChainStream_WriteAt(bbTempChain,
3298 offset,
3299 cbRead,
3300 buffer,
3301 &cbWritten);
3302 cbTotalWritten += cbWritten;
3303
3304 offset.s.LowPart += This->smallBlockSize;
3305
3306 } while (successRead && successWrite);
3307 HeapFree(GetProcessHeap(),0,buffer);
3308
3309 assert(cbTotalRead == cbTotalWritten);
3310
3311 /*
3312 * Destroy the small block chain.
3313 */
3314 propertyIndex = (*ppsbChain)->ownerPropertyIndex;
3315 size.s.HighPart = 0;
3316 size.s.LowPart = 0;
3317 SmallBlockChainStream_SetSize(*ppsbChain, size);
3318 SmallBlockChainStream_Destroy(*ppsbChain);
3319 *ppsbChain = 0;
3320
3321 /*
3322 * Change the property information. This chain is now a big block chain
3323 * and it doesn't reside in the small blocks chain anymore.
3324 */
3325 StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
3326
3327 chainProperty.startingBlock = bbHeadOfChain;
3328
3329 StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
3330
3331 /*
3332 * Destroy the temporary propertyless big block chain.
3333 * Create a new big block chain associated with this property.
3334 */
3335 BlockChainStream_Destroy(bbTempChain);
3336 bigBlockChain = BlockChainStream_Construct(This,
3337 NULL,
3338 propertyIndex);
3339
3340 return bigBlockChain;
3341}
3342
3343/******************************************************************************
3344** Storage32InternalImpl implementation
3345*/
3346
3347StorageInternalImpl* StorageInternalImpl_Construct(
3348 StorageImpl* ancestorStorage,
3349 ULONG rootPropertyIndex)
3350{
3351 StorageInternalImpl* newStorage;
3352
3353 /*
3354 * Allocate space for the new storage object
3355 */
3356 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
3357
3358 if (newStorage!=0)
3359 {
3360 memset(newStorage, 0, sizeof(StorageInternalImpl));
3361
3362 /*
3363 * Initialize the virtual function table.
3364 */
3365 ICOM_VTBL(newStorage) = &Storage32InternalImpl_Vtbl;
3366 newStorage->v_destructor = &StorageInternalImpl_Destroy;
3367
3368 /*
3369 * Keep the ancestor storage pointer and nail a reference to it.
3370 */
3371 newStorage->ancestorStorage = ancestorStorage;
3372 StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
3373
3374 /*
3375 * Keep the index of the root property set for this storage,
3376 */
3377 newStorage->rootPropertySetIndex = rootPropertyIndex;
3378
3379 return newStorage;
3380 }
3381
3382 return 0;
3383}
3384
3385void StorageInternalImpl_Destroy(
3386 StorageInternalImpl* This)
3387{
3388 StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
3389 HeapFree(GetProcessHeap(), 0, This);
3390}
3391
3392/******************************************************************************
3393**
3394** Storage32InternalImpl_Commit
3395**
3396** The non-root storages cannot be opened in transacted mode thus this function
3397** does nothing.
3398*/
3399HRESULT WINAPI StorageInternalImpl_Commit(
3400 IStorage* iface,
3401 DWORD grfCommitFlags) /* [in] */
3402{
3403 return S_OK;
3404}
3405
3406/******************************************************************************
3407**
3408** Storage32InternalImpl_Revert
3409**
3410** The non-root storages cannot be opened in transacted mode thus this function
3411** does nothing.
3412*/
3413HRESULT WINAPI StorageInternalImpl_Revert(
3414 IStorage* iface)
3415{
3416 return S_OK;
3417}
3418
3419/******************************************************************************
3420** IEnumSTATSTGImpl implementation
3421*/
3422
3423IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
3424 StorageImpl* parentStorage,
3425 ULONG firstPropertyNode)
3426{
3427 IEnumSTATSTGImpl* newEnumeration;
3428
3429 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
3430
3431 if (newEnumeration!=0)
3432 {
3433 /*
3434 * Set-up the virtual function table and reference count.
3435 */
3436 ICOM_VTBL(newEnumeration) = &IEnumSTATSTGImpl_Vtbl;
3437 newEnumeration->ref = 0;
3438
3439 /*
3440 * We want to nail-down the reference to the storage in case the
3441 * enumeration out-lives the storage in the client application.
3442 */
3443 newEnumeration->parentStorage = parentStorage;
3444 IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
3445
3446 newEnumeration->firstPropertyNode = firstPropertyNode;
3447
3448 /*
3449 * Initialize the search stack
3450 */
3451 newEnumeration->stackSize = 0;
3452 newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
3453 newEnumeration->stackToVisit =
3454 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
3455
3456 /*
3457 * Make sure the current node of the iterator is the first one.
3458 */
3459 IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
3460 }
3461
3462 return newEnumeration;
3463}
3464
3465void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
3466{
3467 IStorage_Release((IStorage*)This->parentStorage);
3468 HeapFree(GetProcessHeap(), 0, This->stackToVisit);
3469 HeapFree(GetProcessHeap(), 0, This);
3470}
3471
3472HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
3473 IEnumSTATSTG* iface,
3474 REFIID riid,
3475 void** ppvObject)
3476{
3477 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3478
3479 /*
3480 * Perform a sanity check on the parameters.
3481 */
3482 if (ppvObject==0)
3483 return E_INVALIDARG;
3484
3485 /*
3486 * Initialize the return parameter.
3487 */
3488 *ppvObject = 0;
3489
3490 /*
3491 * Compare the riid with the interface IDs implemented by this object.
3492 */
3493 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
3494 {
3495 *ppvObject = (IEnumSTATSTG*)This;
3496 }
3497 else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0)
3498 {
3499 *ppvObject = (IEnumSTATSTG*)This;
3500 }
3501
3502 /*
3503 * Check that we obtained an interface.
3504 */
3505 if ((*ppvObject)==0)
3506 return E_NOINTERFACE;
3507
3508 /*
3509 * Query Interface always increases the reference count by one when it is
3510 * successful
3511 */
3512 IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
3513
3514 return S_OK;
3515}
3516
3517ULONG WINAPI IEnumSTATSTGImpl_AddRef(
3518 IEnumSTATSTG* iface)
3519{
3520 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3521
3522 This->ref++;
3523 return This->ref;
3524}
3525
3526ULONG WINAPI IEnumSTATSTGImpl_Release(
3527 IEnumSTATSTG* iface)
3528{
3529 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3530
3531 ULONG newRef;
3532
3533 This->ref--;
3534 newRef = This->ref;
3535
3536 /*
3537 * If the reference count goes down to 0, perform suicide.
3538 */
3539 if (newRef==0)
3540 {
3541 IEnumSTATSTGImpl_Destroy(This);
3542 }
3543
3544 return newRef;;
3545}
3546
3547HRESULT WINAPI IEnumSTATSTGImpl_Next(
3548 IEnumSTATSTG* iface,
3549 ULONG celt,
3550 STATSTG* rgelt,
3551 ULONG* pceltFetched)
3552{
3553 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3554
3555 StgProperty currentProperty;
3556 STATSTG* currentReturnStruct = rgelt;
3557 ULONG objectFetched = 0;
3558 ULONG currentSearchNode;
3559
3560 /*
3561 * Perform a sanity check on the parameters.
3562 */
3563 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
3564 return E_INVALIDARG;
3565
3566 /*
3567 * To avoid the special case, get another pointer to a ULONG value if
3568 * the caller didn't supply one.
3569 */
3570 if (pceltFetched==0)
3571 pceltFetched = &objectFetched;
3572
3573 /*
3574 * Start the iteration, we will iterate until we hit the end of the
3575 * linked list or until we hit the number of items to iterate through
3576 */
3577 *pceltFetched = 0;
3578
3579 /*
3580 * Start with the node at the top of the stack.
3581 */
3582 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3583
3584 while ( ( *pceltFetched < celt) &&
3585 ( currentSearchNode!=PROPERTY_NULL) )
3586 {
3587 /*
3588 * Remove the top node from the stack
3589 */
3590 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3591
3592 /*
3593 * Read the property from the storage.
3594 */
3595 StorageImpl_ReadProperty(This->parentStorage,
3596 currentSearchNode,
3597 &currentProperty);
3598
3599 /*
3600 * Copy the information to the return buffer.
3601 */
3602 StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
3603 &currentProperty,
3604 STATFLAG_DEFAULT);
3605
3606 /*
3607 * Step to the next item in the iteration
3608 */
3609 (*pceltFetched)++;
3610 currentReturnStruct++;
3611
3612 /*
3613 * Push the next search node in the search stack.
3614 */
3615 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3616
3617 /*
3618 * continue the iteration.
3619 */
3620 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3621 }
3622
3623 if (*pceltFetched == celt)
3624 return S_OK;
3625
3626 return S_FALSE;
3627}
3628
3629
3630HRESULT WINAPI IEnumSTATSTGImpl_Skip(
3631 IEnumSTATSTG* iface,
3632 ULONG celt)
3633{
3634 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3635
3636 StgProperty currentProperty;
3637 ULONG objectFetched = 0;
3638 ULONG currentSearchNode;
3639
3640 /*
3641 * Start with the node at the top of the stack.
3642 */
3643 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3644
3645 while ( (objectFetched < celt) &&
3646 (currentSearchNode!=PROPERTY_NULL) )
3647 {
3648 /*
3649 * Remove the top node from the stack
3650 */
3651 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3652
3653 /*
3654 * Read the property from the storage.
3655 */
3656 StorageImpl_ReadProperty(This->parentStorage,
3657 currentSearchNode,
3658 &currentProperty);
3659
3660 /*
3661 * Step to the next item in the iteration
3662 */
3663 objectFetched++;
3664
3665 /*
3666 * Push the next search node in the search stack.
3667 */
3668 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
3669
3670 /*
3671 * continue the iteration.
3672 */
3673 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3674 }
3675
3676 if (objectFetched == celt)
3677 return S_OK;
3678
3679 return S_FALSE;
3680}
3681
3682HRESULT WINAPI IEnumSTATSTGImpl_Reset(
3683 IEnumSTATSTG* iface)
3684{
3685 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3686
3687 StgProperty rootProperty;
3688 BOOL readSuccessful;
3689
3690 /*
3691 * Re-initialize the search stack to an empty stack
3692 */
3693 This->stackSize = 0;
3694
3695 /*
3696 * Read the root property from the storage.
3697 */
3698 readSuccessful = StorageImpl_ReadProperty(
3699 This->parentStorage,
3700 This->firstPropertyNode,
3701 &rootProperty);
3702
3703 if (readSuccessful)
3704 {
3705 assert(rootProperty.sizeOfNameString!=0);
3706
3707 /*
3708 * Push the search node in the search stack.
3709 */
3710 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
3711 }
3712
3713 return S_OK;
3714}
3715
3716HRESULT WINAPI IEnumSTATSTGImpl_Clone(
3717 IEnumSTATSTG* iface,
3718 IEnumSTATSTG** ppenum)
3719{
3720 IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
3721
3722 IEnumSTATSTGImpl* newClone;
3723
3724 /*
3725 * Perform a sanity check on the parameters.
3726 */
3727 if (ppenum==0)
3728 return E_INVALIDARG;
3729
3730 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
3731 This->firstPropertyNode);
3732
3733
3734 /*
3735 * The new clone enumeration must point to the same current node as
3736 * the ole one.
3737 */
3738 newClone->stackSize = This->stackSize ;
3739 newClone->stackMaxSize = This->stackMaxSize ;
3740 newClone->stackToVisit =
3741 HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
3742
3743 memcpy(
3744 newClone->stackToVisit,
3745 This->stackToVisit,
3746 sizeof(ULONG) * newClone->stackSize);
3747
3748 *ppenum = (IEnumSTATSTG*)newClone;
3749
3750 /*
3751 * Don't forget to nail down a reference to the clone before
3752 * returning it.
3753 */
3754 IEnumSTATSTGImpl_AddRef(*ppenum);
3755
3756 return S_OK;
3757}
3758
3759INT IEnumSTATSTGImpl_FindParentProperty(
3760 IEnumSTATSTGImpl *This,
3761 ULONG childProperty,
3762 StgProperty *currentProperty,
3763 ULONG *thisNodeId)
3764{
3765 ULONG currentSearchNode;
3766 ULONG foundNode;
3767
3768 /*
3769 * To avoid the special case, get another pointer to a ULONG value if
3770 * the caller didn't supply one.
3771 */
3772 if (thisNodeId==0)
3773 thisNodeId = &foundNode;
3774
3775 /*
3776 * Start with the node at the top of the stack.
3777 */
3778 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3779
3780
3781 while (currentSearchNode!=PROPERTY_NULL)
3782 {
3783 /*
3784 * Store the current node in the returned parameters
3785 */
3786 *thisNodeId = currentSearchNode;
3787
3788 /*
3789 * Remove the top node from the stack
3790 */
3791 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3792
3793 /*
3794 * Read the property from the storage.
3795 */
3796 StorageImpl_ReadProperty(
3797 This->parentStorage,
3798 currentSearchNode,
3799 currentProperty);
3800
3801 if (currentProperty->previousProperty == childProperty)
3802 return PROPERTY_RELATION_PREVIOUS;
3803
3804 else if (currentProperty->nextProperty == childProperty)
3805 return PROPERTY_RELATION_NEXT;
3806
3807 else if (currentProperty->dirProperty == childProperty)
3808 return PROPERTY_RELATION_DIR;
3809
3810 /*
3811 * Push the next search node in the search stack.
3812 */
3813 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3814
3815 /*
3816 * continue the iteration.
3817 */
3818 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3819 }
3820
3821 return PROPERTY_NULL;
3822}
3823
3824ULONG IEnumSTATSTGImpl_FindProperty(
3825 IEnumSTATSTGImpl* This,
3826 const OLECHAR* lpszPropName,
3827 StgProperty* currentProperty)
3828{
3829 ULONG currentSearchNode;
3830
3831 /*
3832 * Start with the node at the top of the stack.
3833 */
3834 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3835
3836 while (currentSearchNode!=PROPERTY_NULL)
3837 {
3838 /*
3839 * Remove the top node from the stack
3840 */
3841 IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
3842
3843 /*
3844 * Read the property from the storage.
3845 */
3846 StorageImpl_ReadProperty(This->parentStorage,
3847 currentSearchNode,
3848 currentProperty);
3849
3850 if ( propertyNameCmp(
3851 (OLECHAR*)currentProperty->name,
3852 (OLECHAR*)lpszPropName) == 0)
3853 return currentSearchNode;
3854
3855 /*
3856 * Push the next search node in the search stack.
3857 */
3858 IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
3859
3860 /*
3861 * continue the iteration.
3862 */
3863 currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
3864 }
3865
3866 return PROPERTY_NULL;
3867}
3868
3869void IEnumSTATSTGImpl_PushSearchNode(
3870 IEnumSTATSTGImpl* This,
3871 ULONG nodeToPush)
3872{
3873 StgProperty rootProperty;
3874 BOOL readSuccessful;
3875
3876 /*
3877 * First, make sure we're not trying to push an unexisting node.
3878 */
3879 if (nodeToPush==PROPERTY_NULL)
3880 return;
3881
3882 /*
3883 * First push the node to the stack
3884 */
3885 if (This->stackSize == This->stackMaxSize)
3886 {
3887 This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
3888
3889 This->stackToVisit = HeapReAlloc(
3890 GetProcessHeap(),
3891 0,
3892 This->stackToVisit,
3893 sizeof(ULONG) * This->stackMaxSize);
3894 }
3895
3896 This->stackToVisit[This->stackSize] = nodeToPush;
3897 This->stackSize++;
3898
3899 /*
3900 * Read the root property from the storage.
3901 */
3902 readSuccessful = StorageImpl_ReadProperty(
3903 This->parentStorage,
3904 nodeToPush,
3905 &rootProperty);
3906
3907 if (readSuccessful)
3908 {
3909 assert(rootProperty.sizeOfNameString!=0);
3910
3911 /*
3912 * Push the previous search node in the search stack.
3913 */
3914 IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
3915 }
3916}
3917
3918ULONG IEnumSTATSTGImpl_PopSearchNode(
3919 IEnumSTATSTGImpl* This,
3920 BOOL remove)
3921{
3922 ULONG topNode;
3923
3924 if (This->stackSize == 0)
3925 return PROPERTY_NULL;
3926
3927 topNode = This->stackToVisit[This->stackSize-1];
3928
3929 if (remove)
3930 This->stackSize--;
3931
3932 return topNode;
3933}
3934
3935/******************************************************************************
3936** StorageUtl implementation
3937*/
3938
3939void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
3940{
3941 memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
3942}
3943
3944void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
3945{
3946 memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
3947}
3948
3949void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
3950{
3951 memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
3952}
3953
3954void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
3955{
3956 memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
3957}
3958
3959void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
3960{
3961 StorageUtl_ReadDWord(buffer, offset, &(value->Data1));
3962 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
3963 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
3964
3965 memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
3966}
3967
3968void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
3969{
3970 StorageUtl_WriteDWord(buffer, offset, value->Data1);
3971 StorageUtl_WriteWord(buffer, offset+4, value->Data2);
3972 StorageUtl_WriteWord(buffer, offset+6, value->Data3);
3973
3974 memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
3975}
3976
3977void StorageUtl_CopyPropertyToSTATSTG(
3978 STATSTG* destination,
3979 StgProperty* source,
3980 int statFlags)
3981{
3982 /*
3983 * The copy of the string occurs only when the flag is not set
3984 */
3985 if ((statFlags & STATFLAG_NONAME) != 0)
3986 {
3987 destination->pwcsName = 0;
3988 }
3989 else
3990 {
3991 destination->pwcsName =
3992 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
3993
3994 strcpyW((LPWSTR)destination->pwcsName, source->name);
3995 }
3996
3997 switch (source->propertyType)
3998 {
3999 case PROPTYPE_STORAGE:
4000 case PROPTYPE_ROOT:
4001 destination->type = STGTY_STORAGE;
4002 break;
4003 case PROPTYPE_STREAM:
4004 destination->type = STGTY_STREAM;
4005 break;
4006 default:
4007 destination->type = STGTY_STREAM;
4008 break;
4009 }
4010
4011 destination->cbSize = source->size;
4012/*
4013 currentReturnStruct->mtime = {0}; TODO
4014 currentReturnStruct->ctime = {0};
4015 currentReturnStruct->atime = {0};
4016*/
4017 destination->grfMode = 0;
4018 destination->grfLocksSupported = 0;
4019 destination->clsid = source->propertyUniqueID;
4020 destination->grfStateBits = 0;
4021 destination->reserved = 0;
4022}
4023
4024/******************************************************************************
4025** BlockChainStream implementation
4026*/
4027
4028BlockChainStream* BlockChainStream_Construct(
4029 StorageImpl* parentStorage,
4030 ULONG* headOfStreamPlaceHolder,
4031 ULONG propertyIndex)
4032{
4033 BlockChainStream* newStream;
4034 ULONG blockIndex;
4035
4036 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
4037
4038 newStream->parentStorage = parentStorage;
4039 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
4040 newStream->ownerPropertyIndex = propertyIndex;
4041 newStream->lastBlockNoInSequence = 0xFFFFFFFF;
4042 newStream->tailIndex = BLOCK_END_OF_CHAIN;
4043 newStream->numBlocks = 0;
4044
4045 blockIndex = BlockChainStream_GetHeadOfChain(newStream);
4046
4047 while (blockIndex != BLOCK_END_OF_CHAIN)
4048 {
4049 newStream->numBlocks++;
4050 newStream->tailIndex = blockIndex;
4051
4052 blockIndex = StorageImpl_GetNextBlockInChain(
4053 parentStorage,
4054 blockIndex);
4055 }
4056
4057 return newStream;
4058}
4059
4060void BlockChainStream_Destroy(BlockChainStream* This)
4061{
4062 HeapFree(GetProcessHeap(), 0, This);
4063}
4064
4065/******************************************************************************
4066 * BlockChainStream_GetHeadOfChain
4067 *
4068 * Returns the head of this stream chain.
4069 * Some special chains don't have properties, their heads are kept in
4070 * This->headOfStreamPlaceHolder.
4071 *
4072 */
4073ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
4074{
4075 StgProperty chainProperty;
4076 BOOL readSuccessful;
4077
4078 if (This->headOfStreamPlaceHolder != 0)
4079 return *(This->headOfStreamPlaceHolder);
4080
4081 if (This->ownerPropertyIndex != PROPERTY_NULL)
4082 {
4083 readSuccessful = StorageImpl_ReadProperty(
4084 This->parentStorage,
4085 This->ownerPropertyIndex,
4086 &chainProperty);
4087
4088 if (readSuccessful)
4089 {
4090 return chainProperty.startingBlock;
4091 }
4092 }
4093
4094 return BLOCK_END_OF_CHAIN;
4095}
4096
4097/******************************************************************************
4098 * BlockChainStream_GetCount
4099 *
4100 * Returns the number of blocks that comprises this chain.
4101 * This is not the size of the stream as the last block may not be full!
4102 *
4103 */
4104ULONG BlockChainStream_GetCount(BlockChainStream* This)
4105{
4106 ULONG blockIndex;
4107 ULONG count = 0;
4108
4109 blockIndex = BlockChainStream_GetHeadOfChain(This);
4110
4111 while (blockIndex != BLOCK_END_OF_CHAIN)
4112 {
4113 count++;
4114
4115 blockIndex = StorageImpl_GetNextBlockInChain(
4116 This->parentStorage,
4117 blockIndex);
4118 }
4119
4120 return count;
4121}
4122
4123/******************************************************************************
4124 * BlockChainStream_ReadAt
4125 *
4126 * Reads a specified number of bytes from this chain at the specified offset.
4127 * bytesRead may be NULL.
4128 * Failure will be returned if the specified number of bytes has not been read.
4129 */
4130BOOL BlockChainStream_ReadAt(BlockChainStream* This,
4131 ULARGE_INTEGER offset,
4132 ULONG size,
4133 void* buffer,
4134 ULONG* bytesRead)
4135{
4136 ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
4137 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->bigBlockSize;
4138 ULONG bytesToReadInBuffer;
4139 ULONG blockIndex;
4140 BYTE* bufferWalker;
4141 BYTE* bigBlockBuffer;
4142
4143 /*
4144 * Find the first block in the stream that contains part of the buffer.
4145 */
4146 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4147 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4148 (blockNoInSequence < This->lastBlockNoInSequence) )
4149 {
4150 blockIndex = BlockChainStream_GetHeadOfChain(This);
4151 This->lastBlockNoInSequence = blockNoInSequence;
4152 }
4153 else
4154 {
4155 ULONG temp = blockNoInSequence;
4156
4157 blockIndex = This->lastBlockNoInSequenceIndex;
4158 blockNoInSequence -= This->lastBlockNoInSequence;
4159 This->lastBlockNoInSequence = temp;
4160 }
4161
4162 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4163 {
4164 blockIndex =
4165 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4166
4167 blockNoInSequence--;
4168 }
4169
4170 This->lastBlockNoInSequenceIndex = blockIndex;
4171
4172 /*
4173 * Start reading the buffer.
4174 */
4175 *bytesRead = 0;
4176 bufferWalker = buffer;
4177
4178 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4179 {
4180 /*
4181 * Calculate how many bytes we can copy from this big block.
4182 */
4183 bytesToReadInBuffer =
4184 min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4185
4186 /*
4187 * Copy those bytes to the buffer
4188 */
4189 bigBlockBuffer =
4190 StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
4191
4192 memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
4193
4194 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4195
4196 /*
4197 * Step to the next big block.
4198 */
4199 blockIndex =
4200 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4201
4202 bufferWalker += bytesToReadInBuffer;
4203 size -= bytesToReadInBuffer;
4204 *bytesRead += bytesToReadInBuffer;
4205 offsetInBlock = 0; /* There is no offset on the next block */
4206
4207 }
4208
4209 return (size == 0);
4210}
4211
4212/******************************************************************************
4213 * BlockChainStream_WriteAt
4214 *
4215 * Writes the specified number of bytes to this chain at the specified offset.
4216 * bytesWritten may be NULL.
4217 * Will fail if not all specified number of bytes have been written.
4218 */
4219BOOL BlockChainStream_WriteAt(BlockChainStream* This,
4220 ULARGE_INTEGER offset,
4221 ULONG size,
4222 const void* buffer,
4223 ULONG* bytesWritten)
4224{
4225 ULONG blockNoInSequence = offset.s.LowPart / This->parentStorage->bigBlockSize;
4226 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->bigBlockSize;
4227 ULONG bytesToWrite;
4228 ULONG blockIndex;
4229 BYTE* bufferWalker;
4230 BYTE* bigBlockBuffer;
4231
4232 /*
4233 * Find the first block in the stream that contains part of the buffer.
4234 */
4235 if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
4236 (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
4237 (blockNoInSequence < This->lastBlockNoInSequence) )
4238 {
4239 blockIndex = BlockChainStream_GetHeadOfChain(This);
4240 This->lastBlockNoInSequence = blockNoInSequence;
4241 }
4242 else
4243 {
4244 ULONG temp = blockNoInSequence;
4245
4246 blockIndex = This->lastBlockNoInSequenceIndex;
4247 blockNoInSequence -= This->lastBlockNoInSequence;
4248 This->lastBlockNoInSequence = temp;
4249 }
4250
4251 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4252 {
4253 blockIndex =
4254 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4255
4256 blockNoInSequence--;
4257 }
4258
4259 This->lastBlockNoInSequenceIndex = blockIndex;
4260
4261 /*
4262 * Here, I'm casting away the constness on the buffer variable
4263 * This is OK since we don't intend to modify that buffer.
4264 */
4265 *bytesWritten = 0;
4266 bufferWalker = (BYTE*)buffer;
4267
4268 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4269 {
4270 /*
4271 * Calculate how many bytes we can copy from this big block.
4272 */
4273 bytesToWrite =
4274 min(This->parentStorage->bigBlockSize - offsetInBlock, size);
4275
4276 /*
4277 * Copy those bytes to the buffer
4278 */
4279 bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
4280
4281 memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
4282
4283 StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
4284
4285 /*
4286 * Step to the next big block.
4287 */
4288 blockIndex =
4289 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4290
4291 bufferWalker += bytesToWrite;
4292 size -= bytesToWrite;
4293 *bytesWritten += bytesToWrite;
4294 offsetInBlock = 0; /* There is no offset on the next block */
4295 }
4296
4297 return (size == 0);
4298}
4299
4300/******************************************************************************
4301 * BlockChainStream_Shrink
4302 *
4303 * Shrinks this chain in the big block depot.
4304 */
4305BOOL BlockChainStream_Shrink(BlockChainStream* This,
4306 ULARGE_INTEGER newSize)
4307{
4308 ULONG blockIndex, extraBlock;
4309 ULONG numBlocks;
4310 ULONG count = 1;
4311
4312 /*
4313 * Reset the last accessed block cache.
4314 */
4315 This->lastBlockNoInSequence = 0xFFFFFFFF;
4316 This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
4317
4318 /*
4319 * Figure out how many blocks are needed to contain the new size
4320 */
4321 numBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
4322
4323 if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
4324 numBlocks++;
4325
4326 blockIndex = BlockChainStream_GetHeadOfChain(This);
4327
4328 /*
4329 * Go to the new end of chain
4330 */
4331 while (count < numBlocks)
4332 {
4333 blockIndex =
4334 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4335
4336 count++;
4337 }
4338
4339 /* Get the next block before marking the new end */
4340 extraBlock =
4341 StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
4342
4343 /* Mark the new end of chain */
4344 StorageImpl_SetNextBlockInChain(
4345 This->parentStorage,
4346 blockIndex,
4347 BLOCK_END_OF_CHAIN);
4348
4349 This->tailIndex = blockIndex;
4350 This->numBlocks = numBlocks;
4351
4352 /*
4353 * Mark the extra blocks as free
4354 */
4355 while (extraBlock != BLOCK_END_OF_CHAIN)
4356 {
4357 blockIndex =
4358 StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
4359
4360 StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
4361 extraBlock = blockIndex;
4362 }
4363
4364 return TRUE;
4365}
4366
4367/******************************************************************************
4368 * BlockChainStream_Enlarge
4369 *
4370 * Grows this chain in the big block depot.
4371 */
4372BOOL BlockChainStream_Enlarge(BlockChainStream* This,
4373 ULARGE_INTEGER newSize)
4374{
4375 ULONG blockIndex, currentBlock;
4376 ULONG newNumBlocks;
4377 ULONG oldNumBlocks = 0;
4378
4379 blockIndex = BlockChainStream_GetHeadOfChain(This);
4380
4381 /*
4382 * Empty chain. Create the head.
4383 */
4384 if (blockIndex == BLOCK_END_OF_CHAIN)
4385 {
4386 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4387 StorageImpl_SetNextBlockInChain(This->parentStorage,
4388 blockIndex,
4389 BLOCK_END_OF_CHAIN);
4390
4391 if (This->headOfStreamPlaceHolder != 0)
4392 {
4393 *(This->headOfStreamPlaceHolder) = blockIndex;
4394 }
4395 else
4396 {
4397 StgProperty chainProp;
4398 assert(This->ownerPropertyIndex != PROPERTY_NULL);
4399
4400 StorageImpl_ReadProperty(
4401 This->parentStorage,
4402 This->ownerPropertyIndex,
4403 &chainProp);
4404
4405 chainProp.startingBlock = blockIndex;
4406
4407 StorageImpl_WriteProperty(
4408 This->parentStorage,
4409 This->ownerPropertyIndex,
4410 &chainProp);
4411 }
4412
4413 This->tailIndex = blockIndex;
4414 This->numBlocks = 1;
4415 }
4416
4417 /*
4418 * Figure out how many blocks are needed to contain this stream
4419 */
4420 newNumBlocks = newSize.s.LowPart / This->parentStorage->bigBlockSize;
4421
4422 if ((newSize.s.LowPart % This->parentStorage->bigBlockSize) != 0)
4423 newNumBlocks++;
4424
4425 /*
4426 * Go to the current end of chain
4427 */
4428 if (This->tailIndex == BLOCK_END_OF_CHAIN)
4429 {
4430 currentBlock = blockIndex;
4431
4432 while (blockIndex != BLOCK_END_OF_CHAIN)
4433 {
4434 This->numBlocks++;
4435 currentBlock = blockIndex;
4436
4437 blockIndex =
4438 StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
4439 }
4440
4441 This->tailIndex = currentBlock;
4442 }
4443
4444 currentBlock = This->tailIndex;
4445 oldNumBlocks = This->numBlocks;
4446
4447 /*
4448 * Add new blocks to the chain
4449 */
4450 if (oldNumBlocks < newNumBlocks)
4451 {
4452 while (oldNumBlocks < newNumBlocks)
4453 {
4454 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4455
4456 StorageImpl_SetNextBlockInChain(
4457 This->parentStorage,
4458 currentBlock,
4459 blockIndex);
4460
4461 StorageImpl_SetNextBlockInChain(
4462 This->parentStorage,
4463 blockIndex,
4464 BLOCK_END_OF_CHAIN);
4465
4466 currentBlock = blockIndex;
4467 oldNumBlocks++;
4468 }
4469
4470 This->tailIndex = blockIndex;
4471 This->numBlocks = newNumBlocks;
4472 }
4473
4474 return TRUE;
4475}
4476
4477/******************************************************************************
4478 * BlockChainStream_SetSize
4479 *
4480 * Sets the size of this stream. The big block depot will be updated.
4481 * The file will grow if we grow the chain.
4482 *
4483 * TODO: Free the actual blocks in the file when we shrink the chain.
4484 * Currently, the blocks are still in the file. So the file size
4485 * doesn't shrink even if we shrink streams.
4486 */
4487BOOL BlockChainStream_SetSize(
4488 BlockChainStream* This,
4489 ULARGE_INTEGER newSize)
4490{
4491 ULARGE_INTEGER size = BlockChainStream_GetSize(This);
4492
4493 if (newSize.s.LowPart == size.s.LowPart)
4494 return TRUE;
4495
4496 if (newSize.s.LowPart < size.s.LowPart)
4497 {
4498 BlockChainStream_Shrink(This, newSize);
4499 }
4500 else
4501 {
4502 ULARGE_INTEGER fileSize =
4503 BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
4504
4505 ULONG diff = newSize.s.LowPart - size.s.LowPart;
4506
4507 /*
4508 * Make sure the file stays a multiple of blocksize
4509 */
4510 if ((diff % This->parentStorage->bigBlockSize) != 0)
4511 diff += (This->parentStorage->bigBlockSize -
4512 (diff % This->parentStorage->bigBlockSize) );
4513
4514 fileSize.s.LowPart += diff;
4515 BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
4516
4517 BlockChainStream_Enlarge(This, newSize);
4518 }
4519
4520 return TRUE;
4521}
4522
4523/******************************************************************************
4524 * BlockChainStream_GetSize
4525 *
4526 * Returns the size of this chain.
4527 * Will return the block count if this chain doesn't have a property.
4528 */
4529ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
4530{
4531 StgProperty chainProperty;
4532
4533 if(This->headOfStreamPlaceHolder == NULL)
4534 {
4535 /*
4536 * This chain is a data stream read the property and return
4537 * the appropriate size
4538 */
4539 StorageImpl_ReadProperty(
4540 This->parentStorage,
4541 This->ownerPropertyIndex,
4542 &chainProperty);
4543
4544 return chainProperty.size;
4545 }
4546 else
4547 {
4548 /*
4549 * this chain is a chain that does not have a property, figure out the
4550 * size by making the product number of used blocks times the
4551 * size of them
4552 */
4553 ULARGE_INTEGER result;
4554 result.s.HighPart = 0;
4555
4556 result.s.LowPart =
4557 BlockChainStream_GetCount(This) *
4558 This->parentStorage->bigBlockSize;
4559
4560 return result;
4561 }
4562}
4563
4564/******************************************************************************
4565** SmallBlockChainStream implementation
4566*/
4567
4568SmallBlockChainStream* SmallBlockChainStream_Construct(
4569 StorageImpl* parentStorage,
4570 ULONG propertyIndex)
4571{
4572 SmallBlockChainStream* newStream;
4573
4574 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
4575
4576 newStream->parentStorage = parentStorage;
4577 newStream->ownerPropertyIndex = propertyIndex;
4578
4579 return newStream;
4580}
4581
4582void SmallBlockChainStream_Destroy(
4583 SmallBlockChainStream* This)
4584{
4585 HeapFree(GetProcessHeap(), 0, This);
4586}
4587
4588/******************************************************************************
4589 * SmallBlockChainStream_GetHeadOfChain
4590 *
4591 * Returns the head of this chain of small blocks.
4592 */
4593ULONG SmallBlockChainStream_GetHeadOfChain(
4594 SmallBlockChainStream* This)
4595{
4596 StgProperty chainProperty;
4597 BOOL readSuccessful;
4598
4599 if (This->ownerPropertyIndex)
4600 {
4601 readSuccessful = StorageImpl_ReadProperty(
4602 This->parentStorage,
4603 This->ownerPropertyIndex,
4604 &chainProperty);
4605
4606 if (readSuccessful)
4607 {
4608 return chainProperty.startingBlock;
4609 }
4610
4611 }
4612
4613 return BLOCK_END_OF_CHAIN;
4614}
4615
4616/******************************************************************************
4617 * SmallBlockChainStream_GetNextBlockInChain
4618 *
4619 * Returns the index of the next small block in this chain.
4620 *
4621 * Return Values:
4622 * - BLOCK_END_OF_CHAIN: end of this chain
4623 * - BLOCK_UNUSED: small block 'blockIndex' is free
4624 */
4625ULONG SmallBlockChainStream_GetNextBlockInChain(
4626 SmallBlockChainStream* This,
4627 ULONG blockIndex)
4628{
4629 ULARGE_INTEGER offsetOfBlockInDepot;
4630 DWORD buffer;
4631 ULONG nextBlockInChain = BLOCK_END_OF_CHAIN;
4632 ULONG bytesRead;
4633 BOOL success;
4634
4635 offsetOfBlockInDepot.s.HighPart = 0;
4636 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4637
4638 /*
4639 * Read those bytes in the buffer from the small block file.
4640 */
4641 success = BlockChainStream_ReadAt(
4642 This->parentStorage->smallBlockDepotChain,
4643 offsetOfBlockInDepot,
4644 sizeof(DWORD),
4645 &buffer,
4646 &bytesRead);
4647
4648 if (success)
4649 {
4650 StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
4651 }
4652
4653 return nextBlockInChain;
4654}
4655
4656/******************************************************************************
4657 * SmallBlockChainStream_SetNextBlockInChain
4658 *
4659 * Writes the index of the next block of the specified block in the small
4660 * block depot.
4661 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
4662 * To flag a block as free use BLOCK_UNUSED as nextBlock.
4663 */
4664void SmallBlockChainStream_SetNextBlockInChain(
4665 SmallBlockChainStream* This,
4666 ULONG blockIndex,
4667 ULONG nextBlock)
4668{
4669 ULARGE_INTEGER offsetOfBlockInDepot;
4670 DWORD buffer;
4671 ULONG bytesWritten;
4672
4673 offsetOfBlockInDepot.s.HighPart = 0;
4674 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4675
4676 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
4677
4678 /*
4679 * Read those bytes in the buffer from the small block file.
4680 */
4681 BlockChainStream_WriteAt(
4682 This->parentStorage->smallBlockDepotChain,
4683 offsetOfBlockInDepot,
4684 sizeof(DWORD),
4685 &buffer,
4686 &bytesWritten);
4687}
4688
4689/******************************************************************************
4690 * SmallBlockChainStream_FreeBlock
4691 *
4692 * Flag small block 'blockIndex' as free in the small block depot.
4693 */
4694void SmallBlockChainStream_FreeBlock(
4695 SmallBlockChainStream* This,
4696 ULONG blockIndex)
4697{
4698 SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
4699}
4700
4701/******************************************************************************
4702 * SmallBlockChainStream_GetNextFreeBlock
4703 *
4704 * Returns the index of a free small block. The small block depot will be
4705 * enlarged if necessary. The small block chain will also be enlarged if
4706 * necessary.
4707 */
4708ULONG SmallBlockChainStream_GetNextFreeBlock(
4709 SmallBlockChainStream* This)
4710{
4711 ULARGE_INTEGER offsetOfBlockInDepot;
4712 DWORD buffer;
4713 ULONG bytesRead;
4714 ULONG blockIndex = 0;
4715 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
4716 BOOL success = TRUE;
4717 ULONG smallBlocksPerBigBlock;
4718
4719 offsetOfBlockInDepot.s.HighPart = 0;
4720
4721 /*
4722 * Scan the small block depot for a free block
4723 */
4724 while (nextBlockIndex != BLOCK_UNUSED)
4725 {
4726 offsetOfBlockInDepot.s.LowPart = blockIndex * sizeof(ULONG);
4727
4728 success = BlockChainStream_ReadAt(
4729 This->parentStorage->smallBlockDepotChain,
4730 offsetOfBlockInDepot,
4731 sizeof(DWORD),
4732 &buffer,
4733 &bytesRead);
4734
4735 /*
4736 * If we run out of space for the small block depot, enlarge it
4737 */
4738 if (success)
4739 {
4740 StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
4741
4742 if (nextBlockIndex != BLOCK_UNUSED)
4743 blockIndex++;
4744 }
4745 else
4746 {
4747 ULONG count =
4748 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
4749
4750 ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
4751 ULONG nextBlock, newsbdIndex;
4752 BYTE* smallBlockDepot;
4753
4754 nextBlock = sbdIndex;
4755 while (nextBlock != BLOCK_END_OF_CHAIN)
4756 {
4757 sbdIndex = nextBlock;
4758 nextBlock =
4759 StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
4760 }
4761
4762 newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4763 if (sbdIndex != BLOCK_END_OF_CHAIN)
4764 StorageImpl_SetNextBlockInChain(
4765 This->parentStorage,
4766 sbdIndex,
4767 newsbdIndex);
4768
4769 StorageImpl_SetNextBlockInChain(
4770 This->parentStorage,
4771 newsbdIndex,
4772 BLOCK_END_OF_CHAIN);
4773
4774 /*
4775 * Initialize all the small blocks to free
4776 */
4777 smallBlockDepot =
4778 StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
4779
4780 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
4781 StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
4782
4783 if (count == 0)
4784 {
4785 /*
4786 * We have just created the small block depot.
4787 */
4788 StgProperty rootProp;
4789 ULONG sbStartIndex;
4790
4791 /*
4792 * Save it in the header
4793 */
4794 This->parentStorage->smallBlockDepotStart = newsbdIndex;
4795 StorageImpl_SaveFileHeader(This->parentStorage);
4796
4797 /*
4798 * And allocate the first big block that will contain small blocks
4799 */
4800 sbStartIndex =
4801 StorageImpl_GetNextFreeBigBlock(This->parentStorage);
4802
4803 StorageImpl_SetNextBlockInChain(
4804 This->parentStorage,
4805 sbStartIndex,
4806 BLOCK_END_OF_CHAIN);
4807
4808 StorageImpl_ReadProperty(
4809 This->parentStorage,
4810 This->parentStorage->rootPropertySetIndex,
4811 &rootProp);
4812
4813 rootProp.startingBlock = sbStartIndex;
4814 rootProp.size.s.HighPart = 0;
4815 rootProp.size.s.LowPart = This->parentStorage->bigBlockSize;
4816
4817 StorageImpl_WriteProperty(
4818 This->parentStorage,
4819 This->parentStorage->rootPropertySetIndex,
4820 &rootProp);
4821 }
4822 }
4823 }
4824
4825 smallBlocksPerBigBlock =
4826 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
4827
4828 /*
4829 * Verify if we have to allocate big blocks to contain small blocks
4830 */
4831 if (blockIndex % smallBlocksPerBigBlock == 0)
4832 {
4833 StgProperty rootProp;
4834 ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
4835
4836 StorageImpl_ReadProperty(
4837 This->parentStorage,
4838 This->parentStorage->rootPropertySetIndex,
4839 &rootProp);
4840
4841 if (rootProp.size.s.LowPart <
4842 (blocksRequired * This->parentStorage->bigBlockSize))
4843 {
4844 rootProp.size.s.LowPart += This->parentStorage->bigBlockSize;
4845
4846 BlockChainStream_SetSize(
4847 This->parentStorage->smallBlockRootChain,
4848 rootProp.size);
4849
4850 StorageImpl_WriteProperty(
4851 This->parentStorage,
4852 This->parentStorage->rootPropertySetIndex,
4853 &rootProp);
4854 }
4855 }
4856
4857 return blockIndex;
4858}
4859
4860/******************************************************************************
4861 * SmallBlockChainStream_ReadAt
4862 *
4863 * Reads a specified number of bytes from this chain at the specified offset.
4864 * bytesRead may be NULL.
4865 * Failure will be returned if the specified number of bytes has not been read.
4866 */
4867BOOL SmallBlockChainStream_ReadAt(
4868 SmallBlockChainStream* This,
4869 ULARGE_INTEGER offset,
4870 ULONG size,
4871 void* buffer,
4872 ULONG* bytesRead)
4873{
4874 ULARGE_INTEGER offsetInBigBlockFile;
4875 ULONG blockNoInSequence =
4876 offset.s.LowPart / This->parentStorage->smallBlockSize;
4877
4878 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
4879 ULONG bytesToReadInBuffer;
4880 ULONG blockIndex;
4881 ULONG bytesReadFromBigBlockFile;
4882 BYTE* bufferWalker;
4883
4884 /*
4885 * This should never happen on a small block file.
4886 */
4887 assert(offset.s.HighPart==0);
4888
4889 /*
4890 * Find the first block in the stream that contains part of the buffer.
4891 */
4892 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4893
4894 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4895 {
4896 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4897
4898 blockNoInSequence--;
4899 }
4900
4901 /*
4902 * Start reading the buffer.
4903 */
4904 *bytesRead = 0;
4905 bufferWalker = buffer;
4906
4907 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4908 {
4909 /*
4910 * Calculate how many bytes we can copy from this small block.
4911 */
4912 bytesToReadInBuffer =
4913 min(This->parentStorage->smallBlockSize - offsetInBlock, size);
4914
4915 /*
4916 * Calculate the offset of the small block in the small block file.
4917 */
4918 offsetInBigBlockFile.s.HighPart = 0;
4919 offsetInBigBlockFile.s.LowPart =
4920 blockIndex * This->parentStorage->smallBlockSize;
4921
4922 offsetInBigBlockFile.s.LowPart += offsetInBlock;
4923
4924 /*
4925 * Read those bytes in the buffer from the small block file.
4926 */
4927 BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
4928 offsetInBigBlockFile,
4929 bytesToReadInBuffer,
4930 bufferWalker,
4931 &bytesReadFromBigBlockFile);
4932
4933 assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
4934
4935 /*
4936 * Step to the next big block.
4937 */
4938 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4939 bufferWalker += bytesToReadInBuffer;
4940 size -= bytesToReadInBuffer;
4941 *bytesRead += bytesToReadInBuffer;
4942 offsetInBlock = 0; /* There is no offset on the next block */
4943 }
4944
4945 return (size == 0);
4946}
4947
4948/******************************************************************************
4949 * SmallBlockChainStream_WriteAt
4950 *
4951 * Writes the specified number of bytes to this chain at the specified offset.
4952 * bytesWritten may be NULL.
4953 * Will fail if not all specified number of bytes have been written.
4954 */
4955BOOL SmallBlockChainStream_WriteAt(
4956 SmallBlockChainStream* This,
4957 ULARGE_INTEGER offset,
4958 ULONG size,
4959 const void* buffer,
4960 ULONG* bytesWritten)
4961{
4962 ULARGE_INTEGER offsetInBigBlockFile;
4963 ULONG blockNoInSequence =
4964 offset.s.LowPart / This->parentStorage->smallBlockSize;
4965
4966 ULONG offsetInBlock = offset.s.LowPart % This->parentStorage->smallBlockSize;
4967 ULONG bytesToWriteInBuffer;
4968 ULONG blockIndex;
4969 ULONG bytesWrittenFromBigBlockFile;
4970 BYTE* bufferWalker;
4971
4972 /*
4973 * This should never happen on a small block file.
4974 */
4975 assert(offset.s.HighPart==0);
4976
4977 /*
4978 * Find the first block in the stream that contains part of the buffer.
4979 */
4980 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
4981
4982 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
4983 {
4984 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
4985
4986 blockNoInSequence--;
4987 }
4988
4989 /*
4990 * Start writing the buffer.
4991 *
4992 * Here, I'm casting away the constness on the buffer variable
4993 * This is OK since we don't intend to modify that buffer.
4994 */
4995 *bytesWritten = 0;
4996 bufferWalker = (BYTE*)buffer;
4997 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
4998 {
4999 /*
5000 * Calculate how many bytes we can copy to this small block.
5001 */
5002 bytesToWriteInBuffer =
5003 min(This->parentStorage->smallBlockSize - offsetInBlock, size);
5004
5005 /*
5006 * Calculate the offset of the small block in the small block file.
5007 */
5008 offsetInBigBlockFile.s.HighPart = 0;
5009 offsetInBigBlockFile.s.LowPart =
5010 blockIndex * This->parentStorage->smallBlockSize;
5011
5012 offsetInBigBlockFile.s.LowPart += offsetInBlock;
5013
5014 /*
5015 * Write those bytes in the buffer to the small block file.
5016 */
5017 BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
5018 offsetInBigBlockFile,
5019 bytesToWriteInBuffer,
5020 bufferWalker,
5021 &bytesWrittenFromBigBlockFile);
5022
5023 assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
5024
5025 /*
5026 * Step to the next big block.
5027 */
5028 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5029 bufferWalker += bytesToWriteInBuffer;
5030 size -= bytesToWriteInBuffer;
5031 *bytesWritten += bytesToWriteInBuffer;
5032 offsetInBlock = 0; /* There is no offset on the next block */
5033 }
5034
5035 return (size == 0);
5036}
5037
5038/******************************************************************************
5039 * SmallBlockChainStream_Shrink
5040 *
5041 * Shrinks this chain in the small block depot.
5042 */
5043BOOL SmallBlockChainStream_Shrink(
5044 SmallBlockChainStream* This,
5045 ULARGE_INTEGER newSize)
5046{
5047 ULONG blockIndex, extraBlock;
5048 ULONG numBlocks;
5049 ULONG count = 0;
5050
5051 numBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
5052
5053 if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
5054 numBlocks++;
5055
5056 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5057
5058 /*
5059 * Go to the new end of chain
5060 */
5061 while (count < numBlocks)
5062 {
5063 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5064 count++;
5065 }
5066
5067 /*
5068 * If the count is 0, we have a special case, the head of the chain was
5069 * just freed.
5070 */
5071 if (count == 0)
5072 {
5073 StgProperty chainProp;
5074
5075 StorageImpl_ReadProperty(This->parentStorage,
5076 This->ownerPropertyIndex,
5077 &chainProp);
5078
5079 chainProp.startingBlock = BLOCK_END_OF_CHAIN;
5080
5081 StorageImpl_WriteProperty(This->parentStorage,
5082 This->ownerPropertyIndex,
5083 &chainProp);
5084
5085 /*
5086 * We start freeing the chain at the head block.
5087 */
5088 extraBlock = blockIndex;
5089 }
5090 else
5091 {
5092 /* Get the next block before marking the new end */
5093 extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5094
5095 /* Mark the new end of chain */
5096 SmallBlockChainStream_SetNextBlockInChain(
5097 This,
5098 blockIndex,
5099 BLOCK_END_OF_CHAIN);
5100 }
5101
5102 /*
5103 * Mark the extra blocks as free
5104 */
5105 while (extraBlock != BLOCK_END_OF_CHAIN)
5106 {
5107 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
5108 SmallBlockChainStream_FreeBlock(This, extraBlock);
5109 extraBlock = blockIndex;
5110 }
5111
5112 return TRUE;
5113}
5114
5115/******************************************************************************
5116 * SmallBlockChainStream_Enlarge
5117 *
5118 * Grows this chain in the small block depot.
5119 */
5120BOOL SmallBlockChainStream_Enlarge(
5121 SmallBlockChainStream* This,
5122 ULARGE_INTEGER newSize)
5123{
5124 ULONG blockIndex, currentBlock;
5125 ULONG newNumBlocks;
5126 ULONG oldNumBlocks = 0;
5127
5128 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5129
5130 /*
5131 * Empty chain
5132 */
5133 if (blockIndex == BLOCK_END_OF_CHAIN)
5134 {
5135
5136 StgProperty chainProp;
5137
5138 StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
5139 &chainProp);
5140
5141 chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
5142
5143 StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
5144 &chainProp);
5145
5146 blockIndex = chainProp.startingBlock;
5147 SmallBlockChainStream_SetNextBlockInChain(
5148 This,
5149 blockIndex,
5150 BLOCK_END_OF_CHAIN);
5151 }
5152
5153 currentBlock = blockIndex;
5154
5155 /*
5156 * Figure out how many blocks are needed to contain this stream
5157 */
5158 newNumBlocks = newSize.s.LowPart / This->parentStorage->smallBlockSize;
5159
5160 if ((newSize.s.LowPart % This->parentStorage->smallBlockSize) != 0)
5161 newNumBlocks++;
5162
5163 /*
5164 * Go to the current end of chain
5165 */
5166 while (blockIndex != BLOCK_END_OF_CHAIN)
5167 {
5168 oldNumBlocks++;
5169 currentBlock = blockIndex;
5170 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
5171 }
5172
5173 /*
5174 * Add new blocks to the chain
5175 */
5176 while (oldNumBlocks < newNumBlocks)
5177 {
5178 blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
5179 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
5180
5181 SmallBlockChainStream_SetNextBlockInChain(
5182 This,
5183 blockIndex,
5184 BLOCK_END_OF_CHAIN);
5185
5186 currentBlock = blockIndex;
5187 oldNumBlocks++;
5188 }
5189
5190 return TRUE;
5191}
5192
5193/******************************************************************************
5194 * SmallBlockChainStream_GetCount
5195 *
5196 * Returns the number of blocks that comprises this chain.
5197 * This is not the size of this chain as the last block may not be full!
5198 */
5199ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
5200{
5201 ULONG blockIndex;
5202 ULONG count = 0;
5203
5204 blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
5205
5206 while (blockIndex != BLOCK_END_OF_CHAIN)
5207 {
5208 count++;
5209
5210 blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
5211 }
5212
5213 return count;
5214}
5215
5216/******************************************************************************
5217 * SmallBlockChainStream_SetSize
5218 *
5219 * Sets the size of this stream.
5220 * The file will grow if we grow the chain.
5221 *
5222 * TODO: Free the actual blocks in the file when we shrink the chain.
5223 * Currently, the blocks are still in the file. So the file size
5224 * doesn't shrink even if we shrink streams.
5225 */
5226BOOL SmallBlockChainStream_SetSize(
5227 SmallBlockChainStream* This,
5228 ULARGE_INTEGER newSize)
5229{
5230 ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
5231
5232 if (newSize.s.LowPart == size.s.LowPart)
5233 return TRUE;
5234
5235 if (newSize.s.LowPart < size.s.LowPart)
5236 {
5237 SmallBlockChainStream_Shrink(This, newSize);
5238 }
5239 else
5240 {
5241 SmallBlockChainStream_Enlarge(This, newSize);
5242 }
5243
5244 return TRUE;
5245}
5246
5247/******************************************************************************
5248 * SmallBlockChainStream_GetSize
5249 *
5250 * Returns the size of this chain.
5251 */
5252ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
5253{
5254 StgProperty chainProperty;
5255
5256 StorageImpl_ReadProperty(
5257 This->parentStorage,
5258 This->ownerPropertyIndex,
5259 &chainProperty);
5260
5261 return chainProperty.size;
5262}
5263
5264/******************************************************************************
5265 * StgCreateDocfile [OLE32.144]
5266 */
5267HRESULT WINAPI StgCreateDocfile(
5268 LPCOLESTR pwcsName,
5269 DWORD grfMode,
5270 DWORD reserved,
5271 IStorage **ppstgOpen)
5272{
5273 StorageImpl* newStorage = 0;
5274 HANDLE hFile = INVALID_HANDLE_VALUE;
5275 HRESULT hr = S_OK;
5276 DWORD shareMode;
5277 DWORD accessMode;
5278 DWORD creationMode;
5279 DWORD fileAttributes;
5280 WCHAR tempFileName[MAX_PATH];
5281
5282 TRACE("(%s, %lx, %ld, %p)\n",
5283 debugstr_w(pwcsName), grfMode,
5284 reserved, ppstgOpen);
5285
5286 /*
5287 * Validate the parameters
5288 */
5289 if (ppstgOpen == 0)
5290 return STG_E_INVALIDPOINTER;
5291
5292 /*
5293 * Validate the STGM flags
5294 */
5295 if ( FAILED( validateSTGM(grfMode) ))
5296 return STG_E_INVALIDFLAG;
5297
5298 /*
5299 * Generate a unique name.
5300 */
5301 if (pwcsName == 0)
5302 {
5303 WCHAR tempPath[MAX_PATH];
5304 WCHAR prefix[] = { 'S', 'T', 'O', 0 };
5305
5306 memset(tempPath, 0, sizeof(tempPath));
5307 memset(tempFileName, 0, sizeof(tempFileName));
5308
5309 if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
5310 tempPath[0] = '.';
5311
5312 if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
5313 pwcsName = tempFileName;
5314 else
5315 return STG_E_INSUFFICIENTMEMORY;
5316 }
5317
5318 /*
5319 * Interpret the STGM value grfMode
5320 */
5321 shareMode = GetShareModeFromSTGM(grfMode);
5322 accessMode = GetAccessModeFromSTGM(grfMode);
5323 creationMode = GetCreationModeFromSTGM(grfMode);
5324
5325 if (grfMode & STGM_DELETEONRELEASE)
5326 fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
5327 else
5328 fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
5329
5330 if (grfMode & STGM_TRANSACTED)
5331 FIXME("Transacted mode not implemented.\n");
5332
5333 /*
5334 * Initialize the "out" parameter.
5335 */
5336 *ppstgOpen = 0;
5337
5338 hFile = CreateFileW(pwcsName,
5339 accessMode,
5340 shareMode,
5341 NULL,
5342 creationMode,
5343 fileAttributes,
5344 0);
5345
5346 if (hFile == INVALID_HANDLE_VALUE)
5347 {
5348 return E_FAIL;
5349 }
5350
5351 /*
5352 * Allocate and initialize the new IStorage32object.
5353 */
5354 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5355
5356 if (newStorage == 0)
5357 return STG_E_INSUFFICIENTMEMORY;
5358
5359 hr = StorageImpl_Construct(
5360 newStorage,
5361 hFile,
5362 NULL,
5363 grfMode,
5364 TRUE,
5365 TRUE);
5366
5367 if (FAILED(hr))
5368 {
5369 HeapFree(GetProcessHeap(), 0, newStorage);
5370 return hr;
5371 }
5372
5373 /*
5374 * Get an "out" pointer for the caller.
5375 */
5376 hr = StorageBaseImpl_QueryInterface(
5377 (IStorage*)newStorage,
5378 (REFIID)&IID_IStorage,
5379 (void**)ppstgOpen);
5380
5381 return hr;
5382}
5383
5384/******************************************************************************
5385 * StgOpenStorage [OLE32.148]
5386 */
5387HRESULT WINAPI StgOpenStorage(
5388 const OLECHAR *pwcsName,
5389 IStorage *pstgPriority,
5390 DWORD grfMode,
5391 SNB snbExclude,
5392 DWORD reserved,
5393 IStorage **ppstgOpen)
5394{
5395 StorageImpl* newStorage = 0;
5396 HRESULT hr = S_OK;
5397 HANDLE hFile = 0;
5398 DWORD shareMode;
5399 DWORD accessMode;
5400
5401 TRACE("(%s, %p, %lx, %p, %ld, %p)\n",
5402 debugstr_w(pwcsName), pstgPriority, grfMode,
5403 snbExclude, reserved, ppstgOpen);
5404
5405 /*
5406 * Perform a sanity check
5407 */
5408 if (( pwcsName == 0) || (ppstgOpen == 0) )
5409 return STG_E_INVALIDPOINTER;
5410
5411 /*
5412 * Validate the STGM flags
5413 */
5414 if ( FAILED( validateSTGM(grfMode) ))
5415 return STG_E_INVALIDFLAG;
5416
5417 /*
5418 * Interpret the STGM value grfMode
5419 */
5420 shareMode = GetShareModeFromSTGM(grfMode);
5421 accessMode = GetAccessModeFromSTGM(grfMode);
5422
5423 /*
5424 * Initialize the "out" parameter.
5425 */
5426 *ppstgOpen = 0;
5427
5428 hFile = CreateFileW( pwcsName,
5429 accessMode,
5430 shareMode,
5431 NULL,
5432 OPEN_EXISTING,
5433 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
5434 0);
5435
5436
5437 if (hFile==INVALID_HANDLE_VALUE)
5438 {
5439 HRESULT hr = E_FAIL;
5440 DWORD last_error = GetLastError();
5441
5442 switch (last_error)
5443 {
5444 case ERROR_FILE_NOT_FOUND:
5445 hr = STG_E_FILENOTFOUND;
5446 break;
5447
5448 case ERROR_PATH_NOT_FOUND:
5449 hr = STG_E_PATHNOTFOUND;
5450 break;
5451
5452 case ERROR_ACCESS_DENIED:
5453 case ERROR_WRITE_PROTECT:
5454 hr = STG_E_ACCESSDENIED;
5455 break;
5456
5457 case ERROR_SHARING_VIOLATION:
5458 hr = STG_E_SHAREVIOLATION;
5459 break;
5460
5461 default:
5462 hr = E_FAIL;
5463 }
5464
5465 return hr;
5466 }
5467
5468 /*
5469 * Allocate and initialize the new IStorage32object.
5470 */
5471 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5472
5473 if (newStorage == 0)
5474 return STG_E_INSUFFICIENTMEMORY;
5475
5476 hr = StorageImpl_Construct(
5477 newStorage,
5478 hFile,
5479 NULL,
5480 grfMode,
5481 TRUE,
5482 FALSE);
5483
5484 if (FAILED(hr))
5485 {
5486 HeapFree(GetProcessHeap(), 0, newStorage);
5487 return hr;
5488 }
5489
5490 /*
5491 * Get an "out" pointer for the caller.
5492 */
5493 hr = StorageBaseImpl_QueryInterface(
5494 (IStorage*)newStorage,
5495 (REFIID)&IID_IStorage,
5496 (void**)ppstgOpen);
5497
5498 return hr;
5499}
5500
5501/******************************************************************************
5502 * StgCreateDocfileOnILockBytes [OLE32.145]
5503 */
5504HRESULT WINAPI StgCreateDocfileOnILockBytes(
5505 ILockBytes *plkbyt,
5506 DWORD grfMode,
5507 DWORD reserved,
5508 IStorage** ppstgOpen)
5509{
5510 StorageImpl* newStorage = 0;
5511 HRESULT hr = S_OK;
5512
5513 /*
5514 * Validate the parameters
5515 */
5516 if ((ppstgOpen == 0) || (plkbyt == 0))
5517 return STG_E_INVALIDPOINTER;
5518
5519 /*
5520 * Allocate and initialize the new IStorage object.
5521 */
5522 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5523
5524 if (newStorage == 0)
5525 return STG_E_INSUFFICIENTMEMORY;
5526
5527 hr = StorageImpl_Construct(
5528 newStorage,
5529 0,
5530 plkbyt,
5531 grfMode,
5532 FALSE,
5533 TRUE);
5534
5535 if (FAILED(hr))
5536 {
5537 HeapFree(GetProcessHeap(), 0, newStorage);
5538 return hr;
5539 }
5540
5541 /*
5542 * Get an "out" pointer for the caller.
5543 */
5544 hr = StorageBaseImpl_QueryInterface(
5545 (IStorage*)newStorage,
5546 (REFIID)&IID_IStorage,
5547 (void**)ppstgOpen);
5548
5549 return hr;
5550}
5551
5552/******************************************************************************
5553 * StgOpenStorageOnILockBytes [OLE32.149]
5554 */
5555HRESULT WINAPI StgOpenStorageOnILockBytes(
5556 ILockBytes *plkbyt,
5557 IStorage *pstgPriority,
5558 DWORD grfMode,
5559 SNB snbExclude,
5560 DWORD reserved,
5561 IStorage **ppstgOpen)
5562{
5563 StorageImpl* newStorage = 0;
5564 HRESULT hr = S_OK;
5565
5566 /*
5567 * Perform a sanity check
5568 */
5569 if ((plkbyt == 0) || (ppstgOpen == 0))
5570 return STG_E_INVALIDPOINTER;
5571
5572 /*
5573 * Validate the STGM flags
5574 */
5575 if ( FAILED( validateSTGM(grfMode) ))
5576 return STG_E_INVALIDFLAG;
5577
5578 /*
5579 * Initialize the "out" parameter.
5580 */
5581 *ppstgOpen = 0;
5582
5583 /*
5584 * Allocate and initialize the new IStorage object.
5585 */
5586 newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5587
5588 if (newStorage == 0)
5589 return STG_E_INSUFFICIENTMEMORY;
5590
5591 hr = StorageImpl_Construct(
5592 newStorage,
5593 0,
5594 plkbyt,
5595 grfMode,
5596 FALSE,
5597 FALSE);
5598
5599 if (FAILED(hr))
5600 {
5601 HeapFree(GetProcessHeap(), 0, newStorage);
5602 return hr;
5603 }
5604
5605 /*
5606 * Get an "out" pointer for the caller.
5607 */
5608 hr = StorageBaseImpl_QueryInterface(
5609 (IStorage*)newStorage,
5610 (REFIID)&IID_IStorage,
5611 (void**)ppstgOpen);
5612
5613 return hr;
5614}
5615#ifndef __WIN32OS2__
5616/******************************************************************************
5617 * StgSetTimes [ole32.150]
5618 *
5619 *
5620 */
5621HRESULT WINAPI StgSetTimes(WCHAR * str, FILETIME * a, FILETIME * b, FILETIME *c )
5622{
5623
5624 FIXME("(%p, %p, %p, %p),stub!\n", str, a, b, c);
5625 return FALSE;
5626}
5627#endif
5628
5629/******************************************************************************
5630 * StgIsStorageILockBytes [OLE32.147]
5631 *
5632 * Determines if the ILockBytes contains a storage object.
5633 */
5634HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
5635{
5636 BYTE sig[8];
5637 ULARGE_INTEGER offset;
5638
5639 offset.s.HighPart = 0;
5640 offset.s.LowPart = 0;
5641
5642 ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
5643
5644 if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
5645 return S_OK;
5646
5647 return S_FALSE;
5648}
5649
5650/******************************************************************************
5651 * WriteClassStg [OLE32.158]
5652 *
5653 * This method will store the specified CLSID in the specified storage object
5654 */
5655HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
5656{
5657 HRESULT hRes;
5658
5659 assert(pStg != 0);
5660
5661 hRes = IStorage_SetClass(pStg, rclsid);
5662
5663 return hRes;
5664}
5665
5666/***********************************************************************
5667 * ReadClassStg
5668 *
5669 * This method reads the CLSID previously written to a storage object with the WriteClassStg.
5670 */
5671HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
5672
5673 STATSTG pstatstg;
5674 HRESULT hRes;
5675
5676 TRACE("()\n");
5677
5678 if(pclsid==NULL)
5679 return E_POINTER;
5680 /*
5681 * read a STATSTG structure (contains the clsid) from the storage
5682 */
5683 hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
5684
5685 if(SUCCEEDED(hRes))
5686 *pclsid=pstatstg.clsid;
5687
5688 return hRes;
5689}
5690
5691/***********************************************************************
5692 * OleLoadFromStream
5693 *
5694 * This function loads an object from stream
5695 */
5696HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
5697{
5698 CLSID clsid;
5699 HRESULT res;
5700 LPPERSISTSTREAM xstm;
5701
5702 TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
5703
5704 res=ReadClassStm(pStm,&clsid);
5705 if (!SUCCEEDED(res))
5706 return res;
5707 res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
5708 if (!SUCCEEDED(res))
5709 return res;
5710 res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
5711 if (!SUCCEEDED(res)) {
5712 IUnknown_Release((IUnknown*)*ppvObj);
5713 return res;
5714 }
5715 res=IPersistStream_Load(xstm,pStm);
5716 IPersistStream_Release(xstm);
5717 /* FIXME: all refcounts ok at this point? I think they should be:
5718 * pStm : unchanged
5719 * ppvObj : 1
5720 * xstm : 0 (released)
5721 */
5722 return res;
5723}
5724
5725/***********************************************************************
5726 * OleSaveToStream
5727 *
5728 * This function saves an object with the IPersistStream interface on it
5729 * to the specified stream.
5730 */
5731HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
5732{
5733
5734 CLSID clsid;
5735 HRESULT res;
5736
5737 TRACE("(%p,%p)\n",pPStm,pStm);
5738
5739 res=IPersistStream_GetClassID(pPStm,&clsid);
5740
5741 if (SUCCEEDED(res)){
5742
5743 res=WriteClassStm(pStm,&clsid);
5744
5745 if (SUCCEEDED(res))
5746
5747 res=IPersistStream_Save(pPStm,pStm,TRUE);
5748 }
5749
5750 TRACE("Finished Save\n");
5751 return res;
5752}
5753
5754/****************************************************************************
5755 * This method validate a STGM parameter that can contain the values below
5756 *
5757 * STGM_DIRECT 0x00000000
5758 * STGM_TRANSACTED 0x00010000
5759 * STGM_SIMPLE 0x08000000
5760 *
5761 * STGM_READ 0x00000000
5762 * STGM_WRITE 0x00000001
5763 * STGM_READWRITE 0x00000002
5764 *
5765 * STGM_SHARE_DENY_NONE 0x00000040
5766 * STGM_SHARE_DENY_READ 0x00000030
5767 * STGM_SHARE_DENY_WRITE 0x00000020
5768 * STGM_SHARE_EXCLUSIVE 0x00000010
5769 *
5770 * STGM_PRIORITY 0x00040000
5771 * STGM_DELETEONRELEASE 0x04000000
5772 *
5773 * STGM_CREATE 0x00001000
5774 * STGM_CONVERT 0x00020000
5775 * STGM_FAILIFTHERE 0x00000000
5776 *
5777 * STGM_NOSCRATCH 0x00100000
5778 * STGM_NOSNAPSHOT 0x00200000
5779 */
5780static HRESULT validateSTGM(DWORD stgm)
5781{
5782 BOOL bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
5783 BOOL bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
5784 BOOL bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
5785
5786 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5787 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5788 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5789
5790 BOOL bSTGM_SHARE_DENY_NONE =
5791 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5792
5793 BOOL bSTGM_SHARE_DENY_READ =
5794 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5795
5796 BOOL bSTGM_SHARE_DENY_WRITE =
5797 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5798
5799 BOOL bSTGM_SHARE_EXCLUSIVE =
5800 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5801
5802 BOOL bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE);
5803 BOOL bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT);
5804
5805 BOOL bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
5806 BOOL bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
5807
5808 /*
5809 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
5810 */
5811 if ( ! bSTGM_DIRECT )
5812 if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
5813 return E_FAIL;
5814
5815 /*
5816 * STGM_WRITE | STGM_READWRITE | STGM_READ
5817 */
5818 if ( ! bSTGM_READ )
5819 if( bSTGM_WRITE && bSTGM_READWRITE )
5820 return E_FAIL;
5821
5822 /*
5823 * STGM_SHARE_DENY_NONE | others
5824 * (I assume here that DENY_READ implies DENY_WRITE)
5825 */
5826 if ( bSTGM_SHARE_DENY_NONE )
5827 if ( bSTGM_SHARE_DENY_READ ||
5828 bSTGM_SHARE_DENY_WRITE ||
5829 bSTGM_SHARE_EXCLUSIVE)
5830 return E_FAIL;
5831
5832 /*
5833 * STGM_CREATE | STGM_CONVERT
5834 * if both are false, STGM_FAILIFTHERE is set to TRUE
5835 */
5836 if ( bSTGM_CREATE && bSTGM_CONVERT )
5837 return E_FAIL;
5838
5839 /*
5840 * STGM_NOSCRATCH requires STGM_TRANSACTED
5841 */
5842 if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
5843 return E_FAIL;
5844
5845 /*
5846 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
5847 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
5848 */
5849 if (bSTGM_NOSNAPSHOT)
5850 {
5851 if ( ! ( bSTGM_TRANSACTED &&
5852 !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
5853 return E_FAIL;
5854 }
5855
5856 return S_OK;
5857}
5858
5859/****************************************************************************
5860 * GetShareModeFromSTGM
5861 *
5862 * This method will return a share mode flag from a STGM value.
5863 * The STGM value is assumed valid.
5864 */
5865static DWORD GetShareModeFromSTGM(DWORD stgm)
5866{
5867 DWORD dwShareMode = 0;
5868 BOOL bSTGM_SHARE_DENY_NONE =
5869 ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE);
5870
5871 BOOL bSTGM_SHARE_DENY_READ =
5872 ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ);
5873
5874 BOOL bSTGM_SHARE_DENY_WRITE =
5875 ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
5876
5877 BOOL bSTGM_SHARE_EXCLUSIVE =
5878 ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE);
5879
5880 if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
5881 dwShareMode = 0;
5882
5883 if (bSTGM_SHARE_DENY_NONE)
5884 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
5885
5886 if (bSTGM_SHARE_DENY_WRITE)
5887 dwShareMode = FILE_SHARE_READ;
5888
5889 return dwShareMode;
5890}
5891
5892/****************************************************************************
5893 * GetAccessModeFromSTGM
5894 *
5895 * This method will return an access mode flag from a STGM value.
5896 * The STGM value is assumed valid.
5897 */
5898static DWORD GetAccessModeFromSTGM(DWORD stgm)
5899{
5900 DWORD dwDesiredAccess = GENERIC_READ;
5901 BOOL bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE);
5902 BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
5903 BOOL bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE);
5904
5905 if (bSTGM_READ)
5906 dwDesiredAccess = GENERIC_READ;
5907
5908 if (bSTGM_WRITE)
5909 dwDesiredAccess |= GENERIC_WRITE;
5910
5911 if (bSTGM_READWRITE)
5912 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
5913
5914 return dwDesiredAccess;
5915}
5916
5917/****************************************************************************
5918 * GetCreationModeFromSTGM
5919 *
5920 * This method will return a creation mode flag from a STGM value.
5921 * The STGM value is assumed valid.
5922 */
5923static DWORD GetCreationModeFromSTGM(DWORD stgm)
5924{
5925 if ( stgm & STGM_CREATE)
5926 return CREATE_ALWAYS;
5927 if (stgm & STGM_CONVERT) {
5928 FIXME("STGM_CONVERT not implemented!\n");
5929 return CREATE_NEW;
5930 }
5931 /* All other cases */
5932 if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
5933 FIXME("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
5934 return CREATE_NEW;
5935}
5936
5937
5938/*************************************************************************
5939 * OLECONVERT_LoadOLE10 [Internal]
5940 *
5941 * Loads the OLE10 STREAM to memory
5942 *
5943 * PARAMS
5944 * pOleStream [I] The OLESTREAM
5945 * pData [I] Data Structure for the OLESTREAM Data
5946 *
5947 * RETURNS
5948 * Success: S_OK
5949 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
5950 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
5951 *
5952 * NOTES
5953 * This function is used by OleConvertOLESTREAMToIStorage only.
5954 *
5955 * Memory allocated for pData must be freed by the caller
5956 */
5957HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1)
5958{
5959 DWORD dwSize;
5960 HRESULT hRes = S_OK;
5961 int nTryCnt=0;
5962 int max_try = 6;
5963
5964 pData->pData = NULL;
5965 pData->pstrOleObjFileName = (CHAR *) NULL;
5966
5967 for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
5968 {
5969 /* Get the OleID */
5970 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
5971 if(dwSize != sizeof(pData->dwOleID))
5972 {
5973 hRes = CONVERT10_E_OLESTREAM_GET;
5974 }
5975 else if(pData->dwOleID != OLESTREAM_ID)
5976 {
5977 hRes = CONVERT10_E_OLESTREAM_FMT;
5978 }
5979 else
5980 {
5981 hRes = S_OK;
5982 break;
5983 }
5984 }
5985
5986 if(hRes == S_OK)
5987 {
5988 /* Get the TypeID...more info needed for this field */
5989 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
5990 if(dwSize != sizeof(pData->dwTypeID))
5991 {
5992 hRes = CONVERT10_E_OLESTREAM_GET;
5993 }
5994 }
5995 if(hRes == S_OK)
5996 {
5997 if(pData->dwTypeID != 0)
5998 {
5999 /* Get the lenght of the OleTypeName */
6000 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6001 if(dwSize != sizeof(pData->dwOleTypeNameLength))
6002 {
6003 hRes = CONVERT10_E_OLESTREAM_GET;
6004 }
6005
6006 if(hRes == S_OK)
6007 {
6008 if(pData->dwOleTypeNameLength > 0)
6009 {
6010 /* Get the OleTypeName */
6011 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength);
6012 if(dwSize != pData->dwOleTypeNameLength)
6013 {
6014 hRes = CONVERT10_E_OLESTREAM_GET;
6015 }
6016 }
6017 }
6018 if(bStrem1)
6019 {
6020 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
6021 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
6022 {
6023 hRes = CONVERT10_E_OLESTREAM_GET;
6024 }
6025 if(hRes == S_OK)
6026 {
6027 if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
6028 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
6029 pData->pstrOleObjFileName = (CHAR *)malloc(pData->dwOleObjFileNameLength);
6030 if(pData->pstrOleObjFileName)
6031 {
6032 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength);
6033 if(dwSize != pData->dwOleObjFileNameLength)
6034 {
6035 hRes = CONVERT10_E_OLESTREAM_GET;
6036 }
6037 }
6038 else
6039 hRes = CONVERT10_E_OLESTREAM_GET;
6040 }
6041 }
6042 else
6043 {
6044 /* Get the Width of the Metafile */
6045 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6046 if(dwSize != sizeof(pData->dwMetaFileWidth))
6047 {
6048 hRes = CONVERT10_E_OLESTREAM_GET;
6049 }
6050 if(hRes == S_OK)
6051 {
6052 /* Get the Height of the Metafile */
6053 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6054 if(dwSize != sizeof(pData->dwMetaFileHeight))
6055 {
6056 hRes = CONVERT10_E_OLESTREAM_GET;
6057 }
6058 }
6059 }
6060 if(hRes == S_OK)
6061 {
6062 /* Get the Lenght of the Data */
6063 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6064 if(dwSize != sizeof(pData->dwDataLength))
6065 {
6066 hRes = CONVERT10_E_OLESTREAM_GET;
6067 }
6068 }
6069
6070 if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */
6071 {
6072 if(!bStrem1) /* if it is a second OLE stream data */
6073 {
6074 pData->dwDataLength -= 8;
6075 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown));
6076 if(dwSize != sizeof(pData->strUnknown))
6077 {
6078 hRes = CONVERT10_E_OLESTREAM_GET;
6079 }
6080 }
6081 }
6082 if(hRes == S_OK)
6083 {
6084 if(pData->dwDataLength > 0)
6085 {
6086 pData->pData = (BYTE *)HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
6087
6088 /* Get Data (ex. IStorage, Metafile, or BMP) */
6089 if(pData->pData)
6090 {
6091 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
6092 if(dwSize != pData->dwDataLength)
6093 {
6094 hRes = CONVERT10_E_OLESTREAM_GET;
6095 }
6096 }
6097 else
6098 {
6099 hRes = CONVERT10_E_OLESTREAM_GET;
6100 }
6101 }
6102 }
6103 }
6104 }
6105 return hRes;
6106}
6107
6108/*************************************************************************
6109 * OLECONVERT_SaveOLE10 [Internal]
6110 *
6111 * Saves the OLE10 STREAM From memory
6112 *
6113 * PARAMS
6114 * pData [I] Data Structure for the OLESTREAM Data
6115 * pOleStream [I] The OLESTREAM to save
6116 *
6117 * RETURNS
6118 * Success: S_OK
6119 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6120 *
6121 * NOTES
6122 * This function is used by OleConvertIStorageToOLESTREAM only.
6123 *
6124 */
6125HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
6126{
6127 DWORD dwSize;
6128 HRESULT hRes = S_OK;
6129
6130
6131 /* Set the OleID */
6132 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
6133 if(dwSize != sizeof(pData->dwOleID))
6134 {
6135 hRes = CONVERT10_E_OLESTREAM_PUT;
6136 }
6137
6138 if(hRes == S_OK)
6139 {
6140 /* Set the TypeID */
6141 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
6142 if(dwSize != sizeof(pData->dwTypeID))
6143 {
6144 hRes = CONVERT10_E_OLESTREAM_PUT;
6145 }
6146 }
6147
6148 if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
6149 {
6150 /* Set the Lenght of the OleTypeName */
6151 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
6152 if(dwSize != sizeof(pData->dwOleTypeNameLength))
6153 {
6154 hRes = CONVERT10_E_OLESTREAM_PUT;
6155 }
6156
6157 if(hRes == S_OK)
6158 {
6159 if(pData->dwOleTypeNameLength > 0)
6160 {
6161 /* Set the OleTypeName */
6162 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->strOleTypeName, pData->dwOleTypeNameLength);
6163 if(dwSize != pData->dwOleTypeNameLength)
6164 {
6165 hRes = CONVERT10_E_OLESTREAM_PUT;
6166 }
6167 }
6168 }
6169
6170 if(hRes == S_OK)
6171 {
6172 /* Set the width of the Metafile */
6173 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
6174 if(dwSize != sizeof(pData->dwMetaFileWidth))
6175 {
6176 hRes = CONVERT10_E_OLESTREAM_PUT;
6177 }
6178 }
6179
6180 if(hRes == S_OK)
6181 {
6182 /* Set the height of the Metafile */
6183 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
6184 if(dwSize != sizeof(pData->dwMetaFileHeight))
6185 {
6186 hRes = CONVERT10_E_OLESTREAM_PUT;
6187 }
6188 }
6189
6190 if(hRes == S_OK)
6191 {
6192 /* Set the lenght of the Data */
6193 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
6194 if(dwSize != sizeof(pData->dwDataLength))
6195 {
6196 hRes = CONVERT10_E_OLESTREAM_PUT;
6197 }
6198 }
6199
6200 if(hRes == S_OK)
6201 {
6202 if(pData->dwDataLength > 0)
6203 {
6204 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
6205 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength);
6206 if(dwSize != pData->dwDataLength)
6207 {
6208 hRes = CONVERT10_E_OLESTREAM_PUT;
6209 }
6210 }
6211 }
6212 }
6213 return hRes;
6214}
6215
6216/*************************************************************************
6217 * OLECONVERT_GetOLE20FromOLE10[Internal]
6218 *
6219 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
6220 * opens it, and copies the content to the dest IStorage for
6221 * OleConvertOLESTREAMToIStorage
6222 *
6223 *
6224 * PARAMS
6225 * pDestStorage [I] The IStorage to copy the data to
6226 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
6227 * nBufferLength [I] The size of the buffer
6228 *
6229 * RETURNS
6230 * Nothing
6231 *
6232 * NOTES
6233 *
6234 *
6235 */
6236void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
6237{
6238 HRESULT hRes;
6239 HANDLE hFile;
6240 IStorage *pTempStorage;
6241 DWORD dwNumOfBytesWritten;
6242 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6243 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6244
6245 /* Create a temp File */
6246 GetTempPathW(MAX_PATH, wstrTempDir);
6247 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6248 hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
6249
6250 if(hFile != INVALID_HANDLE_VALUE)
6251 {
6252 /* Write IStorage Data to File */
6253 WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
6254 CloseHandle(hFile);
6255
6256 /* Open and copy temp storage to the Dest Storage */
6257 hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
6258 if(hRes == S_OK)
6259 {
6260 hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
6261 StorageBaseImpl_Release(pTempStorage);
6262 }
6263 DeleteFileW(wstrTempFile);
6264 }
6265}
6266
6267
6268/*************************************************************************
6269 * OLECONVERT_WriteOLE20ToBuffer [Internal]
6270 *
6271 * Saves the OLE10 STREAM From memory
6272 *
6273 * PARAMS
6274 * pStorage [I] The Src IStorage to copy
6275 * pData [I] The Dest Memory to write to.
6276 *
6277 * RETURNS
6278 * The size in bytes allocated for pData
6279 *
6280 * NOTES
6281 * Memory allocated for pData must be freed by the caller
6282 *
6283 * Used by OleConvertIStorageToOLESTREAM only.
6284 *
6285 */
6286DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
6287{
6288 HANDLE hFile;
6289 HRESULT hRes;
6290 DWORD nDataLength = 0;
6291 IStorage *pTempStorage;
6292 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
6293 WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
6294
6295 *pData = NULL;
6296
6297 /* Create temp Storage */
6298 GetTempPathW(MAX_PATH, wstrTempDir);
6299 GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
6300 hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
6301
6302 if(hRes == S_OK)
6303 {
6304 /* Copy Src Storage to the Temp Storage */
6305 StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
6306 StorageBaseImpl_Release(pTempStorage);
6307
6308 /* Open Temp Storage as a file and copy to memory */
6309 hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
6310 if(hFile != INVALID_HANDLE_VALUE)
6311 {
6312 nDataLength = GetFileSize(hFile, NULL);
6313 *pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,nDataLength);
6314 ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
6315 CloseHandle(hFile);
6316 }
6317 DeleteFileW(wstrTempFile);
6318 }
6319 return nDataLength;
6320}
6321
6322/*************************************************************************
6323 * OLECONVERT_CreateOleStream [Internal]
6324 *
6325 * Creates the "\001OLE" stream in the IStorage if neccessary.
6326 *
6327 * PARAMS
6328 * pStorage [I] Dest storage to create the stream in
6329 *
6330 * RETURNS
6331 * Nothing
6332 *
6333 * NOTES
6334 * This function is used by OleConvertOLESTREAMToIStorage only.
6335 *
6336 * This stream is still unknown, MS Word seems to have extra data
6337 * but since the data is stored in the OLESTREAM there should be
6338 * no need to recreate the stream. If the stream is manually
6339 * deleted it will create it with this default data.
6340 *
6341 */
6342void OLECONVERT_CreateOleStream(LPSTORAGE pStorage)
6343{
6344 HRESULT hRes;
6345 IStream *pStream;
6346 WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
6347 BYTE pOleStreamHeader [] =
6348 {
6349 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
6350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6351 0x00, 0x00, 0x00, 0x00
6352 };
6353
6354 /* Create stream if not present */
6355 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6356 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6357
6358 if(hRes == S_OK)
6359 {
6360 /* Write default Data */
6361 hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
6362 IStream_Release(pStream);
6363 }
6364}
6365
6366
6367/*************************************************************************
6368 * OLECONVERT_CreateCompObjStream [Internal]
6369 *
6370 * Creates a "\001CompObj" is the destination IStorage if necessary.
6371 *
6372 * PARAMS
6373 * pStorage [I] The dest IStorage to create the CompObj Stream
6374 * if necessary.
6375 * strOleTypeName [I] The ProgID
6376 *
6377 * RETURNS
6378 * Success: S_OK
6379 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6380 *
6381 * NOTES
6382 * This function is used by OleConvertOLESTREAMToIStorage only.
6383 *
6384 * The stream data is stored in the OLESTREAM and there should be
6385 * no need to recreate the stream. If the stream is manually
6386 * deleted it will attempt to create it by querying the registry.
6387 *
6388 *
6389 */
6390HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
6391{
6392 IStream *pStream;
6393 HRESULT hStorageRes, hRes = S_OK;
6394 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
6395 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6396
6397 BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
6398 BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
6399
6400 /* Initialize the CompObj structure */
6401 memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
6402 memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
6403 memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
6404
6405
6406 /* Create a CompObj stream if it doesn't exist */
6407 hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName,
6408 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6409 if(hStorageRes == S_OK)
6410 {
6411 /* copy the OleTypeName to the compobj struct */
6412 IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
6413 strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
6414
6415 /* copy the OleTypeName to the compobj struct */
6416 /* Note: in the test made, these where Identical */
6417 IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
6418 strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
6419
6420 /* Get the CLSID */
6421 hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
6422
6423 if(hRes == S_OK)
6424 {
6425 HKEY hKey;
6426 LONG hErr;
6427 /* Get the CLSID Default Name from the Registry */
6428 hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey);
6429 if(hErr == ERROR_SUCCESS)
6430 {
6431 char strTemp[OLESTREAM_MAX_STR_LEN];
6432 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
6433 hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength));
6434 if(hErr == ERROR_SUCCESS)
6435 {
6436 strcpy(IStorageCompObj.strCLSIDName, strTemp);
6437 }
6438 RegCloseKey(hKey);
6439 }
6440 }
6441
6442 /* Write CompObj Structure to stream */
6443 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
6444
6445 WriteClassStm(pStream,&(IStorageCompObj.clsid));
6446
6447 hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
6448 if(IStorageCompObj.dwCLSIDNameLength > 0)
6449 {
6450 hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
6451 }
6452 hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
6453 if(IStorageCompObj.dwOleTypeNameLength > 0)
6454 {
6455 hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
6456 }
6457 hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
6458 if(IStorageCompObj.dwProgIDNameLength > 0)
6459 {
6460 hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
6461 }
6462 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
6463 IStream_Release(pStream);
6464 }
6465 return hRes;
6466}
6467
6468
6469/*************************************************************************
6470 * OLECONVERT_CreateOlePresStream[Internal]
6471 *
6472 * Creates the "\002OlePres000" Stream with the Metafile data
6473 *
6474 * PARAMS
6475 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
6476 * dwExtentX [I] Width of the Metafile
6477 * dwExtentY [I] Height of the Metafile
6478 * pData [I] Metafile data
6479 * dwDataLength [I] Size of the Metafile data
6480 *
6481 * RETURNS
6482 * Success: S_OK
6483 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
6484 *
6485 * NOTES
6486 * This function is used by OleConvertOLESTREAMToIStorage only.
6487 *
6488 */
6489void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
6490{
6491 HRESULT hRes;
6492 IStream *pStream;
6493 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6494 BYTE pOlePresStreamHeader [] =
6495 {
6496 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
6497 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6498 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6499 0x00, 0x00, 0x00, 0x00
6500 };
6501
6502 BYTE pOlePresStreamHeaderEmpty [] =
6503 {
6504 0x00, 0x00, 0x00, 0x00,
6505 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
6506 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
6507 0x00, 0x00, 0x00, 0x00
6508 };
6509
6510 /* Create the OlePres000 Stream */
6511 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6512 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6513
6514 if(hRes == S_OK)
6515 {
6516 DWORD nHeaderSize;
6517 OLECONVERT_ISTORAGE_OLEPRES OlePres;
6518
6519 memset(&OlePres, 0, sizeof(OlePres));
6520 /* Do we have any metafile data to save */
6521 if(dwDataLength > 0)
6522 {
6523 memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
6524 nHeaderSize = sizeof(pOlePresStreamHeader);
6525 }
6526 else
6527 {
6528 memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
6529 nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
6530 }
6531 /* Set width and height of the metafile */
6532 OlePres.dwExtentX = dwExtentX;
6533 OlePres.dwExtentY = -dwExtentY;
6534
6535 /* Set Data and Lenght */
6536 if(dwDataLength > sizeof(METAFILEPICT16))
6537 {
6538 OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
6539 OlePres.pData = &(pData[8]);
6540 }
6541 /* Save OlePres000 Data to Stream */
6542 hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
6543 hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
6544 hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
6545 hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
6546 if(OlePres.dwSize > 0)
6547 {
6548 hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
6549 }
6550 IStream_Release(pStream);
6551 }
6552}
6553
6554/*************************************************************************
6555 * OLECONVERT_CreateOle10NativeStream [Internal]
6556 *
6557 * Creates the "\001Ole10Native" Stream (should contain a BMP)
6558 *
6559 * PARAMS
6560 * pStorage [I] Dest storage to create the stream in
6561 * pData [I] Ole10 Native Data (ex. bmp)
6562 * dwDataLength [I] Size of the Ole10 Native Data
6563 *
6564 * RETURNS
6565 * Nothing
6566 *
6567 * NOTES
6568 * This function is used by OleConvertOLESTREAMToIStorage only.
6569 *
6570 * Might need to verify the data and return appropriate error message
6571 *
6572 */
6573void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
6574{
6575 HRESULT hRes;
6576 IStream *pStream;
6577 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6578
6579 /* Create the Ole10Native Stream */
6580 hRes = IStorage_CreateStream(pStorage, wstrStreamName,
6581 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
6582
6583 if(hRes == S_OK)
6584 {
6585 /* Write info to stream */
6586 hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
6587 hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
6588 IStream_Release(pStream);
6589 }
6590
6591}
6592
6593/*************************************************************************
6594 * OLECONVERT_GetOLE10ProgID [Internal]
6595 *
6596 * Finds the ProgID (or OleTypeID) from the IStorage
6597 *
6598 * PARAMS
6599 * pStorage [I] The Src IStorage to get the ProgID
6600 * strProgID [I] the ProgID string to get
6601 * dwSize [I] the size of the string
6602 *
6603 * RETURNS
6604 * Success: S_OK
6605 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
6606 *
6607 * NOTES
6608 * This function is used by OleConvertIStorageToOLESTREAM only.
6609 *
6610 *
6611 */
6612HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
6613{
6614 HRESULT hRes;
6615 IStream *pStream;
6616 LARGE_INTEGER iSeekPos;
6617 OLECONVERT_ISTORAGE_COMPOBJ CompObj;
6618 WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
6619
6620 /* Open the CompObj Stream */
6621 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6622 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6623 if(hRes == S_OK)
6624 {
6625
6626 /*Get the OleType from the CompObj Stream */
6627 iSeekPos.s.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
6628 iSeekPos.s.HighPart = 0;
6629
6630 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6631 IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
6632 iSeekPos.s.LowPart = CompObj.dwCLSIDNameLength;
6633 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6634 IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
6635 iSeekPos.s.LowPart = CompObj.dwOleTypeNameLength;
6636 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
6637
6638 IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
6639 if(*dwSize > 0)
6640 {
6641 IStream_Read(pStream, strProgID, *dwSize, NULL);
6642 }
6643 IStream_Release(pStream);
6644 }
6645 else
6646 {
6647 STATSTG stat;
6648 LPOLESTR wstrProgID;
6649
6650 /* Get the OleType from the registry */
6651 REFCLSID clsid = &(stat.clsid);
6652 IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
6653 hRes = ProgIDFromCLSID(clsid, &wstrProgID);
6654 if(hRes == S_OK)
6655 {
6656 *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
6657 }
6658
6659 }
6660 return hRes;
6661}
6662
6663/*************************************************************************
6664 * OLECONVERT_GetOle10PresData [Internal]
6665 *
6666 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
6667 *
6668 * PARAMS
6669 * pStorage [I] Src IStroage
6670 * pOleStream [I] Dest OleStream Mem Struct
6671 *
6672 * RETURNS
6673 * Nothing
6674 *
6675 * NOTES
6676 * This function is used by OleConvertIStorageToOLESTREAM only.
6677 *
6678 * Memory allocated for pData must be freed by the caller
6679 *
6680 *
6681 */
6682void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6683{
6684
6685 HRESULT hRes;
6686 IStream *pStream;
6687 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6688
6689 /* Initialize Default data for OLESTREAM */
6690 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6691 pOleStreamData[0].dwTypeID = 2;
6692 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6693 pOleStreamData[1].dwTypeID = 0;
6694 pOleStreamData[0].dwMetaFileWidth = 0;
6695 pOleStreamData[0].dwMetaFileHeight = 0;
6696 pOleStreamData[0].pData = NULL;
6697 pOleStreamData[1].pData = NULL;
6698
6699 /* Open Ole10Native Stream */
6700 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6701 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6702 if(hRes == S_OK)
6703 {
6704
6705 /* Read Size and Data */
6706 IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
6707 if(pOleStreamData->dwDataLength > 0)
6708 {
6709 pOleStreamData->pData = (LPSTR) HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
6710 IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
6711 }
6712 IStream_Release(pStream);
6713 }
6714
6715}
6716
6717
6718/*************************************************************************
6719 * OLECONVERT_GetOle20PresData[Internal]
6720 *
6721 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
6722 *
6723 * PARAMS
6724 * pStorage [I] Src IStroage
6725 * pOleStreamData [I] Dest OleStream Mem Struct
6726 *
6727 * RETURNS
6728 * Nothing
6729 *
6730 * NOTES
6731 * This function is used by OleConvertIStorageToOLESTREAM only.
6732 *
6733 * Memory allocated for pData must be freed by the caller
6734 */
6735void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
6736{
6737 HRESULT hRes;
6738 IStream *pStream;
6739 OLECONVERT_ISTORAGE_OLEPRES olePress;
6740 WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
6741
6742 /* Initialize Default data for OLESTREAM */
6743 pOleStreamData[0].dwOleID = OLESTREAM_ID;
6744 pOleStreamData[0].dwTypeID = 2;
6745 pOleStreamData[0].dwMetaFileWidth = 0;
6746 pOleStreamData[0].dwMetaFileHeight = 0;
6747 pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
6748 pOleStreamData[1].dwOleID = OLESTREAM_ID;
6749 pOleStreamData[1].dwTypeID = 0;
6750 pOleStreamData[1].dwOleTypeNameLength = 0;
6751 pOleStreamData[1].strOleTypeName[0] = 0;
6752 pOleStreamData[1].dwMetaFileWidth = 0;
6753 pOleStreamData[1].dwMetaFileHeight = 0;
6754 pOleStreamData[1].pData = NULL;
6755 pOleStreamData[1].dwDataLength = 0;
6756
6757
6758 /* Open OlePress000 stream */
6759 hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,
6760 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
6761 if(hRes == S_OK)
6762 {
6763 LARGE_INTEGER iSeekPos;
6764 METAFILEPICT16 MetaFilePict;
6765 char strMetafilePictName[] = "METAFILEPICT";
6766
6767 /* Set the TypeID for a Metafile */
6768 pOleStreamData[1].dwTypeID = 5;
6769
6770 /* Set the OleTypeName to Metafile */
6771 pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
6772 strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
6773
6774 iSeekPos.s.HighPart = 0;
6775 iSeekPos.s.LowPart = sizeof(olePress.byUnknown1);
6776
6777 /* Get Presentation Data */
6778 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
6779 IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
6780 IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
6781 IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
6782
6783 /*Set width and Height */
6784 pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
6785 pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
6786 if(olePress.dwSize > 0)
6787 {
6788 /* Set Length */
6789 pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16);
6790
6791 /* Set MetaFilePict struct */
6792 MetaFilePict.mm = 8;
6793 MetaFilePict.xExt = olePress.dwExtentX;
6794 MetaFilePict.yExt = olePress.dwExtentY;
6795 MetaFilePict.hMF = 0;
6796
6797 /* Get Metafile Data */
6798 pOleStreamData[1].pData = (BYTE *) HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
6799 memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
6800 IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
6801 }
6802 IStream_Release(pStream);
6803 }
6804}
6805
6806/*************************************************************************
6807 * OleConvertOLESTREAMToIStorage [OLE32.87]
6808 *
6809 * Read info on MSDN
6810 *
6811 * TODO
6812 * DVTARGETDEVICE paramenter is not handled
6813 * Still unsure of some mem fields for OLE 10 Stream
6814 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6815 * and "\001OLE" streams
6816 *
6817 */
6818HRESULT WINAPI OleConvertOLESTREAMToIStorage (
6819 LPOLESTREAM pOleStream,
6820 LPSTORAGE pstg,
6821 const DVTARGETDEVICE* ptd)
6822{
6823 int i;
6824 HRESULT hRes=S_OK;
6825 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6826
6827 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6828
6829 if(ptd != NULL)
6830 {
6831 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
6832 }
6833
6834 if(pstg == NULL || pOleStream == NULL)
6835 {
6836 hRes = E_INVALIDARG;
6837 }
6838
6839 if(hRes == S_OK)
6840 {
6841 /* Load the OLESTREAM to Memory */
6842 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
6843 }
6844
6845 if(hRes == S_OK)
6846 {
6847 /* Load the OLESTREAM to Memory (part 2)*/
6848 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
6849 }
6850
6851 if(hRes == S_OK)
6852 {
6853
6854 if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
6855 {
6856 /* Do we have the IStorage Data in the OLESTREAM */
6857 if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
6858 {
6859 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6860 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
6861 }
6862 else
6863 {
6864 /* It must be an original OLE 1.0 source */
6865 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6866 }
6867 }
6868 else
6869 {
6870 /* It must be an original OLE 1.0 source */
6871 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
6872 }
6873
6874 /* Create CompObj Stream if necessary */
6875 hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
6876 if(hRes == S_OK)
6877 {
6878 /*Create the Ole Stream if necessary */
6879 OLECONVERT_CreateOleStream(pstg);
6880 }
6881 }
6882
6883
6884 /* Free allocated memory */
6885 for(i=0; i < 2; i++)
6886 {
6887 if(pOleStreamData[i].pData != NULL)
6888 {
6889 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
6890 }
6891 if(pOleStreamData[i].pstrOleObjFileName != NULL)
6892 {
6893 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
6894 pOleStreamData[i].pstrOleObjFileName = NULL;
6895 }
6896 }
6897 return hRes;
6898}
6899
6900/*************************************************************************
6901 * OleConvertIStorageToOLESTREAM [OLE32.85]
6902 *
6903 * Read info on MSDN
6904 *
6905 * Read info on MSDN
6906 *
6907 * TODO
6908 * Still unsure of some mem fields for OLE 10 Stream
6909 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
6910 * and "\001OLE" streams.
6911 *
6912 */
6913HRESULT WINAPI OleConvertIStorageToOLESTREAM (
6914 LPSTORAGE pstg,
6915 LPOLESTREAM pOleStream)
6916{
6917 int i;
6918 HRESULT hRes = S_OK;
6919 IStream *pStream;
6920 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
6921 WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
6922
6923
6924 memset(pOleStreamData, 0, sizeof(pOleStreamData));
6925
6926 if(pstg == NULL || pOleStream == NULL)
6927 {
6928 hRes = E_INVALIDARG;
6929 }
6930 if(hRes == S_OK)
6931 {
6932 /* Get the ProgID */
6933 pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
6934 hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
6935 }
6936 if(hRes == S_OK)
6937 {
6938 /*Was it originaly Ole10 */
6939 hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
6940 if(hRes == S_OK)
6941 {
6942 IStream_Release(pStream);
6943 /*Get Presentation Data for Ole10Native */
6944 OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
6945 }
6946 else
6947 {
6948 /*Get Presentation Data (OLE20)*/
6949 OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
6950 }
6951
6952 /* Save OLESTREAM */
6953 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
6954 if(hRes == S_OK)
6955 {
6956 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
6957 }
6958
6959 }
6960
6961 /* Free allocated memory */
6962 for(i=0; i < 2; i++)
6963 {
6964 if(pOleStreamData[i].pData != NULL)
6965 {
6966 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
6967 }
6968 }
6969
6970 return hRes;
6971}
6972
6973#ifdef __WIN32OS2__
6974/******************************************************************************
6975 * StgIsStorageFile16 [STORAGE.5]
6976 */
6977HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
6978static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
6979 HFILE hf;
6980 OFSTRUCT ofs;
6981 BYTE magic[24];
6982
6983 TRACE_(ole)("(\'%s\')\n",fn);
6984 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
6985 if (hf==HFILE_ERROR)
6986 return STG_E_FILENOTFOUND;
6987 if (24!=_lread(hf,magic,24)) {
6988 WARN_(ole)(" too short\n");
6989 _lclose(hf);
6990 return S_FALSE;
6991 }
6992 if (!memcmp(magic,STORAGE_magic,8)) {
6993 WARN_(ole)(" -> YES\n");
6994 _lclose(hf);
6995 return S_OK;
6996 }
6997 if (!memcmp(magic,STORAGE_notmagic,8)) {
6998 WARN_(ole)(" -> NO\n");
6999 _lclose(hf);
7000 return S_FALSE;
7001 }
7002 if (!memcmp(magic,STORAGE_oldmagic,8)) {
7003 WARN_(ole)(" -> old format\n");
7004 _lclose(hf);
7005 return STG_E_OLDFORMAT;
7006 }
7007 WARN_(ole)(" -> Invalid header.\n");
7008 _lclose(hf);
7009 return STG_E_INVALIDHEADER;
7010}
7011
7012HRESULT WINAPI
7013StgIsStorageFile(LPCOLESTR fn)
7014{
7015 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
7016 HRESULT ret = StgIsStorageFile16(xfn);
7017
7018 HeapFree(GetProcessHeap(),0,xfn);
7019 return ret;
7020}
7021#endif
Note: See TracBrowser for help on using the repository browser.