text: /**
   * Copyright © 2019 IBM Corporation
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  #include "json_utils.hpp"
  
  #include <stdio.h>
  
  #include <cstring>
  #include <sstream>
  #include <string>
  
  namespace openpower
  {
  namespace pels
  {
  
  std::string escapeJSON(const std::string& input)
  {
      std::string output;
      output.reserve(input.length());
  
      for (const auto c : input)
      {
          switch (c)
          {
              case '"':
                  output += "\\\"";
                  break;
              case '/':
                  output += "\\/";
                  break;
              case '\b':
                  output += "\\b";
                  break;
              case '\f':
                  output += "\\f";
                  break;
              case '\n':
                  output += "\\n";
                  break;
              case '\r':
                  output += "\\r";
                  break;
              case '\t':
                  output += "\\t";
                  break;
              case '\\':
                  output += "\\\\";
                  break;
              default:
                  output += c;
                  break;
          }
      }
  
      return output;
  }
  char* dumpHex(const void* data, size_t size, size_t indentCount)
  {
      const int symbolSize = 100;
      std::string jsonIndent(indentLevel * indentCount, 0x20);
      jsonIndent.append("\"");
      char* buffer = (char*)calloc(std::max(70, 10 * (int)size), sizeof(char));
      char* symbol = (char*)calloc(symbolSize, sizeof(char));
      char ascii[17];
      size_t i, j;
      ascii[16] = '\0';
      for (i = 0; i < size; ++i)
      {
          if (i % 16 == 0)
          {
              strcat(buffer, jsonIndent.c_str());
          }
          snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]);
          strcat(buffer, symbol);
          memset(symbol, 0, strlen(symbol));
          if (((unsigned char*)data)[i] >= ' ' &&
              ((unsigned char*)data)[i] <= '~')
          {
              ascii[i % 16] = ((unsigned char*)data)[i];
          }
          else
          {
              ascii[i % 16] = '.';
          }
          if ((i + 1) % 8 == 0 || i + 1 == size)
          {
              std::string asciiString(ascii);
              asciiString = escapeJSON(asciiString);
              const char* asciiToPrint = asciiString.c_str();
              strcat(buffer, " ");
              if ((i + 1) % 16 == 0)
              {
                  if (i + 1 != size)
                  {
                      snprintf(symbol, symbolSize, "|  %s\",\n", asciiToPrint);
                  }
                  else
                  {
                      snprintf(symbol, symbolSize, "|  %s\"\n", asciiToPrint);
                  }
                  strcat(buffer, symbol);
                  memset(symbol, 0, strlen(symbol));
              }
              else if (i + 1 == size)
              {
                  ascii[(i + 1) % 16] = '\0';
                  if ((i + 1) % 16 <= 8)
                  {
                      strcat(buffer, " ");
                  }
                  for (j = (i + 1) % 16; j < 16; ++j)
                  {
                      strcat(buffer, "   ");
                  }
                  std::string asciiString2(ascii);
                  asciiString2 = escapeJSON(asciiString2);
                  asciiToPrint = asciiString2.c_str();
                  snprintf(symbol, symbolSize, "|  %s\"\n", asciiToPrint);
                  strcat(buffer, symbol);
                  memset(symbol, 0, strlen(symbol));
              }
          }
      }
      free(symbol);
      return buffer;
  }
  
  void jsonInsert(std::string& jsonStr, const std::string& fieldName,
                  std::string fieldValue, uint8_t indentCount)
  {
      const int8_t spacesToAppend =
          colAlign - (indentCount * indentLevel) - fieldName.length() - 3;
      const std::string jsonIndent(indentCount * indentLevel, 0x20);
      jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
      if (spacesToAppend >= 0)
      {
          jsonStr.append(spacesToAppend, 0x20);
      }
      else
      {
          jsonStr.append(1, 0x20);
      }
      jsonStr.append("\"" + fieldValue + "\",\n");
  }
  
  void jsonInsertArray(std::string& jsonStr, const std::string& fieldName,
                       std::vector<std::string>& values, uint8_t indentCount)
  {
      const std::string jsonIndent(indentCount * indentLevel, 0x20);
      if (!values.empty())
      {
          jsonStr.append(jsonIndent + "\"" + fieldName + "\": [\n");
          for (size_t i = 0; i < values.size(); i++)
          {
              jsonStr.append(colAlign, 0x20);
              if (i == values.size() - 1)
              {
                  jsonStr.append("\"" + values[i] + "\"\n");
              }
              else
              {
                  jsonStr.append("\"" + values[i] + "\",\n");
              }
          }
          jsonStr.append(jsonIndent + "],\n");
      }
      else
      {
          const int8_t spacesToAppend =
              colAlign - (indentCount * indentLevel) - fieldName.length() - 3;
          jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
          if (spacesToAppend > 0)
          {
              jsonStr.append(spacesToAppend, 0x20);
          }
          else
          {
              jsonStr.append(1, 0x20);
          }
          jsonStr.append("[],\n");
      }
  }
  
  std::string trimEnd(std::string s)
  {
      const char* t = " \t\n\r\f\v";
      if (s.find_last_not_of(t) != std::string::npos)
      {
          s.erase(s.find_last_not_of(t) + 1);
      }
      return s;
  }
  } // namespace pels
  } // namespace openpower
  