Coverage for /Syzygy/core/json_file_writer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
86.6%2522910.C++source

Line-by-line coverage:

   1    :  // Copyright 2011 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    :  // JSONFileWriter works as a simple state machine. Rather than using an
  16    :  // exhaustive set of states and a big switch, its encoded via a few state
  17    :  // variables, and a handful of state determination functions. The general rule
  18    :  // of thumb is that when output is produced we write as much as is possible.
  19    :  #include "syzygy/core/json_file_writer.h"
  20    :  
  21    :  #include <stdarg.h>
  22    :  
  23    :  #include "base/logging.h"
  24    :  #include "base/utf_string_conversions.h"
  25    :  #include "base/values.h"
  26    :  #include "base/json/json_writer.h"
  27    :  #include "base/json/string_escape.h"
  28    :  #include "base/memory/scoped_ptr.h"
  29    :  
  30    :  namespace core {
  31    :  
  32    :  namespace {
  33    :  
  34    :  static const char kNewline[] = "\n";
  35    :  static const char kIndent[] = "  ";
  36    :  static const char kNull[] = "null";
  37    :  static const char kTrue[] = "true";
  38    :  static const char kFalse[] = "false";
  39    :  static const char kCommentPrefix[] = "//";
  40    :  
  41    :  static const char* kStructureOpenings[] = { "[", "{", NULL };
  42    :  static const char* kStructureClosings[] = { "]", "}", NULL };
  43    :  
  44    :  }  // namespace
  45    :  
  46    :  struct JSONFileWriter::Helper {
  47    :    template<typename KeyType>
  48  E :    static bool OutputKey(KeyType key, JSONFileWriter* json_file_writer) {
  49  E :      DCHECK(json_file_writer != NULL);
  50    :  
  51  E :      if (!json_file_writer->ReadyForKey())
  52  E :        return false;
  53    :  
  54  E :      if (!json_file_writer->AlignForValueOrKey())
  55  i :        return false;
  56    :  
  57  E :      std::string formatted_key = base::GetDoubleQuotedJson(key.as_string());
  58  E :      if (!json_file_writer->Printf("%s:", formatted_key.c_str()))
  59  i :        return false;
  60    :  
  61    :      // If we're pretty printing, then also output a space between the key and
  62    :      // the value.
  63  E :      if (json_file_writer->pretty_print_ && !json_file_writer->PutChar(' '))
  64  i :        return false;
  65    :  
  66    :      // Indicate that we've output a key and require a value.
  67  E :      json_file_writer->stack_.push_back(StackElement(kDictKey));
  68  E :      return true;
  69  E :    }
  70    :  
  71    :    template<typename ValueType, typename PrintFunctionPointer>
  72    :    static bool OutputValue(ValueType value,
  73    :                            PrintFunctionPointer print_function,
  74  E :                            JSONFileWriter* json_file_writer) {
  75  E :      DCHECK(print_function != NULL);
  76  E :      DCHECK(json_file_writer != NULL);
  77    :  
  78  E :      if (!json_file_writer->ReadyForValue())
  79  E :        return false;
  80  E :      if (!json_file_writer->AlignForValueOrKey())
  81  i :        return false;
  82  E :      if (!(json_file_writer->*print_function)(value))
  83  i :        return false;
  84  E :      json_file_writer->FlushValue(true);
  85  E :      return true;
  86  E :    }
  87    :  };
  88    :  
  89    :  JSONFileWriter::JSONFileWriter(FILE* file, bool pretty_print)
  90    :      : file_(file),
  91    :        pretty_print_(pretty_print),
  92    :        finished_(false),
  93    :        at_col_zero_(true),
  94  E :        indent_depth_(0) {
  95  E :    DCHECK(file != NULL);
  96  E :  }
  97    :  
  98  E :  JSONFileWriter::~JSONFileWriter() {
  99  E :    Flush();
 100  E :  }
 101    :  
 102  E :  bool JSONFileWriter::OutputComment(const base::StringPiece& comment) {
 103    :    // If we are in the middle of writing a dictionary key/value pair
 104    :    // (have the key, not the value), then we can't write a comment.
 105  E :    if (RequireKeyValue())
 106  E :      return false;
 107    :  
 108    :    // If we're not pretty-printing, this is a no-op.
 109  E :    if (!pretty_print_)
 110  E :      return true;
 111    :  
 112    :    // Trailing comments can be written directly.
 113  E :    if (finished_) {
 114  E :      if (!OutputNewline() || !Printf("%s", kCommentPrefix))
 115  i :        return false;
 116  E :      if (comment[0] != 0 && !Printf(" %s", comment))
 117  i :        return false;
 118  E :      return true;
 119    :    }
 120    :  
 121    :    // Store the comment for output before the next value.
 122  E :    comments_.push_back(comment.as_string());
 123    :  
 124  E :    return true;
 125  E :  }
 126    :  
 127  E :  bool JSONFileWriter::OutputComment(const base::StringPiece16& comment) {
 128  E :    std::string utf8;
 129  E :    if (!WideToUTF8(comment.data(), comment.length(), &utf8))
 130  i :      return false;
 131  E :    return OutputComment(utf8);
 132  E :  }
 133    :  
 134  E :  bool JSONFileWriter::OutputTrailingComment(const base::StringPiece& comment) {
 135    :    // A trailing comment can only go out after a value has been written.
 136  E :    if (!stack_.empty()) {
 137  E :      if (stack_.back().type_ == kDictKey)
 138  i :        return false;
 139    :  
 140  E :      if (stack_.back().has_entries_ == false)
 141  i :        return false;
 142  E :    } else {
 143    :      // If the stack is empty, then a value has only been written if we are
 144    :      // finished.
 145  E :      if (!finished_)
 146  i :        return false;
 147    :    }
 148    :  
 149    :    // No comment? Do nothing!
 150  E :    if (comment[0] == 0)
 151  i :      return true;
 152    :  
 153    :    // If we already have a trailing comment, bail!
 154  E :    if (!trailing_comment_.empty())
 155  E :      return false;
 156    :  
 157    :    // Save the comment for output when we're ready. We do this even when not
 158    :    // pretty-printing so that the state machine functions identically in either
 159    :    // case.
 160  E :    trailing_comment_.assign(comment.begin(), comment.end());
 161    :  
 162    :    // Are we finished? Immediately write the comment, but leave
 163    :    // trailing_comment_ populated so that repeated calls will fail.
 164    :    if (finished_ &&
 165  E :        !Printf("  %s %s", kCommentPrefix, trailing_comment_.c_str())) {
 166  i :      return false;
 167    :    }
 168    :  
 169  E :    return true;
 170  E :  }
 171    :  
 172  E :  bool JSONFileWriter::OutputTrailingComment(const base::StringPiece16& comment) {
 173  E :    std::string utf8;
 174  E :    if (!WideToUTF8(comment.data(), comment.length(), &utf8))
 175  i :      return false;
 176  E :    return OutputTrailingComment(utf8);
 177  E :  }
 178    :  
 179  E :  bool JSONFileWriter::PrintBoolean(bool value) {
 180  E :    return Printf("%s", value ? kTrue : kFalse);
 181  E :  }
 182    :  
 183  E :  bool JSONFileWriter::PrintInteger(int value) {
 184  E :    return Printf("%d", value);
 185  E :  }
 186    :  
 187  E :  bool JSONFileWriter::PrintDouble(double value) {
 188  E :    base::FundamentalValue fundamental_value(value);
 189  E :    return PrintValue(&fundamental_value);
 190  E :  }
 191    :  
 192  E :  bool JSONFileWriter::PrintString(const base::StringPiece& value) {
 193  E :    return Printf("%s", base::GetDoubleQuotedJson(value.as_string()).c_str());
 194  E :  }
 195    :  
 196  E :  bool JSONFileWriter::PrintNull(int value_unused) {
 197  E :    return Printf("%s", kNull);
 198  E :  }
 199    :  
 200  E :  bool JSONFileWriter::PrintValue(const base::Value* value) {
 201  E :    DCHECK(value != NULL);
 202    :  
 203  E :    switch (value->GetType()) {
 204    :      case Value::TYPE_LIST:
 205    :      case Value::TYPE_DICTIONARY: {
 206    :        // TODO(chrisha): Eventually, these should be implemented.
 207  i :        LOG(ERROR) << "JSON Lists and Dictionaries are currently unsupported.";
 208  i :        return false;
 209    :      }
 210    :  
 211    :      // All simple types.
 212    :      case Value::TYPE_BOOLEAN:
 213    :      case Value::TYPE_INTEGER:
 214    :      case Value::TYPE_DOUBLE:
 215    :      case Value::TYPE_NULL:
 216    :      case Value::TYPE_STRING:
 217    :      case Value::TYPE_BINARY: {
 218  E :        std::string str;
 219  E :        base::JSONWriter::Write(value, &str);
 220  E :        return Printf("%s", str.c_str());
 221    :      }
 222    :  
 223    :      default: {
 224  i :        NOTREACHED() << "Unexpected JSON type: " << value->GetType();
 225  i :        return false;
 226    :      }
 227    :    }
 228  E :  }
 229    :  
 230  E :  bool JSONFileWriter::Printf(const char* format, ...) {
 231    :    va_list args;
 232  E :    va_start(args, format);
 233  E :    int chars_written = vfprintf(file_, format, args);
 234  E :    va_end(args);
 235  E :    if (chars_written > 0)
 236  E :      at_col_zero_ = false;
 237  E :    return chars_written >= 0;
 238  E :  }
 239    :  
 240  E :  bool JSONFileWriter::PutChar(char c) {
 241  E :    if (fputc(c, file_) != c)
 242  i :      return false;
 243  E :    at_col_zero_ = false;
 244  E :    return true;
 245  E :  }
 246    :  
 247  E :  bool JSONFileWriter::OpenList() {
 248  E :    return OpenStructure(kList);
 249  E :  }
 250    :  
 251  E :  bool JSONFileWriter::CloseList() {
 252  E :    return CloseStructure(kList);
 253  E :  }
 254    :  
 255  E :  bool JSONFileWriter::OpenDict() {
 256  E :    return OpenStructure(kDict);
 257  E :  }
 258    :  
 259  E :  bool JSONFileWriter::CloseDict() {
 260  E :    return CloseStructure(kDict);
 261  E :  }
 262    :  
 263  E :  bool JSONFileWriter::OutputKey(const base::StringPiece& key) {
 264  E :    return Helper::OutputKey(key, this);
 265  E :  }
 266    :  
 267  E :  bool JSONFileWriter::OutputKey(const base::StringPiece16& key) {
 268  E :    return Helper::OutputKey(key, this);
 269  E :  }
 270    :  
 271  E :  bool JSONFileWriter::Flush() {
 272    :    // Already finished? This is a no-op.
 273  E :    if (finished_)
 274  E :      return true;
 275    :  
 276    :    // Are we waiting on a required value?
 277  E :    if (RequireKeyValue())
 278  E :      return false;
 279    :  
 280    :    // Otherwise, simply close off the structures one by one.
 281  E :    while (!stack_.empty()) {
 282  E :      if (!CloseStructure(stack_.back().type_))
 283  i :        return false;
 284  E :    }
 285    :  
 286  E :    return true;
 287  E :  }
 288    :  
 289  E :  bool JSONFileWriter::OutputBoolean(bool value) {
 290    :    return Helper::OutputValue(
 291  E :        value, &JSONFileWriter::PrintBoolean, this);
 292  E :  }
 293    :  
 294  E :  bool JSONFileWriter::OutputInteger(int value) {
 295    :    return Helper::OutputValue(
 296  E :        value, &JSONFileWriter::PrintInteger, this);
 297  E :  }
 298    :  
 299  E :  bool JSONFileWriter::OutputDouble(double value) {
 300    :    return Helper::OutputValue(
 301  E :        value, &JSONFileWriter::PrintDouble, this);
 302  E :  }
 303    :  
 304  E :  bool JSONFileWriter::OutputString(const base::StringPiece& value) {
 305    :    return Helper::OutputValue(
 306  E :        value, &JSONFileWriter::PrintString, this);
 307  E :  }
 308    :  
 309  E :  bool JSONFileWriter::OutputString(const base::StringPiece16& value) {
 310  E :    std::string utf8;
 311  E :    if (!WideToUTF8(value.data(), value.length(), &utf8))
 312  i :      return false;
 313  E :    return OutputString(utf8);
 314  E :  }
 315    :  
 316  E :  bool JSONFileWriter::OutputNull() {
 317  E :    int unused = 0;
 318    :    return Helper::OutputValue(
 319  E :        unused, &JSONFileWriter::PrintNull, this);
 320  E :  }
 321    :  
 322    :  bool JSONFileWriter::OutputValue(const Value* value) {
 323    :    return Helper::OutputValue(
 324    :        value, &JSONFileWriter::PrintValue, this);
 325    :  }
 326    :  
 327  E :  bool JSONFileWriter::OutputIndent() {
 328  E :    if (!pretty_print_)
 329  i :      return true;
 330    :  
 331    :    // We bypass Printf and manually update at_col_zero_ here for efficiency.
 332  E :    if (indent_depth_ > 0)
 333  E :      at_col_zero_ = false;
 334  E :    for (size_t i = 0; i < indent_depth_; ++i) {
 335  E :      if (fprintf(file_, "%s", kIndent) < 0)
 336  i :        return false;
 337  E :    }
 338  E :    return true;
 339  E :  }
 340    :  
 341  E :  bool JSONFileWriter::OutputNewline() {
 342  E :    if (!pretty_print_ || at_col_zero_)
 343  E :      return true;
 344    :  
 345    :    // Bypass Printf and manually at_col_zero_ for efficiency.
 346  E :    if (fprintf(file_, "%s", kNewline) < 0)
 347  i :      return false;
 348  E :    at_col_zero_ = true;
 349    :  
 350  E :    return true;
 351  E :  }
 352    :  
 353  E :  bool JSONFileWriter::OutputComments() {
 354  E :    if (comments_.empty())
 355  E :      return true;
 356    :  
 357    :    // Comments are only stored if we're pretty-printing.
 358  E :    DCHECK(pretty_print_);
 359    :  
 360  E :    bool indented = at_col_zero_ == false;
 361    :  
 362  E :    for (size_t i = 0; i < comments_.size(); ++i) {
 363    :      // Indent if need be.
 364  E :      if (at_col_zero_ && !OutputIndent())
 365  i :        return false;
 366    :  
 367    :      // Output the comment prefix.
 368  E :      if (!Printf("%s", kCommentPrefix))
 369  i :        return false;
 370    :  
 371    :      // Output the comment if there's any content.
 372    :      if (!comments_[i].empty() &&
 373  E :          !Printf(" %s", comments_[i].c_str()))
 374  i :        return false;
 375    :  
 376  E :      if (!OutputNewline())
 377  i :        return false;
 378  E :    }
 379    :  
 380    :    // If we were indented when entering, indent on the way out.
 381  E :    if (indented && !OutputIndent())
 382  i :      return false;
 383    :  
 384    :    // Clear the comments.
 385  E :    comments_.clear();
 386    :  
 387  E :    return true;
 388  E :  }
 389    :  
 390  E :  bool JSONFileWriter::OutputTrailingComment() {
 391  E :    if (trailing_comment_.empty())
 392  E :      return true;
 393    :  
 394    :    // If we're pretty-printing, output the comment.
 395    :    if (pretty_print_ &&
 396  E :        !Printf("  %s %s", kCommentPrefix, trailing_comment_.c_str())) {
 397  i :      return false;
 398    :    }
 399    :  
 400  E :    trailing_comment_.clear();
 401    :  
 402  E :    return true;
 403  E :  }
 404    :  
 405  E :  bool JSONFileWriter::AlignForValueOrKey() {
 406    :    // Are we a dictionary key waiting for a value? If so, there's nothing to
 407    :    // do as the alignment was taken care of when the key was written.
 408  E :    if (RequireKeyValue())
 409  E :      return true;
 410    :  
 411    :    // Are we in a structure, and not the first entry? Then we need to
 412    :    // output a trailing comma.
 413  E :    if (!stack_.empty() && !FirstEntry() && !PutChar(','))
 414  i :      return false;
 415    :  
 416    :    // Are we not pretty-printing? Then we're done!
 417  E :    if (!pretty_print_)
 418  E :      return true;
 419    :  
 420  E :    if (!OutputTrailingComment())
 421  i :      return false;
 422    :  
 423    :    // Go to a new line if need be.
 424  E :    if (!OutputNewline())
 425  i :      return false;
 426    :  
 427  E :    if (!OutputIndent())
 428  i :      return false;
 429    :  
 430  E :    return OutputComments();
 431  E :  }
 432    :  
 433  E :  bool JSONFileWriter::FirstEntry() const {
 434  E :    if (stack_.empty())
 435  E :      return true;
 436  E :    return !stack_.back().has_entries_;
 437  E :  }
 438    :  
 439  E :  bool JSONFileWriter::ReadyForKey() const {
 440  E :    if (stack_.empty())
 441  i :      return false;
 442  E :    return stack_.back().type_ == kDict;
 443  E :  }
 444    :  
 445  E :  bool JSONFileWriter::ReadyForValue() const {
 446  E :    if (finished_)
 447  E :      return false;
 448  E :    if (stack_.empty())
 449  E :      return true;
 450  E :    return stack_.back().type_ != kDict;
 451  E :  }
 452    :  
 453  E :  bool JSONFileWriter::RequireKeyValue() const {
 454  E :    if (stack_.empty())
 455  E :      return false;
 456  E :    return stack_.back().type_ == kDictKey;
 457  E :  }
 458    :  
 459  E :  bool JSONFileWriter::CanClose(StructureType type) const {
 460    :    // You can never 'close' a dict key.
 461  E :    if (stack_.empty() || type == kDictKey)
 462  i :      return false;
 463  E :    return stack_.back().type_ == type;
 464  E :  }
 465    :  
 466  E :  bool JSONFileWriter::OpenStructure(StructureType type) {
 467  E :    DCHECK_GT(arraysize(kStructureOpenings), static_cast<size_t>(type));
 468  E :    DCHECK(kStructureOpenings[type] != NULL);
 469    :  
 470    :    if (!ReadyForValue() ||
 471    :        !AlignForValueOrKey() ||
 472  E :        !Printf("%s", kStructureOpenings[type])) {
 473  i :      return false;
 474    :    }
 475    :  
 476    :    // Opening a new structure is like writing a new value, but the value has
 477    :    // not been *finished*.
 478  E :    FlushValue(false);
 479    :  
 480  E :    stack_.push_back(StackElement(type));
 481  E :    ++indent_depth_;
 482    :  
 483  E :    return true;
 484  E :  }
 485    :  
 486  E :  bool JSONFileWriter::CloseStructure(StructureType type) {
 487  E :    DCHECK_GT(arraysize(kStructureClosings), static_cast<size_t>(type));
 488  E :    DCHECK(kStructureClosings[type] != NULL);
 489    :  
 490    :    if (!CanClose(type) ||
 491    :        !OutputTrailingComment() ||
 492    :        !OutputNewline() ||
 493  E :        !OutputComments()) {
 494  E :      return false;
 495    :    }
 496    :  
 497  E :    stack_.pop_back();
 498  E :    --indent_depth_;
 499  E :    if (pretty_print_ && !OutputIndent())
 500  i :      return false;
 501    :  
 502  E :    if (!Printf("%s", kStructureClosings[type])) {
 503  i :      return false;
 504    :    }
 505    :  
 506    :    // If this closed the last open structure, then the JSON file is finished.
 507  E :    if (stack_.empty())
 508  E :      finished_ = true;
 509    :  
 510  E :    return true;
 511  E :  }
 512    :  
 513  E :  void JSONFileWriter::FlushValue(bool value_completed) {
 514    :    // The value was successfully written, so if we were in a dictionary waiting
 515    :    // for a value, pop the kDictKey entry off the stack.
 516  E :    if (RequireKeyValue())
 517  E :      stack_.pop_back();
 518    :  
 519    :    // If the stack is not empty, indicate that a value has been written to
 520    :    // the open structure.
 521  E :    if (!stack_.empty()) {
 522  E :      stack_.back().has_entries_ = true;
 523  E :    } else {
 524  E :      if (value_completed) {
 525    :        // If the stack is empty then having a written a single value means the
 526    :        // JSON file is finished.
 527  E :        finished_ = true;
 528    :      }
 529    :    }
 530  E :  }
 531    :  
 532    :  void JSONFileWriter::CompileAsserts() {
 533    :    COMPILE_ASSERT(
 534    :        arraysize(kStructureOpenings) == JSONFileWriter::kMaxStructureType,
 535    :        StructureOpenings_not_in_sync_with_StructureType_enum);
 536    :    COMPILE_ASSERT(
 537    :        arraysize(kStructureClosings) == JSONFileWriter::kMaxStructureType,
 538    :        StructureClosings_not_in_sync_with_StructureType_enum);
 539    :  }
 540    :  
 541    :  }  // namespace core

Coverage information generated Thu Mar 14 11:53:36 2013.