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