1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Author: kenton@google.com (Kenton Varda)
32//  Based on original Protocol Buffers design by
33//  Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <google/protobuf/io/printer.h>
36#include <google/protobuf/io/zero_copy_stream.h>
37#include <google/protobuf/stubs/logging.h>
38#include <google/protobuf/stubs/common.h>
39
40namespace google {
41namespace protobuf {
42namespace io {
43
44Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
45    : variable_delimiter_(variable_delimiter),
46      output_(output),
47      buffer_(NULL),
48      buffer_size_(0),
49      offset_(0),
50      at_start_of_line_(true),
51      failed_(false),
52      annotation_collector_(NULL) {}
53
54Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
55                 AnnotationCollector* annotation_collector)
56    : variable_delimiter_(variable_delimiter),
57      output_(output),
58      buffer_(NULL),
59      buffer_size_(0),
60      offset_(0),
61      at_start_of_line_(true),
62      failed_(false),
63      annotation_collector_(annotation_collector) {}
64
65Printer::~Printer() {
66  // Only BackUp() if we have called Next() at least once and never failed.
67  if (buffer_size_ > 0 && !failed_) {
68    output_->BackUp(buffer_size_);
69  }
70}
71
72bool Printer::GetSubstitutionRange(const char* varname,
73                                   pair<size_t, size_t>* range) {
74  map<string, pair<size_t, size_t> >::const_iterator iter =
75      substitutions_.find(varname);
76  if (iter == substitutions_.end()) {
77    GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
78    return false;
79  }
80  if (iter->second.first > iter->second.second) {
81    GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
82                << varname;
83    return false;
84  }
85  *range = iter->second;
86  return true;
87}
88
89void Printer::Annotate(const char* begin_varname, const char* end_varname,
90                       const string& file_path, const vector<int>& path) {
91  if (annotation_collector_ == NULL) {
92    // Can't generate signatures with this Printer.
93    return;
94  }
95  pair<size_t, size_t> begin, end;
96  if (!GetSubstitutionRange(begin_varname, &begin) ||
97      !GetSubstitutionRange(end_varname, &end)) {
98    return;
99  }
100  if (begin.first > end.second) {
101    GOOGLE_LOG(DFATAL) << "  Annotation has negative length from " << begin_varname
102                << " to " << end_varname;
103  } else {
104    annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
105                                         path);
106  }
107}
108
109void Printer::Print(const map<string, string>& variables, const char* text) {
110  int size = strlen(text);
111  int pos = 0;  // The number of bytes we've written so far.
112  substitutions_.clear();
113
114  for (int i = 0; i < size; i++) {
115    if (text[i] == '\n') {
116      // Saw newline.  If there is more text, we may need to insert an indent
117      // here.  So, write what we have so far, including the '\n'.
118      WriteRaw(text + pos, i - pos + 1);
119      pos = i + 1;
120
121      // Setting this true will cause the next WriteRaw() to insert an indent
122      // first.
123      at_start_of_line_ = true;
124
125    } else if (text[i] == variable_delimiter_) {
126      // Saw the start of a variable name.
127
128      // Write what we have so far.
129      WriteRaw(text + pos, i - pos);
130      pos = i + 1;
131
132      // Find closing delimiter.
133      const char* end = strchr(text + pos, variable_delimiter_);
134      if (end == NULL) {
135        GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
136        end = text + pos;
137      }
138      int endpos = end - text;
139
140      string varname(text + pos, endpos - pos);
141      if (varname.empty()) {
142        // Two delimiters in a row reduce to a literal delimiter character.
143        WriteRaw(&variable_delimiter_, 1);
144      } else {
145        // Replace with the variable's value.
146        map<string, string>::const_iterator iter = variables.find(varname);
147        if (iter == variables.end()) {
148          GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
149        } else {
150          size_t begin = offset_;
151          WriteRaw(iter->second.data(), iter->second.size());
152          pair<map<string, pair<size_t, size_t> >::iterator, bool> inserted =
153              substitutions_.insert(
154                  std::make_pair(varname, std::make_pair(begin, offset_)));
155          if (!inserted.second) {
156            // This variable was used multiple times.  Make its span have
157            // negative length so we can detect it if it gets used in an
158            // annotation.
159            inserted.first->second = std::make_pair(1, 0);
160          }
161        }
162      }
163
164      // Advance past this variable.
165      i = endpos;
166      pos = endpos + 1;
167    }
168  }
169
170  // Write the rest.
171  WriteRaw(text + pos, size - pos);
172}
173
174void Printer::Print(const char* text) {
175  static map<string, string> empty;
176  Print(empty, text);
177}
178
179void Printer::Print(const char* text,
180                    const char* variable, const string& value) {
181  map<string, string> vars;
182  vars[variable] = value;
183  Print(vars, text);
184}
185
186void Printer::Print(const char* text,
187                    const char* variable1, const string& value1,
188                    const char* variable2, const string& value2) {
189  map<string, string> vars;
190  vars[variable1] = value1;
191  vars[variable2] = value2;
192  Print(vars, text);
193}
194
195void Printer::Print(const char* text,
196                    const char* variable1, const string& value1,
197                    const char* variable2, const string& value2,
198                    const char* variable3, const string& value3) {
199  map<string, string> vars;
200  vars[variable1] = value1;
201  vars[variable2] = value2;
202  vars[variable3] = value3;
203  Print(vars, text);
204}
205
206void Printer::Print(const char* text,
207                    const char* variable1, const string& value1,
208                    const char* variable2, const string& value2,
209                    const char* variable3, const string& value3,
210                    const char* variable4, const string& value4) {
211  map<string, string> vars;
212  vars[variable1] = value1;
213  vars[variable2] = value2;
214  vars[variable3] = value3;
215  vars[variable4] = value4;
216  Print(vars, text);
217}
218
219void Printer::Print(const char* text,
220                    const char* variable1, const string& value1,
221                    const char* variable2, const string& value2,
222                    const char* variable3, const string& value3,
223                    const char* variable4, const string& value4,
224                    const char* variable5, const string& value5) {
225  map<string, string> vars;
226  vars[variable1] = value1;
227  vars[variable2] = value2;
228  vars[variable3] = value3;
229  vars[variable4] = value4;
230  vars[variable5] = value5;
231  Print(vars, text);
232}
233
234void Printer::Print(const char* text,
235                    const char* variable1, const string& value1,
236                    const char* variable2, const string& value2,
237                    const char* variable3, const string& value3,
238                    const char* variable4, const string& value4,
239                    const char* variable5, const string& value5,
240                    const char* variable6, const string& value6) {
241  map<string, string> vars;
242  vars[variable1] = value1;
243  vars[variable2] = value2;
244  vars[variable3] = value3;
245  vars[variable4] = value4;
246  vars[variable5] = value5;
247  vars[variable6] = value6;
248  Print(vars, text);
249}
250
251void Printer::Print(const char* text,
252                    const char* variable1, const string& value1,
253                    const char* variable2, const string& value2,
254                    const char* variable3, const string& value3,
255                    const char* variable4, const string& value4,
256                    const char* variable5, const string& value5,
257                    const char* variable6, const string& value6,
258                    const char* variable7, const string& value7) {
259  map<string, string> vars;
260  vars[variable1] = value1;
261  vars[variable2] = value2;
262  vars[variable3] = value3;
263  vars[variable4] = value4;
264  vars[variable5] = value5;
265  vars[variable6] = value6;
266  vars[variable7] = value7;
267  Print(vars, text);
268}
269
270void Printer::Print(const char* text,
271                    const char* variable1, const string& value1,
272                    const char* variable2, const string& value2,
273                    const char* variable3, const string& value3,
274                    const char* variable4, const string& value4,
275                    const char* variable5, const string& value5,
276                    const char* variable6, const string& value6,
277                    const char* variable7, const string& value7,
278                    const char* variable8, const string& value8) {
279  map<string, string> vars;
280  vars[variable1] = value1;
281  vars[variable2] = value2;
282  vars[variable3] = value3;
283  vars[variable4] = value4;
284  vars[variable5] = value5;
285  vars[variable6] = value6;
286  vars[variable7] = value7;
287  vars[variable8] = value8;
288  Print(vars, text);
289}
290
291void Printer::Indent() {
292  indent_ += "  ";
293}
294
295void Printer::Outdent() {
296  if (indent_.empty()) {
297    GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
298    return;
299  }
300
301  indent_.resize(indent_.size() - 2);
302}
303
304void Printer::PrintRaw(const string& data) {
305  WriteRaw(data.data(), data.size());
306}
307
308void Printer::PrintRaw(const char* data) {
309  if (failed_) return;
310  WriteRaw(data, strlen(data));
311}
312
313void Printer::WriteRaw(const char* data, int size) {
314  if (failed_) return;
315  if (size == 0) return;
316
317  if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
318    // Insert an indent.
319    at_start_of_line_ = false;
320    WriteRaw(indent_.data(), indent_.size());
321    if (failed_) return;
322  }
323
324  while (size > buffer_size_) {
325    // Data exceeds space in the buffer.  Copy what we can and request a
326    // new buffer.
327    memcpy(buffer_, data, buffer_size_);
328    offset_ += buffer_size_;
329    data += buffer_size_;
330    size -= buffer_size_;
331    void* void_buffer;
332    failed_ = !output_->Next(&void_buffer, &buffer_size_);
333    if (failed_) return;
334    buffer_ = reinterpret_cast<char*>(void_buffer);
335  }
336
337  // Buffer is big enough to receive the data; copy it.
338  memcpy(buffer_, data, size);
339  buffer_ += size;
340  buffer_size_ -= size;
341  offset_ += size;
342}
343
344}  // namespace io
345}  // namespace protobuf
346}  // namespace google
347