utility.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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. #include <google/protobuf/util/internal/utility.h>
  31. #include <algorithm>
  32. #include <google/protobuf/stubs/callback.h>
  33. #include <google/protobuf/stubs/common.h>
  34. #include <google/protobuf/stubs/logging.h>
  35. #include <google/protobuf/wrappers.pb.h>
  36. #include <google/protobuf/descriptor.pb.h>
  37. #include <google/protobuf/descriptor.h>
  38. #include <google/protobuf/util/internal/constants.h>
  39. #include <google/protobuf/stubs/strutil.h>
  40. #include <google/protobuf/stubs/map_util.h>
  41. #include <google/protobuf/stubs/mathlimits.h>
  42. namespace google {
  43. namespace protobuf {
  44. namespace util {
  45. namespace converter {
  46. bool GetBoolOptionOrDefault(
  47. const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
  48. const string& option_name, bool default_value) {
  49. const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  50. if (opt == nullptr) {
  51. return default_value;
  52. }
  53. return GetBoolFromAny(opt->value());
  54. }
  55. int64 GetInt64OptionOrDefault(
  56. const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
  57. const string& option_name, int64 default_value) {
  58. const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  59. if (opt == nullptr) {
  60. return default_value;
  61. }
  62. return GetInt64FromAny(opt->value());
  63. }
  64. double GetDoubleOptionOrDefault(
  65. const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
  66. const string& option_name, double default_value) {
  67. const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  68. if (opt == nullptr) {
  69. return default_value;
  70. }
  71. return GetDoubleFromAny(opt->value());
  72. }
  73. string GetStringOptionOrDefault(
  74. const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
  75. const string& option_name, const string& default_value) {
  76. const google::protobuf::Option* opt = FindOptionOrNull(options, option_name);
  77. if (opt == nullptr) {
  78. return default_value;
  79. }
  80. return GetStringFromAny(opt->value());
  81. }
  82. template <typename T>
  83. void ParseFromAny(const string& data, T* result) {
  84. result->ParseFromString(data);
  85. }
  86. // Returns a boolean value contained in Any type.
  87. // TODO(skarvaje): Add type checking & error messages here.
  88. bool GetBoolFromAny(const google::protobuf::Any& any) {
  89. google::protobuf::BoolValue b;
  90. ParseFromAny(any.value(), &b);
  91. return b.value();
  92. }
  93. int64 GetInt64FromAny(const google::protobuf::Any& any) {
  94. google::protobuf::Int64Value i;
  95. ParseFromAny(any.value(), &i);
  96. return i.value();
  97. }
  98. double GetDoubleFromAny(const google::protobuf::Any& any) {
  99. google::protobuf::DoubleValue i;
  100. ParseFromAny(any.value(), &i);
  101. return i.value();
  102. }
  103. string GetStringFromAny(const google::protobuf::Any& any) {
  104. google::protobuf::StringValue s;
  105. ParseFromAny(any.value(), &s);
  106. return s.value();
  107. }
  108. const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
  109. if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') {
  110. return type_url.substr(kTypeUrlSize + 1);
  111. } else {
  112. size_t idx = type_url.rfind('/');
  113. if (idx != type_url.npos) {
  114. type_url.remove_prefix(idx + 1);
  115. }
  116. return type_url;
  117. }
  118. }
  119. const string GetFullTypeWithUrl(StringPiece simple_type) {
  120. return StrCat(kTypeServiceBaseUrl, "/", simple_type);
  121. }
  122. const google::protobuf::Option* FindOptionOrNull(
  123. const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options,
  124. const string& option_name) {
  125. for (int i = 0; i < options.size(); ++i) {
  126. const google::protobuf::Option& opt = options.Get(i);
  127. if (opt.name() == option_name) {
  128. return &opt;
  129. }
  130. }
  131. return nullptr;
  132. }
  133. const google::protobuf::Field* FindFieldInTypeOrNull(
  134. const google::protobuf::Type* type, StringPiece field_name) {
  135. if (type != nullptr) {
  136. for (int i = 0; i < type->fields_size(); ++i) {
  137. const google::protobuf::Field& field = type->fields(i);
  138. if (field.name() == field_name) {
  139. return &field;
  140. }
  141. }
  142. }
  143. return nullptr;
  144. }
  145. const google::protobuf::Field* FindJsonFieldInTypeOrNull(
  146. const google::protobuf::Type* type, StringPiece json_name) {
  147. if (type != nullptr) {
  148. for (int i = 0; i < type->fields_size(); ++i) {
  149. const google::protobuf::Field& field = type->fields(i);
  150. if (field.json_name() == json_name) {
  151. return &field;
  152. }
  153. }
  154. }
  155. return nullptr;
  156. }
  157. const google::protobuf::Field* FindFieldInTypeByNumberOrNull(
  158. const google::protobuf::Type* type, int32 number) {
  159. if (type != nullptr) {
  160. for (int i = 0; i < type->fields_size(); ++i) {
  161. const google::protobuf::Field& field = type->fields(i);
  162. if (field.number() == number) {
  163. return &field;
  164. }
  165. }
  166. }
  167. return nullptr;
  168. }
  169. const google::protobuf::EnumValue* FindEnumValueByNameOrNull(
  170. const google::protobuf::Enum* enum_type, StringPiece enum_name) {
  171. if (enum_type != nullptr) {
  172. for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
  173. const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
  174. if (enum_value.name() == enum_name) {
  175. return &enum_value;
  176. }
  177. }
  178. }
  179. return nullptr;
  180. }
  181. const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
  182. const google::protobuf::Enum* enum_type, int32 value) {
  183. if (enum_type != nullptr) {
  184. for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
  185. const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
  186. if (enum_value.number() == value) {
  187. return &enum_value;
  188. }
  189. }
  190. }
  191. return nullptr;
  192. }
  193. const google::protobuf::EnumValue* FindEnumValueByNameWithoutUnderscoreOrNull(
  194. const google::protobuf::Enum* enum_type, StringPiece enum_name) {
  195. if (enum_type != nullptr) {
  196. for (int i = 0; i < enum_type->enumvalue_size(); ++i) {
  197. const google::protobuf::EnumValue& enum_value = enum_type->enumvalue(i);
  198. string enum_name_without_underscore = enum_value.name();
  199. // Remove underscore from the name.
  200. enum_name_without_underscore.erase(
  201. std::remove(enum_name_without_underscore.begin(),
  202. enum_name_without_underscore.end(), '_'),
  203. enum_name_without_underscore.end());
  204. // Make the name uppercase.
  205. for (string::iterator it = enum_name_without_underscore.begin();
  206. it != enum_name_without_underscore.end(); ++it) {
  207. *it = ascii_toupper(*it);
  208. }
  209. if (enum_name_without_underscore == enum_name) {
  210. return &enum_value;
  211. }
  212. }
  213. }
  214. return nullptr;
  215. }
  216. string EnumValueNameToLowerCamelCase(const StringPiece input) {
  217. string input_string(input);
  218. std::transform(input_string.begin(), input_string.end(), input_string.begin(),
  219. ::tolower);
  220. return ToCamelCase(input_string);
  221. }
  222. string ToCamelCase(const StringPiece input) {
  223. bool capitalize_next = false;
  224. bool was_cap = true;
  225. bool is_cap = false;
  226. bool first_word = true;
  227. string result;
  228. result.reserve(input.size());
  229. for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) {
  230. is_cap = ascii_isupper(input[i]);
  231. if (input[i] == '_') {
  232. capitalize_next = true;
  233. if (!result.empty()) first_word = false;
  234. continue;
  235. } else if (first_word) {
  236. // Consider when the current character B is capitalized,
  237. // first word ends when:
  238. // 1) following a lowercase: "...aB..."
  239. // 2) followed by a lowercase: "...ABc..."
  240. if (!result.empty() && is_cap &&
  241. (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) {
  242. first_word = false;
  243. result.push_back(input[i]);
  244. } else {
  245. result.push_back(ascii_tolower(input[i]));
  246. continue;
  247. }
  248. } else if (capitalize_next) {
  249. capitalize_next = false;
  250. if (ascii_islower(input[i])) {
  251. result.push_back(ascii_toupper(input[i]));
  252. continue;
  253. } else {
  254. result.push_back(input[i]);
  255. continue;
  256. }
  257. } else {
  258. result.push_back(ascii_tolower(input[i]));
  259. }
  260. }
  261. return result;
  262. }
  263. string ToSnakeCase(StringPiece input) {
  264. bool was_not_underscore = false; // Initialize to false for case 1 (below)
  265. bool was_not_cap = false;
  266. string result;
  267. result.reserve(input.size() << 1);
  268. for (size_t i = 0; i < input.size(); ++i) {
  269. if (ascii_isupper(input[i])) {
  270. // Consider when the current character B is capitalized:
  271. // 1) At beginning of input: "B..." => "b..."
  272. // (e.g. "Biscuit" => "biscuit")
  273. // 2) Following a lowercase: "...aB..." => "...a_b..."
  274. // (e.g. "gBike" => "g_bike")
  275. // 3) At the end of input: "...AB" => "...ab"
  276. // (e.g. "GoogleLAB" => "google_lab")
  277. // 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
  278. // (e.g. "GBike" => "g_bike")
  279. if (was_not_underscore && // case 1 out
  280. (was_not_cap || // case 2 in, case 3 out
  281. (i + 1 < input.size() && // case 3 out
  282. ascii_islower(input[i + 1])))) { // case 4 in
  283. // We add an underscore for case 2 and case 4.
  284. result.push_back('_');
  285. }
  286. result.push_back(ascii_tolower(input[i]));
  287. was_not_underscore = true;
  288. was_not_cap = false;
  289. } else {
  290. result.push_back(input[i]);
  291. was_not_underscore = input[i] != '_';
  292. was_not_cap = true;
  293. }
  294. }
  295. return result;
  296. }
  297. std::set<string>* well_known_types_ = NULL;
  298. GOOGLE_PROTOBUF_DECLARE_ONCE(well_known_types_init_);
  299. const char* well_known_types_name_array_[] = {
  300. "google.protobuf.Timestamp", "google.protobuf.Duration",
  301. "google.protobuf.DoubleValue", "google.protobuf.FloatValue",
  302. "google.protobuf.Int64Value", "google.protobuf.UInt64Value",
  303. "google.protobuf.Int32Value", "google.protobuf.UInt32Value",
  304. "google.protobuf.BoolValue", "google.protobuf.StringValue",
  305. "google.protobuf.BytesValue", "google.protobuf.FieldMask"};
  306. void DeleteWellKnownTypes() { delete well_known_types_; }
  307. void InitWellKnownTypes() {
  308. well_known_types_ = new std::set<string>;
  309. for (int i = 0; i < GOOGLE_ARRAYSIZE(well_known_types_name_array_); ++i) {
  310. well_known_types_->insert(well_known_types_name_array_[i]);
  311. }
  312. google::protobuf::internal::OnShutdown(&DeleteWellKnownTypes);
  313. }
  314. bool IsWellKnownType(const string& type_name) {
  315. InitWellKnownTypes();
  316. return ContainsKey(*well_known_types_, type_name);
  317. }
  318. bool IsValidBoolString(const string& bool_string) {
  319. return bool_string == "true" || bool_string == "false" ||
  320. bool_string == "1" || bool_string == "0";
  321. }
  322. bool IsMap(const google::protobuf::Field& field,
  323. const google::protobuf::Type& type) {
  324. return field.cardinality() ==
  325. google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
  326. (GetBoolOptionOrDefault(type.options(), "map_entry", false) ||
  327. GetBoolOptionOrDefault(type.options(),
  328. "google.protobuf.MessageOptions.map_entry",
  329. false));
  330. }
  331. bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
  332. return GetBoolOptionOrDefault(type.options(), "message_set_wire_format",
  333. false) ||
  334. GetBoolOptionOrDefault(
  335. type.options(),
  336. "google.protobuf.MessageOptions.message_set_wire_format", false);
  337. }
  338. string DoubleAsString(double value) {
  339. if (MathLimits<double>::IsPosInf(value)) return "Infinity";
  340. if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
  341. if (MathLimits<double>::IsNaN(value)) return "NaN";
  342. return SimpleDtoa(value);
  343. }
  344. string FloatAsString(float value) {
  345. if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
  346. return DoubleAsString(value);
  347. }
  348. bool SafeStrToFloat(StringPiece str, float* value) {
  349. double double_value;
  350. if (!safe_strtod(str, &double_value)) {
  351. return false;
  352. }
  353. if (MathLimits<double>::IsInf(double_value) ||
  354. MathLimits<double>::IsNaN(double_value))
  355. return false;
  356. // Fail if the value is not representable in float.
  357. if (double_value > std::numeric_limits<float>::max() ||
  358. double_value < -std::numeric_limits<float>::max()) {
  359. return false;
  360. }
  361. *value = static_cast<float>(double_value);
  362. return true;
  363. }
  364. bool StringStartsWith(StringPiece text, StringPiece prefix) {
  365. return text.starts_with(prefix);
  366. }
  367. bool StringEndsWith(StringPiece text, StringPiece suffix) {
  368. return text.ends_with(suffix);
  369. }
  370. } // namespace converter
  371. } // namespace util
  372. } // namespace protobuf
  373. } // namespace google