Coverage for /Syzygy/crashdata/json.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.7%2652860.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    :        : 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 :      EmitHexValue32(stack_trace_->frames().Get(index), output);
 186  E :      return true;
 187  E :    }
 188    :  
 189    :    const StackTrace* stack_trace_;
 190    :  };
 191    :  
 192    :  bool ToJson(const StackTrace* stack_trace,
 193    :              std::string* indent,
 194  E :              std::string* output) {
 195  E :    assert(stack_trace != nullptr);
 196  E :    assert(output != nullptr);
 197  E :    StackTraceYieldFunctor yield(stack_trace);
 198    :    if (!EmitJsonList('[', ']', 4, stack_trace->frames_size(), yield,
 199  E :                      indent, output)) {
 200  i :      return false;
 201    :    }
 202  E :    return true;
 203  E :  }
 204    :  
 205    :  // A functor for emitting the binary data in a blob as an array.
 206    :  struct BlobDataYieldFunctor {
 207  E :    explicit BlobDataYieldFunctor(const Blob* blob)
 208    :        : blob_(blob) {
 209  E :      assert(blob != nullptr);
 210  E :    }
 211    :  
 212  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 213  E :      EmitHexValue8(static_cast<unsigned char>(blob_->data()[index]), output);
 214  E :      return true;
 215  E :    }
 216    :  
 217    :    const Blob* blob_;
 218    :  };
 219    :  
 220    :  // A functor for emitting the contents of a blob as a dictionary.
 221    :  struct BlobYieldFunctor {
 222  E :    explicit BlobYieldFunctor(const Blob* blob)
 223    :        : blob_(blob), need_comma_(false) {
 224  E :      assert(blob != nullptr);
 225  E :    }
 226    :  
 227  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 228  E :      assert(output != nullptr);
 229  E :      switch (index) {
 230    :        case 0: {
 231    :          // Emit a blob descriptor.
 232  E :          EmitDictKey("type", indent, output);
 233  E :          EmitString("blob", output);
 234  E :          return true;
 235    :        }
 236    :        case 1: {
 237  E :          EmitDictKey("address", indent, output);
 238  E :          if (blob_->has_address()) {
 239  E :            if (!ToJson(&blob_->address(), indent, output))
 240  i :              return false;
 241  E :          } else {
 242  E :            EmitNull(output);
 243    :          }
 244  E :          return true;
 245    :        }
 246    :        case 2: {
 247  E :          EmitDictKey("size", indent, output);
 248  E :          if (blob_->has_size()) {
 249  E :            EmitDecValue(blob_->size(), output);
 250  E :          } else {
 251  E :            EmitNull(output);
 252    :          }
 253  E :          return true;
 254    :        }
 255    :        case 3: {
 256  E :          EmitDictKey("data", indent, output);
 257  E :          if (blob_->has_data()) {
 258  E :            BlobDataYieldFunctor yield(blob_);
 259    :            if (!EmitJsonList('[', ']', 8, blob_->data().size(), yield,
 260  E :                              indent, output)) {
 261  i :              return false;
 262    :            }
 263  E :          } else {
 264  E :            EmitNull(output);
 265    :          }
 266  E :          return true;
 267    :        }
 268    :        default: break;
 269    :      }
 270    :  
 271    :      // This should never happen!
 272  i :      assert(false);
 273  i :      return false;
 274  E :    }
 275    :  
 276    :    const Blob* blob_;
 277    :    bool need_comma_;
 278    :  };
 279    :  
 280  E :  bool ToJson(const Blob* blob, std::string* indent, std::string* output) {
 281  E :    assert(blob != nullptr);
 282  E :    assert(output != nullptr);
 283  E :    BlobYieldFunctor yield(blob);
 284    :    // 1 element per line, 4 elements total.
 285  E :    if (!EmitJsonList('{', '}', 1, 4, yield, indent, output))
 286  i :      return false;
 287  E :    return true;
 288  E :  }
 289    :  
 290  E :  bool ToJson(const Leaf* leaf, std::string* indent, std::string* output) {
 291  E :    assert(leaf != nullptr);
 292  E :    assert(output != nullptr);
 293    :  
 294  E :    if (!leaf->has_type())
 295  i :      return false;
 296    :  
 297  E :    switch (leaf->type()) {
 298    :      default:
 299    :      case Leaf_Type_UNKNOWN_TYPE: {
 300  E :        return false;
 301    :      }
 302    :  
 303    :      case Leaf_Type_INTEGER: {
 304  E :        if (!leaf->has_integer())
 305  E :          return false;
 306  E :        EmitDecValue(leaf->integer(), output);
 307  E :        return true;
 308    :      }
 309    :  
 310    :      case Leaf_Type_UNSIGNED_INTEGER: {
 311  E :        if (!leaf->has_unsigned_integer())
 312  E :          return false;
 313  E :        EmitDecValue(leaf->unsigned_integer(), output);
 314  E :        return true;
 315    :      }
 316    :  
 317    :      case Leaf_Type_REAL: {
 318  E :        if (!leaf->has_real())
 319  E :          return false;
 320  E :        EmitDouble(leaf->real(), output);
 321  E :        return true;
 322    :      }
 323    :  
 324    :      case Leaf_Type_STRING: {
 325  E :        if (!leaf->has_string())
 326  E :          return false;
 327  E :        EmitString(leaf->string(), output);
 328  E :        return true;
 329    :      }
 330    :  
 331    :      case Leaf_Type_ADDRESS: {
 332  E :        if (!leaf->has_address())
 333  E :          return false;
 334  E :        if (!ToJson(&leaf->address(), indent, output))
 335  i :          return false;
 336  E :        return true;
 337    :      }
 338    :  
 339    :      case Leaf_Type_STACK_TRACE: {
 340  E :        if (!leaf->has_stack_trace())
 341  E :          return false;
 342  E :        if (!ToJson(&leaf->stack_trace(), indent, output))
 343  i :          return false;
 344  E :        return true;
 345    :      }
 346    :  
 347    :      case Leaf_Type_BLOB: {
 348  E :        if (!leaf->has_blob())
 349  E :          return false;
 350  E :        if (!ToJson(&leaf->blob(), indent, output))
 351  i :          return false;
 352  E :        return true;
 353    :      }
 354    :    }
 355    :  
 356  i :    assert(false);
 357  i :    return false;
 358  E :  }
 359    :  
 360    :  struct ValueListYieldFunctor {
 361  E :    explicit ValueListYieldFunctor(const ValueList* list) : list_(list) {}
 362    :  
 363  E :    bool operator()(size_t index, std::string* indent, std::string* output) {
 364  E :      assert(output != nullptr);
 365  E :      if (!ToJson(&list_->values().Get(index), indent, output))
 366  i :        return false;
 367  E :      return true;
 368  E :    }
 369    :  
 370    :    const ValueList* list_;
 371    :  };
 372    :  
 373  E :  bool ToJson(const ValueList* list, std::string* indent, std::string* output) {
 374  E :    assert(list != nullptr);
 375  E :    assert(output != nullptr);
 376  E :    ValueListYieldFunctor yield(list);
 377  E :    if (!EmitJsonList('[', ']', 1, list->values_size(), yield, indent, output))
 378  i :      return false;
 379  E :    return true;
 380  E :  }
 381    :  
 382    :  bool ToJson(
 383  E :      const KeyValue* key_value, std::string* indent, std::string* output) {
 384  E :    assert(key_value != nullptr);
 385  E :    assert(output != nullptr);
 386  E :    if (!key_value->has_key())
 387  E :      return false;
 388  E :    if (!key_value->has_value())
 389  E :      return false;
 390  E :    EmitDictKey(key_value->key(), indent, output);
 391  E :    if (!ToJson(&key_value->value(), indent, output))
 392  i :      return false;
 393  E :    return true;
 394  E :  }
 395    :  
 396    :  struct DictYieldFunctor {
 397  E :    explicit DictYieldFunctor(const Dictionary* dict) : dict_(dict) {
 398  E :    }
 399    :  
 400    :    bool operator()(size_t index,
 401    :                    std::string* indent,
 402  E :                    std::string* output) {
 403  E :      assert(output != nullptr);
 404  E :      if (!ToJson(&dict_->values().Get(index), indent, output))
 405  E :        return false;
 406  E :      return true;
 407  E :    }
 408    :  
 409    :    const Dictionary* dict_;
 410    :  };
 411    :  
 412  E :  bool ToJson(const Dictionary* dict, std::string* indent, std::string* output) {
 413  E :    assert(dict != nullptr);
 414  E :    assert(output != nullptr);
 415  E :    DictYieldFunctor yield(dict);
 416  E :    if (!EmitJsonList('{', '}', 1, dict->values_size(), yield, indent, output))
 417  E :      return false;
 418  E :    return true;
 419  E :  }
 420    :  
 421  E :  bool ToJson(const Value* value, std::string* indent, std::string* output) {
 422  E :    assert(value != nullptr);
 423  E :    assert(output != nullptr);
 424  E :    if (!value->has_type())
 425  i :      return false;
 426  E :    switch (value->type()) {
 427    :      default:
 428    :      case Value_Type_UNKNOWN_TYPE: {
 429  E :        return false;
 430    :      }
 431    :  
 432    :      case Value_Type_LEAF: {
 433  E :        if (!value->has_leaf())
 434  E :          return false;
 435  E :        if (!ToJson(&value->leaf(), indent, output))
 436  E :          return false;
 437  E :        return true;
 438    :      }
 439    :  
 440    :      case Value_Type_VALUE_LIST: {
 441  E :        if (!value->has_list())
 442  E :          return false;
 443  E :        if (!ToJson(&value->list(), indent, output))
 444  i :          return false;
 445  E :        return true;
 446    :      }
 447    :  
 448    :      case Value_Type_DICTIONARY: {
 449  E :        if (!value->has_dictionary())
 450  E :          return false;
 451  E :        if (!ToJson(&value->dictionary(), indent, output))
 452  E :          return false;
 453  E :        return true;
 454    :      }
 455    :    }
 456    :  
 457  i :    assert(false);
 458  i :    return false;
 459  E :  }
 460    :  
 461    :  }  // namespace
 462    :  
 463  E :  bool ToJson(bool pretty_print, const Value* value, std::string* output) {
 464  E :    assert(value != nullptr);
 465  E :    assert(output != nullptr);
 466  E :    std::string* indent = nullptr;
 467  E :    std::string indent_content;
 468  E :    if (pretty_print) {
 469  E :      indent_content = "\n";
 470  E :      indent = &indent_content;
 471    :    }
 472    :  
 473    :    // Produce the output to a temp variable, as partial output may be produced
 474    :    // in case of error.
 475  E :    std::string temp;
 476  E :    if (!ToJson(value, indent, &temp))
 477  E :      return false;
 478    :  
 479    :    // Place the output in the desired string as efficiently as possible.
 480  E :    if (output->empty()) {
 481  E :      output->swap(temp);
 482  E :    } else {
 483  i :      output->append(temp);
 484    :    }
 485    :  
 486  E :    return true;
 487  E :  }
 488    :  
 489    :  }  // namespace crashdata

Coverage information generated Thu Jan 14 17:40:38 2016.