source: trunk/src/ole32/storage.cpp@ 3830

Last change on this file since 3830 was 3167, checked in by davidr, 25 years ago

Ported changes from wine/corel sources

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