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

Last change on this file since 8620 was 8620, checked in by sandervl, 23 years ago

Resync with latest Wine

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