Coverage for /Syzygy/crashdata/json.cc

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

Coverage information generated Thu Mar 26 16:15:41 2015.