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 (at) 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 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 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 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 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 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 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 174 void Printer::Print(const char* text) { 175 static map<string, string> empty; 176 Print(empty, text); 177 } 178 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 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 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 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 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 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 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 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 291 void Printer::Indent() { 292 indent_ += " "; 293 } 294 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 304 void Printer::PrintRaw(const string& data) { 305 WriteRaw(data.data(), data.size()); 306 } 307 308 void Printer::PrintRaw(const char* data) { 309 if (failed_) return; 310 WriteRaw(data, strlen(data)); 311 } 312 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