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
parse()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
populateVpdMap()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
validateChecksum(types::BinaryVector::const_iterator i_checkSumStart,types::BinaryVector::const_iterator i_checkSumEnd)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
checkNextBytesValidity(uint8_t i_numberOfBytes)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
137