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