blob: 9997f94170da2ff5d7818bf0ffb1bbb7a9249b84 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#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
11namespace vpd
12{
13
14types::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
68types::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
108void 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
126void 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