| Sunny Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 1 | #include "keyword_vpd_parser.hpp" | 
|  | 2 |  | 
|  | 3 | #include "constants.hpp" | 
|  | 4 | #include "exceptions.hpp" | 
|  | 5 | #include "logger.hpp" | 
|  | 6 |  | 
|  | 7 | #include <iostream> | 
|  | 8 | #include <numeric> | 
|  | 9 | #include <string> | 
|  | 10 |  | 
|  | 11 | namespace vpd | 
|  | 12 | { | 
|  | 13 |  | 
|  | 14 | types::VPDMapVariant KeywordVpdParser::parse() | 
|  | 15 | { | 
|  | 16 | if (m_keywordVpdVector.empty()) | 
|  | 17 | { | 
|  | 18 | throw(DataException("Vector for Keyword format VPD is empty")); | 
|  | 19 | } | 
|  | 20 | m_vpdIterator = m_keywordVpdVector.begin(); | 
|  | 21 |  | 
|  | 22 | if (*m_vpdIterator != constants::KW_VPD_START_TAG) | 
|  | 23 | { | 
|  | 24 | throw(DataException("Invalid Large resource type Identifier String")); | 
|  | 25 | } | 
|  | 26 |  | 
|  | 27 | checkNextBytesValidity(sizeof(constants::KW_VPD_START_TAG)); | 
|  | 28 | std::advance(m_vpdIterator, sizeof(constants::KW_VPD_START_TAG)); | 
|  | 29 |  | 
|  | 30 | uint16_t l_dataSize = getKwDataSize(); | 
|  | 31 |  | 
|  | 32 | checkNextBytesValidity(constants::TWO_BYTES + l_dataSize); | 
|  | 33 | std::advance(m_vpdIterator, constants::TWO_BYTES + l_dataSize); | 
|  | 34 |  | 
|  | 35 | // Check for invalid vendor defined large resource type | 
|  | 36 | if (*m_vpdIterator != constants::KW_VPD_PAIR_START_TAG) | 
|  | 37 | { | 
|  | 38 | if (*m_vpdIterator != constants::ALT_KW_VPD_PAIR_START_TAG) | 
|  | 39 | { | 
|  | 40 | throw(DataException("Invalid Keyword Vpd Start Tag")); | 
|  | 41 | } | 
|  | 42 | } | 
|  | 43 | types::BinaryVector::const_iterator l_checkSumStart = m_vpdIterator; | 
|  | 44 | auto l_kwValMap = populateVpdMap(); | 
|  | 45 |  | 
|  | 46 | // Do these validations before returning parsed data. | 
|  | 47 | // Check for small resource type end tag | 
|  | 48 | if (*m_vpdIterator != constants::KW_VAL_PAIR_END_TAG) | 
|  | 49 | { | 
|  | 50 | throw(DataException("Invalid Small resource type End")); | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | types::BinaryVector::const_iterator l_checkSumEnd = m_vpdIterator; | 
|  | 54 | validateChecksum(l_checkSumStart, l_checkSumEnd); | 
|  | 55 |  | 
|  | 56 | checkNextBytesValidity(constants::TWO_BYTES); | 
|  | 57 | std::advance(m_vpdIterator, constants::TWO_BYTES); | 
|  | 58 |  | 
|  | 59 | // Check VPD end Tag. | 
|  | 60 | if (*m_vpdIterator != constants::KW_VPD_END_TAG) | 
|  | 61 | { | 
|  | 62 | throw(DataException("Invalid Small resource type.")); | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | return l_kwValMap; | 
|  | 66 | } | 
|  | 67 |  | 
|  | 68 | types::KeywordVpdMap KeywordVpdParser::populateVpdMap() | 
|  | 69 | { | 
|  | 70 | checkNextBytesValidity(constants::ONE_BYTE); | 
|  | 71 | std::advance(m_vpdIterator, constants::ONE_BYTE); | 
|  | 72 |  | 
|  | 73 | auto l_totalSize = getKwDataSize(); | 
|  | 74 | if (l_totalSize == 0) | 
|  | 75 | { | 
|  | 76 | throw(DataException("Data size is 0, badly formed keyword VPD")); | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | checkNextBytesValidity(constants::TWO_BYTES); | 
|  | 80 | std::advance(m_vpdIterator, constants::TWO_BYTES); | 
|  | 81 |  | 
|  | 82 | types::KeywordVpdMap l_kwValMap; | 
|  | 83 |  | 
|  | 84 | // Parse the keyword-value and store the pairs in map | 
|  | 85 | while (l_totalSize > 0) | 
|  | 86 | { | 
|  | 87 | checkNextBytesValidity(constants::TWO_BYTES); | 
|  | 88 | std::string l_keywordName(m_vpdIterator, | 
|  | 89 | m_vpdIterator + constants::TWO_BYTES); | 
|  | 90 | std::advance(m_vpdIterator, constants::TWO_BYTES); | 
|  | 91 |  | 
|  | 92 | size_t l_kwSize = *m_vpdIterator; | 
|  | 93 | checkNextBytesValidity(constants::ONE_BYTE + l_kwSize); | 
|  | 94 | m_vpdIterator++; | 
|  | 95 | std::vector<uint8_t> l_valueBytes(m_vpdIterator, | 
|  | 96 | m_vpdIterator + l_kwSize); | 
|  | 97 | std::advance(m_vpdIterator, l_kwSize); | 
|  | 98 |  | 
|  | 99 | l_kwValMap.emplace( | 
|  | 100 | std::make_pair(std::move(l_keywordName), std::move(l_valueBytes))); | 
|  | 101 |  | 
|  | 102 | l_totalSize -= constants::TWO_BYTES + constants::ONE_BYTE + l_kwSize; | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | return l_kwValMap; | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | void KeywordVpdParser::validateChecksum( | 
|  | 109 | types::BinaryVector::const_iterator i_checkSumStart, | 
|  | 110 | types::BinaryVector::const_iterator i_checkSumEnd) | 
|  | 111 | { | 
|  | 112 | uint8_t l_checkSumCalculated = 0; | 
|  | 113 |  | 
|  | 114 | // Checksum calculation | 
|  | 115 | l_checkSumCalculated = | 
|  | 116 | std::accumulate(i_checkSumStart, i_checkSumEnd, l_checkSumCalculated); | 
|  | 117 | l_checkSumCalculated = ~l_checkSumCalculated + 1; | 
|  | 118 | uint8_t l_checksumVpdValue = *(m_vpdIterator + constants::ONE_BYTE); | 
|  | 119 |  | 
|  | 120 | if (l_checkSumCalculated != l_checksumVpdValue) | 
|  | 121 | { | 
|  | 122 | throw(DataException("Invalid Checksum")); | 
|  | 123 | } | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | void KeywordVpdParser::checkNextBytesValidity(uint8_t i_numberOfBytes) | 
|  | 127 | { | 
|  | 128 | if ((std::distance(m_keywordVpdVector.begin(), | 
|  | 129 | m_vpdIterator + i_numberOfBytes)) > | 
|  | 130 | std::distance(m_keywordVpdVector.begin(), m_keywordVpdVector.end())) | 
|  | 131 | { | 
|  | 132 | throw(DataException("Truncated VPD data")); | 
|  | 133 | } | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | } // namespace vpd |