Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #ifndef ctrlplane_proto_h
7 : #define ctrlplane_proto_h
8 :
9 : #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
10 : #define BOOST_MPL_LIMIT_MAP_SIZE 30
11 :
12 : #include <map>
13 : #include <memory>
14 :
15 : #include <vector>
16 :
17 : #include <boost/ptr_container/ptr_vector.hpp>
18 : #include <boost/function.hpp>
19 : #include <boost/type_traits/is_same.hpp>
20 : #include <boost/type_traits/is_base_of.hpp>
21 : #include <boost/mpl/equal_to.hpp>
22 : #include <boost/mpl/for_each.hpp>
23 : #include <boost/mpl/greater.hpp>
24 : #include <boost/mpl/list.hpp>
25 : #include <boost/mpl/map.hpp>
26 : #include <boost/mpl/or.hpp>
27 : #include <boost/mpl/vector.hpp>
28 : #include <boost/mpl/string.hpp>
29 :
30 : #include "base/compiler.h"
31 : #include "base/logging.h"
32 : #include "base/parse_object.h"
33 :
34 : namespace mpl = boost::mpl;
35 :
36 : class ParseContext {
37 : public:
38 :
39 : ParseContext();
40 : ~ParseContext();
41 :
42 : ParseObject *release();
43 :
44 : void Push(ParseObject *data);
45 : ParseObject *Pop();
46 :
47 : void SwapData(ParseObject *obj);
48 : void ReleaseData();
49 :
50 : ParseObject *data();
51 :
52 : void advance(int delta);
53 195410 : int offset() const { return offset_; }
54 :
55 : void set_lensize(int lensize);
56 : int lensize() const;
57 : void set_size(size_t length);
58 : size_t size() const;
59 : void set_total_size();
60 : size_t total_size() const;
61 :
62 : void SetError(int error, int subcode, std::string type, const uint8_t *data,
63 : int data_size);
64 139 : const ParseErrorContext &error_context() { return error_context_; }
65 : private:
66 :
67 : ParseErrorContext error_context_;
68 : struct StackFrame;
69 : int offset_;
70 : std::vector<StackFrame *> stack_;
71 : };
72 :
73 : class EncodeContext {
74 : public:
75 : typedef boost::function<void(EncodeContext *, uint8_t *, int, int)> CallbackType;
76 :
77 : EncodeContext();
78 : ~EncodeContext();
79 :
80 : void Push();
81 : void Pop(bool callback);
82 : void AddCallback(CallbackType cb, uint8_t *data, int arg);
83 :
84 : void advance(int delta);
85 : int length() const;
86 :
87 : void SaveOffset(std::string);
88 155459 : EncodeOffsets &encode_offsets() { return offsets_; }
89 : private:
90 : struct StackFrame;
91 : boost::ptr_vector<StackFrame> stack_;
92 : EncodeOffsets offsets_;
93 : };
94 :
95 : template <class C, typename T, T C::* Member>
96 : struct Accessor {
97 : typedef T C::* member_ptr_t;
98 2369158 : static void set(C *obj, T value) {
99 2369158 : obj->*Member = value;
100 2369158 : }
101 3025617 : static T get(const C *obj) {
102 3025617 : return obj->*Member;
103 : }
104 : };
105 :
106 : template <class C, std::string C::* Member>
107 : struct Accessor<C, std::string, Member> {
108 4928 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
109 4928 : obj->*Member = std::string((const char *) data, elem_size);
110 4928 : }
111 7582 : static int size(const C *obj) {
112 7582 : return (obj->*Member).size();
113 : }
114 7584 : static std::string::const_iterator begin(const C *obj) {
115 7584 : return (obj->*Member).begin();
116 : }
117 7583 : static std::string::const_iterator end(const C *obj) {
118 7583 : return (obj->*Member).end();
119 : }
120 : };
121 :
122 : template <class C, typename T, std::vector<T> C::* Member>
123 : struct VectorAccessor {
124 1547510 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
125 1547510 : obj->*Member = std::vector<T>();
126 1547599 : size_t size = sizeof(T);
127 13346422 : for (size_t i = 0; i < elem_size; i += size) {
128 11798826 : T value = get_value(data, size);
129 11798804 : data += size;
130 11798804 : (obj->*Member).push_back(value);
131 : }
132 1547596 : }
133 2134181 : static int size(const C *obj) {
134 2134181 : return (obj->*Member).size() * sizeof(T);
135 : }
136 2134046 : static typename std::vector<T>::const_iterator begin(const C *obj) {
137 2134046 : return (obj->*Member).begin();
138 : }
139 2134020 : static typename std::vector<T>::const_iterator end(const C *obj) {
140 2134020 : return (obj->*Member).end();
141 : }
142 : };
143 :
144 : // Extract the underlying type for pointer types.
145 : template <typename T>
146 : struct ValueType {
147 : typedef T type;
148 : };
149 : template <typename T>
150 : struct ValueType<T *> {
151 : typedef T type;
152 : };
153 :
154 : template <typename Obj, typename Col, Col Obj::* Member>
155 : struct CollectionAccessor {
156 : typedef typename ValueType<typename Col::value_type>::type ValueType;
157 : typedef Col CollectionType;
158 : typedef typename CollectionType::const_iterator iterator;
159 1792336 : static void insert(Obj *obj, ValueType *element) {
160 1792336 : (obj->*Member).push_back(element);
161 1792283 : }
162 960381 : static iterator begin(const Obj *obj) {
163 960381 : return (obj->*Member).begin();
164 : }
165 3292212 : static iterator end(const Obj *obj) {
166 3292212 : return (obj->*Member).end();
167 : }
168 : };
169 :
170 : // Interface
171 : struct ElementBase {
172 : static const int kSize = 0;
173 : static const int kErrorCode = 0;
174 : static const int kErrorSubcode = 0;
175 : struct NullCtxInit {
176 5747789 : void operator()(void *) {
177 5747789 : }
178 : };
179 : struct NoMatch {
180 : bool match(const void *) {
181 : return false;
182 : }
183 : };
184 6209407 : static bool Verifier(const void * obj, const uint8_t *data, size_t size,
185 : ParseContext *context) {
186 6209407 : return true;
187 : }
188 :
189 : typedef void SaveOffset; // Save the offset in encode context
190 : typedef void ContextType; // push a new context on the stack
191 : typedef NullCtxInit ContextInit; // initialize the context data
192 : typedef NoMatch ContextMatch;
193 : typedef void Setter;
194 : typedef void EncodingCallback;
195 : typedef void ContextSwap; // swap a context with another one
196 : typedef void SizeSetter; // set the size of the element
197 : };
198 :
199 : struct ChoiceBase : public ElementBase {
200 : typedef void ContextStorer; // store the context data on pop.
201 : };
202 :
203 : class SequenceBase : public ElementBase {
204 : public:
205 : static const int kMinOccurs = 1;
206 : static const int kMaxOccurs = 1;
207 : typedef void ContextStorer; // store the context data on pop.
208 : };
209 :
210 : #include "base/proto_impl.h"
211 :
212 : template<class Derived>
213 : class ProtoElement : public ElementBase {
214 : public:
215 : typedef void SequenceLength;
216 :
217 : template <typename T>
218 6944272 : static void Writer(T *msg, uint8_t *data, size_t size) {
219 : typedef typename Derived::Setter setter_t;
220 : typedef typename mpl::if_<
221 : mpl::equal_to<
222 : mpl::int_<Derived::kSize>, mpl::int_<-1> >,
223 : detail::VariableLengthWriter<typename Derived::Setter, T>,
224 : detail::ApplyGetter<setter_t>
225 : >::type writer_t;
226 : writer_t writer;
227 6944272 : writer(data, Derived::kSize, msg);
228 6944490 : }
229 :
230 : template <typename T>
231 5752385 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
232 : T *obj) {
233 : typedef typename mpl::if_<
234 : mpl::greater<
235 : mpl::int_<Derived::kSize>, mpl::int_<0> >,
236 : detail::SizeComparer<Derived>,
237 : detail::NopComparer
238 : >::type cmp_t;
239 :
240 : cmp_t cmp;
241 5752385 : if (!cmp(size)) {
242 8 : PROTO_DEBUG("Error: cmp(size) failed");
243 8 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
244 : TYPE_NAME(Derived), data,
245 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
246 8 : return -1;
247 : }
248 5752378 : if (!Derived::Verifier(obj, data, size, context)) {
249 4240 : PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
250 4240 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
251 : TYPE_NAME(Derived), data,
252 109 : Derived::kSize > 0 ? Derived::kSize : context->size());
253 4240 : return -1;
254 : }
255 :
256 : typedef typename Derived::ContextInit ctx_init_t;
257 : ctx_init_t initializer;
258 5748128 : initializer(obj);
259 :
260 : detail::SequenceLengthSetter<typename Derived::SequenceLength, T> slen;
261 5748122 : int res = slen(context, data, Derived::kSize, size, obj);
262 5748090 : if (res < 0) {
263 163 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: Length Setter failed");
264 163 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
265 : TYPE_NAME(Derived), data, context->lensize());
266 163 : return -1;
267 : }
268 :
269 : typedef typename mpl::if_<boost::is_same<typename Derived::SizeSetter, void>,
270 : typename mpl::if_<
271 : mpl::equal_to<mpl::int_<Derived::kSize>, mpl::int_<-1> >,
272 : detail::VariableLengthSetter<typename Derived::Setter, T>,
273 : typename mpl::if_<
274 : mpl::greater<mpl::int_<Derived::kSize>, mpl::int_<0> >,
275 : detail::FixedLengthSetter<Derived, T>,
276 : detail::NopSetter<Derived, T>
277 : >::type
278 : >::type,
279 : detail::LengthSizeSetter<typename Derived::SizeSetter, T>
280 : >::type setter_t;
281 :
282 : setter_t setter;
283 5747927 : res = setter(data, size, context, obj);
284 5748017 : if (res < 0) {
285 2 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
286 : TYPE_NAME(Derived), data,
287 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
288 : }
289 5748020 : return res;
290 : }
291 :
292 : template <typename T>
293 7281671 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
294 : size_t size) {
295 : typedef typename
296 : mpl::if_<boost::is_same<typename Derived::SizeSetter, void>,
297 : typename mpl::if_<mpl::equal_to<mpl::int_<Derived::kSize>, mpl::int_<-1> >,
298 : detail::VarLengthSizeValue<typename Derived::Setter, T>,
299 : detail::FixedLengthSizeValue<Derived> >::type,
300 : typename Derived::SizeSetter
301 : >::type size_value_t;
302 :
303 7281671 : int element_size = size_value_t::get(msg);
304 7281879 : if (data == NULL) {
305 8 : context->advance(element_size);
306 0 : return element_size;
307 : }
308 7281894 : assert(element_size >= 0);
309 7281894 : if (size < (size_t) element_size) {
310 175 : return -1;
311 : }
312 :
313 : // Setter overrides SequenceLength. Do not register a sequence length
314 : // callback if the element has defined a Setter.
315 : typename mpl::if_<
316 : boost::is_same<typename Derived::Setter, void>,
317 : detail::SequenceLengthAddCallback<typename Derived::SequenceLength>,
318 : detail::SequenceLengthAddCallback<void> >::type slen;
319 7281719 : slen(&ProtoElement::SequenceLengthWriteLen, context, data, element_size);
320 :
321 : detail::AddCallback<typename Derived::EncodingCallback> cbadd;
322 7281625 : cbadd(context, data, element_size);
323 :
324 7281647 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
325 :
326 7281741 : Derived::Writer(msg, data, size);
327 :
328 7281873 : context->advance(element_size);
329 7281491 : return element_size;
330 : }
331 :
332 : private:
333 1584885 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
334 : int offset, int element_size) {
335 1584885 : int length = context->length() - offset - element_size;
336 1584835 : put_value(data, element_size, length);
337 1584797 : }
338 : };
339 :
340 : template <typename Setter, typename T>
341 : struct ChoiceSetter {
342 790019 : void operator()(T *obj, int &value) {
343 790019 : Setter::set(obj, value);
344 790017 : }
345 : };
346 :
347 : template <typename T>
348 : struct ChoiceSetter<void, T> {
349 198862 : void operator()(T* obj, int value) { }
350 : };
351 :
352 : template <class Derived>
353 : class ProtoChoice : public ChoiceBase {
354 : public:
355 : template <typename T>
356 988876 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
357 : T *obj) {
358 988876 : int advance = Derived::kSize;
359 988876 : int value = -1;
360 :
361 988876 : if (size < (size_t) advance) {
362 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
363 : TYPE_NAME(Derived), data, advance);
364 0 : return -1;
365 : }
366 :
367 988876 : value = get_value(data, advance);
368 :
369 988873 : data += advance;
370 988873 : size -= advance;
371 988873 : context->advance(advance);
372 :
373 : typedef typename mpl::if_<
374 : boost::is_same<typename Derived::Setter, void>,
375 : ChoiceSetter<void, T>,
376 : ChoiceSetter<typename Derived::Setter, T>
377 : >::type choice_setter_t;
378 :
379 : choice_setter_t setter;
380 988882 : setter(obj, value);
381 :
382 988879 : int result = ParseChoice(data, size, value, context, obj);
383 988839 : if (result < 0) {
384 4188 : PROTO_DEBUG(TYPE_NAME(Derived) << " ParseChoice failed");
385 4188 : if (result == -2) {
386 45 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
387 45 : TYPE_NAME(Derived), data - advance, advance);
388 : }
389 4188 : return result;
390 : }
391 984651 : advance += result;
392 984651 : return advance;
393 : }
394 :
395 : template <typename T>
396 1070659 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
397 : size_t size) {
398 : typedef typename Derived::Choice choice_t;
399 1070659 : int result = 0;
400 1070659 : ChoiceEncoder<T> encoder(context, msg, data, size, &result);
401 1070835 : mpl::for_each<choice_t>(encoder);
402 1071090 : return result;
403 : }
404 :
405 : private:
406 : template <typename T>
407 : struct ChoiceMatcher {
408 988874 : ChoiceMatcher(const uint8_t *data, size_t size, int value,
409 : ParseContext *context, T *obj, int *resultp)
410 988874 : : data(data), size(size), value(value), context(context),
411 988874 : obj(obj), resultp(resultp), found(false) {
412 988874 : }
413 : template <typename U>
414 14630330 : void operator()(U x) {
415 14630330 : if (found) return;
416 5768867 : if (U::first::value != -1 && U::first::value != value) {
417 4782660 : return;
418 : }
419 988788 : found = true;
420 : typedef detail::DescendentParser<Derived, typename U::second>
421 : parser_t;
422 988788 : *resultp = parser_t::Parse(data, size, context, obj);
423 : }
424 : const uint8_t *data;
425 : size_t size;
426 : int value;
427 : ParseContext *context;
428 : T *obj;
429 : int *resultp;
430 : bool found;
431 : };
432 : template <typename T>
433 988877 : static int ParseChoice(const uint8_t *data, size_t size, int value,
434 : ParseContext *context, T *obj) {
435 988877 : int result = -2;
436 988877 : ChoiceMatcher<T> match(data, size, value, context, obj, &result);
437 988876 : mpl::for_each<typename Derived::Choice>(match);
438 988846 : return result;
439 : }
440 :
441 : template <typename T>
442 : struct ChoiceEncoder {
443 1070820 : ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
444 : int *resultp)
445 1070820 : : context(context), msg(msg), data(data), size(size),
446 1070820 : resultp(resultp), found(false) {
447 1070820 : }
448 : template <typename U, typename CtxType>
449 : struct EncoderTrue {
450 1071195 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
451 : uint8_t *data, int size) {
452 : if (Derived::kSize) {
453 898968 : if (data != NULL) {
454 898976 : if (size < Derived::kSize) return -1;
455 898976 : put_value(data, Derived::kSize, opt);
456 898995 : data += Derived::kSize;
457 898995 : size -= Derived::kSize;
458 : }
459 898987 : context->advance(Derived::kSize);
460 : }
461 1071121 : int result = U::Encode(context, msg, data, size);
462 1071247 : if (result >= 0) {
463 1070907 : result += Derived::kSize;
464 : }
465 1071247 : return result;
466 : }
467 : };
468 : template <typename U, typename CtxType>
469 : struct EncoderSetter {
470 733814 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
471 : uint8_t *data, int size) {
472 733814 : int value = Derived::Setter::get(msg);
473 733827 : if (value == opt || opt == -1) {
474 677121 : return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
475 : }
476 56706 : return 0;
477 : }
478 : };
479 : template <typename U>
480 : struct EncoderMatch {
481 251224 : int operator()(int opt, EncodeContext *context, const T *msg,
482 : uint8_t *data, int size) {
483 : typename U::ContextMatch matcher;
484 251224 : if (matcher.match(msg)) {
485 181729 : return EncoderTrue<U, T>()(opt, context, msg, data, size);
486 : }
487 69490 : return 0;
488 : }
489 : };
490 : template <typename U>
491 : struct EncoderRunTime {
492 6040821 : int operator()(int opt, EncodeContext *context, const T *msg,
493 : uint8_t *data, int size) {
494 6040821 : if (typeid(*msg) == typeid(typename U::ContextType)) {
495 : typedef typename U::ContextType ctx_t;
496 946024 : const ctx_t *ctx = static_cast<const ctx_t *>(msg);
497 :
498 : typedef typename mpl::if_<
499 : boost::is_same<typename Derived::Setter, void>,
500 : EncoderTrue<U, ctx_t>,
501 : EncoderSetter<U, ctx_t>
502 : >::type encoder;
503 946024 : return encoder()(opt, context, ctx, data, size);
504 : }
505 5094909 : return 0;
506 : }
507 : };
508 : struct EncoderNil {
509 : int operator()(int opt, EncodeContext *context, T *msg,
510 : uint8_t *data, int size) {
511 : return 0;
512 : }
513 : };
514 : template <typename U>
515 15764948 : void operator()(U x) {
516 15764948 : if (*resultp < 0 || found) {
517 9472747 : return;
518 : }
519 : // The choice element can be determined by:
520 : // 1. ContextType of the descendent or
521 : // 2. ContextMatch type of the descendent
522 : // In the case of ContextType match, the match can be either
523 : // performed at compile type (in case of exact match) or at run
524 : // type using RTTI.
525 : typedef typename mpl::if_<
526 : boost::is_same<typename U::second::ContextType, T>,
527 : EncoderTrue<typename U::second, T>,
528 : typename mpl::if_<
529 : boost::is_same<typename U::second::ContextType, void>,
530 : EncoderMatch<typename U::second>,
531 : typename mpl::if_<
532 : boost::is_base_of<T, typename U::second::ContextType>,
533 : EncoderRunTime<typename U::second>,
534 : EncoderNil
535 : >::type
536 : >::type
537 : >::type choice_t;
538 : choice_t choice;
539 6292232 : int result = choice(U::first::value, context, msg, data, size);
540 6292303 : if (result < 0) {
541 334 : *resultp = result;
542 6291969 : } else if (result > 0) {
543 1057942 : found = true;
544 1057942 : *resultp += result;
545 : }
546 : }
547 : private:
548 : EncodeContext *context;
549 : const T *msg;
550 : uint8_t *data;
551 : int size;
552 : int *resultp;
553 : bool found;
554 : };
555 : };
556 :
557 : template <class Derived>
558 : class ProtoSequence : public SequenceBase {
559 : public:
560 : template <typename T>
561 : struct SequenceParser {
562 3277131 : SequenceParser(const uint8_t *data, size_t size, ParseContext *context,
563 : T *obj, int *resultp)
564 3277131 : : data(data), size(size), context(context), obj(obj),
565 3277131 : resultp(resultp) {
566 3277131 : }
567 :
568 : template <typename U>
569 7881898 : void operator()(U x) {
570 7881898 : if (*resultp < 0) {
571 9007 : return;
572 : }
573 : typedef detail::DescendentParser<Derived, U> parser_t;
574 7872891 : size_t prev_size = context->size();
575 7872850 : int result = parser_t::Parse(data, size, context, obj);
576 7872874 : if (result < 0) {
577 12393 : *resultp = result;
578 12393 : return;
579 : }
580 :
581 7860481 : data += result;
582 7860481 : size -= result;
583 7860481 : context->advance(result);
584 7860496 : *resultp += result;
585 :
586 7860496 : if (context->size() != prev_size) {
587 2778389 : size = context->size();
588 2778437 : context->set_total_size();
589 : } else {
590 5082065 : context->set_size(prev_size - result);
591 : }
592 : }
593 :
594 : const uint8_t *data;
595 : size_t size;
596 : ParseContext *context;
597 : T *obj;
598 : int *resultp;
599 : };
600 :
601 : template <typename T>
602 2317023 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
603 : T *obj) {
604 2317023 : int min = Derived::kMinOccurs;
605 2317023 : if (min == 0 && size == 0) {
606 206557 : return 0;
607 : }
608 2110466 : if (!Derived::Verifier(obj, data, size, context)) {
609 48 : PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
610 48 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
611 : TYPE_NAME(Derived), data,
612 48 : Derived::kSize > 0 ? Derived::kSize : context->size());
613 48 : return -1;
614 : }
615 2110423 : int lensize = Derived::kSize;
616 2110423 : int length = size;
617 2110423 : if (lensize) {
618 361525 : if (size < (size_t) lensize) {
619 0 : PROTO_DEBUG("Error: size = " << size << " lensize = " << lensize);
620 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
621 : TYPE_NAME(Derived), data, lensize);
622 0 : return -1;
623 : }
624 : // TODO: options for length (include or exclude length field).
625 361525 : length = get_value(data, lensize);
626 361527 : assert(length >= 0);
627 361525 : size -= lensize;
628 361525 : if ((size_t) length > size) {
629 3036 : PROTO_DEBUG("Error: length = " << length << " size = " << size);
630 3036 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
631 : TYPE_NAME(Derived), data, lensize);
632 3036 : return -1;
633 : }
634 358489 : data += lensize;
635 358489 : context->advance(lensize);
636 : }
637 2107371 : int result = lensize;
638 2107371 : int max = Derived::kMaxOccurs;
639 5372025 : for (int i = 0; (max == -1 || i < max) && (length > 0); i++) {
640 3277087 : int sublen = 0;
641 : typedef typename Derived::ContextStorer ctx_access_t;
642 : typedef typename
643 : detail::ContextElementType<ctx_access_t>::ValueType child_obj_t;
644 : typedef typename mpl::if_<boost::is_same<typename Derived::ContextSwap, void>,
645 : detail::ContextPush<T, child_obj_t>,
646 : detail::NoContextPush<T>
647 : >::type ContextPush;
648 : ContextPush pushfn;
649 : typedef typename mpl::if_<boost::is_same<child_obj_t, void>,
650 : T, child_obj_t>::type ctx_t;
651 3277087 : ctx_t *child_obj = pushfn(context, obj);
652 :
653 3277131 : SequenceParser<ctx_t> parser(data, length, context, child_obj, &sublen);
654 3277138 : mpl::for_each<typename Derived::Sequence>(parser);
655 3277085 : if (sublen < 0) {
656 12393 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen);
657 12393 : return -1;
658 : }
659 3264692 : if (sublen < (int)(context->size() + context->lensize())) {
660 0 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen
661 : << " < " << context->size() << "+" << context->lensize());
662 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
663 : TYPE_NAME(Derived), data,
664 0 : context->size()+context->lensize());
665 0 : return -1;
666 : }
667 3264707 : result += sublen;
668 3264707 : data += sublen;
669 3264707 : length -= sublen;
670 :
671 : typedef typename mpl::if_<boost::is_same<typename Derived::ContextSwap, void>,
672 : detail::ContextPop<Derived, T, child_obj_t>,
673 : detail::ContextPop<Derived, void, void>
674 : >::type ContextPop;
675 : ContextPop popfn;
676 3264707 : popfn(context, obj);
677 : }
678 2094938 : return result;
679 : }
680 :
681 : template <typename T>
682 : struct SingleEncoder {
683 : typedef typename Derived::Sequence sequence_t;
684 1773443 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
685 : size_t size) {
686 1773443 : int result = 0;
687 1773443 : SequenceEncoder<T> encoder(context, msg, data, size, &result);
688 1773470 : mpl::for_each<sequence_t>(encoder);
689 1773507 : return result;
690 : }
691 : };
692 :
693 : template <typename T>
694 : struct ListEncoder {
695 : typedef typename Derived::Sequence sequence_t;
696 960425 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
697 : size_t size) {
698 : typedef typename Derived::ContextStorer ctx_access_t;
699 : typedef typename
700 : detail::ContextElementType<ctx_access_t>::ValueType child_obj_t;
701 960425 : int result = 0;
702 :
703 960425 : detail::ContextIterator<ctx_access_t> iter(msg);
704 3292318 : while (iter.HasNext(msg)) {
705 2332058 : child_obj_t *child_obj = iter.Next();
706 2332042 : int subres = 0;
707 2332042 : context->Push();
708 2332046 : SequenceEncoder<child_obj_t> encoder(context, child_obj,
709 : data, size, &subres);
710 2332041 : mpl::for_each<sequence_t>(encoder);
711 2332163 : if (subres < 0) {
712 223 : result = subres;
713 223 : break;
714 : }
715 2331940 : result += subres;
716 2331940 : if (data != NULL) {
717 2331959 : data += subres;
718 2331959 : size -= subres;
719 : }
720 2331940 : context->Pop(data != NULL);
721 : }
722 960382 : return result;
723 : }
724 : };
725 :
726 : template <typename T>
727 2733754 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
728 : size_t size) {
729 2733754 : context->Push();
730 2733956 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
731 : if (Derived::kSize > 0) {
732 : // context push callback
733 395821 : if (data != NULL) {
734 395821 : context->AddCallback(&SequenceLengthWriteLen, data, Derived::kSize);
735 395741 : data += Derived::kSize;
736 395741 : size -= Derived::kSize;
737 : }
738 395741 : context->advance(Derived::kSize);
739 : }
740 : typedef typename mpl::if_<
741 : mpl::or_<
742 : mpl::equal_to<mpl::int_<Derived::kMaxOccurs>,
743 : mpl::int_<-1> >,
744 : mpl::greater<mpl::int_<Derived::kMaxOccurs>,
745 : mpl::int_<1> >
746 : >,
747 : ListEncoder<T>,
748 : SingleEncoder<T> >::type encoder_t;
749 : encoder_t encoder;
750 2733973 : int result = encoder(context, msg, data, size);
751 2734012 : if (result >= 0) {
752 2733328 : result += Derived::kSize;
753 2733328 : context->Pop(data != NULL);
754 : }
755 2734110 : return result;
756 : }
757 :
758 : private:
759 : template <typename T>
760 : struct SequenceEncoder {
761 4105471 : SequenceEncoder(EncodeContext *context, const T *msg, uint8_t *data,
762 : size_t size, int *resultp)
763 4105471 : : context(context), msg(msg), data(data), size(size),
764 4105471 : resultp(resultp) {
765 4105471 : }
766 : template <typename U>
767 9739685 : void operator()(U element) {
768 9739685 : if (*resultp < 0) {
769 241 : return;
770 : }
771 9739444 : int res = U::Encode(context, msg, data, size);
772 9739751 : if (res < 0) {
773 734 : *resultp = res;
774 : } else {
775 9739017 : *resultp += res;
776 : }
777 9739751 : if (data != NULL) {
778 9739781 : data += res;
779 9739781 : size -= res;
780 : }
781 : }
782 :
783 : private:
784 : EncodeContext *context;
785 : const T *msg;
786 : uint8_t *data;
787 : size_t size;
788 : int *resultp;
789 : };
790 :
791 395617 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
792 : int offset, int arg) {
793 395617 : int length = context->length() - Derived::kSize;
794 395609 : put_value(data, Derived::kSize, length);
795 395607 : }
796 : };
797 :
798 : #endif
|