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 | // File: MDInternalDisp.CPP |
6 | // |
7 | |
8 | // Notes: |
9 | // |
10 | // |
11 | // =========================================================================== |
12 | #include "stdafx.h" |
13 | #include "mdinternaldisp.h" |
14 | #include "mdinternalro.h" |
15 | #include "posterror.h" |
16 | #include "corpriv.h" |
17 | #include "assemblymdinternaldisp.h" |
18 | #include "pedecoder.h" |
19 | #include "winmdinterfaces.h" |
20 | |
21 | #ifdef FEATURE_METADATA_INTERNAL_APIS |
22 | |
23 | // forward declaration |
24 | HRESULT GetInternalWithRWFormat( |
25 | LPVOID pData, |
26 | ULONG cbData, |
27 | DWORD flags, // [IN] MDInternal_OpenForRead or MDInternal_OpenForENC |
28 | REFIID riid, // [in] The interface desired. |
29 | void **ppIUnk); // [out] Return interface on success. |
30 | |
31 | //***************************************************************************** |
32 | // CheckFileFormat |
33 | // This function will determine if the in-memory image is a readonly, readwrite, |
34 | // or ICR format. |
35 | //***************************************************************************** |
36 | HRESULT |
37 | CheckFileFormat( |
38 | LPVOID pData, |
39 | ULONG cbData, |
40 | MDFileFormat *pFormat) // [OUT] the file format |
41 | { |
42 | HRESULT hr = NOERROR; |
43 | STORAGEHEADER sHdr; // Header for the storage. |
44 | PSTORAGESTREAM pStream; // Pointer to each stream. |
45 | int i; |
46 | ULONG cbStreamBuffer; |
47 | |
48 | _ASSERTE(pFormat != NULL); |
49 | |
50 | *pFormat = MDFormat_Invalid; |
51 | |
52 | // Validate the signature of the format, or it isn't ours. |
53 | if (FAILED(hr = MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData))) |
54 | goto ErrExit; |
55 | |
56 | // Remaining buffer size behind the stream header (pStream). |
57 | cbStreamBuffer = cbData; |
58 | // Get back the first stream. |
59 | pStream = MDFormat::GetFirstStream_Verify(&sHdr, pData, &cbStreamBuffer); |
60 | if (pStream == NULL) |
61 | { |
62 | Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header." ); |
63 | IfFailGo(CLDB_E_FILE_CORRUPT); |
64 | } |
65 | |
66 | // Loop through each stream and pick off the ones we need. |
67 | for (i = 0; i < sHdr.GetiStreams(); i++) |
68 | { |
69 | // Do we have enough buffer to read stream header? |
70 | if (cbStreamBuffer < sizeof(*pStream)) |
71 | { |
72 | Debug_ReportError("Stream header is not within MetaData block." ); |
73 | IfFailGo(CLDB_E_FILE_CORRUPT); |
74 | } |
75 | // Get next stream. |
76 | PSTORAGESTREAM pNext = pStream->NextStream_Verify(); |
77 | if (pNext == NULL) |
78 | { // Stream header is corrupted. |
79 | Debug_ReportError("Invalid stream header - cannot get next stream header." ); |
80 | IfFailGo(CLDB_E_FILE_CORRUPT); |
81 | } |
82 | |
83 | // Check that stream header is within the buffer. |
84 | if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) || |
85 | ((LPBYTE)pNext > ((LPBYTE)pData + cbData))) |
86 | { |
87 | Debug_ReportError("Stream header is not within MetaData block." ); |
88 | hr = CLDB_E_FILE_CORRUPT; |
89 | goto ErrExit; |
90 | } |
91 | |
92 | // Check that the stream data starts and fits within the buffer. |
93 | // need two checks on size because of wraparound. |
94 | if ((pStream->GetOffset() > cbData) || |
95 | (pStream->GetSize() > cbData) || |
96 | ((pStream->GetSize() + pStream->GetOffset()) < pStream->GetOffset()) || |
97 | ((pStream->GetSize() + pStream->GetOffset()) > cbData)) |
98 | { |
99 | Debug_ReportError("Stream data are not within MetaData block." ); |
100 | hr = CLDB_E_FILE_CORRUPT; |
101 | goto ErrExit; |
102 | } |
103 | |
104 | // Pick off the location and size of the data. |
105 | |
106 | if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0) |
107 | { |
108 | // Validate that only one of compressed/uncompressed is present. |
109 | if (*pFormat != MDFormat_Invalid) |
110 | { // Already found a good stream. |
111 | Debug_ReportError("Compressed model stream #~ is second important stream." ); |
112 | hr = CLDB_E_FILE_CORRUPT; |
113 | goto ErrExit; |
114 | } |
115 | // Found the compressed meta data stream. |
116 | *pFormat = MDFormat_ReadOnly; |
117 | } |
118 | else if (strcmp(pStream->GetName(), ENC_MODEL_STREAM_A) == 0) |
119 | { |
120 | // Validate that only one of compressed/uncompressed is present. |
121 | if (*pFormat != MDFormat_Invalid) |
122 | { // Already found a good stream. |
123 | Debug_ReportError("ENC model stream #- is second important stream." ); |
124 | hr = CLDB_E_FILE_CORRUPT; |
125 | goto ErrExit; |
126 | } |
127 | // Found the ENC meta data stream. |
128 | *pFormat = MDFormat_ReadWrite; |
129 | } |
130 | else if (strcmp(pStream->GetName(), SCHEMA_STREAM_A) == 0) |
131 | { |
132 | // Found the uncompressed format |
133 | *pFormat = MDFormat_ICR; |
134 | |
135 | // keep going. We may find the compressed format later. |
136 | // If so, we want to use the compressed format. |
137 | } |
138 | |
139 | // Pick off the next stream if there is one. |
140 | pStream = pNext; |
141 | cbStreamBuffer = (ULONG)((LPBYTE)pData + cbData - (LPBYTE)pNext); |
142 | } |
143 | |
144 | if (*pFormat == MDFormat_Invalid) |
145 | { // Didn't find a good stream. |
146 | Debug_ReportError("Cannot find MetaData stream." ); |
147 | hr = CLDB_E_FILE_CORRUPT; |
148 | } |
149 | |
150 | ErrExit: |
151 | return hr; |
152 | } // CheckFileFormat |
153 | |
154 | |
155 | |
156 | //***************************************************************************** |
157 | // GetMDInternalInterface. |
158 | // This function will check the metadata section and determine if it should |
159 | // return an interface which implements ReadOnly or ReadWrite. |
160 | //***************************************************************************** |
161 | STDAPI GetMDInternalInterface( |
162 | LPVOID pData, |
163 | ULONG cbData, |
164 | DWORD flags, // [IN] ofRead or ofWrite. |
165 | REFIID riid, // [in] The interface desired. |
166 | void **ppIUnk) // [out] Return interface on success. |
167 | { |
168 | HRESULT hr = NOERROR; |
169 | MDInternalRO *pInternalRO = NULL; |
170 | IMDCommon *pInternalROMDCommon = NULL; |
171 | MDFileFormat format; |
172 | |
173 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); |
174 | |
175 | if (ppIUnk == NULL) |
176 | IfFailGo(E_INVALIDARG); |
177 | |
178 | // Determine the file format we're trying to read. |
179 | IfFailGo( CheckFileFormat(pData, cbData, &format) ); |
180 | |
181 | // Found a fully-compressed, read-only format. |
182 | if ( format == MDFormat_ReadOnly ) |
183 | { |
184 | pInternalRO = new (nothrow) MDInternalRO; |
185 | IfNullGo( pInternalRO ); |
186 | |
187 | IfFailGo( pInternalRO->Init(const_cast<void*>(pData), cbData) ); |
188 | |
189 | #ifdef FEATURE_COMINTEROP |
190 | IfFailGo(pInternalRO->QueryInterface(IID_IMDCommon, (void**)&pInternalROMDCommon)); |
191 | IfFailGo( (flags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pInternalROMDCommon)); |
192 | if (hr == S_OK) |
193 | { |
194 | IfFailGo(CreateWinMDInternalImportRO(pInternalROMDCommon, riid, (void**)ppIUnk)); |
195 | } |
196 | else |
197 | #endif // FEATURE_COMINTEROP |
198 | { |
199 | IfFailGo(pInternalRO->QueryInterface(riid, ppIUnk)); |
200 | } |
201 | |
202 | } |
203 | else |
204 | { |
205 | // Found a not-fully-compressed, ENC format. |
206 | _ASSERTE( format == MDFormat_ReadWrite ); |
207 | IfFailGo( GetInternalWithRWFormat( pData, cbData, flags, riid, ppIUnk ) ); |
208 | } |
209 | |
210 | ErrExit: |
211 | |
212 | // clean up |
213 | if ( pInternalRO ) |
214 | pInternalRO->Release(); |
215 | if ( pInternalROMDCommon ) |
216 | pInternalROMDCommon->Release(); |
217 | |
218 | END_SO_INTOLERANT_CODE; |
219 | |
220 | return hr; |
221 | } // GetMDInternalInterface |
222 | |
223 | |
224 | |
225 | #endif //FEATURE_METADATA_INTERNAL_APIS |
226 | |