• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 namespace google {
41 namespace protobuf {
42 namespace io {
43 
Printer(ZeroCopyOutputStream * output,char variable_delimiter)44 Printer::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 
Printer(ZeroCopyOutputStream * output,char variable_delimiter,AnnotationCollector * annotation_collector)54 Printer::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 
~Printer()65 Printer::~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 
GetSubstitutionRange(const char * varname,pair<size_t,size_t> * range)72 bool 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 
Annotate(const char * begin_varname,const char * end_varname,const string & file_path,const vector<int> & path)89 void 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 
Print(const map<string,string> & variables,const char * text)109 void 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 
Print(const char * text)174 void Printer::Print(const char* text) {
175   static map<string, string> empty;
176   Print(empty, text);
177 }
178 
Print(const char * text,const char * variable,const string & value)179 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2)186 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2,const char * variable3,const string & value3)195 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2,const char * variable3,const string & value3,const char * variable4,const string & value4)206 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2,const char * variable3,const string & value3,const char * variable4,const string & value4,const char * variable5,const string & value5)219 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2,const char * variable3,const string & value3,const char * variable4,const string & value4,const char * variable5,const string & value5,const char * variable6,const string & value6)234 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2,const char * variable3,const string & value3,const char * variable4,const string & value4,const char * variable5,const string & value5,const char * variable6,const string & value6,const char * variable7,const string & value7)251 void 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 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2,const char * variable3,const string & value3,const char * variable4,const string & value4,const char * variable5,const string & value5,const char * variable6,const string & value6,const char * variable7,const string & value7,const char * variable8,const string & value8)270 void 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 
Indent()291 void Printer::Indent() {
292   indent_ += "  ";
293 }
294 
Outdent()295 void 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 
PrintRaw(const string & data)304 void Printer::PrintRaw(const string& data) {
305   WriteRaw(data.data(), data.size());
306 }
307 
PrintRaw(const char * data)308 void Printer::PrintRaw(const char* data) {
309   if (failed_) return;
310   WriteRaw(data, strlen(data));
311 }
312 
WriteRaw(const char * data,int size)313 void 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