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
24HRESULT 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//*****************************************************************************
36HRESULT
37CheckFileFormat(
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
150ErrExit:
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//*****************************************************************************
161STDAPI 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
210ErrExit:
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