• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
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/common.h>
38 #include <google/protobuf/stubs/strutil.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     at_start_of_line_(true),
50     failed_(false) {
51 }
52 
~Printer()53 Printer::~Printer() {
54   // Only BackUp() if we're sure we've successfully called Next() at least once.
55   if (buffer_size_ > 0) {
56     output_->BackUp(buffer_size_);
57   }
58 }
59 
Print(const map<string,string> & variables,const char * text)60 void Printer::Print(const map<string, string>& variables, const char* text) {
61   int size = strlen(text);
62   int pos = 0;  // The number of bytes we've written so far.
63 
64   for (int i = 0; i < size; i++) {
65     if (text[i] == '\n') {
66       // Saw newline.  If there is more text, we may need to insert an indent
67       // here.  So, write what we have so far, including the '\n'.
68       WriteRaw(text + pos, i - pos + 1);
69       pos = i + 1;
70 
71       // Setting this true will cause the next WriteRaw() to insert an indent
72       // first.
73       at_start_of_line_ = true;
74 
75     } else if (text[i] == variable_delimiter_) {
76       // Saw the start of a variable name.
77 
78       // Write what we have so far.
79       WriteRaw(text + pos, i - pos);
80       pos = i + 1;
81 
82       // Find closing delimiter.
83       const char* end = strchr(text + pos, variable_delimiter_);
84       if (end == NULL) {
85         GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
86         end = text + pos;
87       }
88       int endpos = end - text;
89 
90       string varname(text + pos, endpos - pos);
91       if (varname.empty()) {
92         // Two delimiters in a row reduce to a literal delimiter character.
93         WriteRaw(&variable_delimiter_, 1);
94       } else {
95         // Replace with the variable's value.
96         map<string, string>::const_iterator iter = variables.find(varname);
97         if (iter == variables.end()) {
98           GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
99         } else {
100           WriteRaw(iter->second.data(), iter->second.size());
101         }
102       }
103 
104       // Advance past this variable.
105       i = endpos;
106       pos = endpos + 1;
107     }
108   }
109 
110   // Write the rest.
111   WriteRaw(text + pos, size - pos);
112 }
113 
Print(const char * text)114 void Printer::Print(const char* text) {
115   static map<string, string> empty;
116   Print(empty, text);
117 }
118 
Print(const char * text,const char * variable,const string & value)119 void Printer::Print(const char* text,
120                     const char* variable, const string& value) {
121   map<string, string> vars;
122   vars[variable] = value;
123   Print(vars, text);
124 }
125 
Print(const char * text,const char * variable1,const string & value1,const char * variable2,const string & value2)126 void Printer::Print(const char* text,
127                     const char* variable1, const string& value1,
128                     const char* variable2, const string& value2) {
129   map<string, string> vars;
130   vars[variable1] = value1;
131   vars[variable2] = value2;
132   Print(vars, text);
133 }
134 
Indent()135 void Printer::Indent() {
136   indent_ += "  ";
137 }
138 
Outdent()139 void Printer::Outdent() {
140   if (indent_.empty()) {
141     GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
142     return;
143   }
144 
145   indent_.resize(indent_.size() - 2);
146 }
147 
PrintRaw(const string & data)148 void Printer::PrintRaw(const string& data) {
149   WriteRaw(data.data(), data.size());
150 }
151 
PrintRaw(const char * data)152 void Printer::PrintRaw(const char* data) {
153   if (failed_) return;
154   WriteRaw(data, strlen(data));
155 }
156 
WriteRaw(const char * data,int size)157 void Printer::WriteRaw(const char* data, int size) {
158   if (failed_) return;
159   if (size == 0) return;
160 
161   if (at_start_of_line_) {
162     // Insert an indent.
163     at_start_of_line_ = false;
164     WriteRaw(indent_.data(), indent_.size());
165     if (failed_) return;
166   }
167 
168   while (size > buffer_size_) {
169     // Data exceeds space in the buffer.  Copy what we can and request a
170     // new buffer.
171     memcpy(buffer_, data, buffer_size_);
172     data += buffer_size_;
173     size -= buffer_size_;
174     void* void_buffer;
175     failed_ = !output_->Next(&void_buffer, &buffer_size_);
176     if (failed_) return;
177     buffer_ = reinterpret_cast<char*>(void_buffer);
178   }
179 
180   // Buffer is big enough to receive the data; copy it.
181   memcpy(buffer_, data, size);
182   buffer_ += size;
183   buffer_size_ -= size;
184 }
185 
186 }  // namespace io
187 }  // namespace protobuf
188 }  // namespace google
189