Coverage for /Syzygy/crashdata/json.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.8%2712920.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/crashdata/json.h"
  16    :  
  17    :  // We use standard dependencies only, as we don't want to introduce a
  18    :  // dependency on base into the backend crash processing code.
  19    :  #include <assert.h>
  20    :  #include <iomanip>
  21    :  #include <iostream>
  22    :  #include <sstream>
  23    :  
  24    :  namespace crashdata {
  25    :  
  26    :  namespace {
  27    :  
  28    :  const size_t kIndentSize = 2;
  29    :  
  30  E :  void IncreaseIndent(std::string* indent) {
  31  E :    if (!indent)
  32  E :      return;
  33  E :    indent->append(kIndentSize, ' ');
  34  E :  }
  35    :  
  36  E :  void DecreaseIndent(std::string* indent) {
  37  E :    if (!indent)
  38  i :      return;
  39  E :    indent->resize(indent->size() - kIndentSize);
  40  E :  }
  41    :  
  42  E :  void EmitIndent(std::string* indent, std::string* output) {
  43  E :    assert(output != nullptr);
  44  E :    if (!indent)
  45  E :      return;
  46  E :    output->append(*indent);
  47  E :  }
  48    :  
  49  E :  void EmitHexValue8(unsigned char value, std::string* output) {
  50  E :    assert(output != nullptr);
  51  E :    output->push_back('"');
  52  E :    std::ostringstream oss;
  53    :    oss << "0x" << std::hex << std::setfill('0') << std::setw(2)
  54  E :        << std::uppercase << static_cast<unsigned int>(value);
  55  E :    output->append(oss.str());
  56  E :    output->push_back('"');
  57  E :  }
  58    :  
  59  E :  void EmitHexValue32(google::protobuf::uint64 value, std::string* output) {
  60  E :    assert(output != nullptr);
  61  E :    output->push_back('"');
  62  E :    std::ostringstream oss;
  63    :    oss << "0x" << std::hex << std::setfill('0') << std::setw(8)
  64  E :        << std::uppercase << value;
  65  E :    output->append(oss.str());
  66  E :    output->push_back('"');
  67  E :  }
  68    :  
  69    :  template <typename IntType>
  70  E :  void EmitDecValue(IntType value, std::string* output) {
  71  E :    assert(output != nullptr);
  72  E :    std::ostringstream oss;
  73  E :    oss << std::dec << std::setw(0) << value;
  74  E :    output->append(oss.str());
  75  E :  }
  76    :  
  77  E :  void EmitDouble(double value, std::string* output) {
  78  E :    assert(output != nullptr);
  79  E :    std::ostringstream oss;
  80  E :    oss << std::scientific << std::setprecision(16) << std::uppercase << value;
  81  E :    output->append(oss.str());
  82  E :  }
  83    :  
  84  E :  void EmitNull(std::string* output) {
  85  E :    assert(output != nullptr);
  86  E :    output->append("null");
  87  E :  }
  88    :  
  89  E :  void EmitString(const std::string& s, std::string* output) {
  90  E :    assert(output != nullptr);
  91  E :    output->reserve(output->size() + 2 + s.size());
  92  E :    output->push_back('"');
  93  E :    for (size_t i = 0; i < s.size(); ++i) {
  94  E :      if (s[i] == '"') {
  95  E :        output->append("\\\"");
  96  E :      } else if (s[i] == '\\') {
  97  E :        output->append("\\\\");
  98  E :      } else {
  99  E :        output->push_back(s[i]);
 100    :      }
 101  E :    }
 102  E :    output->push_back('"');
 103  E :  }
 104    :  
 105    :  // A helper for emitting a list like object. Calls the provided yield functor
 106    :  // for each element.
 107    :  template <typename YieldFunctor>
 108    :  bool EmitJsonList(char open_bracket,
 109    :                    char close_bracket,
 110    :                    size_t items_per_line,
 111    :                    size_t item_count,
 112    :                    YieldFunctor& yield,
 113    :                    std::string* indent,
 114  E :                    std::string* output) {
 115  E :    assert(items_per_line > 0);
 116  E :    assert(output != nullptr);
 117    :  
 118    :    // Open up the list, and indent if necessary.
 119  E :    output->push_back(open_bracket);
 120  E :    IncreaseIndent(indent);
 121  E :    EmitIndent(indent, output);
 122    :  
 123    :    // Emit the stack frames.
 124  E :    for (size_t i = 0; i < item_count; ++i) {
 125  E :      if (!yield(i, indent, output))
 126  E :        return false;
 127    :  
 128    :      // Emit a trailing comma for all entries but the last. For
 129    :      // the last entry reduce the indent amount to match the opening
 130    :      // bracket.
 131  E :      if (i + 1 < item_count) {
 132  E :        output->push_back(',');
 133  E :      } else if (indent) {
 134  E :        DecreaseIndent(indent);
 135    :      }
 136    :  
 137    :      // If at the last element in a line, or the last element in the list then
 138    :      // emit a line ending and indent.
 139  E :      if ((i + 1) % items_per_line == 0 || i + 1 == item_count) {
 140    :        // Output the appropriate indent for the next line or the
 141    :        // closing bracket.
 142  E :        EmitIndent(indent, output);
 143  E :      } else if (indent != nullptr) {
 144    :        // Emit a single space for the next element if we're emitting whitespace.
 145  E :        output->push_back(' ');
 146    :      }
 147  E :    }
 148    :  
 149    :    // Close the list.
 150  E :    output->push_back(close_bracket);
 151  E :    return true;
 152  E :  }
 153    :  
 154    :  // Emits a dictionary key, but not the value. Does not increase the indent
 155    :  // for the value.
 156    :  void EmitDictKey(const std::string& key,
 157    :                   std::string* indent,
 158  E :                   std::string* output) {
 159  E :    assert(output != nullptr);
 160  E :    EmitString(key, output);
 161  E :    output->push_back(':');
 162  E :    if (indent)
 163  E :      output->push_back(' ');
 164  E :  }
 165    :  
 166    :  // Forward declaration of this, as it's the common container type for other
 167    :  // values.
 168    :  bool ToJson(const Value* value, std::string* indent, std::string* output);
 169    :  
 170  E :  bool ToJson(const Address* address, std::string* indent, std::string* output) {
 171  E :    assert(address != nullptr);
 172  E :    assert(output != nullptr);
 173  E :    EmitHexValue32(address->address(), output);
 174  E :    return true;
 175  E :  }
 176    :  
 177    :  struct StackTraceYieldFunctor {
 178  E :    explicit StackTraceYieldFunctor(const StackTrace* stack_trace)
 179  E :        : stack_trace_(stack_trace) {
 180  E :      assert(stack_trace != nullptr);
 181  E :    }
 182    :  
 183  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 184  E :      assert(output != nullptr);
 185  E :      assert(index <= std::numeric_limits<int>::max());
 186  E :      EmitHexValue32(stack_trace_->frames().Get(static_cast<int>(index)), output);
 187  E :      return true;
 188  E :    }
 189    :  
 190    :    const StackTrace* stack_trace_;
 191    :  };
 192    :  
 193    :  bool ToJson(const StackTrace* stack_trace,
 194    :              std::string* indent,
 195  E :              std::string* output) {
 196  E :    assert(stack_trace != nullptr);
 197  E :    assert(output != nullptr);
 198  E :    StackTraceYieldFunctor yield(stack_trace);
 199  E :    if (!EmitJsonList('[', ']', 4, stack_trace->frames_size(), yield,
 200    :                      indent, output)) {
 201  i :      return false;
 202    :    }
 203  E :    return true;
 204  E :  }
 205    :  
 206    :  // A functor for emitting the binary data in a blob as an array.
 207    :  struct BlobDataYieldFunctor {
 208  E :    explicit BlobDataYieldFunctor(const Blob* blob)
 209  E :        : blob_(blob) {
 210  E :      assert(blob != nullptr);
 211  E :    }
 212    :  
 213  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 214  E :      EmitHexValue8(static_cast<unsigned char>(blob_->data()[index]), output);
 215  E :      return true;
 216  E :    }
 217    :  
 218    :    const Blob* blob_;
 219    :  };
 220    :  
 221    :  // A functor for emitting the contents of a blob as a dictionary.
 222    :  struct BlobYieldFunctor {
 223  E :    explicit BlobYieldFunctor(const Blob* blob)
 224  E :        : blob_(blob), need_comma_(false) {
 225  E :      assert(blob != nullptr);
 226  E :    }
 227    :  
 228  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 229  E :      assert(output != nullptr);
 230  E :      switch (index) {
 231    :        case 0: {
 232    :          // Emit a blob descriptor.
 233  E :          EmitDictKey("type", indent, output);
 234  E :          EmitString("blob", output);
 235  E :          return true;
 236    :        }
 237    :        case 1: {
 238  E :          EmitDictKey("address", indent, output);
 239  E :          if (blob_->has_address()) {
 240  E :            if (!ToJson(&blob_->address(), indent, output))
 241  i :              return false;
 242  E :          } else {
 243  E :            EmitNull(output);
 244    :          }
 245  E :          return true;
 246    :        }
 247    :        case 2: {
 248  E :          EmitDictKey("size", indent, output);
 249  E :          if (blob_->has_size()) {
 250  E :            EmitDecValue(blob_->size(), output);
 251  E :          } else {
 252  E :            EmitNull(output);
 253    :          }
 254  E :          return true;
 255    :        }
 256    :        case 3: {
 257  E :          EmitDictKey("data", indent, output);
 258  E :          if (blob_->has_data()) {
 259  E :            BlobDataYieldFunctor yield(blob_);
 260  E :            if (!EmitJsonList('[', ']', 8, blob_->data().size(), yield,
 261    :                              indent, output)) {
 262  i :              return false;
 263    :            }
 264  E :          } else {
 265  E :            EmitNull(output);
 266    :          }
 267  E :          return true;
 268    :        }
 269    :        default: break;
 270    :      }
 271    :  
 272    :      // This should never happen!
 273  i :      assert(false);
 274  i :      return false;
 275  E :    }
 276    :  
 277    :    const Blob* blob_;
 278    :    bool need_comma_;
 279    :  };
 280    :  
 281  E :  bool ToJson(const Blob* blob, std::string* indent, std::string* output) {
 282  E :    assert(blob != nullptr);
 283  E :    assert(output != nullptr);
 284  E :    BlobYieldFunctor yield(blob);
 285    :    // 1 element per line, 4 elements total.
 286  E :    if (!EmitJsonList('{', '}', 1, 4, yield, indent, output))
 287  i :      return false;
 288  E :    return true;
 289  E :  }
 290    :  
 291  E :  bool ToJson(const Leaf* leaf, std::string* indent, std::string* output) {
 292  E :    assert(leaf != nullptr);
 293  E :    assert(output != nullptr);
 294    :  
 295  E :    if (!leaf->has_type())
 296  i :      return false;
 297    :  
 298  E :    switch (leaf->type()) {
 299    :      default:
 300    :      case Leaf_Type_UNKNOWN_TYPE: {
 301  E :        return false;
 302    :      }
 303    :  
 304    :      case Leaf_Type_INTEGER: {
 305  E :        if (!leaf->has_integer())
 306  E :          return false;
 307  E :        EmitDecValue(leaf->integer(), output);
 308  E :        return true;
 309    :      }
 310    :  
 311    :      case Leaf_Type_UNSIGNED_INTEGER: {
 312  E :        if (!leaf->has_unsigned_integer())
 313  E :          return false;
 314  E :        EmitDecValue(leaf->unsigned_integer(), output);
 315  E :        return true;
 316    :      }
 317    :  
 318    :      case Leaf_Type_REAL: {
 319  E :        if (!leaf->has_real())
 320  E :          return false;
 321  E :        EmitDouble(leaf->real(), output);
 322  E :        return true;
 323    :      }
 324    :  
 325    :      case Leaf_Type_STRING: {
 326  E :        if (!leaf->has_string())
 327  E :          return false;
 328  E :        EmitString(leaf->string(), output);
 329  E :        return true;
 330    :      }
 331    :  
 332    :      case Leaf_Type_ADDRESS: {
 333  E :        if (!leaf->has_address())
 334  E :          return false;
 335  E :        if (!ToJson(&leaf->address(), indent, output))
 336  i :          return false;
 337  E :        return true;
 338    :      }
 339    :  
 340    :      case Leaf_Type_STACK_TRACE: {
 341  E :        if (!leaf->has_stack_trace())
 342  E :          return false;
 343  E :        if (!ToJson(&leaf->stack_trace(), indent, output))
 344  i :          return false;
 345  E :        return true;
 346    :      }
 347    :  
 348    :      case Leaf_Type_BLOB: {
 349  E :        if (!leaf->has_blob())
 350  E :          return false;
 351  E :        if (!ToJson(&leaf->blob(), indent, output))
 352  i :          return false;
 353  E :        return true;
 354    :      }
 355    :    }
 356    :  
 357  i :    assert(false);
 358  i :    return false;
 359  E :  }
 360    :  
 361    :  struct ValueListYieldFunctor {
 362  E :    explicit ValueListYieldFunctor(const ValueList* list) : list_(list) {}
 363    :  
 364  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 365  E :      assert(output != nullptr);
 366  E :      assert(index <= std::numeric_limits<int>::max());
 367  E :      if (!ToJson(&list_->values().Get(static_cast<int>(index)), indent, output))
 368  i :        return false;
 369  E :      return true;
 370  E :    }
 371    :  
 372    :    const ValueList* list_;
 373    :  };
 374    :  
 375  E :  bool ToJson(const ValueList* list, std::string* indent, std::string* output) {
 376  E :    assert(list != nullptr);
 377  E :    assert(output != nullptr);
 378  E :    ValueListYieldFunctor yield(list);
 379  E :    if (!EmitJsonList('[', ']', 1, list->values_size(), yield, indent, output))
 380  i :      return false;
 381  E :    return true;
 382  E :  }
 383    :  
 384    :  bool ToJson(
 385  E :      const KeyValue* key_value, std::string* indent, std::string* output) {
 386  E :    assert(key_value != nullptr);
 387  E :    assert(output != nullptr);
 388  E :    if (!key_value->has_key())
 389  E :      return false;
 390  E :    if (!key_value->has_value())
 391  E :      return false;
 392  E :    EmitDictKey(key_value->key(), indent, output);
 393  E :    if (!ToJson(&key_value->value(), indent, output))
 394  i :      return false;
 395  E :    return true;
 396  E :  }
 397    :  
 398    :  struct DictYieldFunctor {
 399  E :    explicit DictYieldFunctor(const Dictionary* dict) : dict_(dict) {
 400  E :    }
 401    :  
 402    :    bool operator()(size_t index,
 403    :                    std::string* indent,
 404  E :                    std::string* output) {
 405  E :      assert(output != nullptr);
 406  E :      assert(index <= std::numeric_limits<int>::max());
 407  E :      if (!ToJson(&dict_->values().Get(static_cast<int>(index)), indent, output))
 408  E :        return false;
 409  E :      return true;
 410  E :    }
 411    :  
 412    :    const Dictionary* dict_;
 413    :  };
 414    :  
 415  E :  bool ToJson(const Dictionary* dict, std::string* indent, std::string* output) {
 416  E :    assert(dict != nullptr);
 417  E :    assert(output != nullptr);
 418  E :    DictYieldFunctor yield(dict);
 419  E :    if (!EmitJsonList('{', '}', 1, dict->values_size(), yield, indent, output))
 420  E :      return false;
 421  E :    return true;
 422  E :  }
 423    :  
 424  E :  bool ToJson(const Value* value, std::string* indent, std::string* output) {
 425  E :    assert(value != nullptr);
 426  E :    assert(output != nullptr);
 427  E :    if (!value->has_type())
 428  i :      return false;
 429  E :    switch (value->type()) {
 430    :      default:
 431    :      case Value_Type_UNKNOWN_TYPE: {
 432  E :        return false;
 433    :      }
 434    :  
 435    :      case Value_Type_LEAF: {
 436  E :        if (!value->has_leaf())
 437  E :          return false;
 438  E :        if (!ToJson(&value->leaf(), indent, output))
 439  E :          return false;
 440  E :        return true;
 441    :      }
 442    :  
 443    :      case Value_Type_VALUE_LIST: {
 444  E :        if (!value->has_list())
 445  E :          return false;
 446  E :        if (!ToJson(&value->list(), indent, output))
 447  i :          return false;
 448  E :        return true;
 449    :      }
 450    :  
 451    :      case Value_Type_DICTIONARY: {
 452  E :        if (!value->has_dictionary())
 453  E :          return false;
 454  E :        if (!ToJson(&value->dictionary(), indent, output))
 455  E :          return false;
 456  E :        return true;
 457    :      }
 458    :    }
 459    :  
 460  i :    assert(false);
 461  i :    return false;
 462  E :  }
 463    :  
 464    :  }  // namespace
 465    :  
 466  E :  bool ToJson(bool pretty_print, const Value* value, std::string* output) {
 467  E :    assert(value != nullptr);
 468  E :    assert(output != nullptr);
 469  E :    std::string* indent = nullptr;
 470  E :    std::string indent_content;
 471  E :    if (pretty_print) {
 472  E :      indent_content = "\n";
 473  E :      indent = &indent_content;
 474    :    }
 475    :  
 476    :    // Produce the output to a temp variable, as partial output may be produced
 477    :    // in case of error.
 478  E :    std::string temp;
 479  E :    if (!ToJson(value, indent, &temp))
 480  E :      return false;
 481    :  
 482    :    // Place the output in the desired string as efficiently as possible.
 483  E :    if (output->empty()) {
 484  E :      output->swap(temp);
 485  E :    } else {
 486  i :      output->append(temp);
 487    :    }
 488    :  
 489  E :    return true;
 490  E :  }
 491    :  
 492    :  }  // namespace crashdata

Coverage information generated Fri Jul 29 11:00:21 2016.