26 #ifndef GOBY_MOOS_MOOS_PROTOBUF_HELPERS_H
27 #define GOBY_MOOS_MOOS_PROTOBUF_HELPERS_H
44 #include <boost/algorithm/string/case_conv.hpp>
45 #include <boost/algorithm/string/classification.hpp>
46 #include <boost/algorithm/string/erase.hpp>
47 #include <boost/algorithm/string/replace.hpp>
48 #include <boost/algorithm/string/split.hpp>
49 #include <boost/algorithm/string/trim.hpp>
50 #include <boost/core/enable_if.hpp>
51 #include <boost/format.hpp>
52 #include <boost/lexical_cast.hpp>
53 #include <boost/lexical_cast/bad_lexical_cast.hpp>
54 #include <google/protobuf/descriptor.h>
56 #include <google/protobuf/text_format.h>
58 #include "dccl/dynamic_protobuf_manager.h"
77 inline std::map<int, std::string>
82 const google::protobuf::Descriptor* desc = in.
GetDescriptor();
85 std::map<int, std::string> modified_values;
87 for (
const auto& algorithm : algorithms)
89 const google::protobuf::FieldDescriptor* primary_field_desc =
90 desc->FindFieldByNumber(algorithm.primary_field());
92 if (!primary_field_desc || primary_field_desc->is_repeated())
95 std::string primary_val;
97 if (!modified_values.count(algorithm.output_virtual_field()))
99 google::protobuf::TextFormat::PrintFieldValueToString(in, primary_field_desc, -1,
101 boost::trim_if(primary_val, boost::is_any_of(
"\""));
105 primary_val = modified_values[algorithm.output_virtual_field()];
109 std::vector<goby::moos::transitional::DCCLMessageVal> ref;
110 for (
int i = 0, m = algorithm.reference_field_size(); i < m; ++i)
112 const google::protobuf::FieldDescriptor* field_desc =
113 desc->FindFieldByNumber(algorithm.reference_field(i));
115 if (field_desc && !field_desc->is_repeated())
117 std::string ref_value;
118 google::protobuf::TextFormat::PrintFieldValueToString(in, field_desc, -1,
120 ref.emplace_back(ref_value);
125 std::runtime_error(
"Reference field given is invalid or repeated (must be "
126 "optional or required): " +
127 goby::util::as<std::string>(algorithm.reference_field(i))));
134 val = std::string(val);
135 modified_values[algorithm.output_virtual_field()] = std::string(val);
138 return modified_values;
142 const std::string& field_name)
144 return boost::ierase_first_copy(enum_value, field_name +
"_");
147 inline std::string
add_name_to_enum(
const std::string& enum_value,
const std::string& field_name)
149 return boost::to_upper_copy(field_name) +
"_" + enum_value;
152 template <goby::moos::protobuf::TranslatorEntry::ParserSerializerTechnique technique>
157 template <>
class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_TEXT_FORMAT>
162 google::protobuf::TextFormat::Printer printer;
163 printer.SetSingleLineMode(
true);
164 printer.PrintToString(in, out);
169 google::protobuf::TextFormat::Parser parser;
171 parser.RecordErrorsTo(&error_collector);
172 parser.ParseFromString(in, out);
176 template <>
class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_ENCODED>
190 template <>
class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_HEX>
195 std::string native_encoded;
198 serialize(&native_encoded, in);
204 std::string native_encoded;
207 TECHNIQUE_PROTOBUF_NATIVE_ENCODED>::parse(native_encoded,
222 *out = header + *out;
231 size_t end_bracket_pos = in.find(
']');
233 if (end_bracket_pos == std::string::npos)
234 throw(std::runtime_error(
235 "Incorrectly formatted protobuf message passed to MOOSTranslation<" +
243 if (name !=
msg->GetDescriptor()->full_name())
244 throw(std::runtime_error(
245 "Wrong Protobuf type passed to MOOSTranslation<" +
248 ">::parse. Expected: " +
msg->GetDescriptor()->full_name() +
249 ", received: " + name));
251 if (in.size() > end_bracket_pos + 2)
263 static std::shared_ptr<google::protobuf::Message>
dynamic_parse(
const std::string& in)
269 size_t end_bracket_pos = in.find(
']');
271 if (end_bracket_pos == std::string::npos)
272 throw(std::runtime_error(
273 "Incorrectly formatted protobuf message passed to MOOSTranslation<" +
276 ">::dynamic_parse."));
287 auto return_message = dccl::DynamicProtobufManager::new_protobuf_message<
288 std::shared_ptr<google::protobuf::Message>>(name);
289 if (in.size() > end_bracket_pos + 1)
291 in.substr(end_bracket_pos + 1), return_message.get());
292 return return_message;
294 catch (std::exception&
e)
296 return std::shared_ptr<google::protobuf::Message>();
301 return std::shared_ptr<google::protobuf::Message>();
307 class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT>
309 protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT,
310 protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_TEXT_FORMAT>
314 class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED>
316 protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED,
317 protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_ENCODED>
321 class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX>
323 protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX,
324 protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_HEX>
329 class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_COMMA_SEPARATED_KEY_EQUALS_VALUE_PAIRS>
337 bool use_short_enum =
false)
339 std::stringstream out_ss;
341 const google::protobuf::Descriptor* desc = in.
GetDescriptor();
344 int included_fields = 0;
345 for (
int i = 0, n = desc->field_count(); i < n; ++i)
347 const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
350 if ((!field_desc->is_repeated() && !refl->
HasField(in, field_desc)) ||
351 (field_desc->is_repeated() && refl->
FieldSize(in, field_desc) == 0))
358 const std::string& field_name = field_desc->name();
360 switch (field_desc->cpp_type())
363 out_ss << to_moos_comma_equals_string_field(in, field_desc,
true,
367 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
368 if (field_desc->is_repeated())
370 for (
int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
374 out_ss << field_name <<
"_"
375 << field_desc->message_type()->field(k)->name() <<
"={";
376 for (
int j = 0, m = refl->
FieldSize(in, field_desc); j < m; ++j)
382 out_ss << to_moos_comma_equals_string_field(
392 for (
int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
396 out_ss << field_name <<
"_"
397 << field_desc->message_type()->field(k)->name() <<
"=";
400 out_ss << to_moos_comma_equals_string_field(
411 for (
const auto& additional_value : additional_values)
416 int primary_field = 0;
417 for (
const auto& algorithm : algorithms)
419 if (algorithm.output_virtual_field() == additional_value.first)
424 key += algorithm.name();
425 primary_field = algorithm.primary_field();
428 key +=
"(" + desc->FindFieldByNumber(primary_field)->name() +
")";
430 out_ss << key <<
"=" << additional_value.second;
441 bool use_short_enum =
false)
443 const google::protobuf::Descriptor* desc = out->
GetDescriptor();
448 for (
int i = 0, n = desc->field_count(); i < n; ++i)
450 const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
452 switch (field_desc->cpp_type())
461 for (
const auto& algorithm : algorithms)
465 if (algorithm.primary_field() == field_desc->number())
468 algorithm.name(), extract_val,
469 std::vector<goby::moos::transitional::DCCLMessageVal>());
471 val = std::string(extract_val);
474 std::vector<std::string> vals;
476 from_moos_comma_equals_string_field(out, field_desc, vals, 0,
482 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
483 if (field_desc->is_repeated())
485 for (
int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
490 field_desc->name() +
"_" +
491 field_desc->message_type()->field(k)->name()))
493 std::vector<std::string> vals;
496 for (
int j = 0, m = vals.size(); j < m; ++j)
499 (refl->
FieldSize(*out, field_desc) < j + 1)
502 from_moos_comma_equals_string_field(
511 for (
int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
516 field_desc->name() +
"_" +
517 field_desc->message_type()->field(k)->name()))
519 std::vector<std::string> vals;
524 from_moos_comma_equals_string_field(
525 embedded_msg, embedded_msg->
GetDescriptor()->field(k), vals, 0,
538 const google::protobuf::FieldDescriptor* field_desc,
539 bool write_key =
true,
bool use_short_enum =
false)
543 std::stringstream out;
544 const std::string& field_name = field_desc->name();
546 if (field_desc->is_repeated())
549 out << field_name <<
"={";
551 for (
int j = 0, m = refl->
FieldSize(proto_msg, field_desc); j < m; ++j)
556 switch (field_desc->cpp_type())
558 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
563 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
567 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
571 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
575 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
579 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
580 out << std::boolalpha << refl->
GetRepeatedBool(proto_msg, field_desc, j);
583 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
584 if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_STRING)
586 else if (field_desc->type() ==
587 google::protobuf::FieldDescriptor::TYPE_BYTES)
592 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
593 out << std::setprecision(std::numeric_limits<float>::digits10)
597 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
598 out << std::setprecision(std::numeric_limits<double>::digits10)
602 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
603 out << ((use_short_enum)
618 out << field_name <<
"=";
619 switch (field_desc->cpp_type())
621 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
626 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
627 out << refl->
GetInt32(proto_msg, field_desc);
630 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
631 out << refl->
GetInt64(proto_msg, field_desc);
634 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
635 out << refl->
GetUInt32(proto_msg, field_desc);
638 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
639 out << refl->
GetUInt64(proto_msg, field_desc);
642 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
643 out << std::boolalpha << refl->
GetBool(proto_msg, field_desc);
646 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
647 if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_STRING)
648 out << refl->
GetString(proto_msg, field_desc);
649 else if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_BYTES)
653 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
654 out << std::setprecision(std::numeric_limits<float>::digits10)
655 << refl->
GetFloat(proto_msg, field_desc);
658 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
659 out << std::setprecision(std::numeric_limits<double>::digits10)
660 << refl->
GetDouble(proto_msg, field_desc);
663 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
664 out << ((use_short_enum)
667 : refl->
GetEnum(proto_msg, field_desc)->name());
673 static void from_moos_comma_equals_string_field(
675 const std::vector<std::string>& values,
int value_key = 0,
bool use_short_enum =
false)
677 if (values.size() == 0)
681 if (field_desc->is_repeated())
683 for (
const auto& v : values)
685 switch (field_desc->cpp_type())
687 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
692 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
693 refl->
AddInt32(proto_msg, field_desc,
694 goby::util::as<google::protobuf::int32>(v));
697 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
698 refl->
AddInt64(proto_msg, field_desc,
699 goby::util::as<google::protobuf::int64>(v));
702 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
704 goby::util::as<google::protobuf::uint32>(v));
707 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
709 goby::util::as<google::protobuf::uint64>(v));
712 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
713 refl->
AddBool(proto_msg, field_desc, goby::util::as<bool>(v));
716 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
717 if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_STRING)
718 refl->
AddString(proto_msg, field_desc, v);
719 else if (field_desc->type() ==
720 google::protobuf::FieldDescriptor::TYPE_BYTES)
724 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
725 refl->
AddFloat(proto_msg, field_desc, goby::util::as<float>(v));
728 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
729 refl->
AddDouble(proto_msg, field_desc, goby::util::as<double>(v));
732 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
734 std::string enum_value =
737 const google::protobuf::EnumValueDescriptor* enum_desc =
738 field_desc->enum_type()->FindValueByName(enum_value);
742 enum_desc = field_desc->enum_type()->FindValueByName(
743 boost::algorithm::to_upper_copy(enum_value));
746 enum_desc = field_desc->enum_type()->FindValueByName(
747 boost::algorithm::to_lower_copy(enum_value));
750 refl->
AddEnum(proto_msg, field_desc, enum_desc);
758 const std::string& v = values[value_key];
759 switch (field_desc->cpp_type())
761 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
766 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
767 refl->
SetInt32(proto_msg, field_desc,
768 goby::util::as<google::protobuf::int32>(v));
771 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
772 refl->
SetInt64(proto_msg, field_desc,
773 goby::util::as<google::protobuf::int64>(v));
776 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
778 goby::util::as<google::protobuf::uint32>(v));
781 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
783 goby::util::as<google::protobuf::uint64>(v));
786 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
787 refl->
SetBool(proto_msg, field_desc, goby::util::as<bool>(v));
790 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
791 if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_STRING)
792 refl->
SetString(proto_msg, field_desc, v);
793 else if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_BYTES)
797 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
798 refl->
SetFloat(proto_msg, field_desc, goby::util::as<float>(v));
801 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
802 refl->
SetDouble(proto_msg, field_desc, goby::util::as<double>(v));
805 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
807 std::string enum_value =
810 const google::protobuf::EnumValueDescriptor* enum_desc =
811 field_desc->enum_type()->FindValueByName(enum_value);
815 enum_desc = field_desc->enum_type()->FindValueByName(
816 boost::algorithm::to_upper_copy(enum_value));
819 enum_desc = field_desc->enum_type()->FindValueByName(
820 boost::algorithm::to_lower_copy(enum_value));
823 refl->
SetEnum(proto_msg, field_desc, enum_desc);
834 struct RepeatedFieldKey
843 const std::string& format,
const std::string& repeated_delimiter,
844 bool use_short_enum =
false)
846 std::string mutable_format = format;
848 const google::protobuf::Descriptor* desc = in.
GetDescriptor();
851 int max_field_number = 1;
852 for (
int i = 1, n = desc->field_count(); i < n; ++i)
854 const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
855 if (field_desc->number() > max_field_number)
856 max_field_number = field_desc->number();
862 for (
const auto& modified_value : modified_values)
864 if (modified_value.first > max_field_number)
865 max_field_number = modified_value.first;
868 std::string mutable_format_temp = mutable_format;
870 std::regex moos_index_regex(
"%([0-9\\.]+:)+[0-9\\.]+%");
871 for (std::sregex_iterator
872 it(mutable_format.begin(), mutable_format.end(), moos_index_regex),
876 std::string match = (*it)[0];
878 boost::trim_if(match, boost::is_any_of(
"%"));
879 std::vector<std::string> subfields;
884 const google::protobuf::FieldDescriptor* field_desc =
nullptr;
888 for (
int i = 0, n = subfields.size() - 1; i < n; ++i)
890 std::vector<std::string> field_and_index;
891 boost::split(field_and_index, subfields[i], boost::is_any_of(
"."));
893 field_desc = sub_message->
GetDescriptor()->FindFieldByNumber(
894 goby::util::as<int>(field_and_index[0]));
896 field_desc->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
898 throw(std::runtime_error(
899 "Invalid ':' syntax given for format: " + match +
900 ". All field indices except the last must be embedded messages"));
902 if (field_desc->is_repeated() && field_and_index.size() != 2)
904 throw(std::runtime_error(
"Invalid '.' syntax given for format: " + match +
905 ". Repeated message, but no valid index given. E.g., "
906 "use '3.4' for index 4 of field 3."));
910 (field_desc->is_repeated())
912 goby::util::as<int>(field_and_index[1]))
913 : &sub_refl->
GetMessage(*sub_message, field_desc);
917 serialize(&modified_values[max_field_number], *sub_message, algorithms,
918 "%" + subfields[subfields.size() - 1] +
"%", repeated_delimiter,
922 mutable_format_temp, std::string(
"%" + match +
"%"),
923 std::string(
"%" + goby::util::as<std::string>(max_field_number) +
"%"));
926 mutable_format = mutable_format_temp;
928 std::map<int, RepeatedFieldKey> indexed_repeated_fields;
930 std::regex repeated_field_regex(
"%[0-9]+\\.[0-9]+%");
931 for (std::sregex_iterator
932 it(mutable_format.begin(), mutable_format.end(), repeated_field_regex),
936 std::string match = (*it)[0];
937 boost::trim_if(match, boost::is_any_of(
"%"));
942 mutable_format_temp, std::string(
"%" + match +
"%"),
943 std::string(
"%" + goby::util::as<std::string>(max_field_number) +
"%"));
945 RepeatedFieldKey key;
947 std::vector<std::string> field_and_index;
948 boost::split(field_and_index, match, boost::is_any_of(
"."));
950 key.field = goby::util::as<int>(field_and_index[0]);
951 key.index = goby::util::as<int>(field_and_index[1]);
953 indexed_repeated_fields[max_field_number] = key;
956 mutable_format = mutable_format_temp;
958 boost::format out_format(mutable_format);
959 out_format.exceptions(boost::io::all_error_bits ^
960 (boost::io::too_many_args_bit | boost::io::too_few_args_bit));
962 for (
int i = 1; i <= max_field_number; ++i)
964 bool is_indexed_repeated_field = indexed_repeated_fields.count(i);
966 const google::protobuf::FieldDescriptor* field_desc = desc->FindFieldByNumber(
967 is_indexed_repeated_field ? indexed_repeated_fields[i].
field : i);
968 std::map<int, std::string>::const_iterator mod_it = modified_values.find(i);
971 if (field_desc->is_repeated())
973 int start = (is_indexed_repeated_field) ? indexed_repeated_fields[i].index : 0;
974 int end = (is_indexed_repeated_field) ? indexed_repeated_fields[i].index + 1
977 std::stringstream out_repeated;
978 for (
int j = start; j < end; ++j)
980 if (j && !is_indexed_repeated_field)
981 out_repeated << repeated_delimiter;
982 switch (field_desc->cpp_type())
984 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
990 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
991 out_repeated << ((j < refl->
FieldSize(in, field_desc))
993 : std::numeric_limits<std::int32_t>::max());
997 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
998 out_repeated << ((j < refl->
FieldSize(in, field_desc))
1000 : std::numeric_limits<std::int64_t>::max());
1003 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
1004 out_repeated << ((j < refl->
FieldSize(in, field_desc))
1006 : std::numeric_limits<std::uint32_t>::max());
1009 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
1010 out_repeated << ((j < refl->
FieldSize(in, field_desc))
1012 : std::numeric_limits<std::uint64_t>::max());
1015 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
1016 out_repeated << std::boolalpha
1017 << ((j < refl->
FieldSize(in, field_desc))
1019 : field_desc->default_value_bool());
1022 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
1023 if (field_desc->type() ==
1024 google::protobuf::FieldDescriptor::TYPE_STRING)
1026 << ((j < refl->FieldSize(in, field_desc))
1028 : field_desc->default_value_string());
1029 else if (field_desc->type() ==
1030 google::protobuf::FieldDescriptor::TYPE_BYTES)
1032 ((j < refl->FieldSize(in, field_desc))
1034 : field_desc->default_value_string()));
1037 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
1039 << std::setprecision(std::numeric_limits<float>::digits10)
1040 << ((j < refl->
FieldSize(in, field_desc))
1042 : std::numeric_limits<float>::quiet_NaN());
1045 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
1047 << std::setprecision(std::numeric_limits<double>::digits10)
1048 << ((j < refl->
FieldSize(in, field_desc))
1050 : std::numeric_limits<double>::quiet_NaN());
1053 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
1055 const google::protobuf::EnumValueDescriptor* enum_val =
1058 : field_desc->default_value_enum());
1062 : enum_val->name());
1067 out_format % out_repeated.str();
1071 switch (field_desc->cpp_type())
1073 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
1078 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
1079 out_format % refl->
GetInt32(in, field_desc);
1082 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
1083 out_format % refl->
GetInt64(in, field_desc);
1086 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
1087 out_format % refl->
GetUInt32(in, field_desc);
1090 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
1091 out_format % refl->
GetUInt64(in, field_desc);
1094 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
1095 out_format % goby::util::as<std::string>(refl->
GetBool(in, field_desc));
1098 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
1099 if (field_desc->type() ==
1100 google::protobuf::FieldDescriptor::TYPE_STRING)
1101 out_format % refl->
GetString(in, field_desc);
1102 else if (field_desc->type() ==
1103 google::protobuf::FieldDescriptor::TYPE_BYTES)
1108 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
1110 std::numeric_limits<float>::digits10),
1114 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
1117 std::setprecision(std::numeric_limits<double>::digits10),
1121 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
1127 : refl->
GetEnum(in, field_desc)->name());
1132 else if (mod_it != modified_values.end())
1134 out_format % mod_it->second;
1138 out_format %
"unknown";
1142 *out = out_format.str();
1146 const std::string& repeated_delimiter,
1151 bool use_short_enum =
false)
1153 const google::protobuf::Descriptor* desc = out->
GetDescriptor();
1156 std::string
str = in;
1157 std::string lower_str = boost::to_lower_copy(in);
1163 std::string::const_iterator i = format.begin();
1165 while (i != format.end())
1170 std::string specifier;
1171 while (*i !=
'%') specifier += *i++;
1174 std::string extract =
str.substr(0, lower_str.find(*i));
1176 if (specifier.find(
':') != std::string::npos)
1178 std::vector<std::string> subfields;
1179 boost::split(subfields, specifier, boost::is_any_of(
":"));
1180 const google::protobuf::FieldDescriptor* field_desc =
nullptr;
1184 for (
int i = 0, n = subfields.size() - 1; i < n; ++i)
1186 std::vector<std::string> field_and_index;
1187 boost::split(field_and_index, subfields[i], boost::is_any_of(
"."));
1189 field_desc = sub_message->
GetDescriptor()->FindFieldByNumber(
1190 goby::util::as<int>(field_and_index[0]));
1191 if (!field_desc || field_desc->cpp_type() !=
1192 google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
1194 throw(std::runtime_error(
1195 "Invalid ':' syntax given for format: " + specifier +
1196 ". All field indices except the last must be singular embedded "
1201 if (field_desc->is_repeated())
1203 if (field_and_index.size() != 2)
1204 throw(std::runtime_error(
1205 "Invalid '.' syntax given for format: " + specifier +
1206 ". Repeated message, but no valid index given. E.g., use '3.4' "
1207 "for index 4 of field 3."));
1208 index = goby::util::as<int>(field_and_index.at(1));
1209 while (sub_refl->
FieldSize(*sub_message, field_desc) <= index)
1210 sub_refl->
AddMessage(sub_message, field_desc);
1214 (field_desc->is_repeated())
1220 parse(extract, sub_message,
"%" + subfields[subfields.size() - 1] +
"%",
1221 repeated_delimiter, algorithms, use_short_enum);
1227 std::vector<std::string> field_and_index;
1228 boost::split(field_and_index, specifier, boost::is_any_of(
"."));
1230 int field_index = boost::lexical_cast<int>(field_and_index[0]);
1231 bool is_indexed_repeated_field = field_and_index.size() == 2;
1233 int value_index = 0;
1234 if (is_indexed_repeated_field)
1235 value_index = boost::lexical_cast<int>(field_and_index[1]);
1237 const google::protobuf::FieldDescriptor* field_desc =
1238 desc->FindFieldByNumber(field_index);
1241 throw(std::runtime_error(
"Bad field: " + specifier +
1242 " not in message " + desc->full_name()));
1245 for (
const auto& algorithm : algorithms)
1249 if (algorithm.primary_field() == field_index)
1252 algorithm.name(), extract_val,
1253 std::vector<goby::moos::transitional::DCCLMessageVal>());
1255 extract = std::string(extract_val);
1258 std::vector<std::string> parts;
1259 if (is_indexed_repeated_field || !field_desc->is_repeated())
1260 parts.push_back(extract);
1262 boost::split(parts, extract, boost::is_any_of(repeated_delimiter));
1264 for (
auto& part : parts)
1266 switch (field_desc->cpp_type())
1268 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
1269 if (is_indexed_repeated_field)
1271 while (refl->
FieldSize(*out, field_desc) <= value_index)
1274 field_desc->is_repeated()
1275 ? (is_indexed_repeated_field
1286 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
1287 if (is_indexed_repeated_field)
1289 while (refl->
FieldSize(*out, field_desc) <= value_index)
1291 field_desc->default_value_int32());
1293 field_desc->is_repeated()
1294 ? (is_indexed_repeated_field
1296 out, field_desc, value_index,
1297 goby::util::as<google::protobuf::int32>(part))
1300 goby::util::as<google::protobuf::int32>(part)))
1303 goby::util::as<google::protobuf::int32>(part));
1306 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
1307 if (is_indexed_repeated_field)
1309 while (refl->
FieldSize(*out, field_desc) <= value_index)
1311 field_desc->default_value_int64());
1313 field_desc->is_repeated()
1314 ? (is_indexed_repeated_field
1316 out, field_desc, value_index,
1317 goby::util::as<google::protobuf::int64>(part))
1320 goby::util::as<google::protobuf::int64>(part)))
1323 goby::util::as<google::protobuf::int64>(part));
1326 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
1327 if (is_indexed_repeated_field)
1329 while (refl->
FieldSize(*out, field_desc) <= value_index)
1331 field_desc->default_value_uint32());
1333 field_desc->is_repeated()
1334 ? (is_indexed_repeated_field
1336 out, field_desc, value_index,
1337 goby::util::as<google::protobuf::uint32>(part))
1340 goby::util::as<google::protobuf::uint32>(
1344 goby::util::as<google::protobuf::uint32>(part));
1347 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
1348 if (is_indexed_repeated_field)
1350 while (refl->
FieldSize(*out, field_desc) <= value_index)
1352 field_desc->default_value_uint64());
1354 field_desc->is_repeated()
1355 ? (is_indexed_repeated_field
1357 out, field_desc, value_index,
1358 goby::util::as<google::protobuf::uint64>(part))
1361 goby::util::as<google::protobuf::uint64>(
1365 goby::util::as<google::protobuf::uint64>(part));
1368 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
1369 if (is_indexed_repeated_field)
1371 while (refl->
FieldSize(*out, field_desc) <= value_index)
1372 refl->
AddBool(out, field_desc,
1373 field_desc->default_value_bool());
1375 field_desc->is_repeated()
1376 ? (is_indexed_repeated_field
1378 goby::util::as<bool>(part))
1379 : refl->
AddBool(out, field_desc,
1380 goby::util::as<bool>(part)))
1381 : refl->
SetBool(out, field_desc,
1382 goby::util::as<bool>(part));
1385 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
1386 if (is_indexed_repeated_field)
1388 while (refl->
FieldSize(*out, field_desc) <= value_index)
1390 field_desc->default_value_string());
1392 field_desc->is_repeated()
1393 ? (is_indexed_repeated_field
1396 : refl->
AddString(out, field_desc, part))
1397 : refl->
SetString(out, field_desc, part);
1400 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
1401 if (is_indexed_repeated_field)
1403 while (refl->
FieldSize(*out, field_desc) <= value_index)
1405 field_desc->default_value_float());
1407 field_desc->is_repeated()
1408 ? (is_indexed_repeated_field
1411 goby::util::as<float>(part))
1413 goby::util::as<float>(part)))
1415 goby::util::as<float>(part));
1418 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
1419 if (is_indexed_repeated_field)
1421 while (refl->
FieldSize(*out, field_desc) <= value_index)
1423 field_desc->default_value_double());
1425 field_desc->is_repeated()
1426 ? (is_indexed_repeated_field
1428 out, field_desc, value_index,
1429 goby::util::as<double>(part))
1431 goby::util::as<double>(part)))
1433 goby::util::as<double>(part));
1436 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
1438 if (is_indexed_repeated_field)
1440 while (refl->
FieldSize(*out, field_desc) <= value_index)
1441 refl->
AddEnum(out, field_desc,
1442 field_desc->default_value_enum());
1444 std::string enum_value =
1449 const google::protobuf::EnumValueDescriptor* enum_desc =
1450 refl->
GetEnum(*out, field_desc)
1452 ->FindValueByName(enum_value);
1457 refl->
GetEnum(*out, field_desc)
1459 ->FindValueByName(boost::to_upper_copy(enum_value));
1463 refl->
GetEnum(*out, field_desc)
1465 ->FindValueByName(boost::to_lower_copy(enum_value));
1468 field_desc->is_repeated()
1469 ? (is_indexed_repeated_field
1471 value_index, enum_desc)
1472 : refl->
AddEnum(out, field_desc, enum_desc))
1473 : refl->
SetEnum(out, field_desc, enum_desc);
1480 catch (boost::bad_lexical_cast&)
1482 throw(std::runtime_error(
1483 "Bad specifier: " + specifier +
1484 ", must be an integer. For message: " + desc->full_name()));
1493 std::string::size_type pos_to_remove = lower_str.find(*i) + 1;
1494 lower_str.erase(0, pos_to_remove);
1495 str.erase(0, pos_to_remove);
1544 TECHNIQUE_PROTOBUF_NATIVE_ENCODED>::serialize(out,
msg);
1548 TECHNIQUE_PROTOBUF_NATIVE_HEX>::serialize(out,
msg);
1552 TECHNIQUE_PROTOBUF_TEXT_FORMAT>::serialize(out,
msg);
1557 serialize(out,
msg);
1561 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX>::serialize(out,
1567 serialize(out,
msg);
1572 <<
"Non-PROTOBUF techniques are not supported for 'moos_parser_technique': "
1590 TECHNIQUE_PROTOBUF_NATIVE_ENCODED>::parse(in,
msg);
1605 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED>::parse(in,
1610 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX>::parse(in,
msg);
1614 TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT>::parse(in,
1620 <<
"Non-PROTOBUF techniques are not supported for 'moos_parser_technique': "
1649 goby::glog <<
"Non-PREFIX techniques are not supported when using "
1650 "dynamic_parse_for_moos for 'moos_parser_technique': "
1654 return std::shared_ptr<google::protobuf::Message>();