ReactOS 0.4.16-dev-2332-g4cba65d
storage32.c
Go to the documentation of this file.
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 * Copyright 2005 Mike McCormack
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 *
27 * NOTES
28 * The compound file implementation of IStorage used for create
29 * and manage substorages and streams within a storage object
30 * residing in a compound file object.
31 */
32
33#include <assert.h>
34#include <stdarg.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#define COBJMACROS
40#include "windef.h"
41#include "winbase.h"
42#include "winnls.h"
43#include "winuser.h"
44#include "wine/debug.h"
45
46#include "storage32.h"
47#include "ole2.h" /* For Write/ReadClassStm */
48
49#include "winreg.h"
50#include "wine/wingdi16.h"
51#include "compobj_private.h"
52
54
55
56/*
57 * These are signatures to detect the type of Document file.
58 */
59static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
60static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
61
62extern const IPropertySetStorageVtbl IPropertySetStorage_Vtbl;
63
64
65/****************************************************************************
66 * StorageInternalImpl definitions.
67 *
68 * Definition of the implementation structure for the IStorage interface.
69 * This one implements the IStorage interface for storage that are
70 * inside another storage.
71 */
72typedef struct StorageInternalImpl
73{
75
76 /*
77 * Entry in the parent's stream tracking list
78 */
80
83
84static const IStorageVtbl StorageInternalImpl_Vtbl;
86
87typedef struct TransactedDirEntry
88{
89 /* If applicable, a reference to the original DirEntry in the transacted
90 * parent. If this is a newly-created entry, DIRENTRY_NULL. */
92
93 /* True if this entry is being used. */
95
96 /* True if data is up to date. */
98
99 /* True if this entry has been modified. */
101
102 /* True if this entry's stream has been modified. */
104
105 /* True if this entry has been deleted in the transacted storage, but the
106 * delete has not yet been committed. */
108
109 /* If this entry's stream has been modified, a reference to where the stream
110 * is stored in the snapshot file. */
112
113 /* This directory entry's data, including any changes that have been made. */
115
116 /* A reference to the parent of this node. This is only valid while we are
117 * committing changes. */
119
120 /* A reference to a newly-created entry in the transacted parent. This is
121 * always equal to transactedParentEntry except when committing changes. */
124
125
126/****************************************************************************
127 * Transacted storage object.
128 */
130{
132
133 /*
134 * Modified streams are temporarily saved to the scratch file.
135 */
137
138 /* The directory structure is kept here, so that we can track how these
139 * entries relate to those in the parent storage. */
143
144 /*
145 * Changes are committed to the transacted parent.
146 */
148
149 /* The transaction signature from when we last committed */
152
153static const IStorageVtbl TransactedSnapshotImpl_Vtbl;
155
157{
159
160 /*
161 * Snapshot and uncommitted changes go here.
162 */
164
165 /*
166 * Changes are committed to the transacted parent.
167 */
169
170 /* The transaction signature from when we last committed */
173
174
175/****************************************************************************
176 * BlockChainStream definitions.
177 *
178 * The BlockChainStream class is a utility class that is used to create an
179 * abstraction of the big block chains in the storage file.
180 */
181
183{
184 /* This represents a range of blocks that happen reside in consecutive sectors. */
188};
189
190typedef struct BlockChainBlock
191{
198
200{
211};
212
213/* Returns the number of blocks that comprises this chain.
214 * This is not the size of the stream as the last block may not be full!
215 */
217{
218 return This->numBlocks;
219}
220
228
229
230/****************************************************************************
231 * SmallBlockChainStream definitions.
232 *
233 * The SmallBlockChainStream class is a utility class that is used to create an
234 * abstraction of the small block chains in the storage file.
235 */
236
238{
242};
243
250
251
252/************************************************************************
253 * STGM Functions
254 ***********************************************************************/
255
256/************************************************************************
257 * This method validates an STGM parameter that can contain the values below
258 *
259 * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values.
260 * The stgm values contained in 0xffff0000 are bitmasks.
261 *
262 * STGM_DIRECT 0x00000000
263 * STGM_TRANSACTED 0x00010000
264 * STGM_SIMPLE 0x08000000
265 *
266 * STGM_READ 0x00000000
267 * STGM_WRITE 0x00000001
268 * STGM_READWRITE 0x00000002
269 *
270 * STGM_SHARE_DENY_NONE 0x00000040
271 * STGM_SHARE_DENY_READ 0x00000030
272 * STGM_SHARE_DENY_WRITE 0x00000020
273 * STGM_SHARE_EXCLUSIVE 0x00000010
274 *
275 * STGM_PRIORITY 0x00040000
276 * STGM_DELETEONRELEASE 0x04000000
277 *
278 * STGM_CREATE 0x00001000
279 * STGM_CONVERT 0x00020000
280 * STGM_FAILIFTHERE 0x00000000
281 *
282 * STGM_NOSCRATCH 0x00100000
283 * STGM_NOSNAPSHOT 0x00200000
284 */
286{
288 DWORD share = STGM_SHARE_MODE(stgm);
290
291 if (stgm&~STGM_KNOWN_FLAGS)
292 {
293 ERR("unknown flags %#lx\n", stgm);
294 return E_FAIL;
295 }
296
297 switch (access)
298 {
299 case STGM_READ:
300 case STGM_WRITE:
301 case STGM_READWRITE:
302 break;
303 default:
304 return E_FAIL;
305 }
306
307 switch (share)
308 {
313 break;
314 case 0:
315 if (!(stgm & STGM_TRANSACTED))
316 return E_FAIL;
317 break;
318 default:
319 return E_FAIL;
320 }
321
322 switch (create)
323 {
324 case STGM_CREATE:
325 case STGM_FAILIFTHERE:
326 break;
327 default:
328 return E_FAIL;
329 }
330
331 /*
332 * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
333 */
334 if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) )
335 return E_FAIL;
336
337 /*
338 * STGM_CREATE | STGM_CONVERT
339 * if both are false, STGM_FAILIFTHERE is set to TRUE
340 */
341 if ( create == STGM_CREATE && (stgm & STGM_CONVERT) )
342 return E_FAIL;
343
344 /*
345 * STGM_NOSCRATCH requires STGM_TRANSACTED
346 */
347 if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) )
348 return E_FAIL;
349
350 /*
351 * STGM_NOSNAPSHOT requires STGM_TRANSACTED and
352 * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
353 */
354 if ( (stgm & STGM_NOSNAPSHOT) &&
355 (!(stgm & STGM_TRANSACTED) ||
356 share == STGM_SHARE_EXCLUSIVE ||
357 share == STGM_SHARE_DENY_WRITE) )
358 return E_FAIL;
359
360 return S_OK;
361}
362
363/************************************************************************
364 * GetShareModeFromSTGM
365 *
366 * This method will return a share mode flag from a STGM value.
367 * The STGM value is assumed valid.
368 */
370{
371 switch (STGM_SHARE_MODE(stgm))
372 {
373 case 0:
374 assert(stgm & STGM_TRANSACTED);
375 /* fall-through */
379 return FILE_SHARE_WRITE;
382 return FILE_SHARE_READ;
383 }
384 ERR("Invalid share mode!\n");
385 assert(0);
386 return 0;
387}
388
389/************************************************************************
390 * GetAccessModeFromSTGM
391 *
392 * This method will return an access mode flag from a STGM value.
393 * The STGM value is assumed valid.
394 */
396{
397 switch (STGM_ACCESS_MODE(stgm))
398 {
399 case STGM_READ:
400 return GENERIC_READ;
401 case STGM_WRITE:
402 case STGM_READWRITE:
404 }
405 ERR("Invalid access mode!\n");
406 assert(0);
407 return 0;
408}
409
410/************************************************************************
411 * GetCreationModeFromSTGM
412 *
413 * This method will return a creation mode flag from a STGM value.
414 * The STGM value is assumed valid.
415 */
417{
418 switch(STGM_CREATE_MODE(stgm))
419 {
420 case STGM_CREATE:
421 return CREATE_ALWAYS;
422 case STGM_CONVERT:
423 FIXME("STGM_CONVERT not implemented!\n");
424 return CREATE_NEW;
425 case STGM_FAILIFTHERE:
426 return CREATE_NEW;
427 }
428 ERR("Invalid create mode!\n");
429 assert(0);
430 return 0;
431}
432
433
434/************************************************************************
435 * IDirectWriterLock implementation
436 ***********************************************************************/
437
439{
440 return CONTAINING_RECORD(iface, StorageBaseImpl, IDirectWriterLock_iface);
441}
442
444{
446 return IStorage_QueryInterface(&This->IStorage_iface, riid, obj);
447}
448
450{
452 return IStorage_AddRef(&This->IStorage_iface);
453}
454
456{
458 return IStorage_Release(&This->IStorage_iface);
459}
460
462{
464 FIXME("%p, %ld: stub\n", This, timeout);
465 return E_NOTIMPL;
466}
467
469{
471 FIXME("(%p): stub\n", This);
472 return E_NOTIMPL;
473}
474
476{
478 FIXME("(%p): stub\n", This);
479 return E_NOTIMPL;
480}
481
482static const IDirectWriterLockVtbl DirectWriterLockVtbl =
483{
490};
491
492
493/************************************************************************
494 * StorageBaseImpl implementation : Tree helper functions
495 ***********************************************************************/
496
497/****************************************************************************
498 *
499 * Internal Method
500 *
501 * Case insensitive comparison of DirEntry.name by first considering
502 * their size.
503 *
504 * Returns <0 when name1 < name2
505 * >0 when name1 > name2
506 * 0 when name1 == name2
507 */
509 const OLECHAR *name1,
510 const OLECHAR *name2)
511{
512 LONG diff = lstrlenW(name1) - lstrlenW(name2);
513
514 while (diff == 0 && *name1 != 0)
515 {
516 /*
517 * We compare the string themselves only when they are of the same length
518 */
519 diff = towupper(*name1++) - towupper(*name2++);
520 }
521
522 return diff;
523}
524
525/****************************************************************************
526 *
527 * Internal Method
528 *
529 * Find and read the element of a storage with the given name.
530 */
532 const OLECHAR *name, DirEntry *data)
533{
534 DirRef currentEntry;
535
536 /* Read the storage entry to find the root of the tree. */
538
539 currentEntry = data->dirRootEntry;
540
541 while (currentEntry != DIRENTRY_NULL)
542 {
543 LONG cmp;
544
546
548
549 if (cmp == 0)
550 /* found it */
551 break;
552
553 else if (cmp < 0)
554 currentEntry = data->leftChild;
555
556 else if (cmp > 0)
557 currentEntry = data->rightChild;
558 }
559
560 return currentEntry;
561}
562
563/****************************************************************************
564 *
565 * Internal Method
566 *
567 * Find and read the binary tree parent of the element with the given name.
568 *
569 * If there is no such element, find a place where it could be inserted and
570 * return STG_E_FILENOTFOUND.
571 */
573 const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry,
574 ULONG *relation)
575{
576 DirRef childEntry;
577 DirEntry childData;
578
579 /* Read the storage entry to find the root of the tree. */
580 StorageBaseImpl_ReadDirEntry(storage, storageEntry, parentData);
581
582 *parentEntry = storageEntry;
583 *relation = DIRENTRY_RELATION_DIR;
584
585 childEntry = parentData->dirRootEntry;
586
587 while (childEntry != DIRENTRY_NULL)
588 {
589 LONG cmp;
590
591 StorageBaseImpl_ReadDirEntry(storage, childEntry, &childData);
592
593 cmp = entryNameCmp(childName, childData.name);
594
595 if (cmp == 0)
596 /* found it */
597 break;
598
599 else if (cmp < 0)
600 {
601 *parentData = childData;
602 *parentEntry = childEntry;
603 *relation = DIRENTRY_RELATION_PREVIOUS;
604
605 childEntry = parentData->leftChild;
606 }
607
608 else if (cmp > 0)
609 {
610 *parentData = childData;
611 *parentEntry = childEntry;
612 *relation = DIRENTRY_RELATION_NEXT;
613
614 childEntry = parentData->rightChild;
615 }
616 }
617
618 if (childEntry == DIRENTRY_NULL)
619 return STG_E_FILENOTFOUND;
620 else
621 return S_OK;
622}
623
624static void setEntryLink(DirEntry *entry, ULONG relation, DirRef new_target)
625{
626 switch (relation)
627 {
629 entry->leftChild = new_target;
630 break;
632 entry->rightChild = new_target;
633 break;
635 entry->dirRootEntry = new_target;
636 break;
637 default:
638 assert(0);
639 }
640}
641
642/****************************************************************************
643 *
644 * Internal Method
645 *
646 * Add a directory entry to a storage
647 */
650 DirRef parentStorageIndex,
651 DirRef newEntryIndex)
652{
653 DirEntry currentEntry;
654 DirEntry newEntry;
655
656 /*
657 * Read the inserted entry
658 */
660 newEntryIndex,
661 &newEntry);
662
663 /*
664 * Read the storage entry
665 */
667 parentStorageIndex,
668 &currentEntry);
669
670 if (currentEntry.dirRootEntry != DIRENTRY_NULL)
671 {
672 /*
673 * The root storage contains some element, therefore, start the research
674 * for the appropriate location.
675 */
676 BOOL found = FALSE;
677 DirRef current, next, previous, currentEntryId;
678
679 /*
680 * Keep a reference to the root of the storage's element tree
681 */
682 currentEntryId = currentEntry.dirRootEntry;
683
684 /*
685 * Read
686 */
688 currentEntry.dirRootEntry,
689 &currentEntry);
690
691 previous = currentEntry.leftChild;
692 next = currentEntry.rightChild;
693 current = currentEntryId;
694
695 while (!found)
696 {
697 LONG diff = entryNameCmp( newEntry.name, currentEntry.name);
698
699 if (diff < 0)
700 {
701 if (previous != DIRENTRY_NULL)
702 {
704 previous,
705 &currentEntry);
706 current = previous;
707 }
708 else
709 {
710 currentEntry.leftChild = newEntryIndex;
712 current,
713 &currentEntry);
714 found = TRUE;
715 }
716 }
717 else if (diff > 0)
718 {
719 if (next != DIRENTRY_NULL)
720 {
722 next,
723 &currentEntry);
724 current = next;
725 }
726 else
727 {
728 currentEntry.rightChild = newEntryIndex;
730 current,
731 &currentEntry);
732 found = TRUE;
733 }
734 }
735 else
736 {
737 /*
738 * Trying to insert an item with the same name in the
739 * subtree structure.
740 */
742 }
743
744 previous = currentEntry.leftChild;
745 next = currentEntry.rightChild;
746 }
747 }
748 else
749 {
750 /*
751 * The storage is empty, make the new entry the root of its element tree
752 */
753 currentEntry.dirRootEntry = newEntryIndex;
755 parentStorageIndex,
756 &currentEntry);
757 }
758
759 return S_OK;
760}
761
762/*************************************************************************
763 *
764 * Internal Method
765 *
766 * This method removes a directory entry from its parent storage tree without
767 * freeing any resources attached to it.
768 */
771 DirRef parentStorageIndex,
772 DirRef deletedIndex)
773{
774 DirEntry entryToDelete;
775 DirEntry parentEntry;
776 DirRef parentEntryRef;
777 ULONG typeOfRelation;
778 HRESULT hr;
779
780 hr = StorageBaseImpl_ReadDirEntry(This, deletedIndex, &entryToDelete);
781
782 if (hr != S_OK)
783 return hr;
784
785 /*
786 * Find the element that links to the one we want to delete.
787 */
788 hr = findTreeParent(This, parentStorageIndex, entryToDelete.name,
789 &parentEntry, &parentEntryRef, &typeOfRelation);
790
791 if (hr != S_OK)
792 return hr;
793
794 if (entryToDelete.leftChild != DIRENTRY_NULL)
795 {
796 /*
797 * Replace the deleted entry with its left child
798 */
799 setEntryLink(&parentEntry, typeOfRelation, entryToDelete.leftChild);
800
802 This,
803 parentEntryRef,
804 &parentEntry);
805 if(FAILED(hr))
806 {
807 return hr;
808 }
809
810 if (entryToDelete.rightChild != DIRENTRY_NULL)
811 {
812 /*
813 * We need to reinsert the right child somewhere. We already know it and
814 * its children are greater than everything in the left tree, so we
815 * insert it at the rightmost point in the left tree.
816 */
817 DirRef newRightChildParent = entryToDelete.leftChild;
818 DirEntry newRightChildParentEntry;
819
820 do
821 {
823 This,
824 newRightChildParent,
825 &newRightChildParentEntry);
826 if (FAILED(hr))
827 {
828 return hr;
829 }
830
831 if (newRightChildParentEntry.rightChild != DIRENTRY_NULL)
832 newRightChildParent = newRightChildParentEntry.rightChild;
833 } while (newRightChildParentEntry.rightChild != DIRENTRY_NULL);
834
835 newRightChildParentEntry.rightChild = entryToDelete.rightChild;
836
838 This,
839 newRightChildParent,
840 &newRightChildParentEntry);
841 if (FAILED(hr))
842 {
843 return hr;
844 }
845 }
846 }
847 else
848 {
849 /*
850 * Replace the deleted entry with its right child
851 */
852 setEntryLink(&parentEntry, typeOfRelation, entryToDelete.rightChild);
853
855 This,
856 parentEntryRef,
857 &parentEntry);
858 if(FAILED(hr))
859 {
860 return hr;
861 }
862 }
863
864 return hr;
865}
866
867
868/************************************************************************
869 * IEnumSTATSTGImpl implementation for StorageBaseImpl_EnumElements
870 ***********************************************************************/
871
872/*
873 * IEnumSTATSTGImpl definitions.
874 *
875 * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
876 * This class allows iterating through the content of a storage and finding
877 * specific items inside it.
878 */
880{
882
883 LONG ref; /* Reference count */
884 StorageBaseImpl* parentStorage; /* Reference to the parent storage */
885 DirRef storageDirEntry; /* Directory entry of the storage to enumerate */
886
887 WCHAR name[DIRENTRY_NAME_MAX_LEN]; /* The most recent name visited */
888};
889
891{
892 return CONTAINING_RECORD(iface, IEnumSTATSTGImpl, IEnumSTATSTG_iface);
893}
894
896{
897 IStorage_Release(&This->parentStorage->IStorage_iface);
899}
900
902 IEnumSTATSTG* iface,
903 REFIID riid,
904 void** ppvObject)
905{
907
908 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), ppvObject);
909
910 if (ppvObject==0)
911 return E_INVALIDARG;
912
913 *ppvObject = 0;
914
917 {
918 *ppvObject = &This->IEnumSTATSTG_iface;
919 IEnumSTATSTG_AddRef(&This->IEnumSTATSTG_iface);
920 TRACE("<-- %p\n", *ppvObject);
921 return S_OK;
922 }
923
924 TRACE("<-- E_NOINTERFACE\n");
925 return E_NOINTERFACE;
926}
927
929 IEnumSTATSTG* iface)
930{
932 return InterlockedIncrement(&This->ref);
933}
934
936 IEnumSTATSTG* iface)
937{
939
940 ULONG newRef;
941
942 newRef = InterlockedDecrement(&This->ref);
943
944 if (newRef==0)
945 {
947 }
948
949 return newRef;
950}
951
954 DirRef *ref)
955{
957 DirRef searchNode;
959 HRESULT hr;
960 WCHAR result_name[DIRENTRY_NAME_MAX_LEN];
961
962 TRACE("%p,%p\n", This, ref);
963
964 hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
965 This->parentStorage->storageDirEntry, &entry);
966 searchNode = entry.dirRootEntry;
967
968 while (SUCCEEDED(hr) && searchNode != DIRENTRY_NULL)
969 {
970 hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, searchNode, &entry);
971
972 if (SUCCEEDED(hr))
973 {
974 LONG diff = entryNameCmp( entry.name, This->name);
975
976 if (diff <= 0)
977 {
978 searchNode = entry.rightChild;
979 }
980 else
981 {
982 result = searchNode;
983 memcpy(result_name, entry.name, sizeof(result_name));
984 searchNode = entry.leftChild;
985 }
986 }
987 }
988
989 if (SUCCEEDED(hr))
990 {
991 *ref = result;
992 if (result != DIRENTRY_NULL)
993 memcpy(This->name, result_name, sizeof(result_name));
994 }
995
996 TRACE("<-- %#lx\n", hr);
997 return hr;
998}
999
1001 IEnumSTATSTG* iface,
1002 ULONG celt,
1003 STATSTG* rgelt,
1004 ULONG* pceltFetched)
1005{
1007
1008 DirEntry currentEntry;
1009 STATSTG* currentReturnStruct = rgelt;
1010 ULONG objectFetched = 0;
1011 DirRef currentSearchNode;
1012 HRESULT hr=S_OK;
1013
1014 TRACE("%p, %lu, %p, %p.\n", iface, celt, rgelt, pceltFetched);
1015
1016 if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
1017 return E_INVALIDARG;
1018
1019 if (This->parentStorage->reverted)
1020 {
1021 TRACE("<-- STG_E_REVERTED\n");
1022 return STG_E_REVERTED;
1023 }
1024
1025 /*
1026 * To avoid the special case, get another pointer to a ULONG value if
1027 * the caller didn't supply one.
1028 */
1029 if (pceltFetched==0)
1030 pceltFetched = &objectFetched;
1031
1032 /*
1033 * Start the iteration, we will iterate until we hit the end of the
1034 * linked list or until we hit the number of items to iterate through
1035 */
1036 *pceltFetched = 0;
1037
1038 while ( *pceltFetched < celt )
1039 {
1040 hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
1041
1042 if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
1043 {
1044 memset(currentReturnStruct, 0, sizeof(*currentReturnStruct));
1045 break;
1046 }
1047
1048 /*
1049 * Read the entry from the storage.
1050 */
1051 hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
1052 currentSearchNode,
1053 &currentEntry);
1054 if (FAILED(hr)) break;
1055
1056 /*
1057 * Copy the information to the return buffer.
1058 */
1060 currentReturnStruct,
1061 &currentEntry,
1062 STATFLAG_DEFAULT);
1063
1064 /*
1065 * Step to the next item in the iteration
1066 */
1067 (*pceltFetched)++;
1068 currentReturnStruct++;
1069 }
1070
1071 if (SUCCEEDED(hr) && *pceltFetched != celt)
1072 hr = S_FALSE;
1073
1074 TRACE("<-- %#lx (asked %lu, got %lu)\n", hr, celt, *pceltFetched);
1075 return hr;
1076}
1077
1078
1080 IEnumSTATSTG* iface,
1081 ULONG celt)
1082{
1084
1085 ULONG objectFetched = 0;
1086 DirRef currentSearchNode;
1087 HRESULT hr=S_OK;
1088
1089 TRACE("%p, %lu.\n", iface, celt);
1090
1091 if (This->parentStorage->reverted)
1092 {
1093 TRACE("<-- STG_E_REVERTED\n");
1094 return STG_E_REVERTED;
1095 }
1096
1097 while ( (objectFetched < celt) )
1098 {
1099 hr = IEnumSTATSTGImpl_GetNextRef(This, &currentSearchNode);
1100
1101 if (FAILED(hr) || currentSearchNode == DIRENTRY_NULL)
1102 break;
1103
1104 objectFetched++;
1105 }
1106
1107 if (SUCCEEDED(hr) && objectFetched != celt)
1108 return S_FALSE;
1109
1110 TRACE("<-- %#lx\n", hr);
1111 return hr;
1112}
1113
1115 IEnumSTATSTG* iface)
1116{
1118
1119 TRACE("%p\n", iface);
1120
1121 if (This->parentStorage->reverted)
1122 {
1123 TRACE("<-- STG_E_REVERTED\n");
1124 return STG_E_REVERTED;
1125 }
1126
1127 This->name[0] = 0;
1128
1129 return S_OK;
1130}
1131
1133
1135 IEnumSTATSTG* iface,
1136 IEnumSTATSTG** ppenum)
1137{
1139 IEnumSTATSTGImpl* newClone;
1140
1141 TRACE("%p,%p\n", iface, ppenum);
1142
1143 if (This->parentStorage->reverted)
1144 {
1145 TRACE("<-- STG_E_REVERTED\n");
1146 return STG_E_REVERTED;
1147 }
1148
1149 if (ppenum==0)
1150 return E_INVALIDARG;
1151
1152 newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
1153 This->storageDirEntry);
1154 if (!newClone)
1155 {
1156 *ppenum = NULL;
1157 return E_OUTOFMEMORY;
1158 }
1159
1160 /*
1161 * The new clone enumeration must point to the same current node as
1162 * the old one.
1163 */
1164 memcpy(newClone->name, This->name, sizeof(newClone->name));
1165
1166 *ppenum = &newClone->IEnumSTATSTG_iface;
1167
1168 return S_OK;
1169}
1170
1171/*
1172 * Virtual function table for the IEnumSTATSTGImpl class.
1173 */
1174static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl =
1175{
1183};
1184
1186 StorageBaseImpl* parentStorage,
1187 DirRef storageDirEntry)
1188{
1189 IEnumSTATSTGImpl* newEnumeration;
1190
1191 newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
1192
1193 if (newEnumeration)
1194 {
1195 newEnumeration->IEnumSTATSTG_iface.lpVtbl = &IEnumSTATSTGImpl_Vtbl;
1196 newEnumeration->ref = 1;
1197 newEnumeration->name[0] = 0;
1198
1199 /*
1200 * We want to nail-down the reference to the storage in case the
1201 * enumeration out-lives the storage in the client application.
1202 */
1203 newEnumeration->parentStorage = parentStorage;
1204 IStorage_AddRef(&newEnumeration->parentStorage->IStorage_iface);
1205
1206 newEnumeration->storageDirEntry = storageDirEntry;
1207 }
1208
1209 return newEnumeration;
1210}
1211
1212
1213/************************************************************************
1214 * StorageBaseImpl implementation
1215 ***********************************************************************/
1216
1218{
1219 return CONTAINING_RECORD(iface, StorageBaseImpl, IStorage_iface);
1220}
1221
1222/************************************************************************
1223 * StorageBaseImpl_QueryInterface (IUnknown)
1224 *
1225 * This method implements the common QueryInterface for all IStorage
1226 * implementations contained in this file.
1227 *
1228 * See Windows documentation for more details on IUnknown methods.
1229 */
1231 IStorage* iface,
1232 REFIID riid,
1233 void** ppvObject)
1234{
1236
1237 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), ppvObject);
1238
1239 if (!ppvObject)
1240 return E_INVALIDARG;
1241
1242 *ppvObject = 0;
1243
1244 if (IsEqualGUID(&IID_IUnknown, riid) ||
1245 IsEqualGUID(&IID_IStorage, riid))
1246 {
1247 *ppvObject = &This->IStorage_iface;
1248 }
1249 else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
1250 {
1251 *ppvObject = &This->IPropertySetStorage_iface;
1252 }
1253 /* locking interface is reported for writer only */
1254 else if (IsEqualGUID(&IID_IDirectWriterLock, riid) && This->lockingrole == SWMR_Writer)
1255 {
1256 *ppvObject = &This->IDirectWriterLock_iface;
1257 }
1258 else
1259 {
1260 TRACE("<-- E_NOINTERFACE\n");
1261 return E_NOINTERFACE;
1262 }
1263
1264 IStorage_AddRef(iface);
1265 TRACE("<-- %p\n", *ppvObject);
1266 return S_OK;
1267}
1268
1269/************************************************************************
1270 * StorageBaseImpl_AddRef (IUnknown)
1271 *
1272 * This method implements the common AddRef for all IStorage
1273 * implementations contained in this file.
1274 *
1275 * See Windows documentation for more details on IUnknown methods.
1276 */
1278 IStorage* iface)
1279{
1282
1283 TRACE("%p, refcount %lu.\n", iface, ref);
1284
1285 return ref;
1286}
1287
1288/************************************************************************
1289 * StorageBaseImpl_Release (IUnknown)
1290 *
1291 * This method implements the common Release for all IStorage
1292 * implementations contained in this file.
1293 *
1294 * See Windows documentation for more details on IUnknown methods.
1295 */
1297 IStorage* iface)
1298{
1300
1302
1303 TRACE("%p, refcount %lu.\n", iface, ref);
1304
1305 if (ref == 0)
1306 {
1307 /*
1308 * Since we are using a system of base-classes, we want to call the
1309 * destructor of the appropriate derived class. To do this, we are
1310 * using virtual functions to implement the destructor.
1311 */
1313 }
1314
1315 return ref;
1316}
1317
1319 DirRef srcEntry, BOOL skip_storage, BOOL skip_stream,
1320 SNB snbExclude, IStorage *pstgDest);
1321
1323 DirRef srcEntry, BOOL skip_storage, BOOL skip_stream,
1324 SNB snbExclude, IStorage *pstgDest)
1325{
1326 DirEntry data;
1327 HRESULT hr;
1328 BOOL skip = FALSE;
1329 IStorage *pstgTmp;
1330 IStream *pstrChild, *pstrTmp;
1331 STATSTG strStat;
1332
1333 if (srcEntry == DIRENTRY_NULL)
1334 return S_OK;
1335
1336 hr = StorageBaseImpl_ReadDirEntry( This, srcEntry, &data );
1337
1338 if (FAILED(hr))
1339 return hr;
1340
1341 if ( snbExclude )
1342 {
1343 WCHAR **snb = snbExclude;
1344
1345 while ( *snb != NULL && !skip )
1346 {
1347 if ( wcscmp(data.name, *snb) == 0 )
1348 skip = TRUE;
1349 ++snb;
1350 }
1351 }
1352
1353 if (!skip)
1354 {
1355 if (data.stgType == STGTY_STORAGE && !skip_storage)
1356 {
1357 /*
1358 * create a new storage in destination storage
1359 */
1360 hr = IStorage_CreateStorage( pstgDest, data.name,
1362 0, 0,
1363 &pstgTmp );
1364
1365 /*
1366 * if it already exist, don't create a new one use this one
1367 */
1369 {
1370 hr = IStorage_OpenStorage( pstgDest, data.name, NULL,
1372 NULL, 0, &pstgTmp );
1373 }
1374
1375 if (SUCCEEDED(hr))
1376 {
1377 hr = StorageBaseImpl_CopyStorageEntryTo( This, srcEntry, skip_storage,
1378 skip_stream, NULL, pstgTmp );
1379
1380 IStorage_Release(pstgTmp);
1381 }
1382 }
1383 else if (data.stgType == STGTY_STREAM && !skip_stream)
1384 {
1385 /*
1386 * create a new stream in destination storage. If the stream already
1387 * exist, it will be deleted and a new one will be created.
1388 */
1389 hr = IStorage_CreateStream( pstgDest, data.name,
1391 0, 0, &pstrTmp );
1392
1393 /*
1394 * open child stream storage. This operation must succeed even if the
1395 * stream is already open, so we use internal functions to do it.
1396 */
1397 if (hr == S_OK)
1398 {
1400
1401 if (streamimpl)
1402 {
1403 pstrChild = &streamimpl->IStream_iface;
1404 if (pstrChild)
1405 IStream_AddRef(pstrChild);
1406 }
1407 else
1408 {
1409 pstrChild = NULL;
1410 hr = E_OUTOFMEMORY;
1411 }
1412 }
1413
1414 if (hr == S_OK)
1415 {
1416 /*
1417 * Get the size of the source stream
1418 */
1419 IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
1420
1421 /*
1422 * Set the size of the destination stream.
1423 */
1424 IStream_SetSize(pstrTmp, strStat.cbSize);
1425
1426 /*
1427 * do the copy
1428 */
1429 hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
1430 NULL, NULL );
1431
1432 IStream_Release( pstrChild );
1433 }
1434
1435 IStream_Release( pstrTmp );
1436 }
1437 }
1438
1439 /* copy siblings */
1440 if (SUCCEEDED(hr))
1441 hr = StorageBaseImpl_CopyChildEntryTo( This, data.leftChild, skip_storage,
1442 skip_stream, snbExclude, pstgDest );
1443
1444 if (SUCCEEDED(hr))
1445 hr = StorageBaseImpl_CopyChildEntryTo( This, data.rightChild, skip_storage,
1446 skip_stream, snbExclude, pstgDest );
1447
1448 TRACE("<-- %#lx\n", hr);
1449 return hr;
1450}
1451
1453{
1454 StgStreamImpl *strm;
1455
1456 TRACE("%p, %ld.\n", stg, streamEntry);
1457
1458 LIST_FOR_EACH_ENTRY(strm, &stg->strmHead, StgStreamImpl, StrmListEntry)
1459 {
1460 if (strm->dirEntry == streamEntry)
1461 {
1462 return TRUE;
1463 }
1464 }
1465
1466 return FALSE;
1467}
1468
1470{
1471 StorageInternalImpl *childstg;
1472
1473 TRACE("%p, %ld.\n", stg, storageEntry);
1474
1475 LIST_FOR_EACH_ENTRY(childstg, &stg->storageHead, StorageInternalImpl, ParentListEntry)
1476 {
1477 if (childstg->base.storageDirEntry == storageEntry)
1478 {
1479 return TRUE;
1480 }
1481 }
1482
1483 return FALSE;
1484}
1485
1486/************************************************************************
1487 * StorageBaseImpl_OpenStream (IStorage)
1488 *
1489 * This method will open the specified stream object from the current storage.
1490 *
1491 * See Windows documentation for more details on IStorage methods.
1492 */
1494 IStorage* iface,
1495 const OLECHAR* pwcsName, /* [string][in] */
1496 void* reserved1, /* [unique][in] */
1497 DWORD grfMode, /* [in] */
1498 DWORD reserved2, /* [in] */
1499 IStream** ppstm) /* [out] */
1500{
1502 StgStreamImpl* newStream;
1503 DirEntry currentEntry;
1504 DirRef streamEntryRef;
1506
1507 TRACE("%p, %s, %p, %#lx, %ld, %p.\n", iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
1508
1509 if ( (pwcsName==NULL) || (ppstm==0) )
1510 {
1511 res = E_INVALIDARG;
1512 goto end;
1513 }
1514
1515 *ppstm = NULL;
1516
1517 if ( FAILED( validateSTGM(grfMode) ) ||
1519 {
1521 goto end;
1522 }
1523
1524 /*
1525 * As documented.
1526 */
1527 if ( (grfMode & STGM_DELETEONRELEASE) || (grfMode & STGM_TRANSACTED) )
1528 {
1530 goto end;
1531 }
1532
1533 if (This->reverted)
1534 {
1536 goto end;
1537 }
1538
1539 /*
1540 * Check that we're compatible with the parent's storage mode, but
1541 * only if we are not in transacted mode
1542 */
1543 if(!(This->openFlags & STGM_TRANSACTED)) {
1544 if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
1545 {
1547 goto end;
1548 }
1549 }
1550
1551 /*
1552 * Search for the element with the given name
1553 */
1554 streamEntryRef = findElement(
1555 This,
1556 This->storageDirEntry,
1557 pwcsName,
1558 &currentEntry);
1559
1560 /*
1561 * If it was found, construct the stream object and return a pointer to it.
1562 */
1563 if ( (streamEntryRef!=DIRENTRY_NULL) &&
1564 (currentEntry.stgType==STGTY_STREAM) )
1565 {
1566 if (StorageBaseImpl_IsStreamOpen(This, streamEntryRef))
1567 {
1568 /* A single stream cannot be opened a second time. */
1570 goto end;
1571 }
1572
1573 newStream = StgStreamImpl_Construct(This, grfMode, streamEntryRef);
1574
1575 if (newStream)
1576 {
1577 newStream->grfMode = grfMode;
1578 *ppstm = &newStream->IStream_iface;
1579
1580 IStream_AddRef(*ppstm);
1581
1582 res = S_OK;
1583 goto end;
1584 }
1585
1587 goto end;
1588 }
1589
1591
1592end:
1593 if (res == S_OK)
1594 TRACE("<-- IStream %p\n", *ppstm);
1595 TRACE("<-- %#lx\n", res);
1596 return res;
1597}
1598
1599/************************************************************************
1600 * StorageBaseImpl_OpenStorage (IStorage)
1601 *
1602 * This method will open a new storage object from the current storage.
1603 *
1604 * See Windows documentation for more details on IStorage methods.
1605 */
1607 IStorage* iface,
1608 const OLECHAR* pwcsName, /* [string][unique][in] */
1609 IStorage* pstgPriority, /* [unique][in] */
1610 DWORD grfMode, /* [in] */
1611 SNB snbExclude, /* [unique][in] */
1612 DWORD reserved, /* [in] */
1613 IStorage** ppstg) /* [out] */
1614{
1616 StorageInternalImpl* newStorage;
1617 StorageBaseImpl* newTransactedStorage;
1618 DirEntry currentEntry;
1619 DirRef storageEntryRef;
1621
1622 TRACE("%p, %s, %p, %#lx, %p, %ld, %p.\n", iface, debugstr_w(pwcsName), pstgPriority,
1623 grfMode, snbExclude, reserved, ppstg);
1624
1625 if ((pwcsName==NULL) || (ppstg==0) )
1626 {
1627 res = E_INVALIDARG;
1628 goto end;
1629 }
1630
1631 if (This->openFlags & STGM_SIMPLE)
1632 {
1634 goto end;
1635 }
1636
1637 /* as documented */
1638 if (snbExclude != NULL)
1639 {
1641 goto end;
1642 }
1643
1644 if ( FAILED( validateSTGM(grfMode) ))
1645 {
1647 goto end;
1648 }
1649
1650 /*
1651 * As documented.
1652 */
1653 if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE ||
1654 (grfMode & STGM_DELETEONRELEASE) ||
1655 (grfMode & STGM_PRIORITY) )
1656 {
1658 goto end;
1659 }
1660
1661 if (This->reverted)
1662 return STG_E_REVERTED;
1663
1664 /*
1665 * Check that we're compatible with the parent's storage mode,
1666 * but only if we are not transacted
1667 */
1668 if(!(This->openFlags & STGM_TRANSACTED)) {
1669 if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
1670 {
1672 goto end;
1673 }
1674 }
1675
1676 *ppstg = NULL;
1677
1678 storageEntryRef = findElement(
1679 This,
1680 This->storageDirEntry,
1681 pwcsName,
1682 &currentEntry);
1683
1684 if ( (storageEntryRef!=DIRENTRY_NULL) &&
1685 (currentEntry.stgType==STGTY_STORAGE) )
1686 {
1687 if (StorageBaseImpl_IsStorageOpen(This, storageEntryRef))
1688 {
1689 /* A single storage cannot be opened a second time. */
1691 goto end;
1692 }
1693
1694 newStorage = StorageInternalImpl_Construct(
1695 This,
1696 grfMode,
1697 storageEntryRef);
1698
1699 if (newStorage != 0)
1700 {
1701 if (grfMode & STGM_TRANSACTED)
1702 {
1703 res = Storage_ConstructTransacted(&newStorage->base, FALSE, &newTransactedStorage);
1704
1705 if (FAILED(res))
1706 {
1707 HeapFree(GetProcessHeap(), 0, newStorage);
1708 goto end;
1709 }
1710
1711 *ppstg = &newTransactedStorage->IStorage_iface;
1712 }
1713 else
1714 {
1715 *ppstg = &newStorage->base.IStorage_iface;
1716 }
1717
1718 list_add_tail(&This->storageHead, &newStorage->ParentListEntry);
1719
1720 res = S_OK;
1721 goto end;
1722 }
1723
1725 goto end;
1726 }
1727
1729
1730end:
1731 TRACE("<-- %#lx\n", res);
1732 return res;
1733}
1734
1735/************************************************************************
1736 * StorageBaseImpl_EnumElements (IStorage)
1737 *
1738 * This method will create an enumerator object that can be used to
1739 * retrieve information about all the elements in the storage object.
1740 *
1741 * See Windows documentation for more details on IStorage methods.
1742 */
1744 IStorage* iface,
1745 DWORD reserved1, /* [in] */
1746 void* reserved2, /* [size_is][unique][in] */
1747 DWORD reserved3, /* [in] */
1748 IEnumSTATSTG** ppenum) /* [out] */
1749{
1751 IEnumSTATSTGImpl* newEnum;
1752
1753 TRACE("%p, %ld, %p, %ld, %p.\n", iface, reserved1, reserved2, reserved3, ppenum);
1754
1755 if (!ppenum)
1756 return E_INVALIDARG;
1757
1758 if (This->reverted)
1759 return STG_E_REVERTED;
1760
1762 This,
1763 This->storageDirEntry);
1764
1765 if (newEnum)
1766 {
1767 *ppenum = &newEnum->IEnumSTATSTG_iface;
1768 return S_OK;
1769 }
1770
1771 return E_OUTOFMEMORY;
1772}
1773
1774/************************************************************************
1775 * StorageBaseImpl_Stat (IStorage)
1776 *
1777 * This method will retrieve information about this storage object.
1778 *
1779 * See Windows documentation for more details on IStorage methods.
1780 */
1782 IStorage* iface,
1783 STATSTG* pstatstg, /* [out] */
1784 DWORD grfStatFlag) /* [in] */
1785{
1787 DirEntry currentEntry;
1789
1790 TRACE("%p, %p, %#lx.\n", iface, pstatstg, grfStatFlag);
1791
1792 if (!pstatstg)
1793 {
1794 res = E_INVALIDARG;
1795 goto end;
1796 }
1797
1798 if (This->reverted)
1799 {
1801 goto end;
1802 }
1803
1805 This,
1806 This->storageDirEntry,
1807 &currentEntry);
1808
1809 if (SUCCEEDED(res))
1810 {
1812 This,
1813 pstatstg,
1814 &currentEntry,
1815 grfStatFlag);
1816
1817 pstatstg->grfMode = This->openFlags;
1818 pstatstg->grfStateBits = This->stateBits;
1819 }
1820
1821end:
1822 if (res == S_OK)
1823 {
1824 TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %#lx, grfLocksSupported: %ld, grfStateBits: %#lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.LowPart, pstatstg->cbSize.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits);
1825 }
1826 TRACE("<-- %#lx\n", res);
1827 return res;
1828}
1829
1830/************************************************************************
1831 * StorageBaseImpl_RenameElement (IStorage)
1832 *
1833 * This method will rename the specified element.
1834 *
1835 * See Windows documentation for more details on IStorage methods.
1836 */
1838 IStorage* iface,
1839 const OLECHAR* pwcsOldName, /* [in] */
1840 const OLECHAR* pwcsNewName) /* [in] */
1841{
1843 DirEntry currentEntry;
1844 DirRef currentEntryRef;
1845
1846 TRACE("(%p, %s, %s)\n",
1847 iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
1848
1849 if (This->reverted)
1850 return STG_E_REVERTED;
1851
1852 currentEntryRef = findElement(This,
1853 This->storageDirEntry,
1854 pwcsNewName,
1855 &currentEntry);
1856
1857 if (currentEntryRef != DIRENTRY_NULL)
1858 {
1859 /*
1860 * There is already an element with the new name
1861 */
1863 }
1864
1865 /*
1866 * Search for the old element name
1867 */
1868 currentEntryRef = findElement(This,
1869 This->storageDirEntry,
1870 pwcsOldName,
1871 &currentEntry);
1872
1873 if (currentEntryRef != DIRENTRY_NULL)
1874 {
1875 if (StorageBaseImpl_IsStreamOpen(This, currentEntryRef) ||
1876 StorageBaseImpl_IsStorageOpen(This, currentEntryRef))
1877 {
1878 WARN("Element is already open; cannot rename.\n");
1879 return STG_E_ACCESSDENIED;
1880 }
1881
1882 /* Remove the element from its current position in the tree */
1883 removeFromTree(This, This->storageDirEntry,
1884 currentEntryRef);
1885
1886 /* Change the name of the element */
1887 lstrcpyW(currentEntry.name, pwcsNewName);
1888
1889 /* Delete any sibling links */
1890 currentEntry.leftChild = DIRENTRY_NULL;
1891 currentEntry.rightChild = DIRENTRY_NULL;
1892
1893 StorageBaseImpl_WriteDirEntry(This, currentEntryRef,
1894 &currentEntry);
1895
1896 /* Insert the element in a new position in the tree */
1897 insertIntoTree(This, This->storageDirEntry,
1898 currentEntryRef);
1899 }
1900 else
1901 {
1902 /*
1903 * There is no element with the old name
1904 */
1905 return STG_E_FILENOTFOUND;
1906 }
1907
1909}
1910
1911/************************************************************************
1912 * StorageBaseImpl_CreateStream (IStorage)
1913 *
1914 * This method will create a stream object within this storage
1915 *
1916 * See Windows documentation for more details on IStorage methods.
1917 */
1919 IStorage* iface,
1920 const OLECHAR* pwcsName, /* [string][in] */
1921 DWORD grfMode, /* [in] */
1922 DWORD reserved1, /* [in] */
1923 DWORD reserved2, /* [in] */
1924 IStream** ppstm) /* [out] */
1925{
1927 StgStreamImpl* newStream;
1928 DirEntry currentEntry, newStreamEntry;
1929 DirRef currentEntryRef, newStreamEntryRef;
1930 HRESULT hr;
1931
1932 TRACE("%p, %s, %#lx, %ld, %ld, %p.\n", iface, debugstr_w(pwcsName), grfMode, reserved1, reserved2, ppstm);
1933
1934 if (ppstm == 0)
1935 return STG_E_INVALIDPOINTER;
1936
1937 if (pwcsName == 0)
1938 return STG_E_INVALIDNAME;
1939
1940 if (reserved1 || reserved2)
1942
1943 if ( FAILED( validateSTGM(grfMode) ))
1944 return STG_E_INVALIDFLAG;
1945
1946 if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE)
1947 return STG_E_INVALIDFLAG;
1948
1949 if (This->reverted)
1950 return STG_E_REVERTED;
1951
1952 /*
1953 * As documented.
1954 */
1955 if ((grfMode & STGM_DELETEONRELEASE) ||
1956 (grfMode & STGM_TRANSACTED))
1957 return STG_E_INVALIDFUNCTION;
1958
1959 /*
1960 * Don't worry about permissions in transacted mode, as we can always write
1961 * changes; we just can't always commit them.
1962 */
1963 if(!(This->openFlags & STGM_TRANSACTED)) {
1964 /* Can't create a stream on read-only storage */
1965 if ( STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
1966 return STG_E_ACCESSDENIED;
1967
1968 /* Can't create a stream with greater access than the parent. */
1969 if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
1970 return STG_E_ACCESSDENIED;
1971 }
1972
1973 if(This->openFlags & STGM_SIMPLE)
1974 if(grfMode & STGM_CREATE) return STG_E_INVALIDFLAG;
1975
1976 *ppstm = 0;
1977
1978 currentEntryRef = findElement(This,
1979 This->storageDirEntry,
1980 pwcsName,
1981 &currentEntry);
1982
1983 if (currentEntryRef != DIRENTRY_NULL)
1984 {
1985 /*
1986 * An element with this name already exists
1987 */
1988 if (STGM_CREATE_MODE(grfMode) == STGM_CREATE)
1989 {
1990 IStorage_DestroyElement(iface, pwcsName);
1991 }
1992 else
1994 }
1995
1996 /*
1997 * memset the empty entry
1998 */
1999 memset(&newStreamEntry, 0, sizeof(DirEntry));
2000
2001 newStreamEntry.sizeOfNameString =
2002 ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
2003
2004 if (newStreamEntry.sizeOfNameString > DIRENTRY_NAME_BUFFER_LEN)
2005 return STG_E_INVALIDNAME;
2006
2007 lstrcpyW(newStreamEntry.name, pwcsName);
2008
2009 newStreamEntry.stgType = STGTY_STREAM;
2010 newStreamEntry.startingBlock = BLOCK_END_OF_CHAIN;
2011 newStreamEntry.size.LowPart = 0;
2012 newStreamEntry.size.HighPart = 0;
2013
2014 newStreamEntry.leftChild = DIRENTRY_NULL;
2015 newStreamEntry.rightChild = DIRENTRY_NULL;
2016 newStreamEntry.dirRootEntry = DIRENTRY_NULL;
2017
2018 /* call CoFileTime to get the current time
2019 newStreamEntry.ctime
2020 newStreamEntry.mtime
2021 */
2022
2023 /* newStreamEntry.clsid */
2024
2025 /*
2026 * Create an entry with the new data
2027 */
2028 hr = StorageBaseImpl_CreateDirEntry(This, &newStreamEntry, &newStreamEntryRef);
2029 if (FAILED(hr))
2030 return hr;
2031
2032 /*
2033 * Insert the new entry in the parent storage's tree.
2034 */
2036 This,
2037 This->storageDirEntry,
2038 newStreamEntryRef);
2039 if (FAILED(hr))
2040 {
2041 StorageBaseImpl_DestroyDirEntry(This, newStreamEntryRef);
2042 return hr;
2043 }
2044
2045 /*
2046 * Open the stream to return it.
2047 */
2048 newStream = StgStreamImpl_Construct(This, grfMode, newStreamEntryRef);
2049
2050 if (newStream)
2051 {
2052 *ppstm = &newStream->IStream_iface;
2053 IStream_AddRef(*ppstm);
2054 }
2055 else
2056 {
2058 }
2059
2061}
2062
2063/************************************************************************
2064 * StorageBaseImpl_SetClass (IStorage)
2065 *
2066 * This method will write the specified CLSID in the directory entry of this
2067 * storage.
2068 *
2069 * See Windows documentation for more details on IStorage methods.
2070 */
2072 IStorage* iface,
2073 REFCLSID clsid) /* [in] */
2074{
2076 HRESULT hRes;
2077 DirEntry currentEntry;
2078
2079 TRACE("(%p, %s)\n", iface, wine_dbgstr_guid(clsid));
2080
2081 if (This->reverted)
2082 return STG_E_REVERTED;
2083
2085 This->storageDirEntry,
2086 &currentEntry);
2087 if (SUCCEEDED(hRes))
2088 {
2089 currentEntry.clsid = *clsid;
2090
2092 This->storageDirEntry,
2093 &currentEntry);
2094 }
2095
2096 if (SUCCEEDED(hRes))
2098
2099 return hRes;
2100}
2101
2102/************************************************************************
2103 * StorageBaseImpl_CreateStorage (IStorage)
2104 *
2105 * This method will create the storage object within the provided storage.
2106 *
2107 * See Windows documentation for more details on IStorage methods.
2108 */
2110 IStorage* iface,
2111 const OLECHAR *pwcsName, /* [string][in] */
2112 DWORD grfMode, /* [in] */
2113 DWORD reserved1, /* [in] */
2114 DWORD reserved2, /* [in] */
2115 IStorage **ppstg) /* [out] */
2116{
2118
2119 DirEntry currentEntry;
2120 DirEntry newEntry;
2121 DirRef currentEntryRef;
2122 DirRef newEntryRef;
2123 HRESULT hr;
2124
2125 TRACE("%p, %s, %#lx, %ld, %ld, %p.\n", iface, debugstr_w(pwcsName), grfMode,
2126 reserved1, reserved2, ppstg);
2127
2128 if (ppstg == 0)
2129 return STG_E_INVALIDPOINTER;
2130
2131 if (This->openFlags & STGM_SIMPLE)
2132 {
2133 return STG_E_INVALIDFUNCTION;
2134 }
2135
2136 if (pwcsName == 0)
2137 return STG_E_INVALIDNAME;
2138
2139 *ppstg = NULL;
2140
2141 if ( FAILED( validateSTGM(grfMode) ) ||
2142 (grfMode & STGM_DELETEONRELEASE) )
2143 {
2144 WARN("bad grfMode: %#lx\n", grfMode);
2145 return STG_E_INVALIDFLAG;
2146 }
2147
2148 if (This->reverted)
2149 return STG_E_REVERTED;
2150
2151 /*
2152 * Check that we're compatible with the parent's storage mode
2153 */
2154 if ( !(This->openFlags & STGM_TRANSACTED) &&
2155 STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( This->openFlags ) )
2156 {
2157 WARN("access denied\n");
2158 return STG_E_ACCESSDENIED;
2159 }
2160
2161 currentEntryRef = findElement(This,
2162 This->storageDirEntry,
2163 pwcsName,
2164 &currentEntry);
2165
2166 if (currentEntryRef != DIRENTRY_NULL)
2167 {
2168 /*
2169 * An element with this name already exists
2170 */
2171 if (STGM_CREATE_MODE(grfMode) == STGM_CREATE &&
2172 ((This->openFlags & STGM_TRANSACTED) ||
2173 STGM_ACCESS_MODE(This->openFlags) != STGM_READ))
2174 {
2175 hr = IStorage_DestroyElement(iface, pwcsName);
2176 if (FAILED(hr))
2177 return hr;
2178 }
2179 else
2180 {
2181 WARN("file already exists\n");
2183 }
2184 }
2185 else if (!(This->openFlags & STGM_TRANSACTED) &&
2186 STGM_ACCESS_MODE(This->openFlags) == STGM_READ)
2187 {
2188 WARN("read-only storage\n");
2189 return STG_E_ACCESSDENIED;
2190 }
2191
2192 memset(&newEntry, 0, sizeof(DirEntry));
2193
2194 newEntry.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
2195
2197 {
2198 FIXME("name too long\n");
2199 return STG_E_INVALIDNAME;
2200 }
2201
2202 lstrcpyW(newEntry.name, pwcsName);
2203
2204 newEntry.stgType = STGTY_STORAGE;
2206 newEntry.size.LowPart = 0;
2207 newEntry.size.HighPart = 0;
2208
2209 newEntry.leftChild = DIRENTRY_NULL;
2210 newEntry.rightChild = DIRENTRY_NULL;
2211 newEntry.dirRootEntry = DIRENTRY_NULL;
2212
2213 /* call CoFileTime to get the current time
2214 newEntry.ctime
2215 newEntry.mtime
2216 */
2217
2218 /* newEntry.clsid */
2219
2220 /*
2221 * Create a new directory entry for the storage
2222 */
2223 hr = StorageBaseImpl_CreateDirEntry(This, &newEntry, &newEntryRef);
2224 if (FAILED(hr))
2225 return hr;
2226
2227 /*
2228 * Insert the new directory entry into the parent storage's tree
2229 */
2231 This,
2232 This->storageDirEntry,
2233 newEntryRef);
2234 if (FAILED(hr))
2235 {
2237 return hr;
2238 }
2239
2240 /*
2241 * Open it to get a pointer to return.
2242 */
2243 hr = IStorage_OpenStorage(iface, pwcsName, 0, grfMode, 0, 0, ppstg);
2244
2245 if( (hr != S_OK) || (*ppstg == NULL))
2246 {
2247 return hr;
2248 }
2249
2250 if (SUCCEEDED(hr))
2252
2253 return S_OK;
2254}
2255
2257 DirRef srcEntry, BOOL skip_storage, BOOL skip_stream,
2258 SNB snbExclude, IStorage *pstgDest)
2259{
2260 DirEntry data;
2261 HRESULT hr;
2262
2263 hr = StorageBaseImpl_ReadDirEntry( This, srcEntry, &data );
2264
2265 if (SUCCEEDED(hr))
2266 hr = IStorage_SetClass( pstgDest, &data.clsid );
2267
2268 if (SUCCEEDED(hr))
2269 hr = StorageBaseImpl_CopyChildEntryTo( This, data.dirRootEntry, skip_storage,
2270 skip_stream, snbExclude, pstgDest );
2271
2272 TRACE("<-- %#lx\n", hr);
2273 return hr;
2274}
2275
2276/*************************************************************************
2277 * CopyTo (IStorage)
2278 */
2280 IStorage* iface,
2281 DWORD ciidExclude, /* [in] */
2282 const IID* rgiidExclude, /* [size_is][unique][in] */
2283 SNB snbExclude, /* [unique][in] */
2284 IStorage* pstgDest) /* [unique][in] */
2285{
2287
2288 BOOL skip_storage = FALSE, skip_stream = FALSE;
2289 DWORD i;
2290
2291 TRACE("%p, %ld, %p, %p, %p.\n", iface, ciidExclude, rgiidExclude, snbExclude, pstgDest);
2292
2293 if ( pstgDest == 0 )
2294 return STG_E_INVALIDPOINTER;
2295
2296 for(i = 0; i < ciidExclude; ++i)
2297 {
2298 if(IsEqualGUID(&IID_IStorage, &rgiidExclude[i]))
2299 skip_storage = TRUE;
2300 else if(IsEqualGUID(&IID_IStream, &rgiidExclude[i]))
2301 skip_stream = TRUE;
2302 else
2303 WARN("Unknown excluded GUID: %s\n", debugstr_guid(&rgiidExclude[i]));
2304 }
2305
2306 if (!skip_storage)
2307 {
2308 /* Give up early if it looks like this would be infinitely recursive.
2309 * Oddly enough, this includes some cases that aren't really recursive, like
2310 * copying to a transacted child. */
2311 IStorage *pstgDestAncestor = pstgDest;
2312 IStorage *pstgDestAncestorChild = NULL;
2313
2314 /* Go up the chain from the destination until we find the source storage. */
2315 while (pstgDestAncestor != iface) {
2316 pstgDestAncestorChild = pstgDest;
2317
2318 if (pstgDestAncestor->lpVtbl == &TransactedSnapshotImpl_Vtbl)
2319 {
2321
2322 pstgDestAncestor = &snapshot->transactedParent->IStorage_iface;
2323 }
2324 else if (pstgDestAncestor->lpVtbl == &StorageInternalImpl_Vtbl)
2325 {
2326 StorageInternalImpl *internal = (StorageInternalImpl*) pstgDestAncestor;
2327
2328 pstgDestAncestor = &internal->parentStorage->IStorage_iface;
2329 }
2330 else
2331 break;
2332 }
2333
2334 if (pstgDestAncestor == iface)
2335 {
2336 BOOL fail = TRUE;
2337
2338 if (pstgDestAncestorChild && snbExclude)
2339 {
2340 StorageBaseImpl *ancestorChildBase = (StorageBaseImpl*)pstgDestAncestorChild;
2341 DirEntry data;
2342 WCHAR **snb = snbExclude;
2343
2344 StorageBaseImpl_ReadDirEntry(ancestorChildBase, ancestorChildBase->storageDirEntry, &data);
2345
2346 while ( *snb != NULL && fail )
2347 {
2348 if ( wcscmp(data.name, *snb) == 0 )
2349 fail = FALSE;
2350 ++snb;
2351 }
2352 }
2353
2354 if (fail)
2355 return STG_E_ACCESSDENIED;
2356 }
2357 }
2358
2359 return StorageBaseImpl_CopyStorageEntryTo( This, This->storageDirEntry,
2360 skip_storage, skip_stream, snbExclude, pstgDest );
2361}
2362
2363/*************************************************************************
2364 * MoveElementTo (IStorage)
2365 */
2367 IStorage* iface,
2368 const OLECHAR *pwcsName, /* [string][in] */
2369 IStorage *pstgDest, /* [unique][in] */
2370 const OLECHAR *pwcsNewName,/* [string][in] */
2371 DWORD grfFlags) /* [in] */
2372{
2373 FIXME("%p, %s, %p, %s, %#lx: stub\n", iface, debugstr_w(pwcsName), pstgDest,
2374 debugstr_w(pwcsNewName), grfFlags);
2375 return E_NOTIMPL;
2376}
2377
2378/*************************************************************************
2379 * Commit (IStorage)
2380 *
2381 * Ensures that any changes made to a storage object open in transacted mode
2382 * are reflected in the parent storage
2383 *
2384 * In a non-transacted mode, this ensures all cached writes are completed.
2385 */
2387 IStorage* iface,
2388 DWORD grfCommitFlags)/* [in] */
2389{
2391 TRACE("%p, %#lx.\n", iface, grfCommitFlags);
2393}
2394
2395/*************************************************************************
2396 * Revert (IStorage)
2397 *
2398 * Discard all changes that have been made since the last commit operation
2399 */
2401 IStorage* iface)
2402{
2403 TRACE("(%p)\n", iface);
2404 return S_OK;
2405}
2406
2407/*********************************************************************
2408 *
2409 * Internal helper function for StorageBaseImpl_DestroyElement()
2410 *
2411 * Delete the contents of a storage entry.
2412 *
2413 */
2415 StorageBaseImpl *parentStorage,
2416 DirRef indexToDelete,
2417 DirEntry entryDataToDelete)
2418{
2419 IEnumSTATSTG *elements = 0;
2420 IStorage *childStorage = 0;
2421 STATSTG currentElement;
2422 HRESULT hr;
2423 HRESULT destroyHr = S_OK;
2424 StorageInternalImpl *stg, *stg2;
2425
2426 TRACE("%p, %ld.\n", parentStorage, indexToDelete);
2427
2428 /* Invalidate any open storage objects. */
2429 LIST_FOR_EACH_ENTRY_SAFE(stg, stg2, &parentStorage->storageHead, StorageInternalImpl, ParentListEntry)
2430 {
2431 if (stg->base.storageDirEntry == indexToDelete)
2432 {
2434 }
2435 }
2436
2437 /*
2438 * Open the storage and enumerate it
2439 */
2440 hr = IStorage_OpenStorage(
2441 &parentStorage->IStorage_iface,
2442 entryDataToDelete.name,
2443 0,
2445 0,
2446 0,
2447 &childStorage);
2448
2449 if (hr != S_OK)
2450 {
2451 TRACE("<-- %#lx\n", hr);
2452 return hr;
2453 }
2454
2455 /*
2456 * Enumerate the elements
2457 */
2458 hr = IStorage_EnumElements(childStorage, 0, 0, 0, &elements);
2459 if (FAILED(hr))
2460 {
2461 IStorage_Release(childStorage);
2462 TRACE("<-- %#lx\n", hr);
2463 return hr;
2464 }
2465
2466 do
2467 {
2468 /*
2469 * Obtain the next element
2470 */
2471 hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
2472 if (hr==S_OK)
2473 {
2474 destroyHr = IStorage_DestroyElement(childStorage, currentElement.pwcsName);
2475
2476 CoTaskMemFree(currentElement.pwcsName);
2477 }
2478
2479 /*
2480 * We need to Reset the enumeration every time because we delete elements
2481 * and the enumeration could be invalid
2482 */
2483 IEnumSTATSTG_Reset(elements);
2484
2485 } while ((hr == S_OK) && (destroyHr == S_OK));
2486
2487 IStorage_Release(childStorage);
2488 IEnumSTATSTG_Release(elements);
2489
2490 TRACE("%#lx\n", hr);
2491 return destroyHr;
2492}
2493
2494/*********************************************************************
2495 *
2496 * Internal helper function for StorageBaseImpl_DestroyElement()
2497 *
2498 * Perform the deletion of a stream's data
2499 *
2500 */
2502 StorageBaseImpl *parentStorage,
2503 DirRef indexToDelete,
2504 DirEntry entryDataToDelete)
2505{
2506 IStream *pis;
2507 HRESULT hr;
2509 StgStreamImpl *strm, *strm2;
2510
2511 /* Invalidate any open stream objects. */
2512 LIST_FOR_EACH_ENTRY_SAFE(strm, strm2, &parentStorage->strmHead, StgStreamImpl, StrmListEntry)
2513 {
2514 if (strm->dirEntry == indexToDelete)
2515 {
2516 TRACE("Stream deleted %p\n", strm);
2517 strm->parentStorage = NULL;
2518 list_remove(&strm->StrmListEntry);
2519 }
2520 }
2521
2522 size.HighPart = 0;
2523 size.LowPart = 0;
2524
2525 hr = IStorage_OpenStream(&parentStorage->IStorage_iface,
2526 entryDataToDelete.name, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pis);
2527
2528 if (hr!=S_OK)
2529 {
2530 TRACE("<-- %#lx\n", hr);
2531 return(hr);
2532 }
2533
2534 /*
2535 * Zap the stream
2536 */
2537 hr = IStream_SetSize(pis, size);
2538
2539 if(hr != S_OK)
2540 {
2541 TRACE("<-- %#lx\n", hr);
2542 return hr;
2543 }
2544
2545 /*
2546 * Release the stream object.
2547 */
2548 IStream_Release(pis);
2549 TRACE("<-- %#lx\n", hr);
2550 return S_OK;
2551}
2552
2553/*************************************************************************
2554 * DestroyElement (IStorage)
2555 *
2556 * Strategy: This implementation is built this way for simplicity not for speed.
2557 * I always delete the topmost element of the enumeration and adjust
2558 * the deleted element pointer all the time. This takes longer to
2559 * do but allows reinvoking DestroyElement whenever we encounter a
2560 * storage object. The optimisation resides in the usage of another
2561 * enumeration strategy that would give all the leaves of a storage
2562 * first. (postfix order)
2563 */
2565 IStorage* iface,
2566 const OLECHAR *pwcsName)/* [string][in] */
2567{
2569
2570 HRESULT hr = S_OK;
2571 DirEntry entryToDelete;
2572 DirRef entryToDeleteRef;
2573
2574 TRACE("(%p, %s)\n",
2575 iface, debugstr_w(pwcsName));
2576
2577 if (pwcsName==NULL)
2578 return STG_E_INVALIDPOINTER;
2579
2580 if (This->reverted)
2581 return STG_E_REVERTED;
2582
2583 if ( !(This->openFlags & STGM_TRANSACTED) &&
2584 STGM_ACCESS_MODE( This->openFlags ) == STGM_READ )
2585 return STG_E_ACCESSDENIED;
2586
2587 entryToDeleteRef = findElement(
2588 This,
2589 This->storageDirEntry,
2590 pwcsName,
2591 &entryToDelete);
2592
2593 if ( entryToDeleteRef == DIRENTRY_NULL )
2594 {
2595 TRACE("<-- STG_E_FILENOTFOUND\n");
2596 return STG_E_FILENOTFOUND;
2597 }
2598
2599 if ( entryToDelete.stgType == STGTY_STORAGE )
2600 {
2602 This,
2603 entryToDeleteRef,
2604 entryToDelete);
2605 }
2606 else if ( entryToDelete.stgType == STGTY_STREAM )
2607 {
2609 This,
2610 entryToDeleteRef,
2611 entryToDelete);
2612 }
2613
2614 if (hr!=S_OK)
2615 {
2616 TRACE("<-- %#lx\n", hr);
2617 return hr;
2618 }
2619
2620 /*
2621 * Remove the entry from its parent storage
2622 */
2624 This,
2625 This->storageDirEntry,
2626 entryToDeleteRef);
2627
2628 /*
2629 * Invalidate the entry
2630 */
2631 if (SUCCEEDED(hr))
2632 StorageBaseImpl_DestroyDirEntry(This, entryToDeleteRef);
2633
2634 if (SUCCEEDED(hr))
2636
2637 TRACE("<-- %#lx\n", hr);
2638 return hr;
2639}
2640
2642{
2643 struct list *cur, *cur2;
2644 StgStreamImpl *strm=NULL;
2645 StorageInternalImpl *childstg=NULL;
2646
2647 LIST_FOR_EACH_SAFE(cur, cur2, &stg->strmHead) {
2648 strm = LIST_ENTRY(cur,StgStreamImpl,StrmListEntry);
2649 TRACE("Streams invalidated (stg=%p strm=%p next=%p prev=%p)\n", stg,strm,cur->next,cur->prev);
2650 strm->parentStorage = NULL;
2652 }
2653
2654 LIST_FOR_EACH_SAFE(cur, cur2, &stg->storageHead) {
2655 childstg = LIST_ENTRY(cur,StorageInternalImpl,ParentListEntry);
2656 StorageBaseImpl_Invalidate( &childstg->base );
2657 }
2658
2659 if (stg->transactedChild)
2660 {
2662
2663 stg->transactedChild = NULL;
2664 }
2665}
2666
2667/******************************************************************************
2668 * SetElementTimes (IStorage)
2669 */
2671 IStorage* iface,
2672 const OLECHAR *pwcsName,/* [string][in] */
2673 const FILETIME *pctime, /* [in] */
2674 const FILETIME *patime, /* [in] */
2675 const FILETIME *pmtime) /* [in] */
2676{
2677 FIXME("(%s,...), stub!\n",debugstr_w(pwcsName));
2678 return S_OK;
2679}
2680
2681/******************************************************************************
2682 * SetStateBits (IStorage)
2683 */
2685 IStorage* iface,
2686 DWORD grfStateBits,/* [in] */
2687 DWORD grfMask) /* [in] */
2688{
2690
2691 if (This->reverted)
2692 return STG_E_REVERTED;
2693
2694 This->stateBits = (This->stateBits & ~grfMask) | (grfStateBits & grfMask);
2695 return S_OK;
2696}
2697
2698/******************************************************************************
2699 * Internal stream list handlers
2700 */
2701
2703{
2704 TRACE("Stream added (stg=%p strm=%p)\n", stg, strm);
2705 list_add_tail(&stg->strmHead,&strm->StrmListEntry);
2706}
2707
2709{
2710 TRACE("Stream removed (stg=%p strm=%p)\n", stg,strm);
2711 list_remove(&(strm->StrmListEntry));
2712}
2713
2716 StorageBaseImpl *src, DirRef src_entry)
2717{
2718 HRESULT hr;
2719 BYTE data[4096];
2720 DirEntry srcdata;
2721 ULARGE_INTEGER bytes_copied;
2722 ULONG bytestocopy, bytesread, byteswritten;
2723
2724 hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &srcdata);
2725
2726 if (SUCCEEDED(hr))
2727 {
2729
2730 bytes_copied.QuadPart = 0;
2731 while (bytes_copied.QuadPart < srcdata.size.QuadPart && SUCCEEDED(hr))
2732 {
2733 bytestocopy = min(4096, srcdata.size.QuadPart - bytes_copied.QuadPart);
2734
2735 hr = StorageBaseImpl_StreamReadAt(src, src_entry, bytes_copied, bytestocopy,
2736 data, &bytesread);
2737 if (SUCCEEDED(hr) && bytesread != bytestocopy) hr = STG_E_READFAULT;
2738
2739 if (SUCCEEDED(hr))
2740 hr = StorageBaseImpl_StreamWriteAt(dst, dst_entry, bytes_copied, bytestocopy,
2741 data, &byteswritten);
2742 if (SUCCEEDED(hr))
2743 {
2744 if (byteswritten != bytestocopy) hr = STG_E_WRITEFAULT;
2745 bytes_copied.QuadPart += byteswritten;
2746 }
2747 }
2748 }
2749
2750 return hr;
2751}
2752
2755 StorageBaseImpl *src, DirRef src_entry)
2756{
2757 HRESULT hr;
2758 DirEntry data;
2759 BOOL has_stream=FALSE;
2760
2761 if (src_entry == DIRENTRY_NULL)
2762 {
2764 return S_OK;
2765 }
2766
2767 hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &data);
2768 if (SUCCEEDED(hr))
2769 {
2770 has_stream = (data.stgType == STGTY_STREAM && data.size.QuadPart != 0);
2771 data.startingBlock = BLOCK_END_OF_CHAIN;
2772 data.size.QuadPart = 0;
2773
2774 hr = StorageBaseImpl_DupStorageTree(dst, &data.leftChild, src, data.leftChild);
2775 }
2776
2777 if (SUCCEEDED(hr))
2778 hr = StorageBaseImpl_DupStorageTree(dst, &data.rightChild, src, data.rightChild);
2779
2780 if (SUCCEEDED(hr))
2781 hr = StorageBaseImpl_DupStorageTree(dst, &data.dirRootEntry, src, data.dirRootEntry);
2782
2783 if (SUCCEEDED(hr))
2785
2786 if (SUCCEEDED(hr) && has_stream)
2788
2789 return hr;
2790}
2791
2794 StorageBaseImpl *src, DirRef src_entry)
2795{
2796 HRESULT hr;
2797 DirEntry src_data, dst_data;
2798 DirRef new_root_entry;
2799
2800 hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &src_data);
2801
2802 if (SUCCEEDED(hr))
2803 {
2804 hr = StorageBaseImpl_DupStorageTree(dst, &new_root_entry, src, src_data.dirRootEntry);
2805 }
2806
2807 if (SUCCEEDED(hr))
2808 {
2810 dst_data.clsid = src_data.clsid;
2811 dst_data.ctime = src_data.ctime;
2812 dst_data.mtime = src_data.mtime;
2813 dst_data.dirRootEntry = new_root_entry;
2814 }
2815
2816 if (SUCCEEDED(hr))
2818
2819 return hr;
2820}
2821
2823{
2824 HRESULT hr;
2825 DirEntry data;
2827
2828 if (entry == DIRENTRY_NULL)
2829 return S_OK;
2830
2831 zero.QuadPart = 0;
2832
2834
2835 if (SUCCEEDED(hr) && include_siblings)
2837
2838 if (SUCCEEDED(hr) && include_siblings)
2840
2841 if (SUCCEEDED(hr))
2843
2844 if (SUCCEEDED(hr) && data.stgType == STGTY_STREAM)
2846
2847 if (SUCCEEDED(hr))
2849
2850 return hr;
2851}
2852
2853
2854/************************************************************************
2855 * StorageImpl implementation
2856 ***********************************************************************/
2857
2860 void* buffer,
2861 ULONG size,
2862 ULONG* bytesRead)
2863{
2864 return ILockBytes_ReadAt(This->lockBytes,offset,buffer,size,bytesRead);
2865}
2866
2869 const void* buffer,
2870 const ULONG size,
2872{
2873 return ILockBytes_WriteAt(This->lockBytes,offset,buffer,size,bytesWritten);
2874}
2875
2876/******************************************************************************
2877 * StorageImpl_LoadFileHeader
2878 *
2879 * This method will read in the file header
2880 */
2883{
2884 HRESULT hr;
2885 BYTE headerBigBlock[HEADER_SIZE];
2886 int index;
2888 DWORD bytes_read;
2889
2890 TRACE("\n");
2891 /*
2892 * Get a pointer to the big block of data containing the header.
2893 */
2894 offset.HighPart = 0;
2895 offset.LowPart = 0;
2896 hr = StorageImpl_ReadAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_read);
2897 if (SUCCEEDED(hr) && bytes_read != HEADER_SIZE)
2899
2900 /*
2901 * Extract the information from the header.
2902 */
2903 if (SUCCEEDED(hr))
2904 {
2905 /*
2906 * Check for the "magic number" signature and return an error if it is not
2907 * found.
2908 */
2909 if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
2910 {
2911 return STG_E_OLDFORMAT;
2912 }
2913
2914 if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
2915 {
2916 return STG_E_INVALIDHEADER;
2917 }
2918
2920 headerBigBlock,
2922 &This->bigBlockSizeBits);
2923
2925 headerBigBlock,
2927 &This->smallBlockSizeBits);
2928
2930 headerBigBlock,
2932 &This->bigBlockDepotCount);
2933
2935 headerBigBlock,
2937 &This->rootStartBlock);
2938
2940 headerBigBlock,
2942 &This->transactionSig);
2943
2945 headerBigBlock,
2947 &This->smallBlockLimit);
2948
2950 headerBigBlock,
2952 &This->smallBlockDepotStart);
2953
2955 headerBigBlock,
2957 &This->extBigBlockDepotStart);
2958
2960 headerBigBlock,
2962 &This->extBigBlockDepotCount);
2963
2964 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
2965 {
2967 headerBigBlock,
2968 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
2969 &(This->bigBlockDepotStart[index]));
2970 }
2971
2972 /*
2973 * Make the bitwise arithmetic to get the size of the blocks in bytes.
2974 */
2975 This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits;
2976 This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
2977
2978 /*
2979 * Right now, the code is making some assumptions about the size of the
2980 * blocks, just make sure they are what we're expecting.
2981 */
2982 if ((This->bigBlockSize != MIN_BIG_BLOCK_SIZE && This->bigBlockSize != MAX_BIG_BLOCK_SIZE) ||
2983 This->smallBlockSize != DEF_SMALL_BLOCK_SIZE ||
2984 This->smallBlockLimit != LIMIT_TO_USE_SMALL_BLOCK)
2985 {
2986 FIXME("Broken OLE storage file? bigblock=%#lx, smallblock=%#lx, sblimit=%#lx\n",
2987 This->bigBlockSize, This->smallBlockSize, This->smallBlockLimit);
2989 }
2990 else
2991 hr = S_OK;
2992 }
2993
2994 return hr;
2995}
2996
2997/******************************************************************************
2998 * StorageImpl_SaveFileHeader
2999 *
3000 * This method will save to the file the header
3001 */
3004{
3005 BYTE headerBigBlock[HEADER_SIZE];
3006 int index;
3008 DWORD bytes_written;
3009 DWORD major_version, dirsectorcount;
3010
3011 if (This->bigBlockSizeBits == 0x9)
3012 major_version = 3;
3013 else if (This->bigBlockSizeBits == 0xc)
3014 major_version = 4;
3015 else
3016 {
3017 ERR("invalid big block shift 0x%x\n", This->bigBlockSizeBits);
3018 major_version = 4;
3019 }
3020
3021 memset(headerBigBlock, 0, HEADER_SIZE);
3022 memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
3023
3024 /*
3025 * Write the information to the header.
3026 */
3028 headerBigBlock,
3030 0x3e);
3031
3033 headerBigBlock,
3035 major_version);
3036
3038 headerBigBlock,
3040 (WORD)-2);
3041
3043 headerBigBlock,
3045 This->bigBlockSizeBits);
3046
3048 headerBigBlock,
3050 This->smallBlockSizeBits);
3051
3052 if (major_version >= 4)
3053 {
3054 if (This->rootBlockChain)
3055 dirsectorcount = BlockChainStream_GetCount(This->rootBlockChain);
3056 else
3057 /* This file is being created, and it will start out with one block. */
3058 dirsectorcount = 1;
3059 }
3060 else
3061 /* This field must be 0 in versions older than 4 */
3062 dirsectorcount = 0;
3063
3065 headerBigBlock,
3067 dirsectorcount);
3068
3070 headerBigBlock,
3072 This->bigBlockDepotCount);
3073
3075 headerBigBlock,
3077 This->rootStartBlock);
3078
3080 headerBigBlock,
3082 This->transactionSig);
3083
3085 headerBigBlock,
3087 This->smallBlockLimit);
3088
3090 headerBigBlock,
3092 This->smallBlockDepotStart);
3093
3095 headerBigBlock,
3097 This->smallBlockDepotChain ?
3098 BlockChainStream_GetCount(This->smallBlockDepotChain) : 0);
3099
3101 headerBigBlock,
3103 This->extBigBlockDepotStart);
3104
3106 headerBigBlock,
3108 This->extBigBlockDepotCount);
3109
3110 for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
3111 {
3113 headerBigBlock,
3114 OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
3115 (This->bigBlockDepotStart[index]));
3116 }
3117
3118 offset.QuadPart = 0;
3119 StorageImpl_WriteAt(This, offset, headerBigBlock, HEADER_SIZE, &bytes_written);
3120}
3121
3122
3123/************************************************************************
3124 * StorageImpl implementation : DirEntry methods
3125 ***********************************************************************/
3126
3127/******************************************************************************
3128 * StorageImpl_ReadRawDirEntry
3129 *
3130 * This method will read the raw data from a directory entry in the file.
3131 *
3132 * buffer must be RAW_DIRENTRY_SIZE bytes long.
3133 */
3135{
3137 HRESULT hr;
3138 ULONG bytesRead;
3139
3141
3143 This->rootBlockChain,
3144 offset,
3146 buffer,
3147 &bytesRead);
3148
3149 if (bytesRead != RAW_DIRENTRY_SIZE)
3150 return STG_E_READFAULT;
3151
3152 return hr;
3153}
3154
3155/******************************************************************************
3156 * StorageImpl_WriteRawDirEntry
3157 *
3158 * This method will write the raw data from a directory entry in the file.
3159 *
3160 * buffer must be RAW_DIRENTRY_SIZE bytes long.
3161 */
3163{
3165 ULONG bytesRead;
3166
3168
3170 This->rootBlockChain,
3171 offset,
3173 buffer,
3174 &bytesRead);
3175}
3176
3177/***************************************************************************
3178 *
3179 * Internal Method
3180 *
3181 * Mark a directory entry in the file as free.
3182 */
3185 DirRef index)
3186{
3187 BYTE emptyData[RAW_DIRENTRY_SIZE];
3189
3190 memset(emptyData, 0, RAW_DIRENTRY_SIZE);
3191
3192 return StorageImpl_WriteRawDirEntry(storage, index, emptyData);
3193}
3194
3195/******************************************************************************
3196 * UpdateRawDirEntry
3197 *
3198 * Update raw directory entry data from the fields in newData.
3199 *
3200 * buffer must be RAW_DIRENTRY_SIZE bytes long.
3201 */
3202static void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData)
3203{
3205
3206 memcpy(
3208 newData->name,
3210
3211 memcpy(buffer + OFFSET_PS_STGTYPE, &newData->stgType, 1);
3212
3214 buffer,
3216 newData->sizeOfNameString);
3217
3219 buffer,
3221 newData->leftChild);
3222
3224 buffer,
3226 newData->rightChild);
3227
3229 buffer,
3231 newData->dirRootEntry);
3232
3234 buffer,
3236 &newData->clsid);
3237
3239 buffer,
3241 newData->ctime.dwLowDateTime);
3242
3244 buffer,
3246 newData->ctime.dwHighDateTime);
3247
3249 buffer,
3251 newData->mtime.dwLowDateTime);
3252
3254 buffer,
3256 newData->mtime.dwHighDateTime);
3257
3259 buffer,
3261 newData->startingBlock);
3262
3264 buffer,
3266 newData->size.LowPart);
3267
3269 buffer,
3271 newData->size.HighPart);
3272}
3273
3274/***************************************************************************
3275 *
3276 * Internal Method
3277 *
3278 * Reserve a directory entry in the file and initialize it.
3279 */
3282 const DirEntry *newData,
3283 DirRef *index)
3284{
3286 ULONG currentEntryIndex = 0;
3287 ULONG newEntryIndex = DIRENTRY_NULL;
3288 HRESULT hr = S_OK;
3289 BYTE currentData[RAW_DIRENTRY_SIZE];
3290 WORD sizeOfNameString;
3291
3292 do
3293 {
3295 currentEntryIndex,
3296 currentData);
3297
3298 if (SUCCEEDED(hr))
3299 {
3301 currentData,
3303 &sizeOfNameString);
3304
3305 if (sizeOfNameString == 0)
3306 {
3307 /*
3308 * The entry exists and is available, we found it.
3309 */
3310 newEntryIndex = currentEntryIndex;
3311 }
3312 }
3313 else
3314 {
3315 /*
3316 * We exhausted the directory entries, we will create more space below
3317 */
3318 newEntryIndex = currentEntryIndex;
3319 }
3320 currentEntryIndex++;
3321
3322 } while (newEntryIndex == DIRENTRY_NULL);
3323
3324 /*
3325 * grow the directory stream
3326 */
3327 if (FAILED(hr))
3328 {
3329 BYTE emptyData[RAW_DIRENTRY_SIZE];
3330 ULARGE_INTEGER newSize;
3331 ULONG entryIndex;
3332 ULONG lastEntry = 0;
3333 ULONG blockCount = 0;
3334
3335 /*
3336 * obtain the new count of blocks in the directory stream
3337 */
3338 blockCount = BlockChainStream_GetCount(
3339 storage->rootBlockChain)+1;
3340
3341 /*
3342 * initialize the size used by the directory stream
3343 */
3344 newSize.QuadPart = (ULONGLONG)storage->bigBlockSize * blockCount;
3345
3346 /*
3347 * add a block to the directory stream
3348 */
3349 BlockChainStream_SetSize(storage->rootBlockChain, newSize);
3350
3351 /*
3352 * memset the empty entry in order to initialize the unused newly
3353 * created entries
3354 */
3355 memset(emptyData, 0, RAW_DIRENTRY_SIZE);
3356
3357 /*
3358 * initialize them
3359 */
3360 lastEntry = storage->bigBlockSize / RAW_DIRENTRY_SIZE * blockCount;
3361
3362 for(
3363 entryIndex = newEntryIndex + 1;
3364 entryIndex < lastEntry;
3365 entryIndex++)
3366 {
3368 storage,
3369 entryIndex,
3370 emptyData);
3371 }
3372
3374 }
3375
3376 UpdateRawDirEntry(currentData, newData);
3377
3378 hr = StorageImpl_WriteRawDirEntry(storage, newEntryIndex, currentData);
3379
3380 if (SUCCEEDED(hr))
3381 *index = newEntryIndex;
3382
3383 return hr;
3384}
3385
3386/******************************************************************************
3387 * StorageImpl_ReadDirEntry
3388 *
3389 * This method will read the specified directory entry.
3390 */
3393 DirRef index,
3395{
3396 BYTE currentEntry[RAW_DIRENTRY_SIZE];
3397 HRESULT readRes;
3398
3399 readRes = StorageImpl_ReadRawDirEntry(This, index, currentEntry);
3400
3401 if (SUCCEEDED(readRes))
3402 {
3403 memset(buffer->name, 0, sizeof(buffer->name));
3404 memcpy(
3405 buffer->name,
3406 (WCHAR *)currentEntry+OFFSET_PS_NAME,
3408 TRACE("storage name: %s\n", debugstr_w(buffer->name));
3409
3410 memcpy(&buffer->stgType, currentEntry + OFFSET_PS_STGTYPE, 1);
3411
3413 currentEntry,
3415 &buffer->sizeOfNameString);
3416
3418 currentEntry,
3420 &buffer->leftChild);
3421
3423 currentEntry,
3425 &buffer->rightChild);
3426
3428 currentEntry,
3430 &buffer->dirRootEntry);
3431
3433 currentEntry,
3435 &buffer->clsid);
3436
3438 currentEntry,
3440 &buffer->ctime.dwLowDateTime);
3441
3443 currentEntry,
3445 &buffer->ctime.dwHighDateTime);
3446
3448 currentEntry,
3450 &buffer->mtime.dwLowDateTime);
3451
3453 currentEntry,
3455 &buffer->mtime.dwHighDateTime);
3456
3458 currentEntry,
3460 &buffer->startingBlock);
3461
3463 currentEntry,
3465 &buffer->size.LowPart);
3466
3467 if (This->bigBlockSize < 4096)
3468 {
3469 /* Version 3 files may have junk in the high part of size. */
3470 buffer->size.HighPart = 0;
3471 }
3472 else
3473 {
3475 currentEntry,
3477 &buffer->size.HighPart);
3478 }
3479 }
3480
3481 return readRes;
3482}
3483
3484/*********************************************************************
3485 * Write the specified directory entry to the file
3486 */
3489 DirRef index,
3490 const DirEntry* buffer)
3491{
3492 BYTE currentEntry[RAW_DIRENTRY_SIZE];
3493
3494 UpdateRawDirEntry(currentEntry, buffer);
3495
3496 return StorageImpl_WriteRawDirEntry(This, index, currentEntry);
3497}
3498
3499
3500/************************************************************************
3501 * StorageImpl implementation : Block methods
3502 ***********************************************************************/
3503
3505{
3506 return (ULONGLONG)(index+1) * This->bigBlockSize;
3507}
3508
3511 ULONG blockIndex,
3512 void* buffer,
3513 ULONG* out_read)
3514{
3515 ULARGE_INTEGER ulOffset;
3516 DWORD read=0;
3517 HRESULT hr;
3518
3519 ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3520
3521 hr = StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
3522
3523 if (SUCCEEDED(hr) && read < This->bigBlockSize)
3524 {
3525 /* File ends during this block; fill the rest with 0's. */
3526 memset((LPBYTE)buffer+read, 0, This->bigBlockSize-read);
3527 }
3528
3529 if (out_read) *out_read = read;
3530
3531 return hr;
3532}
3533
3536 ULONG blockIndex,
3537 ULONG offset,
3538 DWORD* value)
3539{
3540 ULARGE_INTEGER ulOffset;
3541 DWORD read;
3542 DWORD tmp;
3543
3544 ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3545 ulOffset.QuadPart += offset;
3546
3547 StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
3548 *value = lendian32toh(tmp);
3549 return (read == sizeof(DWORD));
3550}
3551
3554 ULONG blockIndex,
3555 const void* buffer)
3556{
3557 ULARGE_INTEGER ulOffset;
3558 DWORD wrote;
3559
3560 ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3561
3562 StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
3563 return (wrote == This->bigBlockSize);
3564}
3565
3568 ULONG blockIndex,
3569 ULONG offset,
3570 DWORD value)
3571{
3572 ULARGE_INTEGER ulOffset;
3573 DWORD wrote;
3574
3575 ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This, blockIndex);
3576 ulOffset.QuadPart += offset;
3577
3578 value = htole32(value);
3579 StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
3580 return (wrote == sizeof(DWORD));
3581}
3582
3583/******************************************************************************
3584 * Storage32Impl_SmallBlocksToBigBlocks
3585 *
3586 * This method will convert a small block chain to a big block chain.
3587 * The small block chain will be destroyed.
3588 */
3591 SmallBlockChainStream** ppsbChain)
3592{
3593 ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
3595 ULONG cbRead, cbWritten;
3596 ULARGE_INTEGER cbTotalRead;
3597 DirRef streamEntryRef;
3598 HRESULT resWrite = S_OK;
3599 HRESULT resRead;
3600 DirEntry streamEntry;
3601 BYTE *buffer;
3602 BlockChainStream *bbTempChain = NULL;
3603 BlockChainStream *bigBlockChain = NULL;
3604
3605 /*
3606 * Create a temporary big block chain that doesn't have
3607 * an associated directory entry. This temporary chain will be
3608 * used to copy data from small blocks to big blocks.
3609 */
3610 bbTempChain = BlockChainStream_Construct(This,
3611 &bbHeadOfChain,
3613 if(!bbTempChain) return NULL;
3614 /*
3615 * Grow the big block chain.
3616 */
3617 size = SmallBlockChainStream_GetSize(*ppsbChain);
3618 BlockChainStream_SetSize(bbTempChain, size);
3619
3620 /*
3621 * Copy the contents of the small block chain to the big block chain
3622 * by small block size increments.
3623 */
3624 offset.LowPart = 0;
3625 offset.HighPart = 0;
3626 cbTotalRead.QuadPart = 0;
3627
3629 do
3630 {
3631 resRead = SmallBlockChainStream_ReadAt(*ppsbChain,
3632 offset,
3633 min(This->smallBlockSize, size.LowPart - offset.LowPart),
3634 buffer,
3635 &cbRead);
3636 if (FAILED(resRead))
3637 break;
3638
3639 if (cbRead > 0)
3640 {
3641 cbTotalRead.QuadPart += cbRead;
3642
3643 resWrite = BlockChainStream_WriteAt(bbTempChain,
3644 offset,
3645 cbRead,
3646 buffer,
3647 &cbWritten);
3648
3649 if (FAILED(resWrite))
3650 break;
3651
3652 offset.LowPart += cbRead;
3653 }
3654 else
3655 {
3656 resRead = STG_E_READFAULT;
3657 break;
3658 }
3659 } while (cbTotalRead.QuadPart < size.QuadPart);
3661
3662 size.HighPart = 0;
3663 size.LowPart = 0;
3664
3665 if (FAILED(resRead) || FAILED(resWrite))
3666 {
3667 ERR("conversion failed: resRead = %#lx, resWrite = %#lx\n", resRead, resWrite);
3668 BlockChainStream_SetSize(bbTempChain, size);
3669 BlockChainStream_Destroy(bbTempChain);
3670 return NULL;
3671 }
3672
3673 /*
3674 * Destroy the small block chain.
3675 */
3676 streamEntryRef = (*ppsbChain)->ownerDirEntry;
3679 *ppsbChain = 0;
3680
3681 /*
3682 * Change the directory entry. This chain is now a big block chain
3683 * and it doesn't reside in the small blocks chain anymore.
3684 */
3685 StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
3686
3687 streamEntry.startingBlock = bbHeadOfChain;
3688
3689 StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
3690
3691 /*
3692 * Destroy the temporary entryless big block chain.
3693 * Create a new big block chain associated with this entry.
3694 */
3695 BlockChainStream_Destroy(bbTempChain);
3696 bigBlockChain = BlockChainStream_Construct(This,
3697 NULL,
3698 streamEntryRef);
3699
3700 return bigBlockChain;
3701}
3702
3703/******************************************************************************
3704 * Storage32Impl_BigBlocksToSmallBlocks
3705 *
3706 * This method will convert a big block chain to a small block chain.
3707 * The big block chain will be destroyed on success.
3708 */
3711 BlockChainStream** ppbbChain,
3712 ULARGE_INTEGER newSize)
3713{
3714 ULARGE_INTEGER size, offset, cbTotalRead;
3715 ULONG cbRead, cbWritten, sbHeadOfChain = BLOCK_END_OF_CHAIN;
3716 DirRef streamEntryRef;
3717 HRESULT resWrite = S_OK, resRead = S_OK;
3718 DirEntry streamEntry;
3719 BYTE* buffer;
3720 SmallBlockChainStream* sbTempChain;
3721
3722 TRACE("%p %p\n", This, ppbbChain);
3723
3724 sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain,
3726
3727 if(!sbTempChain)
3728 return NULL;
3729
3730 SmallBlockChainStream_SetSize(sbTempChain, newSize);
3731 size = BlockChainStream_GetSize(*ppbbChain);
3732 size.QuadPart = min(size.QuadPart, newSize.QuadPart);
3733
3734 offset.HighPart = 0;
3735 offset.LowPart = 0;
3736 cbTotalRead.QuadPart = 0;
3737 buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize);
3738 while(cbTotalRead.QuadPart < size.QuadPart)
3739 {
3740 resRead = BlockChainStream_ReadAt(*ppbbChain, offset,
3741 min(This->bigBlockSize, size.LowPart - offset.LowPart),
3742 buffer, &cbRead);
3743
3744 if(FAILED(resRead))
3745 break;
3746
3747 if(cbRead > 0)
3748 {
3749 cbTotalRead.QuadPart += cbRead;
3750
3751 resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset,
3752 cbRead, buffer, &cbWritten);
3753
3754 if(FAILED(resWrite))
3755 break;
3756
3757 offset.LowPart += cbRead;
3758 }
3759 else
3760 {
3761 resRead = STG_E_READFAULT;
3762 break;
3763 }
3764 }
3766
3767 size.HighPart = 0;
3768 size.LowPart = 0;
3769
3770 if(FAILED(resRead) || FAILED(resWrite))
3771 {
3772 ERR("conversion failed: resRead = %#lx, resWrite = %#lx\n", resRead, resWrite);
3773 SmallBlockChainStream_SetSize(sbTempChain, size);
3774 SmallBlockChainStream_Destroy(sbTempChain);
3775 return NULL;
3776 }
3777
3778 /* destroy the original big block chain */
3779 streamEntryRef = (*ppbbChain)->ownerDirEntry;
3780 BlockChainStream_SetSize(*ppbbChain, size);
3781 BlockChainStream_Destroy(*ppbbChain);
3782 *ppbbChain = NULL;
3783
3784 StorageImpl_ReadDirEntry(This, streamEntryRef, &streamEntry);
3785 streamEntry.startingBlock = sbHeadOfChain;
3786 StorageImpl_WriteDirEntry(This, streamEntryRef, &streamEntry);
3787
3788 SmallBlockChainStream_Destroy(sbTempChain);
3789 return SmallBlockChainStream_Construct(This, NULL, streamEntryRef);
3790}
3791
3792/******************************************************************************
3793 * Storage32Impl_AddBlockDepot
3794 *
3795 * This will create a depot block, essentially it is a block initialized
3796 * to BLOCK_UNUSEDs.
3797 */
3798static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex, ULONG depotIndex)
3799{
3800 BYTE blockBuffer[MAX_BIG_BLOCK_SIZE];
3801 ULONG rangeLockIndex = RANGELOCK_FIRST / This->bigBlockSize - 1;
3802 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
3803 ULONG rangeLockDepot = rangeLockIndex / blocksPerDepot;
3804
3805 /*
3806 * Initialize blocks as free
3807 */
3808 memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
3809
3810 /* Reserve the range lock sector */
3811 if (depotIndex == rangeLockDepot)
3812 {
3813 ((ULONG*)blockBuffer)[rangeLockIndex % blocksPerDepot] = BLOCK_END_OF_CHAIN;
3814 }
3815
3816 StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
3817}
3818
3819/******************************************************************************
3820 * Storage32Impl_GetExtDepotBlock
3821 *
3822 * Returns the index of the block that corresponds to the specified depot
3823 * index. This method is only for depot indexes equal or greater than
3824 * COUNT_BBDEPOTINHEADER.
3825 */
3827{
3828 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
3829 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
3830 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
3831 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
3832 ULONG blockIndex = BLOCK_UNUSED;
3833 ULONG extBlockIndex;
3834 BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
3835 int index, num_blocks;
3836
3837 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
3838
3839 if (extBlockCount >= This->extBigBlockDepotCount)
3840 return BLOCK_UNUSED;
3841
3842 if (This->indexExtBlockDepotCached != extBlockCount)
3843 {
3844 extBlockIndex = This->extBigBlockDepotLocations[extBlockCount];
3845
3846 StorageImpl_ReadBigBlock(This, extBlockIndex, depotBuffer, NULL);
3847
3848 num_blocks = This->bigBlockSize / 4;
3849
3850 for (index = 0; index < num_blocks; index++)
3851 {
3852 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), &blockIndex);
3853 This->extBlockDepotCached[index] = blockIndex;
3854 }
3855
3856 This->indexExtBlockDepotCached = extBlockCount;
3857 }
3858
3859 blockIndex = This->extBlockDepotCached[extBlockOffset];
3860
3861 return blockIndex;
3862}
3863
3864/******************************************************************************
3865 * Storage32Impl_SetExtDepotBlock
3866 *
3867 * Associates the specified block index to the specified depot index.
3868 * This method is only for depot indexes equal or greater than
3869 * COUNT_BBDEPOTINHEADER.
3870 */
3871static void Storage32Impl_SetExtDepotBlock(StorageImpl* This, ULONG depotIndex, ULONG blockIndex)
3872{
3873 ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
3874 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
3875 ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock;
3876 ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock;
3877 ULONG extBlockIndex;
3878
3879 assert(depotIndex >= COUNT_BBDEPOTINHEADER);
3880
3881 assert(extBlockCount < This->extBigBlockDepotCount);
3882
3883 extBlockIndex = This->extBigBlockDepotLocations[extBlockCount];
3884
3885 if (extBlockIndex != BLOCK_UNUSED)
3886 {
3888 extBlockOffset * sizeof(ULONG),
3889 blockIndex);
3890 }
3891
3892 if (This->indexExtBlockDepotCached == extBlockCount)
3893 {
3894 This->extBlockDepotCached[extBlockOffset] = blockIndex;
3895 }
3896}
3897
3898/******************************************************************************
3899 * Storage32Impl_AddExtBlockDepot
3900 *
3901 * Creates an extended depot block.
3902 */
3904{
3905 ULONG numExtBlocks = This->extBigBlockDepotCount;
3906 ULONG nextExtBlock = This->extBigBlockDepotStart;
3907 BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
3909 ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
3910 ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
3911 ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
3912
3913 index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
3914 blocksPerDepotBlock;
3915
3916 if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
3917 {
3918 /*
3919 * The first extended block.
3920 */
3921 This->extBigBlockDepotStart = index;
3922 }
3923 else
3924 {
3925 /*
3926 * Find the last existing extended block.
3927 */
3928 nextExtBlock = This->extBigBlockDepotLocations[This->extBigBlockDepotCount-1];
3929
3930 /*
3931 * Add the new extended block to the chain.
3932 */
3933 StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
3934 index);
3935 }
3936
3937 /*
3938 * Initialize this block.
3939 */
3940 memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
3941 StorageImpl_WriteBigBlock(This, index, depotBuffer);
3942
3943 /* Add the block to our cache. */
3944 if (This->extBigBlockDepotLocationsSize == numExtBlocks)
3945 {
3946 ULONG new_cache_size = (This->extBigBlockDepotLocationsSize+1)*2;
3947 ULONG *new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * new_cache_size);
3948
3949 memcpy(new_cache, This->extBigBlockDepotLocations, sizeof(ULONG) * This->extBigBlockDepotLocationsSize);
3950 HeapFree(GetProcessHeap(), 0, This->extBigBlockDepotLocations);
3951
3952 This->extBigBlockDepotLocations = new_cache;
3953 This->extBigBlockDepotLocationsSize = new_cache_size;
3954 }
3955 This->extBigBlockDepotLocations[numExtBlocks] = index;
3956
3957 return index;
3958}
3959
3960/************************************************************************
3961 * StorageImpl_GetNextBlockInChain
3962 *
3963 * This method will retrieve the block index of the next big block in
3964 * in the chain.
3965 *
3966 * Params: This - Pointer to the Storage object.
3967 * blockIndex - Index of the block to retrieve the chain
3968 * for.
3969 * nextBlockIndex - receives the return value.
3970 *
3971 * Returns: This method returns the index of the next block in the chain.
3972 * It will return the constants:
3973 * BLOCK_SPECIAL - If the block given was not part of a
3974 * chain.
3975 * BLOCK_END_OF_CHAIN - If the block given was the last in
3976 * a chain.
3977 * BLOCK_UNUSED - If the block given was not past of a chain
3978 * and is available.
3979 * BLOCK_EXTBBDEPOT - This block is part of the extended
3980 * big block depot.
3981 *
3982 * See Windows documentation for more details on IStorage methods.
3983 */
3986 ULONG blockIndex,
3987 ULONG* nextBlockIndex)
3988{
3989 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
3990 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
3991 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
3992 BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
3993 ULONG read;
3994 ULONG depotBlockIndexPos;
3995 int index, num_blocks;
3996
3997 *nextBlockIndex = BLOCK_SPECIAL;
3998
3999 if(depotBlockCount >= This->bigBlockDepotCount)
4000 {
4001 WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount, This->bigBlockDepotCount);
4002 return STG_E_READFAULT;
4003 }
4004
4005 /*
4006 * Cache the currently accessed depot block.
4007 */
4008 if (depotBlockCount != This->indexBlockDepotCached)
4009 {
4010 This->indexBlockDepotCached = depotBlockCount;
4011
4012 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
4013 {
4014 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
4015 }
4016 else
4017 {
4018 /*
4019 * We have to look in the extended depot.
4020 */
4021 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
4022 }
4023
4024 StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer, &read);
4025
4026 if (!read)
4027 return STG_E_READFAULT;
4028
4029 num_blocks = This->bigBlockSize / 4;
4030
4031 for (index = 0; index < num_blocks; index++)
4032 {
4033 StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
4034 This->blockDepotCached[index] = *nextBlockIndex;
4035 }
4036 }
4037
4038 *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
4039
4040 return S_OK;
4041}
4042
4043/******************************************************************************
4044 * Storage32Impl_GetNextExtendedBlock
4045 *
4046 * Given an extended block this method will return the next extended block.
4047 *
4048 * NOTES:
4049 * The last ULONG of an extended block is the block index of the next
4050 * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
4051 * depot.
4052 *
4053 * Return values:
4054 * - The index of the next extended block
4055 * - BLOCK_UNUSED: there is no next extended block.
4056 * - Any other return values denotes failure.
4057 */
4059{
4060 ULONG nextBlockIndex = BLOCK_SPECIAL;
4061 ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
4062
4063 StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
4064 &nextBlockIndex);
4065
4066 return nextBlockIndex;
4067}
4068
4069/******************************************************************************
4070 * StorageImpl_SetNextBlockInChain
4071 *
4072 * This method will write the index of the specified block's next block
4073 * in the big block depot.
4074 *
4075 * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
4076 * do the following
4077 *
4078 * StorageImpl_SetNextBlockInChain(This, 3, 1);
4079 * StorageImpl_SetNextBlockInChain(This, 1, 7);
4080 * StorageImpl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
4081 *
4082 */
4085 ULONG blockIndex,
4086 ULONG nextBlock)
4087{
4088 ULONG offsetInDepot = blockIndex * sizeof (ULONG);
4089 ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
4090 ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
4091 ULONG depotBlockIndexPos;
4092
4093 assert(depotBlockCount < This->bigBlockDepotCount);
4094 assert(blockIndex != nextBlock);
4095
4096 if (blockIndex == (RANGELOCK_FIRST / This->bigBlockSize) - 1)
4097 /* This should never happen (storage file format spec forbids it), but
4098 * older versions of Wine may have generated broken files. We don't want to
4099 * assert and potentially lose data, but we do want to know if this ever
4100 * happens in a newly-created file. */
4101 ERR("Using range lock page\n");
4102
4103 if (depotBlockCount < COUNT_BBDEPOTINHEADER)
4104 {
4105 depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
4106 }
4107 else
4108 {
4109 /*
4110 * We have to look in the extended depot.
4111 */
4112 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
4113 }
4114
4115 StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
4116 nextBlock);
4117 /*
4118 * Update the cached block depot, if necessary.
4119 */
4120 if (depotBlockCount == This->indexBlockDepotCached)
4121 {
4122 This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
4123 }
4124}
4125
4126/******************************************************************************
4127 * StorageImpl_GetNextFreeBigBlock
4128 *
4129 * Returns the index of the next free big block.
4130 * If the big block depot is filled, this method will enlarge it.
4131 *
4132 */
4134 StorageImpl* This, ULONG neededAddNumBlocks)
4135{
4136 ULONG depotBlockIndexPos;
4137 BYTE depotBuffer[MAX_BIG_BLOCK_SIZE];
4138 ULONG depotBlockOffset;
4139 ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
4140 ULONG nextBlockIndex = BLOCK_SPECIAL;
4141 int depotIndex = 0;
4142 ULONG freeBlock = BLOCK_UNUSED;
4143 ULONG read;
4144 ULARGE_INTEGER neededSize;
4145 STATSTG statstg;
4146
4147 depotIndex = This->prevFreeBlock / blocksPerDepot;
4148 depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
4149
4150 /*
4151 * Scan the entire big block depot until we find a block marked free
4152 */
4153 while (nextBlockIndex != BLOCK_UNUSED)
4154 {
4155 if (depotIndex < COUNT_BBDEPOTINHEADER)
4156 {
4157 depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
4158
4159 /*
4160 * Grow the primary depot.
4161 */
4162 if (depotBlockIndexPos == BLOCK_UNUSED)
4163 {
4164 depotBlockIndexPos = depotIndex*blocksPerDepot;
4165
4166 /*
4167 * Add a block depot.
4168 */
4169 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos, depotIndex);
4170 This->bigBlockDepotCount++;
4171 This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
4172
4173 /*
4174 * Flag it as a block depot.
4175 */
4177 depotBlockIndexPos,
4179
4180 /* Save new header information.
4181 */
4183 }
4184 }
4185 else
4186 {
4187 depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
4188
4189 if (depotBlockIndexPos == BLOCK_UNUSED)
4190 {
4191 /*
4192 * Grow the extended depot.
4193 */
4194 ULONG extIndex = BLOCK_UNUSED;
4195 ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER;
4196 ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
4197
4198 if (extBlockOffset == 0)
4199 {
4200 /* We need an extended block.
4201 */
4203 This->extBigBlockDepotCount++;
4204 depotBlockIndexPos = extIndex + 1;
4205 }
4206 else
4207 depotBlockIndexPos = depotIndex * blocksPerDepot;
4208
4209 /*
4210 * Add a block depot and mark it in the extended block.
4211 */
4212 Storage32Impl_AddBlockDepot(This, depotBlockIndexPos, depotIndex);
4213 This->bigBlockDepotCount++;
4214 Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
4215
4216 /* Flag the block depot.
4217 */
4219 depotBlockIndexPos,
4221
4222 /* If necessary, flag the extended depot block.
4223 */
4224 if (extIndex != BLOCK_UNUSED)
4226
4227 /* Save header information.
4228 */
4230 }
4231 }
4232
4233 StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer, &read);
4234
4235 if (read)
4236 {
4237 while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
4238 ( nextBlockIndex != BLOCK_UNUSED))
4239 {
4240 StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
4241
4242 if (nextBlockIndex == BLOCK_UNUSED)
4243 {
4244 freeBlock = (depotIndex * blocksPerDepot) +
4245 (depotBlockOffset/sizeof(ULONG));
4246 }
4247
4248 depotBlockOffset += sizeof(ULONG);
4249 }
4250 }
4251
4252 depotIndex++;
4253 depotBlockOffset = 0;
4254 }
4255
4256 /*
4257 * make sure that the block physically exists before using it
4258 */
4259 neededSize.QuadPart = StorageImpl_GetBigBlockOffset(This, freeBlock)+This->bigBlockSize * neededAddNumBlocks;
4260
4261 ILockBytes_Stat(This->lockBytes, &statstg, STATFLAG_NONAME);
4262
4263 if (neededSize.QuadPart > statstg.cbSize.QuadPart)
4264 ILockBytes_SetSize(This->lockBytes, neededSize);
4265
4266 This->prevFreeBlock = freeBlock;
4267
4268 return freeBlock;
4269}
4270
4271/******************************************************************************
4272 * StorageImpl_FreeBigBlock
4273 *
4274 * This method will flag the specified block as free in the big block depot.
4275 */
4278 ULONG blockIndex)
4279{
4281
4282 if (blockIndex < This->prevFreeBlock)
4283 This->prevFreeBlock = blockIndex;
4284}
4285
4286
4288 DirRef index, const DirEntry *data)
4289{
4292}
4293
4296{
4299}
4300
4302{
4303 int i;
4304
4305 for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
4306 {
4307 if (!This->blockChainCache[i])
4308 {
4309 return &This->blockChainCache[i];
4310 }
4311 }
4312
4313 i = This->blockChainToEvict;
4314
4315 BlockChainStream_Destroy(This->blockChainCache[i]);
4316 This->blockChainCache[i] = NULL;
4317
4318 This->blockChainToEvict++;
4319 if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE)
4320 This->blockChainToEvict = 0;
4321
4322 return &This->blockChainCache[i];
4323}
4324
4326 DirRef index)
4327{
4328 int i, free_index=-1;
4329
4330 for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
4331 {
4332 if (!This->blockChainCache[i])
4333 {
4334 if (free_index == -1) free_index = i;
4335 }
4336 else if (This->blockChainCache[i]->ownerDirEntry == index)
4337 {
4338 return &This->blockChainCache[i];
4339 }
4340 }
4341
4342 if (free_index == -1)
4343 {
4344 free_index = This->blockChainToEvict;
4345
4346 BlockChainStream_Destroy(This->blockChainCache[free_index]);
4347 This->blockChainCache[free_index] = NULL;
4348
4349 This->blockChainToEvict++;
4350 if (This->blockChainToEvict == BLOCKCHAIN_CACHE_SIZE)
4351 This->blockChainToEvict = 0;
4352 }
4353
4354 This->blockChainCache[free_index] = BlockChainStream_Construct(This, NULL, index);
4355 return &This->blockChainCache[free_index];
4356}
4357
4359{
4360 int i;
4361
4362 for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
4363 {
4364 if (This->blockChainCache[i] && This->blockChainCache[i]->ownerDirEntry == index)
4365 {
4366 BlockChainStream_Destroy(This->blockChainCache[i]);
4367 This->blockChainCache[i] = NULL;
4368 return;
4369 }
4370 }
4371}
4372
4374 ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
4375{
4377 DirEntry data;
4378 HRESULT hr;
4379 ULONG bytesToRead;
4380
4382 if (FAILED(hr)) return hr;
4383
4384 if (data.size.QuadPart == 0)
4385 {
4386 *bytesRead = 0;
4387 return S_OK;
4388 }
4389
4390 if (offset.QuadPart + size > data.size.QuadPart)
4391 {
4392 bytesToRead = data.size.QuadPart - offset.QuadPart;
4393 }
4394 else
4395 {
4396 bytesToRead = size;
4397 }
4398
4399 if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
4400 {
4402
4404 if (!stream) return E_OUTOFMEMORY;
4405
4406 hr = SmallBlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead);
4407
4409
4410 return hr;
4411 }
4412 else
4413 {
4415
4417 if (!stream) return E_OUTOFMEMORY;
4418
4419 hr = BlockChainStream_ReadAt(stream, offset, bytesToRead, buffer, bytesRead);
4420
4421 return hr;
4422 }
4423}
4424
4426 ULARGE_INTEGER newsize)
4427{
4429 DirEntry data;
4430 HRESULT hr;
4431 SmallBlockChainStream *smallblock=NULL;
4432 BlockChainStream **pbigblock=NULL, *bigblock=NULL;
4433
4435 if (FAILED(hr)) return hr;
4436
4437 /* In simple mode keep the stream size above the small block limit */
4438 if (This->base.openFlags & STGM_SIMPLE)
4439 newsize.QuadPart = max(newsize.QuadPart, LIMIT_TO_USE_SMALL_BLOCK);
4440
4441 if (data.size.QuadPart == newsize.QuadPart)
4442 return S_OK;
4443
4444 /* Create a block chain object of the appropriate type */
4445 if (data.size.QuadPart == 0)
4446 {
4447 if (newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
4448 {
4450 if (!smallblock) return E_OUTOFMEMORY;
4451 }
4452 else
4453 {
4455 bigblock = *pbigblock;
4456 if (!bigblock) return E_OUTOFMEMORY;
4457 }
4458 }
4459 else if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
4460 {
4462 if (!smallblock) return E_OUTOFMEMORY;
4463 }
4464 else
4465 {
4467 bigblock = *pbigblock;
4468 if (!bigblock) return E_OUTOFMEMORY;
4469 }
4470
4471 /* Change the block chain type if necessary. */
4472 if (smallblock && newsize.QuadPart >= LIMIT_TO_USE_SMALL_BLOCK)
4473 {
4474 bigblock = Storage32Impl_SmallBlocksToBigBlocks(This, &smallblock);
4475 if (!bigblock)
4476 {
4478 return E_FAIL;
4479 }
4480
4482 *pbigblock = bigblock;
4483 }
4484 else if (bigblock && newsize.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
4485 {
4486 smallblock = Storage32Impl_BigBlocksToSmallBlocks(This, pbigblock, newsize);
4487 if (!smallblock)
4488 return E_FAIL;
4489 }
4490
4491 /* Set the size of the block chain. */
4492 if (smallblock)
4493 {
4494 SmallBlockChainStream_SetSize(smallblock, newsize);
4496 }
4497 else
4498 {
4499 BlockChainStream_SetSize(bigblock, newsize);
4500 }
4501
4502 /* Set the size in the directory entry. */
4504 if (SUCCEEDED(hr))
4505 {
4506 data.size = newsize;
4507
4509 }
4510 return hr;
4511}
4512
4515{
4517 DirEntry data;
4518 HRESULT hr;
4519 ULARGE_INTEGER newSize;
4520
4522 if (FAILED(hr)) return hr;
4523
4524 /* Grow the stream if necessary */
4525 newSize.QuadPart = offset.QuadPart + size;
4526
4527 if (newSize.QuadPart > data.size.QuadPart)
4528 {
4530 if (FAILED(hr))
4531 return hr;
4532
4534 if (FAILED(hr)) return hr;
4535 }
4536
4537 if (data.size.QuadPart < LIMIT_TO_USE_SMALL_BLOCK)
4538 {
4540
4542 if (!stream) return E_OUTOFMEMORY;
4543
4545
4547
4548 return hr;
4549 }
4550 else
4551 {
4553
4555 if (!stream) return E_OUTOFMEMORY;
4556
4558 }
4559}
4560
4562 DirRef src)
4563{
4565 DirEntry dst_data, src_data;
4566 HRESULT hr;
4567
4568 hr = StorageImpl_ReadDirEntry(This, dst, &dst_data);
4569
4570 if (SUCCEEDED(hr))
4571 hr = StorageImpl_ReadDirEntry(This, src, &src_data);
4572
4573 if (SUCCEEDED(hr))
4574 {
4576 dst_data.startingBlock = src_data.startingBlock;
4577 dst_data.size = src_data.size;
4578
4579 hr = StorageImpl_WriteDirEntry(This, dst, &dst_data);
4580 }
4581
4582 return hr;
4583}
4584
4586{
4587 HRESULT hr=S_OK;
4588 DirEntry currentEntry;
4589 DirRef currentEntryRef;
4590 BlockChainStream *blockChainStream;
4591
4592 if (create)
4593 {
4595 BYTE bigBlockBuffer[MAX_BIG_BLOCK_SIZE];
4596
4597 /* Discard any existing data. */
4598 size.QuadPart = 0;
4599 ILockBytes_SetSize(This->lockBytes, size);
4600
4601 /*
4602 * Initialize all header variables:
4603 * - The big block depot consists of one block and it is at block 0
4604 * - The directory table starts at block 1
4605 * - There is no small block depot
4606 */
4607 memset( This->bigBlockDepotStart,
4609 sizeof(This->bigBlockDepotStart));
4610
4611 This->bigBlockDepotCount = 1;
4612 This->bigBlockDepotStart[0] = 0;
4613 This->rootStartBlock = 1;
4614 This->smallBlockLimit = LIMIT_TO_USE_SMALL_BLOCK;
4615 This->smallBlockDepotStart = BLOCK_END_OF_CHAIN;
4616 if (This->bigBlockSize == 4096)
4617 This->bigBlockSizeBits = MAX_BIG_BLOCK_SIZE_BITS;
4618 else
4619 This->bigBlockSizeBits = MIN_BIG_BLOCK_SIZE_BITS;
4620 This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS;
4621 This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
4622 This->extBigBlockDepotCount = 0;
4623
4625
4626 /*
4627 * Add one block for the big block depot and one block for the directory table
4628 */
4629 size.HighPart = 0;
4630 size.LowPart = This->bigBlockSize * 3;
4631 ILockBytes_SetSize(This->lockBytes, size);
4632
4633 /*
4634 * Initialize the big block depot
4635 */
4636 memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
4637 StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
4638 StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
4639 StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
4640 }
4641 else
4642 {
4643 /*
4644 * Load the header for the file.
4645 */
4647
4648 if (FAILED(hr))
4649 {
4650 return hr;
4651 }
4652 }
4653
4654 /*
4655 * There is no block depot cached yet.
4656 */
4657 This->indexBlockDepotCached = 0xFFFFFFFF;
4658 This->indexExtBlockDepotCached = 0xFFFFFFFF;
4659
4660 /*
4661 * Start searching for free blocks with block 0.
4662 */
4663 This->prevFreeBlock = 0;
4664
4665 This->firstFreeSmallBlock = 0;
4666
4667 /* Read the extended big block depot locations. */
4668 if (This->extBigBlockDepotCount != 0)
4669 {
4670 ULONG current_block = This->extBigBlockDepotStart;
4671 ULONG cache_size = This->extBigBlockDepotCount * 2;
4672 ULONG i;
4673
4674 This->extBigBlockDepotLocations = HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * cache_size);
4675 if (!This->extBigBlockDepotLocations)
4676 {
4677 return E_OUTOFMEMORY;
4678 }
4679
4680 This->extBigBlockDepotLocationsSize = cache_size;
4681
4682 for (i=0; i<This->extBigBlockDepotCount; i++)
4683 {
4684 if (current_block == BLOCK_END_OF_CHAIN)
4685 {
4686 WARN("File has too few extended big block depot blocks.\n");
4687 return STG_E_DOCFILECORRUPT;
4688 }
4689 This->extBigBlockDepotLocations[i] = current_block;
4690 current_block = Storage32Impl_GetNextExtendedBlock(This, current_block);
4691 }
4692 }
4693 else
4694 {
4695 This->extBigBlockDepotLocations = NULL;
4696 This->extBigBlockDepotLocationsSize = 0;
4697 }
4698
4699 /*
4700 * Create the block chain abstractions.
4701 */
4702 if(!(blockChainStream =
4704 {
4705 return STG_E_READFAULT;
4706 }
4707 if (!new_object)
4708 BlockChainStream_Destroy(This->rootBlockChain);
4709 This->rootBlockChain = blockChainStream;
4710
4711 if(!(blockChainStream =
4712 BlockChainStream_Construct(This, &This->smallBlockDepotStart,
4713 DIRENTRY_NULL)))
4714 {
4715 return STG_E_READFAULT;
4716 }
4717 if (!new_object)
4718 BlockChainStream_Destroy(This->smallBlockDepotChain);
4719 This->smallBlockDepotChain = blockChainStream;
4720
4721 /*
4722 * Write the root storage entry (memory only)
4723 */
4724 if (create)
4725 {
4726 DirEntry rootEntry;
4727 /*
4728 * Initialize the directory table
4729 */
4730 memset(&rootEntry, 0, sizeof(rootEntry));
4731 lstrcpyW(rootEntry.name, L"Root Entry");
4732 rootEntry.sizeOfNameString = sizeof(L"Root Entry");
4733 rootEntry.stgType = STGTY_ROOT;
4734 rootEntry.leftChild = DIRENTRY_NULL;
4735 rootEntry.rightChild = DIRENTRY_NULL;
4736 rootEntry.dirRootEntry = DIRENTRY_NULL;
4738 rootEntry.size.HighPart = 0;
4739 rootEntry.size.LowPart = 0;
4740
4741 StorageImpl_WriteDirEntry(This, 0, &rootEntry);
4742 }
4743
4744 /*
4745 * Find the ID of the root storage.
4746 */
4747 currentEntryRef = 0;
4748
4749 do
4750 {
4752 This,
4753 currentEntryRef,
4754 &currentEntry);
4755
4756 if (SUCCEEDED(hr))
4757 {
4758 if ( (currentEntry.sizeOfNameString != 0 ) &&
4759 (currentEntry.stgType == STGTY_ROOT) )
4760 {
4761 This->base.storageDirEntry = currentEntryRef;
4762 }
4763 }
4764
4765 currentEntryRef++;
4766
4767 } while (SUCCEEDED(hr) && (This->base.storageDirEntry == DIRENTRY_NULL) );
4768
4769 if (FAILED(hr))
4770 {
4771 return STG_E_READFAULT;
4772 }
4773
4774 /*
4775 * Create the block chain abstraction for the small block root chain.
4776 */
4777 if(!(blockChainStream =
4778 BlockChainStream_Construct(This, NULL, This->base.storageDirEntry)))
4779 {
4780 return STG_E_READFAULT;
4781 }
4782 if (!new_object)
4783 BlockChainStream_Destroy(This->smallBlockRootChain);
4784 This->smallBlockRootChain = blockChainStream;
4785
4786 if (!new_object)
4787 {
4788 int i;
4789 for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
4790 {
4791 BlockChainStream_Destroy(This->blockChainCache[i]);
4792 This->blockChainCache[i] = NULL;
4793 }
4794 }
4795
4796 return hr;
4797}
4798
4800 ULONG* result, BOOL refresh)
4801{
4803 HRESULT hr=S_OK;
4804 DWORD oldTransactionSig = This->transactionSig;
4805
4806 if (refresh)
4807 {
4809 ULONG bytes_read;
4810 BYTE data[4];
4811
4812 offset.HighPart = 0;
4813 offset.LowPart = OFFSET_TRANSACTIONSIG;
4814 hr = StorageImpl_ReadAt(This, offset, data, 4, &bytes_read);
4815
4816 if (SUCCEEDED(hr))
4817 {
4818 StorageUtl_ReadDWord(data, 0, &This->transactionSig);
4819
4820 if (oldTransactionSig != This->transactionSig)
4821 {
4822 /* Someone else wrote to this, so toss all cached information. */
4823 TRACE("signature changed\n");
4824
4826 }
4827
4828 if (FAILED(hr))
4829 This->transactionSig = oldTransactionSig;
4830 }
4831 }
4832
4833 *result = This->transactionSig;
4834
4835 return hr;
4836}
4837
4839 ULONG value)
4840{
4842
4843 This->transactionSig = value;
4845
4846 return S_OK;
4847}
4848
4850 ULARGE_INTEGER cb, DWORD dwLockType, BOOL *supported)
4851{
4852 if ((dwLockType & This->locks_supported) == 0)
4853 {
4854 if (supported) *supported = FALSE;
4855 return S_OK;
4856 }
4857
4858 if (supported) *supported = TRUE;
4859 return ILockBytes_LockRegion(This->lockBytes, offset, cb, dwLockType);
4860}
4861
4863 ULARGE_INTEGER cb, DWORD dwLockType)
4864{
4865 if ((dwLockType & This->locks_supported) == 0)
4866 return S_OK;
4867
4868 return ILockBytes_UnlockRegion(This->lockBytes, offset, cb, dwLockType);
4869}
4870
4871/* Internal function */
4873 ULARGE_INTEGER cb, DWORD dwLockType, BOOL *supported)
4874{
4875 HRESULT hr;
4876 int delay = 0;
4877 DWORD start_time = GetTickCount();
4878 DWORD last_sanity_check = start_time;
4879 ULARGE_INTEGER sanity_offset, sanity_cb;
4880
4881 sanity_offset.QuadPart = RANGELOCK_UNK1_FIRST;
4883
4884 do
4885 {
4886 hr = StorageImpl_LockRegion(This, offset, cb, dwLockType, supported);
4887
4889 {
4890 DWORD current_time = GetTickCount();
4891 if (current_time - start_time >= 20000)
4892 {
4893 /* timeout */
4894 break;
4895 }
4896 if (current_time - last_sanity_check >= 500)
4897 {
4898 /* Any storage implementation with the file open in a
4899 * shared mode should not lock these bytes for writing. However,
4900 * some programs (LibreOffice Writer) will keep ALL bytes locked
4901 * when opening in exclusive mode. We can use a read lock to
4902 * detect this case early, and not hang a full 20 seconds.
4903 *
4904 * This can collide with another attempt to open the file in
4905 * exclusive mode, but it's unlikely, and someone would fail anyway. */
4906 hr = StorageImpl_LockRegion(This, sanity_offset, sanity_cb, WINE_LOCK_READ, NULL);
4908 break;
4909 if (SUCCEEDED(hr))
4910 {
4911 StorageImpl_UnlockRegion(This, sanity_offset, sanity_cb, WINE_LOCK_READ);
4913 }
4914
4915 last_sanity_check = current_time;
4916 }
4917 Sleep(delay);
4918 if (delay < 150) delay++;
4919 }
4920 } while (hr == STG_E_ACCESSDENIED || hr == STG_E_LOCKVIOLATION);
4921
4922 return hr;
4923}
4924
4926{
4928 HRESULT hr;
4930
4931 if (write)
4932 {
4933 /* Synchronous grab of second priority range, the commit lock, and the
4934 * lock-checking lock. */
4937 }
4938 else
4939 {
4940 offset.QuadPart = RANGELOCK_COMMIT;
4941 cb.QuadPart = 1;
4942 }
4943
4944 hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE, NULL);
4945
4946 return hr;
4947}
4948
4950{
4952 HRESULT hr;
4954
4955 if (write)
4956 {
4959 }
4960 else
4961 {
4962 offset.QuadPart = RANGELOCK_COMMIT;
4963 cb.QuadPart = 1;
4964 }
4965
4966 hr = StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
4967
4968 return hr;
4969}
4970
4972{
4973 StorageImpl *This = (StorageImpl*) iface;
4974 STATSTG statstg;
4975 HRESULT hr;
4976
4977 hr = ILockBytes_Stat(This->lockBytes, &statstg, 0);
4978
4979 *result = statstg.pwcsName;
4980
4981 return hr;
4982}
4983
4985 ULONG end, HRESULT fail_hr)
4986{
4987 HRESULT hr;
4989
4990 offset.QuadPart = start;
4991 cb.QuadPart = 1 + end - start;
4992
4993 hr = StorageImpl_LockRegion(This, offset, cb, LOCK_ONLYONCE, NULL);
4994 if (SUCCEEDED(hr)) StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
4995
4996 if (FAILED(hr))
4997 return fail_hr;
4998 else
4999 return S_OK;
5000}
5001
5003{
5004 HRESULT hr=S_OK;
5005 int i, j;
5007
5008 cb.QuadPart = 1;
5009
5010 for (i=start; i<=end; i++)
5011 {
5012 offset.QuadPart = i;
5013 hr = StorageImpl_LockRegion(This, offset, cb, LOCK_ONLYONCE, NULL);
5015 break;
5016 }
5017
5018 if (SUCCEEDED(hr))
5019 {
5020 for (j = 0; j < ARRAY_SIZE(This->locked_bytes); j++)
5021 {
5022 if (This->locked_bytes[j] == 0)
5023 {
5024 This->locked_bytes[j] = i;
5025 break;
5026 }
5027 }
5028 }
5029
5030 return hr;
5031}
5032
5034{
5035 HRESULT hr;
5038 DWORD share_mode = STGM_SHARE_MODE(openFlags);
5039 BOOL supported, ro_denyw;
5040
5041 if (openFlags & STGM_NOSNAPSHOT)
5042 {
5043 /* STGM_NOSNAPSHOT implies deny write */
5044 if (share_mode == STGM_SHARE_DENY_READ) share_mode = STGM_SHARE_EXCLUSIVE;
5045 else if (share_mode != STGM_SHARE_EXCLUSIVE) share_mode = STGM_SHARE_DENY_WRITE;
5046 }
5047
5048 ro_denyw = (STGM_ACCESS_MODE(openFlags) == STGM_READ) && (share_mode == STGM_SHARE_DENY_WRITE);
5049
5050 /* Wrap all other locking inside a single lock so we can check ranges safely */
5051 offset.QuadPart = RANGELOCK_CHECKLOCKS;
5052 cb.QuadPart = 1;
5053 hr = StorageImpl_LockRegionSync(This, offset, cb, LOCK_ONLYONCE, &supported);
5054
5055 /* If the ILockBytes doesn't support locking that's ok. */
5056 if (!supported) return S_OK;
5057 else if (FAILED(hr)) return hr;
5058
5059 hr = S_OK;
5060
5061 /* First check for any conflicting locks. */
5062 if ((openFlags & STGM_PRIORITY) == STGM_PRIORITY)
5064
5065 if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_WRITE))
5067
5068 if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_READ))
5070
5071 if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_READ || share_mode == STGM_SHARE_EXCLUSIVE))
5073
5074 if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_WRITE || share_mode == STGM_SHARE_EXCLUSIVE))
5076
5077 if (SUCCEEDED(hr) && STGM_ACCESS_MODE(openFlags) == STGM_READ && share_mode == STGM_SHARE_EXCLUSIVE)
5078 {
5080
5081 if (SUCCEEDED(hr))
5083 }
5084
5085 /* Then grab our locks. */
5086 if (SUCCEEDED(hr) && (openFlags & STGM_PRIORITY) == STGM_PRIORITY)
5087 {
5089 if (SUCCEEDED(hr))
5091 }
5092
5093 if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_WRITE) && !ro_denyw)
5095
5096 if (SUCCEEDED(hr) && (STGM_ACCESS_MODE(openFlags) != STGM_READ))
5098
5099 if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_READ || share_mode == STGM_SHARE_EXCLUSIVE))
5101
5102 if (SUCCEEDED(hr) && (share_mode == STGM_SHARE_DENY_WRITE || share_mode == STGM_SHARE_EXCLUSIVE) && !ro_denyw)
5104
5105 if (SUCCEEDED(hr) && (openFlags & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT)
5107
5108 offset.QuadPart = RANGELOCK_CHECKLOCKS;
5109 cb.QuadPart = 1;
5110 StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
5111
5112 return hr;
5113}
5114
5116{
5118 int i;
5119 HRESULT hr;
5120 TRACE("(%p)\n", This);
5121
5122 hr = BlockChainStream_Flush(This->smallBlockRootChain);
5123
5124 if (SUCCEEDED(hr))
5125 hr = BlockChainStream_Flush(This->rootBlockChain);
5126
5127 if (SUCCEEDED(hr))
5128 hr = BlockChainStream_Flush(This->smallBlockDepotChain);
5129
5130 for (i=0; SUCCEEDED(hr) && i<BLOCKCHAIN_CACHE_SIZE; i++)
5131 if (This->blockChainCache[i])
5132 hr = BlockChainStream_Flush(This->blockChainCache[i]);
5133
5134 if (SUCCEEDED(hr))
5135 hr = ILockBytes_Flush(This->lockBytes);
5136
5137 return hr;
5138}
5139
5141{
5142 StorageImpl *This = (StorageImpl*) iface;
5143
5145
5146 This->base.reverted = TRUE;
5147}
5148
5150{
5151 StorageImpl *This = (StorageImpl*) iface;
5152 int i;
5153 TRACE("(%p)\n", This);
5154
5155 StorageImpl_Flush(iface);
5156
5158
5159 HeapFree(GetProcessHeap(), 0, This->extBigBlockDepotLocations);
5160
5161 BlockChainStream_Destroy(This->smallBlockRootChain);
5162 BlockChainStream_Destroy(This->rootBlockChain);
5163 BlockChainStream_Destroy(This->smallBlockDepotChain);
5164
5165 for (i = 0; i < BLOCKCHAIN_CACHE_SIZE; i++)
5166 BlockChainStream_Destroy(This->blockChainCache[i]);
5167
5168 for (i = 0; i < ARRAY_SIZE(This->locked_bytes); i++)
5169 {
5171 cb.QuadPart = 1;
5172 if (This->locked_bytes[i] != 0)
5173 {
5174 offset.QuadPart = This->locked_bytes[i];
5175 StorageImpl_UnlockRegion(This, offset, cb, LOCK_ONLYONCE);
5176 }
5177 }
5178
5179 if (This->lockBytes)
5180 ILockBytes_Release(This->lockBytes);
5182}
5183
5184
5186{
5203};
5204
5205
5206/*
5207 * Virtual function table for the IStorageBaseImpl class.
5208 */
5209static const IStorageVtbl StorageImpl_Vtbl =
5210{
5229};
5230
5232 HANDLE hFile,
5233 LPCOLESTR pwcsName,
5234 ILockBytes* pLkbyt,
5235 DWORD openFlags,
5236 BOOL fileBased,
5237 BOOL create,
5240{
5242 HRESULT hr = S_OK;
5243 STATSTG stat;
5244
5245 if ( FAILED( validateSTGM(openFlags) ))
5246 return STG_E_INVALIDFLAG;
5247
5248 This = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
5249 if (!This)
5250 return E_OUTOFMEMORY;
5251
5252 memset(This, 0, sizeof(StorageImpl));
5253
5254 list_init(&This->base.strmHead);
5255
5256 list_init(&This->base.storageHead);
5257
5258 This->base.IStorage_iface.lpVtbl = &StorageImpl_Vtbl;
5259 This->base.IPropertySetStorage_iface.lpVtbl = &IPropertySetStorage_Vtbl;
5260 This->base.IDirectWriterLock_iface.lpVtbl = &DirectWriterLockVtbl;
5261 This->base.baseVtbl = &StorageImpl_BaseVtbl;
5262 This->base.openFlags = (openFlags & ~STGM_CREATE);
5263 This->base.ref = 1;
5264 This->base.create = create;
5265
5267 This->base.lockingrole = SWMR_Writer;
5269 This->base.lockingrole = SWMR_Reader;
5270 else
5271 This->base.lockingrole = SWMR_None;
5272
5273 This->base.reverted = FALSE;
5274
5275 /*
5276 * Initialize the big block cache.
5277 */
5278 This->bigBlockSize = sector_size;
5279 This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
5280 if (hFile)
5281 hr = FileLockBytesImpl_Construct(hFile, openFlags, pwcsName, &This->lockBytes);
5282 else
5283 {
5284 This->lockBytes = pLkbyt;
5285 ILockBytes_AddRef(pLkbyt);
5286 }
5287
5288 if (SUCCEEDED(hr))
5289 hr = ILockBytes_Stat(This->lockBytes, &stat, STATFLAG_NONAME);
5290
5291 if (SUCCEEDED(hr))
5292 {
5293 This->locks_supported = stat.grfLocksSupported;
5294 if (!hFile)
5295 /* Don't try to use wine-internal locking flag with custom ILockBytes */
5296 This->locks_supported &= ~WINE_LOCK_READ;
5297
5298 hr = StorageImpl_GrabLocks(This, openFlags);
5299 }
5300
5301 if (SUCCEEDED(hr))
5303
5304 if (FAILED(hr))
5305 {
5306 IStorage_Release(&This->base.IStorage_iface);
5307 *result = NULL;
5308 }
5309 else
5310 {
5311 StorageImpl_Flush(&This->base);
5312 *result = This;
5313 }
5314
5315 return hr;
5316}
5317
5318
5319/************************************************************************
5320 * StorageInternalImpl implementation
5321 ***********************************************************************/
5322
5324{
5326
5327 if (!This->base.reverted)
5328 {
5329 TRACE("Storage invalidated (stg=%p)\n", This);
5330
5331 This->base.reverted = TRUE;
5332
5333 This->parentStorage = NULL;
5334
5336
5337 list_remove(&This->ParentListEntry);
5338 }
5339}
5340
5342{
5344
5346
5348}
5349
5351{
5353
5354 return StorageBaseImpl_Flush(This->parentStorage);
5355}
5356
5358{
5360
5361 return StorageBaseImpl_GetFilename(This->parentStorage, result);
5362}
5363
5365 const DirEntry *newData, DirRef *index)
5366{
5368
5369 return StorageBaseImpl_CreateDirEntry(This->parentStorage,
5370 newData, index);
5371}
5372
5374 DirRef index, const DirEntry *data)
5375{
5377
5378 return StorageBaseImpl_WriteDirEntry(This->parentStorage,
5379 index, data);
5380}
5381
5384{
5386
5387 return StorageBaseImpl_ReadDirEntry(This->parentStorage,
5388 index, data);
5389}
5390
5392 DirRef index)
5393{
5395
5396 return StorageBaseImpl_DestroyDirEntry(This->parentStorage,
5397 index);
5398}
5399
5401 DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
5402{
5404
5405 return StorageBaseImpl_StreamReadAt(This->parentStorage,
5406 index, offset, size, buffer, bytesRead);
5407}
5408
5411{
5413
5414 return StorageBaseImpl_StreamWriteAt(This->parentStorage,
5416}
5417
5419 DirRef index, ULARGE_INTEGER newsize)
5420{
5422
5423 return StorageBaseImpl_StreamSetSize(This->parentStorage,
5424 index, newsize);
5425}
5426
5429{
5431
5432 return StorageBaseImpl_StreamLink(This->parentStorage,
5433 dst, src);
5434}
5435
5437 ULONG* result, BOOL refresh)
5438{
5439 return E_NOTIMPL;
5440}
5441
5443 ULONG value)
5444{
5445 return E_NOTIMPL;
5446}
5447
5449{
5450 return E_NOTIMPL;
5451}
5452
5454{
5455 return E_NOTIMPL;
5456}
5457
5458/******************************************************************************
5459**
5460** StorageInternalImpl_Commit
5461**
5462*/
5464 IStorage* iface,
5465 DWORD grfCommitFlags) /* [in] */
5466{
5468 TRACE("%p, %#lx.\n", iface, grfCommitFlags);
5470}
5471
5472/******************************************************************************
5473**
5474** StorageInternalImpl_Revert
5475**
5476*/
5478 IStorage* iface)
5479{
5480 FIXME("(%p): stub\n", iface);
5481 return S_OK;
5482}
5483
5484/*
5485 * Virtual function table for the StorageInternalImpl class.
5486 */
5487static const IStorageVtbl StorageInternalImpl_Vtbl =
5488{
5507};
5508
5510{
5527};
5528
5530 StorageBaseImpl* parentStorage,
5531 DWORD openFlags,
5532 DirRef storageDirEntry)
5533{
5534 StorageInternalImpl* newStorage;
5535
5537
5538 if (newStorage!=0)
5539 {
5540 list_init(&newStorage->base.strmHead);
5541
5542 list_init(&newStorage->base.storageHead);
5543
5544 /*
5545 * Initialize the virtual function table.
5546 */
5547 newStorage->base.IStorage_iface.lpVtbl = &StorageInternalImpl_Vtbl;
5548 newStorage->base.IPropertySetStorage_iface.lpVtbl = &IPropertySetStorage_Vtbl;
5549 newStorage->base.baseVtbl = &StorageInternalImpl_BaseVtbl;
5550 newStorage->base.openFlags = (openFlags & ~STGM_CREATE);
5551
5552 newStorage->base.reverted = FALSE;
5553
5554 newStorage->base.ref = 1;
5555
5556 newStorage->parentStorage = parentStorage;
5557
5558 /*
5559 * Keep a reference to the directory entry of this storage
5560 */
5561 newStorage->base.storageDirEntry = storageDirEntry;
5562
5563 newStorage->base.create = FALSE;
5564
5565 return newStorage;
5566 }
5567
5568 return 0;
5569}
5570
5571
5572/************************************************************************
5573 * TransactedSnapshotImpl implementation
5574 ***********************************************************************/
5575
5577{
5578 DirRef result=This->firstFreeEntry;
5579
5580 while (result < This->entries_size && This->entries[result].inuse)
5581 result++;
5582
5583 if (result == This->entries_size)
5584 {
5585 ULONG new_size = This->entries_size * 2;
5586 TransactedDirEntry *new_entries;
5587
5589 if (!new_entries) return DIRENTRY_NULL;
5590
5591 memcpy(new_entries, This->entries, sizeof(TransactedDirEntry) * This->entries_size);
5592 HeapFree(GetProcessHeap(), 0, This->entries);
5593
5594 This->entries = new_entries;
5595 This->entries_size = new_size;
5596 }
5597
5598 This->entries[result].inuse = TRUE;
5599
5600 This->firstFreeEntry = result+1;
5601
5602 return result;
5603}
5604
5606 TransactedSnapshotImpl *This, DirRef parentEntryRef)
5607{
5608 DirRef stubEntryRef;
5610
5612
5613 if (stubEntryRef != DIRENTRY_NULL)
5614 {
5615 entry = &This->entries[stubEntryRef];
5616
5617 entry->newTransactedParentEntry = entry->transactedParentEntry = parentEntryRef;
5618
5619 entry->read = FALSE;
5620 }
5621
5622 return stubEntryRef;
5623}
5624
5627{
5628 HRESULT hr=S_OK;
5629 DirEntry data;
5630
5631 if (!This->entries[entry].read)
5632 {
5633 hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
5634 This->entries[entry].transactedParentEntry,
5635 &data);
5636
5637 if (SUCCEEDED(hr) && data.leftChild != DIRENTRY_NULL)
5638 {
5639 data.leftChild = TransactedSnapshotImpl_CreateStubEntry(This, data.leftChild);
5640
5641 if (data.leftChild == DIRENTRY_NULL)
5642 hr = E_OUTOFMEMORY;
5643 }
5644
5645 if (SUCCEEDED(hr) && data.rightChild != DIRENTRY_NULL)
5646 {
5647 data.rightChild = TransactedSnapshotImpl_CreateStubEntry(This, data.rightChild);
5648
5649 if (data.rightChild == DIRENTRY_NULL)
5650 hr = E_OUTOFMEMORY;
5651 }
5652
5653 if (SUCCEEDED(hr) && data.dirRootEntry != DIRENTRY_NULL)
5654 {
5655 data.dirRootEntry = TransactedSnapshotImpl_CreateStubEntry(This, data.dirRootEntry);
5656
5657 if (data.dirRootEntry == DIRENTRY_NULL)
5658 hr = E_OUTOFMEMORY;
5659 }
5660
5661 if (SUCCEEDED(hr))
5662 {
5663 memcpy(&This->entries[entry].data, &data, sizeof(DirEntry));
5664 This->entries[entry].read = TRUE;
5665 }
5666 }
5667
5668 return hr;
5669}
5670
5673{
5674 HRESULT hr = S_OK;
5675
5676 if (!This->entries[entry].stream_dirty)
5677 {
5678 DirEntry new_entrydata;
5679
5680 memset(&new_entrydata, 0, sizeof(DirEntry));
5681 new_entrydata.name[0] = 'S';
5682 new_entrydata.sizeOfNameString = 1;
5683 new_entrydata.stgType = STGTY_STREAM;
5684 new_entrydata.startingBlock = BLOCK_END_OF_CHAIN;
5685 new_entrydata.leftChild = DIRENTRY_NULL;
5686 new_entrydata.rightChild = DIRENTRY_NULL;
5687 new_entrydata.dirRootEntry = DIRENTRY_NULL;
5688
5689 hr = StorageBaseImpl_CreateDirEntry(This->scratch, &new_entrydata,
5690 &This->entries[entry].stream_entry);
5691
5692 if (SUCCEEDED(hr) && This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
5693 {
5695 This->scratch, This->entries[entry].stream_entry,
5696 This->transactedParent, This->entries[entry].transactedParentEntry);
5697
5698 if (FAILED(hr))
5699 StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[entry].stream_entry);
5700 }
5701
5702 if (SUCCEEDED(hr))
5703 This->entries[entry].stream_dirty = TRUE;
5704
5705 if (This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
5706 {
5707 /* Since this entry is modified, and we aren't using its stream data, we
5708 * no longer care about the original entry. */
5709 DirRef delete_ref;
5710 delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[entry].transactedParentEntry);
5711
5712 if (delete_ref != DIRENTRY_NULL)
5713 This->entries[delete_ref].deleted = TRUE;
5714
5715 This->entries[entry].transactedParentEntry = This->entries[entry].newTransactedParentEntry = DIRENTRY_NULL;
5716 }
5717 }
5718
5719 return hr;
5720}
5721
5722/* Find the first entry in a depth-first traversal. */
5725{
5726 DirRef cursor, prev;
5728
5729 cursor = parent;
5730 entry = &This->entries[cursor];
5731 while (entry->read)
5732 {
5733 if (entry->data.leftChild != DIRENTRY_NULL)
5734 {
5735 prev = cursor;
5736 cursor = entry->data.leftChild;
5737 entry = &This->entries[cursor];
5738 entry->parent = prev;
5739 }
5740 else if (entry->data.rightChild != DIRENTRY_NULL)
5741 {
5742 prev = cursor;
5743 cursor = entry->data.rightChild;
5744 entry = &This->entries[cursor];
5745 entry->parent = prev;
5746 }
5747 else if (entry->data.dirRootEntry != DIRENTRY_NULL)
5748 {
5749 prev = cursor;
5750 cursor = entry->data.dirRootEntry;
5751 entry = &This->entries[cursor];
5752 entry->parent = prev;
5753 }
5754 else
5755 break;
5756 }
5757
5758 return cursor;
5759}
5760
5761/* Find the next entry in a depth-first traversal. */
5764{
5765 DirRef parent;
5766 TransactedDirEntry *parent_entry;
5767
5768 parent = This->entries[current].parent;
5769 parent_entry = &This->entries[parent];
5770
5771 if (parent != DIRENTRY_NULL && parent_entry->data.dirRootEntry != current)
5772 {
5773 if (parent_entry->data.rightChild != current && parent_entry->data.rightChild != DIRENTRY_NULL)
5774 {
5775 This->entries[parent_entry->data.rightChild].parent = parent;
5777 }
5778
5779 if (parent_entry->data.dirRootEntry != DIRENTRY_NULL)
5780 {
5781 This->entries[parent_entry->data.dirRootEntry].parent = parent;
5783 }
5784 }
5785
5786 return parent;
5787}
5788
5789/* Return TRUE if we've made a copy of this entry for committing to the parent. */
5792{
5793 return entry != DIRENTRY_NULL &&
5794 This->entries[entry].newTransactedParentEntry != This->entries[entry].transactedParentEntry;
5795}
5796
5797/* Destroy the entries created by CopyTree. */
5800{
5801 DirRef cursor;
5804
5805 zero.QuadPart = 0;
5806
5807 if (!This->entries[This->base.storageDirEntry].read)
5808 return;
5809
5810 cursor = This->entries[This->base.storageDirEntry].data.dirRootEntry;
5811
5812 if (cursor == DIRENTRY_NULL)
5813 return;
5814
5816
5817 while (cursor != DIRENTRY_NULL && cursor != stop)
5818 {
5820 {
5821 entry = &This->entries[cursor];
5822
5823 if (entry->stream_dirty)
5824 StorageBaseImpl_StreamSetSize(This->transactedParent,
5825 entry->newTransactedParentEntry, zero);
5826
5827 StorageBaseImpl_DestroyDirEntry(This->transactedParent,
5828 entry->newTransactedParentEntry);
5829
5830 entry->newTransactedParentEntry = entry->transactedParentEntry;
5831 }
5832
5834 }
5835}
5836
5837/* Make a copy of our edited tree that we can use in the parent. */
5839{
5840 DirRef cursor;
5842 HRESULT hr = S_OK;
5843
5844 cursor = This->base.storageDirEntry;
5845 entry = &This->entries[cursor];
5846 entry->parent = DIRENTRY_NULL;
5847 entry->newTransactedParentEntry = entry->transactedParentEntry;
5848
5849 if (entry->data.dirRootEntry == DIRENTRY_NULL)
5850 return S_OK;
5851
5852 This->entries[entry->data.dirRootEntry].parent = DIRENTRY_NULL;
5853
5855 entry = &This->entries[cursor];
5856
5857 while (cursor != DIRENTRY_NULL)
5858 {
5859 /* Make a copy of this entry in the transacted parent. */
5860 if (!entry->read ||
5861 (!entry->dirty && !entry->stream_dirty &&
5862 !TransactedSnapshotImpl_MadeCopy(This, entry->data.leftChild) &&
5863 !TransactedSnapshotImpl_MadeCopy(This, entry->data.rightChild) &&
5864 !TransactedSnapshotImpl_MadeCopy(This, entry->data.dirRootEntry)))
5865 entry->newTransactedParentEntry = entry->transactedParentEntry;
5866 else
5867 {
5868 DirEntry newData;
5869
5870 memcpy(&newData, &entry->data, sizeof(DirEntry));
5871
5872 newData.size.QuadPart = 0;
5874
5875 if (newData.leftChild != DIRENTRY_NULL)
5876 newData.leftChild = This->entries[newData.leftChild].newTransactedParentEntry;
5877
5878 if (newData.rightChild != DIRENTRY_NULL)
5879 newData.rightChild = This->entries[newData.rightChild].newTransactedParentEntry;
5880
5881 if (newData.dirRootEntry != DIRENTRY_NULL)
5882 newData.dirRootEntry = This->entries[newData.dirRootEntry].newTransactedParentEntry;
5883
5884 hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &newData,
5885 &entry->newTransactedParentEntry);
5886 if (FAILED(hr))
5887 {
5889 return hr;
5890 }
5891
5892 if (entry->stream_dirty)
5893 {
5895 This->transactedParent, entry->newTransactedParentEntry,
5896 This->scratch, entry->stream_entry);
5897 }
5898 else if (entry->data.size.QuadPart)
5899 {
5901 This->transactedParent, entry->newTransactedParentEntry,
5902 entry->transactedParentEntry);
5903 }
5904
5905 if (FAILED(hr))
5906 {
5909 return hr;
5910 }
5911 }
5912
5914 entry = &This->entries[cursor];
5915 }
5916
5917 return hr;
5918}
5919
5921 IStorage* iface,
5922 DWORD grfCommitFlags) /* [in] */
5923{
5925 TransactedDirEntry *root_entry;
5926 DirRef i, dir_root_ref;
5927 DirEntry data;
5929 HRESULT hr;
5930 ULONG transactionSig;
5931
5932 zero.QuadPart = 0;
5933
5934 TRACE("%p, %#lx.\n", iface, grfCommitFlags);
5935
5936 /* Cannot commit a read-only transacted storage */
5937 if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
5938 return STG_E_ACCESSDENIED;
5939
5940 hr = StorageBaseImpl_LockTransaction(This->transactedParent, TRUE);
5941 if (hr == E_NOTIMPL) hr = S_OK;
5942 if (SUCCEEDED(hr))
5943 {
5944 hr = StorageBaseImpl_GetTransactionSig(This->transactedParent, &transactionSig, TRUE);
5945 if (SUCCEEDED(hr))
5946 {
5947 if (transactionSig != This->lastTransactionSig)
5948 {
5949 ERR("file was externally modified\n");
5951 }
5952
5953 if (SUCCEEDED(hr))
5954 {
5955 This->lastTransactionSig = transactionSig+1;
5956 hr = StorageBaseImpl_SetTransactionSig(This->transactedParent, This->lastTransactionSig);
5957 }
5958 }
5959 else if (hr == E_NOTIMPL)
5960 hr = S_OK;
5961
5962 if (FAILED(hr)) goto end;
5963
5964 /* To prevent data loss, we create the new structure in the file before we
5965 * delete the old one, so that in case of errors the old data is intact. We
5966 * shouldn't do this if STGC_OVERWRITE is set, but that flag should only be
5967 * needed in the rare situation where we have just enough free disk space to
5968 * overwrite the existing data. */
5969
5970 root_entry = &This->entries[This->base.storageDirEntry];
5971
5972 if (!root_entry->read)
5973 goto end;
5974
5976 if (FAILED(hr)) goto end;
5977
5978 if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
5979 dir_root_ref = DIRENTRY_NULL;
5980 else
5981 dir_root_ref = This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
5982
5983 hr = StorageBaseImpl_Flush(This->transactedParent);
5984
5985 /* Update the storage to use the new data in one step. */
5986 if (SUCCEEDED(hr))
5987 hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
5988 root_entry->transactedParentEntry, &data);
5989
5990 if (SUCCEEDED(hr))
5991 {
5992 data.dirRootEntry = dir_root_ref;
5993 data.clsid = root_entry->data.clsid;
5994 data.ctime = root_entry->data.ctime;
5995 data.mtime = root_entry->data.mtime;
5996
5997 hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
5998 root_entry->transactedParentEntry, &data);
5999 }
6000
6001 /* Try to flush after updating the root storage, but if the flush fails, keep
6002 * going, on the theory that it'll either succeed later or the subsequent
6003 * writes will fail. */
6004 StorageBaseImpl_Flush(This->transactedParent);
6005
6006 if (SUCCEEDED(hr))
6007 {
6008 /* Destroy the old now-orphaned data. */
6009 for (i=0; i<This->entries_size; i++)
6010 {
6011 TransactedDirEntry *entry = &This->entries[i];
6012 if (entry->inuse)
6013 {
6014 if (entry->deleted)
6015 {
6016 StorageBaseImpl_StreamSetSize(This->transactedParent,
6017 entry->transactedParentEntry, zero);
6018 StorageBaseImpl_DestroyDirEntry(This->transactedParent,
6019 entry->transactedParentEntry);
6020 memset(entry, 0, sizeof(TransactedDirEntry));
6021 This->firstFreeEntry = min(i, This->firstFreeEntry);
6022 }
6023 else if (entry->read && entry->transactedParentEntry != entry->newTransactedParentEntry)
6024 {
6025 if (entry->transactedParentEntry != DIRENTRY_NULL)
6026 StorageBaseImpl_DestroyDirEntry(This->transactedParent,
6027 entry->transactedParentEntry);
6028 if (entry->stream_dirty)
6029 {
6030 StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry, zero);
6031 StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry);
6032 entry->stream_dirty = FALSE;
6033 }
6034 entry->dirty = FALSE;
6035 entry->transactedParentEntry = entry->newTransactedParentEntry;
6036 }
6037 }
6038 }
6039 }
6040 else
6041 {
6043 }
6044
6045 if (SUCCEEDED(hr))
6046 hr = StorageBaseImpl_Flush(This->transactedParent);
6047end:
6048 StorageBaseImpl_UnlockTransaction(This->transactedParent, TRUE);
6049 }
6050
6051 TRACE("<-- %#lx\n", hr);
6052 return hr;
6053}
6054
6056 IStorage* iface)
6057{
6060 ULONG i;
6061
6062 TRACE("(%p)\n", iface);
6063
6064 /* Destroy the open objects. */
6066
6067 /* Clear out the scratch file. */
6068 zero.QuadPart = 0;
6069 for (i=0; i<This->entries_size; i++)
6070 {
6071 if (This->entries[i].stream_dirty)
6072 {
6073 StorageBaseImpl_StreamSetSize(This->scratch, This->entries[i].stream_entry,
6074 zero);
6075
6076 StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[i].stream_entry);
6077 }
6078 }
6079
6080 memset(This->entries, 0, sizeof(TransactedDirEntry) * This->entries_size);
6081
6082 This->firstFreeEntry = 0;
6083 This->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(This, This->transactedParent->storageDirEntry);
6084
6085 return S_OK;
6086}
6087
6089{
6090 if (!This->reverted)
6091 {
6092 TRACE("Storage invalidated (stg=%p)\n", This);
6093
6094 This->reverted = TRUE;
6095
6097 }
6098}
6099
6101{
6103
6104 IStorage_Revert(&This->base.IStorage_iface);
6105 IStorage_Release(&This->transactedParent->IStorage_iface);
6106 IStorage_Release(&This->scratch->IStorage_iface);
6107 HeapFree(GetProcessHeap(), 0, This->entries);
6109}
6110
6112{
6113 /* We only need to flush when committing. */
6114 return S_OK;
6115}
6116
6118{
6120
6121 return StorageBaseImpl_GetFilename(This->transactedParent, result);
6122}
6123
6125 const DirEntry *newData, DirRef *index)
6126{
6128 DirRef new_ref;
6129 TransactedDirEntry *new_entry;
6130
6132 if (new_ref == DIRENTRY_NULL)
6133 return E_OUTOFMEMORY;
6134
6135 new_entry = &This->entries[new_ref];
6136
6138 new_entry->read = TRUE;
6139 new_entry->dirty = TRUE;
6140 memcpy(&new_entry->data, newData, sizeof(DirEntry));
6141
6142 *index = new_ref;
6143
6144 TRACE("%s l=%lx r=%lx d=%lx <-- %lx\n", debugstr_w(newData->name), newData->leftChild, newData->rightChild, newData->dirRootEntry, *index);
6145
6146 return S_OK;
6147}
6148
6150 DirRef index, const DirEntry *data)
6151{
6153 HRESULT hr;
6154
6155 TRACE("%lx %s l=%lx r=%lx d=%lx\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
6156
6158 if (FAILED(hr))
6159 {
6160 TRACE("<-- %#lx\n", hr);
6161 return hr;
6162 }
6163
6164 memcpy(&This->entries[index].data, data, sizeof(DirEntry));
6165
6166 if (index != This->base.storageDirEntry)
6167 {
6168 This->entries[index].dirty = TRUE;
6169
6170 if (data->size.QuadPart == 0 &&
6171 This->entries[index].transactedParentEntry != DIRENTRY_NULL)
6172 {
6173 /* Since this entry is modified, and we aren't using its stream data, we
6174 * no longer care about the original entry. */
6175 DirRef delete_ref;
6176 delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
6177
6178 if (delete_ref != DIRENTRY_NULL)
6179 This->entries[delete_ref].deleted = TRUE;
6180
6181 This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
6182 }
6183 }
6184 TRACE("<-- S_OK\n");
6185 return S_OK;
6186}
6187
6190{
6192 HRESULT hr;
6193
6195 if (FAILED(hr))
6196 {
6197 TRACE("<-- %#lx\n", hr);
6198 return hr;
6199 }
6200
6201 memcpy(data, &This->entries[index].data, sizeof(DirEntry));
6202
6203 TRACE("%lx %s l=%lx r=%lx d=%lx\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
6204
6205 return S_OK;
6206}
6207
6209 DirRef index)
6210{
6212
6213 if (This->entries[index].transactedParentEntry == DIRENTRY_NULL ||
6214 This->entries[index].data.size.QuadPart != 0)
6215 {
6216 /* If we deleted this entry while it has stream data. We must have left the
6217 * data because some other entry is using it, and we need to leave the
6218 * original entry alone. */
6219 memset(&This->entries[index], 0, sizeof(TransactedDirEntry));
6220 This->firstFreeEntry = min(index, This->firstFreeEntry);
6221 }
6222 else
6223 {
6224 This->entries[index].deleted = TRUE;
6225 }
6226
6227 return S_OK;
6228}
6229
6231 DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
6232{
6234
6235 if (This->entries[index].stream_dirty)
6236 {
6237 return StorageBaseImpl_StreamReadAt(This->scratch,
6238 This->entries[index].stream_entry, offset, size, buffer, bytesRead);
6239 }
6240 else if (This->entries[index].transactedParentEntry == DIRENTRY_NULL)
6241 {
6242 /* This stream doesn't live in the parent, and we haven't allocated storage
6243 * for it yet */
6244 *bytesRead = 0;
6245 return S_OK;
6246 }
6247 else
6248 {
6249 return StorageBaseImpl_StreamReadAt(This->transactedParent,
6250 This->entries[index].transactedParentEntry, offset, size, buffer, bytesRead);
6251 }
6252}
6253
6256{
6258 HRESULT hr;
6259
6261 if (FAILED(hr))
6262 {
6263 TRACE("<-- %#lx\n", hr);
6264 return hr;
6265 }
6266
6268 if (FAILED(hr))
6269 {
6270 TRACE("<-- %#lx\n", hr);
6271 return hr;
6272 }
6273
6275 This->entries[index].stream_entry, offset, size, buffer, bytesWritten);
6276
6277 if (SUCCEEDED(hr) && size != 0)
6278 This->entries[index].data.size.QuadPart = max(
6279 This->entries[index].data.size.QuadPart,
6280 offset.QuadPart + size);
6281
6282 TRACE("<-- %#lx\n", hr);
6283 return hr;
6284}
6285
6287 DirRef index, ULARGE_INTEGER newsize)
6288{
6290 HRESULT hr;
6291
6293 if (FAILED(hr))
6294 {
6295 TRACE("<-- %#lx\n", hr);
6296 return hr;
6297 }
6298
6299 if (This->entries[index].data.size.QuadPart == newsize.QuadPart)
6300 return S_OK;
6301
6302 if (newsize.QuadPart == 0)
6303 {
6304 /* Destroy any parent references or entries in the scratch file. */
6305 if (This->entries[index].stream_dirty)
6306 {
6308 zero.QuadPart = 0;
6310 This->entries[index].stream_entry, zero);
6312 This->entries[index].stream_entry);
6313 This->entries[index].stream_dirty = FALSE;
6314 }
6315 else if (This->entries[index].transactedParentEntry != DIRENTRY_NULL)
6316 {
6317 DirRef delete_ref;
6318 delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
6319
6320 if (delete_ref != DIRENTRY_NULL)
6321 This->entries[delete_ref].deleted = TRUE;
6322
6323 This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
6324 }
6325 }
6326 else
6327 {
6329 if (FAILED(hr)) return hr;
6330
6332 This->entries[index].stream_entry, newsize);
6333 }
6334
6335 if (SUCCEEDED(hr))
6336 This->entries[index].data.size = newsize;
6337
6338 TRACE("<-- %#lx\n", hr);
6339 return hr;
6340}
6341
6344{
6346 HRESULT hr;
6347 TransactedDirEntry *dst_entry, *src_entry;
6348
6350 if (FAILED(hr))
6351 {
6352 TRACE("<-- %#lx\n", hr);
6353 return hr;
6354 }
6355
6357 if (FAILED(hr))
6358 {
6359 TRACE("<-- %#lx\n", hr);
6360 return hr;
6361 }
6362
6363 dst_entry = &This->entries[dst];
6364 src_entry = &This->entries[src];
6365
6366 dst_entry->stream_dirty = src_entry->stream_dirty;
6367 dst_entry->stream_entry = src_entry->stream_entry;
6368 dst_entry->transactedParentEntry = src_entry->transactedParentEntry;
6369 dst_entry->newTransactedParentEntry = src_entry->newTransactedParentEntry;
6370 dst_entry->data.size = src_entry->data.size;
6371
6372 return S_OK;
6373}
6374
6376 ULONG* result, BOOL refresh)
6377{
6378 return E_NOTIMPL;
6379}
6380
6382 ULONG value)
6383{
6384 return E_NOTIMPL;
6385}
6386
6388{
6389 return E_NOTIMPL;
6390}
6391
6393{
6394 return E_NOTIMPL;
6395}
6396
6397static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
6398{
6417};
6418
6420{
6437};
6438
6441{
6442 HRESULT hr;
6443
6445 if (*result)
6446 {
6447 IStorage *scratch;
6448
6449 (*result)->base.IStorage_iface.lpVtbl = &TransactedSnapshotImpl_Vtbl;
6450
6451 /* This is OK because the property set storage functions use the IStorage functions. */
6452 (*result)->base.IPropertySetStorage_iface.lpVtbl = parentStorage->IPropertySetStorage_iface.lpVtbl;
6453 (*result)->base.baseVtbl = &TransactedSnapshotImpl_BaseVtbl;
6454
6455 list_init(&(*result)->base.strmHead);
6456
6457 list_init(&(*result)->base.storageHead);
6458
6459 (*result)->base.ref = 1;
6460
6461 (*result)->base.openFlags = parentStorage->openFlags;
6462
6463 /* This cannot fail, except with E_NOTIMPL in which case we don't care */
6464 StorageBaseImpl_GetTransactionSig(parentStorage, &(*result)->lastTransactionSig, FALSE);
6465
6466 /* Create a new temporary storage to act as the scratch file. */
6468 0, &scratch);
6469 (*result)->scratch = impl_from_IStorage(scratch);
6470
6471 if (SUCCEEDED(hr))
6472 {
6473 ULONG num_entries = 20;
6474
6475 (*result)->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * num_entries);
6476 (*result)->entries_size = num_entries;
6477 (*result)->firstFreeEntry = 0;
6478
6479 if ((*result)->entries)
6480 {
6481 /* parentStorage already has 1 reference, which we take over here. */
6482 (*result)->transactedParent = parentStorage;
6483
6484 parentStorage->transactedChild = &(*result)->base;
6485
6487 }
6488 else
6489 {
6490 IStorage_Release(scratch);
6491
6492 hr = E_OUTOFMEMORY;
6493 }
6494 }
6495
6496 if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, *result);
6497
6498 return hr;
6499 }
6500 else
6501 return E_OUTOFMEMORY;
6502}
6503
6504
6505/************************************************************************
6506 * TransactedSharedImpl implementation
6507 ***********************************************************************/
6508
6510{
6511 if (!This->reverted)
6512 {
6513 TRACE("Storage invalidated (stg=%p)\n", This);
6514
6515 This->reverted = TRUE;
6516
6518 }
6519}
6520
6522{
6524
6526 IStorage_Release(&This->transactedParent->IStorage_iface);
6527 IStorage_Release(&This->scratch->base.IStorage_iface);
6529}
6530
6532{
6533 /* We only need to flush when committing. */
6534 return S_OK;
6535}
6536
6538{
6540
6541 return StorageBaseImpl_GetFilename(This->transactedParent, result);
6542}
6543
6545 const DirEntry *newData, DirRef *index)
6546{
6548
6549 return StorageBaseImpl_CreateDirEntry(&This->scratch->base,
6550 newData, index);
6551}
6552
6554 DirRef index, const DirEntry *data)
6555{
6557
6558 return StorageBaseImpl_WriteDirEntry(&This->scratch->base,
6559 index, data);
6560}
6561
6564{
6566
6567 return StorageBaseImpl_ReadDirEntry(&This->scratch->base,
6568 index, data);
6569}
6570
6572 DirRef index)
6573{
6575
6576 return StorageBaseImpl_DestroyDirEntry(&This->scratch->base,
6577 index);
6578}
6579
6581 DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
6582{
6584
6585 return StorageBaseImpl_StreamReadAt(&This->scratch->base,
6586 index, offset, size, buffer, bytesRead);
6587}
6588
6591{
6593
6594 return StorageBaseImpl_StreamWriteAt(&This->scratch->base,
6596}
6597
6599 DirRef index, ULARGE_INTEGER newsize)
6600{
6602
6603 return StorageBaseImpl_StreamSetSize(&This->scratch->base,
6604 index, newsize);
6605}
6606
6609{
6611
6612 return StorageBaseImpl_StreamLink(&This->scratch->base,
6613 dst, src);
6614}
6615
6617 ULONG* result, BOOL refresh)
6618{
6619 return E_NOTIMPL;
6620}
6621
6623 ULONG value)
6624{
6625 return E_NOTIMPL;
6626}
6627
6629{
6630 return E_NOTIMPL;
6631}
6632
6634{
6635 return E_NOTIMPL;
6636}
6637
6639 IStorage* iface,
6640 DWORD grfCommitFlags) /* [in] */
6641{
6643 DirRef new_storage_ref, prev_storage_ref;
6644 DirEntry src_data, dst_data;
6645 HRESULT hr;
6646 ULONG transactionSig;
6647
6648 TRACE("%p, %#lx\n", iface, grfCommitFlags);
6649
6650 /* Cannot commit a read-only transacted storage */
6651 if ( STGM_ACCESS_MODE( This->base.openFlags ) == STGM_READ )
6652 return STG_E_ACCESSDENIED;
6653
6654 hr = StorageBaseImpl_LockTransaction(This->transactedParent, TRUE);
6655 if (hr == E_NOTIMPL) hr = S_OK;
6656 if (SUCCEEDED(hr))
6657 {
6658 hr = StorageBaseImpl_GetTransactionSig(This->transactedParent, &transactionSig, TRUE);
6659 if (SUCCEEDED(hr))
6660 {
6661 if ((grfCommitFlags & STGC_ONLYIFCURRENT) && transactionSig != This->lastTransactionSig)
6663
6664 if (SUCCEEDED(hr))
6665 hr = StorageBaseImpl_SetTransactionSig(This->transactedParent, transactionSig+1);
6666 }
6667 else if (hr == E_NOTIMPL)
6668 hr = S_OK;
6669
6670 if (SUCCEEDED(hr))
6671 hr = StorageBaseImpl_ReadDirEntry(&This->scratch->base, This->scratch->base.storageDirEntry, &src_data);
6672
6673 /* FIXME: If we're current, we should be able to copy only the changes in scratch. */
6674 if (SUCCEEDED(hr))
6675 hr = StorageBaseImpl_DupStorageTree(This->transactedParent, &new_storage_ref, &This->scratch->base, src_data.dirRootEntry);
6676
6677 if (SUCCEEDED(hr))
6678 hr = StorageBaseImpl_Flush(This->transactedParent);
6679
6680 if (SUCCEEDED(hr))
6681 hr = StorageBaseImpl_ReadDirEntry(This->transactedParent, This->transactedParent->storageDirEntry, &dst_data);
6682
6683 if (SUCCEEDED(hr))
6684 {
6685 prev_storage_ref = dst_data.dirRootEntry;
6686 dst_data.dirRootEntry = new_storage_ref;
6687 dst_data.clsid = src_data.clsid;
6688 dst_data.ctime = src_data.ctime;
6689 dst_data.mtime = src_data.mtime;
6690 hr = StorageBaseImpl_WriteDirEntry(This->transactedParent, This->transactedParent->storageDirEntry, &dst_data);
6691 }
6692
6693 if (SUCCEEDED(hr))
6694 {
6695 /* Try to flush after updating the root storage, but if the flush fails, keep
6696 * going, on the theory that it'll either succeed later or the subsequent
6697 * writes will fail. */
6698 StorageBaseImpl_Flush(This->transactedParent);
6699
6700 hr = StorageBaseImpl_DeleteStorageTree(This->transactedParent, prev_storage_ref, TRUE);
6701 }
6702
6703 if (SUCCEEDED(hr))
6704 hr = StorageBaseImpl_Flush(This->transactedParent);
6705
6706 StorageBaseImpl_UnlockTransaction(This->transactedParent, TRUE);
6707
6708 if (SUCCEEDED(hr))
6709 hr = IStorage_Commit(&This->scratch->base.IStorage_iface, STGC_DEFAULT);
6710
6711 if (SUCCEEDED(hr))
6712 {
6713 This->lastTransactionSig = transactionSig+1;
6714 }
6715 }
6716 TRACE("<-- %#lx\n", hr);
6717 return hr;
6718}
6719
6721 IStorage* iface)
6722{
6724
6725 TRACE("(%p)\n", iface);
6726
6727 /* Destroy the open objects. */
6729
6730 return IStorage_Revert(&This->scratch->base.IStorage_iface);
6731}
6732
6733static const IStorageVtbl TransactedSharedImpl_Vtbl =
6734{
6753};
6754
6756{
6773};
6774
6777{
6778 HRESULT hr;
6779
6781 if (*result)
6782 {
6783 IStorage *scratch;
6784
6785 (*result)->base.IStorage_iface.lpVtbl = &TransactedSharedImpl_Vtbl;
6786
6787 /* This is OK because the property set storage functions use the IStorage functions. */
6788 (*result)->base.IPropertySetStorage_iface.lpVtbl = parentStorage->IPropertySetStorage_iface.lpVtbl;
6789 (*result)->base.baseVtbl = &TransactedSharedImpl_BaseVtbl;
6790
6791 list_init(&(*result)->base.strmHead);
6792
6793 list_init(&(*result)->base.storageHead);
6794
6795 (*result)->base.ref = 1;
6796
6797 (*result)->base.openFlags = parentStorage->openFlags;
6798
6799 hr = StorageBaseImpl_LockTransaction(parentStorage, FALSE);
6800
6801 if (SUCCEEDED(hr))
6802 {
6803 STGOPTIONS stgo;
6804
6805 /* This cannot fail, except with E_NOTIMPL in which case we don't care */
6806 StorageBaseImpl_GetTransactionSig(parentStorage, &(*result)->lastTransactionSig, FALSE);
6807
6808 stgo.usVersion = 1;
6809 stgo.reserved = 0;
6810 stgo.ulSectorSize = 4096;
6811 stgo.pwcsTemplateFile = NULL;
6812
6813 /* Create a new temporary storage to act as the scratch file. */
6815 STGFMT_DOCFILE, 0, &stgo, NULL, &IID_IStorage, (void**)&scratch);
6816 (*result)->scratch = (TransactedSnapshotImpl*)impl_from_IStorage(scratch);
6817
6818 if (SUCCEEDED(hr))
6819 {
6820 hr = StorageBaseImpl_CopyStorageTree(&(*result)->scratch->base, (*result)->scratch->base.storageDirEntry,
6821 parentStorage, parentStorage->storageDirEntry);
6822
6823 if (SUCCEEDED(hr))
6824 {
6825 hr = IStorage_Commit(scratch, STGC_DEFAULT);
6826
6827 (*result)->base.storageDirEntry = (*result)->scratch->base.storageDirEntry;
6828 (*result)->transactedParent = parentStorage;
6829 }
6830
6831 if (FAILED(hr))
6832 IStorage_Release(scratch);
6833 }
6834
6836 }
6837
6838 if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, *result);
6839
6840 return hr;
6841 }
6842 else
6843 return E_OUTOFMEMORY;
6844}
6845
6848{
6849 static int fixme_flags=STGM_NOSCRATCH|STGM_NOSNAPSHOT;
6850
6851 if (parentStorage->openFlags & fixme_flags)
6852 {
6853 fixme_flags &= ~parentStorage->openFlags;
6854 FIXME("Unimplemented flags %lx\n", parentStorage->openFlags);
6855 }
6856
6857 if (toplevel && !(parentStorage->openFlags & STGM_NOSNAPSHOT) &&
6858 STGM_SHARE_MODE(parentStorage->openFlags) != STGM_SHARE_DENY_WRITE &&
6860 {
6861 /* Need to create a temp file for the snapshot */
6863 }
6864
6865 return TransactedSnapshotImpl_Construct(parentStorage,
6867}
6868
6870 HANDLE hFile,
6871 LPCOLESTR pwcsName,
6872 ILockBytes* pLkbyt,
6873 DWORD openFlags,
6874 BOOL fileBased,
6875 BOOL create,
6878{
6879 StorageImpl *newStorage;
6880 StorageBaseImpl *newTransactedStorage;
6881 HRESULT hr;
6882
6883 hr = StorageImpl_Construct(hFile, pwcsName, pLkbyt, openFlags, fileBased, create, sector_size, &newStorage);
6884 if (FAILED(hr)) goto end;
6885
6886 if (openFlags & STGM_TRANSACTED)
6887 {
6888 hr = Storage_ConstructTransacted(&newStorage->base, TRUE, &newTransactedStorage);
6889 if (FAILED(hr))
6890 IStorage_Release(&newStorage->base.IStorage_iface);
6891 else
6892 *result = newTransactedStorage;
6893 }
6894 else
6895 *result = &newStorage->base;
6896
6897end:
6898 return hr;
6899}
6900
6901
6902/************************************************************************
6903 * StorageUtl helper functions
6904 ***********************************************************************/
6905
6907{
6908 WORD tmp;
6909
6910 memcpy(&tmp, buffer+offset, sizeof(WORD));
6911 *value = lendian16toh(tmp);
6912}
6913
6915{
6916 value = htole16(value);
6917 memcpy((BYTE *)buffer + offset, &value, sizeof(WORD));
6918}
6919
6921{
6922 DWORD tmp;
6923
6924 memcpy(&tmp, buffer+offset, sizeof(DWORD));
6925 *value = lendian32toh(tmp);
6926}
6927
6929{
6930 value = htole32(value);
6931 memcpy((BYTE *)buffer + offset, &value, sizeof(DWORD));
6932}
6933
6936{
6937#ifdef WORDS_BIGENDIAN
6938 ULARGE_INTEGER tmp;
6939
6940 memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER));
6941 value->u.LowPart = htole32(tmp.HighPart);
6942 value->u.HighPart = htole32(tmp.LowPart);
6943#else
6945#endif
6946}
6947
6949{
6950#ifdef WORDS_BIGENDIAN
6951 ULARGE_INTEGER tmp;
6952
6953 tmp.LowPart = htole32(value->u.HighPart);
6954 tmp.HighPart = htole32(value->u.LowPart);
6955 memcpy((BYTE *)buffer + offset, &tmp, sizeof(ULARGE_INTEGER));
6956#else
6957 memcpy((BYTE *)buffer + offset, value, sizeof(ULARGE_INTEGER));
6958#endif
6959}
6960
6962{
6964 StorageUtl_ReadWord(buffer, offset+4, &(value->Data2));
6965 StorageUtl_ReadWord(buffer, offset+6, &(value->Data3));
6966
6967 memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4));
6968}
6969
6971{
6975
6976 memcpy((BYTE *)buffer + offset + 8, value->Data4, sizeof(value->Data4));
6977}
6978
6981 STATSTG* destination,
6982 const DirEntry* source,
6983 int statFlags)
6984{
6985 /*
6986 * The copy of the string occurs only when the flag is not set
6987 */
6988 if (!(statFlags & STATFLAG_NONAME) && source->stgType == STGTY_ROOT)
6989 {
6990 /* Use the filename for the root storage. */
6991 destination->pwcsName = 0;
6992 StorageBaseImpl_GetFilename(storage, &destination->pwcsName);
6993 }
6994 else if( ((statFlags & STATFLAG_NONAME) != 0) ||
6995 (source->name[0] == 0) )
6996 {
6997 destination->pwcsName = 0;
6998 }
6999 else
7000 {
7001 destination->pwcsName =
7002 CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
7003
7004 lstrcpyW(destination->pwcsName, source->name);
7005 }
7006
7007 switch (source->stgType)
7008 {
7009 case STGTY_STORAGE:
7010 case STGTY_ROOT:
7011 destination->type = STGTY_STORAGE;
7012 break;
7013 case STGTY_STREAM:
7014 destination->type = STGTY_STREAM;
7015 break;
7016 default:
7017 destination->type = STGTY_STREAM;
7018 break;
7019 }
7020
7021 destination->cbSize = source->size;
7022/*
7023 currentReturnStruct->mtime = {0}; TODO
7024 currentReturnStruct->ctime = {0};
7025 currentReturnStruct->atime = {0};
7026*/
7027 destination->grfMode = 0;
7028 destination->grfLocksSupported = 0;
7029 destination->clsid = source->clsid;
7030 destination->grfStateBits = 0;
7031 destination->reserved = 0;
7032}
7033
7034
7035/************************************************************************
7036 * BlockChainStream implementation
7037 ***********************************************************************/
7038
7039/******************************************************************************
7040 * BlockChainStream_GetHeadOfChain
7041 *
7042 * Returns the head of this stream chain.
7043 * Some special chains don't have directory entries, their heads are kept in
7044 * This->headOfStreamPlaceHolder.
7045 *
7046 */
7048{
7049 DirEntry chainEntry;
7050 HRESULT hr;
7051
7052 if (This->headOfStreamPlaceHolder != 0)
7053 return *(This->headOfStreamPlaceHolder);
7054
7055 if (This->ownerDirEntry != DIRENTRY_NULL)
7056 {
7058 This->parentStorage,
7059 This->ownerDirEntry,
7060 &chainEntry);
7061
7062 if (SUCCEEDED(hr) && chainEntry.startingBlock < BLOCK_FIRST_SPECIAL)
7063 return chainEntry.startingBlock;
7064 }
7065
7066 return BLOCK_END_OF_CHAIN;
7067}
7068
7069/* Read and save the index of all blocks in this stream. */
7071{
7072 ULONG next_sector, next_offset;
7073 HRESULT hr;
7074 struct BlockChainRun *last_run;
7075
7076 if (This->indexCacheLen == 0)
7077 {
7078 last_run = NULL;
7079 next_offset = 0;
7081 }
7082 else
7083 {
7084 last_run = &This->indexCache[This->indexCacheLen-1];
7085 next_offset = last_run->lastOffset+1;
7086 hr = StorageImpl_GetNextBlockInChain(This->parentStorage,
7087 last_run->firstSector + last_run->lastOffset - last_run->firstOffset,
7088 &next_sector);
7089 if (FAILED(hr)) return hr;
7090 }
7091
7092 while (next_sector != BLOCK_END_OF_CHAIN)
7093 {
7094 if (!last_run || next_sector != last_run->firstSector + next_offset - last_run->firstOffset)
7095 {
7096 /* Add the current block to the cache. */
7097 if (This->indexCacheSize == 0)
7098 {
7099 This->indexCache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*16);
7100 if (!This->indexCache) return E_OUTOFMEMORY;
7101 This->indexCacheSize = 16;
7102 }
7103 else if (This->indexCacheSize == This->indexCacheLen)
7104 {
7105 struct BlockChainRun *new_cache;
7107
7108 new_size = This->indexCacheSize * 2;
7109 new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*new_size);
7110 if (!new_cache) return E_OUTOFMEMORY;
7111 memcpy(new_cache, This->indexCache, sizeof(struct BlockChainRun)*This->indexCacheLen);
7112
7113 HeapFree(GetProcessHeap(), 0, This->indexCache);
7114 This->indexCache = new_cache;
7115 This->indexCacheSize = new_size;
7116 }
7117
7118 This->indexCacheLen++;
7119 last_run = &This->indexCache[This->indexCacheLen-1];
7120 last_run->firstSector = next_sector;
7121 last_run->firstOffset = next_offset;
7122 }
7123
7124 last_run->lastOffset = next_offset;
7125
7126 /* Find the next block. */
7127 next_offset++;
7128 hr = StorageImpl_GetNextBlockInChain(This->parentStorage, next_sector, &next_sector);
7129 if (FAILED(hr)) return hr;
7130 }
7131
7132 if (This->indexCacheLen)
7133 {
7134 This->tailIndex = last_run->firstSector + last_run->lastOffset - last_run->firstOffset;
7135 This->numBlocks = last_run->lastOffset+1;
7136 }
7137 else
7138 {
7139 This->tailIndex = BLOCK_END_OF_CHAIN;
7140 This->numBlocks = 0;
7141 }
7142
7143 return S_OK;
7144}
7145
7146/* Locate the nth block in this stream. */
7148{
7149 ULONG min_offset = 0, max_offset = This->numBlocks-1;
7150 ULONG min_run = 0, max_run = This->indexCacheLen-1;
7151
7152 if (offset >= This->numBlocks)
7153 return BLOCK_END_OF_CHAIN;
7154
7155 while (min_run < max_run)
7156 {
7157 ULONG run_to_check = min_run + (offset - min_offset) * (max_run - min_run) / (max_offset - min_offset);
7158 if (offset < This->indexCache[run_to_check].firstOffset)
7159 {
7160 max_offset = This->indexCache[run_to_check].firstOffset-1;
7161 max_run = run_to_check-1;
7162 }
7163 else if (offset > This->indexCache[run_to_check].lastOffset)
7164 {
7165 min_offset = This->indexCache[run_to_check].lastOffset+1;
7166 min_run = run_to_check+1;
7167 }
7168 else
7169 /* Block is in this run. */
7170 min_run = max_run = run_to_check;
7171 }
7172
7173 return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset;
7174}
7175
7178{
7180 int i;
7181
7182 for (i=0; i<2; i++)
7183 if (This->cachedBlocks[i].index == index)
7184 {
7185 *sector = This->cachedBlocks[i].sector;
7186 *block = &This->cachedBlocks[i];
7187 return S_OK;
7188 }
7189
7191 if (*sector == BLOCK_END_OF_CHAIN)
7192 return STG_E_DOCFILECORRUPT;
7193
7194 if (create)
7195 {
7196 if (This->cachedBlocks[0].index == 0xffffffff)
7197 result = &This->cachedBlocks[0];
7198 else if (This->cachedBlocks[1].index == 0xffffffff)
7199 result = &This->cachedBlocks[1];
7200 else
7201 {
7202 result = &This->cachedBlocks[This->blockToEvict++];
7203 if (This->blockToEvict == 2)
7204 This->blockToEvict = 0;
7205 }
7206
7207 if (result->dirty)
7208 {
7209 if (!StorageImpl_WriteBigBlock(This->parentStorage, result->sector, result->data))
7210 return STG_E_WRITEFAULT;
7211 result->dirty = FALSE;
7212 }
7213
7214 result->read = FALSE;
7215 result->index = index;
7216 result->sector = *sector;
7217 }
7218
7219 *block = result;
7220 return S_OK;
7221}
7222
7224 StorageImpl* parentStorage,
7225 ULONG* headOfStreamPlaceHolder,
7226 DirRef dirEntry)
7227{
7228 BlockChainStream* newStream;
7229
7230 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
7231 if(!newStream)
7232 return NULL;
7233
7234 newStream->parentStorage = parentStorage;
7235 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
7236 newStream->ownerDirEntry = dirEntry;
7237 newStream->indexCache = NULL;
7238 newStream->indexCacheLen = 0;
7239 newStream->indexCacheSize = 0;
7240 newStream->cachedBlocks[0].index = 0xffffffff;
7241 newStream->cachedBlocks[0].dirty = FALSE;
7242 newStream->cachedBlocks[1].index = 0xffffffff;
7243 newStream->cachedBlocks[1].dirty = FALSE;
7244 newStream->blockToEvict = 0;
7245
7247 {
7248 HeapFree(GetProcessHeap(), 0, newStream->indexCache);
7249 HeapFree(GetProcessHeap(), 0, newStream);
7250 return NULL;
7251 }
7252
7253 return newStream;
7254}
7255
7257{
7258 int i;
7259 if (!This) return S_OK;
7260 for (i=0; i<2; i++)
7261 {
7262 if (This->cachedBlocks[i].dirty)
7263 {
7264 if (StorageImpl_WriteBigBlock(This->parentStorage, This->cachedBlocks[i].sector, This->cachedBlocks[i].data))
7265 This->cachedBlocks[i].dirty = FALSE;
7266 else
7267 return STG_E_WRITEFAULT;
7268 }
7269 }
7270 return S_OK;
7271}
7272
7274{
7275 if (This)
7276 {
7278 HeapFree(GetProcessHeap(), 0, This->indexCache);
7279 }
7281}
7282
7283/******************************************************************************
7284 * BlockChainStream_Shrink
7285 *
7286 * Shrinks this chain in the big block depot.
7287 */
7289 ULARGE_INTEGER newSize)
7290{
7291 ULONG blockIndex;
7292 ULONG numBlocks;
7293 int i;
7294
7295 /*
7296 * Figure out how many blocks are needed to contain the new size
7297 */
7298 numBlocks = newSize.QuadPart / This->parentStorage->bigBlockSize;
7299
7300 if ((newSize.QuadPart % This->parentStorage->bigBlockSize) != 0)
7301 numBlocks++;
7302
7303 if (numBlocks)
7304 {
7305 /*
7306 * Go to the new end of chain
7307 */
7308 blockIndex = BlockChainStream_GetSectorOfOffset(This, numBlocks-1);
7309
7310 /* Mark the new end of chain */
7312 This->parentStorage,
7313 blockIndex,
7315
7316 This->tailIndex = blockIndex;
7317 }
7318 else
7319 {
7320 if (This->headOfStreamPlaceHolder != 0)
7321 {
7322 *This->headOfStreamPlaceHolder = BLOCK_END_OF_CHAIN;
7323 }
7324 else
7325 {
7326 DirEntry chainEntry;
7327 assert(This->ownerDirEntry != DIRENTRY_NULL);
7328
7330 This->parentStorage,
7331 This->ownerDirEntry,
7332 &chainEntry);
7333
7334 chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
7335
7337 This->parentStorage,
7338 This->ownerDirEntry,
7339 &chainEntry);
7340 }
7341
7342 This->tailIndex = BLOCK_END_OF_CHAIN;
7343 }
7344
7345 This->numBlocks = numBlocks;
7346
7347 /*
7348 * Mark the extra blocks as free
7349 */
7350 while (This->indexCacheLen && This->indexCache[This->indexCacheLen-1].lastOffset >= numBlocks)
7351 {
7352 struct BlockChainRun *last_run = &This->indexCache[This->indexCacheLen-1];
7353 StorageImpl_FreeBigBlock(This->parentStorage,
7354 last_run->firstSector + last_run->lastOffset - last_run->firstOffset);
7355 if (last_run->lastOffset == last_run->firstOffset)
7356 This->indexCacheLen--;
7357 else
7358 last_run->lastOffset--;
7359 }
7360
7361 /*
7362 * Reset the last accessed block cache.
7363 */
7364 for (i=0; i<2; i++)
7365 {
7366 if (This->cachedBlocks[i].index >= numBlocks)
7367 {
7368 This->cachedBlocks[i].index = 0xffffffff;
7369 This->cachedBlocks[i].dirty = FALSE;
7370 }
7371 }
7372
7373 return TRUE;
7374}
7375
7376/******************************************************************************
7377 * BlockChainStream_Enlarge
7378 *
7379 * Grows this chain in the big block depot.
7380 */
7382 ULARGE_INTEGER newSize)
7383{
7384 ULONG blockIndex, currentBlock;
7385 ULONG newNumBlocks;
7386 ULONG oldNumBlocks = 0;
7387
7389
7390 /*
7391 * Empty chain. Create the head.
7392 */
7393 if (blockIndex == BLOCK_END_OF_CHAIN)
7394 {
7395 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage, 1);
7397 blockIndex,
7399
7400 if (This->headOfStreamPlaceHolder != 0)
7401 {
7402 *(This->headOfStreamPlaceHolder) = blockIndex;
7403 }
7404 else
7405 {
7406 DirEntry chainEntry;
7407 assert(This->ownerDirEntry != DIRENTRY_NULL);
7408
7410 This->parentStorage,
7411 This->ownerDirEntry,
7412 &chainEntry);
7413
7414 chainEntry.startingBlock = blockIndex;
7415
7417 This->parentStorage,
7418 This->ownerDirEntry,
7419 &chainEntry);
7420 }
7421
7422 This->tailIndex = blockIndex;
7423 This->numBlocks = 1;
7424 }
7425
7426 /*
7427 * Figure out how many blocks are needed to contain this stream
7428 */
7429 newNumBlocks = newSize.QuadPart / This->parentStorage->bigBlockSize;
7430
7431 if ((newSize.QuadPart % This->parentStorage->bigBlockSize) != 0)
7432 newNumBlocks++;
7433
7434 /*
7435 * Go to the current end of chain
7436 */
7437 if (This->tailIndex == BLOCK_END_OF_CHAIN)
7438 {
7439 currentBlock = blockIndex;
7440
7441 while (blockIndex != BLOCK_END_OF_CHAIN)
7442 {
7443 This->numBlocks++;
7444 currentBlock = blockIndex;
7445
7446 if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock,
7447 &blockIndex)))
7448 return FALSE;
7449 }
7450
7451 This->tailIndex = currentBlock;
7452 }
7453
7454 currentBlock = This->tailIndex;
7455 oldNumBlocks = This->numBlocks;
7456
7457 /*
7458 * Add new blocks to the chain
7459 */
7460 if (oldNumBlocks < newNumBlocks)
7461 {
7462 while (oldNumBlocks < newNumBlocks)
7463 {
7464 blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage, newNumBlocks - oldNumBlocks);
7465
7467 This->parentStorage,
7468 currentBlock,
7469 blockIndex);
7470
7472 This->parentStorage,
7473 blockIndex,
7475
7476 currentBlock = blockIndex;
7477 oldNumBlocks++;
7478 }
7479
7480 This->tailIndex = blockIndex;
7481 This->numBlocks = newNumBlocks;
7482 }
7483
7485 return FALSE;
7486
7487 return TRUE;
7488}
7489
7490
7491/******************************************************************************
7492 * BlockChainStream_GetSize
7493 *
7494 * Returns the size of this chain.
7495 * Will return the block count if this chain doesn't have a directory entry.
7496 */
7498{
7499 DirEntry chainEntry;
7500
7501 if(This->headOfStreamPlaceHolder == NULL)
7502 {
7503 /*
7504 * This chain has a directory entry so use the size value from there.
7505 */
7507 This->parentStorage,
7508 This->ownerDirEntry,
7509 &chainEntry);
7510
7511 return chainEntry.size;
7512 }
7513 else
7514 {
7515 /*
7516 * this chain is a chain that does not have a directory entry, figure out the
7517 * size by making the product number of used blocks times the
7518 * size of them
7519 */
7521 result.QuadPart =
7523 This->parentStorage->bigBlockSize;
7524
7525 return result;
7526 }
7527}
7528
7529/******************************************************************************
7530 * BlockChainStream_SetSize
7531 *
7532 * Sets the size of this stream. The big block depot will be updated.
7533 * The file will grow if we grow the chain.
7534 *
7535 * TODO: Free the actual blocks in the file when we shrink the chain.
7536 * Currently, the blocks are still in the file. So the file size
7537 * doesn't shrink even if we shrink streams.
7538 */
7541 ULARGE_INTEGER newSize)
7542{
7544
7545 if (newSize.QuadPart == size.QuadPart)
7546 return TRUE;
7547
7548 if (newSize.QuadPart < size.QuadPart)
7549 {
7550 BlockChainStream_Shrink(This, newSize);
7551 }
7552 else
7553 {
7555 }
7556
7557 return TRUE;
7558}
7559
7560/******************************************************************************
7561 * BlockChainStream_ReadAt
7562 *
7563 * Reads a specified number of bytes from this chain at the specified offset.
7564 * bytesRead may be NULL.
7565 * Failure will be returned if the specified number of bytes has not been read.
7566 */
7569 ULONG size,
7570 void* buffer,
7571 ULONG* bytesRead)
7572{
7573 ULONG blockNoInSequence = offset.QuadPart / This->parentStorage->bigBlockSize;
7574 ULONG offsetInBlock = offset.QuadPart % This->parentStorage->bigBlockSize;
7575 ULONG bytesToReadInBuffer;
7576 ULONG blockIndex;
7577 BYTE* bufferWalker;
7579 HRESULT hr;
7580 BlockChainBlock *cachedBlock;
7581
7582 TRACE("%p, %li, %p, %lu, %p.\n",This, offset.LowPart, buffer, size, bytesRead);
7583
7584 /*
7585 * Find the first block in the stream that contains part of the buffer.
7586 */
7587 blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
7588
7589 *bytesRead = 0;
7590
7592 if (stream_size.QuadPart > offset.QuadPart)
7593 size = min(stream_size.QuadPart - offset.QuadPart, size);
7594 else
7595 return S_OK;
7596
7597 /*
7598 * Start reading the buffer.
7599 */
7600 bufferWalker = buffer;
7601
7602 while (size > 0)
7603 {
7604 ULARGE_INTEGER ulOffset;
7605 DWORD bytesReadAt;
7606
7607 /*
7608 * Calculate how many bytes we can copy from this big block.
7609 */
7610 bytesToReadInBuffer =
7611 min(This->parentStorage->bigBlockSize - offsetInBlock, size);
7612
7613 hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToReadInBuffer);
7614
7615 if (FAILED(hr))
7616 return hr;
7617
7618 if (!cachedBlock)
7619 {
7620 /* Not in cache, and we're going to read past the end of the block. */
7621 ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
7622 offsetInBlock;
7623
7624 StorageImpl_ReadAt(This->parentStorage,
7625 ulOffset,
7626 bufferWalker,
7627 bytesToReadInBuffer,
7628 &bytesReadAt);
7629 }
7630 else
7631 {
7632 if (!cachedBlock->read)
7633 {
7634 ULONG read;
7635 if (FAILED(StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data, &read)) && !read)
7636 return STG_E_READFAULT;
7637
7638 cachedBlock->read = TRUE;
7639 }
7640
7641 memcpy(bufferWalker, cachedBlock->data+offsetInBlock, bytesToReadInBuffer);
7642 bytesReadAt = bytesToReadInBuffer;
7643 }
7644
7645 blockNoInSequence++;
7646 bufferWalker += bytesReadAt;
7647 size -= bytesReadAt;
7648 *bytesRead += bytesReadAt;
7649 offsetInBlock = 0; /* There is no offset on the next block */
7650
7651 if (bytesToReadInBuffer != bytesReadAt)
7652 break;
7653 }
7654
7655 return S_OK;
7656}
7657
7658/******************************************************************************
7659 * BlockChainStream_WriteAt
7660 *
7661 * Writes the specified number of bytes to this chain at the specified offset.
7662 * Will fail if not all specified number of bytes have been written.
7663 */
7666 ULONG size,
7667 const void* buffer,
7669{
7670 ULONG blockNoInSequence = offset.QuadPart / This->parentStorage->bigBlockSize;
7671 ULONG offsetInBlock = offset.QuadPart % This->parentStorage->bigBlockSize;
7672 ULONG bytesToWrite;
7673 ULONG blockIndex;
7674 const BYTE* bufferWalker;
7675 HRESULT hr;
7676 BlockChainBlock *cachedBlock;
7677
7678 *bytesWritten = 0;
7679 bufferWalker = buffer;
7680
7681 while (size > 0)
7682 {
7683 ULARGE_INTEGER ulOffset;
7684 DWORD bytesWrittenAt;
7685
7686 /*
7687 * Calculate how many bytes we can copy to this big block.
7688 */
7689 bytesToWrite =
7690 min(This->parentStorage->bigBlockSize - offsetInBlock, size);
7691
7692 hr = BlockChainStream_GetBlockAtOffset(This, blockNoInSequence, &cachedBlock, &blockIndex, size == bytesToWrite);
7693
7694 /* BlockChainStream_SetSize should have already been called to ensure we have
7695 * enough blocks in the chain to write into */
7696 if (FAILED(hr))
7697 {
7698 ERR("not enough blocks in chain to write data\n");
7699 return hr;
7700 }
7701
7702 if (!cachedBlock)
7703 {
7704 /* Not in cache, and we're going to write past the end of the block. */
7705 ulOffset.QuadPart = StorageImpl_GetBigBlockOffset(This->parentStorage, blockIndex) +
7706 offsetInBlock;
7707
7708 StorageImpl_WriteAt(This->parentStorage,
7709 ulOffset,
7710 bufferWalker,
7711 bytesToWrite,
7712 &bytesWrittenAt);
7713 }
7714 else
7715 {
7716 if (!cachedBlock->read && bytesToWrite != This->parentStorage->bigBlockSize)
7717 {
7718 ULONG read;
7719 if (FAILED(StorageImpl_ReadBigBlock(This->parentStorage, cachedBlock->sector, cachedBlock->data, &read)) && !read)
7720 return STG_E_READFAULT;
7721 }
7722
7723 memcpy(cachedBlock->data+offsetInBlock, bufferWalker, bytesToWrite);
7724 bytesWrittenAt = bytesToWrite;
7725 cachedBlock->read = TRUE;
7726 cachedBlock->dirty = TRUE;
7727 }
7728
7729 blockNoInSequence++;
7730 bufferWalker += bytesWrittenAt;
7731 size -= bytesWrittenAt;
7732 *bytesWritten += bytesWrittenAt;
7733 offsetInBlock = 0; /* There is no offset on the next block */
7734
7735 if (bytesWrittenAt != bytesToWrite)
7736 break;
7737 }
7738
7739 return (size == 0) ? S_OK : STG_E_WRITEFAULT;
7740}
7741
7742
7743/************************************************************************
7744 * SmallBlockChainStream implementation
7745 ***********************************************************************/
7746
7748 StorageImpl* parentStorage,
7749 ULONG* headOfStreamPlaceHolder,
7750 DirRef dirEntry)
7751{
7752 SmallBlockChainStream* newStream;
7753
7754 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
7755
7756 newStream->parentStorage = parentStorage;
7757 newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
7758 newStream->ownerDirEntry = dirEntry;
7759
7760 return newStream;
7761}
7762
7765{
7767}
7768
7769/******************************************************************************
7770 * SmallBlockChainStream_GetHeadOfChain
7771 *
7772 * Returns the head of this chain of small blocks.
7773 */
7776{
7777 DirEntry chainEntry;
7778 HRESULT hr;
7779
7780 if (This->headOfStreamPlaceHolder != NULL)
7781 return *(This->headOfStreamPlaceHolder);
7782
7783 if (This->ownerDirEntry)
7784 {
7786 This->parentStorage,
7787 This->ownerDirEntry,
7788 &chainEntry);
7789
7790 if (SUCCEEDED(hr) && chainEntry.startingBlock < BLOCK_FIRST_SPECIAL)
7791 return chainEntry.startingBlock;
7792 }
7793
7794 return BLOCK_END_OF_CHAIN;
7795}
7796
7797/******************************************************************************
7798 * SmallBlockChainStream_GetNextBlockInChain
7799 *
7800 * Returns the index of the next small block in this chain.
7801 *
7802 * Return Values:
7803 * - BLOCK_END_OF_CHAIN: end of this chain
7804 * - BLOCK_UNUSED: small block 'blockIndex' is free
7805 */
7808 ULONG blockIndex,
7809 ULONG* nextBlockInChain)
7810{
7811 ULARGE_INTEGER offsetOfBlockInDepot;
7812 DWORD buffer;
7813 ULONG bytesRead;
7814 HRESULT res;
7815
7816 *nextBlockInChain = BLOCK_END_OF_CHAIN;
7817
7818 offsetOfBlockInDepot.QuadPart = (ULONGLONG)blockIndex * sizeof(ULONG);
7819
7820 /*
7821 * Read those bytes in the buffer from the small block file.
7822 */
7824 This->parentStorage->smallBlockDepotChain,
7825 offsetOfBlockInDepot,
7826 sizeof(DWORD),
7827 &buffer,
7828 &bytesRead);
7829
7830 if (SUCCEEDED(res) && bytesRead != sizeof(DWORD))
7832
7833 if (SUCCEEDED(res))
7834 {
7835 StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
7836 return S_OK;
7837 }
7838
7839 return res;
7840}
7841
7842/******************************************************************************
7843 * SmallBlockChainStream_SetNextBlockInChain
7844 *
7845 * Writes the index of the next block of the specified block in the small
7846 * block depot.
7847 * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
7848 * To flag a block as free use BLOCK_UNUSED as nextBlock.
7849 */
7852 ULONG blockIndex,
7853 ULONG nextBlock)
7854{
7855 ULARGE_INTEGER offsetOfBlockInDepot;
7856 DWORD buffer;
7858
7859 offsetOfBlockInDepot.QuadPart = (ULONGLONG)blockIndex * sizeof(ULONG);
7860
7861 StorageUtl_WriteDWord(&buffer, 0, nextBlock);
7862
7863 /*
7864 * Read those bytes in the buffer from the small block file.
7865 */
7867 This->parentStorage->smallBlockDepotChain,
7868 offsetOfBlockInDepot,
7869 sizeof(DWORD),
7870 &buffer,
7871 &bytesWritten);
7872}
7873
7874/******************************************************************************
7875 * SmallBlockChainStream_FreeBlock
7876 *
7877 * Flag small block 'blockIndex' as free in the small block depot.
7878 */
7881 ULONG blockIndex)
7882{
7884}
7885
7886/******************************************************************************
7887 * SmallBlockChainStream_GetNextFreeBlock
7888 *
7889 * Returns the index of a free small block. The small block depot will be
7890 * enlarged if necessary. The small block chain will also be enlarged if
7891 * necessary.
7892 */
7895{
7896 ULARGE_INTEGER offsetOfBlockInDepot;
7897 DWORD buffer;
7898 ULONG bytesRead;
7899 ULONG blockIndex = This->parentStorage->firstFreeSmallBlock;
7900 ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
7901 HRESULT res = S_OK;
7902 ULONG smallBlocksPerBigBlock;
7903 DirEntry rootEntry;
7904 ULONG blocksRequired;
7905 ULARGE_INTEGER old_size, size_required;
7906
7907 offsetOfBlockInDepot.HighPart = 0;
7908
7909 /*
7910 * Scan the small block depot for a free block
7911 */
7912 while (nextBlockIndex != BLOCK_UNUSED)
7913 {
7914 offsetOfBlockInDepot.QuadPart = (ULONGLONG)blockIndex * sizeof(ULONG);
7915
7917 This->parentStorage->smallBlockDepotChain,
7918 offsetOfBlockInDepot,
7919 sizeof(DWORD),
7920 &buffer,
7921 &bytesRead);
7922
7923 /*
7924 * If we run out of space for the small block depot, enlarge it
7925 */
7926 if (SUCCEEDED(res) && bytesRead == sizeof(DWORD))
7927 {
7928 StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
7929
7930 if (nextBlockIndex != BLOCK_UNUSED)
7931 blockIndex++;
7932 }
7933 else
7934 {
7935 ULONG count =
7936 BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
7937
7938 BYTE smallBlockDepot[MAX_BIG_BLOCK_SIZE];
7939 ULARGE_INTEGER newSize, offset;
7941
7942 newSize.QuadPart = (ULONGLONG)(count + 1) * This->parentStorage->bigBlockSize;
7943 BlockChainStream_Enlarge(This->parentStorage->smallBlockDepotChain, newSize);
7944
7945 /*
7946 * Initialize all the small blocks to free
7947 */
7948 memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
7949 offset.QuadPart = (ULONGLONG)count * This->parentStorage->bigBlockSize;
7950 BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain,
7951 offset, This->parentStorage->bigBlockSize, smallBlockDepot, &bytesWritten);
7952
7953 StorageImpl_SaveFileHeader(This->parentStorage);
7954 }
7955 }
7956
7957 This->parentStorage->firstFreeSmallBlock = blockIndex+1;
7958
7959 smallBlocksPerBigBlock =
7960 This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
7961
7962 /*
7963 * Verify if we have to allocate big blocks to contain small blocks
7964 */
7965 blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
7966
7967 size_required.QuadPart = (ULONGLONG)blocksRequired * This->parentStorage->bigBlockSize;
7968
7969 old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain);
7970
7971 if (size_required.QuadPart > old_size.QuadPart)
7972 {
7974 This->parentStorage->smallBlockRootChain,
7975 size_required);
7976
7978 This->parentStorage,
7979 This->parentStorage->base.storageDirEntry,
7980 &rootEntry);
7981
7982 rootEntry.size = size_required;
7983
7985 This->parentStorage,
7986 This->parentStorage->base.storageDirEntry,
7987 &rootEntry);
7988 }
7989
7990 return blockIndex;
7991}
7992
7993/******************************************************************************
7994 * SmallBlockChainStream_ReadAt
7995 *
7996 * Reads a specified number of bytes from this chain at the specified offset.
7997 * bytesRead may be NULL.
7998 * Failure will be returned if the specified number of bytes has not been read.
7999 */
8003 ULONG size,
8004 void* buffer,
8005 ULONG* bytesRead)
8006{
8007 HRESULT rc = S_OK;
8008 ULARGE_INTEGER offsetInBigBlockFile;
8009 ULONG blockNoInSequence =
8010 offset.LowPart / This->parentStorage->smallBlockSize;
8011
8012 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
8013 ULONG bytesToReadInBuffer;
8014 ULONG blockIndex;
8015 ULONG bytesReadFromBigBlockFile;
8016 BYTE* bufferWalker;
8018
8019 /*
8020 * This should never happen on a small block file.
8021 */
8022 assert(offset.HighPart==0);
8023
8024 *bytesRead = 0;
8025
8027 if (stream_size.QuadPart > offset.QuadPart)
8028 size = min(stream_size.QuadPart - offset.QuadPart, size);
8029 else
8030 return S_OK;
8031
8032 /*
8033 * Find the first block in the stream that contains part of the buffer.
8034 */
8036
8037 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
8038 {
8039 rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
8040 if(FAILED(rc))
8041 return rc;
8042 blockNoInSequence--;
8043 }
8044
8045 /*
8046 * Start reading the buffer.
8047 */
8048 bufferWalker = buffer;
8049
8050 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
8051 {
8052 /*
8053 * Calculate how many bytes we can copy from this small block.
8054 */
8055 bytesToReadInBuffer =
8056 min(This->parentStorage->smallBlockSize - offsetInBlock, size);
8057
8058 /*
8059 * Calculate the offset of the small block in the small block file.
8060 */
8061 offsetInBigBlockFile.QuadPart =
8062 (ULONGLONG)blockIndex * This->parentStorage->smallBlockSize;
8063
8064 offsetInBigBlockFile.QuadPart += offsetInBlock;
8065
8066 /*
8067 * Read those bytes in the buffer from the small block file.
8068 * The small block has already been identified so it shouldn't fail
8069 * unless the file is corrupt.
8070 */
8071 rc = BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
8072 offsetInBigBlockFile,
8073 bytesToReadInBuffer,
8074 bufferWalker,
8075 &bytesReadFromBigBlockFile);
8076
8077 if (FAILED(rc))
8078 return rc;
8079
8080 if (!bytesReadFromBigBlockFile)
8081 return STG_E_DOCFILECORRUPT;
8082
8083 /*
8084 * Step to the next big block.
8085 */
8086 rc = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
8087 if(FAILED(rc))
8088 return STG_E_DOCFILECORRUPT;
8089
8090 bufferWalker += bytesReadFromBigBlockFile;
8091 size -= bytesReadFromBigBlockFile;
8092 *bytesRead += bytesReadFromBigBlockFile;
8093 offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
8094 }
8095
8096 return S_OK;
8097}
8098
8099/******************************************************************************
8100 * SmallBlockChainStream_WriteAt
8101 *
8102 * Writes the specified number of bytes to this chain at the specified offset.
8103 * Will fail if not all specified number of bytes have been written.
8104 */
8108 ULONG size,
8109 const void* buffer,
8111{
8112 ULARGE_INTEGER offsetInBigBlockFile;
8113 ULONG blockNoInSequence =
8114 offset.LowPart / This->parentStorage->smallBlockSize;
8115
8116 ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
8117 ULONG bytesToWriteInBuffer;
8118 ULONG blockIndex;
8119 ULONG bytesWrittenToBigBlockFile;
8120 const BYTE* bufferWalker;
8121 HRESULT res;
8122
8123 /*
8124 * This should never happen on a small block file.
8125 */
8126 assert(offset.HighPart==0);
8127
8128 /*
8129 * Find the first block in the stream that contains part of the buffer.
8130 */
8132
8133 while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
8134 {
8135 if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex)))
8136 return STG_E_DOCFILECORRUPT;
8137 blockNoInSequence--;
8138 }
8139
8140 /*
8141 * Start writing the buffer.
8142 */
8143 *bytesWritten = 0;
8144 bufferWalker = buffer;
8145 while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
8146 {
8147 /*
8148 * Calculate how many bytes we can copy to this small block.
8149 */
8150 bytesToWriteInBuffer =
8151 min(This->parentStorage->smallBlockSize - offsetInBlock, size);
8152
8153 /*
8154 * Calculate the offset of the small block in the small block file.
8155 */
8156 offsetInBigBlockFile.QuadPart =
8157 (ULONGLONG)blockIndex * This->parentStorage->smallBlockSize;
8158
8159 offsetInBigBlockFile.QuadPart += offsetInBlock;
8160
8161 /*
8162 * Write those bytes in the buffer to the small block file.
8163 */
8165 This->parentStorage->smallBlockRootChain,
8166 offsetInBigBlockFile,
8167 bytesToWriteInBuffer,
8168 bufferWalker,
8169 &bytesWrittenToBigBlockFile);
8170 if (FAILED(res))
8171 return res;
8172
8173 /*
8174 * Step to the next big block.
8175 */
8176 res = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex);
8177 if (FAILED(res))
8178 return res;
8179 bufferWalker += bytesWrittenToBigBlockFile;
8180 size -= bytesWrittenToBigBlockFile;
8181 *bytesWritten += bytesWrittenToBigBlockFile;
8182 offsetInBlock = (offsetInBlock + bytesWrittenToBigBlockFile) % This->parentStorage->smallBlockSize;
8183 }
8184
8185 return (size == 0) ? S_OK : STG_E_WRITEFAULT;
8186}
8187
8188/******************************************************************************
8189 * SmallBlockChainStream_Shrink
8190 *
8191 * Shrinks this chain in the small block depot.
8192 */
8195 ULARGE_INTEGER newSize)
8196{
8197 ULONG blockIndex, extraBlock;
8198 ULONG numBlocks;
8199 ULONG count = 0;
8200
8201 numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
8202
8203 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
8204 numBlocks++;
8205
8207
8208 /*
8209 * Go to the new end of chain
8210 */
8211 while (count < numBlocks)
8212 {
8214 &blockIndex)))
8215 return FALSE;
8216 count++;
8217 }
8218
8219 /*
8220 * If the count is 0, we have a special case, the head of the chain was
8221 * just freed.
8222 */
8223 if (count == 0)
8224 {
8225 DirEntry chainEntry;
8226
8227 StorageImpl_ReadDirEntry(This->parentStorage,
8228 This->ownerDirEntry,
8229 &chainEntry);
8230
8231 chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
8232
8233 StorageImpl_WriteDirEntry(This->parentStorage,
8234 This->ownerDirEntry,
8235 &chainEntry);
8236
8237 /*
8238 * We start freeing the chain at the head block.
8239 */
8240 extraBlock = blockIndex;
8241 }
8242 else
8243 {
8244 /* Get the next block before marking the new end */
8246 &extraBlock)))
8247 return FALSE;
8248
8249 /* Mark the new end of chain */
8251 This,
8252 blockIndex,
8254 }
8255
8256 /*
8257 * Mark the extra blocks as free
8258 */
8259 while (extraBlock != BLOCK_END_OF_CHAIN)
8260 {
8262 &blockIndex)))
8263 return FALSE;
8265 This->parentStorage->firstFreeSmallBlock = min(This->parentStorage->firstFreeSmallBlock, extraBlock);
8266 extraBlock = blockIndex;
8267 }
8268
8269 return TRUE;
8270}
8271
8272/******************************************************************************
8273 * SmallBlockChainStream_Enlarge
8274 *
8275 * Grows this chain in the small block depot.
8276 */
8279 ULARGE_INTEGER newSize)
8280{
8281 ULONG blockIndex, currentBlock;
8282 ULONG newNumBlocks;
8283 ULONG oldNumBlocks = 0;
8284
8286
8287 /*
8288 * Empty chain. Create the head.
8289 */
8290 if (blockIndex == BLOCK_END_OF_CHAIN)
8291 {
8294 This,
8295 blockIndex,
8297
8298 if (This->headOfStreamPlaceHolder != NULL)
8299 {
8300 *(This->headOfStreamPlaceHolder) = blockIndex;
8301 }
8302 else
8303 {
8304 DirEntry chainEntry;
8305
8306 StorageImpl_ReadDirEntry(This->parentStorage, This->ownerDirEntry,
8307 &chainEntry);
8308
8309 chainEntry.startingBlock = blockIndex;
8310
8311 StorageImpl_WriteDirEntry(This->parentStorage, This->ownerDirEntry,
8312 &chainEntry);
8313 }
8314 }
8315
8316 currentBlock = blockIndex;
8317
8318 /*
8319 * Figure out how many blocks are needed to contain this stream
8320 */
8321 newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
8322
8323 if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
8324 newNumBlocks++;
8325
8326 /*
8327 * Go to the current end of chain
8328 */
8329 while (blockIndex != BLOCK_END_OF_CHAIN)
8330 {
8331 oldNumBlocks++;
8332 currentBlock = blockIndex;
8333 if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex)))
8334 return FALSE;
8335 }
8336
8337 /*
8338 * Add new blocks to the chain
8339 */
8340 while (oldNumBlocks < newNumBlocks)
8341 {
8343 SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
8344
8346 This,
8347 blockIndex,
8349
8350 currentBlock = blockIndex;
8351 oldNumBlocks++;
8352 }
8353
8354 return TRUE;
8355}
8356
8357/******************************************************************************
8358 * SmallBlockChainStream_SetSize
8359 *
8360 * Sets the size of this stream.
8361 * The file will grow if we grow the chain.
8362 *
8363 * TODO: Free the actual blocks in the file when we shrink the chain.
8364 * Currently, the blocks are still in the file. So the file size
8365 * doesn't shrink even if we shrink streams.
8366 */
8369 ULARGE_INTEGER newSize)
8370{
8372
8373 if (newSize.LowPart == size.LowPart)
8374 return TRUE;
8375
8376 if (newSize.LowPart < size.LowPart)
8377 {
8379 }
8380 else
8381 {
8383 }
8384
8385 return TRUE;
8386}
8387
8388/******************************************************************************
8389 * SmallBlockChainStream_GetCount
8390 *
8391 * Returns the number of small blocks that comprises this chain.
8392 * This is not the size of the stream as the last block may not be full!
8393 *
8394 */
8396{
8397 ULONG blockIndex;
8398 ULONG count = 0;
8399
8401
8402 while(blockIndex != BLOCK_END_OF_CHAIN)
8403 {
8404 count++;
8405
8407 blockIndex, &blockIndex)))
8408 return 0;
8409 }
8410
8411 return count;
8412}
8413
8414/******************************************************************************
8415 * SmallBlockChainStream_GetSize
8416 *
8417 * Returns the size of this chain.
8418 */
8420{
8421 DirEntry chainEntry;
8422
8423 if(This->headOfStreamPlaceHolder != NULL)
8424 {
8426 result.HighPart = 0;
8427
8429 This->parentStorage->smallBlockSize;
8430
8431 return result;
8432 }
8433
8435 This->parentStorage,
8436 This->ownerDirEntry,
8437 &chainEntry);
8438
8439 return chainEntry.size;
8440}
8441
8442
8443/************************************************************************
8444 * Miscellaneous storage functions
8445 ***********************************************************************/
8446
8448 LPCOLESTR pwcsName,
8449 DWORD grfMode,
8450 DWORD grfAttrs,
8451 STGOPTIONS* pStgOptions,
8452 REFIID riid,
8453 void** ppstgOpen)
8454{
8455 StorageBaseImpl* newStorage = 0;
8458 DWORD shareMode;
8459 DWORD accessMode;
8460 DWORD creationMode;
8461 DWORD fileAttributes;
8462 WCHAR tempFileName[MAX_PATH];
8463
8464 if (ppstgOpen == 0)
8465 return STG_E_INVALIDPOINTER;
8466
8467 if (pStgOptions->ulSectorSize != MIN_BIG_BLOCK_SIZE && pStgOptions->ulSectorSize != MAX_BIG_BLOCK_SIZE)
8469
8470 /* if no share mode given then DENY_NONE is the default */
8471 if (STGM_SHARE_MODE(grfMode) == 0)
8472 grfMode |= STGM_SHARE_DENY_NONE;
8473
8474 if ( FAILED( validateSTGM(grfMode) ))
8475 goto end;
8476
8477 /* StgCreateDocFile seems to refuse readonly access, despite MSDN */
8478 switch(STGM_ACCESS_MODE(grfMode))
8479 {
8480 case STGM_WRITE:
8481 case STGM_READWRITE:
8482 break;
8483 default:
8484 goto end;
8485 }
8486
8487 /* in direct mode, can only use SHARE_EXCLUSIVE */
8488 if (!(grfMode & STGM_TRANSACTED) && (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE))
8489 goto end;
8490
8491 /* but in transacted mode, any share mode is valid */
8492
8493 /*
8494 * Generate a unique name.
8495 */
8496 if (pwcsName == 0)
8497 {
8498 WCHAR tempPath[MAX_PATH];
8499
8500 memset(tempPath, 0, sizeof(tempPath));
8501 memset(tempFileName, 0, sizeof(tempFileName));
8502
8503 if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
8504 tempPath[0] = '.';
8505
8506 if (GetTempFileNameW(tempPath, L"STO", 0, tempFileName) != 0)
8507 pwcsName = tempFileName;
8508 else
8509 {
8511 goto end;
8512 }
8513
8514 creationMode = TRUNCATE_EXISTING;
8515 }
8516 else
8517 {
8518 creationMode = GetCreationModeFromSTGM(grfMode);
8519 }
8520
8521 /*
8522 * Interpret the STGM value grfMode
8523 */
8524 shareMode = GetShareModeFromSTGM(grfMode);
8525 accessMode = GetAccessModeFromSTGM(grfMode);
8526
8527 if (grfMode & STGM_DELETEONRELEASE)
8529 else
8531
8532 *ppstgOpen = 0;
8533
8534 hFile = CreateFileW(pwcsName,
8535 accessMode,
8536 shareMode,
8537 NULL,
8538 creationMode,
8539 fileAttributes,
8540 0);
8541
8543 {
8546 else
8547 hr = E_FAIL;
8548 goto end;
8549 }
8550
8551 /*
8552 * Allocate and initialize the new IStorage object.
8553 */
8555 hFile,
8556 pwcsName,
8557 NULL,
8558 grfMode,
8559 TRUE,
8560 TRUE,
8561 pStgOptions->ulSectorSize,
8562 &newStorage);
8563
8564 if (FAILED(hr))
8565 {
8566 goto end;
8567 }
8568
8569 hr = IStorage_QueryInterface(&newStorage->IStorage_iface, riid, ppstgOpen);
8570 IStorage_Release(&newStorage->IStorage_iface);
8571
8572end:
8573 TRACE("<-- %p r = %#lx\n", *ppstgOpen, hr);
8574
8575 return hr;
8576}
8577
8578/******************************************************************************
8579 * StgCreateDocfile [OLE32.@]
8580 * Creates a new compound file storage object
8581 *
8582 * PARAMS
8583 * pwcsName [ I] Unicode string with filename (can be relative or NULL)
8584 * grfMode [ I] Access mode for opening the new storage object (see STGM_ constants)
8585 * reserved [ ?] unused?, usually 0
8586 * ppstgOpen [IO] A pointer to IStorage pointer to the new object
8587 *
8588 * RETURNS
8589 * S_OK if the file was successfully created
8590 * some STG_E_ value if error
8591 * NOTES
8592 * if pwcsName is NULL, create file with new unique name
8593 * the function can returns
8594 * STG_S_CONVERTED if the specified file was successfully converted to storage format
8595 * (unrealized now)
8596 */
8598 LPCOLESTR pwcsName,
8599 DWORD grfMode,
8601 IStorage **ppstgOpen)
8602{
8603 STGOPTIONS stgoptions = {1, 0, 512};
8604
8605 TRACE("%s, %#lx, %ld, %p.\n", debugstr_w(pwcsName), grfMode, reserved, ppstgOpen);
8606
8607 if (ppstgOpen == 0)
8608 return STG_E_INVALIDPOINTER;
8609 if (reserved != 0)
8611
8612 return create_storagefile(pwcsName, grfMode, 0, &stgoptions, &IID_IStorage, (void**)ppstgOpen);
8613}
8614
8615/******************************************************************************
8616 * StgCreateStorageEx [OLE32.@]
8617 */
8618HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
8619{
8620 TRACE("%s, %#lx, %#lx, %#lx, %p, %p, %p, %p.\n", debugstr_w(pwcsName),
8621 grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
8622
8623 if (stgfmt != STGFMT_FILE && grfAttrs != 0)
8624 {
8625 ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n");
8627 }
8628
8629 if (stgfmt == STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING)
8630 {
8631 ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n");
8633 }
8634
8635 if (stgfmt == STGFMT_FILE)
8636 {
8637 ERR("Cannot use STGFMT_FILE - this is NTFS only\n");
8639 }
8640
8641 if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE)
8642 {
8643 STGOPTIONS defaultOptions = {1, 0, 512};
8644
8645 if (!pStgOptions) pStgOptions = &defaultOptions;
8646 return create_storagefile(pwcsName, grfMode, grfAttrs, pStgOptions, riid, ppObjectOpen);
8647 }
8648
8649
8650 ERR("Invalid stgfmt argument\n");
8652}
8653
8654/******************************************************************************
8655 * StgOpenStorageEx [OLE32.@]
8656 */
8657HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen)
8658{
8659 TRACE("%s, %#lx, %#lx, %#lx, %p, %p, %p, %p.\n", debugstr_w(pwcsName),
8660 grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen);
8661
8662 if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0)
8663 {
8664 ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n");
8666 }
8667
8668 switch (stgfmt)
8669 {
8670 case STGFMT_FILE:
8671 ERR("Cannot use STGFMT_FILE - this is NTFS only\n");
8673
8674 case STGFMT_STORAGE:
8675 break;
8676
8677 case STGFMT_DOCFILE:
8678 if (grfAttrs && grfAttrs != FILE_FLAG_NO_BUFFERING)
8679 {
8680 ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n");
8682 }
8683 FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n");
8684 break;
8685
8686 case STGFMT_ANY:
8687 WARN("STGFMT_ANY assuming storage\n");
8688 break;
8689
8690 default:
8692 }
8693
8694 return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
8695}
8696
8697
8698/******************************************************************************
8699 * StgOpenStorage [OLE32.@]
8700 */
8702 const OLECHAR *pwcsName,
8703 IStorage *pstgPriority,
8704 DWORD grfMode,
8705 SNB snbExclude,
8707 IStorage **ppstgOpen)
8708{
8709 StorageBaseImpl* newStorage = 0;
8710 HRESULT hr = S_OK;
8711 HANDLE hFile = 0;
8712 DWORD shareMode;
8713 DWORD accessMode;
8714 LPWSTR temp_name = NULL;
8715
8716 TRACE("%s, %p, %#lx, %p, %ld, %p.\n", debugstr_w(pwcsName), pstgPriority, grfMode,
8717 snbExclude, reserved, ppstgOpen);
8718
8719 if (pstgPriority)
8720 {
8721 /* FIXME: Copy ILockBytes instead? But currently for STGM_PRIORITY it'll be read-only. */
8722 hr = StorageBaseImpl_GetFilename((StorageBaseImpl*)pstgPriority, &temp_name);
8723 if (FAILED(hr)) goto end;
8724 pwcsName = temp_name;
8725 TRACE("using filename %s\n", debugstr_w(temp_name));
8726 }
8727
8728 if (pwcsName == 0)
8729 {
8731 goto end;
8732 }
8733
8734 if (ppstgOpen == 0)
8735 {
8737 goto end;
8738 }
8739
8740 if (reserved)
8741 {
8743 goto end;
8744 }
8745
8746 if (grfMode & STGM_PRIORITY)
8747 {
8749 return STG_E_INVALIDFLAG;
8750 if (grfMode & STGM_DELETEONRELEASE)
8751 return STG_E_INVALIDFUNCTION;
8752 if(STGM_ACCESS_MODE(grfMode) != STGM_READ)
8753 return STG_E_INVALIDFLAG;
8754 grfMode &= ~0xf0; /* remove the existing sharing mode */
8755 grfMode |= STGM_SHARE_DENY_NONE;
8756 }
8757
8758 /*
8759 * Validate the sharing mode
8760 */
8761 if (grfMode & STGM_DIRECT_SWMR)
8762 {
8763 if ((STGM_SHARE_MODE(grfMode) != STGM_SHARE_DENY_WRITE) &&
8765 {
8767 goto end;
8768 }
8769 }
8770 else if (!(grfMode & (STGM_TRANSACTED|STGM_PRIORITY)))
8771 switch(STGM_SHARE_MODE(grfMode))
8772 {
8775 break;
8776 default:
8778 goto end;
8779 }
8780
8781 if ( FAILED( validateSTGM(grfMode) ) ||
8782 (grfMode&STGM_CREATE))
8783 {
8785 goto end;
8786 }
8787
8788 /* shared reading requires transacted or single writer mode */
8789 if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE &&
8790 STGM_ACCESS_MODE(grfMode) == STGM_READWRITE &&
8791 !(grfMode & STGM_TRANSACTED) && !(grfMode & STGM_DIRECT_SWMR))
8792 {
8794 goto end;
8795 }
8796
8797 /*
8798 * Interpret the STGM value grfMode
8799 */
8800 shareMode = GetShareModeFromSTGM(grfMode);
8801 accessMode = GetAccessModeFromSTGM(grfMode);
8802
8803 *ppstgOpen = 0;
8804
8805 hFile = CreateFileW( pwcsName,
8806 accessMode,
8807 shareMode,
8808 NULL,
8811 0);
8812
8814 {
8816
8817 hr = E_FAIL;
8818
8819 switch (last_error)
8820 {
8823 break;
8824
8827 break;
8828
8832 break;
8833
8836 break;
8837
8838 default:
8839 hr = E_FAIL;
8840 }
8841
8842 goto end;
8843 }
8844
8845 /*
8846 * Refuse to open the file if it's too small to be a structured storage file
8847 * FIXME: verify the file when reading instead of here
8848 */
8850 {
8853 goto end;
8854 }
8855
8856 /*
8857 * Allocate and initialize the new IStorage object.
8858 */
8860 hFile,
8861 pwcsName,
8862 NULL,
8863 grfMode,
8864 TRUE,
8865 FALSE,
8866 512,
8867 &newStorage);
8868
8869 if (FAILED(hr))
8870 {
8871 /*
8872 * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS
8873 */
8874 if(hr == STG_E_INVALIDHEADER)
8876 goto end;
8877 }
8878
8879 *ppstgOpen = &newStorage->IStorage_iface;
8880
8881end:
8882 CoTaskMemFree(temp_name);
8883 if (pstgPriority) IStorage_Release(pstgPriority);
8884 TRACE("<-- %#lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL);
8885 return hr;
8886}
8887
8888/******************************************************************************
8889 * StgCreateDocfileOnILockBytes [OLE32.@]
8890 */
8892 ILockBytes *plkbyt,
8893 DWORD grfMode,
8895 IStorage** ppstgOpen)
8896{
8897 StorageBaseImpl* newStorage = 0;
8898 HRESULT hr = S_OK;
8899
8900 if ((ppstgOpen == 0) || (plkbyt == 0))
8901 return STG_E_INVALIDPOINTER;
8902
8903 /*
8904 * Allocate and initialize the new IStorage object.
8905 */
8907 0,
8908 0,
8909 plkbyt,
8910 grfMode,
8911 FALSE,
8912 TRUE,
8913 512,
8914 &newStorage);
8915
8916 if (FAILED(hr))
8917 {
8918 return hr;
8919 }
8920
8921 *ppstgOpen = &newStorage->IStorage_iface;
8922
8923 return hr;
8924}
8925
8926/******************************************************************************
8927 * StgOpenStorageOnILockBytes [OLE32.@]
8928 */
8930 ILockBytes *plkbyt,
8931 IStorage *pstgPriority,
8932 DWORD grfMode,
8933 SNB snbExclude,
8935 IStorage **ppstgOpen)
8936{
8937 StorageBaseImpl* newStorage = 0;
8938 HRESULT hr = S_OK;
8939
8940 if ((plkbyt == 0) || (ppstgOpen == 0))
8941 return STG_E_INVALIDPOINTER;
8942
8943 if ( FAILED( validateSTGM(grfMode) ))
8944 return STG_E_INVALIDFLAG;
8945
8946 *ppstgOpen = 0;
8947
8948 /*
8949 * Allocate and initialize the new IStorage object.
8950 */
8952 0,
8953 0,
8954 plkbyt,
8955 grfMode,
8956 FALSE,
8957 FALSE,
8958 512,
8959 &newStorage);
8960
8961 if (FAILED(hr))
8962 {
8963 return hr;
8964 }
8965
8966 *ppstgOpen = &newStorage->IStorage_iface;
8967
8968 return hr;
8969}
8970
8971/******************************************************************************
8972 * StgSetTimes [ole32.@]
8973 * StgSetTimes [OLE32.@]
8974 *
8975 *
8976 */
8978 FILETIME const *patime, FILETIME const *pmtime)
8979{
8980 IStorage *stg = NULL;
8981 HRESULT r;
8982
8983 TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime);
8984
8986 0, 0, &stg);
8987 if( SUCCEEDED(r) )
8988 {
8989 r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime);
8990 IStorage_Release(stg);
8991 }
8992
8993 return r;
8994}
8995
8996/***********************************************************************
8997 * OleLoadFromStream (OLE32.@)
8998 *
8999 * This function loads an object from stream
9000 */
9001HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
9002{
9003 CLSID clsid;
9004 HRESULT res;
9005 LPPERSISTSTREAM xstm;
9006
9007 TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
9008
9009 res=ReadClassStm(pStm,&clsid);
9010 if (FAILED(res))
9011 return res;
9012 res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
9013 if (FAILED(res))
9014 return res;
9015 res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
9016 if (FAILED(res)) {
9017 IUnknown_Release((IUnknown*)*ppvObj);
9018 return res;
9019 }
9020 res=IPersistStream_Load(xstm,pStm);
9021 IPersistStream_Release(xstm);
9022 /* FIXME: all refcounts ok at this point? I think they should be:
9023 * pStm : unchanged
9024 * ppvObj : 1
9025 * xstm : 0 (released)
9026 */
9027 return res;
9028}
9029
9030/***********************************************************************
9031 * OleSaveToStream (OLE32.@)
9032 *
9033 * This function saves an object with the IPersistStream interface on it
9034 * to the specified stream.
9035 */
9037{
9038
9039 CLSID clsid;
9040 HRESULT res;
9041
9042 TRACE("(%p,%p)\n",pPStm,pStm);
9043
9044 res=IPersistStream_GetClassID(pPStm,&clsid);
9045
9046 if (SUCCEEDED(res)){
9047
9048 res=WriteClassStm(pStm,&clsid);
9049
9050 if (SUCCEEDED(res))
9051
9052 res=IPersistStream_Save(pPStm,pStm,TRUE);
9053 }
9054
9055 TRACE("Finished Save\n");
9056 return res;
9057}
9058
9059/*************************************************************************
9060 * STORAGE_CreateOleStream [Internal]
9061 *
9062 * Creates the "\001OLE" stream in the IStorage if necessary.
9063 *
9064 * PARAMS
9065 * storage [I] Dest storage to create the stream in
9066 * flags [I] flags to be set for newly created stream
9067 *
9068 * RETURNS
9069 * HRESULT return value
9070 *
9071 * NOTES
9072 *
9073 * This stream is still unknown, MS Word seems to have extra data
9074 * but since the data is stored in the OLESTREAM there should be
9075 * no need to recreate the stream. If the stream is manually
9076 * deleted it will create it with this default data.
9077 *
9078 */
9080{
9081 static const DWORD version_magic = 0x02000001;
9082 IStream *stream;
9083 HRESULT hr;
9084
9085 hr = IStorage_CreateStream(storage, L"\1Ole", STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stream);
9086 if (hr == S_OK)
9087 {
9088 struct empty_1ole_stream {
9089 DWORD version_magic;
9090 DWORD flags;
9091 DWORD update_options;
9093 DWORD mon_stream_size;
9094 };
9095 struct empty_1ole_stream stream_data;
9096
9097 stream_data.version_magic = version_magic;
9098 stream_data.flags = flags;
9099 stream_data.update_options = 0;
9100 stream_data.reserved = 0;
9101 stream_data.mon_stream_size = 0;
9102
9103 hr = IStream_Write(stream, &stream_data, sizeof(stream_data), NULL);
9104 IStream_Release(stream);
9105 }
9106
9107 return hr;
9108}
9109
9110/* write a string to a stream, preceded by its length */
9112{
9113 HRESULT r;
9114 LPSTR str;
9115 DWORD len = 0;
9116
9117 if( string )
9118 len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL);
9119 r = IStream_Write( stm, &len, sizeof(len), NULL);
9120 if( FAILED( r ) )
9121 return r;
9122 if(len == 0)
9123 return r;
9124 str = CoTaskMemAlloc( len );
9125 WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL);
9126 r = IStream_Write( stm, str, len, NULL);
9127 CoTaskMemFree( str );
9128 return r;
9129}
9130
9131/* read a string preceded by its length from a stream */
9133{
9134 HRESULT r;
9135 DWORD len, count = 0;
9136 LPSTR str;
9137 LPWSTR wstr;
9138
9139 r = IStream_Read( stm, &len, sizeof(len), &count );
9140 if( FAILED( r ) )
9141 return r;
9142 if( count != sizeof(len) )
9143 return E_OUTOFMEMORY;
9144
9145 TRACE("%ld bytes\n",len);
9146
9147 str = CoTaskMemAlloc( len );
9148 if( !str )
9149 return E_OUTOFMEMORY;
9150 count = 0;
9151 r = IStream_Read( stm, str, len, &count );
9152 if( FAILED( r ) )
9153 {
9154 CoTaskMemFree( str );
9155 return r;
9156 }
9157 if( count != len )
9158 {
9159 CoTaskMemFree( str );
9160 return E_OUTOFMEMORY;
9161 }
9162
9163 TRACE("Read string %s\n",debugstr_an(str,len));
9164
9166 wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) );
9167 if( wstr )
9168 {
9169 MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len );
9170 wstr[len] = 0;
9171 }
9172 CoTaskMemFree( str );
9173
9174 *string = wstr;
9175
9176 return r;
9177}
9178
9179
9181 LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName )
9182{
9183 IStream *pstm;
9184 HRESULT r = S_OK;
9185
9186 static const BYTE unknown1[12] =
9187 { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
9188 0xFF, 0xFF, 0xFF, 0xFF};
9189 static const BYTE unknown2[16] =
9190 { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
9191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
9192
9193 TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid),
9194 debugstr_w(lpszUserType), debugstr_w(szClipName),
9195 debugstr_w(szProgIDName));
9196
9197 /* Create a CompObj stream */
9198 r = IStorage_CreateStream(pstg, L"\1CompObj",
9199 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm );
9200 if( FAILED (r) )
9201 return r;
9202
9203 /* Write CompObj Structure to stream */
9204 r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL);
9205
9206 if( SUCCEEDED( r ) )
9207 r = WriteClassStm( pstm, clsid );
9208
9209 if( SUCCEEDED( r ) )
9210 r = STREAM_WriteString( pstm, lpszUserType );
9211 if( SUCCEEDED( r ) )
9212 r = STREAM_WriteString( pstm, szClipName );
9213 if( SUCCEEDED( r ) )
9214 r = STREAM_WriteString( pstm, szProgIDName );
9215 if( SUCCEEDED( r ) )
9216 r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL);
9217
9218 IStream_Release( pstm );
9219
9220 return r;
9221}
9222
9223/***********************************************************************
9224 * WriteFmtUserTypeStg (OLE32.@)
9225 */
9227 LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
9228{
9229 STATSTG stat;
9230 HRESULT r;
9231 WCHAR szwClipName[0x40];
9232 CLSID clsid;
9233 LPWSTR wstrProgID = NULL;
9234 DWORD n;
9235
9236 TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType));
9237
9238 /* get the clipboard format name */
9239 if( cf )
9240 {
9241 n = GetClipboardFormatNameW(cf, szwClipName, ARRAY_SIZE(szwClipName));
9242 szwClipName[n]=0;
9243 }
9244
9245 TRACE("Clipboard name is %s\n", debugstr_w(szwClipName));
9246
9247 r = IStorage_Stat(pstg, &stat, STATFLAG_NONAME);
9248 if(SUCCEEDED(r))
9249 clsid = stat.clsid;
9250 else
9251 clsid = CLSID_NULL;
9252
9253 ProgIDFromCLSID(&clsid, &wstrProgID);
9254
9255 TRACE("progid is %s\n",debugstr_w(wstrProgID));
9256
9257 r = STORAGE_WriteCompObj( pstg, &clsid, lpszUserType,
9258 cf ? szwClipName : NULL, wstrProgID );
9259
9260 CoTaskMemFree(wstrProgID);
9261
9262 return r;
9263}
9264
9265
9266/******************************************************************************
9267 * ReadFmtUserTypeStg [OLE32.@]
9268 */
9269HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType)
9270{
9271 HRESULT r;
9272 IStream *stm = 0;
9273 unsigned char unknown1[12];
9274 unsigned char unknown2[16];
9275 DWORD count;
9276 LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL;
9277 CLSID clsid;
9278
9279 TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType);
9280
9281 r = IStorage_OpenStream( pstg, L"\1CompObj", NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm );
9282 if( FAILED ( r ) )
9283 {
9284 WARN("Failed to open stream r = %#lx\n", r);
9285 return r;
9286 }
9287
9288 /* read the various parts of the structure */
9289 r = IStream_Read( stm, unknown1, sizeof(unknown1), &count );
9290 if( FAILED( r ) || ( count != sizeof(unknown1) ) )
9291 goto end;
9292 r = ReadClassStm( stm, &clsid );
9293 if( FAILED( r ) )
9294 goto end;
9295
9296 r = STREAM_ReadString( stm, &szCLSIDName );
9297 if( FAILED( r ) )
9298 goto end;
9299
9300 r = STREAM_ReadString( stm, &szOleTypeName );
9301 if( FAILED( r ) )
9302 goto end;
9303
9304 r = STREAM_ReadString( stm, &szProgIDName );
9305 if( FAILED( r ) )
9306 goto end;
9307
9308 r = IStream_Read( stm, unknown2, sizeof(unknown2), &count );
9309 if( FAILED( r ) || ( count != sizeof(unknown2) ) )
9310 goto end;
9311
9312 /* ok, success... now we just need to store what we found */
9313 if( pcf )
9314 *pcf = RegisterClipboardFormatW( szOleTypeName );
9315
9316 if( lplpszUserType )
9317 {
9318 *lplpszUserType = szCLSIDName;
9319 szCLSIDName = NULL;
9320 }
9321
9322end:
9323 CoTaskMemFree( szCLSIDName );
9324 CoTaskMemFree( szOleTypeName );
9325 CoTaskMemFree( szProgIDName );
9326 IStream_Release( stm );
9327
9328 return r;
9329}
9330
9331/************************************************************************
9332 * OleConvert Functions
9333 ***********************************************************************/
9334
9335#define OLESTREAM_ID 0x501
9336#define OLESTREAM_MAX_STR_LEN 255
9337
9338/* OLESTREAM memory structure to use for Get and Put Routines */
9339typedef struct
9340{
9349 CHAR strUnknown[8]; /* don't know what this 8 byte information in OLE stream is. */
9353
9354/* CompObj Stream structure */
9355typedef struct
9356{
9357 BYTE byUnknown1[12];
9365 BYTE byUnknown2[16];
9367
9368/* Ole Presentation Stream structure */
9369typedef struct
9370{
9371 BYTE byUnknown1[28];
9377
9378
9379/*************************************************************************
9380 * OLECONVERT_LoadOLE10 [Internal]
9381 *
9382 * Loads the OLE10 STREAM to memory
9383 *
9384 * PARAMS
9385 * pOleStream [I] The OLESTREAM
9386 * pData [I] Data Structure for the OLESTREAM Data
9387 *
9388 * RETURNS
9389 * Success: S_OK
9390 * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get
9391 * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalid
9392 *
9393 * NOTES
9394 * This function is used by OleConvertOLESTREAMToIStorage only.
9395 *
9396 * Memory allocated for pData must be freed by the caller
9397 */
9399{
9400 DWORD dwSize;
9401 HRESULT hRes = S_OK;
9402 int nTryCnt=0;
9403 int max_try = 6;
9404
9405 pData->pData = NULL;
9406 pData->pstrOleObjFileName = NULL;
9407
9408 for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
9409 {
9410 /* Get the OleID */
9411 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
9412 if(dwSize != sizeof(pData->dwOleID))
9413 {
9415 }
9416 else if(pData->dwOleID != OLESTREAM_ID)
9417 {
9419 }
9420 else
9421 {
9422 hRes = S_OK;
9423 break;
9424 }
9425 }
9426
9427 if(hRes == S_OK)
9428 {
9429 /* Get the TypeID... more info needed for this field */
9430 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
9431 if(dwSize != sizeof(pData->dwTypeID))
9432 {
9434 }
9435 }
9436 if(hRes == S_OK)
9437 {
9438 if(pData->dwTypeID != 0)
9439 {
9440 /* Get the length of the OleTypeName */
9441 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
9442 if(dwSize != sizeof(pData->dwOleTypeNameLength))
9443 {
9445 }
9446
9447 if(hRes == S_OK)
9448 {
9449 if(pData->dwOleTypeNameLength > 0)
9450 {
9451 /* Get the OleTypeName */
9452 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
9453 if(dwSize != pData->dwOleTypeNameLength)
9454 {
9456 }
9457 }
9458 }
9459 if(bStream1)
9460 {
9461 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength));
9462 if(dwSize != sizeof(pData->dwOleObjFileNameLength))
9463 {
9465 }
9466 if(hRes == S_OK)
9467 {
9468 if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */
9469 pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength);
9470 pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength);
9471 if(pData->pstrOleObjFileName)
9472 {
9473 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->pstrOleObjFileName, pData->dwOleObjFileNameLength);
9474 if(dwSize != pData->dwOleObjFileNameLength)
9475 {
9477 }
9478 }
9479 else
9481 }
9482 }
9483 else
9484 {
9485 /* Get the Width of the Metafile */
9486 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
9487 if(dwSize != sizeof(pData->dwMetaFileWidth))
9488 {
9490 }
9491 if(hRes == S_OK)
9492 {
9493 /* Get the Height of the Metafile */
9494 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
9495 if(dwSize != sizeof(pData->dwMetaFileHeight))
9496 {
9498 }
9499 }
9500 }
9501 if(hRes == S_OK)
9502 {
9503 /* Get the Length of the Data */
9504 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
9505 if(dwSize != sizeof(pData->dwDataLength))
9506 {
9508 }
9509 }
9510
9511 if(hRes == S_OK) /* I don't know what this 8 byte information is. We have to figure out */
9512 {
9513 if(!bStream1) /* if it is a second OLE stream data */
9514 {
9515 pData->dwDataLength -= 8;
9516 dwSize = pOleStream->lpstbl->Get(pOleStream, pData->strUnknown, sizeof(pData->strUnknown));
9517 if(dwSize != sizeof(pData->strUnknown))
9518 {
9520 }
9521 }
9522 }
9523 if(hRes == S_OK)
9524 {
9525 if(pData->dwDataLength > 0)
9526 {
9527 pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength);
9528
9529 /* Get Data (ex. IStorage, Metafile, or BMP) */
9530 if(pData->pData)
9531 {
9532 dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength);
9533 if(dwSize != pData->dwDataLength)
9534 {
9536 }
9537 }
9538 else
9539 {
9541 }
9542 }
9543 }
9544 }
9545 }
9546 return hRes;
9547}
9548
9549/*************************************************************************
9550 * OLECONVERT_SaveOLE10 [Internal]
9551 *
9552 * Saves the OLE10 STREAM From memory
9553 *
9554 * PARAMS
9555 * pData [I] Data Structure for the OLESTREAM Data
9556 * pOleStream [I] The OLESTREAM to save
9557 *
9558 * RETURNS
9559 * Success: S_OK
9560 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
9561 *
9562 * NOTES
9563 * This function is used by OleConvertIStorageToOLESTREAM only.
9564 *
9565 */
9567{
9568 DWORD dwSize;
9569 HRESULT hRes = S_OK;
9570
9571
9572 /* Set the OleID */
9573 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID));
9574 if(dwSize != sizeof(pData->dwOleID))
9575 {
9577 }
9578
9579 if(hRes == S_OK)
9580 {
9581 /* Set the TypeID */
9582 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID));
9583 if(dwSize != sizeof(pData->dwTypeID))
9584 {
9586 }
9587 }
9588
9589 if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK)
9590 {
9591 /* Set the Length of the OleTypeName */
9592 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
9593 if(dwSize != sizeof(pData->dwOleTypeNameLength))
9594 {
9596 }
9597
9598 if(hRes == S_OK)
9599 {
9600 if(pData->dwOleTypeNameLength > 0)
9601 {
9602 /* Set the OleTypeName */
9603 dwSize = pOleStream->lpstbl->Put(pOleStream, pData->strOleTypeName, pData->dwOleTypeNameLength);
9604 if(dwSize != pData->dwOleTypeNameLength)
9605 {
9607 }
9608 }
9609 }
9610
9611 if(hRes == S_OK)
9612 {
9613 /* Set the width of the Metafile */
9614 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
9615 if(dwSize != sizeof(pData->dwMetaFileWidth))
9616 {
9618 }
9619 }
9620
9621 if(hRes == S_OK)
9622 {
9623 /* Set the height of the Metafile */
9624 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
9625 if(dwSize != sizeof(pData->dwMetaFileHeight))
9626 {
9628 }
9629 }
9630
9631 if(hRes == S_OK)
9632 {
9633 /* Set the length of the Data */
9634 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength));
9635 if(dwSize != sizeof(pData->dwDataLength))
9636 {
9638 }
9639 }
9640
9641 if(hRes == S_OK)
9642 {
9643 if(pData->dwDataLength > 0)
9644 {
9645 /* Set the Data (eg. IStorage, Metafile, Bitmap) */
9646 dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength);
9647 if(dwSize != pData->dwDataLength)
9648 {
9650 }
9651 }
9652 }
9653 }
9654 return hRes;
9655}
9656
9657/*************************************************************************
9658 * OLECONVERT_GetOLE20FromOLE10[Internal]
9659 *
9660 * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
9661 * opens it, and copies the content to the dest IStorage for
9662 * OleConvertOLESTREAMToIStorage
9663 *
9664 *
9665 * PARAMS
9666 * pDestStorage [I] The IStorage to copy the data to
9667 * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM
9668 * nBufferLength [I] The size of the buffer
9669 *
9670 * RETURNS
9671 * Nothing
9672 *
9673 * NOTES
9674 *
9675 *
9676 */
9678{
9679 HRESULT hRes;
9680 HANDLE hFile;
9681 IStorage *pTempStorage;
9682 DWORD dwNumOfBytesWritten;
9683 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
9684
9685 /* Create a temp File */
9686 GetTempPathW(MAX_PATH, wstrTempDir);
9687 GetTempFileNameW(wstrTempDir, L"sis", 0, wstrTempFile);
9689
9691 {
9692 /* Write IStorage Data to File */
9693 WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
9695
9696 /* Open and copy temp storage to the Dest Storage */
9697 hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
9698 if(hRes == S_OK)
9699 {
9700 hRes = IStorage_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage);
9701 IStorage_Release(pTempStorage);
9702 }
9703 DeleteFileW(wstrTempFile);
9704 }
9705}
9706
9707
9708/*************************************************************************
9709 * OLECONVERT_WriteOLE20ToBuffer [Internal]
9710 *
9711 * Saves the OLE10 STREAM From memory
9712 *
9713 * PARAMS
9714 * pStorage [I] The Src IStorage to copy
9715 * pData [I] The Dest Memory to write to.
9716 *
9717 * RETURNS
9718 * The size in bytes allocated for pData
9719 *
9720 * NOTES
9721 * Memory allocated for pData must be freed by the caller
9722 *
9723 * Used by OleConvertIStorageToOLESTREAM only.
9724 *
9725 */
9727{
9728 HANDLE hFile;
9729 HRESULT hRes;
9730 DWORD nDataLength = 0;
9731 IStorage *pTempStorage;
9732 WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
9733
9734 *pData = NULL;
9735
9736 /* Create temp Storage */
9737 GetTempPathW(MAX_PATH, wstrTempDir);
9738 GetTempFileNameW(wstrTempDir, L"sis", 0, wstrTempFile);
9739 hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage);
9740
9741 if(hRes == S_OK)
9742 {
9743 /* Copy Src Storage to the Temp Storage */
9744 IStorage_CopyTo(pStorage, 0, NULL, NULL, pTempStorage);
9745 IStorage_Release(pTempStorage);
9746
9747 /* Open Temp Storage as a file and copy to memory */
9750 {
9751 nDataLength = GetFileSize(hFile, NULL);
9752 *pData = HeapAlloc(GetProcessHeap(),0,nDataLength);
9753 ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
9755 }
9756 DeleteFileW(wstrTempFile);
9757 }
9758 return nDataLength;
9759}
9760
9761/*************************************************************************
9762 * OLECONVERT_CreateCompObjStream [Internal]
9763 *
9764 * Creates a "\001CompObj" is the destination IStorage if necessary.
9765 *
9766 * PARAMS
9767 * pStorage [I] The dest IStorage to create the CompObj Stream
9768 * if necessary.
9769 * strOleTypeName [I] The ProgID
9770 *
9771 * RETURNS
9772 * Success: S_OK
9773 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
9774 *
9775 * NOTES
9776 * This function is used by OleConvertOLESTREAMToIStorage only.
9777 *
9778 * The stream data is stored in the OLESTREAM and there should be
9779 * no need to recreate the stream. If the stream is manually
9780 * deleted it will attempt to create it by querying the registry.
9781 *
9782 *
9783 */
9785{
9786 IStream *pStream;
9787 HRESULT hStorageRes, hRes = S_OK;
9788 OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
9790
9791 static const BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
9792 static const BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
9793
9794 /* Initialize the CompObj structure */
9795 memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
9796 memcpy(IStorageCompObj.byUnknown1, pCompObjUnknown1, sizeof(pCompObjUnknown1));
9797 memcpy(IStorageCompObj.byUnknown2, pCompObjUnknown2, sizeof(pCompObjUnknown2));
9798
9799
9800 /* Create a CompObj stream if it doesn't exist */
9801 hStorageRes = IStorage_CreateStream(pStorage, L"\1CompObj",
9802 STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
9803 if(hStorageRes == S_OK)
9804 {
9805 /* copy the OleTypeName to the compobj struct */
9806 IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
9807 strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
9808
9809 /* copy the OleTypeName to the compobj struct */
9810 /* Note: in the test made, these were Identical */
9811 IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
9812 strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
9813
9814 /* Get the CLSID */
9815 MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1,
9816 bufferW, OLESTREAM_MAX_STR_LEN );
9817 hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid));
9818
9819 if(hRes == S_OK)
9820 {
9821 HKEY hKey;
9822 LONG hErr;
9823 /* Get the CLSID Default Name from the Registry */
9825 if(hErr == ERROR_SUCCESS)
9826 {
9827 char strTemp[OLESTREAM_MAX_STR_LEN];
9828 IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
9829 hErr = RegQueryValueA(hKey, NULL, strTemp, (LONG*) &(IStorageCompObj.dwCLSIDNameLength));
9830 if(hErr == ERROR_SUCCESS)
9831 {
9832 strcpy(IStorageCompObj.strCLSIDName, strTemp);
9833 }
9835 }
9836 }
9837
9838 /* Write CompObj Structure to stream */
9839 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
9840
9841 WriteClassStm(pStream,&(IStorageCompObj.clsid));
9842
9843 hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
9844 if(IStorageCompObj.dwCLSIDNameLength > 0)
9845 {
9846 hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
9847 }
9848 hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
9849 if(IStorageCompObj.dwOleTypeNameLength > 0)
9850 {
9851 hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
9852 }
9853 hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
9854 if(IStorageCompObj.dwProgIDNameLength > 0)
9855 {
9856 hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
9857 }
9858 hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
9859 IStream_Release(pStream);
9860 }
9861 return hRes;
9862}
9863
9864
9865/*************************************************************************
9866 * OLECONVERT_CreateOlePresStream[Internal]
9867 *
9868 * Creates the "\002OlePres000" Stream with the Metafile data
9869 *
9870 * PARAMS
9871 * pStorage [I] The dest IStorage to create \002OLEPres000 stream in.
9872 * dwExtentX [I] Width of the Metafile
9873 * dwExtentY [I] Height of the Metafile
9874 * pData [I] Metafile data
9875 * dwDataLength [I] Size of the Metafile data
9876 *
9877 * RETURNS
9878 * Success: S_OK
9879 * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put
9880 *
9881 * NOTES
9882 * This function is used by OleConvertOLESTREAMToIStorage only.
9883 *
9884 */
9885static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
9886{
9887 HRESULT hRes;
9888 IStream *pStream;
9889 static const BYTE pOlePresStreamHeader[] =
9890 {
9891 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
9892 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
9893 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
9894 0x00, 0x00, 0x00, 0x00
9895 };
9896
9897 static const BYTE pOlePresStreamHeaderEmpty[] =
9898 {
9899 0x00, 0x00, 0x00, 0x00,
9900 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
9901 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
9902 0x00, 0x00, 0x00, 0x00
9903 };
9904
9905 /* Create the OlePres000 Stream */
9906 hRes = IStorage_CreateStream(pStorage, L"\2OlePres000",
9907 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
9908
9909 if(hRes == S_OK)
9910 {
9911 DWORD nHeaderSize;
9913
9914 memset(&OlePres, 0, sizeof(OlePres));
9915 /* Do we have any metafile data to save */
9916 if(dwDataLength > 0)
9917 {
9918 memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader));
9919 nHeaderSize = sizeof(pOlePresStreamHeader);
9920 }
9921 else
9922 {
9923 memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
9924 nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
9925 }
9926 /* Set width and height of the metafile */
9927 OlePres.dwExtentX = dwExtentX;
9928 OlePres.dwExtentY = -dwExtentY;
9929
9930 /* Set Data and Length */
9931 if(dwDataLength > sizeof(METAFILEPICT16))
9932 {
9933 OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
9934 OlePres.pData = &(pData[8]);
9935 }
9936 /* Save OlePres000 Data to Stream */
9937 hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
9938 hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
9939 hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
9940 hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
9941 if(OlePres.dwSize > 0)
9942 {
9943 hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
9944 }
9945 IStream_Release(pStream);
9946 }
9947}
9948
9949/*************************************************************************
9950 * OLECONVERT_CreateOle10NativeStream [Internal]
9951 *
9952 * Creates the "\001Ole10Native" Stream (should contain a BMP)
9953 *
9954 * PARAMS
9955 * pStorage [I] Dest storage to create the stream in
9956 * pData [I] Ole10 Native Data (ex. bmp)
9957 * dwDataLength [I] Size of the Ole10 Native Data
9958 *
9959 * RETURNS
9960 * Nothing
9961 *
9962 * NOTES
9963 * This function is used by OleConvertOLESTREAMToIStorage only.
9964 *
9965 * Might need to verify the data and return appropriate error message
9966 *
9967 */
9968static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
9969{
9970 HRESULT hRes;
9971 IStream *pStream;
9972
9973 /* Create the Ole10Native Stream */
9974 hRes = IStorage_CreateStream(pStorage, L"\1Ole10Native",
9975 STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
9976
9977 if(hRes == S_OK)
9978 {
9979 /* Write info to stream */
9980 hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
9981 hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
9982 IStream_Release(pStream);
9983 }
9984
9985}
9986
9987/*************************************************************************
9988 * OLECONVERT_GetOLE10ProgID [Internal]
9989 *
9990 * Finds the ProgID (or OleTypeID) from the IStorage
9991 *
9992 * PARAMS
9993 * pStorage [I] The Src IStorage to get the ProgID
9994 * strProgID [I] the ProgID string to get
9995 * dwSize [I] the size of the string
9996 *
9997 * RETURNS
9998 * Success: S_OK
9999 * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream
10000 *
10001 * NOTES
10002 * This function is used by OleConvertIStorageToOLESTREAM only.
10003 *
10004 *
10005 */
10006static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
10007{
10008 HRESULT hRes;
10009 IStream *pStream;
10010 LARGE_INTEGER iSeekPos;
10012
10013 /* Open the CompObj Stream */
10014 hRes = IStorage_OpenStream(pStorage, L"\1CompObj", NULL,
10015 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
10016 if(hRes == S_OK)
10017 {
10018
10019 /*Get the OleType from the CompObj Stream */
10020 iSeekPos.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
10021 iSeekPos.HighPart = 0;
10022
10023 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
10024 IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
10025 iSeekPos.LowPart = CompObj.dwCLSIDNameLength;
10026 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
10027 IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
10028 iSeekPos.LowPart = CompObj.dwOleTypeNameLength;
10029 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
10030
10031 IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
10032 if(*dwSize > 0)
10033 {
10034 IStream_Read(pStream, strProgID, *dwSize, NULL);
10035 }
10036 IStream_Release(pStream);
10037 }
10038 else
10039 {
10040 STATSTG stat;
10041 LPOLESTR wstrProgID;
10042
10043 /* Get the OleType from the registry */
10044 REFCLSID clsid = &(stat.clsid);
10045 IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
10046 hRes = ProgIDFromCLSID(clsid, &wstrProgID);
10047 if(hRes == S_OK)
10048 {
10049 *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
10050 CoTaskMemFree(wstrProgID);
10051 }
10052
10053 }
10054 return hRes;
10055}
10056
10057/*************************************************************************
10058 * OLECONVERT_GetOle10PresData [Internal]
10059 *
10060 * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
10061 *
10062 * PARAMS
10063 * pStorage [I] Src IStroage
10064 * pOleStream [I] Dest OleStream Mem Struct
10065 *
10066 * RETURNS
10067 * Nothing
10068 *
10069 * NOTES
10070 * This function is used by OleConvertIStorageToOLESTREAM only.
10071 *
10072 * Memory allocated for pData must be freed by the caller
10073 *
10074 *
10075 */
10077{
10078
10079 HRESULT hRes;
10080 IStream *pStream;
10081
10082 /* Initialize Default data for OLESTREAM */
10083 pOleStreamData[0].dwOleID = OLESTREAM_ID;
10084 pOleStreamData[0].dwTypeID = 2;
10085 pOleStreamData[1].dwOleID = OLESTREAM_ID;
10086 pOleStreamData[1].dwTypeID = 0;
10087 pOleStreamData[0].dwMetaFileWidth = 0;
10088 pOleStreamData[0].dwMetaFileHeight = 0;
10089 pOleStreamData[0].pData = NULL;
10090 pOleStreamData[1].pData = NULL;
10091
10092 /* Open Ole10Native Stream */
10093 hRes = IStorage_OpenStream(pStorage, L"\1Ole10Native", NULL,
10094 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
10095 if(hRes == S_OK)
10096 {
10097
10098 /* Read Size and Data */
10099 IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
10100 if(pOleStreamData->dwDataLength > 0)
10101 {
10102 pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength);
10103 IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
10104 }
10105 IStream_Release(pStream);
10106 }
10107
10108}
10109
10110
10111/*************************************************************************
10112 * OLECONVERT_GetOle20PresData[Internal]
10113 *
10114 * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
10115 *
10116 * PARAMS
10117 * pStorage [I] Src IStroage
10118 * pOleStreamData [I] Dest OleStream Mem Struct
10119 *
10120 * RETURNS
10121 * Nothing
10122 *
10123 * NOTES
10124 * This function is used by OleConvertIStorageToOLESTREAM only.
10125 *
10126 * Memory allocated for pData must be freed by the caller
10127 */
10129{
10130 HRESULT hRes;
10131 IStream *pStream;
10133
10134 /* Initialize Default data for OLESTREAM */
10135 pOleStreamData[0].dwOleID = OLESTREAM_ID;
10136 pOleStreamData[0].dwTypeID = 2;
10137 pOleStreamData[0].dwMetaFileWidth = 0;
10138 pOleStreamData[0].dwMetaFileHeight = 0;
10139 pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData));
10140 pOleStreamData[1].dwOleID = OLESTREAM_ID;
10141 pOleStreamData[1].dwTypeID = 0;
10142 pOleStreamData[1].dwOleTypeNameLength = 0;
10143 pOleStreamData[1].strOleTypeName[0] = 0;
10144 pOleStreamData[1].dwMetaFileWidth = 0;
10145 pOleStreamData[1].dwMetaFileHeight = 0;
10146 pOleStreamData[1].pData = NULL;
10147 pOleStreamData[1].dwDataLength = 0;
10148
10149
10150 /* Open OlePress000 stream */
10151 hRes = IStorage_OpenStream(pStorage, L"\2OlePres000", NULL,
10152 STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream );
10153 if(hRes == S_OK)
10154 {
10155 LARGE_INTEGER iSeekPos;
10156 METAFILEPICT16 MetaFilePict;
10157 static const char strMetafilePictName[] = "METAFILEPICT";
10158
10159 /* Set the TypeID for a Metafile */
10160 pOleStreamData[1].dwTypeID = 5;
10161
10162 /* Set the OleTypeName to Metafile */
10163 pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
10164 strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
10165
10166 iSeekPos.HighPart = 0;
10167 iSeekPos.LowPart = sizeof(olePress.byUnknown1);
10168
10169 /* Get Presentation Data */
10170 IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
10171 IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
10172 IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
10173 IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
10174
10175 /*Set width and Height */
10176 pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
10177 pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
10178 if(olePress.dwSize > 0)
10179 {
10180 /* Set Length */
10181 pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16);
10182
10183 /* Set MetaFilePict struct */
10184 MetaFilePict.mm = 8;
10185 MetaFilePict.xExt = olePress.dwExtentX;
10186 MetaFilePict.yExt = olePress.dwExtentY;
10187 MetaFilePict.hMF = 0;
10188
10189 /* Get Metafile Data */
10190 pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength);
10191 memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
10192 IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
10193 }
10194 IStream_Release(pStream);
10195 }
10196}
10197
10198/*************************************************************************
10199 * OleConvertOLESTREAMToIStorage [OLE32.@]
10200 *
10201 * Read info on MSDN
10202 *
10203 * TODO
10204 * DVTARGETDEVICE parameter is not handled
10205 * Still unsure of some mem fields for OLE 10 Stream
10206 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
10207 * and "\001OLE" streams
10208 *
10209 */
10211 LPOLESTREAM pOleStream,
10212 LPSTORAGE pstg,
10213 const DVTARGETDEVICE* ptd)
10214{
10215 int i;
10216 HRESULT hRes=S_OK;
10217 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
10218
10219 TRACE("%p %p %p\n", pOleStream, pstg, ptd);
10220
10221 memset(pOleStreamData, 0, sizeof(pOleStreamData));
10222
10223 if(ptd != NULL)
10224 {
10225 FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
10226 }
10227
10228 if(pstg == NULL || pOleStream == NULL)
10229 {
10230 hRes = E_INVALIDARG;
10231 }
10232
10233 if(hRes == S_OK)
10234 {
10235 /* Load the OLESTREAM to Memory */
10236 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE);
10237 }
10238
10239 if(hRes == S_OK)
10240 {
10241 /* Load the OLESTREAM to Memory (part 2)*/
10242 hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE);
10243 }
10244
10245 if(hRes == S_OK)
10246 {
10247
10248 if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
10249 {
10250 /* Do we have the IStorage Data in the OLESTREAM */
10251 if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
10252 {
10253 OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
10254 OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
10255 }
10256 else
10257 {
10258 /* It must be an original OLE 1.0 source */
10259 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
10260 }
10261 }
10262 else
10263 {
10264 /* It must be an original OLE 1.0 source */
10265 OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
10266 }
10267
10268 /* Create CompObj Stream if necessary */
10269 hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName);
10270 if(hRes == S_OK)
10271 {
10272 /*Create the Ole Stream if necessary */
10273 STORAGE_CreateOleStream(pstg, 0);
10274 }
10275 }
10276
10277
10278 /* Free allocated memory */
10279 for(i=0; i < 2; i++)
10280 {
10281 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
10282 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName);
10283 pOleStreamData[i].pstrOleObjFileName = NULL;
10284 }
10285 return hRes;
10286}
10287
10288/*************************************************************************
10289 * OleConvertIStorageToOLESTREAM [OLE32.@]
10290 *
10291 * Read info on MSDN
10292 *
10293 * Read info on MSDN
10294 *
10295 * TODO
10296 * Still unsure of some mem fields for OLE 10 Stream
10297 * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
10298 * and "\001OLE" streams.
10299 *
10300 */
10302 LPSTORAGE pstg,
10303 LPOLESTREAM pOleStream)
10304{
10305 int i;
10306 HRESULT hRes = S_OK;
10307 IStream *pStream;
10308 OLECONVERT_OLESTREAM_DATA pOleStreamData[2];
10309
10310 TRACE("%p %p\n", pstg, pOleStream);
10311
10312 memset(pOleStreamData, 0, sizeof(pOleStreamData));
10313
10314 if(pstg == NULL || pOleStream == NULL)
10315 {
10316 hRes = E_INVALIDARG;
10317 }
10318 if(hRes == S_OK)
10319 {
10320 /* Get the ProgID */
10321 pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
10322 hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
10323 }
10324 if(hRes == S_OK)
10325 {
10326 /* Was it originally Ole10 */
10327 hRes = IStorage_OpenStream(pstg, L"\1Ole10Native", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
10328 if(hRes == S_OK)
10329 {
10330 IStream_Release(pStream);
10331 /* Get Presentation Data for Ole10Native */
10332 OLECONVERT_GetOle10PresData(pstg, pOleStreamData);
10333 }
10334 else
10335 {
10336 /* Get Presentation Data (OLE20) */
10337 OLECONVERT_GetOle20PresData(pstg, pOleStreamData);
10338 }
10339
10340 /* Save OLESTREAM */
10341 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
10342 if(hRes == S_OK)
10343 {
10344 hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
10345 }
10346
10347 }
10348
10349 /* Free allocated memory */
10350 for(i=0; i < 2; i++)
10351 {
10352 HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData);
10353 }
10354
10355 return hRes;
10356}
10357
10360 OleStream_Convert = 0x00000004
10362
10363/*************************************************************************
10364 * OleConvertIStorageToOLESTREAMEx [OLE32.@]
10365 */
10367 DWORD size, LPSTGMEDIUM medium, LPOLESTREAM olestream )
10368{
10369 FIXME("%p, %x, %ld, %ld, %ld, %p, %p: stub\n", stg, cf, width, height, size, medium, olestream);
10370
10371 return E_NOTIMPL;
10372}
10373
10374/***********************************************************************
10375 * SetConvertStg (OLE32.@)
10376 */
10378{
10380 IStream *stream;
10381 DWORD header[2];
10382 HRESULT hr;
10383
10384 TRACE("(%p, %d)\n", storage, convert);
10385
10386 hr = IStorage_OpenStream(storage, L"\1Ole", NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stream);
10387 if (FAILED(hr))
10388 {
10389 if (hr != STG_E_FILENOTFOUND)
10390 return hr;
10391
10393 }
10394
10395 hr = IStream_Read(stream, header, sizeof(header), NULL);
10396 if (FAILED(hr))
10397 {
10398 IStream_Release(stream);
10399 return hr;
10400 }
10401
10402 /* update flag if differs */
10403 if ((header[1] ^ flags) & OleStream_Convert)
10404 {
10405 LARGE_INTEGER pos = {{0}};
10406
10407 if (header[1] & OleStream_Convert)
10408 flags = header[1] & ~OleStream_Convert;
10409 else
10411
10412 pos.QuadPart = sizeof(DWORD);
10413 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
10414 if (FAILED(hr))
10415 {
10416 IStream_Release(stream);
10417 return hr;
10418 }
10419
10420 hr = IStream_Write(stream, &flags, sizeof(flags), NULL);
10421 }
10422
10423 IStream_Release(stream);
10424 return hr;
10425}
ios_base &_STLP_CALL internal(ios_base &__s)
Definition: _ios_base.h:311
#define stat
Definition: acwin.h:99
#define read
Definition: acwin.h:96
#define write
Definition: acwin.h:97
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define skip(...)
Definition: atltest.h:64
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define index(s, c)
Definition: various.h:29
#define ARRAY_SIZE(A)
Definition: main.h:20
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static void list_init(struct list_entry *head)
Definition: list.h:51
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
const GUID IID_IUnknown
#define RegCloseKey(hKey)
Definition: registry.h:49
Definition: list.h:37
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LSTATUS WINAPI RegQueryValueA(HKEY hkey, LPCSTR name, LPSTR data, LPLONG count)
Definition: reg.c:4212
HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid)
Definition: combase.c:1437
HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *progid)
Definition: combase.c:1262
static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey)
Definition: combase.c:297
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, REFIID riid, void **obj)
Definition: combase.c:1685
HRESULT WINAPI WriteClassStm(IStream *pStm, REFCLSID rclsid)
Definition: storage32.c:96
static const BYTE STORAGE_magic[8]
Definition: storage32.c:53
HRESULT WINAPI ReadClassStm(IStream *pStm, CLSID *pclsid)
Definition: storage32.c:109
stream_1ole_flags
Definition: storage32.c:133
@ OleStream_Convert
Definition: storage32.c:135
@ OleStream_LinkedObject
Definition: storage32.c:134
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define HeapAlloc
Definition: compat.h:733
WCHAR OLECHAR
Definition: compat.h:2292
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:55
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CreateFileW
Definition: compat.h:741
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
#define FILE_SHARE_READ
Definition: compat.h:136
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define lstrlenW
Definition: compat.h:750
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:331
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
DWORD WINAPI GetTempPathW(IN DWORD count, OUT LPWSTR path)
Definition: path.c:1999
ULONG WINAPI DECLSPEC_HOTPATCH GetTickCount(void)
Definition: sync.c:182
static MonoProfilerRuntimeShutdownBeginCallback cb
Definition: metahost.c:118
#define assert(_expr)
Definition: assert.h:32
_ACRTIMP int __cdecl wcscmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:1972
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2802
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1592
static HRESULT StorageBaseImpl_DupStorageTree(StorageBaseImpl *dst, DirRef *dst_entry, StorageBaseImpl *src, DirRef src_entry)
Definition: storage32.c:2753
static HRESULT WINAPI StorageBaseImpl_DestroyElement(IStorage *iface, const OLECHAR *pwcsName)
Definition: storage32.c:2564
static HRESULT StorageInternalImpl_GetFilename(StorageBaseImpl *iface, LPWSTR *result)
Definition: storage32.c:5357
static HRESULT WINAPI directwriterlock_QueryInterface(IDirectWriterLock *iface, REFIID riid, void **obj)
Definition: storage32.c:443
static HRESULT StorageInternalImpl_GetTransactionSig(StorageBaseImpl *base, ULONG *result, BOOL refresh)
Definition: storage32.c:5436
static HRESULT WINAPI TransactedSharedImpl_Revert(IStorage *iface)
Definition: storage32.c:6720
static void Storage32Impl_AddBlockDepot(StorageImpl *This, ULONG blockIndex, ULONG depotIndex)
Definition: storage32.c:3798
static StorageBaseImpl * impl_from_IStorage(IStorage *iface)
Definition: storage32.c:1217
static const StorageBaseImplVtbl TransactedSnapshotImpl_BaseVtbl
Definition: storage32.c:6419
HRESULT WINAPI StgOpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstgOpen)
Definition: storage32.c:8701
static HRESULT StorageInternalImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:5448
static void StorageImpl_DeleteCachedBlockChainStream(StorageImpl *This, DirRef index)
Definition: storage32.c:4358
static BOOL SmallBlockChainStream_Enlarge(SmallBlockChainStream *This, ULARGE_INTEGER newSize)
Definition: storage32.c:8277
HRESULT WINAPI OleConvertIStorageToOLESTREAM(LPSTORAGE pstg, LPOLESTREAM pOleStream)
Definition: storage32.c:10301
static HRESULT StorageInternalImpl_Flush(StorageBaseImpl *iface)
Definition: storage32.c:5350
static HRESULT StorageImpl_StreamReadAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
Definition: storage32.c:4373
static ULONG Storage32Impl_AddExtBlockDepot(StorageImpl *This)
Definition: storage32.c:3903
static HRESULT SmallBlockChainStream_ReadAt(SmallBlockChainStream *, ULARGE_INTEGER, ULONG, void *, ULONG *)
Definition: storage32.c:8000
static HRESULT StorageImpl_BaseReadDirEntry(StorageBaseImpl *base, DirRef index, DirEntry *data)
Definition: storage32.c:4294
static HRESULT Storage_Construct(HANDLE hFile, LPCOLESTR pwcsName, ILockBytes *pLkbyt, DWORD openFlags, BOOL fileBased, BOOL create, ULONG sector_size, StorageBaseImpl **result)
Definition: storage32.c:6869
static HRESULT WINAPI TransactedSnapshotImpl_Commit(IStorage *iface, DWORD grfCommitFlags)
Definition: storage32.c:5920
#define OLESTREAM_ID
Definition: storage32.c:9335
static HRESULT StorageImpl_BaseWriteDirEntry(StorageBaseImpl *base, DirRef index, const DirEntry *data)
Definition: storage32.c:4287
static HRESULT StorageImpl_SetTransactionSig(StorageBaseImpl *base, ULONG value)
Definition: storage32.c:4838
static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base, DirRef dst, DirRef src)
Definition: storage32.c:5427
HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime)
Definition: storage32.c:8977
static HRESULT WINAPI StorageBaseImpl_Revert(IStorage *iface)
Definition: storage32.c:2400
static HRESULT TransactedSharedImpl_StreamLink(StorageBaseImpl *base, DirRef dst, DirRef src)
Definition: storage32.c:6607
void StorageUtl_ReadGUID(const BYTE *buffer, ULONG offset, GUID *value)
Definition: storage32.c:6961
static HRESULT TransactedSharedImpl_DestroyDirEntry(StorageBaseImpl *base, DirRef index)
Definition: storage32.c:6571
static void TransactedSnapshotImpl_DestroyTemporaryCopy(TransactedSnapshotImpl *This, DirRef stop)
Definition: storage32.c:5798
static IEnumSTATSTGImpl * impl_from_IEnumSTATSTG(IEnumSTATSTG *iface)
Definition: storage32.c:890
static HRESULT WINAPI directwriterlock_HaveWriteAccess(IDirectWriterLock *iface)
Definition: storage32.c:475
static ULONG WINAPI IEnumSTATSTGImpl_AddRef(IEnumSTATSTG *iface)
Definition: storage32.c:928
static HRESULT TransactedSnapshotImpl_EnsureReadEntry(TransactedSnapshotImpl *This, DirRef entry)
Definition: storage32.c:5625
static HRESULT BlockChainStream_Flush(BlockChainStream *)
Definition: storage32.c:7256
static HRESULT StorageInternalImpl_SetTransactionSig(StorageBaseImpl *base, ULONG value)
Definition: storage32.c:5442
static BOOL StorageImpl_WriteDWordToBigBlock(StorageImpl *This, ULONG blockIndex, ULONG offset, DWORD value)
Definition: storage32.c:3566
static StorageBaseImpl * impl_from_IDirectWriterLock(IDirectWriterLock *iface)
Definition: storage32.c:438
static BlockChainStream * Storage32Impl_SmallBlocksToBigBlocks(StorageImpl *This, SmallBlockChainStream **ppsbChain)
Definition: storage32.c:3589
static void StorageImpl_FreeBigBlock(StorageImpl *This, ULONG blockIndex)
Definition: storage32.c:4276
static HRESULT SmallBlockChainStream_WriteAt(SmallBlockChainStream *, ULARGE_INTEGER, ULONG, const void *, ULONG *)
Definition: storage32.c:8105
static DWORD GetCreationModeFromSTGM(DWORD stgm)
Definition: storage32.c:416
void StorageUtl_WriteDWord(void *buffer, ULONG offset, DWORD value)
Definition: storage32.c:6928
static BOOL StorageImpl_WriteBigBlock(StorageImpl *This, ULONG blockIndex, const void *buffer)
Definition: storage32.c:3552
const IPropertySetStorageVtbl IPropertySetStorage_Vtbl
Definition: stg_prop.c:2978
static HRESULT WINAPI StorageBaseImpl_CreateStream(IStorage *iface, const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm)
Definition: storage32.c:1918
static HRESULT WINAPI StorageBaseImpl_MoveElementTo(IStorage *iface, const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags)
Definition: storage32.c:2366
static void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, const BYTE *pData, DWORD dwDataLength)
Definition: storage32.c:9968
static HRESULT StorageImpl_GrabLocks(StorageImpl *This, DWORD openFlags)
Definition: storage32.c:5033
static BOOL SmallBlockChainStream_Shrink(SmallBlockChainStream *This, ULARGE_INTEGER newSize)
Definition: storage32.c:8193
static HRESULT SmallBlockChainStream_GetNextBlockInChain(SmallBlockChainStream *This, ULONG blockIndex, ULONG *nextBlockInChain)
Definition: storage32.c:7806
static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
Definition: storage32.c:6254
static HRESULT StorageImpl_WriteAt(StorageImpl *This, ULARGE_INTEGER offset, const void *buffer, const ULONG size, ULONG *bytesWritten)
Definition: storage32.c:2867
static HRESULT TransactedSharedImpl_GetFilename(StorageBaseImpl *iface, LPWSTR *result)
Definition: storage32.c:6537
static HRESULT StorageImpl_LockRegionSync(StorageImpl *This, ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType, BOOL *supported)
Definition: storage32.c:4872
static SmallBlockChainStream * Storage32Impl_BigBlocksToSmallBlocks(StorageImpl *This, BlockChainStream **ppbbChain, ULARGE_INTEGER newSize)
Definition: storage32.c:3709
static BOOL BlockChainStream_SetSize(BlockChainStream *, ULARGE_INTEGER)
Definition: storage32.c:7539
static void StorageInternalImpl_Invalidate(StorageBaseImpl *base)
Definition: storage32.c:5323
static void StorageImpl_SaveFileHeader(StorageImpl *This)
Definition: storage32.c:3002
static void StorageBaseImpl_DeleteAll(StorageBaseImpl *stg)
Definition: storage32.c:2641
static HRESULT WINAPI TransactedSnapshotImpl_Revert(IStorage *iface)
Definition: storage32.c:6055
static void StorageImpl_Invalidate(StorageBaseImpl *iface)
Definition: storage32.c:5140
static const StorageBaseImplVtbl StorageImpl_BaseVtbl
Definition: storage32.c:5185
static HRESULT BlockChainStream_ReadAt(BlockChainStream *, ULARGE_INTEGER, ULONG, void *, ULONG *)
Definition: storage32.c:7567
static HRESULT WINAPI TransactedSharedImpl_Commit(IStorage *iface, DWORD grfCommitFlags)
Definition: storage32.c:6638
static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage, TransactedSnapshotImpl **result)
Definition: storage32.c:6439
void StorageUtl_ReadWord(const BYTE *buffer, ULONG offset, WORD *value)
Definition: storage32.c:6906
static const StorageBaseImplVtbl StorageInternalImpl_BaseVtbl
Definition: storage32.c:5509
static HRESULT StorageImpl_DestroyDirEntry(StorageBaseImpl *base, DirRef index)
Definition: storage32.c:3183
void StorageUtl_ReadULargeInteger(const BYTE *buffer, ULONG offset, ULARGE_INTEGER *value)
Definition: storage32.c:6934
static const IStorageVtbl StorageImpl_Vtbl
Definition: storage32.c:5209
static HRESULT BlockChainStream_GetBlockAtOffset(BlockChainStream *This, ULONG index, BlockChainBlock **block, ULONG *sector, BOOL create)
Definition: storage32.c:7176
static HRESULT WINAPI StorageBaseImpl_OpenStorage(IStorage *iface, const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
Definition: storage32.c:1606
static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream *This)
Definition: storage32.c:8395
static ULONG WINAPI StorageBaseImpl_AddRef(IStorage *iface)
Definition: storage32.c:1277
static DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
Definition: storage32.c:9726
static HRESULT WINAPI directwriterlock_ReleaseWriteAccess(IDirectWriterLock *iface)
Definition: storage32.c:468
static void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
Definition: storage32.c:10076
static void TransactedSnapshotImpl_Invalidate(StorageBaseImpl *This)
Definition: storage32.c:6088
void StorageBaseImpl_RemoveStream(StorageBaseImpl *stg, StgStreamImpl *strm)
Definition: storage32.c:2708
static DirRef TransactedSnapshotImpl_FindFirstChild(TransactedSnapshotImpl *This, DirRef parent)
Definition: storage32.c:5723
HRESULT WINAPI ReadFmtUserTypeStg(LPSTORAGE pstg, CLIPFORMAT *pcf, LPOLESTR *lplpszUserType)
Definition: storage32.c:9269
static BOOL StorageImpl_ReadDWordFromBigBlock(StorageImpl *This, ULONG blockIndex, ULONG offset, DWORD *value)
Definition: storage32.c:3534
static void TransactedSharedImpl_Destroy(StorageBaseImpl *iface)
Definition: storage32.c:6521
HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
Definition: storage32.c:9784
static HRESULT StorageImpl_Flush(StorageBaseImpl *storage)
Definition: storage32.c:5115
static void Storage32Impl_SetExtDepotBlock(StorageImpl *This, ULONG depotIndex, ULONG blockIndex)
Definition: storage32.c:3871
static HRESULT WINAPI StorageBaseImpl_EnumElements(IStorage *iface, DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum)
Definition: storage32.c:1743
static ULONG SmallBlockChainStream_GetNextFreeBlock(SmallBlockChainStream *This)
Definition: storage32.c:7893
static ULONG StorageImpl_GetNextFreeBigBlock(StorageImpl *This, ULONG neededAddNumBlocks)
Definition: storage32.c:4133
static HRESULT TransactedSnapshotImpl_GetTransactionSig(StorageBaseImpl *base, ULONG *result, BOOL refresh)
Definition: storage32.c:6375
static HRESULT TransactedSharedImpl_StreamSetSize(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER newsize)
Definition: storage32.c:6598
static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base, DirRef index)
Definition: storage32.c:6208
static HRESULT StorageImpl_ReadAt(StorageImpl *This, ULARGE_INTEGER offset, void *buffer, ULONG size, ULONG *bytesRead)
Definition: storage32.c:2858
HRESULT WINAPI OleLoadFromStream(IStream *pStm, REFIID iidInterface, void **ppvObj)
Definition: storage32.c:9001
static void SmallBlockChainStream_Destroy(SmallBlockChainStream *)
Definition: storage32.c:7763
static HRESULT StorageBaseImpl_CopyStorageTree(StorageBaseImpl *dst, DirRef dst_entry, StorageBaseImpl *src, DirRef src_entry)
Definition: storage32.c:2792
static BlockChainStream ** StorageImpl_GetCachedBlockChainStream(StorageImpl *This, DirRef index)
Definition: storage32.c:4325
static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream *)
Definition: storage32.c:8419
static HRESULT StorageImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:4925
static HRESULT WINAPI IEnumSTATSTGImpl_Skip(IEnumSTATSTG *iface, ULONG celt)
Definition: storage32.c:1079
static HRESULT StorageImpl_Refresh(StorageImpl *This, BOOL new_object, BOOL create)
Definition: storage32.c:4585
static StorageInternalImpl * StorageInternalImpl_Construct(StorageBaseImpl *, DWORD, DirRef)
Definition: storage32.c:5529
static DirRef TransactedSnapshotImpl_FindNextChild(TransactedSnapshotImpl *This, DirRef current)
Definition: storage32.c:5762
static HRESULT WINAPI StorageInternalImpl_Revert(IStorage *iface)
Definition: storage32.c:5477
HRESULT WINAPI StgCreateDocfileOnILockBytes(ILockBytes *plkbyt, DWORD grfMode, DWORD reserved, IStorage **ppstgOpen)
Definition: storage32.c:8891
static void StorageInternalImpl_Destroy(StorageBaseImpl *iface)
Definition: storage32.c:5341
static ULONGLONG StorageImpl_GetBigBlockOffset(StorageImpl *This, ULONG index)
Definition: storage32.c:3504
void StorageUtl_CopyDirEntryToSTATSTG(StorageBaseImpl *storage, STATSTG *destination, const DirEntry *source, int statFlags)
Definition: storage32.c:6979
static const IDirectWriterLockVtbl DirectWriterLockVtbl
Definition: storage32.c:482
static const IStorageVtbl StorageInternalImpl_Vtbl
Definition: storage32.c:84
HRESULT WINAPI OleConvertIStorageToOLESTREAMEx(LPSTORAGE stg, CLIPFORMAT cf, LONG width, LONG height, DWORD size, LPSTGMEDIUM medium, LPOLESTREAM olestream)
Definition: storage32.c:10366
static HRESULT deleteStreamContents(StorageBaseImpl *parentStorage, DirRef indexToDelete, DirEntry entryDataToDelete)
Definition: storage32.c:2501
static ULONG WINAPI IEnumSTATSTGImpl_Release(IEnumSTATSTG *iface)
Definition: storage32.c:935
static ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
Definition: storage32.c:7147
static ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl *This, ULONG blockIndex)
Definition: storage32.c:4058
static HRESULT Storage_ConstructTransacted(StorageBaseImpl *, BOOL, StorageBaseImpl **)
Definition: storage32.c:6846
static const StorageBaseImplVtbl TransactedSharedImpl_BaseVtbl
Definition: storage32.c:6755
static DWORD GetAccessModeFromSTGM(DWORD stgm)
Definition: storage32.c:395
static HRESULT TransactedSharedImpl_StreamReadAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
Definition: storage32.c:6580
static HRESULT TransactedSnapshotImpl_SetTransactionSig(StorageBaseImpl *base, ULONG value)
Definition: storage32.c:6381
static void setEntryLink(DirEntry *entry, ULONG relation, DirRef new_target)
Definition: storage32.c:624
static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base, DirRef index, const DirEntry *data)
Definition: storage32.c:6149
static HRESULT StorageImpl_StreamLink(StorageBaseImpl *base, DirRef dst, DirRef src)
Definition: storage32.c:4561
static ULONG Storage32Impl_GetExtDepotBlock(StorageImpl *This, ULONG depotIndex)
Definition: storage32.c:3826
static HRESULT StorageImpl_StreamSetSize(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER newsize)
Definition: storage32.c:4425
static HRESULT TransactedSharedImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:6633
void StorageUtl_WriteGUID(void *buffer, ULONG offset, const GUID *value)
Definition: storage32.c:6970
static HRESULT create_storagefile(LPCOLESTR pwcsName, DWORD grfMode, DWORD grfAttrs, STGOPTIONS *pStgOptions, REFIID riid, void **ppstgOpen)
Definition: storage32.c:8447
static void SmallBlockChainStream_FreeBlock(SmallBlockChainStream *This, ULONG blockIndex)
Definition: storage32.c:7879
static HRESULT StorageImpl_ReadRawDirEntry(StorageImpl *This, ULONG index, BYTE *buffer)
Definition: storage32.c:3134
HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm, IStream *pStm)
Definition: storage32.c:9036
static HRESULT BlockChainStream_WriteAt(BlockChainStream *, ULARGE_INTEGER, ULONG, const void *, ULONG *)
Definition: storage32.c:7664
static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream *)
Definition: storage32.c:7497
static HRESULT TransactedSnapshotImpl_MakeStreamDirty(TransactedSnapshotImpl *This, DirRef entry)
Definition: storage32.c:5671
static HRESULT StorageImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:4949
static void StorageImpl_Destroy(StorageBaseImpl *iface)
Definition: storage32.c:5149
HRESULT WINAPI StgCreateDocfile(LPCOLESTR pwcsName, DWORD grfMode, DWORD reserved, IStorage **ppstgOpen)
Definition: storage32.c:8597
static BOOL SmallBlockChainStream_SetSize(SmallBlockChainStream *, ULARGE_INTEGER)
Definition: storage32.c:8367
static ULONG WINAPI StorageBaseImpl_Release(IStorage *iface)
Definition: storage32.c:1296
static HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(IEnumSTATSTG *iface, REFIID riid, void **ppvObject)
Definition: storage32.c:901
static void SmallBlockChainStream_SetNextBlockInChain(SmallBlockChainStream *This, ULONG blockIndex, ULONG nextBlock)
Definition: storage32.c:7850
static HRESULT StorageImpl_WriteRawDirEntry(StorageImpl *This, ULONG index, const BYTE *buffer)
Definition: storage32.c:3162
static void StorageImpl_SetNextBlockInChain(StorageImpl *This, ULONG blockIndex, ULONG nextBlock)
Definition: storage32.c:4083
static HRESULT StorageImpl_LoadFileHeader(StorageImpl *This)
Definition: storage32.c:2881
static HRESULT WINAPI StorageBaseImpl_RenameElement(IStorage *iface, const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName)
Definition: storage32.c:1837
void StorageBaseImpl_AddStream(StorageBaseImpl *stg, StgStreamImpl *strm)
Definition: storage32.c:2702
static HRESULT removeFromTree(StorageBaseImpl *This, DirRef parentStorageIndex, DirRef deletedIndex)
Definition: storage32.c:769
static HRESULT STORAGE_WriteCompObj(LPSTORAGE pstg, CLSID *clsid, LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName)
Definition: storage32.c:9180
static HRESULT StorageImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
Definition: storage32.c:4513
static HRESULT STREAM_ReadString(IStream *stm, LPWSTR *string)
Definition: storage32.c:9132
static void UpdateRawDirEntry(BYTE *buffer, const DirEntry *newData)
Definition: storage32.c:3202
static HRESULT WINAPI StorageBaseImpl_Commit(IStorage *iface, DWORD grfCommitFlags)
Definition: storage32.c:2386
static HRESULT StorageImpl_Construct(HANDLE hFile, LPCOLESTR pwcsName, ILockBytes *pLkbyt, DWORD openFlags, BOOL fileBased, BOOL create, ULONG sector_size, StorageImpl **result)
Definition: storage32.c:5231
static void BlockChainStream_Destroy(BlockChainStream *)
Definition: storage32.c:7273
static HRESULT TransactedSharedImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:6628
static HRESULT StorageImpl_CheckLockRange(StorageImpl *This, ULONG start, ULONG end, HRESULT fail_hr)
Definition: storage32.c:4984
static HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
Definition: storage32.c:9566
static void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
Definition: storage32.c:10128
static HRESULT WINAPI directwriterlock_WaitForWriteAccess(IDirectWriterLock *iface, DWORD timeout)
Definition: storage32.c:461
static HRESULT TransactedSharedImpl_Flush(StorageBaseImpl *iface)
Definition: storage32.c:6531
static const IStorageVtbl TransactedSharedImpl_Vtbl
Definition: storage32.c:6733
static HRESULT WINAPI StorageBaseImpl_CreateStorage(IStorage *iface, const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg)
Definition: storage32.c:2109
static HRESULT TransactedSharedImpl_GetTransactionSig(StorageBaseImpl *base, ULONG *result, BOOL refresh)
Definition: storage32.c:6616
HRESULT WINAPI OleConvertOLESTREAMToIStorage(LPOLESTREAM pOleStream, LPSTORAGE pstg, const DVTARGETDEVICE *ptd)
Definition: storage32.c:10210
static HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStream1)
Definition: storage32.c:9398
static HRESULT WINAPI StorageBaseImpl_OpenStream(IStorage *iface, const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
Definition: storage32.c:1493
static HRESULT StorageInternalImpl_ReadDirEntry(StorageBaseImpl *base, DirRef index, DirEntry *data)
Definition: storage32.c:5382
static HRESULT IEnumSTATSTGImpl_GetNextRef(IEnumSTATSTGImpl *This, DirRef *ref)
Definition: storage32.c:952
static HRESULT TransactedSnapshotImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:6392
static HRESULT StorageInternalImpl_WriteDirEntry(StorageBaseImpl *base, DirRef index, const DirEntry *data)
Definition: storage32.c:5373
static HRESULT StorageBaseImpl_DeleteStorageTree(StorageBaseImpl *This, DirRef entry, BOOL include_siblings)
Definition: storage32.c:2822
static ULONG SmallBlockChainStream_GetHeadOfChain(SmallBlockChainStream *This)
Definition: storage32.c:7774
static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base, DirRef dst, DirRef src)
Definition: storage32.c:6342
static IEnumSTATSTGImpl * IEnumSTATSTGImpl_Construct(StorageBaseImpl *, DirRef)
Definition: storage32.c:1185
static HRESULT TransactedSharedImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
Definition: storage32.c:6589
static HRESULT TransactedSnapshotImpl_GetFilename(StorageBaseImpl *iface, LPWSTR *result)
Definition: storage32.c:6117
static DirRef TransactedSnapshotImpl_CreateStubEntry(TransactedSnapshotImpl *This, DirRef parentEntryRef)
Definition: storage32.c:5605
static BOOL BlockChainStream_Shrink(BlockChainStream *This, ULARGE_INTEGER newSize)
Definition: storage32.c:7288
static BOOL BlockChainStream_Enlarge(BlockChainStream *This, ULARGE_INTEGER newSize)
Definition: storage32.c:7381
static HRESULT StorageImpl_GetFilename(StorageBaseImpl *iface, LPWSTR *result)
Definition: storage32.c:4971
static HRESULT findTreeParent(StorageBaseImpl *storage, DirRef storageEntry, const OLECHAR *childName, DirEntry *parentData, DirRef *parentEntry, ULONG *relation)
Definition: storage32.c:572
static HRESULT StorageImpl_WriteDirEntry(StorageImpl *This, DirRef index, const DirEntry *buffer)
Definition: storage32.c:3487
static HRESULT StorageImpl_CreateDirEntry(StorageBaseImpl *base, const DirEntry *newData, DirRef *index)
Definition: storage32.c:3280
static void TransactedSharedImpl_Invalidate(StorageBaseImpl *This)
Definition: storage32.c:6509
static LONG entryNameCmp(const OLECHAR *name1, const OLECHAR *name2)
Definition: storage32.c:508
static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base, DirRef index, DirEntry *data)
Definition: storage32.c:6188
static HRESULT WINAPI IEnumSTATSTGImpl_Clone(IEnumSTATSTG *iface, IEnumSTATSTG **ppenum)
Definition: storage32.c:1134
static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
Definition: storage32.c:6230
static HRESULT WINAPI IEnumSTATSTGImpl_Reset(IEnumSTATSTG *iface)
Definition: storage32.c:1114
static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl *stg, DirRef streamEntry)
Definition: storage32.c:1452
static HRESULT StorageBaseImpl_CopyStorageEntryTo(StorageBaseImpl *This, DirRef srcEntry, BOOL skip_storage, BOOL skip_stream, SNB snbExclude, IStorage *pstgDest)
Definition: storage32.c:2256
static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This)
Definition: storage32.c:5576
static HRESULT WINAPI StorageBaseImpl_SetClass(IStorage *iface, REFCLSID clsid)
Definition: storage32.c:2071
static void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, const BYTE *pBuffer, DWORD nBufferLength)
Definition: storage32.c:9677
static HRESULT STREAM_WriteString(IStream *stm, LPCWSTR string)
Definition: storage32.c:9111
static HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
Definition: storage32.c:10006
static HRESULT TransactedSharedImpl_CreateDirEntry(StorageBaseImpl *base, const DirEntry *newData, DirRef *index)
Definition: storage32.c:6544
HRESULT STORAGE_CreateOleStream(IStorage *storage, DWORD flags)
Definition: storage32.c:9079
static BOOL TransactedSnapshotImpl_MadeCopy(TransactedSnapshotImpl *This, DirRef entry)
Definition: storage32.c:5790
static HRESULT TransactedSnapshotImpl_CopyTree(TransactedSnapshotImpl *This)
Definition: storage32.c:5838
static HRESULT BlockChainStream_UpdateIndexCache(BlockChainStream *This)
Definition: storage32.c:7070
static void TransactedSnapshotImpl_Destroy(StorageBaseImpl *iface)
Definition: storage32.c:6100
static HRESULT StorageImpl_GetNextBlockInChain(StorageImpl *This, ULONG blockIndex, ULONG *nextBlockIndex)
Definition: storage32.c:3984
static HRESULT WINAPI StorageInternalImpl_Commit(IStorage *iface, DWORD grfCommitFlags)
Definition: storage32.c:5463
static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER newsize)
Definition: storage32.c:6286
static HRESULT StorageImpl_LockOne(StorageImpl *This, ULONG start, ULONG end)
Definition: storage32.c:5002
static HRESULT WINAPI IEnumSTATSTGImpl_Next(IEnumSTATSTG *iface, ULONG celt, STATSTG *rgelt, ULONG *pceltFetched)
Definition: storage32.c:1000
static HRESULT StorageImpl_GetTransactionSig(StorageBaseImpl *base, ULONG *result, BOOL refresh)
Definition: storage32.c:4799
static SmallBlockChainStream * SmallBlockChainStream_Construct(StorageImpl *, ULONG *, DirRef)
Definition: storage32.c:7747
static HRESULT WINAPI StorageBaseImpl_SetElementTimes(IStorage *iface, const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
Definition: storage32.c:2670
static HRESULT validateSTGM(DWORD stgm)
Definition: storage32.c:285
static void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY, BYTE *pData, DWORD dwDataLength)
Definition: storage32.c:9885
static HRESULT TransactedSharedImpl_SetTransactionSig(StorageBaseImpl *base, ULONG value)
Definition: storage32.c:6622
static HRESULT StorageImpl_LockRegion(StorageImpl *This, ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType, BOOL *supported)
Definition: storage32.c:4849
static DWORD GetShareModeFromSTGM(DWORD stgm)
Definition: storage32.c:369
static HRESULT StorageImpl_ReadBigBlock(StorageImpl *This, ULONG blockIndex, void *buffer, ULONG *out_read)
Definition: storage32.c:3509
static HRESULT TransactedSnapshotImpl_Flush(StorageBaseImpl *iface)
Definition: storage32.c:6111
static HRESULT StorageInternalImpl_CreateDirEntry(StorageBaseImpl *base, const DirEntry *newData, DirRef *index)
Definition: storage32.c:5364
static HRESULT TransactedSnapshotImpl_LockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:6387
static ULONG WINAPI directwriterlock_Release(IDirectWriterLock *iface)
Definition: storage32.c:455
static ULONG WINAPI directwriterlock_AddRef(IDirectWriterLock *iface)
Definition: storage32.c:449
static HRESULT StorageImpl_UnlockRegion(StorageImpl *This, ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType)
Definition: storage32.c:4862
static HRESULT StorageBaseImpl_CopyStream(StorageBaseImpl *dst, DirRef dst_entry, StorageBaseImpl *src, DirRef src_entry)
Definition: storage32.c:2714
static HRESULT StorageInternalImpl_StreamWriteAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
Definition: storage32.c:5409
static HRESULT StorageImpl_ReadDirEntry(StorageImpl *This, DirRef index, DirEntry *buffer)
Definition: storage32.c:3391
HRESULT WINAPI StgOpenStorageEx(const WCHAR *pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS *pStgOptions, void *reserved, REFIID riid, void **ppObjectOpen)
Definition: storage32.c:8657
static HRESULT WINAPI StorageBaseImpl_Stat(IStorage *iface, STATSTG *pstatstg, DWORD grfStatFlag)
Definition: storage32.c:1781
static HRESULT WINAPI StorageBaseImpl_CopyTo(IStorage *iface, DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
Definition: storage32.c:2279
void StorageUtl_WriteWord(void *buffer, ULONG offset, WORD value)
Definition: storage32.c:6914
static HRESULT TransactedSharedImpl_Construct(StorageBaseImpl *parentStorage, TransactedSharedImpl **result)
Definition: storage32.c:6775
static const BYTE STORAGE_oldmagic[8]
Definition: storage32.c:60
static const IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl
Definition: storage32.c:1174
static HRESULT StorageInternalImpl_DestroyDirEntry(StorageBaseImpl *base, DirRef index)
Definition: storage32.c:5391
HRESULT WINAPI WriteFmtUserTypeStg(LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
Definition: storage32.c:9226
static BlockChainStream ** StorageImpl_GetFreeBlockChainCacheEntry(StorageImpl *This)
Definition: storage32.c:4301
static HRESULT deleteStorageContents(StorageBaseImpl *parentStorage, DirRef indexToDelete, DirEntry entryDataToDelete)
Definition: storage32.c:2414
static DirRef findElement(StorageBaseImpl *storage, DirRef storageEntry, const OLECHAR *name, DirEntry *data)
Definition: storage32.c:531
static HRESULT WINAPI StorageBaseImpl_SetStateBits(IStorage *iface, DWORD grfStateBits, DWORD grfMask)
Definition: storage32.c:2684
static BlockChainStream * BlockChainStream_Construct(StorageImpl *, ULONG *, DirRef)
Definition: storage32.c:7223
static HRESULT StorageInternalImpl_UnlockTransaction(StorageBaseImpl *base, BOOL write)
Definition: storage32.c:5453
static HRESULT insertIntoTree(StorageBaseImpl *This, DirRef parentStorageIndex, DirRef newEntryIndex)
Definition: storage32.c:648
static HRESULT TransactedSharedImpl_ReadDirEntry(StorageBaseImpl *base, DirRef index, DirEntry *data)
Definition: storage32.c:6562
void StorageUtl_WriteULargeInteger(void *buffer, ULONG offset, const ULARGE_INTEGER *value)
Definition: storage32.c:6948
HRESULT WINAPI StgCreateStorageEx(const WCHAR *pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS *pStgOptions, void *reserved, REFIID riid, void **ppObjectOpen)
Definition: storage32.c:8618
static HRESULT StorageInternalImpl_StreamSetSize(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER newsize)
Definition: storage32.c:5418
static HRESULT TransactedSnapshotImpl_CreateDirEntry(StorageBaseImpl *base, const DirEntry *newData, DirRef *index)
Definition: storage32.c:6124
void StorageUtl_ReadDWord(const BYTE *buffer, ULONG offset, DWORD *value)
Definition: storage32.c:6920
static HRESULT StorageBaseImpl_CopyChildEntryTo(StorageBaseImpl *This, DirRef srcEntry, BOOL skip_storage, BOOL skip_stream, SNB snbExclude, IStorage *pstgDest)
Definition: storage32.c:1322
#define OLESTREAM_MAX_STR_LEN
Definition: storage32.c:9336
static HRESULT TransactedSharedImpl_WriteDirEntry(StorageBaseImpl *base, DirRef index, const DirEntry *data)
Definition: storage32.c:6553
HRESULT WINAPI SetConvertStg(IStorage *storage, BOOL convert)
Definition: storage32.c:10377
HRESULT WINAPI StgOpenStorageOnILockBytes(ILockBytes *plkbyt, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstgOpen)
Definition: storage32.c:8929
static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl *stg, DirRef storageEntry)
Definition: storage32.c:1469
static HRESULT StorageInternalImpl_StreamReadAt(StorageBaseImpl *base, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
Definition: storage32.c:5400
static ULONG BlockChainStream_GetCount(BlockChainStream *This)
Definition: storage32.c:216
static void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl *This)
Definition: storage32.c:895
static const IStorageVtbl TransactedSnapshotImpl_Vtbl
Definition: storage32.c:153
static HRESULT WINAPI StorageBaseImpl_QueryInterface(IStorage *iface, REFIID riid, void **ppvObject)
Definition: storage32.c:1230
static ULONG BlockChainStream_GetHeadOfChain(BlockChainStream *This)
Definition: storage32.c:7047
HCRYPTKEY new_object(struct handle_table *lpTable, size_t cbSize, DWORD dwType, DESTRUCTOR destructor, OBJECTHDR **ppObject)
Definition: handle.c:353
#define L(x)
Definition: resources.c:13
r parent
Definition: btrfs.c:3010
r reserved
Definition: btrfs.c:3006
size_t const old_size
Definition: expand.cpp:65
size_t const new_size
Definition: expand.cpp:66
HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes)
Definition: filelockbytes.c:86
UINT WINAPI GetTempFileNameW(IN LPCWSTR lpPathName, IN LPCWSTR lpPrefixString, IN UINT uUnique, OUT LPWSTR lpTempFileName)
Definition: filename.c:84
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
#define HEADER_SIZE
Definition: fontview.h:6
uint8_t reserved2[12]
Definition: fsck.fat.h:23
uint8_t reserved3
Definition: fsck.fat.h:26
jmp_buf toplevel
Definition: main.c:95
FxAutoRegKey hKey
FxCollectionEntry * cur
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLint GLint GLsizei width
Definition: gl.h:1546
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLenum GLsizei GLuint GLint * bytesWritten
Definition: glext.h:11123
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLuint index
Definition: glext.h:6031
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
GLuint64EXT * result
Definition: glext.h:11304
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
const char cursor[]
Definition: icontest.c:13
REFIID riid
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
uint32_t sector
Definition: isohybrid.c:61
uint32_t entry
Definition: isohybrid.c:63
JBLOCKROW JDIMENSION num_blocks
Definition: jpegint.h:423
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_w
Definition: kernel32.h:32
if(dx< 0)
Definition: linetemp.h:194
void *WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: malloc.c:381
void WINAPI CoTaskMemFree(void *ptr)
Definition: malloc.c:389
__u8 sector_size[2]
Definition: mkdosfs.c:3
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
struct task_struct * current
Definition: linux.c:32
#define CREATE_ALWAYS
Definition: disk.h:72
#define TRUNCATE_EXISTING
Definition: disk.h:71
#define FILE_FLAG_NO_BUFFERING
Definition: disk.h:45
#define FILE_FLAG_RANDOM_ACCESS
Definition: disk.h:44
#define FILE_FLAG_DELETE_ON_CLOSE
Definition: disk.h:42
#define CREATE_NEW
Definition: disk.h:69
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
static WCHAR name1[]
Definition: record.c:34
static WCHAR name2[]
Definition: record.c:35
static const char stream_data[]
Definition: mlang.c:2327
static const struct access_res create[16]
Definition: package.c:7505
#define cmp(status, error)
Definition: error.c:114
static BSTR *static LPOLESTR
Definition: varformat.c:44
#define min(a, b)
Definition: monoChain.cc:55
int convert
Definition: msacm.c:1374
const CLSID * clsid
Definition: msctf.cpp:50
_In_ HANDLE hFile
Definition: mswsock.h:90
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define DWORD
Definition: nt_native.h:44
#define GENERIC_WRITE
Definition: nt_native.h:90
#define MAXIMUM_ALLOWED
Definition: nt_native.h:83
#define STGM_CREATE
Definition: objbase.h:943
#define STGFMT_DOCFILE
Definition: objbase.h:953
#define STGM_SHARE_DENY_NONE
Definition: objbase.h:937
#define STGM_CONVERT
Definition: objbase.h:944
#define STGFMT_FILE
Definition: objbase.h:951
#define STGM_DIRECT_SWMR
Definition: objbase.h:948
#define STGM_READWRITE
Definition: objbase.h:936
#define STGM_TRANSACTED
Definition: objbase.h:932
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:940
#define STGM_FAILIFTHERE
Definition: objbase.h:945
#define STGM_DELETEONRELEASE
Definition: objbase.h:942
#define STGM_NOSNAPSHOT
Definition: objbase.h:947
#define STGM_SHARE_DENY_WRITE
Definition: objbase.h:939
#define STGM_SIMPLE
Definition: objbase.h:933
#define STGM_PRIORITY
Definition: objbase.h:941
#define STGM_WRITE
Definition: objbase.h:935
#define STGM_READ
Definition: objbase.h:934
#define STGFMT_ANY
Definition: objbase.h:952
#define STGFMT_STORAGE
Definition: objbase.h:950
#define STGM_SHARE_DENY_READ
Definition: objbase.h:938
#define STGM_NOSCRATCH
Definition: objbase.h:946
interface IPersistStream * LPPERSISTSTREAM
Definition: objfwd.h:16
interface IStorage * LPSTORAGE
Definition: objfwd.h:30
const GUID IID_IEnumSTATSTG
long LONG
Definition: pedump.c:60
const GUID IID_IPersistStream
Definition: proxy.cpp:13
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
#define CLSID_NULL
Definition: guiddef.h:99
#define REFIID
Definition: guiddef.h:118
#define REFCLSID
Definition: guiddef.h:117
static unsigned __int64 next
Definition: rand_nt.c:6
PVOID pBuffer
const WCHAR * str
strcpy
Definition: string.h:131
static __inline const char * wine_dbgstr_guid(const GUID *id)
Definition: debug.h:206
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
#define LIST_FOR_EACH_SAFE(cursor, cursor2, list)
Definition: list.h:192
int const char int stream_size
Definition: zlib.h:814
#define memset(x, y, z)
Definition: compat.h:39
#define towupper(c)
Definition: wctype.h:99
int zero
Definition: sehframes.cpp:29
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
StgStreamImpl * StgStreamImpl_Construct(StorageBaseImpl *parentStorage, DWORD grfMode, DirRef dirEntry)
Definition: stg_stream.c:660
static HRESULT StorageBaseImpl_DestroyDirEntry(StorageBaseImpl *This, DirRef index)
Definition: storage32.h:296
#define RANGELOCK_LAST
Definition: storage32.h:520
#define lendian32toh(x)
Definition: storage32.h:548
static HRESULT StorageBaseImpl_GetFilename(StorageBaseImpl *This, LPWSTR *result)
Definition: storage32.h:273
static const WORD MIN_BIG_BLOCK_SIZE_BITS
Definition: storage32.h:76
static const ULONG OFFSET_BIGBLOCKSIZEBITS
Definition: storage32.h:49
#define STGTY_ROOT
Definition: storage32.h:108
#define DIRENTRY_NAME_BUFFER_LEN
Definition: storage32.h:89
static HRESULT StorageBaseImpl_StreamSetSize(StorageBaseImpl *This, DirRef index, ULARGE_INTEGER newsize)
Definition: storage32.h:317
static const ULONG OFFSET_MAJORVERSION
Definition: storage32.h:47
static const ULONG OFFSET_PS_CTIMELOW
Definition: storage32.h:68
#define RANGELOCK_PRIORITY2_FIRST
Definition: storage32.h:504
static const ULONG OFFSET_MINORVERSION
Definition: storage32.h:46
#define RANGELOCK_CHECKLOCKS
Definition: storage32.h:506
static HRESULT StorageBaseImpl_CreateDirEntry(StorageBaseImpl *This, const DirEntry *newData, DirRef *index)
Definition: storage32.h:278
#define RANGELOCK_UNK1_LAST
Definition: storage32.h:498
static const ULONG OFFSET_PS_STGTYPE
Definition: storage32.h:63
#define MIN_BIG_BLOCK_SIZE
Definition: storage32.h:95
#define RANGELOCK_READ_FIRST
Definition: storage32.h:507
#define DIRENTRY_RELATION_PREVIOUS
Definition: storage32.h:101
#define lendian16toh(x)
Definition: storage32.h:549
#define DIRENTRY_RELATION_NEXT
Definition: storage32.h:102
#define RANGELOCK_DENY_WRITE_LAST
Definition: storage32.h:514
static const ULONG OFFSET_DIRSECTORCOUNT
Definition: storage32.h:51
#define htole16(x)
Definition: storage32.h:546
static void StorageBaseImpl_Invalidate(StorageBaseImpl *This)
Definition: storage32.h:263
#define STGM_CREATE_MODE(stgm)
Definition: storage32.h:117
static HRESULT StorageBaseImpl_WriteDirEntry(StorageBaseImpl *This, DirRef index, const DirEntry *data)
Definition: storage32.h:284
#define STGM_KNOWN_FLAGS
Definition: storage32.h:119
static const ULONG OFFSET_PS_LEFTCHILD
Definition: storage32.h:64
#define RANGELOCK_NOSNAPSHOT_LAST
Definition: storage32.h:502
static const ULONG OFFSET_SMALLBLOCKLIMIT
Definition: storage32.h:55
static HRESULT StorageBaseImpl_StreamLink(StorageBaseImpl *This, DirRef dst, DirRef src)
Definition: storage32.h:327
static HRESULT StorageBaseImpl_LockTransaction(StorageBaseImpl *This, BOOL write)
Definition: storage32.h:345
static const ULONG OFFSET_PS_MTIMELOW
Definition: storage32.h:70
static HRESULT StorageBaseImpl_StreamReadAt(StorageBaseImpl *This, DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
Definition: storage32.h:303
static HRESULT StorageBaseImpl_StreamWriteAt(StorageBaseImpl *This, DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
Definition: storage32.h:311
#define RANGELOCK_FIRST
Definition: storage32.h:519
static const ULONG OFFSET_EXTBBDEPOTCOUNT
Definition: storage32.h:59
static const WORD DEF_SMALL_BLOCK_SIZE_BITS
Definition: storage32.h:78
static const ULONG BLOCK_UNUSED
Definition: storage32.h:85
@ SWMR_Reader
Definition: storage32.h:173
@ SWMR_None
Definition: storage32.h:171
@ SWMR_Writer
Definition: storage32.h:172
#define WINE_LOCK_READ
Definition: storage32.h:523
static const ULONG DIRENTRY_NULL
Definition: storage32.h:86
#define DIRENTRY_NAME_MAX_LEN
Definition: storage32.h:88
static const ULONG OFFSET_SBDEPOTSTART
Definition: storage32.h:56
static const ULONG OFFSET_PS_MTIMEHIGH
Definition: storage32.h:71
#define RANGELOCK_TRANSACTION_LAST
Definition: storage32.h:518
#define STGM_SHARE_MODE(stgm)
Definition: storage32.h:116
ULONG DirRef
Definition: storage32.h:139
#define RANGELOCK_NOSNAPSHOT_FIRST
Definition: storage32.h:501
#define RAW_DIRENTRY_SIZE
Definition: storage32.h:91
static const ULONG OFFSET_BBDEPOTSTART
Definition: storage32.h:60
#define LIMIT_TO_USE_SMALL_BLOCK
Definition: storage32.h:113
#define STGM_ACCESS_MODE(stgm)
Definition: storage32.h:115
#define MAX_BIG_BLOCK_SIZE
Definition: storage32.h:96
#define RANGELOCK_WRITE_LAST
Definition: storage32.h:510
static const ULONG OFFSET_ROOTSTARTBLOCK
Definition: storage32.h:53
static const ULONG BLOCK_EXTBBDEPOT
Definition: storage32.h:82
#define htole32(x)
Definition: storage32.h:543
static const ULONG OFFSET_EXTBBDEPOTSTART
Definition: storage32.h:58
#define RANGELOCK_READ_LAST
Definition: storage32.h:508
#define BLOCKCHAIN_CACHE_SIZE
Definition: storage32.h:363
static void StorageBaseImpl_Destroy(StorageBaseImpl *This)
Definition: storage32.h:258
static const ULONG OFFSET_PS_CTIMEHIGH
Definition: storage32.h:69
#define DIRENTRY_RELATION_DIR
Definition: storage32.h:103
#define RANGELOCK_DENY_READ_FIRST
Definition: storage32.h:511
#define RANGELOCK_DENY_READ_LAST
Definition: storage32.h:512
#define RANGELOCK_PRIORITY1_FIRST
Definition: storage32.h:499
#define RANGELOCK_PRIORITY2_LAST
Definition: storage32.h:505
static const ULONG BLOCK_SPECIAL
Definition: storage32.h:83
static const ULONG OFFSET_PS_SIZE_HIGH
Definition: storage32.h:74
static const WORD DEF_SMALL_BLOCK_SIZE
Definition: storage32.h:80
static const ULONG OFFSET_PS_DIRROOT
Definition: storage32.h:66
static const ULONG OFFSET_TRANSACTIONSIG
Definition: storage32.h:54
static const ULONG OFFSET_PS_NAME
Definition: storage32.h:61
#define RANGELOCK_WRITE_FIRST
Definition: storage32.h:509
static const ULONG OFFSET_SMALLBLOCKSIZEBITS
Definition: storage32.h:50
#define RANGELOCK_COMMIT
Definition: storage32.h:503
#define RANGELOCK_DENY_WRITE_FIRST
Definition: storage32.h:513
static HRESULT StorageBaseImpl_GetTransactionSig(StorageBaseImpl *This, ULONG *result, BOOL refresh)
Definition: storage32.h:333
static HRESULT StorageBaseImpl_Flush(StorageBaseImpl *This)
Definition: storage32.h:268
static const ULONG OFFSET_BBDEPOTCOUNT
Definition: storage32.h:52
#define RANGELOCK_UNK1_FIRST
Definition: storage32.h:497
static HRESULT StorageBaseImpl_SetTransactionSig(StorageBaseImpl *This, ULONG value)
Definition: storage32.h:339
static const ULONG BLOCK_END_OF_CHAIN
Definition: storage32.h:84
static const ULONG OFFSET_PS_NAMELENGTH
Definition: storage32.h:62
static const ULONG OFFSET_SBDEPOTCOUNT
Definition: storage32.h:57
#define RANGELOCK_TRANSACTION_FIRST
Definition: storage32.h:517
static const WORD MAX_BIG_BLOCK_SIZE_BITS
Definition: storage32.h:77
static const ULONG OFFSET_PS_SIZE
Definition: storage32.h:73
static const ULONG BLOCK_FIRST_SPECIAL
Definition: storage32.h:81
static HRESULT StorageBaseImpl_ReadDirEntry(StorageBaseImpl *This, DirRef index, DirEntry *data)
Definition: storage32.h:290
#define RANGELOCK_PRIORITY1_LAST
Definition: storage32.h:500
static const ULONG OFFSET_BYTEORDERMARKER
Definition: storage32.h:48
static HRESULT StorageBaseImpl_UnlockTransaction(StorageBaseImpl *This, BOOL write)
Definition: storage32.h:350
static const ULONG OFFSET_PS_RIGHTCHILD
Definition: storage32.h:65
#define COUNT_BBDEPOTINHEADER
Definition: storage32.h:110
static const ULONG OFFSET_PS_STARTBLOCK
Definition: storage32.h:72
static const ULONG OFFSET_PS_GUID
Definition: storage32.h:67
BYTE data[MAX_BIG_BLOCK_SIZE]
Definition: storage32.c:196
ULONG firstOffset
Definition: storage32.c:186
ULONG firstSector
Definition: storage32.c:185
ULONG lastOffset
Definition: storage32.c:187
ULONG indexCacheSize
Definition: storage32.c:206
ULONG indexCacheLen
Definition: storage32.c:205
StorageImpl * parentStorage
Definition: storage32.c:201
ULONG blockToEvict
Definition: storage32.c:208
struct BlockChainRun * indexCache
Definition: storage32.c:204
DirRef ownerDirEntry
Definition: storage32.c:203
ULONG * headOfStreamPlaceHolder
Definition: storage32.c:202
BlockChainBlock cachedBlocks[2]
Definition: storage32.c:207
ULONG startingBlock
Definition: storage32.h:156
DirRef dirRootEntry
Definition: storage32.h:152
BYTE stgType
Definition: storage32.h:149
GUID clsid
Definition: storage32.h:153
DirRef rightChild
Definition: storage32.h:151
ULARGE_INTEGER size
Definition: storage32.h:157
FILETIME ctime
Definition: storage32.h:154
WORD sizeOfNameString
Definition: storage32.h:148
WCHAR name[DIRENTRY_NAME_MAX_LEN]
Definition: storage32.h:147
DirRef leftChild
Definition: storage32.h:150
FILETIME mtime
Definition: storage32.h:155
IEnumSTATSTG IEnumSTATSTG_iface
Definition: storage32.c:881
StorageBaseImpl * parentStorage
Definition: storage32.c:884
WCHAR name[DIRENTRY_NAME_MAX_LEN]
Definition: storage32.c:887
DirRef storageDirEntry
Definition: storage32.c:885
INT16 xExt
Definition: wingdi16.h:58
INT16 yExt
Definition: wingdi16.h:59
HMETAFILE16 hMF
Definition: wingdi16.h:60
CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN]
Definition: storage32.c:9360
CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN]
Definition: storage32.c:9362
CHAR strProgIDName[OLESTREAM_MAX_STR_LEN]
Definition: storage32.c:9364
CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN]
Definition: storage32.c:9344
ULONG * headOfStreamPlaceHolder
Definition: storage32.c:241
StorageImpl * parentStorage
Definition: storage32.c:239
struct list StrmListEntry
Definition: storage32.h:435
IStream IStream_iface
Definition: storage32.h:429
StorageBaseImpl * parentStorage
Definition: storage32.h:440
DWORD grfMode
Definition: storage32.h:445
DirRef dirEntry
Definition: storage32.h:450
struct list strmHead
Definition: storage32.h:196
IPropertySetStorage IPropertySetStorage_iface
Definition: storage32.h:188
DirRef storageDirEntry
Definition: storage32.h:211
IStorage IStorage_iface
Definition: storage32.h:187
StorageBaseImpl * transactedChild
Definition: storage32.h:234
struct list storageHead
Definition: storage32.h:201
struct StorageBaseImpl base
Definition: storage32.h:373
StorageBaseImpl * parentStorage
Definition: storage32.c:81
struct StorageBaseImpl base
Definition: storage32.c:74
struct list ParentListEntry
Definition: storage32.c:79
DirRef transactedParentEntry
Definition: storage32.c:91
DirRef newTransactedParentEntry
Definition: storage32.c:122
StorageBaseImpl * transactedParent
Definition: storage32.c:168
TransactedSnapshotImpl * scratch
Definition: storage32.c:163
TransactedDirEntry * entries
Definition: storage32.c:140
StorageBaseImpl * scratch
Definition: storage32.c:136
StorageBaseImpl * transactedParent
Definition: storage32.c:147
DWORD dwHighDateTime
Definition: mapidefs.h:66
DWORD dwLowDateTime
Definition: mapidefs.h:65
LPOLESTREAMVTBL lpstbl
Definition: ole.h:206
$ULONG LowPart
Definition: ntbasedef.h:581
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
$ULONG HighPart
Definition: ntbasedef.h:582
Definition: tcpcore.h:1673
Definition: name.c:39
WCHAR * name
Definition: name.c:42
Definition: send.c:48
Definition: stat.h:66
Definition: parse.h:23
USHORT reserved
Definition: objbase.h:958
const WCHAR * pwcsTemplateFile
Definition: objbase.h:960
ULONG ulSectorSize
Definition: objbase.h:959
USHORT usVersion
Definition: objbase.h:957
Definition: dhcpd.h:248
#define max(a, b)
Definition: svc.c:63
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:726
#define LIST_ENTRY(type)
Definition: queue.h:175
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
unsigned char * LPBYTE
Definition: typedefs.h:53
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
ULONG LowPart
Definition: typedefs.h:106
Definition: pdh_main.c:96
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD nBufferLength
Definition: winbase.h:2826
#define WINAPI
Definition: msvc.h:6
#define STG_E_SHAREVIOLATION
Definition: winerror.h:3672
#define CONVERT10_E_OLESTREAM_GET
Definition: winerror.h:3868
#define STG_E_INVALIDPOINTER
Definition: winerror.h:3666
#define S_FALSE
Definition: winerror.h:3451
#define STG_E_PATHNOTFOUND
Definition: winerror.h:3661
#define STG_E_REVERTED
Definition: winerror.h:3686
#define ERROR_SHARING_VIOLATION
Definition: winerror.h:257
#define STG_E_NOTCURRENT
Definition: winerror.h:3685
#define STG_E_LOCKVIOLATION
Definition: winerror.h:3673
#define STG_E_INVALIDNAME
Definition: winerror.h:3680
#define E_NOINTERFACE
Definition: winerror.h:3479
#define STG_E_INVALIDHEADER
Definition: winerror.h:3679
#define STG_E_READFAULT
Definition: winerror.h:3671
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:228
#define ERROR_WRITE_PROTECT
Definition: winerror.h:244
#define STG_E_FILEALREADYEXISTS
Definition: winerror.h:3674
#define STG_E_DOCFILECORRUPT
Definition: winerror.h:3693
#define STG_E_FILENOTFOUND
Definition: winerror.h:3660
#define ERROR_FILE_EXISTS
Definition: winerror.h:287
#define STG_E_OLDFORMAT
Definition: winerror.h:3688
#define STG_E_ACCESSDENIED
Definition: winerror.h:3663
#define STG_E_INVALIDPARAMETER
Definition: winerror.h:3675
#define STG_E_INVALIDFLAG
Definition: winerror.h:3683
#define CONVERT10_E_OLESTREAM_PUT
Definition: winerror.h:3869
#define STG_E_WRITEFAULT
Definition: winerror.h:3670
#define STG_E_INVALIDFUNCTION
Definition: winerror.h:3659
#define STG_E_INSUFFICIENTMEMORY
Definition: winerror.h:3665
#define CONVERT10_E_OLESTREAM_FMT
Definition: winerror.h:3870
#define STG_E_UNKNOWN
Definition: winerror.h:3681
#define HKEY_CLASSES_ROOT
Definition: winreg.h:10
UINT WINAPI RegisterClipboardFormatW(_In_ LPCWSTR)
int WINAPI GetClipboardFormatNameW(_In_ UINT format, _Out_writes_(cchMaxCount) LPWSTR lpszFormatName, _In_ int cchMaxCount)
static unsigned int block
Definition: xmlmemory.c:101
const char * LPCSTR
Definition: xmlstorage.h:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
char * LPSTR
Definition: xmlstorage.h:182
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193