1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format
2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc.  All rights reserved.
3fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// http://code.google.com/p/protobuf/
4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without
6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are
7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met:
8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions of source code must retain the above copyright
10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer.
11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions in binary form must reproduce the above
12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer
13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the
14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution.
15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Neither the name of Google Inc. nor the names of its
16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from
17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission.
18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Author: kenton@google.com (Kenton Varda)
32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//  Based on original Protocol Buffers design by
33fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//  Sanjay Ghemawat, Jeff Dean, and others.
34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/io/printer.h>
36fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/io/zero_copy_stream.h>
37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/stubs/common.h>
38fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/stubs/strutil.h>
39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace google {
41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace protobuf {
42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace io {
43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
44fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavillePrinter::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
45fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  : variable_delimiter_(variable_delimiter),
46fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    output_(output),
47fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    buffer_(NULL),
48fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    buffer_size_(0),
49fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    at_start_of_line_(true),
50fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    failed_(false) {
51fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
52fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
53fbaaef999ba563838ebd00874ed8a1c01fbf286dWink SavillePrinter::~Printer() {
54fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Only BackUp() if we're sure we've successfully called Next() at least once.
55fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (buffer_size_ > 0) {
56fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    output_->BackUp(buffer_size_);
57fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
58fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
59fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
60fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid Printer::Print(const map<string, string>& variables, const char* text) {
61fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  int size = strlen(text);
62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  int pos = 0;  // The number of bytes we've written so far.
63fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  for (int i = 0; i < size; i++) {
65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (text[i] == '\n') {
66fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Saw newline.  If there is more text, we may need to insert an indent
67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // here.  So, write what we have so far, including the '\n'.
68d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      WriteRaw(text + pos, i - pos + 1);
69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      pos = i + 1;
70fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
71d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      // Setting this true will cause the next WriteRaw() to insert an indent
72fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // first.
73fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      at_start_of_line_ = true;
74fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
75fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    } else if (text[i] == variable_delimiter_) {
76fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Saw the start of a variable name.
77fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
78fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Write what we have so far.
79d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      WriteRaw(text + pos, i - pos);
80fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      pos = i + 1;
81fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
82fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Find closing delimiter.
83fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      const char* end = strchr(text + pos, variable_delimiter_);
84fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (end == NULL) {
85fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
86fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        end = text + pos;
87fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
88fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      int endpos = end - text;
89fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
90fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      string varname(text + pos, endpos - pos);
91fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if (varname.empty()) {
92fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // Two delimiters in a row reduce to a literal delimiter character.
93d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville        WriteRaw(&variable_delimiter_, 1);
94fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      } else {
95fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        // Replace with the variable's value.
96fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        map<string, string>::const_iterator iter = variables.find(varname);
97fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        if (iter == variables.end()) {
98fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
99fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        } else {
100d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          WriteRaw(iter->second.data(), iter->second.size());
101fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        }
102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      }
103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      // Advance past this variable.
105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      i = endpos;
106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      pos = endpos + 1;
107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    }
108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
109fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
110fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Write the rest.
111d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  WriteRaw(text + pos, size - pos);
112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
113fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid Printer::Print(const char* text) {
115fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static map<string, string> empty;
116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Print(empty, text);
117fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
118fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid Printer::Print(const char* text,
120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    const char* variable, const string& value) {
121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  map<string, string> vars;
122fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars[variable] = value;
123fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Print(vars, text);
124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid Printer::Print(const char* text,
127fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    const char* variable1, const string& value1,
128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    const char* variable2, const string& value2) {
129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  map<string, string> vars;
130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars[variable1] = value1;
131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  vars[variable2] = value2;
132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Print(vars, text);
133fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid Printer::Indent() {
136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  indent_ += "  ";
137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillevoid Printer::Outdent() {
140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (indent_.empty()) {
141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return;
143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  indent_.resize(indent_.size() - 2);
146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
148d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillevoid Printer::PrintRaw(const string& data) {
149d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  WriteRaw(data.data(), data.size());
150d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
151d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
152d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillevoid Printer::PrintRaw(const char* data) {
153d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  if (failed_) return;
154d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  WriteRaw(data, strlen(data));
155d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville}
156d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
157d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillevoid Printer::WriteRaw(const char* data, int size) {
158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (failed_) return;
159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (size == 0) return;
160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if (at_start_of_line_) {
162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // Insert an indent.
163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    at_start_of_line_ = false;
164d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    WriteRaw(indent_.data(), indent_.size());
165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (failed_) return;
166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
168fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  while (size > buffer_size_) {
169fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // Data exceeds space in the buffer.  Copy what we can and request a
170fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // new buffer.
171fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    memcpy(buffer_, data, buffer_size_);
172fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    data += buffer_size_;
173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    size -= buffer_size_;
174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    void* void_buffer;
175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    failed_ = !output_->Next(&void_buffer, &buffer_size_);
176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (failed_) return;
177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    buffer_ = reinterpret_cast<char*>(void_buffer);
178fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
179fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
180fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Buffer is big enough to receive the data; copy it.
181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  memcpy(buffer_, data, size);
182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  buffer_ += size;
183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  buffer_size_ -= size;
184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}
185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace io
187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace protobuf
188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace google
189