PageRenderTime 62ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/protobuf/src/google/protobuf/io/printer.cc

https://github.com/chromium/chromium
C++ | 400 lines | 297 code | 39 blank | 64 comment | 87 complexity | efd4be39cc030eac51780af4f76a75a2 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  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. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. #include <google/protobuf/io/printer.h>
  34. #include <cctype>
  35. #include <google/protobuf/stubs/logging.h>
  36. #include <google/protobuf/stubs/common.h>
  37. #include <google/protobuf/io/zero_copy_stream.h>
  38. namespace google {
  39. namespace protobuf {
  40. namespace io {
  41. Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
  42. : variable_delimiter_(variable_delimiter),
  43. output_(output),
  44. buffer_(NULL),
  45. buffer_size_(0),
  46. offset_(0),
  47. at_start_of_line_(true),
  48. failed_(false),
  49. annotation_collector_(NULL) {}
  50. Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
  51. AnnotationCollector* annotation_collector)
  52. : variable_delimiter_(variable_delimiter),
  53. output_(output),
  54. buffer_(NULL),
  55. buffer_size_(0),
  56. offset_(0),
  57. at_start_of_line_(true),
  58. failed_(false),
  59. annotation_collector_(annotation_collector) {}
  60. Printer::~Printer() {
  61. // Only BackUp() if we have called Next() at least once and never failed.
  62. if (buffer_size_ > 0 && !failed_) {
  63. output_->BackUp(buffer_size_);
  64. }
  65. }
  66. bool Printer::GetSubstitutionRange(const char* varname,
  67. std::pair<size_t, size_t>* range) {
  68. std::map<std::string, std::pair<size_t, size_t> >::const_iterator iter =
  69. substitutions_.find(varname);
  70. if (iter == substitutions_.end()) {
  71. GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
  72. return false;
  73. }
  74. if (iter->second.first > iter->second.second) {
  75. GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
  76. << varname;
  77. return false;
  78. }
  79. *range = iter->second;
  80. return true;
  81. }
  82. void Printer::Annotate(const char* begin_varname, const char* end_varname,
  83. const std::string& file_path,
  84. const std::vector<int>& path) {
  85. if (annotation_collector_ == NULL) {
  86. // Can't generate signatures with this Printer.
  87. return;
  88. }
  89. std::pair<size_t, size_t> begin, end;
  90. if (!GetSubstitutionRange(begin_varname, &begin) ||
  91. !GetSubstitutionRange(end_varname, &end)) {
  92. return;
  93. }
  94. if (begin.first > end.second) {
  95. GOOGLE_LOG(DFATAL) << " Annotation has negative length from " << begin_varname
  96. << " to " << end_varname;
  97. } else {
  98. annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
  99. path);
  100. }
  101. }
  102. void Printer::Print(const std::map<std::string, std::string>& variables,
  103. const char* text) {
  104. int size = strlen(text);
  105. int pos = 0; // The number of bytes we've written so far.
  106. substitutions_.clear();
  107. line_start_variables_.clear();
  108. for (int i = 0; i < size; i++) {
  109. if (text[i] == '\n') {
  110. // Saw newline. If there is more text, we may need to insert an indent
  111. // here. So, write what we have so far, including the '\n'.
  112. WriteRaw(text + pos, i - pos + 1);
  113. pos = i + 1;
  114. // Setting this true will cause the next WriteRaw() to insert an indent
  115. // first.
  116. at_start_of_line_ = true;
  117. line_start_variables_.clear();
  118. } else if (text[i] == variable_delimiter_) {
  119. // Saw the start of a variable name.
  120. // Write what we have so far.
  121. WriteRaw(text + pos, i - pos);
  122. pos = i + 1;
  123. // Find closing delimiter.
  124. const char* end = strchr(text + pos, variable_delimiter_);
  125. if (end == NULL) {
  126. GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
  127. end = text + pos;
  128. }
  129. int endpos = end - text;
  130. std::string varname(text + pos, endpos - pos);
  131. if (varname.empty()) {
  132. // Two delimiters in a row reduce to a literal delimiter character.
  133. WriteRaw(&variable_delimiter_, 1);
  134. } else {
  135. // Replace with the variable's value.
  136. std::map<std::string, std::string>::const_iterator iter =
  137. variables.find(varname);
  138. if (iter == variables.end()) {
  139. GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
  140. } else {
  141. if (at_start_of_line_ && iter->second.empty()) {
  142. line_start_variables_.push_back(varname);
  143. }
  144. WriteRaw(iter->second.data(), iter->second.size());
  145. std::pair<std::map<std::string, std::pair<size_t, size_t> >::iterator,
  146. bool>
  147. inserted = substitutions_.insert(std::make_pair(
  148. varname,
  149. std::make_pair(offset_ - iter->second.size(), offset_)));
  150. if (!inserted.second) {
  151. // This variable was used multiple times. Make its span have
  152. // negative length so we can detect it if it gets used in an
  153. // annotation.
  154. inserted.first->second = std::make_pair(1, 0);
  155. }
  156. }
  157. }
  158. // Advance past this variable.
  159. i = endpos;
  160. pos = endpos + 1;
  161. }
  162. }
  163. // Write the rest.
  164. WriteRaw(text + pos, size - pos);
  165. }
  166. void Printer::Indent() { indent_ += " "; }
  167. void Printer::Outdent() {
  168. if (indent_.empty()) {
  169. GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
  170. return;
  171. }
  172. indent_.resize(indent_.size() - 2);
  173. }
  174. void Printer::PrintRaw(const std::string& data) {
  175. WriteRaw(data.data(), data.size());
  176. }
  177. void Printer::PrintRaw(const char* data) {
  178. if (failed_) return;
  179. WriteRaw(data, strlen(data));
  180. }
  181. void Printer::WriteRaw(const char* data, int size) {
  182. if (failed_) return;
  183. if (size == 0) return;
  184. if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
  185. // Insert an indent.
  186. at_start_of_line_ = false;
  187. CopyToBuffer(indent_.data(), indent_.size());
  188. if (failed_) return;
  189. // Fix up empty variables (e.g., "{") that should be annotated as
  190. // coming after the indent.
  191. for (std::vector<std::string>::iterator i = line_start_variables_.begin();
  192. i != line_start_variables_.end(); ++i) {
  193. substitutions_[*i].first += indent_.size();
  194. substitutions_[*i].second += indent_.size();
  195. }
  196. }
  197. // If we're going to write any data, clear line_start_variables_, since
  198. // we've either updated them in the block above or they no longer refer to
  199. // the current line.
  200. line_start_variables_.clear();
  201. CopyToBuffer(data, size);
  202. }
  203. bool Printer::Next() {
  204. do {
  205. void* void_buffer;
  206. if (!output_->Next(&void_buffer, &buffer_size_)) {
  207. failed_ = true;
  208. return false;
  209. }
  210. buffer_ = reinterpret_cast<char*>(void_buffer);
  211. } while (buffer_size_ == 0);
  212. return true;
  213. }
  214. void Printer::CopyToBuffer(const char* data, int size) {
  215. if (failed_) return;
  216. if (size == 0) return;
  217. while (size > buffer_size_) {
  218. // Data exceeds space in the buffer. Copy what we can and request a
  219. // new buffer.
  220. if (buffer_size_ > 0) {
  221. memcpy(buffer_, data, buffer_size_);
  222. offset_ += buffer_size_;
  223. data += buffer_size_;
  224. size -= buffer_size_;
  225. }
  226. void* void_buffer;
  227. failed_ = !output_->Next(&void_buffer, &buffer_size_);
  228. if (failed_) return;
  229. buffer_ = reinterpret_cast<char*>(void_buffer);
  230. }
  231. // Buffer is big enough to receive the data; copy it.
  232. memcpy(buffer_, data, size);
  233. buffer_ += size;
  234. buffer_size_ -= size;
  235. offset_ += size;
  236. }
  237. void Printer::IndentIfAtStart() {
  238. if (at_start_of_line_) {
  239. CopyToBuffer(indent_.data(), indent_.size());
  240. at_start_of_line_ = false;
  241. }
  242. }
  243. void Printer::FormatInternal(const std::vector<std::string>& args,
  244. const std::map<std::string, std::string>& vars,
  245. const char* format) {
  246. auto save = format;
  247. int arg_index = 0;
  248. std::vector<AnnotationCollector::Annotation> annotations;
  249. while (*format) {
  250. char c = *format++;
  251. switch (c) {
  252. case '$':
  253. format = WriteVariable(args, vars, format, &arg_index, &annotations);
  254. continue;
  255. case '\n':
  256. at_start_of_line_ = true;
  257. line_start_variables_.clear();
  258. break;
  259. default:
  260. IndentIfAtStart();
  261. break;
  262. }
  263. push_back(c);
  264. }
  265. if (arg_index != args.size()) {
  266. GOOGLE_LOG(FATAL) << " Unused arguments. " << save;
  267. }
  268. if (!annotations.empty()) {
  269. GOOGLE_LOG(FATAL) << " Annotation range is not-closed, expect $}$. " << save;
  270. }
  271. }
  272. const char* Printer::WriteVariable(
  273. const std::vector<std::string>& args,
  274. const std::map<std::string, std::string>& vars, const char* format,
  275. int* arg_index, std::vector<AnnotationCollector::Annotation>* annotations) {
  276. auto start = format;
  277. auto end = strchr(format, '$');
  278. if (!end) {
  279. GOOGLE_LOG(FATAL) << " Unclosed variable name.";
  280. }
  281. format = end + 1;
  282. if (end == start) {
  283. // "$$" is an escape for just '$'
  284. IndentIfAtStart();
  285. push_back('$');
  286. return format;
  287. }
  288. if (*start == '{') {
  289. GOOGLE_CHECK(std::isdigit(start[1]));
  290. GOOGLE_CHECK_EQ(end - start, 2);
  291. int idx = start[1] - '1';
  292. if (idx < 0 || idx >= args.size()) {
  293. GOOGLE_LOG(FATAL) << "Annotation ${" << idx + 1 << "$ is out of bounds.";
  294. }
  295. if (idx > *arg_index) {
  296. GOOGLE_LOG(FATAL) << "Annotation arg must be in correct order as given. Expected"
  297. << " ${" << (*arg_index) + 1 << "$ got ${" << idx + 1 << "$.";
  298. } else if (idx == *arg_index) {
  299. (*arg_index)++;
  300. }
  301. IndentIfAtStart();
  302. annotations->push_back({{offset_, 0}, args[idx]});
  303. return format;
  304. } else if (*start == '}') {
  305. GOOGLE_CHECK(annotations);
  306. if (annotations->empty()) {
  307. GOOGLE_LOG(FATAL) << "Unexpected end of annotation found.";
  308. }
  309. auto& a = annotations->back();
  310. a.first.second = offset_;
  311. if (annotation_collector_) annotation_collector_->AddAnnotationNew(a);
  312. annotations->pop_back();
  313. return format;
  314. }
  315. auto start_var = start;
  316. while (start_var < end && *start_var == ' ') start_var++;
  317. if (start_var == end) {
  318. GOOGLE_LOG(FATAL) << " Empty variable.";
  319. }
  320. auto end_var = end;
  321. while (start_var < end_var && *(end_var - 1) == ' ') end_var--;
  322. std::string var_name{
  323. start_var, static_cast<std::string::size_type>(end_var - start_var)};
  324. std::string sub;
  325. if (std::isdigit(var_name[0])) {
  326. GOOGLE_CHECK_EQ(var_name.size(), 1); // No need for multi-digits
  327. int idx = var_name[0] - '1'; // Start counting at 1
  328. GOOGLE_CHECK_GE(idx, 0);
  329. if (idx >= args.size()) {
  330. GOOGLE_LOG(FATAL) << "Argument $" << idx + 1 << "$ is out of bounds.";
  331. }
  332. if (idx > *arg_index) {
  333. GOOGLE_LOG(FATAL) << "Arguments must be used in same order as given. Expected $"
  334. << (*arg_index) + 1 << "$ got $" << idx + 1 << "$.";
  335. } else if (idx == *arg_index) {
  336. (*arg_index)++;
  337. }
  338. sub = args[idx];
  339. } else {
  340. auto it = vars.find(var_name);
  341. if (it == vars.end()) {
  342. GOOGLE_LOG(FATAL) << " Unknown variable: " << var_name << ".";
  343. }
  344. sub = it->second;
  345. }
  346. // By returning here in case of empty we also skip possible spaces inside
  347. // the $...$, i.e. "void$ dllexpor$ f();" -> "void f();" in the empty case.
  348. if (sub.empty()) return format;
  349. // We're going to write something non-empty so we need a possible indent.
  350. IndentIfAtStart();
  351. // Write the possible spaces in front.
  352. CopyToBuffer(start, start_var - start);
  353. // Write a non-empty substituted variable.
  354. CopyToBuffer(sub.c_str(), sub.size());
  355. // Finish off with writing possible trailing spaces.
  356. CopyToBuffer(end_var, end - end_var);
  357. return format;
  358. }
  359. } // namespace io
  360. } // namespace protobuf
  361. } // namespace google