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

Last change on this file since 22012 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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