| 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 | // StgPooli.h |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // This is helper code for the string and blob pools. It is here because it is |
| 10 | // secondary to the pooling interface and reduces clutter in the main file. |
| 11 | // |
| 12 | //***************************************************************************** |
| 13 | |
| 14 | #ifndef __StgPooli_h__ |
| 15 | #define __StgPooli_h__ |
| 16 | |
| 17 | #include "utilcode.h" // Base hashing code. |
| 18 | |
| 19 | |
| 20 | |
| 21 | // |
| 22 | // |
| 23 | // CPackedLen |
| 24 | // |
| 25 | // |
| 26 | |
| 27 | //***************************************************************************** |
| 28 | // Helper class to pack and unpack lengths. |
| 29 | //***************************************************************************** |
| 30 | struct CPackedLen |
| 31 | { |
| 32 | enum {MAX_LEN = 0x1fffffff}; |
| 33 | static int Size(ULONG len) |
| 34 | { |
| 35 | LIMITED_METHOD_CONTRACT; |
| 36 | // Smallest. |
| 37 | if (len <= 0x7F) |
| 38 | return 1; |
| 39 | // Medium. |
| 40 | if (len <= 0x3FFF) |
| 41 | return 2; |
| 42 | // Large (too large?). |
| 43 | _ASSERTE(len <= MAX_LEN); |
| 44 | return 4; |
| 45 | } |
| 46 | |
| 47 | // Get a pointer to the data, and store the length. |
| 48 | static void const *GetData(void const *pData, ULONG *pLength); |
| 49 | |
| 50 | // Get the length value encoded at *pData. Update ppData to point past data. |
| 51 | static ULONG GetLength(void const *pData, void const **ppData=0); |
| 52 | |
| 53 | // Get the length value encoded at *pData, and the size of that encoded value. |
| 54 | static ULONG GetLength(void const *pData, int *pSizeOfLength); |
| 55 | |
| 56 | // Pack a length at *pData; return a pointer to the next byte. |
| 57 | static void* PutLength(void *pData, ULONG len); |
| 58 | |
| 59 | // This is used for just getting an encoded length, and verifies that |
| 60 | // there is no buffer or integer overflow. |
| 61 | static HRESULT SafeGetLength( // S_OK, or error |
| 62 | void const *pDataSource, // First byte of length. |
| 63 | void const *pDataSourceEnd, // End of valid source data memory |
| 64 | ULONG *pLength, // Encoded value |
| 65 | void const **ppDataNext); // Pointer immediately following encoded length |
| 66 | |
| 67 | static HRESULT SafeGetLength( // S_OK, or error |
| 68 | BYTE const *pDataSource, // First byte of length. |
| 69 | BYTE const *pDataSourceEnd, // End of valid source data memory |
| 70 | ULONG *pLength, // Encoded value |
| 71 | BYTE const **ppDataNext) // Pointer immediately following encoded length |
| 72 | { |
| 73 | return SafeGetLength( |
| 74 | reinterpret_cast<void const *>(pDataSource), |
| 75 | reinterpret_cast<void const *>(pDataSourceEnd), |
| 76 | pLength, |
| 77 | reinterpret_cast<void const **>(ppDataNext)); |
| 78 | } |
| 79 | |
| 80 | // This performs the same tasks as GetLength above in addition to checking |
| 81 | // that the value in *pcbData does not extend *ppData beyond pDataSourceEnd |
| 82 | // and does not cause an integer overflow. |
| 83 | static HRESULT SafeGetData( |
| 84 | void const *pDataSource, // First byte of length. |
| 85 | void const *pDataSourceEnd, // End of valid source data memory |
| 86 | ULONG *pcbData, // Length of data |
| 87 | void const **ppData); // Start of data |
| 88 | |
| 89 | static HRESULT SafeGetData( |
| 90 | BYTE const *pDataSource, // First byte of length. |
| 91 | BYTE const *pDataSourceEnd, // End of valid source data memory |
| 92 | ULONG *pcbData, // Length of data |
| 93 | BYTE const **ppData) // Start of data |
| 94 | { |
| 95 | return SafeGetData( |
| 96 | reinterpret_cast<void const *>(pDataSource), |
| 97 | reinterpret_cast<void const *>(pDataSourceEnd), |
| 98 | pcbData, |
| 99 | reinterpret_cast<void const **>(ppData)); |
| 100 | } |
| 101 | |
| 102 | // This is the same as GetData above except it takes a byte count instead |
| 103 | // of pointer to determine the source data length. |
| 104 | static HRESULT SafeGetData( // S_OK, or error |
| 105 | void const *pDataSource, // First byte of data |
| 106 | ULONG cbDataSource, // Count of valid bytes in data source |
| 107 | ULONG *pcbData, // Length of data |
| 108 | void const **ppData); // Start of data |
| 109 | |
| 110 | static HRESULT SafeGetData( |
| 111 | BYTE const *pDataSource, // First byte of length. |
| 112 | ULONG cbDataSource, // Count of valid bytes in data source |
| 113 | ULONG *pcbData, // Length of data |
| 114 | BYTE const **ppData) // Start of data |
| 115 | { |
| 116 | return SafeGetData( |
| 117 | reinterpret_cast<void const *>(pDataSource), |
| 118 | cbDataSource, |
| 119 | pcbData, |
| 120 | reinterpret_cast<void const **>(ppData)); |
| 121 | } |
| 122 | }; |
| 123 | |
| 124 | |
| 125 | class StgPoolReadOnly; |
| 126 | |
| 127 | //***************************************************************************** |
| 128 | // This hash class will handle strings inside of a chunk of the pool. |
| 129 | //***************************************************************************** |
| 130 | struct STRINGHASH : HASHLINK |
| 131 | { |
| 132 | ULONG iOffset; // Offset of this item. |
| 133 | }; |
| 134 | |
| 135 | class CStringPoolHash : public CChainedHash<STRINGHASH> |
| 136 | { |
| 137 | friend class VerifyLayoutsMD; |
| 138 | public: |
| 139 | CStringPoolHash(StgPoolReadOnly *pool) : m_Pool(pool) |
| 140 | { |
| 141 | LIMITED_METHOD_CONTRACT; |
| 142 | } |
| 143 | |
| 144 | virtual bool InUse(STRINGHASH *pItem) |
| 145 | { |
| 146 | LIMITED_METHOD_CONTRACT; |
| 147 | return (pItem->iOffset != 0xffffffff); |
| 148 | } |
| 149 | |
| 150 | virtual void SetFree(STRINGHASH *pItem) |
| 151 | { |
| 152 | LIMITED_METHOD_CONTRACT; |
| 153 | pItem->iOffset = 0xffffffff; |
| 154 | } |
| 155 | |
| 156 | virtual ULONG Hash(const void *pData) |
| 157 | { |
| 158 | WRAPPER_NO_CONTRACT; |
| 159 | return (HashStringA(reinterpret_cast<LPCSTR>(pData))); |
| 160 | } |
| 161 | |
| 162 | virtual int Cmp(const void *pData, void *pItem); |
| 163 | |
| 164 | private: |
| 165 | StgPoolReadOnly *m_Pool; // String pool which this hashes. |
| 166 | }; |
| 167 | |
| 168 | |
| 169 | //***************************************************************************** |
| 170 | // This version is for byte streams with a 2 byte WORD giving the length of |
| 171 | // the data. |
| 172 | //***************************************************************************** |
| 173 | typedef STRINGHASH BLOBHASH; |
| 174 | |
| 175 | class CBlobPoolHash : public CChainedHash<STRINGHASH> |
| 176 | { |
| 177 | friend class VerifyLayoutsMD; |
| 178 | public: |
| 179 | CBlobPoolHash(StgPoolReadOnly *pool) : m_Pool(pool) |
| 180 | { |
| 181 | LIMITED_METHOD_CONTRACT; |
| 182 | } |
| 183 | |
| 184 | virtual bool InUse(BLOBHASH *pItem) |
| 185 | { |
| 186 | LIMITED_METHOD_CONTRACT; |
| 187 | return (pItem->iOffset != 0xffffffff); |
| 188 | } |
| 189 | |
| 190 | virtual void SetFree(BLOBHASH *pItem) |
| 191 | { |
| 192 | LIMITED_METHOD_CONTRACT; |
| 193 | pItem->iOffset = 0xffffffff; |
| 194 | } |
| 195 | |
| 196 | virtual ULONG Hash(const void *pData) |
| 197 | { |
| 198 | STATIC_CONTRACT_NOTHROW; |
| 199 | STATIC_CONTRACT_GC_NOTRIGGER; |
| 200 | STATIC_CONTRACT_FORBID_FAULT; |
| 201 | |
| 202 | ULONG ulSize; |
| 203 | ulSize = CPackedLen::GetLength(pData); |
| 204 | ulSize += CPackedLen::Size(ulSize); |
| 205 | return (HashBytes(reinterpret_cast<BYTE const *>(pData), ulSize)); |
| 206 | } |
| 207 | |
| 208 | virtual int Cmp(const void *pData, void *pItem); |
| 209 | |
| 210 | private: |
| 211 | StgPoolReadOnly *m_Pool; // Blob pool which this hashes. |
| 212 | }; |
| 213 | |
| 214 | //***************************************************************************** |
| 215 | // This hash class will handle guids inside of a chunk of the pool. |
| 216 | //***************************************************************************** |
| 217 | struct GUIDHASH : HASHLINK |
| 218 | { |
| 219 | ULONG iIndex; // Index of this item. |
| 220 | }; |
| 221 | |
| 222 | class CGuidPoolHash : public CChainedHash<GUIDHASH> |
| 223 | { |
| 224 | friend class VerifyLayoutsMD; |
| 225 | public: |
| 226 | CGuidPoolHash(StgPoolReadOnly *pool) : m_Pool(pool) |
| 227 | { |
| 228 | LIMITED_METHOD_CONTRACT; |
| 229 | } |
| 230 | |
| 231 | virtual bool InUse(GUIDHASH *pItem) |
| 232 | { |
| 233 | LIMITED_METHOD_CONTRACT; |
| 234 | return (pItem->iIndex != 0xffffffff); |
| 235 | } |
| 236 | |
| 237 | virtual void SetFree(GUIDHASH *pItem) |
| 238 | { |
| 239 | LIMITED_METHOD_CONTRACT; |
| 240 | pItem->iIndex = 0xffffffff; |
| 241 | } |
| 242 | |
| 243 | virtual ULONG Hash(const void *pData) |
| 244 | { |
| 245 | WRAPPER_NO_CONTRACT; |
| 246 | return (HashBytes(reinterpret_cast<BYTE const *>(pData), sizeof(GUID))); |
| 247 | } |
| 248 | |
| 249 | virtual int Cmp(const void *pData, void *pItem); |
| 250 | |
| 251 | private: |
| 252 | StgPoolReadOnly *m_Pool; // The GUID pool which this hashes. |
| 253 | }; |
| 254 | |
| 255 | |
| 256 | #endif // __StgPooli_h__ |
| 257 | |