1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// StgTiggerStorage.h
6//
7
8//
9// TiggerStorage is a stripped down version of compound doc files. Doc files
10// have some very useful and complex features to them, unfortunately nothing
11// comes for free. Given the incredibly tuned format of existing .tlb files,
12// every single byte counts and 10% added by doc files is just too exspensive.
13//
14// The storage itself is made up of a bunch of streams (each aligned to a 4 byte
15// value), followed at the end of the file with the header. The header is
16// put at the end so that you can continue to write as many streams as you
17// like without thrashing the disk.
18// +-------------------+
19// | Signature |
20// +-------------------+
21// | Stream 1, 2, [] |
22// +-------------------+
23// | STORAGEHEADER |
24// | Extra data |
25// | STORAGESTREAM[] |
26// +-------------------+
27// | offset |
28// +-------------------+
29//
30// The STORAGEHEADER contains flags describing the rest of the file, including
31// the ability to have extra data stored in the header. If there is extra
32// data, then immediately after the STORAGEHEADER struct is a 4 byte size of
33// that data, followed immediately by the extra data. The length must be
34// 4 byte aligned so that the first STORAGESTREAM starts on an aligned
35// boundary. The contents of the extra data is caller defined.
36//
37// This code handles the signature at the start of the file, and the list of
38// streams at the end (kept in the header). The data in each stream is, of
39// course, caller specific.
40//
41// This code requires the StgIO code to handle the input and output from the
42// backing storage, whatever scheme that may be. There are no consistency
43// checks on the data (for example crc's) due to the expense in computation
44// required. There is a signature at the front of the file and in the header.
45//
46//*****************************************************************************
47#ifndef __StgTiggerStorage_h__
48#define __StgTiggerStorage_h__
49
50//#include "utilcode.h" // Helpers.
51
52#include "mdfileformat.h"
53
54typedef CDynArray<STORAGESTREAM> STORAGESTREAMLST;
55
56
57// Forwards.
58class TiggerStream;
59class StgIO;
60
61
62
63class TiggerStorage :
64 public IStorage
65{
66friend class TiggerStream;
67public:
68 TiggerStorage();
69 virtual ~TiggerStorage();
70
71// IUnknown so you can ref count this thing.
72 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *pp)
73 { return (BadError(E_NOTIMPL)); }
74 virtual ULONG STDMETHODCALLTYPE AddRef()
75 { return (InterlockedIncrement(&m_cRef)); }
76 virtual ULONG STDMETHODCALLTYPE Release()
77 {
78 SUPPORTS_DAC_HOST_ONLY;
79 ULONG cRef;
80 if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
81 delete this;
82 return (cRef);
83 }
84
85
86//*****************************************************************************
87// Init this storage object on top of the given storage unit.
88//*****************************************************************************
89 HRESULT Init( // Return code.
90 StgIO *pStgIO, // The I/O subsystem.
91 __in __in_z LPSTR pVersion); // Compiler-supplied CLR version
92
93//*****************************************************************************
94// Retrieves a the size and a pointer to the extra data that can optionally be
95// written in the header of the storage system. This data is not required to
96// be in the file, in which case *pcbExtra will come back as 0 and pbData will
97// be set to null. You must have initialized the storage using Init() before
98// calling this function.
99//*****************************************************************************
100 HRESULT GetExtraData( // Return code.
101 ULONG *pcbExtra, // Return size of extra data.
102 BYTE *&pbData); // Return a pointer to extra data.
103
104//*****************************************************************************
105// Flushes the header to disk.
106//*****************************************************************************
107 HRESULT WriteHeader( // Return code.
108 STORAGESTREAMLST *pList, // List of streams.
109 ULONG cbExtraData, // Size of extra data, may be 0.
110 BYTE *pbExtraData); // Pointer to extra data for header.
111
112//*****************************************************************************
113// Called when all data has been written. Forces cached data to be flushed
114// and stream lists to be validated.
115//*****************************************************************************
116 HRESULT WriteFinished( // Return code.
117 STORAGESTREAMLST *pList, // List of streams.
118 ULONG *pcbSaveSize, // Return size of total data.
119 BOOL fDeltaSave); // Was this a delta
120
121//*****************************************************************************
122// Called after a successful rewrite of an existing file. The in memory
123// backing store is no longer valid because all new data is in memory and
124// on disk. This is essentially the same state as created, so free up some
125// working set and remember this state.
126//*****************************************************************************
127 HRESULT ResetBackingStore(); // Return code.
128
129//*****************************************************************************
130// Called to restore the original file. If this operation is successful, then
131// the backup file is deleted as requested. The restore of the file is done
132// in write through mode to the disk help ensure the contents are not lost.
133// This is not good enough to fulfill ACID props, but it ain't that bad.
134//*****************************************************************************
135 HRESULT Restore( // Return code.
136 __in __in_z LPWSTR szBackup, // If non-0, backup the file.
137 int bDeleteOnSuccess); // Delete backup file if successful.
138
139//*****************************************************************************
140// Given the name of a stream that will be persisted into a stream in this
141// storage type, figure out how big that stream would be including the user's
142// stream data and the header overhead the file format incurs. The name is
143// stored in ANSI and the header struct is aligned to 4 bytes.
144//*****************************************************************************
145 static HRESULT GetStreamSaveSize( // Return code.
146 LPCWSTR szStreamName, // Name of stream.
147 UINT32 cbDataSize, // Size of data to go into stream.
148 UINT32 *pcbSaveSize); // Return data size plus stream overhead.
149
150//*****************************************************************************
151// Return the fixed size overhead for the storage implementation. This includes
152// the signature and fixed header overhead. The overhead in the header for each
153// stream is calculated as part of GetStreamSaveSize because these structs are
154// variable sized on the name.
155//*****************************************************************************
156 static HRESULT GetStorageSaveSize( // Return code.
157 ULONG *pcbSaveSize, // [in] current size, [out] plus overhead.
158 ULONG cbExtra, // How much extra data to store in header.
159 LPCSTR pRuntimeVersion); // The version string as it's length is part of the total size.
160
161//*****************************************************************************
162// Adjust the offset in each known stream to match where it will wind up after
163// a save operation.
164//*****************************************************************************
165 static HRESULT CalcOffsets( // Return code.
166 STORAGESTREAMLST *pStreamList, // List of streams for header.
167 ULONG cbExtra, // Size of variable extra data in header.
168 LPCSTR pRuntimeVersion); // The version string as it's length is part of the total size.
169
170
171
172//*****************************************************************************
173// Returns the size of the signature plus the verion information
174//*****************************************************************************
175 static HRESULT SizeOfStorageSignature(
176 LPCSTR pRuntimeVersion, // The version string as it's length is part of the total size.
177 ULONG *pcbSignatureSize);
178
179// IStorage
180 virtual HRESULT STDMETHODCALLTYPE CreateStream(
181 const OLECHAR *pwcsName,
182 DWORD grfMode,
183 DWORD reserved1,
184 DWORD reserved2,
185 IStream **ppstm);
186
187 virtual HRESULT STDMETHODCALLTYPE CreateStream(
188 LPCSTR szName,
189 DWORD grfMode,
190 DWORD reserved1,
191 DWORD reserved2,
192 IStream **ppstm)
193 DAC_UNEXPECTED();
194
195 virtual HRESULT STDMETHODCALLTYPE OpenStream(
196 const OLECHAR *pwcsName,
197 void *reserved1,
198 DWORD grfMode,
199 DWORD reserved2,
200 IStream **ppstm);
201
202 virtual HRESULT STDMETHODCALLTYPE CreateStorage(
203 const OLECHAR *pwcsName,
204 DWORD grfMode,
205 DWORD dwStgFmt,
206 DWORD reserved2,
207 IStorage **ppstg);
208
209 virtual HRESULT STDMETHODCALLTYPE OpenStorage(
210 const OLECHAR * wcsName,
211 IStorage * pStgPriority,
212 DWORD dwMode,
213 __in
214 SNB snbExclude,
215 DWORD reserved,
216 IStorage ** ppStg);
217
218 virtual HRESULT STDMETHODCALLTYPE CopyTo(
219 DWORD cIidExclude,
220 const IID * rgIidExclude,
221 __in
222 SNB snbExclude,
223 IStorage * pStgDest);
224
225 virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
226 const OLECHAR *pwcsName,
227 IStorage *pstgDest,
228 const OLECHAR *pwcsNewName,
229 DWORD grfFlags);
230
231 virtual HRESULT STDMETHODCALLTYPE Commit(
232 DWORD grfCommitFlags);
233
234 virtual HRESULT STDMETHODCALLTYPE Revert();
235
236 virtual HRESULT STDMETHODCALLTYPE EnumElements(
237 DWORD reserved1,
238 void *reserved2,
239 DWORD reserved3,
240 IEnumSTATSTG **ppenum);
241
242 virtual HRESULT STDMETHODCALLTYPE DestroyElement(
243 const OLECHAR *pwcsName);
244
245 virtual HRESULT STDMETHODCALLTYPE RenameElement(
246 const OLECHAR *pwcsOldName,
247 const OLECHAR *pwcsNewName);
248
249 virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
250 const OLECHAR *pwcsName,
251 const FILETIME *pctime,
252 const FILETIME *patime,
253 const FILETIME *pmtime);
254
255 virtual HRESULT STDMETHODCALLTYPE SetClass(
256 REFCLSID clsid);
257
258 virtual HRESULT STDMETHODCALLTYPE SetStateBits(
259 DWORD grfStateBits,
260 DWORD grfMask);
261
262 virtual HRESULT STDMETHODCALLTYPE Stat(
263 STATSTG *pstatstg,
264 DWORD grfStatFlag);
265
266 virtual HRESULT STDMETHODCALLTYPE OpenStream(
267 LPCWSTR szStream,
268 ULONG *pcbData,
269 void **ppAddress);
270
271 // Access storage object.
272 StgIO *GetStgIO()
273 { return (m_pStgIO); }
274
275#if defined(_DEBUG)
276 ULONG PrintSizeInfo( // Size of streams.
277 bool verbose); // Be verbose?
278#endif
279
280protected:
281 HRESULT Write( // Return code.
282 LPCSTR szName, // Name of stream we're writing.
283 const void *pData, // Data to write.
284 ULONG cbData, // Size of data.
285 ULONG *pcbWritten); // How much did we write.
286
287private:
288 HRESULT FindStream(LPCSTR szName, __out PSTORAGESTREAM *stream);
289 HRESULT WriteSignature(LPCSTR pVersion);
290 HRESULT VerifySignature(PSTORAGESIGNATURE pSig);
291 HRESULT ReadHeader();
292 HRESULT VerifyHeader();
293
294 static HRESULT GetDefaultVersion(LPCSTR* ppVersion);
295
296public:
297 // This function is a workaround to allow access to the "version requested" string.
298 HRESULT GetHeaderPointer(const void **ppv, ULONG *pcb);
299
300private:
301 // State data.
302 StgIO *m_pStgIO; // Storage subsystem.
303 LONG m_cRef; // Ref count for COM.
304
305 // Header data.
306 STORAGEHEADER m_StgHdr; // Header for storage.
307 STORAGESTREAMLST m_Streams; // List of streams in the storage.
308 PSTORAGESTREAM m_pStreamList; // For read mode.
309 void *m_pbExtra; // Pointer to extra data if on disk.
310};
311
312
313//*****************************************************************************
314// Debugging helpers. #define __SAVESIZE_TRACE__ to enable.
315//*****************************************************************************
316
317// #define __SAVESIZE_TRACE__
318#ifdef __SAVESIZE_TRACE__
319#define SAVETRACE(func) DEBUG_STMT(func)
320#else
321#define SAVETRACE(func)
322#endif // __SAVESIZE_TRACE__
323
324#endif // StgTiggerStorage
325
326
327
328// EOF
329