Merge lp:~tes/dccl/3.0-codec-groups into lp:~dccl-dev/dccl/3.0

Proposed by toby schneider
Status: Merged
Approved by: toby schneider
Approved revision: 321
Merged at revision: 297
Proposed branch: lp:~tes/dccl/3.0-codec-groups
Merge into: lp:~dccl-dev/dccl/3.0
Diff against target: 5407 lines (+2997/-930)
60 files modified
CMakeLists.txt (+2/-4)
src/CMakeLists.txt (+12/-2)
src/apps/dccl/dccl_tool.cpp (+208/-103)
src/arithmetic/field_codec_arithmetic.cpp (+25/-2)
src/binary.h (+23/-0)
src/ccl/CMakeLists.txt (+0/-1)
src/ccl/ccl_compatibility.cpp (+44/-17)
src/ccl/ccl_compatibility.h (+3/-4)
src/codec.cpp (+68/-30)
src/codec.h (+28/-10)
src/codecs2/field_codec_default.cpp (+25/-105)
src/codecs2/field_codec_default.h (+299/-319)
src/codecs2/field_codec_default_message.cpp (+15/-15)
src/codecs2/field_codec_default_message.h (+159/-201)
src/codecs3/field_codec_default.cpp (+122/-0)
src/codecs3/field_codec_default.h (+77/-0)
src/codecs3/field_codec_default_message.cpp (+236/-0)
src/codecs3/field_codec_default_message.h (+213/-0)
src/field_codec.cpp (+82/-18)
src/field_codec.h (+47/-5)
src/field_codec_id.cpp (+100/-0)
src/field_codec_id.h (+50/-0)
src/field_codec_manager.h (+169/-28)
src/field_codec_message_stack.cpp (+38/-4)
src/field_codec_message_stack.h (+7/-16)
src/field_codec_typed.h (+12/-3)
src/logger.cpp (+6/-4)
src/logger.h (+2/-1)
src/protobuf/option_extensions.proto (+8/-5)
src/test/CMakeLists.txt (+5/-0)
src/test/dccl_all_fields/test.cpp (+3/-1)
src/test/dccl_all_fields/test.proto (+2/-2)
src/test/dccl_arithmetic/test.proto (+7/-1)
src/test/dccl_ccl/test.cpp (+2/-4)
src/test/dccl_ccl/test.proto (+1/-0)
src/test/dccl_codec_group/CMakeLists.txt (+6/-0)
src/test/dccl_codec_group/test.cpp (+104/-0)
src/test/dccl_codec_group/test.proto (+77/-0)
src/test/dccl_custom_id/test.proto (+3/-0)
src/test/dccl_custom_message/test.proto (+2/-0)
src/test/dccl_default_id/test.proto (+8/-1)
src/test/dccl_header/header.proto (+9/-18)
src/test/dccl_header/test.cpp (+1/-1)
src/test/dccl_header/test.proto (+2/-1)
src/test/dccl_message_fix/CMakeLists.txt (+6/-0)
src/test/dccl_message_fix/test.cpp (+110/-0)
src/test/dccl_message_fix/test.proto (+31/-0)
src/test/dccl_numeric_bounds/test.proto (+3/-0)
src/test/dccl_repeated/test.cpp (+0/-1)
src/test/dccl_repeated/test.proto (+3/-0)
src/test/dccl_required_optional/test.proto (+1/-0)
src/test/dccl_static_methods/test.proto (+3/-0)
src/test/dccl_v2_all_fields/CMakeLists.txt (+6/-0)
src/test/dccl_v2_all_fields/test.cpp (+175/-0)
src/test/dccl_v2_all_fields/test.proto (+159/-0)
src/test/dccl_v2_header/CMakeLists.txt (+6/-0)
src/test/dccl_v2_header/header.proto (+54/-0)
src/test/dccl_v2_header/test.cpp (+92/-0)
src/test/dccl_v2_header/test.proto (+16/-0)
src/type_helper.h (+20/-3)
To merge this branch: bzr merge lp:~tes/dccl/3.0-codec-groups
Reviewer Review Type Date Requested Status
Chris Murphy (community) Approve
Review via email: mp+216939@code.launchpad.net

Description of the change

Two blueprints implemented:

1. http://gobysoft.org/wiki/DcclCodecGroups
These changes allow a user to change the codec name that is used for every field in an entire message with a single DCCLMessageOption. In addition, it defines an integer for the codec_version = N that resolves to a codec_group of "dccl.defaultN". This allows us to write new codecs for version 3 that fix bugs, improve functionality from version 2 while preserving backwards compatibility (since codec_version defaults to 2, the first version of Goby/DCCL that used Google Protobuf).

2. http://gobysoft.org/wiki/DcclImproveDefaultCodecs
These changes build on the codec_version defined in 1. to fix bugs and improve the efficiency of the DefaultMessageCodec and all the "repeated" field codecs that rely on the FieldCodecBase implementation (i.e. repeated calls of the singular encode/decode).

The links above go into more detail regarding the changes.

To post a comment you must log in.
lp:~tes/dccl/3.0-codec-groups updated
315. By toby schneider

Added exports for additional dccl libraries (ccl and arithmetic)

316. By toby schneider

Fixed export install location

317. By toby schneider

Added logging of size of each field to dlog

318. By toby schneider

1. Add vector size for repeated fields when reporting size during encode, 2. Restore setfill after timestamp formatting for logger

319. By toby schneider

Added b64_encode and b64_decode helper functions that are similar to their hex_* equivalents; Added 'loaded()' method to Codec to allow a user to see all the loaded DCCL messages

320. By toby schneider

Changed default string codec in v3 to use a length prefix that is sized based on max_length (not fixed to 8 bits)

321. By toby schneider

Added warning for users who don't specify (dccl.msg).codec_version to encourage use of the DCCL3 defaults: option (dccl.msg).codec_version=3

Revision history for this message
Chris Murphy (chrismurf-bluefin) wrote :

  Per our discussion yesterday, this seems like a reasonable approach. We discussed a few ideas that may or may not make it into the final:

1. Add a deprecation warning for people who are implicitly relying on DCCL2 behavior.
2. Allow codec groups to fall back on the standard codecs by default, so a Bluefin codec library could consist of the standard DCCL3 Codecs... "plus X".
3. Change codec group to codec library (I don't care)
4. More documentation

None of these are major or blockers.

review: Approve
Revision history for this message
toby schneider (tes) wrote :

The deprecation warning (1.) is included in this merge.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-01-06 17:25:02 +0000
3+++ CMakeLists.txt 2014-08-27 16:27:22 +0000
4@@ -72,7 +72,7 @@
5 install(DIRECTORY ${dccl_INC_DIR}/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include
6 FILES_MATCHING PATTERN "*.h" PATTERN "*.proto" PATTERN "test*" EXCLUDE)
7
8-install(EXPORT dccl-config DESTINATION share/${PROJECTNAME}/cmake)
9+install(EXPORT dccl-config DESTINATION share/dccl/cmake)
10
11 ## let cmake know where the headers are
12 include_directories(${dccl_INC_DIR})
13@@ -132,10 +132,8 @@
14 include_directories(${Cryptopp_INCLUDE_DIRS})
15 endif()
16
17+
18 ## start adding subdirectories
19 add_subdirectory(src)
20
21-## export a file for folks to use
22-export(TARGETS dccl FILE ${CMAKE_BINARY_DIR}/dccl-config.cmake)
23-file(APPEND ${CMAKE_BINARY_DIR}/dccl-config.cmake "set(DCCL_INCLUDE_DIR \"${dccl_INC_DIR}\")")
24
25
26=== modified file 'src/CMakeLists.txt'
27--- src/CMakeLists.txt 2014-01-08 22:30:52 +0000
28+++ src/CMakeLists.txt 2014-08-27 16:27:22 +0000
29@@ -10,9 +10,12 @@
30 codec.cpp
31 field_codec.cpp
32 field_codec_message_stack.cpp
33- field_codec_default.cpp
34- field_codec_default_message.cpp
35 field_codec_manager.cpp
36+ field_codec_id.cpp
37+ codecs2/field_codec_default.cpp
38+ codecs2/field_codec_default_message.cpp
39+ codecs3/field_codec_default_message.cpp
40+ codecs3/field_codec_default.cpp
41 type_helper.cpp
42 bitset.cpp
43 dynamic_protobuf_manager.cpp
44@@ -32,14 +35,21 @@
45 option(build_arithmetic "Build arithmetic coders shared library" ON)
46 option(build_ccl "Build Compact Control Language (CCL) legacy support shared library" ON)
47
48+set(DCCL_EXPORT_TARGETS dccl)
49+
50 if(build_ccl)
51 add_subdirectory(ccl)
52+ set(DCCL_EXPORT_TARGETS ${DCCL_EXPORT_TARGETS} dccl_ccl_compat)
53 endif()
54
55 if(build_arithmetic)
56 add_subdirectory(arithmetic)
57+ set(DCCL_EXPORT_TARGETS ${DCCL_EXPORT_TARGETS} dccl_arithmetic)
58 endif()
59
60+export(TARGETS ${DCCL_EXPORT_TARGETS} FILE ${CMAKE_BINARY_DIR}/dccl-config.cmake)
61+file(APPEND ${CMAKE_BINARY_DIR}/dccl-config.cmake "set(DCCL_INCLUDE_DIR \"${dccl_INC_DIR}\")")
62+
63 if(enable_testing)
64 add_subdirectory(test)
65 endif()
66
67=== modified file 'src/apps/dccl/dccl_tool.cpp'
68--- src/apps/dccl/dccl_tool.cpp 2014-04-22 20:08:20 +0000
69+++ src/apps/dccl/dccl_tool.cpp 2014-08-27 16:27:22 +0000
70@@ -26,6 +26,8 @@
71
72
73 #include <sstream>
74+#include <fstream>
75+
76
77 #include <google/protobuf/descriptor.h>
78 #include <google/protobuf/text_format.h>
79@@ -40,13 +42,16 @@
80 #include "dccl_tool.pb.h"
81
82 enum Action { NO_ACTION, ENCODE, DECODE, ANALYZE, DISP_PROTO };
83-enum Format { TEXTFORMAT, HEX, BASE64 };
84+enum Format { BINARY, TEXTFORMAT, HEX, BASE64 };
85
86 struct Config
87 {
88 Config()
89 : action(NO_ACTION),
90- format(HEX)
91+ format(BINARY),
92+ id_codec(dccl::Codec::default_id_codec_name()),
93+ verbose(false),
94+ omit_prefix(false)
95 { }
96
97 Action action;
98@@ -55,11 +60,14 @@
99 std::set<std::string> message;
100 std::set<std::string> proto_file;
101 Format format;
102+ std::string id_codec;
103+ bool verbose;
104+ bool omit_prefix;
105 };
106
107
108 void analyze(dccl::Codec& dccl, const Config& cfg);
109-void encode(dccl::Codec& dccl, const Config& cfg);
110+void encode(dccl::Codec& dccl, Config& cfg);
111 void decode(dccl::Codec& dccl, const Config& cfg);
112 void disp_proto(dccl::Codec& dccl, const Config& cfg);
113
114@@ -67,67 +75,95 @@
115 void load_desc(dccl::Codec* dccl, const google::protobuf::Descriptor* desc, const std::string& name);
116 void parse_options(int argc, char* argv[], Config* cfg);
117
118+
119 int main(int argc, char* argv[])
120 {
121- Config cfg;
122- parse_options(argc, argv, &cfg);
123-
124- dccl::dlog.connect(dccl::logger::WARN_PLUS, &std::cerr);
125-
126- dccl::DynamicProtobufManager::enable_compilation();
127-
128- for(std::set<std::string>::const_iterator it = cfg.include.begin(),
129- end = cfg.include.end(); it != end; ++it)
130- dccl::DynamicProtobufManager::add_include_path(*it);
131-
132- dccl::Codec dccl;
133- for(std::set<std::string>::const_iterator it = cfg.dlopen.begin(),
134- end = cfg.dlopen.end(); it != end; ++it)
135- dccl.load_library(*it);
136-
137- for(std::set<std::string>::const_iterator it = cfg.proto_file.begin(),
138- end = cfg.proto_file.end(); it != end; ++it)
139- {
140- const google::protobuf::FileDescriptor* file_desc =
141- dccl::DynamicProtobufManager::load_from_proto_file(*it);
142-
143- if(!file_desc)
144- {
145- std::cerr << "failed to read in: " << *it << std::endl;
146- exit(EXIT_FAILURE);
147- }
148-
149- // if no messages explicity specified, load them all.
150- if(cfg.message.empty())
151- {
152- for(int i = 0, n = file_desc->message_type_count(); i < n; ++i)
153- {
154- const google::protobuf::Descriptor* desc = file_desc->message_type(i);
155- cfg.message.insert(file_desc->message_type(i)->full_name());
156- }
157- }
158- }
159-
160- // Load up all the messages
161- for(std::set<std::string>::const_iterator it = cfg.message.begin(),
162- end = cfg.message.end(); it != end; ++it)
163- {
164- const google::protobuf::Descriptor* desc =
165- dccl::DynamicProtobufManager::find_descriptor(*it);
166- load_desc(&dccl, desc, *it);
167- }
168-
169- switch(cfg.action)
170- {
171- case ENCODE: encode(dccl, cfg); break;
172- case DECODE: decode(dccl, cfg); break;
173- case ANALYZE: analyze(dccl, cfg); break;
174- case DISP_PROTO: disp_proto(dccl, cfg); break;
175- default:
176- std::cerr << "No action specified (e.g. analyze, decode, encode). Try --help." << std::endl;
177- exit(EXIT_SUCCESS);
178-
179- }
180+ std::vector<void *> dl_handles;
181+ {
182+ Config cfg;
183+ parse_options(argc, argv, &cfg);
184+
185+ if(!cfg.verbose)
186+ dccl::dlog.connect(dccl::logger::WARN_PLUS, &std::cerr);
187+ else
188+ dccl::dlog.connect(dccl::logger::DEBUG1_PLUS, &std::cerr);
189+
190+ dccl::DynamicProtobufManager::enable_compilation();
191+
192+ for(std::set<std::string>::const_iterator it = cfg.include.begin(),
193+ end = cfg.include.end(); it != end; ++it)
194+ dccl::DynamicProtobufManager::add_include_path(*it);
195+
196+ for(std::set<std::string>::const_iterator it = cfg.dlopen.begin(),
197+ end = cfg.dlopen.end(); it != end; ++it)
198+ {
199+ void* handle = dlopen(it->c_str(), RTLD_LAZY);
200+ if(handle)
201+ {
202+ dl_handles.push_back(handle);
203+ }
204+ else
205+ {
206+ std::cerr << "Failed to open shared library: " << *it << std::endl;
207+ exit(EXIT_FAILURE);
208+ }
209+
210+ }
211+
212+ dccl::Codec dccl(cfg.id_codec);
213+ for(std::vector<void *>::iterator it = dl_handles.begin(),
214+ n = dl_handles.end(); it != n; ++it)
215+ dccl.load_library(*it);
216+
217+ bool no_messages_specified = cfg.message.empty();
218+ for(std::set<std::string>::const_iterator it = cfg.proto_file.begin(),
219+ end = cfg.proto_file.end(); it != end; ++it)
220+ {
221+ const google::protobuf::FileDescriptor* file_desc =
222+ dccl::DynamicProtobufManager::load_from_proto_file(*it);
223+
224+ if(!file_desc)
225+ {
226+ std::cerr << "failed to read in: " << *it << std::endl;
227+ exit(EXIT_FAILURE);
228+ }
229+
230+ // if no messages explicitly specified, load them all.
231+ if(no_messages_specified && cfg.action != ENCODE)
232+ {
233+ for(int i = 0, n = file_desc->message_type_count(); i < n; ++i)
234+ {
235+ cfg.message.insert(file_desc->message_type(i)->full_name());
236+ }
237+ }
238+ }
239+
240+ // Load up all the messages
241+ for(std::set<std::string>::const_iterator it = cfg.message.begin(),
242+ end = cfg.message.end(); it != end; ++it)
243+ {
244+ const google::protobuf::Descriptor* desc =
245+ dccl::DynamicProtobufManager::find_descriptor(*it);
246+ load_desc(&dccl, desc, *it);
247+ }
248+
249+ switch(cfg.action)
250+ {
251+ case ENCODE: encode(dccl, cfg); break;
252+ case DECODE: decode(dccl, cfg); break;
253+ case ANALYZE: analyze(dccl, cfg); break;
254+ case DISP_PROTO: disp_proto(dccl, cfg); break;
255+ default:
256+ std::cerr << "No action specified (e.g. analyze, decode, encode). Try --help." << std::endl;
257+ exit(EXIT_SUCCESS);
258+
259+ }
260+ }
261+
262+ for(std::vector<void *>::iterator it = dl_handles.begin(),
263+ n = dl_handles.end(); it != n; ++it)
264+ dlclose(*it);
265+
266 }
267
268
269@@ -137,16 +173,14 @@
270 dccl.info_all(&std::cout);
271 }
272
273-void encode(dccl::Codec& dccl, const Config& cfg)
274+void encode(dccl::Codec& dccl, Config& cfg)
275 {
276- if(cfg.message.size() != 1)
277+ if(cfg.message.size() > 1)
278 {
279- std::cerr << "Exactly one DCCL message must be specified with -m or --message" << std::endl;
280+ std::cerr << "No more than one DCCL message can be specified with -m or --message for encoding." << std::endl;
281 exit(EXIT_FAILURE);
282 }
283- const google::protobuf::Descriptor* desc =
284- dccl::DynamicProtobufManager::find_descriptor(*cfg.message.begin());
285- int dccl_id = dccl.id(desc);
286+ std::string command_line_name = *cfg.message.begin();
287
288 while(!std::cin.eof())
289 {
290@@ -156,6 +190,50 @@
291 boost::trim(input);
292 if(input.empty())
293 continue;
294+
295+ std::string name;
296+ if(input[0] == '|')
297+ {
298+ std::string::size_type close_bracket_pos = input.find('|', 1);
299+ if(close_bracket_pos == std::string::npos)
300+ {
301+ std::cerr << "Incorrectly formatted input: expected '|'" << std::endl;
302+ exit(EXIT_FAILURE);
303+ }
304+
305+ name = input.substr(1, close_bracket_pos-1);
306+ if(cfg.message.find(name) == cfg.message.end())
307+ {
308+ const google::protobuf::Descriptor* desc =
309+ dccl::DynamicProtobufManager::find_descriptor(name);
310+ load_desc(&dccl, desc, name);
311+ cfg.message.insert(name);
312+ }
313+
314+
315+ if(input.size() > close_bracket_pos+1)
316+ input = input.substr(close_bracket_pos+1);
317+ else
318+ input.clear();
319+ }
320+ else
321+ {
322+ if(cfg.message.size() == 0)
323+ {
324+ std::cerr << "Message name not given with -m or in the input (i.e. '[Name] field1: value field2: value')." << std::endl;
325+ exit(EXIT_FAILURE);
326+ }
327+
328+ name = command_line_name;
329+ }
330+
331+ const google::protobuf::Descriptor* desc = dccl::DynamicProtobufManager::find_descriptor(name);
332+ if(desc == 0)
333+ {
334+ std::cerr << "No descriptor with name " << name << " found! Make sure you have loaded all the necessary .proto files and/or shared libraries. Also make sure you specified the fully qualified name including the package, if any (e.g. 'goby.acomms.protobuf.NetworkAck', not just 'NetworkAck')." << std::endl;
335+ exit(EXIT_FAILURE);
336+ }
337+
338
339 boost::shared_ptr<google::protobuf::Message> msg = dccl::DynamicProtobufManager::new_protobuf_message(desc);
340 google::protobuf::TextFormat::ParseFromString(input, msg.get());
341@@ -167,6 +245,13 @@
342 switch(cfg.format)
343 {
344 default:
345+ case BINARY:
346+ {
347+ std::ofstream fout("/dev/stdout", std::ios::binary | std::ios::app);
348+ fout.write(encoded.data(), encoded.size());
349+ break;
350+ }
351+
352 case TEXTFORMAT:
353 {
354
355@@ -197,49 +282,61 @@
356
357 void decode(dccl::Codec& dccl, const Config& cfg)
358 {
359- if(cfg.message.size() != 1)
360+ std::string input;
361+ if(cfg.format == BINARY)
362 {
363- std::cerr << "Exactly one DCCL message must be specified with -m or --message" << std::endl;
364- exit(EXIT_FAILURE);
365+ std::ifstream fin("/dev/stdin", std::ios::binary);
366+ std::ostringstream ostrm;
367+ ostrm << fin.rdbuf();
368+ input = ostrm.str();
369 }
370-
371- while(!std::cin.eof())
372+ else
373 {
374- std::string input;
375- std::getline (std::cin, input);
376-
377- if(boost::trim_copy(input).empty())
378- continue;
379-
380- switch(cfg.format)
381+ while(!std::cin.eof())
382 {
383- default:
384- case TEXTFORMAT:
385+ std::string line;
386+ std::getline (std::cin, line);
387+
388+ if(boost::trim_copy(line).empty())
389+ continue;
390+
391+ switch(cfg.format)
392 {
393- boost::trim_if(input, boost::is_any_of("\""));
394-
395-
396- ByteString s;
397- google::protobuf::TextFormat::ParseFieldValueFromString("\"" + input + "\"", s.GetDescriptor()->FindFieldByNumber(1), &s);
398- input = s.b();
399- break;
400+ default:
401+ case BINARY:
402+ break;
403+
404+ case TEXTFORMAT:
405+ {
406+ boost::trim_if(line, boost::is_any_of("\""));
407+
408+
409+ ByteString s;
410+ google::protobuf::TextFormat::ParseFieldValueFromString("\"" + line + "\"", s.GetDescriptor()->FindFieldByNumber(1), &s);
411+ input += s.b();
412+ break;
413+ }
414+ case HEX:
415+ input += dccl::hex_decode(line);
416+ break;
417+ case BASE64:
418+ std::stringstream instream(line);
419+ std::stringstream outstream;
420+ base64::decoder D;
421+ D.decode(instream, outstream);
422+ input += outstream.str();
423+ break;
424 }
425- case HEX:
426- input = dccl::hex_decode(input);
427- break;
428- case BASE64:
429- std::string in = input;
430- std::stringstream instream(input);
431- std::stringstream outstream;
432- base64::decoder D;
433- D.decode(instream, outstream);
434- input = outstream.str();
435- break;
436 }
437+ }
438
439- boost::shared_ptr<google::protobuf::Message> msg = dccl.decode<boost::shared_ptr<google::protobuf::Message> >(input);
440+ while(!input.empty())
441+ {
442+ boost::shared_ptr<google::protobuf::Message> msg = dccl.decode<boost::shared_ptr<google::protobuf::Message> >(&input);
443+ if(!cfg.omit_prefix)
444+ std::cout << "|" << msg->GetDescriptor()->full_name() << "| ";
445 std::cout << msg->ShortDebugString() << std::endl;
446- }
447+ }
448 }
449
450 void disp_proto(dccl::Codec& dccl, const Config& cfg)
451@@ -286,7 +383,10 @@
452 options.push_back(dccl::Option('l', "dlopen", required_argument, "Open this shared library containing compiled DCCL messages."));
453 options.push_back(dccl::Option('m', "message", required_argument, "Message name to encode, decode or analyze."));
454 options.push_back(dccl::Option('f', "proto_file", required_argument, ".proto file to load."));
455- options.push_back(dccl::Option(0, "format", required_argument, "Format for encode output or decode input: 'hex' is ascii-encoded hexadecimal (default), 'textformat' is a Google Protobuf TextFormat byte string, 'base64' is ascii-encoded base 64."));
456+ options.push_back(dccl::Option(0, "format", required_argument, "Format for encode output or decode input: 'bin' (default) is raw binary, 'hex' is ascii-encoded hexadecimal, 'textformat' is a Google Protobuf TextFormat byte string, 'base64' is ascii-encoded base 64."));
457+ options.push_back(dccl::Option('v', "verbose", no_argument, "Display extra debugging information."));
458+ options.push_back(dccl::Option('o', "omit_prefix", no_argument, "Omit the DCCL type name prefix from the output of decode."));
459+ options.push_back(dccl::Option('i', "id_codec", required_argument, "(Advanced) name for a nonstandard DCCL ID codec to use"));
460
461 std::vector<option> long_options;
462 std::string opt_string;
463@@ -314,6 +414,8 @@
464 cfg->format = HEX;
465 else if(!strcmp(optarg, "base64"))
466 cfg->format = BASE64;
467+ else if(!strcmp(optarg, "bin"))
468+ cfg->format = BINARY;
469 else
470 {
471 std::cerr << "Invalid format '" << optarg << "'" << std::endl;
472@@ -336,6 +438,9 @@
473 case 'l': cfg->dlopen.insert(optarg); break;
474 case 'm': cfg->message.insert(optarg); break;
475 case 'f': cfg->proto_file.insert(optarg); break;
476+ case 'i': cfg->id_codec = optarg; break;
477+ case 'v': cfg->verbose = true; break;
478+ case 'o': cfg->omit_prefix = true; break;
479
480 case 'h':
481 std::cout << "Usage of the Dynamic Compact Control Language (DCCL) tool ('dccl'): " << std::endl;
482
483=== modified file 'src/arithmetic/field_codec_arithmetic.cpp'
484--- src/arithmetic/field_codec_arithmetic.cpp 2013-06-18 12:55:43 +0000
485+++ src/arithmetic/field_codec_arithmetic.cpp 2014-08-27 16:27:22 +0000
486@@ -38,9 +38,9 @@
487
488 // shared library load
489
490-extern "C"
491+struct CodecLoader
492 {
493- void dccl3_load(dccl::Codec* dccl)
494+ CodecLoader()
495 {
496 using namespace dccl;
497
498@@ -53,6 +53,29 @@
499 FieldCodecManager::add<ArithmeticFieldCodec<bool> >("_arithmetic");
500 FieldCodecManager::add<ArithmeticFieldCodec<const google::protobuf::EnumValueDescriptor*> >("_arithmetic");
501 }
502+ ~CodecLoader()
503+ {
504+ using namespace dccl;
505+
506+ FieldCodecManager::remove<ArithmeticFieldCodec<int32> >("_arithmetic");
507+ FieldCodecManager::remove<ArithmeticFieldCodec<int64> >("_arithmetic");
508+ FieldCodecManager::remove<ArithmeticFieldCodec<uint32> >("_arithmetic");
509+ FieldCodecManager::remove<ArithmeticFieldCodec<uint64> >("_arithmetic");
510+ FieldCodecManager::remove<ArithmeticFieldCodec<double> >("_arithmetic");
511+ FieldCodecManager::remove<ArithmeticFieldCodec<float> >("_arithmetic");
512+ FieldCodecManager::remove<ArithmeticFieldCodec<bool> >("_arithmetic");
513+ FieldCodecManager::remove<ArithmeticFieldCodec<const google::protobuf::EnumValueDescriptor*> >("_arithmetic");
514+ }
515+};
516+
517+
518+static CodecLoader loader;
519+
520+extern "C"
521+{
522+ void dccl3_load(dccl::Codec* dccl)
523+ {
524+ }
525 }
526
527 dccl::Model::symbol_type dccl::Model::value_to_symbol(value_type value) const
528
529=== modified file 'src/binary.h'
530--- src/binary.h 2014-04-22 20:10:37 +0000
531+++ src/binary.h 2014-08-27 16:27:22 +0000
532@@ -29,6 +29,8 @@
533 #include <sstream>
534
535 #include "dccl/common.h"
536+#include "dccl/b64/encode.h"
537+#include "dccl/b64/decode.h"
538
539 namespace dccl
540 {
541@@ -124,6 +126,27 @@
542 hex_encode(in, &out);
543 return out;
544 }
545+
546+
547+ inline std::string b64_encode(const std::string& in)
548+ {
549+ std::stringstream instream(in);
550+ std::stringstream outstream;
551+ base64::encoder D;
552+ D.encode(instream, outstream);
553+ return outstream.str();
554+ }
555+
556+ inline std::string b64_decode(const std::string& in)
557+ {
558+ std::stringstream instream(in);
559+ std::stringstream outstream;
560+ base64::decoder D;
561+ D.decode(instream, outstream);
562+ return outstream.str();
563+ }
564+
565+
566
567 /// \return ceil(log2(v))
568 inline unsigned ceil_log2(dccl::uint64 v)
569
570=== modified file 'src/ccl/CMakeLists.txt'
571--- src/ccl/CMakeLists.txt 2014-01-06 17:25:02 +0000
572+++ src/ccl/CMakeLists.txt 2014-08-27 16:27:22 +0000
573@@ -17,7 +17,6 @@
574 set_target_properties(dccl_ccl_compat
575 PROPERTIES VERSION "${DCCL_VERSION}" SOVERSION "${DCCL_SOVERSION}")
576
577-
578 install(TARGETS dccl_ccl_compat EXPORT dccl-config
579 LIBRARY DESTINATION lib
580 ARCHIVE DESTINATION lib)
581
582=== modified file 'src/ccl/ccl_compatibility.cpp'
583--- src/ccl/ccl_compatibility.cpp 2013-06-18 12:55:43 +0000
584+++ src/ccl/ccl_compatibility.cpp 2014-08-27 16:27:22 +0000
585@@ -31,27 +31,54 @@
586
587 // shared library load
588
589+struct CodecLoader
590+{
591+ CodecLoader()
592+ {
593+ using namespace dccl;
594+ FieldCodecManager::add<LegacyCCLIdentifierCodec>("dccl.ccl.id");
595+
596+ FieldCodecManager::add<LegacyCCLLatLonCompressedCodec>("_ccl_latloncompressed");
597+ FieldCodecManager::add<LegacyCCLFixAgeCodec>("_ccl_fix_age");
598+ FieldCodecManager::add<LegacyCCLTimeDateCodec>("_ccl_time_date");
599+ FieldCodecManager::add<LegacyCCLHeadingCodec>("_ccl_heading");
600+ FieldCodecManager::add<LegacyCCLDepthCodec>("_ccl_depth");
601+ FieldCodecManager::add<LegacyCCLVelocityCodec>("_ccl_velocity");
602+ FieldCodecManager::add<LegacyCCLWattsCodec>("_ccl_watts");
603+ FieldCodecManager::add<LegacyCCLGFIPitchOilCodec>("_ccl_gfi_pitch_oil");
604+ FieldCodecManager::add<LegacyCCLSpeedCodec>("_ccl_speed");
605+ FieldCodecManager::add<LegacyCCLHiResAltitudeCodec>("_ccl_hires_altitude");
606+ FieldCodecManager::add<LegacyCCLTemperatureCodec>("_ccl_temperature");
607+ FieldCodecManager::add<LegacyCCLSalinityCodec>("_ccl_salinity");
608+ FieldCodecManager::add<LegacyCCLSoundSpeedCodec>("_ccl_sound_speed");
609+ }
610+ ~CodecLoader()
611+ {
612+ using namespace dccl;
613+ FieldCodecManager::remove<LegacyCCLIdentifierCodec>("dccl.ccl.id");
614+
615+ FieldCodecManager::remove<LegacyCCLLatLonCompressedCodec>("_ccl_latloncompressed");
616+ FieldCodecManager::remove<LegacyCCLFixAgeCodec>("_ccl_fix_age");
617+ FieldCodecManager::remove<LegacyCCLTimeDateCodec>("_ccl_time_date");
618+ FieldCodecManager::remove<LegacyCCLHeadingCodec>("_ccl_heading");
619+ FieldCodecManager::remove<LegacyCCLDepthCodec>("_ccl_depth");
620+ FieldCodecManager::remove<LegacyCCLVelocityCodec>("_ccl_velocity");
621+ FieldCodecManager::remove<LegacyCCLWattsCodec>("_ccl_watts");
622+ FieldCodecManager::remove<LegacyCCLGFIPitchOilCodec>("_ccl_gfi_pitch_oil");
623+ FieldCodecManager::remove<LegacyCCLSpeedCodec>("_ccl_speed");
624+ FieldCodecManager::remove<LegacyCCLHiResAltitudeCodec>("_ccl_hires_altitude");
625+ FieldCodecManager::remove<LegacyCCLTemperatureCodec>("_ccl_temperature");
626+ FieldCodecManager::remove<LegacyCCLSalinityCodec>("_ccl_salinity");
627+ FieldCodecManager::remove<LegacyCCLSoundSpeedCodec>("_ccl_sound_speed");
628+ }
629+};
630+
631+static CodecLoader loader;
632
633 extern "C"
634 {
635 void dccl3_load(dccl::Codec* dccl)
636- {
637- using namespace dccl;
638-
639- FieldCodecManager::add<LegacyCCLLatLonCompressedCodec>("_ccl_latloncompressed");
640- FieldCodecManager::add<LegacyCCLFixAgeCodec>("_ccl_fix_age");
641- FieldCodecManager::add<LegacyCCLTimeDateCodec>("_ccl_time_date");
642- FieldCodecManager::add<LegacyCCLHeadingCodec>("_ccl_heading");
643- FieldCodecManager::add<LegacyCCLDepthCodec>("_ccl_depth");
644- FieldCodecManager::add<LegacyCCLVelocityCodec>("_ccl_velocity");
645- FieldCodecManager::add<LegacyCCLWattsCodec>("_ccl_watts");
646- FieldCodecManager::add<LegacyCCLGFIPitchOilCodec>("_ccl_gfi_pitch_oil");
647- FieldCodecManager::add<LegacyCCLSpeedCodec>("_ccl_speed");
648- FieldCodecManager::add<LegacyCCLHiResAltitudeCodec>("_ccl_hires_altitude");
649- FieldCodecManager::add<LegacyCCLTemperatureCodec>("_ccl_temperature");
650- FieldCodecManager::add<LegacyCCLSalinityCodec>("_ccl_salinity");
651- FieldCodecManager::add<LegacyCCLSoundSpeedCodec>("_ccl_sound_speed");
652-
653+ {
654 dccl->load<dccl::protobuf::CCLMDATEmpty>();
655 dccl->load<dccl::protobuf::CCLMDATRedirect>();
656 dccl->load<dccl::protobuf::CCLMDATBathy>();
657
658=== modified file 'src/ccl/ccl_compatibility.h'
659--- src/ccl/ccl_compatibility.h 2013-09-12 16:23:45 +0000
660+++ src/ccl/ccl_compatibility.h 2014-08-27 16:27:22 +0000
661@@ -24,7 +24,8 @@
662 #ifndef DCCLCCLCOMPATIBILITY20120426H
663 #define DCCLCCLCOMPATIBILITY20120426H
664
665-#include "dccl/field_codec_default.h"
666+#include "dccl/codecs2/field_codec_default.h"
667+#include "dccl/field_codec_id.h"
668 #include "dccl/ccl/protobuf/ccl.pb.h"
669 #include "dccl/ccl/protobuf/ccl_extensions.pb.h"
670
671@@ -33,8 +34,6 @@
672 void dccl3_load(dccl::Codec* dccl);
673 }
674
675-
676-
677 namespace dccl
678 {
679 const unsigned char DCCL_CCL_HEADER = 32;
680@@ -117,7 +116,7 @@
681 enum { LATLON_COMPRESSED_BYTE_SIZE = 3 };
682 };
683
684- class LegacyCCLFixAgeCodec : public dccl::DefaultNumericFieldCodec<dccl::uint32>
685+ class LegacyCCLFixAgeCodec : public dccl::v2::DefaultNumericFieldCodec<dccl::uint32>
686 {
687 private:
688 dccl::Bitset encode()
689
690=== modified file 'src/codec.cpp'
691--- src/codec.cpp 2014-04-22 20:10:37 +0000
692+++ src/codec.cpp 2014-08-27 16:27:22 +0000
693@@ -38,7 +38,9 @@
694 #endif // HAS_CRYPTOPP
695
696 #include "dccl/codec.h"
697-#include "field_codec_default.h"
698+#include "dccl/codecs2/field_codec_default.h"
699+#include "dccl/codecs3/field_codec_default.h"
700+#include "dccl/field_codec_id.h"
701
702 #include "dccl/protobuf/option_extensions.pb.h"
703
704@@ -63,7 +65,7 @@
705 dccl::Codec::Codec(const std::string& dccl_id_codec)
706 : id_codec_(dccl_id_codec)
707 {
708- FieldCodecManager::add<DefaultIdentifierCodec>("_default_id_codec");
709+ FieldCodecManager::add<DefaultIdentifierCodec>(default_id_codec_name());
710 // make sure the id codec exists
711 id_codec();
712 set_default_codecs();
713@@ -77,31 +79,59 @@
714 if(!defaults_loaded)
715 {
716 using google::protobuf::FieldDescriptor;
717-
718- FieldCodecManager::add<DefaultNumericFieldCodec<double> >(default_codec_name());
719- FieldCodecManager::add<DefaultNumericFieldCodec<float> >(default_codec_name());
720- FieldCodecManager::add<DefaultBoolCodec>(default_codec_name());
721- FieldCodecManager::add<DefaultNumericFieldCodec<int32> >(default_codec_name());
722- FieldCodecManager::add<DefaultNumericFieldCodec<int64> >(default_codec_name());
723- FieldCodecManager::add<DefaultNumericFieldCodec<uint32> >(default_codec_name());
724- FieldCodecManager::add<DefaultNumericFieldCodec<uint64> >(default_codec_name());
725- FieldCodecManager::add<DefaultStringCodec, FieldDescriptor::TYPE_STRING>(default_codec_name());
726- FieldCodecManager::add<DefaultBytesCodec, FieldDescriptor::TYPE_BYTES>(default_codec_name());
727- FieldCodecManager::add<DefaultEnumCodec>(default_codec_name());
728- FieldCodecManager::add<DefaultMessageCodec, FieldDescriptor::TYPE_MESSAGE>(default_codec_name());
729-
730- FieldCodecManager::add<TimeCodec<uint64> >("_time");
731- FieldCodecManager::add<TimeCodec<int64> >("_time");
732- FieldCodecManager::add<TimeCodec<double> >("_time");
733-
734- FieldCodecManager::add<StaticCodec<std::string> >("_static");
735- FieldCodecManager::add<StaticCodec<double> >("_static");
736- FieldCodecManager::add<StaticCodec<float> >("_static");
737- FieldCodecManager::add<StaticCodec<int32> >("_static");
738- FieldCodecManager::add<StaticCodec<int64> >("_static");
739- FieldCodecManager::add<StaticCodec<uint32> >("_static");
740- FieldCodecManager::add<StaticCodec<uint64> >("_static");
741-
742+
743+ // version 2
744+ FieldCodecManager::add<v2::DefaultNumericFieldCodec<double> >(default_codec_name());
745+ FieldCodecManager::add<v2::DefaultNumericFieldCodec<float> >(default_codec_name());
746+ FieldCodecManager::add<v2::DefaultBoolCodec>(default_codec_name());
747+ FieldCodecManager::add<v2::DefaultNumericFieldCodec<int32> >(default_codec_name());
748+ FieldCodecManager::add<v2::DefaultNumericFieldCodec<int64> >(default_codec_name());
749+ FieldCodecManager::add<v2::DefaultNumericFieldCodec<uint32> >(default_codec_name());
750+ FieldCodecManager::add<v2::DefaultNumericFieldCodec<uint64> >(default_codec_name());
751+ FieldCodecManager::add<v2::DefaultStringCodec, FieldDescriptor::TYPE_STRING>(default_codec_name());
752+ FieldCodecManager::add<v2::DefaultBytesCodec, FieldDescriptor::TYPE_BYTES>(default_codec_name());
753+ FieldCodecManager::add<v2::DefaultEnumCodec >(default_codec_name());
754+ FieldCodecManager::add<v2::DefaultMessageCodec, FieldDescriptor::TYPE_MESSAGE>(default_codec_name());
755+
756+ FieldCodecManager::add<v2::TimeCodec<uint64> >("dccl.time2");
757+ FieldCodecManager::add<v2::TimeCodec<int64> >("dccl.time2");
758+ FieldCodecManager::add<v2::TimeCodec<double> >("dccl.time2");
759+
760+ FieldCodecManager::add<v2::StaticCodec<std::string> >("dccl.static2");
761+ FieldCodecManager::add<v2::StaticCodec<double> >("dccl.static2");
762+ FieldCodecManager::add<v2::StaticCodec<float> >("dccl.static2");
763+ FieldCodecManager::add<v2::StaticCodec<int32> >("dccl.static2");
764+ FieldCodecManager::add<v2::StaticCodec<int64> >("dccl.static2");
765+ FieldCodecManager::add<v2::StaticCodec<uint32> >("dccl.static2");
766+ FieldCodecManager::add<v2::StaticCodec<uint64> >("dccl.static2");
767+
768+ // version 3
769+ FieldCodecManager::add<v3::DefaultNumericFieldCodec<double> >(default_codec_name(3));
770+ FieldCodecManager::add<v3::DefaultNumericFieldCodec<float> >(default_codec_name(3));
771+ FieldCodecManager::add<v3::DefaultBoolCodec>(default_codec_name(3));
772+ FieldCodecManager::add<v3::DefaultNumericFieldCodec<int32> >(default_codec_name(3));
773+ FieldCodecManager::add<v3::DefaultNumericFieldCodec<int64> >(default_codec_name(3));
774+ FieldCodecManager::add<v3::DefaultNumericFieldCodec<uint32> >(default_codec_name(3));
775+ FieldCodecManager::add<v3::DefaultNumericFieldCodec<uint64> >(default_codec_name(3));
776+ FieldCodecManager::add<v3::DefaultStringCodec, FieldDescriptor::TYPE_STRING>(default_codec_name(3));
777+ FieldCodecManager::add<v3::DefaultBytesCodec, FieldDescriptor::TYPE_BYTES>(default_codec_name(3));
778+ FieldCodecManager::add<v3::DefaultEnumCodec >(default_codec_name(3));
779+ FieldCodecManager::add<v3::DefaultMessageCodec, FieldDescriptor::TYPE_MESSAGE>(default_codec_name(3));
780+
781+ // for backwards compatibility
782+ FieldCodecManager::add<v2::TimeCodec<uint64> >("_time");
783+ FieldCodecManager::add<v2::TimeCodec<int64> >("_time");
784+ FieldCodecManager::add<v2::TimeCodec<double> >("_time");
785+
786+ FieldCodecManager::add<v2::StaticCodec<std::string> >("_static");
787+ FieldCodecManager::add<v2::StaticCodec<double> >("_static");
788+ FieldCodecManager::add<v2::StaticCodec<float> >("_static");
789+ FieldCodecManager::add<v2::StaticCodec<int32> >("_static");
790+ FieldCodecManager::add<v2::StaticCodec<int64> >("_static");
791+ FieldCodecManager::add<v2::StaticCodec<uint32> >("_static");
792+ FieldCodecManager::add<v2::StaticCodec<uint64> >("_static");
793+
794+
795 defaults_loaded = true;
796 }
797 }
798@@ -326,6 +356,9 @@
799 throw(Exception("Missing message option `(dccl.msg).id`. Specify a unique id (e.g. 3) in the body of your .proto message using \"option (dccl.msg).id = 3\""));
800 if(!desc->options().GetExtension(dccl::msg).has_max_bytes())
801 throw(Exception("Missing message option `(dccl.msg).max_bytes`. Specify a maximum (encoded) message size in bytes (e.g. 32) in the body of your .proto message using \"option (dccl.msg).max_bytes = 32\""));
802+
803+ if(!desc->options().GetExtension(dccl::msg).has_codec_version())
804+ dlog.is(WARN) && dlog << "** NOTE: No (dccl.msg).codec_version set for DCCL Message '" << desc->full_name() << "'. Unless you need backwards compatibility with Goby 2.0 (DCCL2), we highly recommend setting 'option (dccl.msg).codec_version = 3' in the message definition for " << desc->full_name() << " to use the default DCCL3 codecs. If you need compatibility with Goby 2.0, ignore this warning, or set 'option (dccl.msg).codec_version = 2' to remove this warning. **" << std::endl;
805
806 boost::shared_ptr<FieldCodecBase> codec = FieldCodecManager::find(desc);
807
808@@ -419,7 +452,8 @@
809 const unsigned allowed_byte_size = desc->options().GetExtension(dccl::msg).max_bytes();
810 const unsigned allowed_bit_size = allowed_byte_size * BITS_IN_BYTE;
811
812- std::string guard = std::string((full_width-desc->full_name().size())/2, '=');
813+ std::string message_name = boost::lexical_cast<std::string>(dccl_id) + ": " + desc->full_name();
814+ std::string guard = std::string((full_width-message_name.size())/2, '=');
815
816 std::string bits_dccl_head_str = "dccl.id head";
817 std::string bits_user_head_str = "user head";
818@@ -430,7 +464,7 @@
819 const int spaces = 8;
820 std::string indent = std::string(spaces,' ');
821
822- *os << guard << " " << desc->full_name() << " " << guard << "\n"
823+ *os << guard << " " << message_name << " " << guard << "\n"
824 << "Actual maximum size of message: " << byte_size << " bytes / "
825 << byte_size*BITS_IN_BYTE << " bits\n"
826 << indent << bits_dccl_head_str << std::setfill('.') << std::setw(bits_width-bits_dccl_head_str.size()) << id_bit_size << "\n"
827@@ -443,7 +477,7 @@
828 std::string header_str = "Header";
829 std::string header_guard = std::string((full_width-header_str.size())/2, '-');
830 *os << header_guard << " " << header_str << " " << header_guard << std::endl;
831- *os << bits_dccl_head_str << std::setfill('.') << std::setw(bits_width-bits_dccl_head_str.size()+spaces) << id_bit_size << "\n";
832+ *os << bits_dccl_head_str << std::setfill('.') << std::setw(bits_width-bits_dccl_head_str.size()+spaces) << id_bit_size << " {" << id_codec()->name() << "}\n";
833 codec->base_info(os, desc, MessageStack::HEAD);
834 // *os << std::string(header_str.size() + 2 + 2*header_guard.size(), '-') << std::endl;
835
836@@ -459,6 +493,9 @@
837 {
838 dlog.is(DEBUG1) && dlog << "Message " << desc->full_name() << " cannot provide information due to invalid configuration. Reason: " << e.what() << std::endl;
839 }
840+
841+ os->flush();
842+
843 }
844
845 }
846@@ -564,4 +601,5 @@
847
848 // *os << std::string(codec_str.size() + 2 + 2*codec_guard.size(), '|') << std::endl;
849 }
850+
851 }
852
853=== modified file 'src/codec.h'
854--- src/codec.h 2014-04-22 20:10:37 +0000
855+++ src/codec.h 2014-08-27 16:27:22 +0000
856@@ -42,7 +42,9 @@
857 #include "exception.h"
858 #include "field_codec.h"
859 #include "field_codec_fixed.h"
860-#include "field_codec_default.h"
861+
862+#include "codecs2/field_codec_default_message.h"
863+#include "codecs3/field_codec_default_message.h"
864 #include "type_helper.h"
865 #include "field_codec_manager.h"
866
867@@ -84,7 +86,7 @@
868 class Codec
869 {
870 public:
871- Codec(const std::string& dccl_id_codec = "_default_id_codec");
872+ Codec(const std::string& dccl_id_codec = default_id_codec_name());
873 virtual ~Codec()
874 {
875 for(std::vector<void *>::iterator it = dl_handles_.begin(),
876@@ -181,6 +183,9 @@
877 return desc->options().GetExtension(dccl::msg).id();
878 }
879
880+ /// \brief Provides a map of all loaded DCCL IDs to the equivalent Protobuf descriptor
881+ const std::map<int32, const google::protobuf::Descriptor*>& loaded() const { return id2desc_; }
882+
883 //@}
884
885 /// \brief Provides the encoded size (in bytes) of msg. This is useful if you need to know the size of a message before encoding it (encoding it is generally much more expensive than calling this method)
886@@ -237,8 +242,26 @@
887 /// \return pointer to decoded message (a google::protobuf::Message). You are responsible for deleting the memory used by this pointer, so we recommend using a smart pointer here (e.g. boost::shared_ptr or the C++11 equivalent). This message can be examined using the Google Reflection/Descriptor API.
888 template<typename GoogleProtobufMessagePointer>
889 GoogleProtobufMessagePointer decode(std::string* bytes);
890-
891- friend class DefaultMessageCodec;
892+
893+ static std::string default_id_codec_name()
894+ { return "dccl.default.id"; }
895+
896+
897+ static std::string default_codec_name(int version = 2)
898+ {
899+ switch(version)
900+ {
901+ case 2:
902+ return dccl::DCCLFieldOptions::descriptor()->FindFieldByName("codec")->default_value_string();
903+ default:
904+ return "dccl.default" + boost::lexical_cast<std::string>(version);
905+ }
906+
907+ }
908+
909+
910+ friend class v2::DefaultMessageCodec;
911+ //friend class v3::DefaultMessageCodec;
912 private:
913 Codec(const Codec&);
914 Codec& operator= (const Codec&);
915@@ -254,11 +277,6 @@
916 id_codec_);
917 }
918
919- static const std::string& default_codec_name()
920- {
921- return dccl::DCCLFieldOptions::descriptor()->FindFieldByName("codec")->default_value_string();
922- }
923-
924 private:
925 // SHA256 hash of the crypto passphrase
926 std::string crypto_key_;
927@@ -287,7 +305,7 @@
928 unsigned this_id = id(bytes);
929
930 if(!id2desc_.count(this_id))
931- throw(Exception("Message id " + boost::lexical_cast<std::string>(this_id) + " has not been validated. Call validate() before decoding this type."));
932+ throw(Exception("Message id " + boost::lexical_cast<std::string>(this_id) + " has not been loaded. Call load() before decoding this type."));
933
934 // ownership of this object goes to the caller of decode()
935 GoogleProtobufMessagePointer msg =
936
937=== added directory 'src/codecs2'
938=== renamed file 'src/field_codec_default.cpp' => 'src/codecs2/field_codec_default.cpp'
939--- src/field_codec_default.cpp 2014-04-22 20:10:37 +0000
940+++ src/codecs2/field_codec_default.cpp 2014-08-27 16:27:22 +0000
941@@ -25,108 +25,28 @@
942 #include <sstream>
943 #include <algorithm>
944
945-#include "field_codec_default.h"
946-#include "type_helper.h"
947+#include "dccl/codecs2/field_codec_default.h"
948+#include "dccl/type_helper.h"
949 #include "dccl/codec.h"
950
951 using namespace dccl::logger;
952
953
954 //
955-// DefaultIdentifierCodec
956-//
957-
958-dccl::Bitset dccl::DefaultIdentifierCodec::encode()
959-{
960- return encode(0);
961-}
962-
963-dccl::Bitset dccl::DefaultIdentifierCodec::encode(const uint32& id)
964-{
965- if(id <= ONE_BYTE_MAX_ID)
966- {
967- return(dccl::Bitset(this_size(id), id) << 1);
968- }
969- else
970- {
971- dccl::Bitset return_bits(this_size(id), id);
972- return_bits <<= 1;
973- // set LSB to indicate long header form
974- return_bits.set(0, true);
975-
976-
977- return return_bits;
978- }
979-}
980-
981-dccl::uint32 dccl::DefaultIdentifierCodec::decode(Bitset* bits)
982-{
983- if(bits->test(0))
984- {
985- // long header
986- // grabs more bits to add to the MSB of `bits`
987- bits->get_more_bits((LONG_FORM_ID_BYTES - SHORT_FORM_ID_BYTES)*BITS_IN_BYTE);
988- // discard identifier
989- *(bits) >>= 1;
990- return bits->to_ulong();
991- }
992- else
993- {
994- // short header
995- *(bits) >>= 1;
996- return bits->to_ulong();
997- }
998-}
999-
1000-unsigned dccl::DefaultIdentifierCodec::size()
1001-{
1002- return this_size(0);
1003-}
1004-
1005-unsigned dccl::DefaultIdentifierCodec::size(const uint32& id)
1006-{
1007- return this_size(id);
1008-}
1009-
1010-unsigned dccl::DefaultIdentifierCodec::this_size(const uint32& id)
1011-{
1012- if(id > TWO_BYTE_MAX_ID)
1013- throw(Exception("dccl.id provided (" + boost::lexical_cast<std::string>(id) + ") exceeds maximum: " + boost::lexical_cast<std::string>(int(TWO_BYTE_MAX_ID))));
1014-
1015- return (id <= ONE_BYTE_MAX_ID) ?
1016- SHORT_FORM_ID_BYTES*BITS_IN_BYTE :
1017- LONG_FORM_ID_BYTES*BITS_IN_BYTE;
1018-}
1019-
1020-
1021-unsigned dccl::DefaultIdentifierCodec::max_size()
1022-{
1023- return LONG_FORM_ID_BYTES * BITS_IN_BYTE;
1024-}
1025-
1026-unsigned dccl::DefaultIdentifierCodec::min_size()
1027-{
1028- return SHORT_FORM_ID_BYTES * BITS_IN_BYTE;
1029-}
1030-
1031-
1032-
1033-
1034-//
1035 // DefaultBoolCodec
1036 //
1037
1038-dccl::Bitset dccl::DefaultBoolCodec::encode()
1039+dccl::Bitset dccl::v2::DefaultBoolCodec::encode()
1040 {
1041 return Bitset(size());
1042 }
1043
1044-dccl::Bitset dccl::DefaultBoolCodec::encode(const bool& wire_value)
1045+dccl::Bitset dccl::v2::DefaultBoolCodec::encode(const bool& wire_value)
1046 {
1047 return Bitset(size(), this_field()->is_required() ? wire_value : wire_value + 1);
1048 }
1049
1050-bool dccl::DefaultBoolCodec::decode(Bitset* bits)
1051+bool dccl::v2::DefaultBoolCodec::decode(Bitset* bits)
1052 {
1053 unsigned long t = bits->to_ulong();
1054 if(this_field()->is_required())
1055@@ -145,7 +65,7 @@
1056 }
1057
1058
1059-unsigned dccl::DefaultBoolCodec::size()
1060+unsigned dccl::v2::DefaultBoolCodec::size()
1061 {
1062 // true and false
1063 const unsigned BOOL_VALUES = 2;
1064@@ -155,19 +75,19 @@
1065 return dccl::ceil_log2(BOOL_VALUES + NULL_VALUE);
1066 }
1067
1068-void dccl::DefaultBoolCodec::validate()
1069+void dccl::v2::DefaultBoolCodec::validate()
1070 { }
1071
1072 //
1073 // DefaultStringCodec
1074 //
1075
1076-dccl::Bitset dccl::DefaultStringCodec::encode()
1077+dccl::Bitset dccl::v2::DefaultStringCodec::encode()
1078 {
1079 return Bitset(min_size());
1080 }
1081
1082-dccl::Bitset dccl::DefaultStringCodec::encode(const std::string& wire_value)
1083+dccl::Bitset dccl::v2::DefaultStringCodec::encode(const std::string& wire_value)
1084 {
1085 std::string s = wire_value;
1086 if(s.size() > dccl_field_options().max_length())
1087@@ -197,7 +117,7 @@
1088 return length_bits;
1089 }
1090
1091-std::string dccl::DefaultStringCodec::decode(Bitset* bits)
1092+std::string dccl::v2::DefaultStringCodec::decode(Bitset* bits)
1093 {
1094 unsigned value_length = bits->to_ulong();
1095
1096@@ -228,30 +148,30 @@
1097
1098 }
1099
1100-unsigned dccl::DefaultStringCodec::size()
1101+unsigned dccl::v2::DefaultStringCodec::size()
1102 {
1103 return min_size();
1104 }
1105
1106-unsigned dccl::DefaultStringCodec::size(const std::string& wire_value)
1107+unsigned dccl::v2::DefaultStringCodec::size(const std::string& wire_value)
1108 {
1109 return std::min(min_size() + static_cast<unsigned>(wire_value.length()*BITS_IN_BYTE), max_size());
1110 }
1111
1112
1113-unsigned dccl::DefaultStringCodec::max_size()
1114+unsigned dccl::v2::DefaultStringCodec::max_size()
1115 {
1116 // string length + actual string
1117 return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
1118 }
1119
1120-unsigned dccl::DefaultStringCodec::min_size()
1121+unsigned dccl::v2::DefaultStringCodec::min_size()
1122 {
1123 return dccl::ceil_log2(MAX_STRING_LENGTH+1);
1124 }
1125
1126
1127-void dccl::DefaultStringCodec::validate()
1128+void dccl::v2::DefaultStringCodec::validate()
1129 {
1130 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
1131 require(dccl_field_options().max_length() <= MAX_STRING_LENGTH,
1132@@ -261,13 +181,13 @@
1133 //
1134 // DefaultBytesCodec
1135 //
1136-dccl::Bitset dccl::DefaultBytesCodec::encode()
1137+dccl::Bitset dccl::v2::DefaultBytesCodec::encode()
1138 {
1139 return Bitset(min_size(), 0);
1140 }
1141
1142
1143-dccl::Bitset dccl::DefaultBytesCodec::encode(const std::string& wire_value)
1144+dccl::Bitset dccl::v2::DefaultBytesCodec::encode(const std::string& wire_value)
1145 {
1146 Bitset bits;
1147 bits.from_byte_string(wire_value);
1148@@ -282,19 +202,19 @@
1149 return bits;
1150 }
1151
1152-unsigned dccl::DefaultBytesCodec::size()
1153+unsigned dccl::v2::DefaultBytesCodec::size()
1154 {
1155 return min_size();
1156 }
1157
1158
1159-unsigned dccl::DefaultBytesCodec::size(const std::string& wire_value)
1160+unsigned dccl::v2::DefaultBytesCodec::size(const std::string& wire_value)
1161 {
1162 return max_size();
1163 }
1164
1165
1166-std::string dccl::DefaultBytesCodec::decode(Bitset* bits)
1167+std::string dccl::v2::DefaultBytesCodec::decode(Bitset* bits)
1168 {
1169 if(!this_field()->is_required())
1170 {
1171@@ -320,13 +240,13 @@
1172 }
1173 }
1174
1175-unsigned dccl::DefaultBytesCodec::max_size()
1176+unsigned dccl::v2::DefaultBytesCodec::max_size()
1177 {
1178 return dccl_field_options().max_length() * BITS_IN_BYTE +
1179 (this_field()->is_required() ? 0 : 1); // presence bit?
1180 }
1181
1182-unsigned dccl::DefaultBytesCodec::min_size()
1183+unsigned dccl::v2::DefaultBytesCodec::min_size()
1184 {
1185 if(this_field()->is_required())
1186 return max_size();
1187@@ -334,7 +254,7 @@
1188 return 1; // presence bit
1189 }
1190
1191-void dccl::DefaultBytesCodec::validate()
1192+void dccl::v2::DefaultBytesCodec::validate()
1193 {
1194 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
1195 }
1196@@ -342,12 +262,12 @@
1197 //
1198 // DefaultEnumCodec
1199 //
1200-dccl::int32 dccl::DefaultEnumCodec::pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value)
1201+dccl::int32 dccl::v2::DefaultEnumCodec::pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value)
1202 {
1203 return field_value->index();
1204 }
1205
1206-const google::protobuf::EnumValueDescriptor* dccl::DefaultEnumCodec::post_decode(const dccl::int32& wire_value)
1207+const google::protobuf::EnumValueDescriptor* dccl::v2::DefaultEnumCodec::post_decode(const dccl::int32& wire_value)
1208 {
1209 const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
1210
1211
1212=== renamed file 'src/field_codec_default.h' => 'src/codecs2/field_codec_default.h'
1213--- src/field_codec_default.h 2014-04-22 20:10:37 +0000
1214+++ src/codecs2/field_codec_default.h 2014-08-27 16:27:22 +0000
1215@@ -2,6 +2,7 @@
1216 // GobySoft, LLC (2013-)
1217 // Massachusetts Institute of Technology (2007-2014)
1218 // DCCL Developers Team (https://launchpad.net/~dccl-dev)
1219+//
1220 //
1221 // This file is part of the Dynamic Compact Control Language Library
1222 // ("DCCL").
1223@@ -39,328 +40,307 @@
1224
1225 #include "dccl/protobuf/option_extensions.pb.h"
1226
1227-#include "field_codec_default_message.h"
1228-#include "field_codec_fixed.h"
1229-#include "field_codec.h"
1230-#include "binary.h"
1231+#include "dccl/codecs2/field_codec_default_message.h"
1232+#include "dccl/field_codec_fixed.h"
1233+#include "dccl/field_codec.h"
1234+#include "dccl/binary.h"
1235
1236 namespace dccl
1237 {
1238- /// \brief Provides the default 1 byte or 2 byte DCCL ID codec
1239- class DefaultIdentifierCodec : public TypedFieldCodec<uint32>
1240- {
1241- protected:
1242- virtual Bitset encode();
1243- virtual Bitset encode(const uint32& wire_value);
1244- virtual uint32 decode(Bitset* bits);
1245- virtual unsigned size();
1246- virtual unsigned size(const uint32& wire_value);
1247- virtual unsigned max_size();
1248- virtual unsigned min_size();
1249- virtual void validate() { }
1250-
1251- private:
1252- unsigned this_size(const uint32& wire_value);
1253- // maximum id we can fit in short or long header (MSB reserved to indicate
1254- // short or long header)
1255- enum { ONE_BYTE_MAX_ID = (1 << 7) - 1,
1256- TWO_BYTE_MAX_ID = (1 << 15) - 1};
1257-
1258- enum { SHORT_FORM_ID_BYTES = 1,
1259- LONG_FORM_ID_BYTES = 2 };
1260- };
1261-
1262-
1263-
1264- /// \brief Provides a basic bounded arbitrary length numeric (double, float, uint32, uint64, int32, int64) encoder.
1265- ///
1266- /// Takes ceil(log2((max-min)*10^precision)+1) bits for required fields, ceil(log2((max-min)*10^precision)+2) for optional fields.
1267- template<typename WireType, typename FieldType = WireType>
1268- class DefaultNumericFieldCodec : public TypedFixedFieldCodec<WireType, FieldType>
1269- {
1270- protected:
1271-
1272- virtual double max()
1273- { return FieldCodecBase::dccl_field_options().max(); }
1274-
1275- virtual double min()
1276- { return FieldCodecBase::dccl_field_options().min(); }
1277-
1278- virtual double precision()
1279- { return FieldCodecBase::dccl_field_options().precision(); }
1280-
1281- virtual void validate()
1282- {
1283- FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_min(),
1284- "missing (dccl.field).min");
1285- FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_max(),
1286- "missing (dccl.field).max");
1287-
1288- validate_numeric_bounds();
1289- }
1290-
1291- void validate_numeric_bounds()
1292- {
1293-
1294- // ensure given max and min fit within WireType ranges
1295- FieldCodecBase::require(min() >= boost::numeric::bounds<WireType>::lowest(),
1296- "(dccl.field).min must be >= minimum of this field type.");
1297- FieldCodecBase::require(max() <= boost::numeric::bounds<WireType>::highest(),
1298- "(dccl.field).max must be <= maximum of this field type.");
1299-
1300-
1301- // ensure value fits into double
1302- FieldCodecBase::require((precision() + std::ceil(std::log10(max() - min()))) <= std::numeric_limits<double>::digits10,
1303- "[(dccl.field).max-(dccl.field).min]*10^(dccl.field).precision must fit in a double-precision floating point value. Please increase min, decrease max, or decrease precision.");
1304-
1305- }
1306-
1307-
1308- Bitset encode()
1309- {
1310- return Bitset(size());
1311- }
1312-
1313-
1314- virtual Bitset encode(const WireType& value)
1315- {
1316- WireType wire_value = value;
1317-
1318- if(wire_value < min() || wire_value > max())
1319- return Bitset(size());
1320-
1321- wire_value -= (WireType)min();
1322-
1323- wire_value = dccl::round(wire_value, precision());
1324- if (precision() < 0) {
1325- wire_value /= (WireType)std::pow(10.0, -precision());
1326- } else if (precision() > 0) {
1327- wire_value *= (WireType)std::pow(10.0, precision());
1328- }
1329-
1330- // "presence" value (0)
1331- if(!FieldCodecBase::this_field()->is_required())
1332- wire_value += 1;
1333-
1334-
1335- Bitset encoded;
1336- encoded.from(boost::numeric_cast<dccl::uint64>(dccl::round(wire_value, 0)), size());
1337- return encoded;
1338- }
1339-
1340- virtual WireType decode(Bitset* bits)
1341- {
1342- // The line below SHOULD BE:
1343- // dccl::uint64 t = bits->to<dccl::uint64>();
1344- // But GCC3.3 requires an explicit template modifier on the method.
1345- // See, e.g., http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10959
1346- dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
1347-
1348- if(!FieldCodecBase::this_field()->is_required())
1349- {
1350- if(!uint_value) throw NullValueException();
1351- --uint_value;
1352- }
1353-
1354- WireType wire_value = (WireType)uint_value;
1355-
1356- if (precision() < 0) {
1357- wire_value *= (WireType)std::pow(10.0, -precision());
1358- } else if (precision() > 0) {
1359- wire_value /= (WireType)std::pow(10.0, precision());
1360- }
1361-
1362- // round values again to properly handle cases where double precision
1363- // leads to slightly off values (e.g. 2.099999999 instead of 2.1)
1364- wire_value = dccl::round(wire_value + (WireType)min(),
1365- precision());
1366-
1367- return wire_value;
1368- }
1369-
1370- unsigned size()
1371- {
1372- // if not required field, leave one value for unspecified (always encoded as 0)
1373- const unsigned NULL_VALUE = FieldCodecBase::this_field()->is_required() ? 0 : 1;
1374-
1375- return dccl::ceil_log2((max()-min())*std::pow(10.0, precision())+1 + NULL_VALUE);
1376- }
1377-
1378- };
1379-
1380- /// \brief Provides a bool encoder. Uses 1 bit if field is `required`, 2 bits if `optional`
1381- ///
1382- /// [presence bit (0 bits if required, 1 bit if optional)][value (1 bit)]
1383- class DefaultBoolCodec : public TypedFixedFieldCodec<bool>
1384- {
1385- private:
1386- Bitset encode(const bool& wire_value);
1387- Bitset encode();
1388- bool decode(Bitset* bits);
1389- unsigned size();
1390- void validate();
1391- };
1392-
1393- /// \brief Provides an variable length ASCII string encoder. Can encode strings up to 255 bytes by using a length byte preceeding the string.
1394- ///
1395- /// [length of following string (1 byte)][string (0-255 bytes)]
1396- class DefaultStringCodec : public TypedFieldCodec<std::string>
1397- {
1398- private:
1399- Bitset encode();
1400- Bitset encode(const std::string& wire_value);
1401- std::string decode(Bitset* bits);
1402- unsigned size();
1403- unsigned size(const std::string& wire_value);
1404- unsigned max_size();
1405- unsigned min_size();
1406- void validate();
1407- private:
1408- enum { MAX_STRING_LENGTH = 255 };
1409-
1410- };
1411-
1412-
1413- /// \brief Provides an fixed length byte string encoder.
1414- class DefaultBytesCodec : public TypedFieldCodec<std::string>
1415- {
1416- private:
1417- Bitset encode();
1418- Bitset encode(const std::string& wire_value);
1419- std::string decode(Bitset* bits);
1420- unsigned size();
1421- unsigned size(const std::string& wire_value);
1422- unsigned max_size();
1423- unsigned min_size();
1424- void validate();
1425- };
1426-
1427- /// \brief Provides an enum encoder. This converts the enumeration to an integer (based on the enumeration <i>index</i> (<b>not</b> its <i>value</i>) and uses DefaultNumericFieldCodec to encode the integer.
1428- class DefaultEnumCodec
1429- : public DefaultNumericFieldCodec<int32, const google::protobuf::EnumValueDescriptor*>
1430- {
1431- public:
1432- int32 pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value);
1433- const google::protobuf::EnumValueDescriptor* post_decode(const int32& wire_value);
1434-
1435- private:
1436- void validate() { }
1437-
1438- double max()
1439- {
1440- const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
1441- return e->value_count()-1;
1442- }
1443- double min()
1444- { return 0; }
1445- };
1446-
1447-
1448- /// \brief Encodes time of day (default: second precision, but can be set with (dccl.field).precision extension)
1449- ///
1450- /// \tparam TimeType A type representing time: See the various specializations of this class for allowed types.
1451-
1452- typedef double time_wire_type;
1453- template<typename TimeType, int conversion_factor>
1454- class TimeCodecBase : public DefaultNumericFieldCodec<time_wire_type, TimeType>
1455- {
1456- public:
1457- time_wire_type pre_encode(const TimeType& time_of_day) {
1458- time_wire_type max_secs = max();
1459- return std::fmod(time_of_day / static_cast<time_wire_type>(conversion_factor), max_secs);
1460- }
1461-
1462- TimeType post_decode(const time_wire_type& encoded_time) {
1463-
1464- int64 max_secs = (int64)max();
1465- timeval t;
1466- gettimeofday(&t, 0);
1467- int64 now = t.tv_sec;
1468- int64 daystart = now - (now % max_secs);
1469- int64 today_time = now - daystart;
1470-
1471- // If time is more than 12 hours ahead of now, assume it's yesterday.
1472- if ((encoded_time - today_time) > (max_secs/2)) {
1473- daystart -= max_secs;
1474- } else if ((today_time - encoded_time) > (max_secs/2)) {
1475- daystart += max_secs;
1476- }
1477-
1478- return (TimeType)(conversion_factor * (daystart + encoded_time));
1479- }
1480-
1481- private:
1482- void validate()
1483- {
1484- DefaultNumericFieldCodec<time_wire_type, TimeType>::validate_numeric_bounds();
1485- }
1486-
1487- double max() {
1488- return FieldCodecBase::dccl_field_options().num_days() * SECONDS_IN_DAY;
1489- }
1490-
1491- double min() { return 0; }
1492- double precision()
1493- {
1494- if(!FieldCodecBase::dccl_field_options().has_precision())
1495- return 0; // default to second precision
1496- else
1497- {
1498- return FieldCodecBase::dccl_field_options().precision() + (double)std::log10((double)conversion_factor);
1499- }
1500-
1501- }
1502-
1503-
1504- private:
1505- enum { SECONDS_IN_DAY = 86400 };
1506- };
1507-
1508- template<typename TimeType>
1509- class TimeCodec : public TimeCodecBase<TimeType, 0>
1510- { BOOST_STATIC_ASSERT(sizeof(TimeCodec) == 0); };
1511-
1512- template<> class TimeCodec<uint64> : public TimeCodecBase<uint64, 1000000> { };
1513- template<> class TimeCodec<int64> : public TimeCodecBase<int64, 1000000> { };
1514- template<> class TimeCodec<double> : public TimeCodecBase<double, 1> { };
1515-
1516-
1517- /// \brief Placeholder codec that takes no space on the wire (0 bits).
1518- template<typename T>
1519- class StaticCodec : public TypedFixedFieldCodec<T>
1520- {
1521- Bitset encode(const T&)
1522- { return Bitset(size()); }
1523-
1524- Bitset encode()
1525- { return Bitset(size()); }
1526-
1527- T decode(Bitset* bits)
1528- {
1529- return boost::lexical_cast<T>(
1530- FieldCodecBase::dccl_field_options().static_value());
1531- }
1532-
1533- unsigned size()
1534- { return 0; }
1535-
1536- void validate()
1537- {
1538- FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_static_value(), "missing (dccl.field).static_value");
1539-
1540- std::string t = FieldCodecBase::dccl_field_options().static_value();
1541- try
1542- {
1543- boost::lexical_cast<T>(t);
1544- }
1545- catch(boost::bad_lexical_cast&)
1546- {
1547- FieldCodecBase::require(false, "invalid static_value for this type.");
1548- }
1549- }
1550-
1551- };
1552-
1553+ namespace v2
1554+ {
1555+ /// \brief Provides a basic bounded arbitrary length numeric (double, float, uint32, uint64, int32, int64) encoder.
1556+ ///
1557+ /// Takes ceil(log2((max-min)*10^precision)+1) bits for required fields, ceil(log2((max-min)*10^precision)+2) for optional fields.
1558+ template<typename WireType, typename FieldType = WireType>
1559+ class DefaultNumericFieldCodec : public TypedFixedFieldCodec<WireType, FieldType>
1560+ {
1561+ protected:
1562+
1563+ virtual double max()
1564+ { return FieldCodecBase::dccl_field_options().max(); }
1565+
1566+ virtual double min()
1567+ { return FieldCodecBase::dccl_field_options().min(); }
1568+
1569+ virtual double precision()
1570+ { return FieldCodecBase::dccl_field_options().precision(); }
1571+
1572+ virtual void validate()
1573+ {
1574+ FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_min(),
1575+ "missing (dccl.field).min");
1576+ FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_max(),
1577+ "missing (dccl.field).max");
1578+
1579+ validate_numeric_bounds();
1580+ }
1581+
1582+ void validate_numeric_bounds()
1583+ {
1584+
1585+ // ensure given max and min fit within WireType ranges
1586+ FieldCodecBase::require(min() >= boost::numeric::bounds<WireType>::lowest(),
1587+ "(dccl.field).min must be >= minimum of this field type.");
1588+ FieldCodecBase::require(max() <= boost::numeric::bounds<WireType>::highest(),
1589+ "(dccl.field).max must be <= maximum of this field type.");
1590+
1591+
1592+ // ensure value fits into double
1593+ FieldCodecBase::require((precision() + std::ceil(std::log10(max() - min()))) <= std::numeric_limits<double>::digits10,
1594+ "[(dccl.field).max-(dccl.field).min]*10^(dccl.field).precision must fit in a double-precision floating point value. Please increase min, decrease max, or decrease precision.");
1595+
1596+ }
1597+
1598+
1599+ Bitset encode()
1600+ {
1601+ return Bitset(size());
1602+ }
1603+
1604+
1605+ virtual Bitset encode(const WireType& value)
1606+ {
1607+ // round first, before checking bounds
1608+ WireType wire_value = dccl::round(value, precision());
1609+
1610+ // check bounds, if out-of-bounds, send as zeros
1611+ if(wire_value < min() || wire_value > max())
1612+ return Bitset(size());
1613+
1614+ wire_value -= dccl::round((WireType)min(), precision());
1615+
1616+ if (precision() < 0) {
1617+ wire_value /= (WireType)std::pow(10.0, -precision());
1618+ } else if (precision() > 0) {
1619+ wire_value *= (WireType)std::pow(10.0, precision());
1620+ }
1621+
1622+ dccl::uint64 uint_value = boost::numeric_cast<dccl::uint64>(dccl::round(wire_value, 0));
1623+
1624+ // "presence" value (0)
1625+ if(!FieldCodecBase::this_field()->is_required())
1626+ uint_value += 1;
1627+
1628+
1629+ Bitset encoded;
1630+ encoded.from(uint_value, size());
1631+ return encoded;
1632+ }
1633+
1634+ virtual WireType decode(Bitset* bits)
1635+ {
1636+ // The line below SHOULD BE:
1637+ // dccl::uint64 t = bits->to<dccl::uint64>();
1638+ // But GCC3.3 requires an explicit template modifier on the method.
1639+ // See, e.g., http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10959
1640+ dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
1641+
1642+ if(!FieldCodecBase::this_field()->is_required())
1643+ {
1644+ if(!uint_value) throw NullValueException();
1645+ --uint_value;
1646+ }
1647+
1648+ WireType wire_value = (WireType)uint_value;
1649+
1650+ if (precision() < 0) {
1651+ wire_value *= (WireType)std::pow(10.0, -precision());
1652+ } else if (precision() > 0) {
1653+ wire_value /= (WireType)std::pow(10.0, precision());
1654+ }
1655+
1656+ // round values again to properly handle cases where double precision
1657+ // leads to slightly off values (e.g. 2.099999999 instead of 2.1)
1658+ wire_value = dccl::round(wire_value + dccl::round((WireType)min(), precision()),
1659+ precision());
1660+
1661+ return wire_value;
1662+ }
1663+
1664+ unsigned size()
1665+ {
1666+ // if not required field, leave one value for unspecified (always encoded as 0)
1667+ const unsigned NULL_VALUE = FieldCodecBase::this_field()->is_required() ? 0 : 1;
1668+
1669+ return dccl::ceil_log2((max()-min())*std::pow(10.0, precision())+1 + NULL_VALUE);
1670+ }
1671+
1672+ };
1673+
1674+ /// \brief Provides a bool encoder. Uses 1 bit if field is `required`, 2 bits if `optional`
1675+ ///
1676+ /// [presence bit (0 bits if required, 1 bit if optional)][value (1 bit)]
1677+ class DefaultBoolCodec : public TypedFixedFieldCodec<bool>
1678+ {
1679+ private:
1680+ Bitset encode(const bool& wire_value);
1681+ Bitset encode();
1682+ bool decode(Bitset* bits);
1683+ unsigned size();
1684+ void validate();
1685+ };
1686+
1687+ /// \brief Provides an variable length ASCII string encoder. Can encode strings up to 255 bytes by using a length byte preceeding the string.
1688+ ///
1689+ /// [length of following string (1 byte)][string (0-255 bytes)]
1690+ class DefaultStringCodec : public TypedFieldCodec<std::string>
1691+ {
1692+ private:
1693+ Bitset encode();
1694+ Bitset encode(const std::string& wire_value);
1695+ std::string decode(Bitset* bits);
1696+ unsigned size();
1697+ unsigned size(const std::string& wire_value);
1698+ unsigned max_size();
1699+ unsigned min_size();
1700+ void validate();
1701+ private:
1702+ enum { MAX_STRING_LENGTH = 255 };
1703+
1704+ };
1705+
1706+
1707+ /// \brief Provides an fixed length byte string encoder.
1708+ class DefaultBytesCodec : public TypedFieldCodec<std::string>
1709+ {
1710+ private:
1711+ Bitset encode();
1712+ Bitset encode(const std::string& wire_value);
1713+ std::string decode(Bitset* bits);
1714+ unsigned size();
1715+ unsigned size(const std::string& wire_value);
1716+ unsigned max_size();
1717+ unsigned min_size();
1718+ void validate();
1719+ };
1720+
1721+ /// \brief Provides an enum encoder. This converts the enumeration to an integer (based on the enumeration <i>index</i> (<b>not</b> its <i>value</i>) and uses DefaultNumericFieldCodec to encode the integer.
1722+ class DefaultEnumCodec
1723+ : public DefaultNumericFieldCodec<int32, const google::protobuf::EnumValueDescriptor*>
1724+ {
1725+ public:
1726+ int32 pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value);
1727+ const google::protobuf::EnumValueDescriptor* post_decode(const int32& wire_value);
1728+
1729+ private:
1730+ void validate() { }
1731+
1732+ double max()
1733+ {
1734+ const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
1735+ return e->value_count()-1;
1736+ }
1737+ double min()
1738+ { return 0; }
1739+ };
1740+
1741+
1742+ /// \brief Encodes time of day (default: second precision, but can be set with (dccl.field).precision extension)
1743+ ///
1744+ /// \tparam TimeType A type representing time: See the various specializations of this class for allowed types.
1745+
1746+ typedef double time_wire_type;
1747+ template<typename TimeType, int conversion_factor>
1748+ class TimeCodecBase : public DefaultNumericFieldCodec<time_wire_type, TimeType>
1749+ {
1750+ public:
1751+ time_wire_type pre_encode(const TimeType& time_of_day) {
1752+ time_wire_type max_secs = max();
1753+ return std::fmod(time_of_day / static_cast<time_wire_type>(conversion_factor), max_secs);
1754+ }
1755+
1756+ TimeType post_decode(const time_wire_type& encoded_time) {
1757+
1758+ int64 max_secs = (int64)max();
1759+ timeval t;
1760+ gettimeofday(&t, 0);
1761+ int64 now = t.tv_sec;
1762+ int64 daystart = now - (now % max_secs);
1763+ int64 today_time = now - daystart;
1764+
1765+ // If time is more than 12 hours ahead of now, assume it's yesterday.
1766+ if ((encoded_time - today_time) > (max_secs/2)) {
1767+ daystart -= max_secs;
1768+ } else if ((today_time - encoded_time) > (max_secs/2)) {
1769+ daystart += max_secs;
1770+ }
1771+
1772+ return (TimeType)(conversion_factor * (daystart + encoded_time));
1773+ }
1774+
1775+ private:
1776+ void validate()
1777+ {
1778+ DefaultNumericFieldCodec<time_wire_type, TimeType>::validate_numeric_bounds();
1779+ }
1780+
1781+ double max() {
1782+ return FieldCodecBase::dccl_field_options().num_days() * SECONDS_IN_DAY;
1783+ }
1784+
1785+ double min() { return 0; }
1786+ double precision()
1787+ {
1788+ if(!FieldCodecBase::dccl_field_options().has_precision())
1789+ return 0; // default to second precision
1790+ else
1791+ {
1792+ return FieldCodecBase::dccl_field_options().precision() + (double)std::log10((double)conversion_factor);
1793+ }
1794+
1795+ }
1796+
1797+
1798+ private:
1799+ enum { SECONDS_IN_DAY = 86400 };
1800+ };
1801+
1802+ template<typename TimeType>
1803+ class TimeCodec : public TimeCodecBase<TimeType, 0>
1804+ { BOOST_STATIC_ASSERT(sizeof(TimeCodec) == 0); };
1805+
1806+ template<> class TimeCodec<uint64> : public TimeCodecBase<uint64, 1000000> { };
1807+ template<> class TimeCodec<int64> : public TimeCodecBase<int64, 1000000> { };
1808+ template<> class TimeCodec<double> : public TimeCodecBase<double, 1> { };
1809+
1810+
1811+ /// \brief Placeholder codec that takes no space on the wire (0 bits).
1812+ template<typename T>
1813+ class StaticCodec : public TypedFixedFieldCodec<T>
1814+ {
1815+ Bitset encode(const T&)
1816+ { return Bitset(size()); }
1817+
1818+ Bitset encode()
1819+ { return Bitset(size()); }
1820+
1821+ T decode(Bitset* bits)
1822+ {
1823+ return boost::lexical_cast<T>(
1824+ FieldCodecBase::dccl_field_options().static_value());
1825+ }
1826+
1827+ unsigned size()
1828+ { return 0; }
1829+
1830+ void validate()
1831+ {
1832+ FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_static_value(), "missing (dccl.field).static_value");
1833+
1834+ std::string t = FieldCodecBase::dccl_field_options().static_value();
1835+ try
1836+ {
1837+ boost::lexical_cast<T>(t);
1838+ }
1839+ catch(boost::bad_lexical_cast&)
1840+ {
1841+ FieldCodecBase::require(false, "invalid static_value for this type.");
1842+ }
1843+ }
1844+
1845+ };
1846+ }
1847 }
1848
1849
1850
1851=== renamed file 'src/field_codec_default_message.cpp' => 'src/codecs2/field_codec_default_message.cpp'
1852--- src/field_codec_default_message.cpp 2014-04-22 20:10:37 +0000
1853+++ src/codecs2/field_codec_default_message.cpp 2014-08-27 16:27:22 +0000
1854@@ -30,17 +30,17 @@
1855 // DefaultMessageCodec
1856 //
1857
1858-void dccl::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value)
1859+void dccl::v2::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value)
1860 {
1861- if(wire_value.empty())
1862- *bits = Bitset(min_size());
1863- else
1864- *bits = traverse_const_message<Encoder, Bitset>(wire_value);
1865+ if(wire_value.empty())
1866+ *bits = Bitset(min_size());
1867+ else
1868+ *bits = traverse_const_message<Encoder, Bitset>(wire_value);
1869 }
1870
1871
1872
1873-unsigned dccl::DefaultMessageCodec::any_size(const boost::any& wire_value)
1874+unsigned dccl::v2::DefaultMessageCodec::any_size(const boost::any& wire_value)
1875 {
1876 if(wire_value.empty())
1877 return min_size();
1878@@ -49,7 +49,7 @@
1879 }
1880
1881
1882-void dccl::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value)
1883+void dccl::v2::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value)
1884 {
1885 try
1886 {
1887@@ -67,8 +67,8 @@
1888 if(!check_field(field_desc))
1889 continue;
1890
1891- boost::shared_ptr<FieldCodecBase> codec =
1892- FieldCodecManager::find(field_desc);
1893+
1894+ boost::shared_ptr<FieldCodecBase> codec = find(field_desc);
1895 boost::shared_ptr<FromProtoCppTypeBase> helper =
1896 TypeHelper::find(field_desc);
1897
1898@@ -127,14 +127,14 @@
1899 }
1900
1901
1902-unsigned dccl::DefaultMessageCodec::max_size()
1903+unsigned dccl::v2::DefaultMessageCodec::max_size()
1904 {
1905 unsigned u = 0;
1906 traverse_descriptor<MaxSize>(&u);
1907 return u;
1908 }
1909
1910-unsigned dccl::DefaultMessageCodec::min_size()
1911+unsigned dccl::v2::DefaultMessageCodec::min_size()
1912 {
1913 unsigned u = 0;
1914 traverse_descriptor<MinSize>(&u);
1915@@ -142,20 +142,20 @@
1916 }
1917
1918
1919-void dccl::DefaultMessageCodec::validate()
1920+void dccl::v2::DefaultMessageCodec::validate()
1921 {
1922 bool b = false;
1923 traverse_descriptor<Validate>(&b);
1924 }
1925
1926-std::string dccl::DefaultMessageCodec::info()
1927+std::string dccl::v2::DefaultMessageCodec::info()
1928 {
1929 std::stringstream ss;
1930 traverse_descriptor<Info>(&ss);
1931 return ss.str();
1932 }
1933
1934-bool dccl::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field)
1935+bool dccl::v2::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field)
1936 {
1937 if(!field)
1938 {
1939@@ -171,7 +171,7 @@
1940 else if(MessageStack::current_part() == MessageStack::UNKNOWN) // part not yet explicitly specified
1941 {
1942 if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
1943- FieldCodecManager::find(field)->name() == Codec::default_codec_name()) // default message codec will expand
1944+ find(field)->name() == Codec::default_codec_name()) // default message codec will expand
1945 return true;
1946 else if((part() == MessageStack::HEAD && !dccl_field_options.in_head())
1947 || (part() == MessageStack::BODY && dccl_field_options.in_head()))
1948
1949=== renamed file 'src/field_codec_default_message.h' => 'src/codecs2/field_codec_default_message.h'
1950--- src/field_codec_default_message.h 2014-04-22 20:10:37 +0000
1951+++ src/codecs2/field_codec_default_message.h 2014-08-27 16:27:22 +0000
1952@@ -24,225 +24,183 @@
1953 #ifndef DCCLFIELDCODECDEFAULTMESSAGE20110510H
1954 #define DCCLFIELDCODECDEFAULTMESSAGE20110510H
1955
1956-#include "field_codec.h"
1957-#include "field_codec_manager.h"
1958+#include "dccl/field_codec.h"
1959+#include "dccl/field_codec_manager.h"
1960
1961 #include "dccl/protobuf/option_extensions.pb.h"
1962
1963 namespace dccl
1964 {
1965- /// \brief Provides the default codec for encoding a base Google Protobuf message or an embedded message by calling the appropriate field codecs for every field.
1966- class DefaultMessageCodec : public FieldCodecBase
1967+ namespace v2
1968 {
1969- private:
1970-
1971- void any_encode(Bitset* bits, const boost::any& wire_value);
1972- void any_decode(Bitset* bits, boost::any* wire_value);
1973- unsigned max_size();
1974- unsigned min_size();
1975- unsigned any_size(const boost::any& wire_value);
1976-
1977-
1978- void validate();
1979- std::string info();
1980- bool check_field(const google::protobuf::FieldDescriptor* field);
1981-
1982- struct Size
1983- {
1984- static void repeated(boost::shared_ptr<FieldCodecBase> codec,
1985- unsigned* return_value,
1986- const std::vector<boost::any>& field_values,
1987- const google::protobuf::FieldDescriptor* field_desc)
1988- {
1989- codec->field_size_repeated(return_value, field_values, field_desc);
1990- }
1991-
1992- static void single(boost::shared_ptr<FieldCodecBase> codec,
1993- unsigned* return_value,
1994- const boost::any& field_value,
1995- const google::protobuf::FieldDescriptor* field_desc)
1996- {
1997- codec->field_size(return_value, field_value, field_desc);
1998- }
1999-
2000- };
2001-
2002- struct Encoder
2003- {
2004- static void repeated(boost::shared_ptr<FieldCodecBase> codec,
2005- Bitset* return_value,
2006- const std::vector<boost::any>& field_values,
2007- const google::protobuf::FieldDescriptor* field_desc)
2008- {
2009- codec->field_encode_repeated(return_value, field_values, field_desc);
2010- }
2011-
2012- static void single(boost::shared_ptr<FieldCodecBase> codec,
2013- Bitset* return_value,
2014- const boost::any& field_value,
2015- const google::protobuf::FieldDescriptor* field_desc)
2016- {
2017- codec->field_encode(return_value, field_value, field_desc);
2018- }
2019- };
2020-
2021- struct MaxSize
2022- {
2023- static void field(boost::shared_ptr<FieldCodecBase> codec,
2024- unsigned* return_value,
2025- const google::protobuf::FieldDescriptor* field_desc)
2026- {
2027- codec->field_max_size(return_value, field_desc);
2028- }
2029- };
2030-
2031- struct MinSize
2032- {
2033- static void field(boost::shared_ptr<FieldCodecBase> codec,
2034- unsigned* return_value,
2035- const google::protobuf::FieldDescriptor* field_desc)
2036- {
2037- codec->field_min_size(return_value, field_desc);
2038- }
2039- };
2040-
2041-
2042- struct Validate
2043- {
2044- static void field(boost::shared_ptr<FieldCodecBase> codec,
2045- bool* return_value,
2046- const google::protobuf::FieldDescriptor* field_desc)
2047- {
2048- codec->field_validate(return_value, field_desc);
2049- }
2050- };
2051-
2052- struct Info
2053- {
2054- static void field(boost::shared_ptr<FieldCodecBase> codec,
2055- std::stringstream* return_value,
2056- const google::protobuf::FieldDescriptor* field_desc)
2057- {
2058- codec->field_info(return_value, field_desc);
2059- }
2060- };
2061-
2062-
2063- template<typename Action, typename ReturnType>
2064- void traverse_descriptor(ReturnType* return_value)
2065- {
2066- const google::protobuf::Descriptor* desc =
2067- FieldCodecBase::this_descriptor();
2068- for(int i = 0, n = desc->field_count(); i < n; ++i)
2069- {
2070- const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2071+ /// \brief Provides the default codec for encoding a base Google Protobuf message or an embedded message by calling the appropriate field codecs for every field.
2072+ class DefaultMessageCodec : public FieldCodecBase
2073+ {
2074+ private:
2075+
2076+ void any_encode(Bitset* bits, const boost::any& wire_value);
2077+ void any_decode(Bitset* bits, boost::any* wire_value);
2078+ unsigned max_size();
2079+ unsigned min_size();
2080+ unsigned any_size(const boost::any& wire_value);
2081+
2082+
2083+ boost::shared_ptr<FieldCodecBase> find(const google::protobuf::FieldDescriptor* field_desc)
2084+ {
2085+ return FieldCodecManager::find(field_desc, has_codec_group(), codec_group());
2086+ }
2087+
2088+
2089+ void validate();
2090+ std::string info();
2091+ bool check_field(const google::protobuf::FieldDescriptor* field);
2092+
2093+ struct Size
2094+ {
2095+ static void repeated(boost::shared_ptr<FieldCodecBase> codec,
2096+ unsigned* return_value,
2097+ const std::vector<boost::any>& field_values,
2098+ const google::protobuf::FieldDescriptor* field_desc)
2099+ {
2100+ codec->field_size_repeated(return_value, field_values, field_desc);
2101+ }
2102+
2103+ static void single(boost::shared_ptr<FieldCodecBase> codec,
2104+ unsigned* return_value,
2105+ const boost::any& field_value,
2106+ const google::protobuf::FieldDescriptor* field_desc)
2107+ {
2108+ codec->field_size(return_value, field_value, field_desc);
2109+ }
2110+
2111+ };
2112+
2113+ struct Encoder
2114+ {
2115+ static void repeated(boost::shared_ptr<FieldCodecBase> codec,
2116+ Bitset* return_value,
2117+ const std::vector<boost::any>& field_values,
2118+ const google::protobuf::FieldDescriptor* field_desc)
2119+ {
2120+ codec->field_encode_repeated(return_value, field_values, field_desc);
2121+ }
2122+
2123+ static void single(boost::shared_ptr<FieldCodecBase> codec,
2124+ Bitset* return_value,
2125+ const boost::any& field_value,
2126+ const google::protobuf::FieldDescriptor* field_desc)
2127+ {
2128+ codec->field_encode(return_value, field_value, field_desc);
2129+ }
2130+ };
2131+
2132+ struct MaxSize
2133+ {
2134+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2135+ unsigned* return_value,
2136+ const google::protobuf::FieldDescriptor* field_desc)
2137+ {
2138+ codec->field_max_size(return_value, field_desc);
2139+ }
2140+ };
2141+
2142+ struct MinSize
2143+ {
2144+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2145+ unsigned* return_value,
2146+ const google::protobuf::FieldDescriptor* field_desc)
2147+ {
2148+ codec->field_min_size(return_value, field_desc);
2149+ }
2150+ };
2151+
2152+
2153+ struct Validate
2154+ {
2155+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2156+ bool* return_value,
2157+ const google::protobuf::FieldDescriptor* field_desc)
2158+ {
2159+ codec->field_validate(return_value, field_desc);
2160+ }
2161+ };
2162+
2163+ struct Info
2164+ {
2165+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2166+ std::stringstream* return_value,
2167+ const google::protobuf::FieldDescriptor* field_desc)
2168+ {
2169+ codec->field_info(return_value, field_desc);
2170+ }
2171+ };
2172+
2173+
2174+ template<typename Action, typename ReturnType>
2175+ void traverse_descriptor(ReturnType* return_value)
2176+ {
2177+ const google::protobuf::Descriptor* desc =
2178+ FieldCodecBase::this_descriptor();
2179+ for(int i = 0, n = desc->field_count(); i < n; ++i)
2180+ {
2181+ const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2182
2183- if(!check_field(field_desc))
2184- continue;
2185+ if(!check_field(field_desc))
2186+ continue;
2187
2188- Action::field(FieldCodecManager::find(field_desc),
2189- return_value, field_desc);
2190+ Action::field(find(field_desc), return_value, field_desc);
2191+ }
2192 }
2193- }
2194
2195
2196- template<typename Action, typename ReturnType>
2197- ReturnType traverse_const_message(const boost::any& wire_value)
2198- {
2199- try
2200+ template<typename Action, typename ReturnType>
2201+ ReturnType traverse_const_message(const boost::any& wire_value)
2202 {
2203- ReturnType return_value = ReturnType();
2204+ try
2205+ {
2206+ ReturnType return_value = ReturnType();
2207
2208- const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value);
2209- const google::protobuf::Descriptor* desc = msg->GetDescriptor();
2210- const google::protobuf::Reflection* refl = msg->GetReflection();
2211- for(int i = 0, n = desc->field_count(); i < n; ++i)
2212- {
2213- const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2214+ const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value);
2215+ const google::protobuf::Descriptor* desc = msg->GetDescriptor();
2216+ const google::protobuf::Reflection* refl = msg->GetReflection();
2217+ for(int i = 0, n = desc->field_count(); i < n; ++i)
2218+ {
2219+ const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2220
2221- if(!check_field(field_desc))
2222- continue;
2223+ if(!check_field(field_desc))
2224+ continue;
2225
2226- boost::shared_ptr<FieldCodecBase> codec =
2227- FieldCodecManager::find(field_desc);
2228- boost::shared_ptr<FromProtoCppTypeBase> helper =
2229- TypeHelper::find(field_desc);
2230-
2231-
2232- if(field_desc->is_repeated())
2233- {
2234- std::vector<boost::any> field_values;
2235- for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j)
2236- field_values.push_back(helper->get_repeated_value(field_desc, *msg, j));
2237+ boost::shared_ptr<FieldCodecBase> codec = find(field_desc);
2238+ boost::shared_ptr<FromProtoCppTypeBase> helper =
2239+ TypeHelper::find(field_desc);
2240+
2241+
2242+ if(field_desc->is_repeated())
2243+ {
2244+ std::vector<boost::any> field_values;
2245+ for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j)
2246+ field_values.push_back(helper->get_repeated_value(field_desc, *msg, j));
2247
2248- Action::repeated(codec, &return_value, field_values, field_desc);
2249- }
2250- else
2251- {
2252- Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc);
2253- }
2254- }
2255- return return_value;
2256- }
2257- catch(boost::bad_any_cast& e)
2258- {
2259- throw(Exception("Bad type given to traverse const, expecting const google::protobuf::Message*, got " + std::string(wire_value.type().name())));
2260- }
2261-
2262- }
2263-
2264- template<typename Action, typename ReturnType>
2265- ReturnType traverse_mutable_message(const boost::any& wire_value)
2266- {
2267- try
2268- {
2269- ReturnType return_value = ReturnType();
2270-
2271- const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value);
2272- const google::protobuf::Descriptor* desc = msg->GetDescriptor();
2273- const google::protobuf::Reflection* refl = msg->GetReflection();
2274- for(int i = 0, n = desc->field_count(); i < n; ++i)
2275- {
2276- const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2277-
2278- if(!check_field(field_desc))
2279- continue;
2280-
2281- boost::shared_ptr<FieldCodecBase> codec =
2282- FieldCodecManager::find(field_desc);
2283- boost::shared_ptr<FromProtoCppTypeBase> helper =
2284- TypeHelper::find(field_desc);
2285-
2286-
2287- if(field_desc->is_repeated())
2288- {
2289- std::vector<boost::any> field_values;
2290- for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j)
2291- field_values.push_back(helper->get_repeated_value(field_desc, *msg, j));
2292-
2293- Action::repeated(codec, &return_value, field_values, field_desc);
2294- }
2295- else
2296- {
2297- Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc);
2298- }
2299- }
2300- return return_value;
2301- }
2302- catch(boost::bad_any_cast& e)
2303- {
2304- throw(Exception("Bad type given to traverse, expecting const google::protobuf::Message*"));
2305- }
2306-
2307- }
2308-
2309-
2310-
2311- };
2312-
2313+ Action::repeated(codec, &return_value, field_values, field_desc);
2314+ }
2315+ else
2316+ {
2317+ Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc);
2318+ }
2319+ }
2320+ return return_value;
2321+ }
2322+ catch(boost::bad_any_cast& e)
2323+ {
2324+ throw(Exception("Bad type given to traverse const, expecting const google::protobuf::Message*, got " + std::string(wire_value.type().name())));
2325+ }
2326+
2327+ }
2328+ };
2329+
2330+ }
2331 }
2332
2333-
2334 //encode, size, etc.
2335
2336
2337
2338=== added directory 'src/codecs3'
2339=== added file 'src/codecs3/field_codec_default.cpp'
2340--- src/codecs3/field_codec_default.cpp 1970-01-01 00:00:00 +0000
2341+++ src/codecs3/field_codec_default.cpp 2014-08-27 16:27:22 +0000
2342@@ -0,0 +1,122 @@
2343+// Copyright 2009-2014 Toby Schneider (https://launchpad.net/~tes)
2344+// GobySoft, LLC (2013-)
2345+// Massachusetts Institute of Technology (2007-2014)
2346+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
2347+//
2348+// This file is part of the Dynamic Compact Control Language Library
2349+// ("DCCL").
2350+//
2351+// DCCL is free software: you can redistribute them and/or modify
2352+// them under the terms of the GNU Lesser General Public License as published by
2353+// the Free Software Foundation, either version 2.1 of the License, or
2354+// (at your option) any later version.
2355+//
2356+// DCCL is distributed in the hope that they will be useful,
2357+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2358+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2359+// GNU Lesser General Public License for more details.
2360+//
2361+// You should have received a copy of the GNU Lesser General Public License
2362+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
2363+
2364+#include "dccl/codecs3/field_codec_default.h"
2365+
2366+using namespace dccl::logger;
2367+
2368+//
2369+// DefaultStringCodec
2370+//
2371+
2372+dccl::Bitset dccl::v3::DefaultStringCodec::encode()
2373+{
2374+ return Bitset(min_size());
2375+}
2376+
2377+dccl::Bitset dccl::v3::DefaultStringCodec::encode(const std::string& wire_value)
2378+{
2379+ std::string s = wire_value;
2380+ if(s.size() > dccl_field_options().max_length())
2381+ {
2382+ dccl::dlog.is(DEBUG2) && dccl::dlog << "String " << s << " exceeds `dccl.max_length`, truncating" << std::endl;
2383+ s.resize(dccl_field_options().max_length());
2384+ }
2385+
2386+
2387+ Bitset value_bits;
2388+ value_bits.from_byte_string(s);
2389+
2390+ Bitset length_bits(min_size(), s.length());
2391+
2392+ dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits << std::endl;
2393+
2394+
2395+ dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits << std::endl;
2396+
2397+ // adds to MSBs
2398+ for(int i = 0, n = value_bits.size(); i < n; ++i)
2399+ length_bits.push_back(value_bits[i]);
2400+
2401+ dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits << std::endl;
2402+
2403+
2404+ return length_bits;
2405+}
2406+
2407+std::string dccl::v3::DefaultStringCodec::decode(Bitset* bits)
2408+{
2409+ unsigned value_length = bits->to_ulong();
2410+
2411+ if(value_length)
2412+ {
2413+
2414+ unsigned header_length = min_size();
2415+
2416+ dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length << std::endl;
2417+
2418+ dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl;
2419+
2420+ // grabs more bits to add to the MSBs of `bits`
2421+ bits->get_more_bits(value_length*BITS_IN_BYTE);
2422+
2423+
2424+ dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl;
2425+ Bitset string_body_bits = *bits;
2426+ string_body_bits >>= header_length;
2427+ string_body_bits.resize(bits->size() - header_length);
2428+
2429+ return string_body_bits.to_byte_string();
2430+ }
2431+ else
2432+ {
2433+ throw NullValueException();
2434+ }
2435+
2436+}
2437+
2438+unsigned dccl::v3::DefaultStringCodec::size()
2439+{
2440+ return min_size();
2441+}
2442+
2443+unsigned dccl::v3::DefaultStringCodec::size(const std::string& wire_value)
2444+{
2445+ return std::min(min_size() + static_cast<unsigned>(wire_value.length()*BITS_IN_BYTE), max_size());
2446+}
2447+
2448+
2449+unsigned dccl::v3::DefaultStringCodec::max_size()
2450+{
2451+ // string length + actual string
2452+ return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
2453+}
2454+
2455+unsigned dccl::v3::DefaultStringCodec::min_size()
2456+{
2457+ return dccl::ceil_log2(dccl_field_options().max_length()+1);
2458+}
2459+
2460+
2461+void dccl::v3::DefaultStringCodec::validate()
2462+{
2463+ require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
2464+}
2465
2466=== added file 'src/codecs3/field_codec_default.h'
2467--- src/codecs3/field_codec_default.h 1970-01-01 00:00:00 +0000
2468+++ src/codecs3/field_codec_default.h 2014-08-27 16:27:22 +0000
2469@@ -0,0 +1,77 @@
2470+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
2471+// Massachusetts Institute of Technology (2007-)
2472+// Woods Hole Oceanographic Institution (2007-)
2473+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
2474+//
2475+//
2476+// This file is part of the Dynamic Compact Control Language Library
2477+// ("DCCL").
2478+//
2479+// DCCL is free software: you can redistribute them and/or modify
2480+// them under the terms of the GNU Lesser General Public License as published by
2481+// the Free Software Foundation, either version 3 of the License, or
2482+// (at your option) any later version.
2483+//
2484+// DCCL is distributed in the hope that they will be useful,
2485+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2486+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2487+// GNU Lesser General Public License for more details.
2488+//
2489+// You should have received a copy of the GNU Lesser General Public License
2490+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
2491+
2492+
2493+
2494+// implements FieldCodecBase for all the basic DCCL types for version 3
2495+
2496+#ifndef DCCLV3FIELDCODECDEFAULT20140403H
2497+#define DCCLV3FIELDCODECDEFAULT20140403H
2498+
2499+#include "dccl/codecs2/field_codec_default.h"
2500+
2501+namespace dccl
2502+{
2503+ namespace v3
2504+ {
2505+ // all these are the same as version 2
2506+ template<typename WireType, typename FieldType = WireType>
2507+ class DefaultNumericFieldCodec : public v2::DefaultNumericFieldCodec<WireType, FieldType> { };
2508+
2509+ typedef v2::DefaultBoolCodec DefaultBoolCodec;
2510+ typedef v2::DefaultBytesCodec DefaultBytesCodec;
2511+ typedef v2::DefaultEnumCodec DefaultEnumCodec;
2512+
2513+
2514+ template<typename TimeType>
2515+ class TimeCodec : public v2::TimeCodecBase<TimeType, 0>
2516+ { BOOST_STATIC_ASSERT(sizeof(TimeCodec) == 0); };
2517+
2518+ template<> class TimeCodec<uint64> : public v2::TimeCodecBase<uint64, 1000000> { };
2519+ template<> class TimeCodec<int64> : public v2::TimeCodecBase<int64, 1000000> { };
2520+ template<> class TimeCodec<double> : public v2::TimeCodecBase<double, 1> { };
2521+
2522+ template<typename T>
2523+ class StaticCodec : public v2::StaticCodec<T>
2524+ { };
2525+
2526+
2527+ /// \brief Provides an variable length ASCII string encoder.
2528+ ///
2529+ /// [length of following string size: ceil(log2(max_length))][string]
2530+ class DefaultStringCodec : public TypedFieldCodec<std::string>
2531+ {
2532+ private:
2533+ Bitset encode();
2534+ Bitset encode(const std::string& wire_value);
2535+ std::string decode(Bitset* bits);
2536+ unsigned size();
2537+ unsigned size(const std::string& wire_value);
2538+ unsigned max_size();
2539+ unsigned min_size();
2540+ void validate();
2541+ };
2542+
2543+ }
2544+}
2545+
2546+#endif
2547
2548=== added file 'src/codecs3/field_codec_default_message.cpp'
2549--- src/codecs3/field_codec_default_message.cpp 1970-01-01 00:00:00 +0000
2550+++ src/codecs3/field_codec_default_message.cpp 2014-08-27 16:27:22 +0000
2551@@ -0,0 +1,236 @@
2552+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
2553+// Massachusetts Institute of Technology (2007-)
2554+// Woods Hole Oceanographic Institution (2007-)
2555+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
2556+//
2557+//
2558+// This file is part of the Dynamic Compact Control Language Library
2559+// ("DCCL").
2560+//
2561+// DCCL is free software: you can redistribute them and/or modify
2562+// them under the terms of the GNU Lesser General Public License as published by
2563+// the Free Software Foundation, either version 3 of the License, or
2564+// (at your option) any later version.
2565+//
2566+// DCCL is distributed in the hope that they will be useful,
2567+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2568+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2569+// GNU Lesser General Public License for more details.
2570+//
2571+// You should have received a copy of the GNU Lesser General Public License
2572+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
2573+
2574+
2575+
2576+#include "dccl/codec.h"
2577+#include "dccl/codecs3/field_codec_default_message.h"
2578+
2579+using dccl::dlog;
2580+
2581+//
2582+// DefaultMessageCodec
2583+//
2584+
2585+void dccl::v3::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value)
2586+{
2587+ if(wire_value.empty())
2588+ {
2589+ *bits = Bitset(min_size());
2590+ }
2591+ else
2592+ {
2593+ *bits = traverse_const_message<Encoder, Bitset>(wire_value);
2594+
2595+ if(is_optional())
2596+ bits->push_front(true); // presence bit
2597+
2598+ }
2599+}
2600+
2601+
2602+
2603+unsigned dccl::v3::DefaultMessageCodec::any_size(const boost::any& wire_value)
2604+{
2605+ if(wire_value.empty())
2606+ {
2607+ return min_size();
2608+ }
2609+ else
2610+ {
2611+ unsigned size = traverse_const_message<Size, unsigned>(wire_value);
2612+ if(is_optional())
2613+ {
2614+ const unsigned presence_bit = 1;
2615+ size += presence_bit;
2616+ }
2617+
2618+ return size;
2619+ }
2620+}
2621+
2622+
2623+void dccl::v3::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value)
2624+{
2625+ try
2626+ {
2627+
2628+ google::protobuf::Message* msg = boost::any_cast<google::protobuf::Message* >(*wire_value);
2629+
2630+ if(is_optional())
2631+ {
2632+ if(!bits->to_ulong())
2633+ {
2634+ *wire_value = boost::any();
2635+ return;
2636+ }
2637+ else
2638+ {
2639+ bits->pop_front(); // presence bit
2640+ }
2641+ }
2642+
2643+ const google::protobuf::Descriptor* desc = msg->GetDescriptor();
2644+ const google::protobuf::Reflection* refl = msg->GetReflection();
2645+
2646+ for(int i = 0, n = desc->field_count(); i < n; ++i)
2647+ {
2648+
2649+ const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2650+
2651+ if(!check_field(field_desc))
2652+ continue;
2653+
2654+
2655+ boost::shared_ptr<FieldCodecBase> codec = find(field_desc);
2656+ boost::shared_ptr<FromProtoCppTypeBase> helper =
2657+ TypeHelper::find(field_desc);
2658+
2659+ if(field_desc->is_repeated())
2660+ {
2661+ std::vector<boost::any> field_values;
2662+ if(field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
2663+ {
2664+ unsigned max_repeat = field_desc->options().GetExtension(dccl::field).max_repeat();
2665+ for(unsigned j = 0, m = max_repeat; j < m; ++j)
2666+ field_values.push_back(refl->AddMessage(msg, field_desc));
2667+
2668+ codec->field_decode_repeated(bits, &field_values, field_desc);
2669+
2670+ // remove the unused messages
2671+ for(int j = field_values.size(), m = max_repeat; j < m; ++j)
2672+ {
2673+ refl->RemoveLast(msg, field_desc);
2674+ }
2675+ }
2676+ else
2677+ {
2678+ // for primitive types
2679+ codec->field_decode_repeated(bits, &field_values, field_desc);
2680+ for(int j = 0, m = field_values.size(); j < m; ++j)
2681+ helper->add_value(field_desc, msg, field_values[j]);
2682+ }
2683+ }
2684+ else
2685+ {
2686+ boost::any field_value;
2687+ if(field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
2688+ {
2689+ // allows us to propagate pointers instead of making many copies of entire messages
2690+ field_value = refl->MutableMessage(msg, field_desc);
2691+ codec->field_decode(bits, &field_value, field_desc);
2692+ if(field_value.empty()) refl->ClearField(msg, field_desc);
2693+ }
2694+ else
2695+ {
2696+ // for primitive types
2697+ codec->field_decode(bits, &field_value, field_desc);
2698+ helper->set_value(field_desc, msg, field_value);
2699+ }
2700+ }
2701+ }
2702+
2703+ std::vector< const google::protobuf::FieldDescriptor* > set_fields;
2704+ refl->ListFields(*msg, &set_fields);
2705+ if(set_fields.empty() && this_field()) *wire_value = boost::any();
2706+ else *wire_value = msg;
2707+ }
2708+ catch(boost::bad_any_cast& e)
2709+ {
2710+ throw(Exception("Bad type given to traverse mutable, expecting google::protobuf::Message*, got " + std::string(wire_value->type().name())));
2711+ }
2712+
2713+}
2714+
2715+
2716+unsigned dccl::v3::DefaultMessageCodec::max_size()
2717+{
2718+ unsigned u = 0;
2719+ traverse_descriptor<MaxSize>(&u);
2720+
2721+ if(is_optional())
2722+ {
2723+ const unsigned presence_bit = 1;
2724+ u += presence_bit;
2725+ }
2726+
2727+ return u;
2728+}
2729+
2730+unsigned dccl::v3::DefaultMessageCodec::min_size()
2731+{
2732+ if(is_optional())
2733+ {
2734+ const unsigned presence_bit = 1;
2735+ return presence_bit;
2736+ }
2737+ else
2738+ {
2739+ unsigned u = 0;
2740+ traverse_descriptor<MinSize>(&u);
2741+ return u;
2742+ }
2743+}
2744+
2745+
2746+void dccl::v3::DefaultMessageCodec::validate()
2747+{
2748+ bool b = false;
2749+ traverse_descriptor<Validate>(&b);
2750+}
2751+
2752+std::string dccl::v3::DefaultMessageCodec::info()
2753+{
2754+ std::stringstream ss;
2755+ traverse_descriptor<Info>(&ss);
2756+ return ss.str();
2757+}
2758+
2759+bool dccl::v3::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field)
2760+{
2761+ if(!field)
2762+ {
2763+ return true;
2764+ }
2765+ else
2766+ {
2767+ dccl::DCCLFieldOptions dccl_field_options = field->options().GetExtension(dccl::field);
2768+ if(dccl_field_options.omit()) // omit
2769+ {
2770+ return false;
2771+ }
2772+ else if(MessageStack::current_part() == MessageStack::UNKNOWN) // part not yet explicitly specified
2773+ {
2774+ if((part() == MessageStack::HEAD && !dccl_field_options.in_head())
2775+ || (part() == MessageStack::BODY && dccl_field_options.in_head()))
2776+ return false;
2777+ else
2778+ return true;
2779+ }
2780+ else if(MessageStack::current_part() != part()) // part specified and doesn't match
2781+ return false;
2782+ else
2783+ return true;
2784+ }
2785+}
2786+
2787+
2788
2789=== added file 'src/codecs3/field_codec_default_message.h'
2790--- src/codecs3/field_codec_default_message.h 1970-01-01 00:00:00 +0000
2791+++ src/codecs3/field_codec_default_message.h 2014-08-27 16:27:22 +0000
2792@@ -0,0 +1,213 @@
2793+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
2794+// Massachusetts Institute of Technology (2007-)
2795+// Woods Hole Oceanographic Institution (2007-)
2796+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
2797+//
2798+//
2799+// This file is part of the Dynamic Compact Control Language Library
2800+// ("DCCL").
2801+//
2802+// DCCL is free software: you can redistribute them and/or modify
2803+// them under the terms of the GNU Lesser General Public License as published by
2804+// the Free Software Foundation, either version 3 of the License, or
2805+// (at your option) any later version.
2806+//
2807+// DCCL is distributed in the hope that they will be useful,
2808+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2809+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2810+// GNU Lesser General Public License for more details.
2811+//
2812+// You should have received a copy of the GNU Lesser General Public License
2813+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
2814+
2815+
2816+
2817+#ifndef DCCLFIELDCODECDEFAULTMESSAGEV320140421H
2818+#define DCCLFIELDCODECDEFAULTMESSAGEV320140421H
2819+
2820+#include "dccl/field_codec.h"
2821+#include "dccl/field_codec_manager.h"
2822+
2823+#include "dccl/protobuf/option_extensions.pb.h"
2824+
2825+namespace dccl
2826+{
2827+ namespace v3
2828+ {
2829+ /// \brief Provides the default codec for encoding a base Google Protobuf message or an embedded message by calling the appropriate field codecs for every field.
2830+ class DefaultMessageCodec : public FieldCodecBase
2831+ {
2832+ private:
2833+
2834+ void any_encode(Bitset* bits, const boost::any& wire_value);
2835+ void any_decode(Bitset* bits, boost::any* wire_value);
2836+ unsigned max_size();
2837+ unsigned min_size();
2838+ unsigned any_size(const boost::any& wire_value);
2839+
2840+
2841+ boost::shared_ptr<FieldCodecBase> find(const google::protobuf::FieldDescriptor* field_desc)
2842+ {
2843+ return FieldCodecManager::find(field_desc, has_codec_group(), codec_group());
2844+ }
2845+
2846+ bool is_optional()
2847+ { return this_field() && this_field()->is_optional(); }
2848+
2849+
2850+ void validate();
2851+ std::string info();
2852+ bool check_field(const google::protobuf::FieldDescriptor* field);
2853+
2854+ struct Size
2855+ {
2856+ static void repeated(boost::shared_ptr<FieldCodecBase> codec,
2857+ unsigned* return_value,
2858+ const std::vector<boost::any>& field_values,
2859+ const google::protobuf::FieldDescriptor* field_desc)
2860+ {
2861+ codec->field_size_repeated(return_value, field_values, field_desc);
2862+ }
2863+
2864+ static void single(boost::shared_ptr<FieldCodecBase> codec,
2865+ unsigned* return_value,
2866+ const boost::any& field_value,
2867+ const google::protobuf::FieldDescriptor* field_desc)
2868+ {
2869+ codec->field_size(return_value, field_value, field_desc);
2870+ }
2871+
2872+ };
2873+
2874+ struct Encoder
2875+ {
2876+ static void repeated(boost::shared_ptr<FieldCodecBase> codec,
2877+ Bitset* return_value,
2878+ const std::vector<boost::any>& field_values,
2879+ const google::protobuf::FieldDescriptor* field_desc)
2880+ {
2881+ codec->field_encode_repeated(return_value, field_values, field_desc);
2882+ }
2883+
2884+ static void single(boost::shared_ptr<FieldCodecBase> codec,
2885+ Bitset* return_value,
2886+ const boost::any& field_value,
2887+ const google::protobuf::FieldDescriptor* field_desc)
2888+ {
2889+ codec->field_encode(return_value, field_value, field_desc);
2890+ }
2891+ };
2892+
2893+ struct MaxSize
2894+ {
2895+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2896+ unsigned* return_value,
2897+ const google::protobuf::FieldDescriptor* field_desc)
2898+ {
2899+ codec->field_max_size(return_value, field_desc);
2900+ }
2901+ };
2902+
2903+ struct MinSize
2904+ {
2905+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2906+ unsigned* return_value,
2907+ const google::protobuf::FieldDescriptor* field_desc)
2908+ {
2909+ codec->field_min_size(return_value, field_desc);
2910+ }
2911+ };
2912+
2913+
2914+ struct Validate
2915+ {
2916+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2917+ bool* return_value,
2918+ const google::protobuf::FieldDescriptor* field_desc)
2919+ {
2920+ codec->field_validate(return_value, field_desc);
2921+ }
2922+ };
2923+
2924+ struct Info
2925+ {
2926+ static void field(boost::shared_ptr<FieldCodecBase> codec,
2927+ std::stringstream* return_value,
2928+ const google::protobuf::FieldDescriptor* field_desc)
2929+ {
2930+ codec->field_info(return_value, field_desc);
2931+ }
2932+ };
2933+
2934+
2935+ template<typename Action, typename ReturnType>
2936+ void traverse_descriptor(ReturnType* return_value)
2937+ {
2938+ const google::protobuf::Descriptor* desc =
2939+ FieldCodecBase::this_descriptor();
2940+ for(int i = 0, n = desc->field_count(); i < n; ++i)
2941+ {
2942+ const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2943+
2944+ if(!check_field(field_desc))
2945+ continue;
2946+
2947+ Action::field(find(field_desc), return_value, field_desc);
2948+ }
2949+ }
2950+
2951+
2952+ template<typename Action, typename ReturnType>
2953+ ReturnType traverse_const_message(const boost::any& wire_value)
2954+ {
2955+ try
2956+ {
2957+ ReturnType return_value = ReturnType();
2958+
2959+ const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value);
2960+ const google::protobuf::Descriptor* desc = msg->GetDescriptor();
2961+ const google::protobuf::Reflection* refl = msg->GetReflection();
2962+ for(int i = 0, n = desc->field_count(); i < n; ++i)
2963+ {
2964+ const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
2965+
2966+ if(!check_field(field_desc))
2967+ continue;
2968+
2969+ boost::shared_ptr<FieldCodecBase> codec = find(field_desc);
2970+ boost::shared_ptr<FromProtoCppTypeBase> helper =
2971+ TypeHelper::find(field_desc);
2972+
2973+
2974+ if(field_desc->is_repeated())
2975+ {
2976+ std::vector<boost::any> field_values;
2977+ for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j)
2978+ field_values.push_back(helper->get_repeated_value(field_desc, *msg, j));
2979+
2980+ Action::repeated(codec, &return_value, field_values, field_desc);
2981+ }
2982+ else
2983+ {
2984+ Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc);
2985+ }
2986+ }
2987+ return return_value;
2988+ }
2989+ catch(boost::bad_any_cast& e)
2990+ {
2991+ throw(Exception("Bad type given to traverse const, expecting const google::protobuf::Message*, got " + std::string(wire_value.type().name())));
2992+ }
2993+
2994+ }
2995+ };
2996+
2997+ }
2998+}
2999+
3000+//encode, size, etc.
3001+
3002+
3003+
3004+
3005+#endif
3006
3007=== modified file 'src/field_codec.cpp'
3008--- src/field_codec.cpp 2014-04-22 20:10:37 +0000
3009+++ src/field_codec.cpp 2014-08-27 16:27:22 +0000
3010@@ -29,6 +29,7 @@
3011 dccl::MessageStack::UNKNOWN;
3012
3013 const google::protobuf::Message* dccl::FieldCodecBase::root_message_ = 0;
3014+const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor_ = 0;
3015
3016 using dccl::dlog;
3017 using namespace dccl::logger;
3018@@ -66,6 +67,7 @@
3019
3020 Bitset new_bits;
3021 any_encode(&new_bits, wire_value);
3022+ disp_size(field, new_bits, msg_handler.field_.size());
3023 bits->append(new_bits);
3024 }
3025
3026@@ -80,6 +82,7 @@
3027
3028 Bitset new_bits;
3029 any_encode_repeated(&new_bits, wire_values);
3030+ disp_size(field, new_bits, msg_handler.field_.size(), wire_values.size());
3031 bits->append(new_bits);
3032 }
3033
3034@@ -190,7 +193,8 @@
3035
3036 std::vector<boost::any> wire_values = *field_values;
3037 any_decode_repeated(&these_bits, &wire_values);
3038-
3039+
3040+ field_values->clear();
3041 field_post_decode_repeated(wire_values, field_values);
3042 }
3043
3044@@ -199,7 +203,7 @@
3045 const google::protobuf::Descriptor* desc,
3046 MessageStack::MessagePart part)
3047 {
3048- BaseRAII scoped_globals(part);
3049+ BaseRAII scoped_globals(part, desc);
3050 *bit_size = 0;
3051
3052 MessageStack msg_handler;
3053@@ -228,7 +232,7 @@
3054 const google::protobuf::Descriptor* desc,
3055 MessageStack::MessagePart part)
3056 {
3057- BaseRAII scoped_globals(part);
3058+ BaseRAII scoped_globals(part, desc);
3059
3060 *bit_size = 0;
3061
3062@@ -257,7 +261,7 @@
3063 void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc,
3064 MessageStack::MessagePart part)
3065 {
3066- BaseRAII scoped_globals(part);
3067+ BaseRAII scoped_globals(part, desc);
3068
3069 MessageStack msg_handler;
3070 if(desc)
3071@@ -283,7 +287,7 @@
3072
3073 void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessageStack::MessagePart part)
3074 {
3075- BaseRAII scoped_globals(part);
3076+ BaseRAII scoped_globals(part, desc);
3077
3078 MessageStack msg_handler;
3079 if(desc)
3080@@ -337,7 +341,11 @@
3081 }
3082
3083 int width = this_field() ? full_width-name.size() : full_width-name.size()+spaces;
3084- ss << indent << name << std::setfill('.') << std::setw(std::max(1, width)) << range.str();
3085+ ss << indent << name <<
3086+ std::setfill('.') << std::setw(std::max(1, width)) << range.str()
3087+ << " {" << (this_field() ? FieldCodecManager::find(this_field(), has_codec_group(), codec_group())->name() : FieldCodecManager::find(root_descriptor_)->name()) << "}";
3088+
3089+
3090
3091 // std::string s = ss.str();
3092 // boost::replace_all(s, "\n", "\n" + indent);
3093@@ -353,6 +361,14 @@
3094
3095 }
3096
3097+std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc)
3098+{
3099+ if(desc->options().GetExtension(dccl::msg).has_codec_group())
3100+ return desc->options().GetExtension(dccl::msg).codec_group();
3101+ else
3102+ return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
3103+}
3104+
3105
3106 //
3107 // FieldCodecBase protected
3108@@ -366,7 +382,18 @@
3109 void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits, const std::vector<boost::any>& wire_values)
3110 {
3111 // out_bits = [field_values[2]][field_values[1]][field_values[0]]
3112- for(unsigned i = 0, n = dccl_field_options().max_repeat(); i < n; ++i)
3113+
3114+ unsigned wire_vector_size = dccl_field_options().max_repeat();
3115+
3116+ // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat
3117+ if(codec_version() > 2)
3118+ {
3119+ wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size());
3120+ Bitset size_bits(repeated_vector_field_size(dccl_field_options().max_repeat()), wire_values.size());
3121+ bits->append(size_bits);
3122+ }
3123+
3124+ for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
3125 {
3126 Bitset new_bits;
3127 if(i < wire_values.size())
3128@@ -379,27 +406,41 @@
3129 }
3130
3131
3132+
3133 void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* wire_values)
3134 {
3135- for(unsigned i = 0, n = dccl_field_options().max_repeat(); i < n; ++i)
3136+
3137+ unsigned wire_vector_size = dccl_field_options().max_repeat();
3138+ if(codec_version() > 2)
3139+ {
3140+ Bitset size_bits(repeated_bits);
3141+ size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().max_repeat()));
3142+
3143+ wire_vector_size = size_bits.to_ulong();
3144+ }
3145+
3146+ wire_values->resize(wire_vector_size);
3147+
3148+ for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
3149 {
3150 Bitset these_bits(repeated_bits);
3151- these_bits.get_more_bits(min_size());
3152-
3153- boost::any value;
3154-
3155- if(wire_values->size() > i)
3156- value = (*wire_values)[i];
3157-
3158- any_decode(&these_bits, &value);
3159- wire_values->push_back(value);
3160+ these_bits.get_more_bits(min_size());
3161+ any_decode(&these_bits, &(*wire_values)[i]);
3162 }
3163 }
3164
3165 unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<boost::any>& wire_values)
3166 {
3167 unsigned out = 0;
3168- for(unsigned i = 0, n = dccl_field_options().max_repeat(); i < n; ++i)
3169+ unsigned wire_vector_size = dccl_field_options().max_repeat();
3170+
3171+ if(codec_version() > 2)
3172+ {
3173+ wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size());
3174+ out += repeated_vector_field_size(dccl_field_options().max_repeat());
3175+ }
3176+
3177+ for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
3178 {
3179 if(i < wire_values.size())
3180 out += any_size(wire_values[i]);
3181@@ -413,6 +454,8 @@
3182 {
3183 if(!dccl_field_options().has_max_repeat())
3184 throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " + this_field()->DebugString()));
3185+ else if(codec_version() > 2)
3186+ return repeated_vector_field_size(dccl_field_options().max_repeat()) + max_size() * dccl_field_options().max_repeat();
3187 else
3188 return max_size() * dccl_field_options().max_repeat();
3189 }
3190@@ -421,6 +464,8 @@
3191 {
3192 if(!dccl_field_options().has_max_repeat())
3193 throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field " + this_field()->DebugString()));
3194+ else if(codec_version() > 2)
3195+ return repeated_vector_field_size(dccl_field_options().max_repeat());
3196 else
3197 return min_size() * dccl_field_options().max_repeat();
3198 }
3199@@ -453,3 +498,22 @@
3200 // FieldCodecBase private
3201 //
3202
3203+void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size /* = -1 */)
3204+{
3205+ if(!root_descriptor_)
3206+ return;
3207+
3208+ if(dlog.is(INFO, SIZE))
3209+ {
3210+ std::string name = ((field) ? field->name() : root_descriptor_->full_name());
3211+ if(vector_size >= 0)
3212+ name += "[" + boost::lexical_cast<std::string>(vector_size) + "]";
3213+
3214+
3215+ dlog << std::string(depth, '|') << name << std::setfill('.') << std::setw(40-name.size()-depth) << new_bits.size() << std::endl;
3216+
3217+ if(!field)
3218+ dlog << std::endl;
3219+
3220+ }
3221+}
3222
3223=== modified file 'src/field_codec.h'
3224--- src/field_codec.h 2014-04-22 20:10:37 +0000
3225+++ src/field_codec.h 2014-08-27 16:27:22 +0000
3226@@ -28,6 +28,7 @@
3227 #include <string>
3228
3229 #include <boost/any.hpp>
3230+#include <boost/lexical_cast.hpp>
3231
3232 #include <google/protobuf/message.h>
3233 #include <google/protobuf/descriptor.pb.h>
3234@@ -38,6 +39,7 @@
3235 #include "dccl/protobuf/option_extensions.pb.h"
3236 #include "type_helper.h"
3237 #include "field_codec_message_stack.h"
3238+#include "dccl/binary.h"
3239
3240 namespace dccl
3241 {
3242@@ -94,7 +96,25 @@
3243 // currently encoded or (partially) decoded root message
3244 static const google::protobuf::Message* root_message()
3245 { return root_message_; }
3246-
3247+
3248+ static bool has_codec_group()
3249+ {
3250+ if(root_descriptor_)
3251+ {
3252+ return root_descriptor_->options().GetExtension(dccl::msg).has_codec_group() ||
3253+ root_descriptor_->options().GetExtension(dccl::msg).has_codec_version();
3254+ }
3255+ else
3256+ return false;
3257+ }
3258+
3259+ static std::string codec_group(const google::protobuf::Descriptor* desc);
3260+
3261+ static std::string codec_group()
3262+ { return codec_group(root_descriptor_); }
3263+
3264+ static int codec_version()
3265+ { return root_descriptor_->options().GetExtension(dccl::msg).codec_version(); }
3266
3267 /// \brief the part of the message currently being encoded (head or body).
3268 static MessageStack::MessagePart part() { return part_; }
3269@@ -379,7 +399,6 @@
3270 ///
3271 /// \return Minimum size of this field (in bits).
3272 virtual unsigned min_size() = 0;
3273-
3274
3275 virtual void any_encode_repeated(Bitset* bits, const std::vector<boost::any>& wire_values);
3276 virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* field_values);
3277@@ -404,29 +423,52 @@
3278 void set_wire_type(google::protobuf::FieldDescriptor::CppType type)
3279 { wire_type_ = type; }
3280
3281- bool variable_size() { return max_size() != min_size(); }
3282-
3283+ bool variable_size()
3284+ {
3285+ if(this_field() && this_field()->is_repeated())
3286+ return max_size_repeated() != min_size_repeated();
3287+ else
3288+ return max_size() != min_size();
3289+ }
3290+
3291+ int repeated_vector_field_size(int max_repeat)
3292+ { return dccl::ceil_log2(max_repeat+1); }
3293+
3294+ void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size = -1);
3295+
3296+
3297 private:
3298 // sets global statics relating the current message begin processed
3299 // and unsets them on destruction
3300 struct BaseRAII
3301 {
3302 BaseRAII(MessageStack::MessagePart part,
3303- const google::protobuf::Message* root_message = 0)
3304+ const google::protobuf::Descriptor* root_descriptor)
3305+ {
3306+ FieldCodecBase::part_ = part;
3307+ FieldCodecBase::root_message_ = 0;
3308+ FieldCodecBase::root_descriptor_ = root_descriptor;
3309+ }
3310+
3311+ BaseRAII(MessageStack::MessagePart part,
3312+ const google::protobuf::Message* root_message)
3313 {
3314 FieldCodecBase::part_ = part;
3315 FieldCodecBase::root_message_ = root_message;
3316+ FieldCodecBase::root_descriptor_ = root_message->GetDescriptor();
3317 }
3318 ~BaseRAII()
3319 {
3320 FieldCodecBase::part_ = dccl::MessageStack::UNKNOWN;
3321 FieldCodecBase::root_message_ = 0;
3322+ FieldCodecBase::root_descriptor_ = 0;
3323 }
3324 };
3325
3326
3327 static MessageStack::MessagePart part_;
3328 static const google::protobuf::Message* root_message_;
3329+ static const google::protobuf::Descriptor* root_descriptor_;
3330
3331 std::string name_;
3332 google::protobuf::FieldDescriptor::Type field_type_;
3333
3334=== added file 'src/field_codec_id.cpp'
3335--- src/field_codec_id.cpp 1970-01-01 00:00:00 +0000
3336+++ src/field_codec_id.cpp 2014-08-27 16:27:22 +0000
3337@@ -0,0 +1,100 @@
3338+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
3339+// Massachusetts Institute of Technology (2007-)
3340+// Woods Hole Oceanographic Institution (2007-)
3341+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
3342+//
3343+//
3344+// This file is part of the Dynamic Compact Control Language Library
3345+// ("DCCL").
3346+//
3347+// DCCL is free software: you can redistribute them and/or modify
3348+// them under the terms of the GNU Lesser General Public License as published by
3349+// the Free Software Foundation, either version 3 of the License, or
3350+// (at your option) any later version.
3351+//
3352+// DCCL is distributed in the hope that they will be useful,
3353+// but WITHOUT ANY WARRANTY; without even the implied warranty of
3354+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3355+// GNU Lesser General Public License for more details.
3356+//
3357+// You should have received a copy of the GNU Lesser General Public License
3358+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
3359+
3360+#include "field_codec_id.h"
3361+
3362+//
3363+// DefaultIdentifierCodec
3364+//
3365+
3366+dccl::Bitset dccl::DefaultIdentifierCodec::encode()
3367+{
3368+ return encode(0);
3369+}
3370+
3371+dccl::Bitset dccl::DefaultIdentifierCodec::encode(const uint32& id)
3372+{
3373+ if(id <= ONE_BYTE_MAX_ID)
3374+ {
3375+ return(dccl::Bitset(this_size(id), id) << 1);
3376+ }
3377+ else
3378+ {
3379+ dccl::Bitset return_bits(this_size(id), id);
3380+ return_bits <<= 1;
3381+ // set LSB to indicate long header form
3382+ return_bits.set(0, true);
3383+
3384+
3385+ return return_bits;
3386+ }
3387+}
3388+
3389+dccl::uint32 dccl::DefaultIdentifierCodec::decode(Bitset* bits)
3390+{
3391+ if(bits->test(0))
3392+ {
3393+ // long header
3394+ // grabs more bits to add to the MSB of `bits`
3395+ bits->get_more_bits((LONG_FORM_ID_BYTES - SHORT_FORM_ID_BYTES)*BITS_IN_BYTE);
3396+ // discard identifier
3397+ *(bits) >>= 1;
3398+ return bits->to_ulong();
3399+ }
3400+ else
3401+ {
3402+ // short header
3403+ *(bits) >>= 1;
3404+ return bits->to_ulong();
3405+ }
3406+}
3407+
3408+unsigned dccl::DefaultIdentifierCodec::size()
3409+{
3410+ return this_size(0);
3411+}
3412+
3413+unsigned dccl::DefaultIdentifierCodec::size(const uint32& id)
3414+{
3415+ return this_size(id);
3416+}
3417+
3418+unsigned dccl::DefaultIdentifierCodec::this_size(const uint32& id)
3419+{
3420+ if(id > TWO_BYTE_MAX_ID)
3421+ throw(Exception("dccl.id provided (" + boost::lexical_cast<std::string>(id) + ") exceeds maximum: " + boost::lexical_cast<std::string>(int(TWO_BYTE_MAX_ID))));
3422+
3423+ return (id <= ONE_BYTE_MAX_ID) ?
3424+ SHORT_FORM_ID_BYTES*BITS_IN_BYTE :
3425+ LONG_FORM_ID_BYTES*BITS_IN_BYTE;
3426+}
3427+
3428+
3429+unsigned dccl::DefaultIdentifierCodec::max_size()
3430+{
3431+ return LONG_FORM_ID_BYTES * BITS_IN_BYTE;
3432+}
3433+
3434+unsigned dccl::DefaultIdentifierCodec::min_size()
3435+{
3436+ return SHORT_FORM_ID_BYTES * BITS_IN_BYTE;
3437+}
3438
3439=== added file 'src/field_codec_id.h'
3440--- src/field_codec_id.h 1970-01-01 00:00:00 +0000
3441+++ src/field_codec_id.h 2014-08-27 16:27:22 +0000
3442@@ -0,0 +1,50 @@
3443+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
3444+// Massachusetts Institute of Technology (2007-)
3445+// Woods Hole Oceanographic Institution (2007-)
3446+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
3447+//
3448+//
3449+// This file is part of the Dynamic Compact Control Language Library
3450+// ("DCCL").
3451+//
3452+// DCCL is free software: you can redistribute them and/or modify
3453+// them under the terms of the GNU Lesser General Public License as published by
3454+// the Free Software Foundation, either version 3 of the License, or
3455+// (at your option) any later version.
3456+//
3457+// DCCL is distributed in the hope that they will be useful,
3458+// but WITHOUT ANY WARRANTY; without even the implied warranty of
3459+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3460+// GNU Lesser General Public License for more details.
3461+//
3462+// You should have received a copy of the GNU Lesser General Public License
3463+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
3464+
3465+#include "field_codec_fixed.h"
3466+
3467+namespace dccl
3468+{
3469+ /// \brief Provides the default 1 byte or 2 byte DCCL ID codec
3470+ class DefaultIdentifierCodec : public TypedFieldCodec<uint32>
3471+ {
3472+ protected:
3473+ virtual Bitset encode();
3474+ virtual Bitset encode(const uint32& wire_value);
3475+ virtual uint32 decode(Bitset* bits);
3476+ virtual unsigned size();
3477+ virtual unsigned size(const uint32& wire_value);
3478+ virtual unsigned max_size();
3479+ virtual unsigned min_size();
3480+ virtual void validate() { }
3481+
3482+ private:
3483+ unsigned this_size(const uint32& wire_value);
3484+ // maximum id we can fit in short or long header (MSB reserved to indicate
3485+ // short or long header)
3486+ enum { ONE_BYTE_MAX_ID = (1 << 7) - 1,
3487+ TWO_BYTE_MAX_ID = (1 << 15) - 1};
3488+
3489+ enum { SHORT_FORM_ID_BYTES = 1,
3490+ LONG_FORM_ID_BYTES = 2 };
3491+ };
3492+}
3493
3494=== modified file 'src/field_codec_manager.h'
3495--- src/field_codec_manager.h 2014-04-22 20:10:37 +0000
3496+++ src/field_codec_manager.h 2014-08-27 16:27:22 +0000
3497@@ -81,12 +81,49 @@
3498 template<class Codec, google::protobuf::FieldDescriptor::Type type>
3499 static void add(const std::string& name);
3500
3501+ /// \brief Remove a new field codec (used for codecs operating on statically generated Protobuf messages, that is, children of google::protobuf::Message but not google::protobuf::Message itself).
3502+ ///
3503+ /// \tparam Codec A child of FieldCodecBase
3504+ /// \param name Name to use for this codec. Corresponds to (dccl.field).codec="name" in .proto file.
3505+ /// \return nothing (void). Return templates are used for template metaprogramming selection of the proper remove() overload.
3506+ template<class Codec>
3507+ typename boost::enable_if<
3508+ boost::mpl::and_<boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>,
3509+ boost::mpl::not_<boost::is_same<google::protobuf::Message, typename Codec::wire_type> >
3510+ >,
3511+ void>::type
3512+ static remove(const std::string& name, dummy_fcm<0> dummy_fcm = 0);
3513+
3514+ /// \brief Remove a new field codec (used for codecs operating on all types except statically generated Protobuf messages).
3515+ ///
3516+ /// \tparam Codec A child of FieldCodecBase
3517+ /// \param name Name to use for this codec. Corresponds to (dccl.field).codec="name" in .proto file.
3518+ /// \return nothing (void). Return templates are used for template metaprogramming selection of the proper remove() overload.
3519+ template<class Codec>
3520+ typename boost::disable_if<
3521+ boost::mpl::and_<boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>,
3522+ boost::mpl::not_<boost::is_same<google::protobuf::Message,typename Codec::wire_type> >
3523+ >,
3524+ void>::type
3525+ static remove(const std::string& name, dummy_fcm<1> dummy_fcm = 0);
3526+
3527+ /// \brief Remove a new field codec only valid for a specific google::protobuf::FieldDescriptor::Type. This is useful if a given codec is designed to work with only a specific Protobuf type that shares an underlying C++ type (e.g. Protobuf types `bytes` and `string`)
3528+ ///
3529+ /// \tparam Codec A child of FieldCodecBase
3530+ /// \tparam type The google::protobuf::FieldDescriptor::Type enumeration that this codec works on.
3531+ /// \param name Name to use for this codec. Corresponds to (dccl.field).codec="name" in .proto file.
3532+ template<class Codec, google::protobuf::FieldDescriptor::Type type>
3533+ static void remove(const std::string& name);
3534+
3535+
3536 /// \brief Find the codec for a given field. For embedded messages, prefers (dccl.field).codec (inside field) over (dccl.msg).codec (inside embedded message).
3537 static boost::shared_ptr<FieldCodecBase> find(
3538- const google::protobuf::FieldDescriptor* field)
3539+ const google::protobuf::FieldDescriptor* field,
3540+ bool has_codec_group,
3541+ const std::string& codec_group)
3542 {
3543- std::string name = __find_codec(field);
3544-
3545+ std::string name = __find_codec(field, has_codec_group, codec_group);
3546+
3547 if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
3548 return find(field->message_type(), name);
3549 else
3550@@ -101,9 +138,16 @@
3551 const google::protobuf::Descriptor* desc,
3552 std::string name = "")
3553 {
3554+ // this was called on the root message
3555 if(name.empty())
3556- name = desc->options().GetExtension(dccl::msg).codec();
3557-
3558+ {
3559+ // explicitly declared codec takes precedence over group
3560+ if(desc->options().GetExtension(dccl::msg).has_codec())
3561+ name = desc->options().GetExtension(dccl::msg).codec();
3562+ else
3563+ name = FieldCodecBase::codec_group(desc);
3564+ }
3565+
3566 return __find(google::protobuf::FieldDescriptor::TYPE_MESSAGE,
3567 name, desc->full_name());
3568 }
3569@@ -115,6 +159,11 @@
3570 return __find(type, name);
3571 }
3572
3573+ static void clear()
3574+ {
3575+ TypeHelper::reset();
3576+ codecs_.clear();
3577+ }
3578
3579
3580 private:
3581@@ -132,27 +181,41 @@
3582
3583 static std::string __mangle_name(const std::string& codec_name,
3584 const std::string& type_name)
3585- { return type_name.empty() ? codec_name : codec_name + "@@" + type_name; }
3586+ { return type_name.empty() ? codec_name : codec_name + "[" + type_name + "]"; }
3587
3588
3589 template<typename WireType, typename FieldType, class Codec>
3590- static void __add(const std::string& name);
3591-
3592- template<class Codec>
3593- static void __add(const std::string& name,
3594- google::protobuf::FieldDescriptor::Type field_type,
3595- google::protobuf::FieldDescriptor::CppType wire_type);
3596-
3597-
3598- static std::string __find_codec(const google::protobuf::FieldDescriptor* field)
3599+ static void add_all_types(const std::string& name);
3600+
3601+ template<class Codec>
3602+ static void add_single_type(const std::string& name,
3603+ google::protobuf::FieldDescriptor::Type field_type,
3604+ google::protobuf::FieldDescriptor::CppType wire_type);
3605+
3606+ template<typename WireType, typename FieldType, class Codec>
3607+ static void remove_all_types(const std::string& name);
3608+
3609+ template<class Codec>
3610+ static void remove_single_type(const std::string& name,
3611+ google::protobuf::FieldDescriptor::Type field_type,
3612+ google::protobuf::FieldDescriptor::CppType wire_type);
3613+
3614+
3615+ static std::string __find_codec(const google::protobuf::FieldDescriptor* field,
3616+ bool has_codec_group, const std::string& codec_group)
3617 {
3618 dccl::DCCLFieldOptions dccl_field_options = field->options().GetExtension(dccl::field);
3619
3620 // prefer the codec listed as a field extension
3621 if(dccl_field_options.has_codec())
3622- return dccl_field_options.codec();
3623- else if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
3624+ return dccl_field_options.codec();
3625+ // then, the codec embedded in the message option extension
3626+ else if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE && field->message_type()->options().GetExtension(dccl::msg).has_codec())
3627 return field->message_type()->options().GetExtension(dccl::msg).codec();
3628+ // then the overarching codec group
3629+ else if(has_codec_group)
3630+ return codec_group;
3631+ // finally the default
3632 else
3633 return dccl_field_options.codec();
3634 }
3635@@ -173,9 +236,9 @@
3636 dccl::FieldCodecManager::add(const std::string& name, dummy_fcm<0> dummy_fcm)
3637 {
3638 TypeHelper::add<typename Codec::wire_type>();
3639- __add<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()),
3640- google::protobuf::FieldDescriptor::TYPE_MESSAGE,
3641- google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
3642+ add_single_type<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()),
3643+ google::protobuf::FieldDescriptor::TYPE_MESSAGE,
3644+ google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
3645 }
3646
3647 template<class Codec>
3648@@ -187,18 +250,18 @@
3649 void>::type
3650 dccl::FieldCodecManager::add(const std::string& name, dummy_fcm<1> dummy_fcm)
3651 {
3652- __add<typename Codec::wire_type, typename Codec::field_type, Codec>(name);
3653+ add_all_types<typename Codec::wire_type, typename Codec::field_type, Codec>(name);
3654 }
3655
3656 template<class Codec, google::protobuf::FieldDescriptor::Type type>
3657 void dccl::FieldCodecManager::add(const std::string& name)
3658 {
3659- __add<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type));
3660+ add_single_type<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type));
3661 }
3662
3663
3664 template<typename WireType, typename FieldType, class Codec>
3665- void dccl::FieldCodecManager::__add(const std::string& name)
3666+ void dccl::FieldCodecManager::add_all_types(const std::string& name)
3667 {
3668 using google::protobuf::FieldDescriptor;
3669 const FieldDescriptor::CppType cpp_field_type = ToProtoCppType<FieldType>::as_enum();
3670@@ -209,17 +272,17 @@
3671 FieldDescriptor::Type field_type = static_cast<FieldDescriptor::Type>(i);
3672 if(FieldDescriptor::TypeToCppType(field_type) == cpp_field_type)
3673 {
3674- __add<Codec>(name, field_type, cpp_wire_type);
3675+ add_single_type<Codec>(name, field_type, cpp_wire_type);
3676 }
3677 }
3678 }
3679
3680 template<class Codec>
3681-void dccl::FieldCodecManager::__add(const std::string& name,
3682- google::protobuf::FieldDescriptor::Type field_type,
3683- google::protobuf::FieldDescriptor::CppType wire_type)
3684+void dccl::FieldCodecManager::add_single_type(const std::string& name,
3685+ google::protobuf::FieldDescriptor::Type field_type,
3686+ google::protobuf::FieldDescriptor::CppType wire_type)
3687 {
3688- using google::protobuf::FieldDescriptor;
3689+ using google::protobuf::FieldDescriptor;
3690 if(!codecs_[field_type].count(name))
3691 {
3692 boost::shared_ptr<FieldCodecBase> new_field_codec(new Codec());
3693@@ -246,4 +309,82 @@
3694
3695
3696
3697+template<class Codec>
3698+typename boost::enable_if<
3699+boost::mpl::and_<
3700+boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>,
3701+boost::mpl::not_<boost::is_same<google::protobuf::Message, typename Codec::wire_type> >
3702+>,
3703+void>::type
3704+dccl::FieldCodecManager::remove(const std::string& name, dummy_fcm<0> dummy_fcm)
3705+{
3706+ TypeHelper::remove<typename Codec::wire_type>();
3707+ remove_single_type<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()),
3708+ google::protobuf::FieldDescriptor::TYPE_MESSAGE,
3709+ google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE);
3710+}
3711+
3712+template<class Codec>
3713+typename boost::disable_if<
3714+boost::mpl::and_<
3715+boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>,
3716+ boost::mpl::not_<boost::is_same<google::protobuf::Message, typename Codec::wire_type> >
3717+ >,
3718+ void>::type
3719+ dccl::FieldCodecManager::remove(const std::string& name, dummy_fcm<1> dummy_fcm)
3720+{
3721+ remove_all_types<typename Codec::wire_type, typename Codec::field_type, Codec>(name);
3722+}
3723+
3724+template<class Codec, google::protobuf::FieldDescriptor::Type type>
3725+ void dccl::FieldCodecManager::remove(const std::string& name)
3726+{
3727+ remove_single_type<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type));
3728+}
3729+
3730+
3731+template<typename WireType, typename FieldType, class Codec>
3732+ void dccl::FieldCodecManager::remove_all_types(const std::string& name)
3733+{
3734+ using google::protobuf::FieldDescriptor;
3735+ const FieldDescriptor::CppType cpp_field_type = ToProtoCppType<FieldType>::as_enum();
3736+ const FieldDescriptor::CppType cpp_wire_type = ToProtoCppType<WireType>::as_enum();
3737+
3738+ for(int i = 1, n = FieldDescriptor::MAX_TYPE; i <= n; ++i)
3739+ {
3740+ FieldDescriptor::Type field_type = static_cast<FieldDescriptor::Type>(i);
3741+ if(FieldDescriptor::TypeToCppType(field_type) == cpp_field_type)
3742+ {
3743+ remove_single_type<Codec>(name, field_type, cpp_wire_type);
3744+ }
3745+ }
3746+}
3747+
3748+template<class Codec>
3749+void dccl::FieldCodecManager::remove_single_type(const std::string& name,
3750+ google::protobuf::FieldDescriptor::Type field_type,
3751+ google::protobuf::FieldDescriptor::CppType wire_type)
3752+{
3753+ using google::protobuf::FieldDescriptor;
3754+ if(codecs_[field_type].count(name))
3755+ {
3756+ dccl::dlog.is(dccl::logger::DEBUG1) && dccl::dlog << "Removing codec " << *codecs_[field_type][name] << std::endl;
3757+ codecs_[field_type].erase(name);
3758+ }
3759+ else
3760+ {
3761+ boost::shared_ptr<FieldCodecBase> new_field_codec(new Codec());
3762+ new_field_codec->set_name(name);
3763+ new_field_codec->set_field_type(field_type);
3764+ new_field_codec->set_wire_type(wire_type);
3765+
3766+ dccl::dlog.is(dccl::logger::DEBUG1) && dccl::dlog << "Trying to remove: " << *new_field_codec
3767+ << ", but no such codec exists"
3768+ << std::endl;
3769+ }
3770+}
3771+
3772+
3773+
3774+
3775 #endif
3776
3777=== modified file 'src/field_codec_message_stack.cpp'
3778--- src/field_codec_message_stack.cpp 2014-04-22 20:10:37 +0000
3779+++ src/field_codec_message_stack.cpp 2014-08-27 16:27:22 +0000
3780@@ -26,7 +26,7 @@
3781
3782 std::vector<const google::protobuf::FieldDescriptor*> dccl::MessageStack::field_;
3783 std::vector<const google::protobuf::Descriptor*> dccl::MessageStack::desc_;
3784-dccl::MessageStack::MessagePart dccl::MessageStack::current_part_ = dccl::MessageStack::UNKNOWN;
3785+std::vector<dccl::MessageStack::MessagePart> dccl::MessageStack::parts_;
3786
3787 //
3788 // MessageStack
3789@@ -45,6 +45,12 @@
3790 ++fields_pushed_;
3791 }
3792
3793+void dccl::MessageStack::push(MessagePart part)
3794+{
3795+ parts_.push_back(part);
3796+ ++parts_pushed_;
3797+}
3798+
3799
3800 void dccl::MessageStack::__pop_desc()
3801 {
3802@@ -58,17 +64,34 @@
3803 field_.pop_back();
3804 }
3805
3806+void dccl::MessageStack::__pop_parts()
3807+{
3808+ if(!parts_.empty())
3809+ parts_.pop_back();
3810+}
3811+
3812+
3813 dccl::MessageStack::MessageStack(const google::protobuf::FieldDescriptor* field)
3814 : descriptors_pushed_(0),
3815- fields_pushed_(0)
3816+ fields_pushed_(0),
3817+ parts_pushed_(0)
3818 {
3819 if(field)
3820 {
3821 if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE)
3822 {
3823- // if explicitly set, set part (HEAD or BODY) of message for all children of this message
3824+ MessagePart part = UNKNOWN;
3825 if(field->options().GetExtension(dccl::field).has_in_head())
3826- current_part_ = field->options().GetExtension(dccl::field).in_head() ? HEAD : BODY;
3827+ {
3828+ // if explicitly set, set part (HEAD or BODY) of message for all children of this message
3829+ part = field->options().GetExtension(dccl::field).in_head() ? HEAD : BODY;
3830+ }
3831+ else
3832+ {
3833+ // use the parent's current part
3834+ part = current_part();
3835+ }
3836+ push(part);
3837
3838 push(field->message_type());
3839 }
3840@@ -77,3 +100,14 @@
3841
3842 }
3843
3844+dccl::MessageStack::~MessageStack()
3845+{
3846+ for(int i = 0; i < fields_pushed_; ++i)
3847+ __pop_field();
3848+
3849+ for(int i = 0; i < descriptors_pushed_; ++i)
3850+ __pop_desc();
3851+
3852+ for(int i = 0; i < parts_pushed_; ++i)
3853+ __pop_parts();
3854+}
3855
3856=== modified file 'src/field_codec_message_stack.h'
3857--- src/field_codec_message_stack.h 2014-04-22 20:10:37 +0000
3858+++ src/field_codec_message_stack.h 2014-08-27 16:27:22 +0000
3859@@ -34,19 +34,7 @@
3860 public:
3861 MessageStack(const google::protobuf::FieldDescriptor* field = 0);
3862
3863- ~MessageStack()
3864- {
3865- for(int i = 0; i < descriptors_pushed_; ++i)
3866- __pop_desc();
3867-
3868- for(int i = 0; i < fields_pushed_; ++i)
3869- __pop_field();
3870-
3871- if(desc_.empty())
3872- {
3873- current_part_ = UNKNOWN;
3874- }
3875- }
3876+ ~MessageStack();
3877
3878 enum MessagePart { HEAD, BODY, UNKNOWN };
3879
3880@@ -57,19 +45,22 @@
3881
3882 void push(const google::protobuf::Descriptor* desc);
3883 void push(const google::protobuf::FieldDescriptor* field);
3884+ void push(MessagePart part);
3885
3886- static MessagePart current_part() { return current_part_; }
3887-
3888+ static MessagePart current_part() { return parts_.empty() ? UNKNOWN : parts_.back(); }
3889+
3890 friend class FieldCodecBase;
3891 private:
3892 void __pop_desc();
3893 void __pop_field();
3894+ void __pop_parts();
3895
3896 static std::vector<const google::protobuf::Descriptor*> desc_;
3897 static std::vector<const google::protobuf::FieldDescriptor*> field_;
3898+ static std::vector<MessagePart> parts_;
3899 int descriptors_pushed_;
3900 int fields_pushed_;
3901- static MessagePart current_part_;
3902+ int parts_pushed_;
3903 };
3904 }
3905
3906
3907=== modified file 'src/field_codec_typed.h'
3908--- src/field_codec_typed.h 2014-04-22 20:10:37 +0000
3909+++ src/field_codec_typed.h 2014-08-27 16:27:22 +0000
3910@@ -24,6 +24,9 @@
3911 #ifndef DCCLFIELDCODECTYPED20120312H
3912 #define DCCLFIELDCODECTYPED20120312H
3913
3914+
3915+#include <boost/type_traits.hpp>
3916+
3917 #include "field_codec.h"
3918
3919 namespace dccl
3920@@ -72,7 +75,7 @@
3921 class TypedFieldCodec : public FieldCodecSelector<WireType, FieldType>
3922 {
3923 public:
3924- typedef WireType wire_type;
3925+typedef WireType wire_type;
3926 typedef FieldType field_type;
3927
3928 public:
3929@@ -256,8 +259,14 @@
3930 ///
3931 /// \param bits Bits to use for decoding.
3932 /// \return the decoded value.
3933- virtual WireType decode(Bitset* bits)
3934- { return decode_repeated(bits).at(0); }
3935+ virtual WireType decode(dccl::Bitset* bits)
3936+ {
3937+ std::vector<WireType> return_vec = decode_repeated(bits);
3938+ if(return_vec.empty())
3939+ throw dccl::NullValueException();
3940+ else
3941+ return return_vec.at(0);
3942+ }
3943
3944 /// \brief Calculate the size (in bits) of an empty field.
3945 ///
3946
3947=== modified file 'src/logger.cpp'
3948--- src/logger.cpp 2014-04-22 20:10:37 +0000
3949+++ src/logger.cpp 2014-08-27 16:27:22 +0000
3950@@ -55,6 +55,7 @@
3951 case logger::GENERAL: break;
3952 case logger::ENCODE: grp_str = "{encode}: "; break;
3953 case logger::DECODE: grp_str = "{decode}: "; break;
3954+ case logger::SIZE: grp_str = "{size}: "; break;
3955 }
3956
3957 std::time_t now = std::time(0);
3958@@ -64,11 +65,12 @@
3959 {
3960 *os << "[ " << (t->tm_year+1900) << "-"
3961 << std::setw(2) << std::setfill('0') << (t->tm_mon+1) << "-"
3962- << std::setw(2) << std::setfill('0') << t->tm_mday
3963+ << std::setw(2) << t->tm_mday
3964 << " "
3965- << std::setw(2) << std::setfill('0') << t->tm_hour << ":"
3966- << std::setw(2) << std::setfill('0') << t->tm_min << ":"
3967- << std::setw(2) << std::setfill('0') << t->tm_sec << " ]: ";
3968+ << std::setw(2) << t->tm_hour << ":"
3969+ << std::setw(2) << t->tm_min << ":"
3970+ << std::setw(2) << t->tm_sec << " ]: "
3971+ << std::setfill(' ');
3972 }
3973
3974 *os << grp_str << msg << std::endl;
3975
3976=== modified file 'src/logger.h'
3977--- src/logger.h 2014-04-22 20:10:37 +0000
3978+++ src/logger.h 2014-08-27 16:27:22 +0000
3979@@ -47,10 +47,11 @@
3980 DEBUG3_PLUS = DEBUG3 | (DEBUG3 - 1)
3981 };
3982 enum Group
3983- { GENERAL, ENCODE, DECODE };
3984+ { GENERAL, ENCODE, DECODE, SIZE };
3985
3986 }
3987
3988+
3989
3990 void to_ostream(const std::string& msg, dccl::logger::Verbosity vrb,
3991 dccl::logger::Group grp, std::ostream* os, bool add_timestamp);
3992
3993=== modified file 'src/protobuf/option_extensions.proto'
3994--- src/protobuf/option_extensions.proto 2013-08-20 16:17:28 +0000
3995+++ src/protobuf/option_extensions.proto 2014-08-27 16:27:22 +0000
3996@@ -25,7 +25,7 @@
3997 message DCCLFieldOptions
3998 {
3999 // what encoder / decoder should we use?
4000- optional string codec = 1 [default = "dccl.default"];
4001+ optional string codec = 1 [default = "dccl.default2"];
4002 // leave this field out of DCCL transmissions (has_field() will be false on receipt)
4003 optional bool omit = 2 [default = false];
4004 // set true for fields in the header (will *not* be encrypte)d
4005@@ -60,9 +60,12 @@
4006
4007 message DCCLMessageOptions
4008 {
4009- required int32 id = 1;
4010- required uint32 max_bytes = 2;
4011-
4012- optional string codec = 3 [default = "dccl.default"];
4013+ optional int32 id = 1;
4014+ optional uint32 max_bytes = 2;
4015+
4016+ optional string codec = 3 [default = "dccl.default2"];
4017+
4018+ optional string codec_group = 4 [default = "dccl.default2"];
4019+ optional int32 codec_version = 5 [default = 2];
4020 }
4021
4022
4023=== modified file 'src/test/CMakeLists.txt'
4024--- src/test/CMakeLists.txt 2014-03-26 16:25:12 +0000
4025+++ src/test/CMakeLists.txt 2014-08-27 16:27:22 +0000
4026@@ -10,6 +10,8 @@
4027 add_subdirectory(dccl_static_methods)
4028 add_subdirectory(dccl_custom_id)
4029 add_subdirectory(dccl_numeric_bounds)
4030+add_subdirectory(dccl_codec_group)
4031+add_subdirectory(dccl_message_fix)
4032
4033 if(build_ccl)
4034 add_subdirectory(dccl_ccl)
4035@@ -19,6 +21,9 @@
4036 add_subdirectory(dccl_arithmetic)
4037 endif()
4038
4039+add_subdirectory(dccl_v2_all_fields)
4040+add_subdirectory(dccl_v2_header)
4041+
4042 add_subdirectory(bitset1)
4043
4044 add_subdirectory(logger1)
4045
4046=== modified file 'src/test/dccl_all_fields/test.cpp'
4047--- src/test/dccl_all_fields/test.cpp 2014-04-22 20:13:39 +0000
4048+++ src/test/dccl_all_fields/test.cpp 2014-08-27 16:27:22 +0000
4049@@ -136,7 +136,9 @@
4050 decode_check(bytes);
4051
4052 // make sure DCCL defaults stay wire compatible
4053- decode_check(dccl::hex_decode("047f277b9628060000b95660c0b0188000d8c0132858800008000dc2c4c6626466024488cca8ee324bd05c3f23af0000ad9112a09509788013e0820b18e0005ed0204c6c2c4666062042644675975982c65235f10a00ad718a5801000000905f27121600000000a0170050640300309201001a0b00007d320a0000a61a0070b20100a81b00d09c6f0000a0401026361643102636160300f0dfbd5b2280ea2e330f3da59a2100aabfa55a000000000000000000000000"));
4054+
4055+ // v3
4056+ decode_check(dccl::hex_decode("047f277b16b95660c0b0188000d8c0132858800008002d4c6c2c4666264084c88cea2eb304cdeb67cc2b00b4464a805626e0014e800b2e60800378410b131b8b91990188109951dd6596a0b154cd7805506b9c2256caaf13094ba0978a6c248a692493c682fa6454a69a4e36a16e6ace37a918263616c330b1b118fd77ef9608a0bacbac574fa9cd1050fd6daa0500"));
4057
4058 // run a bunch of tests with random strings
4059 std::string random = bytes;
4060
4061=== modified file 'src/test/dccl_all_fields/test.proto'
4062--- src/test/dccl_all_fields/test.proto 2012-10-19 16:41:36 +0000
4063+++ src/test/dccl_all_fields/test.proto 2014-08-27 16:27:22 +0000
4064@@ -29,6 +29,7 @@
4065 {
4066 option (dccl.msg).id = 2;
4067 option (dccl.msg).max_bytes = 512;
4068+ option (dccl.msg).codec_version = 3;
4069
4070 // test default enc/dec
4071 optional double double_default_optional = 1 [(dccl.field).min=-100,
4072@@ -123,8 +124,7 @@
4073 (dccl.field).max_repeat=4];
4074 repeated uint32 uint32_default_repeat = 105 [(dccl.field).min=0,
4075 (dccl.field).max=100,
4076- (dccl.field).max_repeat=4,
4077- (dccl.field).in_head=true];
4078+ (dccl.field).max_repeat=4];
4079 repeated uint64 uint64_default_repeat = 106 [(dccl.field).min=0,
4080 (dccl.field).max=100,
4081 (dccl.field).max_repeat=4];
4082
4083=== modified file 'src/test/dccl_arithmetic/test.proto'
4084--- src/test/dccl_arithmetic/test.proto 2012-10-23 00:46:12 +0000
4085+++ src/test/dccl_arithmetic/test.proto 2014-08-27 16:27:22 +0000
4086@@ -25,7 +25,8 @@
4087 {
4088 option (dccl.msg).id = 1;
4089 option (dccl.msg).max_bytes = 512;
4090-
4091+ option (dccl.msg).codec_version = 3;
4092+
4093 repeated double value = 101 [(dccl.field).codec = "_arithmetic",
4094 (dccl.field).(arithmetic).model = "model",
4095 (dccl.field).(arithmetic).debug_assert = true,
4096@@ -35,6 +36,7 @@
4097 {
4098 option (dccl.msg).id = 2;
4099 option (dccl.msg).max_bytes = 512;
4100+ option (dccl.msg).codec_version = 3;
4101
4102 repeated Enum1 value = 114 [(dccl.field).codec = "_arithmetic",
4103 (dccl.field).(arithmetic).model = "model",
4104@@ -47,6 +49,7 @@
4105 {
4106 option (dccl.msg).id = 3;
4107 option (dccl.msg).max_bytes = 512;
4108+ option (dccl.msg).codec_version = 3;
4109
4110 required Enum1 value = 114 [(dccl.field).codec = "_arithmetic",
4111 (dccl.field).(arithmetic).model = "model",
4112@@ -58,6 +61,7 @@
4113 {
4114 option (dccl.msg).id = 4;
4115 option (dccl.msg).max_bytes = 512;
4116+ option (dccl.msg).codec_version = 3;
4117
4118 repeated Enum2 value = 114 [(dccl.field).codec = "_arithmetic",
4119 (dccl.field).(arithmetic).model = "model",
4120@@ -70,6 +74,7 @@
4121 {
4122 option (dccl.msg).id = 5;
4123 option (dccl.msg).max_bytes = 10000;
4124+ option (dccl.msg).codec_version = 3;
4125
4126 repeated int32 value = 101 [(dccl.field).codec = "_arithmetic",
4127 (dccl.field).(arithmetic).model = "model",
4128@@ -82,6 +87,7 @@
4129 {
4130 option (dccl.msg).id = 6;
4131 option (dccl.msg).max_bytes = 10000;
4132+ option (dccl.msg).codec_version = 3;
4133
4134 repeated int32 value = 101 [(dccl.field).codec = "_arithmetic",
4135 (dccl.field).(arithmetic).model = "model",
4136
4137=== modified file 'src/test/dccl_ccl/test.cpp'
4138--- src/test/dccl_ccl/test.cpp 2014-04-22 20:13:39 +0000
4139+++ src/test/dccl_ccl/test.cpp 2014-08-27 16:27:22 +0000
4140@@ -48,11 +48,9 @@
4141 {
4142 dccl::dlog.connect(dccl::logger::ALL, &std::cerr);
4143
4144- {
4145- dccl::FieldCodecManager::add<dccl::LegacyCCLIdentifierCodec>("ccl_id_codec");
4146- dccl::Codec codec("ccl_id_codec");
4147-
4148+ {
4149 void* dl_handle = dlopen("libdccl_ccl_compat" SHARED_LIBRARY_SUFFIX, RTLD_LAZY);
4150+ dccl::Codec codec("dccl.ccl.id");
4151
4152 if(!dl_handle)
4153 {
4154
4155=== modified file 'src/test/dccl_ccl/test.proto'
4156--- src/test/dccl_ccl/test.proto 2012-10-24 14:10:06 +0000
4157+++ src/test/dccl_ccl/test.proto 2014-08-27 16:27:22 +0000
4158@@ -4,6 +4,7 @@
4159 {
4160 option (dccl.msg).id = 1;
4161 option (dccl.msg).max_bytes = 32;
4162+ option (dccl.msg).codec_version = 3;
4163
4164 required int32 a = 1 [(dccl.field).min=0,
4165 (dccl.field).max=0xFFFF];
4166
4167=== added directory 'src/test/dccl_codec_group'
4168=== added file 'src/test/dccl_codec_group/CMakeLists.txt'
4169--- src/test/dccl_codec_group/CMakeLists.txt 1970-01-01 00:00:00 +0000
4170+++ src/test/dccl_codec_group/CMakeLists.txt 2014-08-27 16:27:22 +0000
4171@@ -0,0 +1,6 @@
4172+protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS test.proto)
4173+
4174+add_executable(dccl_test_codec_group test.cpp ${PROTO_SRCS} ${PROTO_HDRS})
4175+target_link_libraries(dccl_test_codec_group dccl)
4176+
4177+add_test(dccl_test_codec_group ${dccl_BIN_DIR}/dccl_test_codec_group)
4178
4179=== added file 'src/test/dccl_codec_group/test.cpp'
4180--- src/test/dccl_codec_group/test.cpp 1970-01-01 00:00:00 +0000
4181+++ src/test/dccl_codec_group/test.cpp 2014-08-27 16:27:22 +0000
4182@@ -0,0 +1,104 @@
4183+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
4184+// Massachusetts Institute of Technology (2007-)
4185+// Woods Hole Oceanographic Institution (2007-)
4186+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
4187+//
4188+//
4189+// This file is part of the Dynamic Compact Control Language Library
4190+// ("DCCL").
4191+//
4192+// DCCL is free software: you can redistribute them and/or modify
4193+// them under the terms of the GNU Lesser General Public License as published by
4194+// the Free Software Foundation, either version 3 of the License, or
4195+// (at your option) any later version.
4196+//
4197+// DCCL is distributed in the hope that they will be useful,
4198+// but WITHOUT ANY WARRANTY; without even the implied warranty of
4199+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4200+// GNU Lesser General Public License for more details.
4201+//
4202+// You should have received a copy of the GNU Lesser General Public License
4203+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
4204+
4205+
4206+// tests all protobuf types with _default codecs, repeat and non repeat
4207+
4208+#include <fstream>
4209+
4210+#include <google/protobuf/descriptor.pb.h>
4211+
4212+#include "dccl/codec.h"
4213+#include "dccl/codecs3/field_codec_default.h"
4214+
4215+#include "test.pb.h"
4216+#include "dccl/binary.h"
4217+
4218+template <typename Msg>
4219+void check(double val, bool should_pass);
4220+dccl::Codec codec;
4221+TestMsg msg_in;
4222+TestMsgGroup msg_group_in;
4223+
4224+class TestCodec : public dccl::v3::DefaultNumericFieldCodec<double>
4225+{
4226+ double max() { return 100; }
4227+ double min() { return -100; }
4228+ double precision() { return 1; }
4229+ void validate() { }
4230+};
4231+
4232+
4233+
4234+
4235+int main(int argc, char* argv[])
4236+{
4237+// dccl::dlog.connect(dccl::logger::ALL, &std::cerr);
4238+
4239+ dccl::FieldCodecManager::add<TestCodec>("test.grouptest");
4240+ dccl::FieldCodecManager::add<dccl::v3::DefaultMessageCodec, google::protobuf::FieldDescriptor::TYPE_MESSAGE>("test.grouptest");
4241+
4242+ check<TestMsg>(50, true);
4243+ check<TestMsg>(-50, false);
4244+ check<TestMsgGroup>(50, true);
4245+ check<TestMsgGroup>(-50, true);
4246+ check<TestMsgVersion>(50, true);
4247+
4248+ std::cout << "all tests passed" << std::endl;
4249+}
4250+
4251+
4252+template <typename Msg>
4253+void check(double val, bool should_pass)
4254+{
4255+ Msg msg_in;
4256+ int i = 0;
4257+ msg_in.set_d(++i + 0.1);
4258+ msg_in.add_d_repeat(12.1);
4259+ msg_in.add_d_repeat(12.2);
4260+ msg_in.add_d_repeat(12.3);
4261+
4262+ msg_in.mutable_msg()->set_val(val);
4263+ msg_in.mutable_msg()->mutable_msg()->set_val(val);
4264+ codec.info(msg_in.GetDescriptor(), &std::cout);
4265+
4266+ std::cout << "Message in:\n" << msg_in.DebugString() << std::endl;
4267+
4268+ codec.load(msg_in.GetDescriptor());
4269+
4270+ std::cout << "Try encode..." << std::endl;
4271+ std::string bytes;
4272+ codec.encode(&bytes, msg_in);
4273+ std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl;
4274+
4275+ std::cout << "Try decode..." << std::endl;
4276+
4277+ Msg msg_out;
4278+ codec.decode(bytes, &msg_out);
4279+
4280+ std::cout << "... got Message out:\n" << msg_out.DebugString() << std::endl;
4281+
4282+ if(should_pass)
4283+ assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
4284+ else
4285+ assert(msg_in.SerializeAsString() != msg_out.SerializeAsString());
4286+}
4287
4288=== added file 'src/test/dccl_codec_group/test.proto'
4289--- src/test/dccl_codec_group/test.proto 1970-01-01 00:00:00 +0000
4290+++ src/test/dccl_codec_group/test.proto 2014-08-27 16:27:22 +0000
4291@@ -0,0 +1,77 @@
4292+import "dccl/protobuf/option_extensions.proto";
4293+
4294+
4295+message EmbeddedMsg1
4296+{
4297+ option (dccl.msg).codec="dccl.default3";
4298+
4299+ optional double val = 1 [(dccl.field).min=0,
4300+ (dccl.field).max=100,
4301+ (dccl.field).precision=3];
4302+
4303+
4304+ optional EmbeddedMsg2 msg = 2;
4305+}
4306+
4307+message EmbeddedMsg2
4308+{
4309+ optional double val = 1 [(dccl.field).min=0,
4310+ (dccl.field).max=100,
4311+ (dccl.field).precision=2];
4312+
4313+}
4314+
4315+message TestMsg
4316+{
4317+ option (dccl.msg).id = 1;
4318+ option (dccl.msg).max_bytes = 32;
4319+ option (dccl.msg).codec_version = 3;
4320+
4321+ optional double d = 1 [(dccl.field).min=-100,
4322+ (dccl.field).max=126,
4323+ (dccl.field).precision=1,
4324+ (dccl.field).codec="dccl.default3"];
4325+
4326+
4327+
4328+ repeated double d_repeat = 3 [(dccl.field).max_repeat=5,
4329+ (dccl.field).codec="test.grouptest"];
4330+ optional EmbeddedMsg1 msg = 2;
4331+}
4332+
4333+message TestMsgGroup
4334+{
4335+ option (dccl.msg).id = 2;
4336+ option (dccl.msg).max_bytes = 32;
4337+ option (dccl.msg).codec_group = "test.grouptest";
4338+ option (dccl.msg).codec_version = 3;
4339+
4340+ optional double d = 1 [(dccl.field).min=-100,
4341+ (dccl.field).max=126,
4342+ (dccl.field).precision=1,
4343+ (dccl.field).codec="dccl.default3"];
4344+
4345+ repeated double d_repeat = 3 [(dccl.field).max_repeat=5];
4346+ optional EmbeddedMsg1 msg = 2;
4347+
4348+}
4349+
4350+
4351+message TestMsgVersion
4352+{
4353+ option (dccl.msg).id = 3;
4354+ option (dccl.msg).max_bytes = 32;
4355+ option (dccl.msg).codec_version = 2;
4356+
4357+ optional double d = 1 [(dccl.field).min=-100,
4358+ (dccl.field).max=126,
4359+ (dccl.field).precision=2];
4360+
4361+ repeated double d_repeat = 3 [(dccl.field).min=12.0,
4362+ (dccl.field).max=13.6,
4363+ (dccl.field).precision=1,
4364+ (dccl.field).max_repeat=5];
4365+
4366+ optional EmbeddedMsg1 msg = 2;
4367+
4368+}
4369
4370=== modified file 'src/test/dccl_custom_id/test.proto'
4371--- src/test/dccl_custom_id/test.proto 2012-10-24 14:10:06 +0000
4372+++ src/test/dccl_custom_id/test.proto 2014-08-27 16:27:22 +0000
4373@@ -4,6 +4,7 @@
4374 {
4375 option (dccl.msg).id = 1000001;
4376 option (dccl.msg).max_bytes = 2;
4377+ option (dccl.msg).codec_version = 3;
4378
4379 required uint32 user = 1 [(dccl.field).min=0,
4380 (dccl.field).max=0x03FF,
4381@@ -14,6 +15,7 @@
4382 {
4383 option (dccl.msg).id = 1000002;
4384 option (dccl.msg).max_bytes = 2;
4385+ option (dccl.msg).codec_version = 3;
4386
4387 required uint32 clock_mode = 1 [(dccl.field).min=0,
4388 (dccl.field).max=3,
4389@@ -32,6 +34,7 @@
4390 {
4391 option (dccl.msg).id = 1000003;
4392 option (dccl.msg).max_bytes = 2;
4393+ option (dccl.msg).codec_version = 3;
4394
4395 required uint32 user = 1 [(dccl.field).min=0,
4396 (dccl.field).max=0x03FF,
4397
4398=== modified file 'src/test/dccl_custom_message/test.proto'
4399--- src/test/dccl_custom_message/test.proto 2012-10-19 16:41:36 +0000
4400+++ src/test/dccl_custom_message/test.proto 2014-08-27 16:27:22 +0000
4401@@ -6,6 +6,7 @@
4402 option (dccl.msg).id = 3;
4403 option (dccl.msg).max_bytes = 256;
4404 option (dccl.msg).codec = "custom_codec";
4405+ option (dccl.msg).codec_version = 3;
4406
4407 optional uint32 a = 1;
4408 optional bool b = 2;
4409@@ -16,6 +17,7 @@
4410 {
4411 option (dccl.msg).id = 4;
4412 option (dccl.msg).max_bytes = 256;
4413+ option (dccl.msg).codec_version = 3;
4414
4415 optional CustomMsg msg = 1;
4416 repeated int32 c = 3 [(dccl.field).max=100,
4417
4418=== modified file 'src/test/dccl_default_id/test.proto'
4419--- src/test/dccl_default_id/test.proto 2012-10-19 16:41:36 +0000
4420+++ src/test/dccl_default_id/test.proto 2014-08-27 16:27:22 +0000
4421@@ -4,12 +4,14 @@
4422 {
4423 option (dccl.msg).id = 2;
4424 option (dccl.msg).max_bytes = 1;
4425+ option (dccl.msg).codec_version = 3;
4426 }
4427
4428 message ShortIDMsgWithData
4429 {
4430 option (dccl.msg).id = 3;
4431 option (dccl.msg).max_bytes = 10;
4432+ option (dccl.msg).codec_version = 3;
4433
4434 optional int32 in_head = 1 [(dccl.field).in_head=true, (dccl.field).min=0, (dccl.field).max=100];
4435 optional int32 in_body = 2 [(dccl.field).in_head=true, (dccl.field).min=0, (dccl.field).max=100];
4436@@ -17,23 +19,28 @@
4437
4438 message LongIDMsg
4439 {
4440- option (dccl.msg).id = 10000; option (dccl.msg).max_bytes = 2;
4441+ option (dccl.msg).id = 10000;
4442+ option (dccl.msg).max_bytes = 2;
4443+ option (dccl.msg).codec_version = 3;
4444 }
4445
4446 message TooLongIDMsg
4447 {
4448 option (dccl.msg).id = 32768;
4449 option (dccl.msg).max_bytes = 32;
4450+ option (dccl.msg).codec_version = 3;
4451 }
4452
4453 message LongIDEdgeMsg
4454 {
4455 option (dccl.msg).id = 128;
4456 option (dccl.msg).max_bytes = 2;
4457+ option (dccl.msg).codec_version = 3;
4458 }
4459
4460 message ShortIDEdgeMsg
4461 {
4462 option (dccl.msg).id = 127;
4463 option (dccl.msg).max_bytes = 1;
4464+ option (dccl.msg).codec_version = 3;
4465 }
4466
4467=== modified file 'src/test/dccl_header/header.proto'
4468--- src/test/dccl_header/header.proto 2013-08-22 18:58:12 +0000
4469+++ src/test/dccl_header/header.proto 2014-08-27 16:27:22 +0000
4470@@ -11,44 +11,35 @@
4471 // microseconds since Unix
4472
4473 // second precision (default)
4474- required uint64 time = 10 [(dccl.field).codec="_time",
4475- (dccl.field).in_head=true];
4476-
4477- optional int64 time_signed = 20 [(dccl.field).codec="_time",
4478- (dccl.field).in_head=true];
4479- optional double time_double = 21 [(dccl.field).codec="_time",
4480- (dccl.field).in_head=true];
4481+ required uint64 time = 10 [(dccl.field).codec="_time"];
4482+
4483+ optional int64 time_signed = 20 [(dccl.field).codec="_time"];
4484+ optional double time_double = 21 [(dccl.field).codec="_time"];
4485 optional double pasttime_double = 22 [(dccl.field).codec="_time",
4486- (dccl.field).num_days=6,
4487- (dccl.field).in_head=true];
4488+ (dccl.field).num_days=6];
4489 optional double futuretime_double = 23 [(dccl.field).codec="_time",
4490- (dccl.field).num_days=6,
4491- (dccl.field).in_head=true];
4492+ (dccl.field).num_days=6];
4493
4494 // microsecond precision
4495 optional int64 time_precision = 24 [(dccl.field).codec="_time",
4496- (dccl.field).in_head=true,
4497 (dccl.field).precision=-3];
4498 optional double time_double_precision = 25 [(dccl.field).codec="_time",
4499- (dccl.field).in_head=true,
4500 (dccl.field).precision=6];
4501
4502 //
4503 // source
4504 //
4505 required int32 source_platform = 11 [(dccl.field).min = 0,
4506- (dccl.field).max = 31,
4507- (dccl.field).in_head=true];
4508+ (dccl.field).max = 31];
4509 optional string source_app = 12 [(dccl.field).omit=true];
4510
4511 //
4512 // destination
4513 //
4514 enum PublishDestination { PUBLISH_SELF = 1; PUBLISH_OTHER = 2; PUBLISH_ALL = 3; }
4515- optional PublishDestination dest_type = 13 [default = PUBLISH_SELF, (dccl.field).in_head=true];
4516+ optional PublishDestination dest_type = 13 [default = PUBLISH_SELF];
4517
4518 optional int32 dest_platform = 14 [(dccl.field).min = 0,
4519- (dccl.field).max = 31,
4520- (dccl.field).in_head=true]; // required if dest_type == other
4521+ (dccl.field).max = 31]; // required if dest_type == other
4522
4523 }
4524
4525=== modified file 'src/test/dccl_header/test.cpp'
4526--- src/test/dccl_header/test.cpp 2014-04-22 20:13:39 +0000
4527+++ src/test/dccl_header/test.cpp 2014-08-27 16:27:22 +0000
4528@@ -24,9 +24,9 @@
4529 // tests proper encoding of standard Goby header
4530
4531 #include "dccl/codec.h"
4532-#include "dccl/field_codec_default.h"
4533 #include "test.pb.h"
4534
4535+#include <sys/time.h>
4536
4537 #include "dccl/binary.h"
4538
4539
4540=== modified file 'src/test/dccl_header/test.proto'
4541--- src/test/dccl_header/test.proto 2013-08-22 18:24:42 +0000
4542+++ src/test/dccl_header/test.proto 2014-08-27 16:27:22 +0000
4543@@ -5,9 +5,10 @@
4544 {
4545 option (dccl.msg).id = 4;
4546 option (dccl.msg).max_bytes = 64;
4547+ option (dccl.msg).codec_version = 3;
4548
4549 required string telegram = 1 [(dccl.field).max_length=10];
4550- required Header header = 2;
4551+ required Header header = 2 [(dccl.field).in_head = true];
4552
4553 optional int32 const_int =3 [(dccl.field).static_value="3", (dccl.field).codec="_static"];
4554 }
4555
4556=== added directory 'src/test/dccl_message_fix'
4557=== added file 'src/test/dccl_message_fix/CMakeLists.txt'
4558--- src/test/dccl_message_fix/CMakeLists.txt 1970-01-01 00:00:00 +0000
4559+++ src/test/dccl_message_fix/CMakeLists.txt 2014-08-27 16:27:22 +0000
4560@@ -0,0 +1,6 @@
4561+protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS test.proto)
4562+
4563+add_executable(dccl_test_message_fix test.cpp ${PROTO_SRCS} ${PROTO_HDRS})
4564+target_link_libraries(dccl_test_message_fix dccl)
4565+
4566+add_test(dccl_test_message_fix ${dccl_BIN_DIR}/dccl_test_message_fix)
4567
4568=== added file 'src/test/dccl_message_fix/test.cpp'
4569--- src/test/dccl_message_fix/test.cpp 1970-01-01 00:00:00 +0000
4570+++ src/test/dccl_message_fix/test.cpp 2014-08-27 16:27:22 +0000
4571@@ -0,0 +1,110 @@
4572+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
4573+// Massachusetts Institute of Technology (2007-)
4574+// Woods Hole Oceanographic Institution (2007-)
4575+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
4576+//
4577+//
4578+// This file is part of the Dynamic Compact Control Language Library
4579+// ("DCCL").
4580+//
4581+// DCCL is free software: you can redistribute them and/or modify
4582+// them under the terms of the GNU Lesser General Public License as published by
4583+// the Free Software Foundation, either version 3 of the License, or
4584+// (at your option) any later version.
4585+//
4586+// DCCL is distributed in the hope that they will be useful,
4587+// but WITHOUT ANY WARRANTY; without even the implied warranty of
4588+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4589+// GNU Lesser General Public License for more details.
4590+//
4591+// You should have received a copy of the GNU Lesser General Public License
4592+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
4593+
4594+
4595+// tests all protobuf types with _default codecs, repeat and non repeat
4596+
4597+#include <fstream>
4598+
4599+#include <google/protobuf/descriptor.pb.h>
4600+
4601+#include "dccl/codec.h"
4602+#include "dccl/codecs2/field_codec_default.h"
4603+
4604+#include "test.pb.h"
4605+#include "dccl/binary.h"
4606+
4607+
4608+int main(int argc, char* argv[])
4609+{
4610+// dccl::dlog.connect(dccl::logger::ALL, &std::cerr);
4611+ // check the empty messages
4612+ dccl::Codec codec;
4613+
4614+ codec.info<TestMsg>(&std::cout);
4615+ codec.load<TestMsg>();
4616+
4617+ {
4618+ TestMsg msg_in, msg_out;
4619+ int i = 0;
4620+
4621+
4622+ std::cout << "Message in:\n" << msg_in.DebugString() << std::endl;
4623+
4624+ codec.load(msg_in.GetDescriptor());
4625+
4626+ std::cout << "Try encode..." << std::endl;
4627+ std::string bytes;
4628+ codec.encode(&bytes, msg_in);
4629+ std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl;
4630+
4631+ std::cout << "Try decode..." << std::endl;
4632+
4633+ codec.decode(bytes, &msg_out);
4634+
4635+ std::cout << "... got Message out:\n" << msg_out.DebugString() << std::endl;
4636+
4637+ assert(!msg_out.has_msg1());
4638+ assert(!msg_out.msg1_repeat_size());
4639+ assert(!msg_out.has_msg2());
4640+ assert(!msg_out.msg2_repeat_size());
4641+ assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
4642+ }
4643+
4644+
4645+ // check partially full messages
4646+ {
4647+ TestMsg msg_in, msg_out;
4648+
4649+ msg_in.mutable_msg1()->set_val(0.1);
4650+ msg_in.add_msg1_repeat()->set_val(0.11);
4651+ msg_in.add_msg1_repeat()->set_val(0.12);
4652+ msg_in.add_msg1_repeat()->set_val(0.13);
4653+ msg_in.mutable_msg2()->set_val(0.2);
4654+ msg_in.add_msg2_repeat()->set_val(0.21);
4655+ msg_in.add_msg2_repeat()->set_val(0.22);
4656+ msg_in.add_msg2_repeat()->set_val(0.23);
4657+
4658+ std::cout << "Message in:\n" << msg_in.DebugString() << std::endl;
4659+
4660+ std::cout << "Try encode..." << std::endl;
4661+ std::string bytes;
4662+ codec.encode(&bytes, msg_in);
4663+ std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl;
4664+
4665+ std::cout << "Try decode..." << std::endl;
4666+
4667+ codec.decode(bytes, &msg_out);
4668+
4669+ std::cout << "... got Message out:\n" << msg_out.DebugString() << std::endl;
4670+
4671+ assert(msg_out.has_msg1());
4672+ assert(msg_out.msg1_repeat_size() == 3);
4673+ assert(msg_out.has_msg2());
4674+ assert(msg_out.msg2_repeat_size() == 3);
4675+ assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
4676+ }
4677+
4678+
4679+ std::cout << "all tests passed" << std::endl;
4680+}
4681+
4682
4683=== added file 'src/test/dccl_message_fix/test.proto'
4684--- src/test/dccl_message_fix/test.proto 1970-01-01 00:00:00 +0000
4685+++ src/test/dccl_message_fix/test.proto 2014-08-27 16:27:22 +0000
4686@@ -0,0 +1,31 @@
4687+import "dccl/protobuf/option_extensions.proto";
4688+
4689+message EmbeddedMsgOptional
4690+{
4691+ optional double val = 1 [(dccl.field).min=0,
4692+ (dccl.field).max=126,
4693+ (dccl.field).precision=3];
4694+}
4695+
4696+message EmbeddedMsgRequired
4697+{
4698+ required double val = 1 [(dccl.field).min=0,
4699+ (dccl.field).max=126,
4700+ (dccl.field).precision=3];
4701+}
4702+
4703+message TestMsg
4704+{
4705+ option (dccl.msg).id = 1;
4706+ option (dccl.msg).max_bytes = 32;
4707+ option (dccl.msg).codec_version = 3;
4708+
4709+ optional EmbeddedMsgOptional msg1 = 1;
4710+ repeated EmbeddedMsgOptional msg1_repeat = 3 [(dccl.field).max_repeat=5];
4711+
4712+ // in DCCL v2, these will always be set upon receipt since it has required children. This test validates the fix in v3
4713+ optional EmbeddedMsgRequired msg2 = 2;
4714+ repeated EmbeddedMsgRequired msg2_repeat = 4 [(dccl.field).max_repeat=5];
4715+
4716+}
4717+
4718
4719=== modified file 'src/test/dccl_numeric_bounds/test.proto'
4720--- src/test/dccl_numeric_bounds/test.proto 2014-03-26 17:27:11 +0000
4721+++ src/test/dccl_numeric_bounds/test.proto 2014-08-27 16:27:22 +0000
4722@@ -4,6 +4,7 @@
4723 {
4724 option (dccl.msg).id = 10;
4725 option (dccl.msg).max_bytes = 32;
4726+ option (dccl.msg).codec_version = 3;
4727
4728 optional double a = 1 [(dccl.field).max = 180,
4729 (dccl.field).min = -180,
4730@@ -30,6 +31,7 @@
4731 {
4732 option (dccl.msg).id = 10;
4733 option (dccl.msg).max_bytes = 32;
4734+ option (dccl.msg).codec_version = 3;
4735
4736 optional double a = 1 [(dccl.field).min = -20,
4737 (dccl.field).max = 20,
4738@@ -45,6 +47,7 @@
4739 {
4740 option (dccl.msg).id = 11;
4741 option (dccl.msg).max_bytes = 32;
4742+ option (dccl.msg).codec_version = 3;
4743
4744 optional double a = 1 [(dccl.field).max = 180,
4745 (dccl.field).min = -180,
4746
4747=== modified file 'src/test/dccl_repeated/test.cpp'
4748--- src/test/dccl_repeated/test.cpp 2014-04-22 20:13:39 +0000
4749+++ src/test/dccl_repeated/test.cpp 2014-08-27 16:27:22 +0000
4750@@ -25,7 +25,6 @@
4751
4752
4753 #include "dccl/codec.h"
4754-#include "dccl/field_codec_default.h"
4755 #include "dccl/binary.h"
4756
4757 #include "test.pb.h"
4758
4759=== modified file 'src/test/dccl_repeated/test.proto'
4760--- src/test/dccl_repeated/test.proto 2012-10-23 00:46:12 +0000
4761+++ src/test/dccl_repeated/test.proto 2014-08-27 16:27:22 +0000
4762@@ -5,6 +5,7 @@
4763 {
4764 option (dccl.msg).id = 4;
4765 option (dccl.msg).max_bytes = 32;
4766+ option (dccl.msg).codec_version = 3;
4767
4768 optional int32 int32_val = 1 [(dccl.field).min=0, (dccl.field).max=20];
4769 }
4770@@ -13,6 +14,7 @@
4771 {
4772 option (dccl.msg).id = 5;
4773 option (dccl.msg).max_bytes = 32;
4774+ option (dccl.msg).codec_version = 3;
4775
4776 optional bool bool_val = 1;
4777 }
4778@@ -21,6 +23,7 @@
4779 {
4780 option (dccl.msg).id = 6;
4781 option (dccl.msg).max_bytes = 32;
4782+ option (dccl.msg).codec_version = 3;
4783
4784 optional string string_val = 1 [(dccl.field).max_length=10];
4785 }
4786
4787=== modified file 'src/test/dccl_required_optional/test.proto'
4788--- src/test/dccl_required_optional/test.proto 2012-10-19 16:41:36 +0000
4789+++ src/test/dccl_required_optional/test.proto 2014-08-27 16:27:22 +0000
4790@@ -4,6 +4,7 @@
4791 {
4792 option (dccl.msg).id = 10;
4793 option (dccl.msg).max_bytes = 32;
4794+ option (dccl.msg).codec_version = 3;
4795
4796 required bytes req_bytes = 1 [(dccl.field).max_length=8];
4797 optional bytes opt_bytes = 2 [(dccl.field).max_length=8];
4798
4799=== modified file 'src/test/dccl_static_methods/test.proto'
4800--- src/test/dccl_static_methods/test.proto 2012-10-23 00:46:12 +0000
4801+++ src/test/dccl_static_methods/test.proto 2014-08-27 16:27:22 +0000
4802@@ -5,6 +5,7 @@
4803 {
4804 option (dccl.msg).id = 4;
4805 option (dccl.msg).max_bytes = 32;
4806+ option (dccl.msg).codec_version = 3;
4807
4808 optional int32 int32_val = 1 [(dccl.field).min=0, (dccl.field).max=20];
4809 }
4810@@ -13,6 +14,7 @@
4811 {
4812 option (dccl.msg).id = 5;
4813 option (dccl.msg).max_bytes = 32;
4814+ option (dccl.msg).codec_version = 3;
4815
4816 optional bool bool_val = 1;
4817 }
4818@@ -21,6 +23,7 @@
4819 {
4820 option (dccl.msg).id = 6;
4821 option (dccl.msg).max_bytes = 32;
4822+ option (dccl.msg).codec_version = 3;
4823
4824 optional string string_val = 1 [(dccl.field).max_length=10];
4825 }
4826
4827=== added directory 'src/test/dccl_v2_all_fields'
4828=== added file 'src/test/dccl_v2_all_fields/CMakeLists.txt'
4829--- src/test/dccl_v2_all_fields/CMakeLists.txt 1970-01-01 00:00:00 +0000
4830+++ src/test/dccl_v2_all_fields/CMakeLists.txt 2014-08-27 16:27:22 +0000
4831@@ -0,0 +1,6 @@
4832+protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS test.proto)
4833+
4834+add_executable(dccl_test_v2_all_fields test.cpp ${PROTO_SRCS} ${PROTO_HDRS})
4835+target_link_libraries(dccl_test_v2_all_fields dccl)
4836+
4837+add_test(dccl_test_v2_all_fields ${dccl_BIN_DIR}/dccl_test_v2_all_fields)
4838
4839=== added file 'src/test/dccl_v2_all_fields/test.cpp'
4840--- src/test/dccl_v2_all_fields/test.cpp 1970-01-01 00:00:00 +0000
4841+++ src/test/dccl_v2_all_fields/test.cpp 2014-08-27 16:27:22 +0000
4842@@ -0,0 +1,175 @@
4843+// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes)
4844+// Massachusetts Institute of Technology (2007-)
4845+// Woods Hole Oceanographic Institution (2007-)
4846+// DCCL Developers Team (https://launchpad.net/~dccl-dev)
4847+//
4848+//
4849+// This file is part of the Dynamic Compact Control Language Library
4850+// ("DCCL").
4851+//
4852+// DCCL is free software: you can redistribute them and/or modify
4853+// them under the terms of the GNU Lesser General Public License as published by
4854+// the Free Software Foundation, either version 3 of the License, or
4855+// (at your option) any later version.
4856+//
4857+// DCCL is distributed in the hope that they will be useful,
4858+// but WITHOUT ANY WARRANTY; without even the implied warranty of
4859+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4860+// GNU Lesser General Public License for more details.
4861+//
4862+// You should have received a copy of the GNU Lesser General Public License
4863+// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
4864+
4865+
4866+// tests all protobuf types with _default codecs, repeat and non repeat
4867+
4868+#include <fstream>
4869+
4870+#include <google/protobuf/descriptor.pb.h>
4871+
4872+#include "dccl/codec.h"
4873+#include "test.pb.h"
4874+#include "dccl/binary.h"
4875+
4876+void decode_check(const std::string& encoded);
4877+dccl::Codec codec;
4878+TestMsg msg_in;
4879+
4880+int main(int argc, char* argv[])
4881+{
4882+ dccl::dlog.connect(dccl::logger::ALL, &std::cerr);
4883+
4884+ int i = 0;
4885+ msg_in.set_double_default_optional(++i + 0.1);
4886+ msg_in.set_float_default_optional(++i + 0.2);
4887+
4888+ msg_in.set_int32_default_optional(++i);
4889+ msg_in.set_int64_default_optional(-++i);
4890+ msg_in.set_uint32_default_optional(++i);
4891+ msg_in.set_uint64_default_optional(++i);
4892+ msg_in.set_sint32_default_optional(-++i);
4893+ msg_in.set_sint64_default_optional(++i);
4894+ msg_in.set_fixed32_default_optional(++i);
4895+ msg_in.set_fixed64_default_optional(++i);
4896+ msg_in.set_sfixed32_default_optional(++i);
4897+ msg_in.set_sfixed64_default_optional(-++i);
4898+
4899+ msg_in.set_bool_default_optional(true);
4900+
4901+ msg_in.set_string_default_optional("abc123");
4902+ msg_in.set_bytes_default_optional(dccl::hex_decode("00112233aabbcc1234"));
4903+
4904+ msg_in.set_enum_default_optional(ENUM_C);
4905+ msg_in.mutable_msg_default_optional()->set_val(++i + 0.3);
4906+ msg_in.mutable_msg_default_optional()->mutable_msg()->set_val(++i);
4907+
4908+ msg_in.set_double_default_required(++i + 0.1);
4909+ msg_in.set_float_default_required(++i + 0.2);
4910+
4911+ msg_in.set_int32_default_required(++i);
4912+ msg_in.set_int64_default_required(-++i);
4913+ msg_in.set_uint32_default_required(++i);
4914+ msg_in.set_uint64_default_required(++i);
4915+ msg_in.set_sint32_default_required(-++i);
4916+ msg_in.set_sint64_default_required(++i);
4917+ msg_in.set_fixed32_default_required(++i);
4918+ msg_in.set_fixed64_default_required(++i);
4919+ msg_in.set_sfixed32_default_required(++i);
4920+ msg_in.set_sfixed64_default_required(-++i);
4921+
4922+ msg_in.set_bool_default_required(true);
4923+
4924+ msg_in.set_string_default_required("abc123");
4925+ msg_in.set_bytes_default_required(dccl::hex_decode("00112233aabbcc1234"));
4926+
4927+ msg_in.set_enum_default_required(ENUM_C);
4928+ msg_in.mutable_msg_default_required()->set_val(++i + 0.3);
4929+ msg_in.mutable_msg_default_required()->mutable_msg()->set_val(++i);
4930+
4931+
4932+ for(int j = 0; j < 2; ++j)
4933+ {
4934+ msg_in.add_double_default_repeat(++i + 0.1);
4935+ msg_in.add_float_default_repeat(++i + 0.2);
4936+
4937+ msg_in.add_int32_default_repeat(++i);
4938+ msg_in.add_int64_default_repeat(-++i);
4939+ msg_in.add_uint32_default_repeat(++i);
4940+ msg_in.add_uint64_default_repeat(++i);
4941+ msg_in.add_sint32_default_repeat(-++i);
4942+ msg_in.add_sint64_default_repeat(++i);
4943+ msg_in.add_fixed32_default_repeat(++i);
4944+ msg_in.add_fixed64_default_repeat(++i);
4945+ msg_in.add_sfixed32_default_repeat(++i);
4946+ msg_in.add_sfixed64_default_repeat(-++i);
4947+
4948+ msg_in.add_bool_default_repeat(true);
4949+
4950+ msg_in.add_string_default_repeat("abc123");
4951+
4952+ if(j)
4953+ msg_in.add_bytes_default_repeat(dccl::hex_decode("00aabbcc"));
4954+ else
4955+ msg_in.add_bytes_default_repeat(dccl::hex_decode("ffeedd12"));
4956+
4957+ msg_in.add_enum_default_repeat(static_cast<Enum1>((++i % 3) + 1));
4958+ EmbeddedMsg1* em_msg = msg_in.add_msg_default_repeat();
4959+ em_msg->set_val(++i + 0.3);
4960+ em_msg->mutable_msg()->set_val(++i);
4961+ }
4962+
4963+ codec.info(msg_in.GetDescriptor());
4964+
4965+ std::ofstream fout("/tmp/testmessage.pb");
4966+ msg_in.SerializeToOstream(&fout);
4967+
4968+
4969+ std::cout << "Message in:\n" << msg_in.DebugString() << std::endl;
4970+
4971+ codec.load(msg_in.GetDescriptor());
4972+
4973+ std::cout << "Try encode..." << std::endl;
4974+ std::string bytes;
4975+ codec.encode(&bytes, msg_in);
4976+ std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl;
4977+
4978+ std::cout << "Try decode..." << std::endl;
4979+ decode_check(bytes);
4980+
4981+ // make sure DCCL defaults stay wire compatible
4982+ decode_check(dccl::hex_decode("047f277b9628060000b95660c0b0188000d8c0132858800008000dc2c4c6626466024488cca8ee324bd05c3f23af0000ad9112a09509788013e0820b18e0005ed0204c6c2c4666062042644675975982c65235f10a00ad718a5801000000905f27121600000000a0170050640300309201001a0b00007d320a0000a61a0070b20100a81b00d09c6f0000a0401026361643102636160300f0dfbd5b2280ea2e330f3da59a2100aabfa55a000000000000000000000000"));
4983+
4984+ // run a bunch of tests with random strings
4985+ std::string random = bytes;
4986+ for(unsigned i = 0; i < 10; ++i)
4987+ {
4988+ random[(rand() % (bytes.size()-1)+1)] = rand() % 256;
4989+ std::cout << "Using junk bytes: " << dccl::hex_encode(random) << std::endl;
4990+
4991+ try
4992+ {
4993+ TestMsg msg_out;
4994+ codec.decode(random, &msg_out);
4995+ }
4996+ catch(dccl::Exception&)
4997+ {
4998+ }
4999+ }
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches