1 /**
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  */
16 #include "json_utils.hpp"
17 
18 #include <stdio.h>
19 
20 #include <cstring>
21 #include <sstream>
22 #include <string>
23 
24 namespace openpower
25 {
26 namespace pels
27 {
28 
29 std::string escapeJSON(const std::string& input)
30 {
31     std::string output;
32     output.reserve(input.length());
33 
34     for (const auto c : input)
35     {
36         switch (c)
37         {
38             case '"':
39                 output += "\\\"";
40                 break;
41             case '/':
42                 output += "\\/";
43                 break;
44             case '\b':
45                 output += "\\b";
46                 break;
47             case '\f':
48                 output += "\\f";
49                 break;
50             case '\n':
51                 output += "\\n";
52                 break;
53             case '\r':
54                 output += "\\r";
55                 break;
56             case '\t':
57                 output += "\\t";
58                 break;
59             case '\\':
60                 output += "\\\\";
61                 break;
62             default:
63                 output += c;
64                 break;
65         }
66     }
67 
68     return output;
69 }
70 char* dumpHex(const void* data, size_t size, size_t indentCount, bool toJson)
71 {
72     const int symbolSize = 100;
73     std::string jsonIndent(indentLevel * indentCount, 0x20);
74     if (toJson)
75     {
76         jsonIndent.append("\"");
77     }
78     char* buffer = (char*)calloc(std::max(70, 10 * (int)size), sizeof(char));
79     char* symbol = (char*)calloc(symbolSize, sizeof(char));
80     char* byteCount = (char*)calloc(11, sizeof(char));
81     char ascii[17];
82     size_t i, j;
83     ascii[16] = '\0';
84     for (i = 0; i < size; ++i)
85     {
86         if (i % 16 == 0)
87         {
88             if (!toJson)
89             {
90                 snprintf(byteCount, 11, "%08X  ", static_cast<uint32_t>(i));
91                 strcat(buffer, byteCount);
92             }
93             strcat(buffer, jsonIndent.c_str());
94         }
95         snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]);
96         strcat(buffer, symbol);
97         memset(symbol, 0, strlen(symbol));
98         if (((unsigned char*)data)[i] >= ' ' &&
99             ((unsigned char*)data)[i] <= '~')
100         {
101             ascii[i % 16] = ((unsigned char*)data)[i];
102         }
103         else
104         {
105             ascii[i % 16] = '.';
106         }
107         if ((i + 1) % 8 == 0 || i + 1 == size)
108         {
109             std::string asciiString(ascii);
110             if (toJson)
111             {
112                 asciiString = escapeJSON(asciiString);
113             }
114             strcat(buffer, " ");
115             if ((i + 1) % 16 == 0)
116             {
117                 if (i + 1 != size && toJson)
118                 {
119                     snprintf(symbol, symbolSize, "|  %s\",\n",
120                              asciiString.c_str());
121                 }
122                 else if (toJson)
123                 {
124                     snprintf(symbol, symbolSize, "|  %s\"\n",
125                              asciiString.c_str());
126                 }
127                 else
128                 {
129                     snprintf(symbol, symbolSize, "|  %s\n",
130                              asciiString.c_str());
131                 }
132                 strcat(buffer, symbol);
133                 memset(symbol, 0, strlen(symbol));
134             }
135             else if (i + 1 == size)
136             {
137                 ascii[(i + 1) % 16] = '\0';
138                 if ((i + 1) % 16 <= 8)
139                 {
140                     strcat(buffer, " ");
141                 }
142                 for (j = (i + 1) % 16; j < 16; ++j)
143                 {
144                     strcat(buffer, "   ");
145                 }
146                 std::string asciiString2(ascii);
147                 if (toJson)
148                 {
149                     asciiString2 = escapeJSON(asciiString2);
150                     snprintf(symbol, symbolSize, "|  %s\"\n",
151                              asciiString2.c_str());
152                 }
153                 else
154                 {
155                     snprintf(symbol, symbolSize, "|  %s\n",
156                              asciiString2.c_str());
157                 }
158 
159                 strcat(buffer, symbol);
160                 memset(symbol, 0, strlen(symbol));
161             }
162         }
163     }
164     free(byteCount);
165     free(symbol);
166     return buffer;
167 }
168 
169 void jsonInsert(std::string& jsonStr, const std::string& fieldName,
170                 const std::string& fieldValue, uint8_t indentCount)
171 {
172     const int8_t spacesToAppend = colAlign - (indentCount * indentLevel) -
173                                   fieldName.length() - 3;
174     const std::string jsonIndent(indentCount * indentLevel, 0x20);
175     jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
176     if (spacesToAppend >= 0)
177     {
178         jsonStr.append(spacesToAppend, 0x20);
179     }
180     else
181     {
182         jsonStr.append(1, 0x20);
183     }
184     jsonStr.append("\"" + fieldValue + "\",\n");
185 }
186 
187 void jsonInsertArray(std::string& jsonStr, const std::string& fieldName,
188                      const std::vector<std::string>& values,
189                      uint8_t indentCount)
190 {
191     const std::string jsonIndent(indentCount * indentLevel, 0x20);
192     if (!values.empty())
193     {
194         jsonStr.append(jsonIndent + "\"" + fieldName + "\": [\n");
195         for (size_t i = 0; i < values.size(); i++)
196         {
197             jsonStr.append(colAlign, 0x20);
198             if (i == values.size() - 1)
199             {
200                 jsonStr.append("\"" + values[i] + "\"\n");
201             }
202             else
203             {
204                 jsonStr.append("\"" + values[i] + "\",\n");
205             }
206         }
207         jsonStr.append(jsonIndent + "],\n");
208     }
209     else
210     {
211         const int8_t spacesToAppend = colAlign - (indentCount * indentLevel) -
212                                       fieldName.length() - 3;
213         jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
214         if (spacesToAppend > 0)
215         {
216             jsonStr.append(spacesToAppend, 0x20);
217         }
218         else
219         {
220             jsonStr.append(1, 0x20);
221         }
222         jsonStr.append("[],\n");
223     }
224 }
225 
226 std::string trimEnd(std::string s)
227 {
228     const char* t = " \t\n\r\f\v";
229     if (s.find_last_not_of(t) != std::string::npos)
230     {
231         s.erase(s.find_last_not_of(t) + 1);
232     }
233     return s;
234 }
235 } // namespace pels
236 } // namespace openpower
237