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// StgPoolReadOnly.cpp
6//
7
8//
9// Read only pools are used to reduce the amount of data actually required in the database.
10//
11//*****************************************************************************
12#include "stdafx.h" // Standard include.
13#include <stgpool.h> // Our interface definitions.
14#include "metadatatracker.h"
15//
16//
17// StgPoolReadOnly
18//
19//
20
21#if METADATATRACKER_ENABLED
22MetaDataTracker *MetaDataTracker::m_MDTrackers = NULL;
23BOOL MetaDataTracker::s_bEnabled = FALSE;
24
25void (*MetaDataTracker::s_IBCLogMetaDataAccess)(const void *addr) = NULL;
26void (*MetaDataTracker::s_IBCLogMetaDataSearch)(const void *result) = NULL;
27
28#endif // METADATATRACKER_ENABLED
29
30const BYTE StgPoolSeg::m_zeros[64] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
31 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
32 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
33 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
34
35
36//*****************************************************************************
37// Free any memory we allocated.
38//*****************************************************************************
39StgPoolReadOnly::~StgPoolReadOnly()
40{
41 LIMITED_METHOD_CONTRACT;
42}
43
44
45//*****************************************************************************
46// Init the pool from existing data.
47//*****************************************************************************
48HRESULT StgPoolReadOnly::InitOnMemReadOnly(// Return code.
49 void *pData, // Predefined data.
50 ULONG iSize) // Size of data.
51{
52 CONTRACTL
53 {
54 NOTHROW;
55 INJECT_FAULT(return E_OUTOFMEMORY);
56 }
57 CONTRACTL_END
58
59 // Make sure we aren't stomping anything and are properly initialized.
60 _ASSERTE(m_pSegData == m_zeros);
61
62 // Create case requires no further action.
63 if (pData == NULL)
64 return E_INVALIDARG;
65
66 // Keep m_zeros data pointer if there's no content of the pool
67 if (iSize != 0)
68 {
69 m_pSegData = reinterpret_cast<BYTE*>(pData);
70 }
71 m_cbSegSize = iSize;
72 m_cbSegNext = iSize;
73 return S_OK;
74}
75
76//*****************************************************************************
77// Prepare to shut down or reinitialize.
78//*****************************************************************************
79void StgPoolReadOnly::Uninit()
80{
81 LIMITED_METHOD_CONTRACT;
82
83 m_pSegData = (BYTE*)m_zeros;
84 m_pNextSeg = 0;
85}
86
87
88//*****************************************************************************
89// Convert a string to UNICODE into the caller's buffer.
90//*****************************************************************************
91HRESULT StgPoolReadOnly::GetStringW( // Return code.
92 ULONG iOffset, // Offset of string in pool.
93 __out_ecount(cchBuffer) LPWSTR szOut, // Output buffer for string.
94 int cchBuffer) // Size of output buffer.
95{
96 STATIC_CONTRACT_NOTHROW;
97 STATIC_CONTRACT_FAULT;
98
99 HRESULT hr;
100 LPCSTR pString; // The string in UTF8.
101 int iChars;
102
103 IfFailRet(GetString(iOffset, &pString));
104 iChars = ::WszMultiByteToWideChar(CP_UTF8, 0, pString, -1, szOut, cchBuffer);
105 if (iChars == 0)
106 return (BadError(HRESULT_FROM_NT(GetLastError())));
107 return S_OK;
108}
109
110//*****************************************************************************
111// Return a pointer to a null terminated blob given an offset previously
112// handed out by Addblob or Findblob.
113//*****************************************************************************
114HRESULT
115StgPoolReadOnly::GetBlob(
116 UINT32 nOffset, // Offset of blob in pool.
117 MetaData::DataBlob *pData)
118{
119 STATIC_CONTRACT_NOTHROW;
120 STATIC_CONTRACT_FORBID_FAULT;
121
122 HRESULT hr;
123 UINT32 cbBlobContentSize;
124
125 // This should not be a necessary special case. The zero byte at the
126 // start of the pool will code for a length of zero. We will return
127 // a pointer to the next length byte, but the caller should notice that
128 // the size is zero, and should not look at any bytes.
129 // [SL] Yes, but we don't need all further computations and checks if iOffset==0
130
131 if (nOffset == 0)
132 {
133 pData->Clear();
134 return S_OK;
135 }
136
137 // Is the offset within this heap?
138 if (!IsValidOffset(nOffset))
139 {
140 Debug_ReportError("Invalid blob offset.");
141 IfFailGo(CLDB_E_INDEX_NOTFOUND);
142 }
143
144 IfFailGo(GetDataReadOnly(nOffset, pData));
145 if (!pData->GetCompressedU(&cbBlobContentSize))
146 {
147 Debug_ReportError("Invalid blob - size compression.");
148 IfFailGo(COR_E_BADIMAGEFORMAT);
149 }
150 if (!pData->TruncateToExactSize(cbBlobContentSize))
151 {
152 Debug_ReportError("Invalid blob - reaches behind the end of data block.");
153 IfFailGo(COR_E_BADIMAGEFORMAT);
154 }
155
156 return S_OK;
157ErrExit:
158 pData->Clear();
159 return hr;
160} // StgPoolReadOnly::GetBlob
161
162//*****************************************************************************
163// code:StgPoolReadOnly::GetBlob specialization with inlined check for valid offsets to avoid redundant code:StgPoolReadOnly::GetDataReadOnly calls.
164// code:StgPoolReadOnly::GetDataReadOnly is not cheap because of it performs binary lookup in hot metadata.
165//*****************************************************************************
166HRESULT
167StgBlobPoolReadOnly::GetBlob(
168 UINT32 nOffset, // Offset of blob in pool.
169 MetaData::DataBlob *pData)
170{
171 STATIC_CONTRACT_NOTHROW;
172 STATIC_CONTRACT_FORBID_FAULT;
173
174 HRESULT hr;
175 UINT32 cbBlobContentSize;
176
177 // This should not be a necessary special case. The zero byte at the
178 // start of the pool will code for a length of zero. We will return
179 // a pointer to the next length byte, but the caller should notice that
180 // the size is zero, and should not look at any bytes.
181 // [SL] Yes, but we don't need all further computations and checks if iOffset==0
182
183 if (nOffset == 0)
184 {
185 pData->Clear();
186 return S_OK;
187 }
188
189 if (m_pSegData == m_zeros)
190 {
191 Debug_ReportError("Invalid blob offset.");
192 IfFailGo(CLDB_E_INDEX_NOTFOUND);
193 }
194
195 IfFailGo(GetDataReadOnly(nOffset, pData));
196 if (!pData->GetCompressedU(&cbBlobContentSize))
197 {
198 Debug_ReportError("Invalid blob - size compression.");
199 IfFailGo(CLDB_E_INDEX_NOTFOUND);
200 }
201 if (!pData->TruncateToExactSize(cbBlobContentSize))
202 {
203 Debug_ReportError("Invalid blob - reaches behind the end of data block.");
204 IfFailGo(CLDB_E_INDEX_NOTFOUND);
205 }
206
207 return S_OK;
208ErrExit:
209 pData->Clear();
210 return hr;
211} // StgBlobPoolReadOnly::GetBlob
212