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

Last change on this file since 8266 was 7926, checked in by sandervl, 24 years ago

Wine 20020215 resync

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