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 | |
54 | typedef CDynArray<STORAGESTREAM> STORAGESTREAMLST; |
55 | |
56 | |
57 | // Forwards. |
58 | class TiggerStream; |
59 | class StgIO; |
60 | |
61 | |
62 | |
63 | class TiggerStorage : |
64 | public IStorage |
65 | { |
66 | friend class TiggerStream; |
67 | public: |
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 ( // Return code. |
101 | ULONG *, // 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 ( // Return code. |
108 | STORAGESTREAMLST *pList, // List of streams. |
109 | ULONG , // Size of extra data, may be 0. |
110 | BYTE *); // 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 , // 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 , // 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 | |
280 | protected: |
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 | |
287 | private: |
288 | HRESULT FindStream(LPCSTR szName, __out PSTORAGESTREAM *stream); |
289 | HRESULT WriteSignature(LPCSTR pVersion); |
290 | HRESULT VerifySignature(PSTORAGESIGNATURE pSig); |
291 | HRESULT (); |
292 | HRESULT (); |
293 | |
294 | static HRESULT GetDefaultVersion(LPCSTR* ppVersion); |
295 | |
296 | public: |
297 | // This function is a workaround to allow access to the "version requested" string. |
298 | HRESULT (const void **ppv, ULONG *pcb); |
299 | |
300 | private: |
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 *; // 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 | |