blob: 13094ed6cf8a7feea248d3546ac409a969296930 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080016#include "json_utils.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050017
Matt Spinlerb832aa52023-03-21 15:32:34 -050018#include "paths.hpp"
19
Aatir186ce8c2019-10-20 15:13:39 -050020#include <stdio.h>
21
Matt Spinlerb832aa52023-03-21 15:32:34 -050022#include <nlohmann/json.hpp>
23
Aatir186ce8c2019-10-20 15:13:39 -050024#include <cstring>
Matt Spinlerb832aa52023-03-21 15:32:34 -050025#include <filesystem>
26#include <optional>
Aatir186ce8c2019-10-20 15:13:39 -050027#include <sstream>
28#include <string>
29
30namespace openpower
31{
32namespace pels
33{
34
35std::string escapeJSON(const std::string& input)
36{
37 std::string output;
38 output.reserve(input.length());
39
40 for (const auto c : input)
41 {
42 switch (c)
43 {
44 case '"':
45 output += "\\\"";
46 break;
47 case '/':
48 output += "\\/";
49 break;
50 case '\b':
51 output += "\\b";
52 break;
53 case '\f':
54 output += "\\f";
55 break;
56 case '\n':
57 output += "\\n";
58 break;
59 case '\r':
60 output += "\\r";
61 break;
62 case '\t':
63 output += "\\t";
64 break;
65 case '\\':
66 output += "\\\\";
67 break;
68 default:
69 output += c;
70 break;
71 }
72 }
73
74 return output;
75}
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080076char* dumpHex(const void* data, size_t size, size_t indentCount, bool toJson)
Aatir186ce8c2019-10-20 15:13:39 -050077{
78 const int symbolSize = 100;
Matt Spinler4220a152020-03-26 10:18:09 -050079 std::string jsonIndent(indentLevel * indentCount, 0x20);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080080 if (toJson)
81 {
82 jsonIndent.append("\"");
83 }
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +080084 char* buffer = (char*)calloc(std::max(70, 10 * (int)size), sizeof(char));
Aatir186ce8c2019-10-20 15:13:39 -050085 char* symbol = (char*)calloc(symbolSize, sizeof(char));
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080086 char* byteCount = (char*)calloc(11, sizeof(char));
Aatir186ce8c2019-10-20 15:13:39 -050087 char ascii[17];
88 size_t i, j;
89 ascii[16] = '\0';
90 for (i = 0; i < size; ++i)
91 {
92 if (i % 16 == 0)
93 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080094 if (!toJson)
95 {
96 snprintf(byteCount, 11, "%08X ", static_cast<uint32_t>(i));
97 strcat(buffer, byteCount);
98 }
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080099 strcat(buffer, jsonIndent.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500100 }
101 snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]);
102 strcat(buffer, symbol);
103 memset(symbol, 0, strlen(symbol));
104 if (((unsigned char*)data)[i] >= ' ' &&
105 ((unsigned char*)data)[i] <= '~')
106 {
107 ascii[i % 16] = ((unsigned char*)data)[i];
108 }
109 else
110 {
111 ascii[i % 16] = '.';
112 }
113 if ((i + 1) % 8 == 0 || i + 1 == size)
114 {
115 std::string asciiString(ascii);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800116 if (toJson)
117 {
118 asciiString = escapeJSON(asciiString);
119 }
Aatir186ce8c2019-10-20 15:13:39 -0500120 strcat(buffer, " ");
121 if ((i + 1) % 16 == 0)
122 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800123 if (i + 1 != size && toJson)
Aatir186ce8c2019-10-20 15:13:39 -0500124 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800125 snprintf(symbol, symbolSize, "| %s\",\n",
126 asciiString.c_str());
127 }
128 else if (toJson)
129 {
130 snprintf(symbol, symbolSize, "| %s\"\n",
131 asciiString.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500132 }
133 else
134 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800135 snprintf(symbol, symbolSize, "| %s\n",
136 asciiString.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500137 }
138 strcat(buffer, symbol);
139 memset(symbol, 0, strlen(symbol));
140 }
141 else if (i + 1 == size)
142 {
143 ascii[(i + 1) % 16] = '\0';
144 if ((i + 1) % 16 <= 8)
145 {
146 strcat(buffer, " ");
147 }
148 for (j = (i + 1) % 16; j < 16; ++j)
149 {
150 strcat(buffer, " ");
151 }
Aatir6a538622019-11-11 13:13:42 -0600152 std::string asciiString2(ascii);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800153 if (toJson)
154 {
155 asciiString2 = escapeJSON(asciiString2);
156 snprintf(symbol, symbolSize, "| %s\"\n",
157 asciiString2.c_str());
158 }
159 else
160 {
161 snprintf(symbol, symbolSize, "| %s\n",
162 asciiString2.c_str());
163 }
164
Aatir186ce8c2019-10-20 15:13:39 -0500165 strcat(buffer, symbol);
166 memset(symbol, 0, strlen(symbol));
167 }
168 }
169 }
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800170 free(byteCount);
Aatir186ce8c2019-10-20 15:13:39 -0500171 free(symbol);
172 return buffer;
173}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800174
175void jsonInsert(std::string& jsonStr, const std::string& fieldName,
Matt Spinler45796e82022-07-01 11:25:27 -0500176 const std::string& fieldValue, uint8_t indentCount)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800177{
Patrick Williams2544b412022-10-04 08:41:06 -0500178 const int8_t spacesToAppend = colAlign - (indentCount * indentLevel) -
179 fieldName.length() - 3;
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800180 const std::string jsonIndent(indentCount * indentLevel, 0x20);
181 jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
Harisuddin Mohamed Isac32e5512020-02-06 18:05:21 +0800182 if (spacesToAppend >= 0)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800183 {
184 jsonStr.append(spacesToAppend, 0x20);
185 }
186 else
187 {
188 jsonStr.append(1, 0x20);
189 }
190 jsonStr.append("\"" + fieldValue + "\",\n");
191}
192
193void jsonInsertArray(std::string& jsonStr, const std::string& fieldName,
Matt Spinler45796e82022-07-01 11:25:27 -0500194 const std::vector<std::string>& values,
195 uint8_t indentCount)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800196{
197 const std::string jsonIndent(indentCount * indentLevel, 0x20);
198 if (!values.empty())
199 {
200 jsonStr.append(jsonIndent + "\"" + fieldName + "\": [\n");
201 for (size_t i = 0; i < values.size(); i++)
202 {
203 jsonStr.append(colAlign, 0x20);
204 if (i == values.size() - 1)
205 {
206 jsonStr.append("\"" + values[i] + "\"\n");
207 }
208 else
209 {
210 jsonStr.append("\"" + values[i] + "\",\n");
211 }
212 }
213 jsonStr.append(jsonIndent + "],\n");
214 }
215 else
216 {
Patrick Williams2544b412022-10-04 08:41:06 -0500217 const int8_t spacesToAppend = colAlign - (indentCount * indentLevel) -
218 fieldName.length() - 3;
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800219 jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
220 if (spacesToAppend > 0)
221 {
222 jsonStr.append(spacesToAppend, 0x20);
223 }
224 else
225 {
226 jsonStr.append(1, 0x20);
227 }
228 jsonStr.append("[],\n");
229 }
230}
Harisuddin Mohamed Isae2d1bf32020-02-06 17:32:38 +0800231
232std::string trimEnd(std::string s)
233{
234 const char* t = " \t\n\r\f\v";
235 if (s.find_last_not_of(t) != std::string::npos)
236 {
237 s.erase(s.find_last_not_of(t) + 1);
238 }
239 return s;
240}
Matt Spinlerb832aa52023-03-21 15:32:34 -0500241
242/**
243 * @brief Lookup the component ID in a JSON file named
244 * after the creator ID.
245 *
246 * Keeps a cache of the JSON it reads to live throughout
247 * the peltool call as the JSON can be reused across
248 * PEL sections or even across PELs.
249 *
250 * @param[in] compID - The component ID
251 * @param[in] creatorID - The creator ID for the PEL
252 * @return optional<string> - The comp name, or std::nullopt
253 */
254static std::optional<std::string> lookupComponentName(uint16_t compID,
255 char creatorID)
256{
257 static std::map<char, nlohmann::json> jsonCache;
258 nlohmann::json jsonData;
259 nlohmann::json* jsonPtr = &jsonData;
260 std::filesystem::path filename{std::string{creatorID} +
261 "_component_ids.json"};
262 filename = getPELReadOnlyDataPath() / filename;
263
264 auto jsonIt = jsonCache.find(creatorID);
265 if (jsonIt != jsonCache.end())
266 {
267 jsonPtr = &(jsonIt->second);
268 }
269 else
270 {
271 std::error_code ec;
272 if (!std::filesystem::exists(filename, ec))
273 {
274 return std::nullopt;
275 }
276
277 std::ifstream file{filename};
278 if (!file)
279 {
280 return std::nullopt;
281 }
282
283 jsonData = nlohmann::json::parse(file, nullptr, false);
284 if (jsonData.is_discarded())
285 {
286 return std::nullopt;
287 }
288
289 jsonCache.emplace(creatorID, jsonData);
290 }
291
292 auto id = getNumberString("%04X", compID);
293
294 auto it = jsonPtr->find(id);
295 if (it == jsonPtr->end())
296 {
297 return std::nullopt;
298 }
299
300 return it->get<std::string>();
301}
302
303/**
304 * @brief Convert the component ID to a 2 character string
305 * if both bytes are nonzero
306 *
307 * e.g. 0x4552 -> "ER"
308 *
309 * @param[in] compID - The component ID
310 * @return optional<string> - The two character string, or std::nullopt.
311 */
312static std::optional<std::string> convertCompIDToChars(uint16_t compID)
313{
314 uint8_t first = (compID >> 8) & 0xFF;
315 uint8_t second = compID & 0xFF;
316 if ((first != 0) && (second != 0))
317 {
318 std::string id{static_cast<char>(first)};
319 id += static_cast<char>(second);
320 return id;
321 }
322
323 return std::nullopt;
324}
325
326std::string getComponentName(uint16_t compID, uint8_t creatorID)
327{
328 // See if there's a JSON file with the names
329 auto name = lookupComponentName(compID, creatorID);
330
331 // If PHYP, convert to ASCII
332 if (!name && ('H' == creatorID))
333 {
334 name = convertCompIDToChars(compID);
335 }
336
337 if (!name)
338 {
339 name = getNumberString("0x%04X", compID);
340 }
341
342 return *name;
343}
344
Aatir186ce8c2019-10-20 15:13:39 -0500345} // namespace pels
346} // namespace openpower