| 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: caparser.h |
| 6 | // |
| 7 | |
| 8 | |
| 9 | // |
| 10 | |
| 11 | // |
| 12 | // ============================================================================ |
| 13 | |
| 14 | #ifndef __CAPARSER_H__ |
| 15 | #define __CAPARSER_H__ |
| 16 | |
| 17 | #include "stgpooli.h" |
| 18 | |
| 19 | class CustomAttributeParser { |
| 20 | public: |
| 21 | CustomAttributeParser( // Constructor for CustomAttributeParser. |
| 22 | const void *pvBlob, // Pointer to the CustomAttribute blob. |
| 23 | ULONG cbBlob) // Size of the CustomAttribute blob. |
| 24 | : m_pbCur(reinterpret_cast<const BYTE*>(pvBlob)), |
| 25 | m_pbBlob(reinterpret_cast<const BYTE*>(pvBlob)), |
| 26 | m_cbBlob(cbBlob) |
| 27 | { |
| 28 | LIMITED_METHOD_CONTRACT; |
| 29 | } |
| 30 | |
| 31 | private: |
| 32 | signed __int8 GetI1() |
| 33 | { |
| 34 | LIMITED_METHOD_CONTRACT; |
| 35 | signed __int8 tmp = *reinterpret_cast<const signed __int8*>(m_pbCur); |
| 36 | m_pbCur += sizeof(signed __int8); |
| 37 | return tmp; |
| 38 | } |
| 39 | unsigned __int8 GetU1() |
| 40 | { |
| 41 | LIMITED_METHOD_CONTRACT; |
| 42 | unsigned __int8 tmp = *reinterpret_cast<const unsigned __int8*>(m_pbCur); |
| 43 | m_pbCur += sizeof(unsigned __int8); |
| 44 | return tmp; |
| 45 | } |
| 46 | |
| 47 | signed __int16 GetI2() |
| 48 | { |
| 49 | LIMITED_METHOD_CONTRACT; |
| 50 | signed __int16 tmp = GET_UNALIGNED_VAL16(m_pbCur); |
| 51 | m_pbCur += sizeof(signed __int16); |
| 52 | return tmp; |
| 53 | } |
| 54 | unsigned __int16 GetU2() |
| 55 | { |
| 56 | LIMITED_METHOD_CONTRACT; |
| 57 | unsigned __int16 tmp = GET_UNALIGNED_VAL16(m_pbCur); |
| 58 | m_pbCur += sizeof(unsigned __int16 ); |
| 59 | return tmp; |
| 60 | } |
| 61 | |
| 62 | signed __int32 GetI4() |
| 63 | { |
| 64 | LIMITED_METHOD_CONTRACT; |
| 65 | signed __int32 tmp = GET_UNALIGNED_VAL32(m_pbCur); |
| 66 | m_pbCur += sizeof(signed __int32 ); |
| 67 | return tmp; |
| 68 | } |
| 69 | unsigned __int32 GetU4() |
| 70 | { |
| 71 | LIMITED_METHOD_CONTRACT; |
| 72 | unsigned __int32 tmp = GET_UNALIGNED_VAL32(m_pbCur); |
| 73 | m_pbCur += sizeof(unsigned __int32 ); |
| 74 | return tmp; |
| 75 | } |
| 76 | |
| 77 | signed __int64 GetI8() |
| 78 | { |
| 79 | LIMITED_METHOD_CONTRACT; |
| 80 | signed __int64 tmp = GET_UNALIGNED_VAL64(m_pbCur); |
| 81 | m_pbCur += sizeof(signed __int64 ); |
| 82 | return tmp; |
| 83 | } |
| 84 | unsigned __int64 GetU8() |
| 85 | { |
| 86 | LIMITED_METHOD_CONTRACT; |
| 87 | unsigned __int64 tmp = GET_UNALIGNED_VAL64(m_pbCur); |
| 88 | m_pbCur += sizeof(unsigned __int64 ); |
| 89 | return tmp; |
| 90 | } |
| 91 | |
| 92 | public: |
| 93 | float GetR4() |
| 94 | { |
| 95 | LIMITED_METHOD_CONTRACT; |
| 96 | __int32 tmp = GET_UNALIGNED_VAL32(m_pbCur); |
| 97 | _ASSERTE(sizeof(__int32) == sizeof(float)); |
| 98 | m_pbCur += sizeof(float); |
| 99 | return (float &)tmp; |
| 100 | } |
| 101 | |
| 102 | double GetR8() |
| 103 | { |
| 104 | LIMITED_METHOD_CONTRACT; |
| 105 | __int64 tmp = GET_UNALIGNED_VAL64(m_pbCur); |
| 106 | _ASSERTE(sizeof(__int64) == sizeof(double)); |
| 107 | m_pbCur += sizeof(double); |
| 108 | return (double &)tmp; |
| 109 | } |
| 110 | |
| 111 | private: |
| 112 | unsigned __int16 GetProlog() |
| 113 | { |
| 114 | WRAPPER_NO_CONTRACT; |
| 115 | unsigned __int16 val; |
| 116 | VERIFY(SUCCEEDED(GetProlog(&val))); |
| 117 | return val; |
| 118 | } |
| 119 | |
| 120 | LPCUTF8 GetString(ULONG *pcbString) |
| 121 | { |
| 122 | WRAPPER_NO_CONTRACT; |
| 123 | LPCUTF8 val; |
| 124 | VERIFY(SUCCEEDED(GetString(&val, pcbString))); |
| 125 | return val; |
| 126 | } |
| 127 | |
| 128 | public: |
| 129 | HRESULT GetI1(signed __int8 *pVal) |
| 130 | { |
| 131 | WRAPPER_NO_CONTRACT; |
| 132 | |
| 133 | if (BytesLeft() < (int) sizeof(signed __int8)) |
| 134 | return META_E_CA_INVALID_BLOB; |
| 135 | *pVal = GetI1(); |
| 136 | return S_OK; |
| 137 | } |
| 138 | |
| 139 | HRESULT GetTag(CorSerializationType *pVal) |
| 140 | { |
| 141 | WRAPPER_NO_CONTRACT; |
| 142 | HRESULT hr; |
| 143 | signed __int8 tmp; |
| 144 | IfFailRet(GetI1(&tmp)); |
| 145 | *pVal = (CorSerializationType)((unsigned __int8)tmp); |
| 146 | return hr; |
| 147 | } |
| 148 | |
| 149 | HRESULT GetU1(unsigned __int8 *pVal) |
| 150 | { |
| 151 | WRAPPER_NO_CONTRACT; |
| 152 | |
| 153 | if (BytesLeft() < (int) sizeof(unsigned __int8)) |
| 154 | return META_E_CA_INVALID_BLOB; |
| 155 | *pVal = GetU1(); |
| 156 | return S_OK; |
| 157 | } |
| 158 | |
| 159 | HRESULT GetI2(signed __int16 *pVal) |
| 160 | { |
| 161 | WRAPPER_NO_CONTRACT; |
| 162 | |
| 163 | if (BytesLeft() < (int) sizeof(signed __int16)) |
| 164 | return META_E_CA_INVALID_BLOB; |
| 165 | *pVal = GetI2(); |
| 166 | return S_OK; |
| 167 | } |
| 168 | HRESULT GetU2(unsigned __int16 *pVal) |
| 169 | { |
| 170 | WRAPPER_NO_CONTRACT; |
| 171 | |
| 172 | if (BytesLeft() < (int) sizeof(unsigned __int16)) |
| 173 | return META_E_CA_INVALID_BLOB; |
| 174 | *pVal = GetU2(); |
| 175 | return S_OK; |
| 176 | } |
| 177 | |
| 178 | HRESULT GetI4(signed __int32 *pVal) |
| 179 | { |
| 180 | WRAPPER_NO_CONTRACT; |
| 181 | |
| 182 | if (BytesLeft() < (int) sizeof(signed __int32)) |
| 183 | return META_E_CA_INVALID_BLOB; |
| 184 | *pVal = GetI4(); |
| 185 | return S_OK; |
| 186 | } |
| 187 | HRESULT GetU4(unsigned __int32 *pVal) |
| 188 | { |
| 189 | WRAPPER_NO_CONTRACT; |
| 190 | |
| 191 | if (BytesLeft() < (int) sizeof(unsigned __int32)) |
| 192 | return META_E_CA_INVALID_BLOB; |
| 193 | *pVal = GetU4(); |
| 194 | return S_OK; |
| 195 | } |
| 196 | |
| 197 | HRESULT GetI8(signed __int64 *pVal) |
| 198 | { |
| 199 | WRAPPER_NO_CONTRACT; |
| 200 | |
| 201 | if (BytesLeft() < (int) sizeof(signed __int64)) |
| 202 | return META_E_CA_INVALID_BLOB; |
| 203 | *pVal = GetI8(); |
| 204 | return S_OK; |
| 205 | } |
| 206 | HRESULT GetU8(unsigned __int64 *pVal) |
| 207 | { |
| 208 | WRAPPER_NO_CONTRACT; |
| 209 | |
| 210 | if (BytesLeft() < (int) sizeof(unsigned __int64)) |
| 211 | return META_E_CA_INVALID_BLOB; |
| 212 | *pVal = GetU8(); |
| 213 | return S_OK; |
| 214 | } |
| 215 | |
| 216 | HRESULT GetR4(float *pVal) |
| 217 | { |
| 218 | WRAPPER_NO_CONTRACT; |
| 219 | |
| 220 | if (BytesLeft() < (int) sizeof(float)) |
| 221 | return META_E_CA_INVALID_BLOB; |
| 222 | *pVal = GetR4(); |
| 223 | return S_OK; |
| 224 | } |
| 225 | HRESULT GetR8(double *pVal) |
| 226 | { |
| 227 | WRAPPER_NO_CONTRACT; |
| 228 | |
| 229 | if (BytesLeft() < (int) sizeof(double)) |
| 230 | return META_E_CA_INVALID_BLOB; |
| 231 | *pVal = GetR8(); |
| 232 | return S_OK; |
| 233 | } |
| 234 | |
| 235 | HRESULT GetProlog(unsigned __int16 *pVal) |
| 236 | { |
| 237 | WRAPPER_NO_CONTRACT; |
| 238 | |
| 239 | m_pbCur = m_pbBlob; |
| 240 | |
| 241 | if (BytesLeft() < (int)(sizeof(BYTE) * 2)) |
| 242 | return META_E_CA_INVALID_BLOB; |
| 243 | |
| 244 | return GetU2(pVal); |
| 245 | } |
| 246 | |
| 247 | // Added for compatibility with anyone that may emit |
| 248 | // blobs where the prolog is the only incorrect data. |
| 249 | HRESULT SkipProlog() |
| 250 | { |
| 251 | unsigned __int16 val; |
| 252 | return GetProlog(&val); |
| 253 | } |
| 254 | |
| 255 | HRESULT ValidateProlog() |
| 256 | { |
| 257 | HRESULT hr; |
| 258 | unsigned __int16 val; |
| 259 | IfFailRet(GetProlog(&val)); |
| 260 | |
| 261 | if (val != 0x0001) |
| 262 | return META_E_CA_INVALID_BLOB; |
| 263 | |
| 264 | return hr; |
| 265 | } |
| 266 | |
| 267 | // |
| 268 | // IMPORTANT: the returned string is typically not null-terminated. |
| 269 | // |
| 270 | // This can return any of three distinct valid results: |
| 271 | // - NULL string, indicated by *pszString==NULL, *pcbString==0 |
| 272 | // - empty string, indicated by *pszString!=NULL, *pcbString==0 |
| 273 | // - non-empty string, indicated by *pdzString!=NULL, *pcbString!=0 |
| 274 | // If you expect non-null or non-empty strings in your usage scenario, |
| 275 | // call the GetNonNullString and GetNonEmptyString helpers below. |
| 276 | // |
| 277 | HRESULT GetString(LPCUTF8 *pszString, ULONG *pcbString) |
| 278 | { |
| 279 | STATIC_CONTRACT_NOTHROW; |
| 280 | STATIC_CONTRACT_FORBID_FAULT; |
| 281 | |
| 282 | HRESULT hr; |
| 283 | |
| 284 | if (BytesLeft() == 0) |
| 285 | { // Need to check for NULL string sentinal (see below), |
| 286 | // so need to have at least one byte to read. |
| 287 | IfFailRet(META_E_CA_INVALID_BLOB); |
| 288 | } |
| 289 | |
| 290 | if (*m_pbCur == 0xFF) |
| 291 | { // 0xFF indicates the NULL string, which is semantically |
| 292 | // different than the empty string. |
| 293 | *pszString = NULL; |
| 294 | *pcbString = 0; |
| 295 | m_pbCur++; |
| 296 | return S_OK; |
| 297 | } |
| 298 | |
| 299 | // Get the length, pointer to data following the length. |
| 300 | return GetData((BYTE const **)pszString, pcbString); |
| 301 | } |
| 302 | |
| 303 | // |
| 304 | // This can return any of two distinct valid results: |
| 305 | // - empty string, indicated by *pszString!=NULL, *pcbString==0 |
| 306 | // - non-empty string, indicated by *pszString!=NULL, *pcbString!=0 |
| 307 | // If you expect non-null or non-empty strings in your usage scenario, |
| 308 | // call the GetNonNullString and GetNonEmptyString helpers below. |
| 309 | // |
| 310 | HRESULT GetNonNullString(LPCUTF8 *pszString, ULONG *pcbString) |
| 311 | { |
| 312 | STATIC_CONTRACT_NOTHROW; |
| 313 | STATIC_CONTRACT_FORBID_FAULT; |
| 314 | |
| 315 | HRESULT hr; |
| 316 | |
| 317 | IfFailRet(GetString(pszString, pcbString)); |
| 318 | |
| 319 | if (*pszString == NULL) |
| 320 | { |
| 321 | return META_E_CA_INVALID_BLOB; |
| 322 | } |
| 323 | |
| 324 | return S_OK; |
| 325 | } |
| 326 | |
| 327 | // |
| 328 | // This function will only return success if the string is valid, |
| 329 | // non-NULL and non-empty; i.e., *pszString!=NULL, *pcbString!=0 |
| 330 | // |
| 331 | HRESULT GetNonEmptyString(LPCUTF8 *pszString, ULONG *pcbString) |
| 332 | { |
| 333 | STATIC_CONTRACT_NOTHROW; |
| 334 | STATIC_CONTRACT_FORBID_FAULT; |
| 335 | |
| 336 | HRESULT hr; |
| 337 | |
| 338 | IfFailRet(GetNonNullString(pszString, pcbString)); |
| 339 | |
| 340 | if (*pcbString == 0) |
| 341 | { |
| 342 | return META_E_CA_INVALID_BLOB; |
| 343 | } |
| 344 | |
| 345 | return S_OK; |
| 346 | } |
| 347 | |
| 348 | // IMPORTANT: do not use with string fetching - use GetString instead. |
| 349 | HRESULT GetData(BYTE const **ppbData, ULONG *pcbData) |
| 350 | { |
| 351 | HRESULT hr; |
| 352 | IfFailRet(CPackedLen::SafeGetData(m_pbCur, m_pbBlob + m_cbBlob, pcbData, ppbData)); |
| 353 | // Move past the data we just recovered |
| 354 | m_pbCur = *ppbData + *pcbData; |
| 355 | |
| 356 | return S_OK; |
| 357 | } |
| 358 | |
| 359 | // IMPORTANT: do not use with string fetching - use GetString instead. |
| 360 | HRESULT GetPackedValue(ULONG *pcbData) |
| 361 | { |
| 362 | return CPackedLen::SafeGetLength(m_pbCur, m_pbBlob + m_cbBlob, pcbData, &m_pbCur); |
| 363 | } |
| 364 | |
| 365 | int BytesLeft() |
| 366 | { |
| 367 | LIMITED_METHOD_CONTRACT; |
| 368 | return (int)(m_cbBlob - (m_pbCur - m_pbBlob)); |
| 369 | } |
| 370 | |
| 371 | private: |
| 372 | const BYTE *m_pbCur; |
| 373 | const BYTE *m_pbBlob; |
| 374 | ULONG m_cbBlob; |
| 375 | }; |
| 376 | |
| 377 | #endif // __CAPARSER_H__ |
| 378 | |