Goby3 3.2.3
2025.05.13
Loading...
Searching...
No Matches
moos_protobuf_helpers.h
Go to the documentation of this file.
1// Copyright 2009-2021:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7// Russ Webber <russ@rw.id.au>
8//
9//
10// This file is part of the Goby Underwater Autonomy Project Libraries
11// ("The Goby Libraries").
12//
13// The Goby Libraries are free software: you can redistribute them and/or modify
14// them under the terms of the GNU Lesser General Public License as published by
15// the Free Software Foundation, either version 2.1 of the License, or
16// (at your option) any later version.
17//
18// The Goby Libraries are distributed in the hope that they will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public License
24// along with Goby. If not, see <http://www.gnu.org/licenses/>.
25
26#ifndef GOBY_MOOS_MOOS_PROTOBUF_HELPERS_H
27#define GOBY_MOOS_MOOS_PROTOBUF_HELPERS_H
28
29#include <algorithm> // for max
30#include <cstddef> // for size_t
31#include <cstdint> // for int32_t, int64_t
32#include <iomanip> // for _Setprecision
33#include <limits> // for numeric_limits
34#include <map> // for map, map<>::c...
35#include <memory> // for allocator
36#include <mutex> // for mutex, lock_g...
37#include <regex> // for sregex_iterator
38#include <sstream> // for basic_ostream
39#include <stdexcept> // for runtime_error
40#include <string> // for string, opera...
41#include <utility> // for pair
42#include <vector> // for vector
43
44#include <boost/algorithm/string/case_conv.hpp> // for to_lower_copy
45#include <boost/algorithm/string/classification.hpp> // for is_any_ofF
46#include <boost/algorithm/string/erase.hpp> // for ierase_first_...
47#include <boost/algorithm/string/replace.hpp> // for replace_all
48#include <boost/algorithm/string/split.hpp> // for split
49#include <boost/algorithm/string/trim.hpp> // for trim_if
50#include <boost/core/enable_if.hpp> // for enable_if_c<>...
51#include <boost/format.hpp> // for basic_altstri...
52#include <boost/lexical_cast.hpp> // for lexical_cast
53#include <boost/lexical_cast/bad_lexical_cast.hpp> // for bad_lexical_cast
54#include <google/protobuf/descriptor.h> // for FieldDescriptor
55#include <google/protobuf/message.h> // for Reflection
56#include <google/protobuf/text_format.h> // for TextFormat
57
58#include "dccl/dynamic_protobuf_manager.h" // for DynamicProtob...
59#include "goby/moos/moos_string.h" // for val_from_string
60#include "goby/moos/protobuf/goby_moos_app.pb.h" // for RepeatedPtrField
61#include "goby/moos/protobuf/translator.pb.h" // for TranslatorEntry
62#include "goby/moos/transitional/message_algorithms.h" // for DCCLAlgorithm...
63#include "goby/moos/transitional/message_val.h" // for DCCLMessageVal
64#include "goby/util/as.h" // for as
65#include "goby/util/binary.h" // for hex_encode
66#include "goby/util/debug_logger/flex_ostream.h" // for operator<<
68
69namespace goby
70{
71namespace moos
72{
73extern std::mutex dynamic_parse_mutex;
74
75const std::string MAGIC_PROTOBUF_HEADER = "@PB";
76
77inline std::map<int, std::string>
81{
82 const google::protobuf::Descriptor* desc = in.GetDescriptor();
83
84 // run algorithms
85 std::map<int, std::string> modified_values;
86
87 for (const auto& algorithm : algorithms)
88 {
89 const google::protobuf::FieldDescriptor* primary_field_desc =
90 desc->FindFieldByNumber(algorithm.primary_field());
91
92 if (!primary_field_desc || primary_field_desc->is_repeated())
93 continue;
94
95 std::string primary_val;
96
97 if (!modified_values.count(algorithm.output_virtual_field()))
98 {
99 google::protobuf::TextFormat::PrintFieldValueToString(in, primary_field_desc, -1,
100 &primary_val);
101 boost::trim_if(primary_val, boost::is_any_of("\""));
102 }
103 else
104 {
105 primary_val = modified_values[algorithm.output_virtual_field()];
106 }
107
109 std::vector<goby::moos::transitional::DCCLMessageVal> ref;
110 for (int i = 0, m = algorithm.reference_field_size(); i < m; ++i)
111 {
112 const google::protobuf::FieldDescriptor* field_desc =
113 desc->FindFieldByNumber(algorithm.reference_field(i));
114
115 if (field_desc && !field_desc->is_repeated())
116 {
117 std::string ref_value;
118 google::protobuf::TextFormat::PrintFieldValueToString(in, field_desc, -1,
119 &ref_value);
120 ref.emplace_back(ref_value);
121 }
122 else
123 {
124 throw(
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))));
128 }
129 }
130
132 val, ref);
133
134 val = std::string(val);
135 modified_values[algorithm.output_virtual_field()] = std::string(val);
136 }
137
138 return modified_values;
139}
140
141inline std::string strip_name_from_enum(const std::string& enum_value,
142 const std::string& field_name)
143{
144 return boost::ierase_first_copy(enum_value, field_name + "_");
145}
146
147inline std::string add_name_to_enum(const std::string& enum_value, const std::string& field_name)
148{
149 return boost::to_upper_copy(field_name) + "_" + enum_value;
150}
151
152template <goby::moos::protobuf::TranslatorEntry::ParserSerializerTechnique technique>
154{
155};
156
157template <> class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_TEXT_FORMAT>
158{
159 public:
160 static void serialize(std::string* out, const google::protobuf::Message& in)
161 {
162 google::protobuf::TextFormat::Printer printer;
163 printer.SetSingleLineMode(true);
164 printer.PrintToString(in, out);
165 }
166
167 static void parse(const std::string& in, google::protobuf::Message* out)
168 {
169 google::protobuf::TextFormat::Parser parser;
170 goby::util::FlexOStreamErrorCollector error_collector(in);
171 parser.RecordErrorsTo(&error_collector);
172 parser.ParseFromString(in, out);
173 }
174};
175
176template <> class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_ENCODED>
177{
178 public:
179 static void serialize(std::string* out, const google::protobuf::Message& in)
180 {
181 in.SerializeToString(out);
182 }
183
184 static void parse(const std::string& in, google::protobuf::Message* out)
185 {
186 out->ParseFromString(in);
187 }
188};
189
190template <> class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_HEX>
191{
192 public:
193 static void serialize(std::string* out, const google::protobuf::Message& in)
194 {
195 std::string native_encoded;
198 serialize(&native_encoded, in);
199 goby::util::hex_encode(native_encoded, out);
200 }
201
202 static void parse(const std::string& in, google::protobuf::Message* out)
203 {
204 std::string native_encoded;
205 goby::util::hex_decode(in, &native_encoded);
206 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
207 TECHNIQUE_PROTOBUF_NATIVE_ENCODED>::parse(native_encoded,
208 out);
209 }
210};
211
215{
216 public:
217 static void serialize(std::string* out, const google::protobuf::Message& msg)
218 {
219 std::string header =
220 goby::moos::MAGIC_PROTOBUF_HEADER + "[" + msg.GetDescriptor()->full_name() + "] ";
222 *out = header + *out;
223 }
224
225 static void parse(const std::string& in, google::protobuf::Message* msg)
226 {
227 if (in.size() > goby::moos::MAGIC_PROTOBUF_HEADER.size() &&
228 in.substr(0, goby::moos::MAGIC_PROTOBUF_HEADER.size()) ==
230 {
231 size_t end_bracket_pos = in.find(']');
232
233 if (end_bracket_pos == std::string::npos)
234 throw(std::runtime_error(
235 "Incorrectly formatted protobuf message passed to MOOSTranslation<" +
237 prefix_technique) +
238 ">::parse."));
239
240 std::string name =
241 in.substr(goby::moos::MAGIC_PROTOBUF_HEADER.size() + 1,
242 end_bracket_pos - 1 - goby::moos::MAGIC_PROTOBUF_HEADER.size());
243 if (name != msg->GetDescriptor()->full_name())
244 throw(std::runtime_error(
245 "Wrong Protobuf type passed to MOOSTranslation<" +
247 prefix_technique) +
248 ">::parse. Expected: " + msg->GetDescriptor()->full_name() +
249 ", received: " + name));
250
251 if (in.size() > end_bracket_pos + 2)
252 goby::moos::MOOSTranslation<base_technique>::parse(in.substr(end_bracket_pos + 2),
253 msg);
254 else
255 msg->Clear();
256 }
257 else
258 {
260 }
261 }
262
263 static std::shared_ptr<google::protobuf::Message> dynamic_parse(const std::string& in)
264 {
265 if (in.size() > goby::moos::MAGIC_PROTOBUF_HEADER.size() &&
266 in.substr(0, goby::moos::MAGIC_PROTOBUF_HEADER.size()) ==
268 {
269 size_t end_bracket_pos = in.find(']');
270
271 if (end_bracket_pos == std::string::npos)
272 throw(std::runtime_error(
273 "Incorrectly formatted protobuf message passed to MOOSTranslation<" +
275 prefix_technique) +
276 ">::dynamic_parse."));
277
278 std::string name =
279 in.substr(goby::moos::MAGIC_PROTOBUF_HEADER.size() + 1,
280 end_bracket_pos - 1 - goby::moos::MAGIC_PROTOBUF_HEADER.size());
281
282 try
283 {
284 // dccl::DynamicProtobufManager appears not to be thread safe
285 const std::lock_guard<std::mutex> lock(goby::moos::dynamic_parse_mutex);
286
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;
293 }
294 catch (std::exception& e)
295 {
296 return std::shared_ptr<google::protobuf::Message>();
297 }
298 }
299 else
300 {
301 return std::shared_ptr<google::protobuf::Message>();
302 }
303 }
304};
305
306template <>
307class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT>
308 : public MOOSPrefixTranslation<
309 protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT,
310 protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_TEXT_FORMAT>
311{
312};
313template <>
314class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED>
315 : public MOOSPrefixTranslation<
316 protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED,
317 protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_ENCODED>
318{
319};
320template <>
321class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX>
322 : public MOOSPrefixTranslation<
323 protobuf::TranslatorEntry::TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX,
324 protobuf::TranslatorEntry::TECHNIQUE_PROTOBUF_NATIVE_HEX>
325{
326};
327
328template <>
329class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_COMMA_SEPARATED_KEY_EQUALS_VALUE_PAIRS>
330{
331 public:
332 static void serialize(std::string* out, const google::protobuf::Message& in,
337 bool use_short_enum = false)
338 {
339 std::stringstream out_ss;
340
341 const google::protobuf::Descriptor* desc = in.GetDescriptor();
343
344 int included_fields = 0;
345 for (int i = 0, n = desc->field_count(); i < n; ++i)
346 {
347 const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
348
349 // leave out unspecified or empty fields
350 if ((!field_desc->is_repeated() && !refl->HasField(in, field_desc)) ||
351 (field_desc->is_repeated() && refl->FieldSize(in, field_desc) == 0))
352 continue;
353
354 if (included_fields)
355 out_ss << ",";
356 ++included_fields;
357
358 const std::string& field_name = field_desc->name();
359
360 switch (field_desc->cpp_type())
361 {
362 default:
363 out_ss << to_moos_comma_equals_string_field(in, field_desc, true,
364 use_short_enum);
365 break;
366
367 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
368 if (field_desc->is_repeated())
369 {
370 for (int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
371 {
372 if (k)
373 out_ss << ",";
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)
377 {
378 if (j)
379 out_ss << ",";
380 const google::protobuf::Message& embedded_msg =
381 refl->GetRepeatedMessage(in, field_desc, j);
382 out_ss << to_moos_comma_equals_string_field(
383 embedded_msg, embedded_msg.GetDescriptor()->field(k), false,
384 use_short_enum);
385 }
386 out_ss << "}";
387 }
388 }
389
390 else
391 {
392 for (int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
393 {
394 if (k)
395 out_ss << ",";
396 out_ss << field_name << "_"
397 << field_desc->message_type()->field(k)->name() << "=";
398 const google::protobuf::Message& embedded_msg =
399 refl->GetMessage(in, field_desc);
400 out_ss << to_moos_comma_equals_string_field(
401 embedded_msg, embedded_msg.GetDescriptor()->field(k), false,
402 use_short_enum);
403 }
404 }
405
406 break;
407 }
408 }
409
410 std::map<int, std::string> additional_values = run_serialize_algorithms(in, algorithms);
411 for (const auto& additional_value : additional_values)
412 {
413 out_ss << ",";
414
415 std::string key;
416 int primary_field = 0;
417 for (const auto& algorithm : algorithms)
418 {
419 if (algorithm.output_virtual_field() == additional_value.first)
420 {
421 if (!key.empty())
422 key += "+";
423
424 key += algorithm.name();
425 primary_field = algorithm.primary_field();
426 }
427 }
428 key += "(" + desc->FindFieldByNumber(primary_field)->name() + ")";
429
430 out_ss << key << "=" << additional_value.second;
431 }
432
433 *out = out_ss.str();
434 }
435
436 static void parse(std::string in, google::protobuf::Message* out,
441 bool use_short_enum = false)
442 {
443 const google::protobuf::Descriptor* desc = out->GetDescriptor();
444 const google::protobuf::Reflection* refl = out->GetReflection();
445
446 boost::to_lower(in);
447
448 for (int i = 0, n = desc->field_count(); i < n; ++i)
449 {
450 const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
451
452 switch (field_desc->cpp_type())
453 {
454 default:
455 {
456 std::string val;
457
458 if (goby::moos::val_from_string(val, in, field_desc->name()))
459 {
460 // run algorithms
461 for (const auto& algorithm : algorithms)
462 {
464
465 if (algorithm.primary_field() == field_desc->number())
468 algorithm.name(), extract_val,
469 std::vector<goby::moos::transitional::DCCLMessageVal>());
470
471 val = std::string(extract_val);
472 }
473
474 std::vector<std::string> vals;
475 boost::split(vals, val, boost::is_any_of(","));
476 from_moos_comma_equals_string_field(out, field_desc, vals, 0,
477 use_short_enum);
478 }
479 }
480 break;
481
482 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
483 if (field_desc->is_repeated())
484 {
485 for (int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
486 {
487 std::string val;
489 val, in,
490 field_desc->name() + "_" +
491 field_desc->message_type()->field(k)->name()))
492 {
493 std::vector<std::string> vals;
494 boost::split(vals, val, boost::is_any_of(","));
495
496 for (int j = 0, m = vals.size(); j < m; ++j)
497 {
498 google::protobuf::Message* embedded_msg =
499 (refl->FieldSize(*out, field_desc) < j + 1)
500 ? refl->AddMessage(out, field_desc)
501 : refl->MutableRepeatedMessage(out, field_desc, j);
502 from_moos_comma_equals_string_field(
503 embedded_msg, embedded_msg->GetDescriptor()->field(k), vals,
504 j, use_short_enum);
505 }
506 }
507 }
508 }
509 else
510 {
511 for (int k = 0, o = field_desc->message_type()->field_count(); k < o; ++k)
512 {
513 std::string val;
515 val, in,
516 field_desc->name() + "_" +
517 field_desc->message_type()->field(k)->name()))
518 {
519 std::vector<std::string> vals;
520 boost::split(vals, val, boost::is_any_of(","));
521
522 google::protobuf::Message* embedded_msg =
523 refl->MutableMessage(out, field_desc);
524 from_moos_comma_equals_string_field(
525 embedded_msg, embedded_msg->GetDescriptor()->field(k), vals, 0,
526 use_short_enum);
527 }
528 }
529 }
530 break;
531 }
532 }
533 }
534
535 private:
536 static std::string
537 to_moos_comma_equals_string_field(const google::protobuf::Message& proto_msg,
538 const google::protobuf::FieldDescriptor* field_desc,
539 bool write_key = true, bool use_short_enum = false)
540 {
541 const google::protobuf::Reflection* refl = proto_msg.GetReflection();
542
543 std::stringstream out;
544 const std::string& field_name = field_desc->name();
545
546 if (field_desc->is_repeated())
547 {
548 if (write_key)
549 out << field_name << "={";
550
551 for (int j = 0, m = refl->FieldSize(proto_msg, field_desc); j < m; ++j)
552 {
553 if (j)
554 out << ",";
555
556 switch (field_desc->cpp_type())
557 {
558 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
560 refl->GetRepeatedMessage(proto_msg, field_desc, j).SerializeAsString());
561 break;
562
563 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
564 out << refl->GetRepeatedInt32(proto_msg, field_desc, j);
565 break;
566
567 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
568 out << refl->GetRepeatedInt64(proto_msg, field_desc, j);
569 break;
570
571 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
572 out << refl->GetRepeatedUInt32(proto_msg, field_desc, j);
573 break;
574
575 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
576 out << refl->GetRepeatedUInt64(proto_msg, field_desc, j);
577 break;
578
579 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
580 out << std::boolalpha << refl->GetRepeatedBool(proto_msg, field_desc, j);
581 break;
582
583 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
584 if (field_desc->type() == google::protobuf::FieldDescriptor::TYPE_STRING)
585 out << refl->GetRepeatedString(proto_msg, field_desc, j);
586 else if (field_desc->type() ==
587 google::protobuf::FieldDescriptor::TYPE_BYTES)
589 refl->GetRepeatedString(proto_msg, field_desc, j));
590 break;
591
592 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
593 out << std::setprecision(std::numeric_limits<float>::digits10)
594 << refl->GetRepeatedFloat(proto_msg, field_desc, j);
595 break;
596
597 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
598 out << std::setprecision(std::numeric_limits<double>::digits10)
599 << refl->GetRepeatedDouble(proto_msg, field_desc, j);
600 break;
601
602 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
603 out << ((use_short_enum)
605 refl->GetRepeatedEnum(proto_msg, field_desc, j)->name(),
606 field_name)
607 : refl->GetRepeatedEnum(proto_msg, field_desc, j)->name());
608
609 break;
610 }
611 }
612 if (write_key)
613 out << "}";
614 }
615 else
616 {
617 if (write_key)
618 out << field_name << "=";
619 switch (field_desc->cpp_type())
620 {
621 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
623 refl->GetMessage(proto_msg, field_desc).SerializeAsString());
624 break;
625
626 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
627 out << refl->GetInt32(proto_msg, field_desc);
628 break;
629
630 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
631 out << refl->GetInt64(proto_msg, field_desc);
632 break;
633
634 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
635 out << refl->GetUInt32(proto_msg, field_desc);
636 break;
637
638 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
639 out << refl->GetUInt64(proto_msg, field_desc);
640 break;
641
642 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
643 out << std::boolalpha << refl->GetBool(proto_msg, field_desc);
644 break;
645
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)
650 out << goby::util::hex_encode(refl->GetString(proto_msg, field_desc));
651 break;
652
653 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
654 out << std::setprecision(std::numeric_limits<float>::digits10)
655 << refl->GetFloat(proto_msg, field_desc);
656 break;
657
658 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
659 out << std::setprecision(std::numeric_limits<double>::digits10)
660 << refl->GetDouble(proto_msg, field_desc);
661 break;
662
663 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
664 out << ((use_short_enum)
665 ? strip_name_from_enum(refl->GetEnum(proto_msg, field_desc)->name(),
666 field_name)
667 : refl->GetEnum(proto_msg, field_desc)->name());
668 break;
669 }
670 }
671 return out.str();
672 }
673 static void from_moos_comma_equals_string_field(
674 google::protobuf::Message* proto_msg, const google::protobuf::FieldDescriptor* field_desc,
675 const std::vector<std::string>& values, int value_key = 0, bool use_short_enum = false)
676 {
677 if (values.size() == 0)
678 return;
679
680 const google::protobuf::Reflection* refl = proto_msg->GetReflection();
681 if (field_desc->is_repeated())
682 {
683 for (const auto& v : values)
684 {
685 switch (field_desc->cpp_type())
686 {
687 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
688 refl->AddMessage(proto_msg, field_desc)
690 break;
691
692 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
693 refl->AddInt32(proto_msg, field_desc,
694 goby::util::as<google::protobuf::int32>(v));
695 break;
696
697 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
698 refl->AddInt64(proto_msg, field_desc,
699 goby::util::as<google::protobuf::int64>(v));
700 break;
701
702 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
703 refl->AddUInt32(proto_msg, field_desc,
704 goby::util::as<google::protobuf::uint32>(v));
705 break;
706
707 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
708 refl->AddUInt64(proto_msg, field_desc,
709 goby::util::as<google::protobuf::uint64>(v));
710 break;
711
712 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
713 refl->AddBool(proto_msg, field_desc, goby::util::as<bool>(v));
714 break;
715
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)
721 refl->AddString(proto_msg, field_desc, goby::util::hex_decode(v));
722 break;
723
724 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
725 refl->AddFloat(proto_msg, field_desc, goby::util::as<float>(v));
726 break;
727
728 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
729 refl->AddDouble(proto_msg, field_desc, goby::util::as<double>(v));
730 break;
731
732 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
733 {
734 std::string enum_value =
735 ((use_short_enum) ? add_name_to_enum(v, field_desc->name()) : v);
736
737 const google::protobuf::EnumValueDescriptor* enum_desc =
738 field_desc->enum_type()->FindValueByName(enum_value);
739
740 // try upper case
741 if (!enum_desc)
742 enum_desc = field_desc->enum_type()->FindValueByName(
743 boost::algorithm::to_upper_copy(enum_value));
744 // try lower case
745 if (!enum_desc)
746 enum_desc = field_desc->enum_type()->FindValueByName(
747 boost::algorithm::to_lower_copy(enum_value));
748
749 if (enum_desc)
750 refl->AddEnum(proto_msg, field_desc, enum_desc);
751 }
752 break;
753 }
754 }
755 }
756 else
757 {
758 const std::string& v = values[value_key];
759 switch (field_desc->cpp_type())
760 {
761 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
762 refl->MutableMessage(proto_msg, field_desc)
764 break;
765
766 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
767 refl->SetInt32(proto_msg, field_desc,
768 goby::util::as<google::protobuf::int32>(v));
769 break;
770
771 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
772 refl->SetInt64(proto_msg, field_desc,
773 goby::util::as<google::protobuf::int64>(v));
774 break;
775
776 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
777 refl->SetUInt32(proto_msg, field_desc,
778 goby::util::as<google::protobuf::uint32>(v));
779 break;
780
781 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
782 refl->SetUInt64(proto_msg, field_desc,
783 goby::util::as<google::protobuf::uint64>(v));
784 break;
785
786 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
787 refl->SetBool(proto_msg, field_desc, goby::util::as<bool>(v));
788 break;
789
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)
794 refl->SetString(proto_msg, field_desc, goby::util::hex_decode(v));
795 break;
796
797 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
798 refl->SetFloat(proto_msg, field_desc, goby::util::as<float>(v));
799 break;
800
801 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
802 refl->SetDouble(proto_msg, field_desc, goby::util::as<double>(v)); /* */
803 break;
804
805 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
806 {
807 std::string enum_value =
808 ((use_short_enum) ? add_name_to_enum(v, field_desc->name()) : v);
809
810 const google::protobuf::EnumValueDescriptor* enum_desc =
811 field_desc->enum_type()->FindValueByName(enum_value);
812
813 // try upper case
814 if (!enum_desc)
815 enum_desc = field_desc->enum_type()->FindValueByName(
816 boost::algorithm::to_upper_copy(enum_value));
817 // try lower case
818 if (!enum_desc)
819 enum_desc = field_desc->enum_type()->FindValueByName(
820 boost::algorithm::to_lower_copy(enum_value));
821
822 if (enum_desc)
823 refl->SetEnum(proto_msg, field_desc, enum_desc);
824 }
825 break;
826 }
827 }
828 }
829};
830
831template <> class MOOSTranslation<protobuf::TranslatorEntry::TECHNIQUE_FORMAT>
832{
833 public:
834 struct RepeatedFieldKey
835 {
836 int field;
837 int index;
838 };
839
840 static void serialize(std::string* out, const google::protobuf::Message& in,
843 const std::string& format, const std::string& repeated_delimiter,
844 bool use_short_enum = false)
845 {
846 std::string mutable_format = format;
847
848 const google::protobuf::Descriptor* desc = in.GetDescriptor();
850
851 int max_field_number = 1;
852 for (int i = 1, n = desc->field_count(); i < n; ++i)
853 {
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();
857 }
858
859 // run algorithms
860 std::map<int, std::string> modified_values = run_serialize_algorithms(in, algorithms);
861
862 for (const auto& modified_value : modified_values)
863 {
864 if (modified_value.first > max_field_number)
865 max_field_number = modified_value.first;
866 }
867
868 std::string mutable_format_temp = mutable_format;
869
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),
873 end;
874 it != end; ++it)
875 {
876 std::string match = (*it)[0];
877
878 boost::trim_if(match, boost::is_any_of("%"));
879 std::vector<std::string> subfields;
880 boost::split(subfields, match, boost::is_any_of(":"));
881
882 ++max_field_number;
883
884 const google::protobuf::FieldDescriptor* field_desc = nullptr;
885 const google::protobuf::Reflection* sub_refl = refl;
886 const google::protobuf::Message* sub_message = &in;
887
888 for (int i = 0, n = subfields.size() - 1; i < n; ++i)
889 {
890 std::vector<std::string> field_and_index;
891 boost::split(field_and_index, subfields[i], boost::is_any_of("."));
892
893 field_desc = sub_message->GetDescriptor()->FindFieldByNumber(
894 goby::util::as<int>(field_and_index[0]));
895 if (!field_desc ||
896 field_desc->cpp_type() != google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
897 {
898 throw(std::runtime_error(
899 "Invalid ':' syntax given for format: " + match +
900 ". All field indices except the last must be embedded messages"));
901 }
902 if (field_desc->is_repeated() && field_and_index.size() != 2)
903 {
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."));
907 }
908
909 sub_message =
910 (field_desc->is_repeated())
911 ? &sub_refl->GetRepeatedMessage(*sub_message, field_desc,
912 goby::util::as<int>(field_and_index[1]))
913 : &sub_refl->GetMessage(*sub_message, field_desc);
914 sub_refl = sub_message->GetReflection();
915 }
916
917 serialize(&modified_values[max_field_number], *sub_message, algorithms,
918 "%" + subfields[subfields.size() - 1] + "%", repeated_delimiter,
919 use_short_enum);
920
921 boost::replace_all(
922 mutable_format_temp, std::string("%" + match + "%"),
923 std::string("%" + goby::util::as<std::string>(max_field_number) + "%"));
924 }
925
926 mutable_format = mutable_format_temp;
927
928 std::map<int, RepeatedFieldKey> indexed_repeated_fields;
929
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),
933 end;
934 it != end; ++it)
935 {
936 std::string match = (*it)[0];
937 boost::trim_if(match, boost::is_any_of("%"));
938
939 ++max_field_number;
940
941 boost::replace_all(
942 mutable_format_temp, std::string("%" + match + "%"),
943 std::string("%" + goby::util::as<std::string>(max_field_number) + "%"));
944
945 RepeatedFieldKey key;
946
947 std::vector<std::string> field_and_index;
948 boost::split(field_and_index, match, boost::is_any_of("."));
949
950 key.field = goby::util::as<int>(field_and_index[0]);
951 key.index = goby::util::as<int>(field_and_index[1]);
952
953 indexed_repeated_fields[max_field_number] = key;
954 }
955
956 mutable_format = mutable_format_temp;
957
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));
961
962 for (int i = 1; i <= max_field_number; ++i)
963 {
964 bool is_indexed_repeated_field = indexed_repeated_fields.count(i);
965
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);
969 if (field_desc)
970 {
971 if (field_desc->is_repeated())
972 {
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
975 : refl->FieldSize(in, field_desc);
976
977 std::stringstream out_repeated;
978 for (int j = start; j < end; ++j)
979 {
980 if (j && !is_indexed_repeated_field)
981 out_repeated << repeated_delimiter;
982 switch (field_desc->cpp_type())
983 {
984 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
985 out_repeated << goby::util::hex_encode(
986 refl->GetRepeatedMessage(in, field_desc, j)
988 break;
989
990 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
991 out_repeated << ((j < refl->FieldSize(in, field_desc))
992 ? refl->GetRepeatedInt32(in, field_desc, j)
993 : std::numeric_limits<std::int32_t>::max());
994
995 break;
996
997 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
998 out_repeated << ((j < refl->FieldSize(in, field_desc))
999 ? refl->GetRepeatedInt64(in, field_desc, j)
1000 : std::numeric_limits<std::int64_t>::max());
1001 break;
1002
1003 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
1004 out_repeated << ((j < refl->FieldSize(in, field_desc))
1005 ? refl->GetRepeatedUInt32(in, field_desc, j)
1006 : std::numeric_limits<std::uint32_t>::max());
1007 break;
1008
1009 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
1010 out_repeated << ((j < refl->FieldSize(in, field_desc))
1011 ? refl->GetRepeatedUInt64(in, field_desc, j)
1012 : std::numeric_limits<std::uint64_t>::max());
1013 break;
1014
1015 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
1016 out_repeated << std::boolalpha
1017 << ((j < refl->FieldSize(in, field_desc))
1018 ? refl->GetRepeatedBool(in, field_desc, j)
1019 : field_desc->default_value_bool());
1020 break;
1021
1022 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
1023 if (field_desc->type() ==
1024 google::protobuf::FieldDescriptor::TYPE_STRING)
1025 out_repeated
1026 << ((j < refl->FieldSize(in, field_desc))
1027 ? refl->GetRepeatedString(in, field_desc, j)
1028 : field_desc->default_value_string());
1029 else if (field_desc->type() ==
1030 google::protobuf::FieldDescriptor::TYPE_BYTES)
1031 out_repeated << goby::util::hex_encode(
1032 ((j < refl->FieldSize(in, field_desc))
1033 ? refl->GetRepeatedString(in, field_desc, j)
1034 : field_desc->default_value_string()));
1035 break;
1036
1037 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
1038 out_repeated
1039 << std::setprecision(std::numeric_limits<float>::digits10)
1040 << ((j < refl->FieldSize(in, field_desc))
1041 ? refl->GetRepeatedFloat(in, field_desc, j)
1042 : std::numeric_limits<float>::quiet_NaN());
1043 break;
1044
1045 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
1046 out_repeated
1047 << std::setprecision(std::numeric_limits<double>::digits10)
1048 << ((j < refl->FieldSize(in, field_desc))
1049 ? refl->GetRepeatedDouble(in, field_desc, j)
1050 : std::numeric_limits<double>::quiet_NaN());
1051 break;
1052
1053 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
1054 {
1055 const google::protobuf::EnumValueDescriptor* enum_val =
1056 ((j < refl->FieldSize(in, field_desc))
1057 ? refl->GetRepeatedEnum(in, field_desc, j)
1058 : field_desc->default_value_enum());
1059 out_repeated
1060 << ((use_short_enum) ? strip_name_from_enum(enum_val->name(),
1061 field_desc->name())
1062 : enum_val->name());
1063 }
1064 break;
1065 }
1066 }
1067 out_format % out_repeated.str();
1068 }
1069 else
1070 {
1071 switch (field_desc->cpp_type())
1072 {
1073 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
1074 out_format % goby::util::hex_encode(
1075 refl->GetMessage(in, field_desc).SerializeAsString());
1076 break;
1077
1078 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
1079 out_format % refl->GetInt32(in, field_desc);
1080 break;
1081
1082 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
1083 out_format % refl->GetInt64(in, field_desc);
1084 break;
1085
1086 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
1087 out_format % refl->GetUInt32(in, field_desc);
1088 break;
1089
1090 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
1091 out_format % refl->GetUInt64(in, field_desc);
1092 break;
1093
1094 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
1095 out_format % goby::util::as<std::string>(refl->GetBool(in, field_desc));
1096 break;
1097
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)
1104 out_format %
1105 goby::util::hex_encode(refl->GetString(in, field_desc));
1106 break;
1107
1108 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
1109 out_format % boost::io::group(std::setprecision(
1110 std::numeric_limits<float>::digits10),
1111 refl->GetFloat(in, field_desc));
1112 break;
1113
1114 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
1115 out_format %
1116 boost::io::group(
1117 std::setprecision(std::numeric_limits<double>::digits10),
1118 refl->GetDouble(in, field_desc));
1119 break;
1120
1121 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
1122
1123 out_format %
1124 ((use_short_enum)
1125 ? strip_name_from_enum(refl->GetEnum(in, field_desc)->name(),
1126 field_desc->name())
1127 : refl->GetEnum(in, field_desc)->name());
1128 break;
1129 }
1130 }
1131 }
1132 else if (mod_it != modified_values.end())
1133 {
1134 out_format % mod_it->second;
1135 }
1136 else
1137 {
1138 out_format % "unknown";
1139 }
1140 }
1141
1142 *out = out_format.str();
1143 }
1144
1145 static void parse(const std::string& in, google::protobuf::Message* out, std::string format,
1146 const std::string& repeated_delimiter,
1151 bool use_short_enum = false)
1152 {
1153 const google::protobuf::Descriptor* desc = out->GetDescriptor();
1154 const google::protobuf::Reflection* refl = out->GetReflection();
1155 boost::to_lower(format);
1156 std::string str = in;
1157 std::string lower_str = boost::to_lower_copy(in);
1158
1159 // goby::glog.is(DEBUG1) && goby::glog << "Format: " << format << std::endl;
1160 // goby::glog.is(DEBUG1) && goby::glog << "String: " << str << std::endl;
1161 // goby::glog.is(DEBUG1) && goby::glog << "Lower String: " << lower_str << std::endl;
1162
1163 std::string::const_iterator i = format.begin();
1164
1165 while (i != format.end())
1166 {
1167 if (*i == '%')
1168 {
1169 ++i; // now *i is the conversion specifier
1170 std::string specifier;
1171 while (*i != '%') specifier += *i++;
1172
1173 ++i; // now *i is the next separator
1174 std::string extract = str.substr(0, lower_str.find(*i));
1175
1176 if (specifier.find(':') != std::string::npos)
1177 {
1178 std::vector<std::string> subfields;
1179 boost::split(subfields, specifier, boost::is_any_of(":"));
1180 const google::protobuf::FieldDescriptor* field_desc = nullptr;
1181 const google::protobuf::Reflection* sub_refl = refl;
1182 google::protobuf::Message* sub_message = out;
1183
1184 for (int i = 0, n = subfields.size() - 1; i < n; ++i)
1185 {
1186 std::vector<std::string> field_and_index;
1187 boost::split(field_and_index, subfields[i], boost::is_any_of("."));
1188
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)
1193 {
1194 throw(std::runtime_error(
1195 "Invalid ':' syntax given for format: " + specifier +
1196 ". All field indices except the last must be singular embedded "
1197 "messages"));
1198 }
1199
1200 int index = -1;
1201 if (field_desc->is_repeated())
1202 {
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);
1211 }
1212
1213 sub_message =
1214 (field_desc->is_repeated())
1215 ? sub_refl->MutableRepeatedMessage(sub_message, field_desc, index)
1216 : sub_refl->MutableMessage(sub_message, field_desc);
1217 sub_refl = sub_message->GetReflection();
1218 }
1219
1220 parse(extract, sub_message, "%" + subfields[subfields.size() - 1] + "%",
1221 repeated_delimiter, algorithms, use_short_enum);
1222 }
1223 else
1224 {
1225 try
1226 {
1227 std::vector<std::string> field_and_index;
1228 boost::split(field_and_index, specifier, boost::is_any_of("."));
1229
1230 int field_index = boost::lexical_cast<int>(field_and_index[0]);
1231 bool is_indexed_repeated_field = field_and_index.size() == 2;
1232
1233 int value_index = 0;
1234 if (is_indexed_repeated_field)
1235 value_index = boost::lexical_cast<int>(field_and_index[1]);
1236
1237 const google::protobuf::FieldDescriptor* field_desc =
1238 desc->FindFieldByNumber(field_index);
1239
1240 if (!field_desc)
1241 throw(std::runtime_error("Bad field: " + specifier +
1242 " not in message " + desc->full_name()));
1243
1244 // run algorithms
1245 for (const auto& algorithm : algorithms)
1246 {
1247 goby::moos::transitional::DCCLMessageVal extract_val(extract);
1248
1249 if (algorithm.primary_field() == field_index)
1251 ->run_algorithm(
1252 algorithm.name(), extract_val,
1253 std::vector<goby::moos::transitional::DCCLMessageVal>());
1254
1255 extract = std::string(extract_val);
1256 }
1257
1258 std::vector<std::string> parts;
1259 if (is_indexed_repeated_field || !field_desc->is_repeated())
1260 parts.push_back(extract);
1261 else
1262 boost::split(parts, extract, boost::is_any_of(repeated_delimiter));
1263
1264 for (auto& part : parts)
1265 {
1266 switch (field_desc->cpp_type())
1267 {
1268 case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
1269 if (is_indexed_repeated_field)
1270 {
1271 while (refl->FieldSize(*out, field_desc) <= value_index)
1272 refl->AddMessage(out, field_desc);
1273 }
1274 field_desc->is_repeated()
1275 ? (is_indexed_repeated_field
1276 ? refl->MutableRepeatedMessage(out, field_desc,
1277 value_index)
1279 : refl->AddMessage(out, field_desc)
1282 : refl->MutableMessage(out, field_desc)
1284 break;
1285
1286 case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
1287 if (is_indexed_repeated_field)
1288 {
1289 while (refl->FieldSize(*out, field_desc) <= value_index)
1290 refl->AddInt32(out, field_desc,
1291 field_desc->default_value_int32());
1292 }
1293 field_desc->is_repeated()
1294 ? (is_indexed_repeated_field
1295 ? refl->SetRepeatedInt32(
1296 out, field_desc, value_index,
1297 goby::util::as<google::protobuf::int32>(part))
1298 : refl->AddInt32(
1299 out, field_desc,
1300 goby::util::as<google::protobuf::int32>(part)))
1301 : refl->SetInt32(
1302 out, field_desc,
1303 goby::util::as<google::protobuf::int32>(part));
1304 break;
1305
1306 case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
1307 if (is_indexed_repeated_field)
1308 {
1309 while (refl->FieldSize(*out, field_desc) <= value_index)
1310 refl->AddInt64(out, field_desc,
1311 field_desc->default_value_int64());
1312 }
1313 field_desc->is_repeated()
1314 ? (is_indexed_repeated_field
1315 ? refl->SetRepeatedInt64(
1316 out, field_desc, value_index,
1317 goby::util::as<google::protobuf::int64>(part))
1318 : refl->AddInt64(
1319 out, field_desc,
1320 goby::util::as<google::protobuf::int64>(part)))
1321 : refl->SetInt64(
1322 out, field_desc,
1323 goby::util::as<google::protobuf::int64>(part));
1324 break;
1325
1326 case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
1327 if (is_indexed_repeated_field)
1328 {
1329 while (refl->FieldSize(*out, field_desc) <= value_index)
1330 refl->AddUInt32(out, field_desc,
1331 field_desc->default_value_uint32());
1332 }
1333 field_desc->is_repeated()
1334 ? (is_indexed_repeated_field
1335 ? refl->SetRepeatedUInt32(
1336 out, field_desc, value_index,
1337 goby::util::as<google::protobuf::uint32>(part))
1338 : refl->AddUInt32(
1339 out, field_desc,
1340 goby::util::as<google::protobuf::uint32>(
1341 part)))
1342 : refl->SetUInt32(
1343 out, field_desc,
1344 goby::util::as<google::protobuf::uint32>(part));
1345 break;
1346
1347 case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
1348 if (is_indexed_repeated_field)
1349 {
1350 while (refl->FieldSize(*out, field_desc) <= value_index)
1351 refl->AddUInt64(out, field_desc,
1352 field_desc->default_value_uint64());
1353 }
1354 field_desc->is_repeated()
1355 ? (is_indexed_repeated_field
1356 ? refl->SetRepeatedUInt64(
1357 out, field_desc, value_index,
1358 goby::util::as<google::protobuf::uint64>(part))
1359 : refl->AddUInt64(
1360 out, field_desc,
1361 goby::util::as<google::protobuf::uint64>(
1362 part)))
1363 : refl->SetUInt64(
1364 out, field_desc,
1365 goby::util::as<google::protobuf::uint64>(part));
1366 break;
1367
1368 case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
1369 if (is_indexed_repeated_field)
1370 {
1371 while (refl->FieldSize(*out, field_desc) <= value_index)
1372 refl->AddBool(out, field_desc,
1373 field_desc->default_value_bool());
1374 }
1375 field_desc->is_repeated()
1376 ? (is_indexed_repeated_field
1377 ? refl->SetRepeatedBool(out, field_desc, value_index,
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));
1383 break;
1384
1385 case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
1386 if (is_indexed_repeated_field)
1387 {
1388 while (refl->FieldSize(*out, field_desc) <= value_index)
1389 refl->AddString(out, field_desc,
1390 field_desc->default_value_string());
1391 }
1392 field_desc->is_repeated()
1393 ? (is_indexed_repeated_field
1394 ? refl->SetRepeatedString(out, field_desc,
1395 value_index, part)
1396 : refl->AddString(out, field_desc, part))
1397 : refl->SetString(out, field_desc, part);
1398 break;
1399
1400 case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
1401 if (is_indexed_repeated_field)
1402 {
1403 while (refl->FieldSize(*out, field_desc) <= value_index)
1404 refl->AddFloat(out, field_desc,
1405 field_desc->default_value_float());
1406 }
1407 field_desc->is_repeated()
1408 ? (is_indexed_repeated_field
1409 ? refl->SetRepeatedFloat(out, field_desc,
1410 value_index,
1411 goby::util::as<float>(part))
1412 : refl->AddFloat(out, field_desc,
1413 goby::util::as<float>(part)))
1414 : refl->SetFloat(out, field_desc,
1415 goby::util::as<float>(part));
1416 break;
1417
1418 case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
1419 if (is_indexed_repeated_field)
1420 {
1421 while (refl->FieldSize(*out, field_desc) <= value_index)
1422 refl->AddDouble(out, field_desc,
1423 field_desc->default_value_double());
1424 }
1425 field_desc->is_repeated()
1426 ? (is_indexed_repeated_field
1427 ? refl->SetRepeatedDouble(
1428 out, field_desc, value_index,
1429 goby::util::as<double>(part))
1430 : refl->AddDouble(out, field_desc,
1431 goby::util::as<double>(part)))
1432 : refl->SetDouble(out, field_desc,
1433 goby::util::as<double>(part));
1434 break;
1435
1436 case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
1437 {
1438 if (is_indexed_repeated_field)
1439 {
1440 while (refl->FieldSize(*out, field_desc) <= value_index)
1441 refl->AddEnum(out, field_desc,
1442 field_desc->default_value_enum());
1443 }
1444 std::string enum_value =
1445 ((use_short_enum)
1446 ? add_name_to_enum(part, field_desc->name())
1447 : part);
1448
1449 const google::protobuf::EnumValueDescriptor* enum_desc =
1450 refl->GetEnum(*out, field_desc)
1451 ->type()
1452 ->FindValueByName(enum_value);
1453
1454 // try upper case
1455 if (!enum_desc)
1456 enum_desc =
1457 refl->GetEnum(*out, field_desc)
1458 ->type()
1459 ->FindValueByName(boost::to_upper_copy(enum_value));
1460 // try lower case
1461 if (!enum_desc)
1462 enum_desc =
1463 refl->GetEnum(*out, field_desc)
1464 ->type()
1465 ->FindValueByName(boost::to_lower_copy(enum_value));
1466 if (enum_desc)
1467 {
1468 field_desc->is_repeated()
1469 ? (is_indexed_repeated_field
1470 ? refl->SetRepeatedEnum(out, field_desc,
1471 value_index, enum_desc)
1472 : refl->AddEnum(out, field_desc, enum_desc))
1473 : refl->SetEnum(out, field_desc, enum_desc);
1474 }
1475 }
1476 break;
1477 }
1478 }
1479 }
1480 catch (boost::bad_lexical_cast&)
1481 {
1482 throw(std::runtime_error(
1483 "Bad specifier: " + specifier +
1484 ", must be an integer. For message: " + desc->full_name()));
1485 }
1486 }
1487
1488 // goby::glog.is(DEBUG1) && goby::glog << "field: [" << field_index << "], parts[j]: [" << parts[j] << "]" << std::endl;
1489 }
1490 else
1491 {
1492 // if it's not a %, eat!
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);
1496 ++i;
1497 }
1498 }
1499 }
1500};
1501} // namespace moos
1502} // namespace goby
1503
1505namespace goby
1506{
1507namespace moos
1508{
1509extern std::mutex moos_technique_mutex;
1511
1513{
1514 const std::lock_guard<std::mutex> lock(moos_technique_mutex);
1515 return moos_technique;
1516}
1517
1530
1531} // namespace moos
1532} // namespace goby
1533
1538inline bool serialize_for_moos(std::string* out, const google::protobuf::Message& msg)
1539{
1541 {
1543 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1544 TECHNIQUE_PROTOBUF_NATIVE_ENCODED>::serialize(out, msg);
1545 return true;
1547 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1548 TECHNIQUE_PROTOBUF_NATIVE_HEX>::serialize(out, msg);
1549 return false;
1551 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1552 TECHNIQUE_PROTOBUF_TEXT_FORMAT>::serialize(out, msg);
1553 return false;
1557 serialize(out, msg);
1558 return true;
1560 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1561 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX>::serialize(out,
1562 msg);
1563 return false;
1567 serialize(out, msg);
1568 return false;
1569 default:
1572 << "Non-PROTOBUF techniques are not supported for 'moos_parser_technique': "
1575 << std::endl;
1576 return false;
1577 }
1578}
1579
1584inline void parse_for_moos(const std::string& in, google::protobuf::Message* msg)
1585{
1587 {
1589 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1590 TECHNIQUE_PROTOBUF_NATIVE_ENCODED>::parse(in, msg);
1591 break;
1595 msg);
1596 break;
1600 msg);
1601 break;
1602
1604 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1605 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED>::parse(in,
1606 msg);
1607 break;
1609 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1610 TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX>::parse(in, msg);
1611 break;
1613 goby::moos::MOOSTranslation<goby::moos::protobuf::TranslatorEntry::
1614 TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT>::parse(in,
1615 msg);
1616 break;
1617 default:
1620 << "Non-PROTOBUF techniques are not supported for 'moos_parser_technique': "
1623 << std::endl;
1624 break;
1625 }
1626}
1627
1628inline std::shared_ptr<google::protobuf::Message> dynamic_parse_for_moos(const std::string& in)
1629{
1631 {
1635 dynamic_parse(in);
1636
1640 dynamic_parse(in);
1641
1645 dynamic_parse(in);
1646
1647 default:
1649 goby::glog << "Non-PREFIX techniques are not supported when using "
1650 "dynamic_parse_for_moos for 'moos_parser_technique': "
1653 << std::endl;
1654 return std::shared_ptr<google::protobuf::Message>();
1655 }
1656}
1657
1658#endif
static std::shared_ptr< google::protobuf::Message > dynamic_parse(const std::string &in)
static void parse(const std::string &in, google::protobuf::Message *msg)
static void serialize(std::string *out, const google::protobuf::Message &msg)
static void serialize(std::string *out, const google::protobuf::Message &in, const google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::PublishSerializer::Algorithm > &algorithms=google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::PublishSerializer::Algorithm >(), bool use_short_enum=false)
static void parse(std::string in, google::protobuf::Message *out, const google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::CreateParser::Algorithm > &algorithms=google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::CreateParser::Algorithm >(), bool use_short_enum=false)
static void serialize(std::string *out, const google::protobuf::Message &in, const google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::PublishSerializer::Algorithm > &algorithms, const std::string &format, const std::string &repeated_delimiter, bool use_short_enum=false)
static void parse(const std::string &in, google::protobuf::Message *out, std::string format, const std::string &repeated_delimiter, const google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::CreateParser::Algorithm > &algorithms=google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::CreateParser::Algorithm >(), bool use_short_enum=false)
static void serialize(std::string *out, const google::protobuf::Message &in)
static void parse(const std::string &in, google::protobuf::Message *out)
static void serialize(std::string *out, const google::protobuf::Message &in)
static void serialize(std::string *out, const google::protobuf::Message &in)
static void parse(const std::string &in, google::protobuf::Message *out)
::goby::moos::protobuf::TranslatorEntry_ParserSerializerTechnique moos_parser_technique() const
static constexpr ParserSerializerTechnique TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_HEX
static constexpr ParserSerializerTechnique TECHNIQUE_PROTOBUF_NATIVE_ENCODED
static const std::string & ParserSerializerTechnique_Name(T enum_t_value)
static constexpr ParserSerializerTechnique TECHNIQUE_PROTOBUF_NATIVE_HEX
static constexpr ParserSerializerTechnique TECHNIQUE_PREFIXED_PROTOBUF_NATIVE_ENCODED
static constexpr ParserSerializerTechnique TECHNIQUE_PROTOBUF_TEXT_FORMAT
static constexpr ParserSerializerTechnique TECHNIQUE_PREFIXED_PROTOBUF_TEXT_FORMAT
void run_algorithm(const std::string &algorithm, DCCLMessageVal &in, const std::vector< DCCLMessageVal > &ref)
static DCCLAlgorithmPerformer * getInstance()
bool is(goby::util::logger::Verbosity verbosity)
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromString(ConstStringParam data)
bool SerializeToString(std::string *output) const
std::string SerializeAsString() const
const Descriptor * GetDescriptor() const
Definition message.h:357
const Reflection * GetReflection() const
Definition message.h:363
int32_t GetRepeatedInt32(const Message &message, const FieldDescriptor *field, int index) const
void SetUInt32(Message *message, const FieldDescriptor *field, uint32_t value) const
float GetFloat(const Message &message, const FieldDescriptor *field) const
std::string GetString(const Message &message, const FieldDescriptor *field) const
uint64_t GetUInt64(const Message &message, const FieldDescriptor *field) const
int64_t GetInt64(const Message &message, const FieldDescriptor *field) const
uint64_t GetRepeatedUInt64(const Message &message, const FieldDescriptor *field, int index) const
Message * AddMessage(Message *message, const FieldDescriptor *field, MessageFactory *factory=nullptr) const
int FieldSize(const Message &message, const FieldDescriptor *field) const
const Message & GetRepeatedMessage(const Message &message, const FieldDescriptor *field, int index) const
void SetRepeatedInt64(Message *message, const FieldDescriptor *field, int index, int64_t value) const
Message * MutableMessage(Message *message, const FieldDescriptor *field, MessageFactory *factory=nullptr) const
void SetRepeatedInt32(Message *message, const FieldDescriptor *field, int index, int32_t value) const
void SetInt64(Message *message, const FieldDescriptor *field, int64_t value) const
bool GetBool(const Message &message, const FieldDescriptor *field) const
void AddUInt64(Message *message, const FieldDescriptor *field, uint64_t value) const
void AddInt32(Message *message, const FieldDescriptor *field, int32_t value) const
bool HasField(const Message &message, const FieldDescriptor *field) const
void AddString(Message *message, const FieldDescriptor *field, std::string value) const
void SetRepeatedEnum(Message *message, const FieldDescriptor *field, int index, const EnumValueDescriptor *value) const
void SetRepeatedUInt32(Message *message, const FieldDescriptor *field, int index, uint32_t value) const
const Message & GetMessage(const Message &message, const FieldDescriptor *field, MessageFactory *factory=nullptr) const
void AddInt64(Message *message, const FieldDescriptor *field, int64_t value) const
void SetRepeatedString(Message *message, const FieldDescriptor *field, int index, std::string value) const
void AddUInt32(Message *message, const FieldDescriptor *field, uint32_t value) const
void SetRepeatedDouble(Message *message, const FieldDescriptor *field, int index, double value) const
void SetInt32(Message *message, const FieldDescriptor *field, int32_t value) const
void SetRepeatedUInt64(Message *message, const FieldDescriptor *field, int index, uint64_t value) const
double GetRepeatedDouble(const Message &message, const FieldDescriptor *field, int index) const
void SetDouble(Message *message, const FieldDescriptor *field, double value) const
void SetRepeatedBool(Message *message, const FieldDescriptor *field, int index, bool value) const
void SetRepeatedFloat(Message *message, const FieldDescriptor *field, int index, float value) const
double GetDouble(const Message &message, const FieldDescriptor *field) const
uint32_t GetRepeatedUInt32(const Message &message, const FieldDescriptor *field, int index) const
void SetFloat(Message *message, const FieldDescriptor *field, float value) const
const EnumValueDescriptor * GetRepeatedEnum(const Message &message, const FieldDescriptor *field, int index) const
const EnumValueDescriptor * GetEnum(const Message &message, const FieldDescriptor *field) const
int64_t GetRepeatedInt64(const Message &message, const FieldDescriptor *field, int index) const
int32_t GetInt32(const Message &message, const FieldDescriptor *field) const
void AddBool(Message *message, const FieldDescriptor *field, bool value) const
Message * MutableRepeatedMessage(Message *message, const FieldDescriptor *field, int index) const
uint32_t GetUInt32(const Message &message, const FieldDescriptor *field) const
void SetString(Message *message, const FieldDescriptor *field, std::string value) const
float GetRepeatedFloat(const Message &message, const FieldDescriptor *field, int index) const
bool GetRepeatedBool(const Message &message, const FieldDescriptor *field, int index) const
void AddEnum(Message *message, const FieldDescriptor *field, const EnumValueDescriptor *value) const
std::string GetRepeatedString(const Message &message, const FieldDescriptor *field, int index) const
void AddFloat(Message *message, const FieldDescriptor *field, float value) const
void SetUInt64(Message *message, const FieldDescriptor *field, uint64_t value) const
void SetEnum(Message *message, const FieldDescriptor *field, const EnumValueDescriptor *value) const
void AddDouble(Message *message, const FieldDescriptor *field, double value) const
void SetBool(Message *message, const FieldDescriptor *field, bool value) const
void parse_for_moos(const std::string &in, google::protobuf::Message *msg)
Parses the string in to Google Protocol Buffers message msg. All errors are written to the goby::util...
std::shared_ptr< google::protobuf::Message > dynamic_parse_for_moos(const std::string &in)
bool serialize_for_moos(std::string *out, const google::protobuf::Message &msg)
Converts the Google Protocol Buffers message msg into a suitable (human readable) string out for send...
std::string add_name_to_enum(const std::string &enum_value, const std::string &field_name)
std::mutex dynamic_parse_mutex
std::map< int, std::string > run_serialize_algorithms(const google::protobuf::Message &in, const google::protobuf::RepeatedPtrField< protobuf::TranslatorEntry::PublishSerializer::Algorithm > &algorithms)
void set_moos_technique(const goby::moos::protobuf::GobyMOOSAppConfig &cfg)
const std::string MAGIC_PROTOBUF_HEADER
goby::moos::protobuf::TranslatorEntry::ParserSerializerTechnique moos_technique
goby::moos::protobuf::TranslatorEntry::ParserSerializerTechnique get_moos_technique()
bool val_from_string(std::string &out, const std::string &str, const std::string &key)
Definition moos_string.h:60
std::string strip_name_from_enum(const std::string &enum_value, const std::string &field_name)
std::mutex moos_technique_mutex
void hex_encode(const std::string &in, std::string *out, bool upper_case=false)
Encodes a (little-endian) hexadecimal string from a byte string. Index 0 of in is written to index 0 ...
Definition binary.h:94
void hex_decode(const std::string &in, std::string *out)
Decodes a (little-endian) hexadecimal string to a byte string. Index 0 and 1 (first byte) of in are w...
Definition binary.h:47
The global namespace for the Goby project.
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::PROTOBUF_NAMESPACE_ID::FieldOptions, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::GobyFieldOptions >, 11, false > field
extern ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< ::PROTOBUF_NAMESPACE_ID::MessageOptions, ::PROTOBUF_NAMESPACE_ID::internal::MessageTypeTraits< ::goby::GobyMessageOptions >, 11, false > msg
util::FlexOstream glog
Access the Goby logger through this object.