Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #ifndef ctrlplane_proto_h
6 : #define ctrlplane_proto_h
7 :
8 : #define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
9 : #define BOOST_MPL_LIMIT_MAP_SIZE 30
10 :
11 : #include <map>
12 : #include <memory>
13 :
14 : #include <vector>
15 :
16 : #include <boost/ptr_container/ptr_vector.hpp>
17 : #include <boost/function.hpp>
18 : #include <boost/type_traits/is_same.hpp>
19 : #include <boost/type_traits/is_base_of.hpp>
20 : #include <boost/mpl/equal_to.hpp>
21 : #include <boost/mpl/for_each.hpp>
22 : #include <boost/mpl/greater.hpp>
23 : #include <boost/mpl/list.hpp>
24 : #include <boost/mpl/map.hpp>
25 : #include <boost/mpl/or.hpp>
26 : #include <boost/mpl/vector.hpp>
27 : #include <boost/mpl/string.hpp>
28 :
29 : #include "base/compiler.h"
30 : #include "base/logging.h"
31 : #include "base/parse_object.h"
32 :
33 : namespace mpl = boost::mpl;
34 :
35 : class ParseContext {
36 : public:
37 :
38 : ParseContext();
39 : ~ParseContext();
40 :
41 : ParseObject *release();
42 :
43 : void Push(ParseObject *data);
44 : ParseObject *Pop();
45 :
46 : void SwapData(ParseObject *obj);
47 : void ReleaseData();
48 :
49 : ParseObject *data();
50 :
51 : void advance(int delta);
52 194713 : int offset() const { return offset_; }
53 :
54 : void set_lensize(int lensize);
55 : int lensize() const;
56 : void set_size(size_t length);
57 : size_t size() const;
58 : void set_total_size();
59 : size_t total_size() const;
60 :
61 : void SetError(int error, int subcode, std::string type, const uint8_t *data,
62 : int data_size);
63 139 : const ParseErrorContext &error_context() { return error_context_; }
64 : private:
65 :
66 : ParseErrorContext error_context_;
67 : struct StackFrame;
68 : int offset_;
69 : std::vector<StackFrame *> stack_;
70 : };
71 :
72 : class EncodeContext {
73 : public:
74 : typedef boost::function<void(EncodeContext *, uint8_t *, int, int)> CallbackType;
75 :
76 : EncodeContext();
77 : ~EncodeContext();
78 :
79 : void Push();
80 : void Pop(bool callback);
81 : void AddCallback(CallbackType cb, uint8_t *data, int arg);
82 :
83 : void advance(int delta);
84 : int length() const;
85 :
86 : void SaveOffset(std::string);
87 154194 : EncodeOffsets &encode_offsets() { return offsets_; }
88 : private:
89 : struct StackFrame;
90 : boost::ptr_vector<StackFrame> stack_;
91 : EncodeOffsets offsets_;
92 : };
93 :
94 : template <class C, typename T, T C::* Member>
95 : struct Accessor {
96 : typedef T C::* member_ptr_t;
97 2363810 : static void set(C *obj, T value) {
98 2363810 : obj->*Member = value;
99 2363810 : }
100 3017154 : static T get(const C *obj) {
101 3017154 : return obj->*Member;
102 : }
103 : };
104 :
105 : template <class C, std::string C::* Member>
106 : struct Accessor<C, std::string, Member> {
107 5042 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
108 5042 : obj->*Member = std::string((const char *) data, elem_size);
109 5042 : }
110 7715 : static int size(const C *obj) {
111 7715 : return (obj->*Member).size();
112 : }
113 7718 : static std::string::const_iterator begin(const C *obj) {
114 7718 : return (obj->*Member).begin();
115 : }
116 7717 : static std::string::const_iterator end(const C *obj) {
117 7717 : return (obj->*Member).end();
118 : }
119 : };
120 :
121 : template <class C, typename T, std::vector<T> C::* Member>
122 : struct VectorAccessor {
123 1545801 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
124 1545801 : obj->*Member = std::vector<T>();
125 1545815 : size_t size = sizeof(T);
126 13325493 : for (size_t i = 0; i < elem_size; i += size) {
127 11779661 : T value = get_value(data, size);
128 11779652 : data += size;
129 11779652 : (obj->*Member).push_back(value);
130 : }
131 1545832 : }
132 2131907 : static int size(const C *obj) {
133 2131907 : return (obj->*Member).size() * sizeof(T);
134 : }
135 2131780 : static typename std::vector<T>::const_iterator begin(const C *obj) {
136 2131780 : return (obj->*Member).begin();
137 : }
138 2131769 : static typename std::vector<T>::const_iterator end(const C *obj) {
139 2131769 : return (obj->*Member).end();
140 : }
141 : };
142 :
143 : // Extract the underlying type for pointer types.
144 : template <typename T>
145 : struct ValueType {
146 : typedef T type;
147 : };
148 : template <typename T>
149 : struct ValueType<T *> {
150 : typedef T type;
151 : };
152 :
153 : template <typename Obj, typename Col, Col Obj::* Member>
154 : struct CollectionAccessor {
155 : typedef typename ValueType<typename Col::value_type>::type ValueType;
156 : typedef Col CollectionType;
157 : typedef typename CollectionType::const_iterator iterator;
158 1789020 : static void insert(Obj *obj, ValueType *element) {
159 1789020 : (obj->*Member).push_back(element);
160 1789012 : }
161 954051 : static iterator begin(const Obj *obj) {
162 954051 : return (obj->*Member).begin();
163 : }
164 3281416 : static iterator end(const Obj *obj) {
165 3281416 : return (obj->*Member).end();
166 : }
167 : };
168 :
169 : // Interface
170 : struct ElementBase {
171 : static const int kSize = 0;
172 : static const int kErrorCode = 0;
173 : static const int kErrorSubcode = 0;
174 : struct NullCtxInit {
175 5735546 : void operator()(void *) {
176 5735546 : }
177 : };
178 : struct NoMatch {
179 : bool match(const void *) {
180 : return false;
181 : }
182 : };
183 6195341 : static bool Verifier(const void * obj, const uint8_t *data, size_t size,
184 : ParseContext *context) {
185 6195341 : return true;
186 : }
187 :
188 : typedef void SaveOffset; // Save the offset in encode context
189 : typedef void ContextType; // push a new context on the stack
190 : typedef NullCtxInit ContextInit; // initialize the context data
191 : typedef NoMatch ContextMatch;
192 : typedef void Setter;
193 : typedef void EncodingCallback;
194 : typedef void ContextSwap; // swap a context with another one
195 : typedef void SizeSetter; // set the size of the element
196 : };
197 :
198 : struct ChoiceBase : public ElementBase {
199 : typedef void ContextStorer; // store the context data on pop.
200 : };
201 :
202 : class SequenceBase : public ElementBase {
203 : public:
204 : static const int kMinOccurs = 1;
205 : static const int kMaxOccurs = 1;
206 : typedef void ContextStorer; // store the context data on pop.
207 : };
208 :
209 : #include "base/proto_impl.h"
210 :
211 : template<class Derived>
212 : class ProtoElement : public ElementBase {
213 : public:
214 : typedef void SequenceLength;
215 :
216 : template <typename T>
217 6930336 : static void Writer(T *msg, uint8_t *data, size_t size) {
218 : typedef typename Derived::Setter setter_t;
219 : typedef typename mpl::if_<
220 : mpl::equal_to<
221 : mpl::int_<Derived::kSize>, mpl::int_<-1> >,
222 : detail::VariableLengthWriter<typename Derived::Setter, T>,
223 : detail::ApplyGetter<setter_t>
224 : >::type writer_t;
225 : writer_t writer;
226 6930336 : writer(data, Derived::kSize, msg);
227 6930528 : }
228 :
229 : template <typename T>
230 5740156 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
231 : T *obj) {
232 : typedef typename mpl::if_<
233 : mpl::greater<
234 : mpl::int_<Derived::kSize>, mpl::int_<0> >,
235 : detail::SizeComparer<Derived>,
236 : detail::NopComparer
237 : >::type cmp_t;
238 :
239 : cmp_t cmp;
240 5740156 : if (!cmp(size)) {
241 8 : PROTO_DEBUG("Error: cmp(size) failed");
242 8 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
243 : TYPE_NAME(Derived), data,
244 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
245 8 : return -1;
246 : }
247 5740143 : if (!Derived::Verifier(obj, data, size, context)) {
248 4240 : PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
249 4240 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
250 : TYPE_NAME(Derived), data,
251 109 : Derived::kSize > 0 ? Derived::kSize : context->size());
252 4240 : return -1;
253 : }
254 :
255 : typedef typename Derived::ContextInit ctx_init_t;
256 : ctx_init_t initializer;
257 5735900 : initializer(obj);
258 :
259 : detail::SequenceLengthSetter<typename Derived::SequenceLength, T> slen;
260 5735890 : int res = slen(context, data, Derived::kSize, size, obj);
261 5735888 : if (res < 0) {
262 163 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: Length Setter failed");
263 163 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
264 : TYPE_NAME(Derived), data, context->lensize());
265 163 : return -1;
266 : }
267 :
268 : typedef typename mpl::if_<boost::is_same<typename Derived::SizeSetter, void>,
269 : typename mpl::if_<
270 : mpl::equal_to<mpl::int_<Derived::kSize>, mpl::int_<-1> >,
271 : detail::VariableLengthSetter<typename Derived::Setter, T>,
272 : typename mpl::if_<
273 : mpl::greater<mpl::int_<Derived::kSize>, mpl::int_<0> >,
274 : detail::FixedLengthSetter<Derived, T>,
275 : detail::NopSetter<Derived, T>
276 : >::type
277 : >::type,
278 : detail::LengthSizeSetter<typename Derived::SizeSetter, T>
279 : >::type setter_t;
280 :
281 : setter_t setter;
282 5735725 : res = setter(data, size, context, obj);
283 5735762 : if (res < 0) {
284 1 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
285 : TYPE_NAME(Derived), data,
286 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
287 : }
288 5735761 : return res;
289 : }
290 :
291 : template <typename T>
292 7266409 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
293 : size_t size) {
294 : typedef typename
295 : mpl::if_<boost::is_same<typename Derived::SizeSetter, void>,
296 : typename mpl::if_<mpl::equal_to<mpl::int_<Derived::kSize>, mpl::int_<-1> >,
297 : detail::VarLengthSizeValue<typename Derived::Setter, T>,
298 : detail::FixedLengthSizeValue<Derived> >::type,
299 : typename Derived::SizeSetter
300 : >::type size_value_t;
301 :
302 7266409 : int element_size = size_value_t::get(msg);
303 7266438 : if (data == NULL) {
304 3 : context->advance(element_size);
305 0 : return element_size;
306 : }
307 7266440 : assert(element_size >= 0);
308 7266440 : if (size < (size_t) element_size) {
309 175 : return -1;
310 : }
311 :
312 : // Setter overrides SequenceLength. Do not register a sequence length
313 : // callback if the element has defined a Setter.
314 : typename mpl::if_<
315 : boost::is_same<typename Derived::Setter, void>,
316 : detail::SequenceLengthAddCallback<typename Derived::SequenceLength>,
317 : detail::SequenceLengthAddCallback<void> >::type slen;
318 7266265 : slen(&ProtoElement::SequenceLengthWriteLen, context, data, element_size);
319 :
320 : detail::AddCallback<typename Derived::EncodingCallback> cbadd;
321 7266159 : cbadd(context, data, element_size);
322 :
323 7266153 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
324 :
325 7266228 : Derived::Writer(msg, data, size);
326 :
327 7266374 : context->advance(element_size);
328 7266012 : return element_size;
329 : }
330 :
331 : private:
332 1581943 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
333 : int offset, int element_size) {
334 1581943 : int length = context->length() - offset - element_size;
335 1581877 : put_value(data, element_size, length);
336 1581876 : }
337 : };
338 :
339 : template <typename Setter, typename T>
340 : struct ChoiceSetter {
341 787033 : void operator()(T *obj, int &value) {
342 787033 : Setter::set(obj, value);
343 787032 : }
344 : };
345 :
346 : template <typename T>
347 : struct ChoiceSetter<void, T> {
348 198038 : void operator()(T* obj, int value) { }
349 : };
350 :
351 : template <class Derived>
352 : class ProtoChoice : public ChoiceBase {
353 : public:
354 : template <typename T>
355 985076 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
356 : T *obj) {
357 985076 : int advance = Derived::kSize;
358 985076 : int value = -1;
359 :
360 985076 : if (size < (size_t) advance) {
361 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
362 : TYPE_NAME(Derived), data, advance);
363 0 : return -1;
364 : }
365 :
366 985076 : value = get_value(data, advance);
367 :
368 985075 : data += advance;
369 985075 : size -= advance;
370 985075 : context->advance(advance);
371 :
372 : typedef typename mpl::if_<
373 : boost::is_same<typename Derived::Setter, void>,
374 : ChoiceSetter<void, T>,
375 : ChoiceSetter<typename Derived::Setter, T>
376 : >::type choice_setter_t;
377 :
378 : choice_setter_t setter;
379 985070 : setter(obj, value);
380 :
381 985071 : int result = ParseChoice(data, size, value, context, obj);
382 985070 : if (result < 0) {
383 4188 : PROTO_DEBUG(TYPE_NAME(Derived) << " ParseChoice failed");
384 4188 : if (result == -2) {
385 45 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
386 45 : TYPE_NAME(Derived), data - advance, advance);
387 : }
388 4188 : return result;
389 : }
390 980882 : advance += result;
391 980882 : return advance;
392 : }
393 :
394 : template <typename T>
395 1065076 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
396 : size_t size) {
397 : typedef typename Derived::Choice choice_t;
398 1065076 : int result = 0;
399 1065076 : ChoiceEncoder<T> encoder(context, msg, data, size, &result);
400 1065145 : mpl::for_each<choice_t>(encoder);
401 1065445 : return result;
402 : }
403 :
404 : private:
405 : template <typename T>
406 : struct ChoiceMatcher {
407 985068 : ChoiceMatcher(const uint8_t *data, size_t size, int value,
408 : ParseContext *context, T *obj, int *resultp)
409 985068 : : data(data), size(size), value(value), context(context),
410 985068 : obj(obj), resultp(resultp), found(false) {
411 985068 : }
412 : template <typename U>
413 14575433 : void operator()(U x) {
414 14575433 : if (found) return;
415 5745455 : if (U::first::value != -1 && U::first::value != value) {
416 4763077 : return;
417 : }
418 984965 : found = true;
419 : typedef detail::DescendentParser<Derived, typename U::second>
420 : parser_t;
421 984965 : *resultp = parser_t::Parse(data, size, context, obj);
422 : }
423 : const uint8_t *data;
424 : size_t size;
425 : int value;
426 : ParseContext *context;
427 : T *obj;
428 : int *resultp;
429 : bool found;
430 : };
431 : template <typename T>
432 985070 : static int ParseChoice(const uint8_t *data, size_t size, int value,
433 : ParseContext *context, T *obj) {
434 985070 : int result = -2;
435 985070 : ChoiceMatcher<T> match(data, size, value, context, obj, &result);
436 985076 : mpl::for_each<typename Derived::Choice>(match);
437 985065 : return result;
438 : }
439 :
440 : template <typename T>
441 : struct ChoiceEncoder {
442 1065128 : ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
443 : int *resultp)
444 1065128 : : context(context), msg(msg), data(data), size(size),
445 1065128 : resultp(resultp), found(false) {
446 1065128 : }
447 : template <typename U, typename CtxType>
448 : struct EncoderTrue {
449 1065511 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
450 : uint8_t *data, int size) {
451 : if (Derived::kSize) {
452 894612 : if (data != NULL) {
453 894625 : if (size < Derived::kSize) return -1;
454 894625 : put_value(data, Derived::kSize, opt);
455 894626 : data += Derived::kSize;
456 894626 : size -= Derived::kSize;
457 : }
458 894613 : context->advance(Derived::kSize);
459 : }
460 1065423 : int result = U::Encode(context, msg, data, size);
461 1065533 : if (result >= 0) {
462 1065197 : result += Derived::kSize;
463 : }
464 1065533 : return result;
465 : }
466 : };
467 : template <typename U, typename CtxType>
468 : struct EncoderSetter {
469 729623 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
470 : uint8_t *data, int size) {
471 729623 : int value = Derived::Setter::get(msg);
472 729621 : if (value == opt || opt == -1) {
473 673845 : return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
474 : }
475 55776 : return 0;
476 : }
477 : };
478 : template <typename U>
479 : struct EncoderMatch {
480 249515 : int operator()(int opt, EncodeContext *context, const T *msg,
481 : uint8_t *data, int size) {
482 : typename U::ContextMatch matcher;
483 249515 : if (matcher.match(msg)) {
484 180484 : return EncoderTrue<U, T>()(opt, context, msg, data, size);
485 : }
486 69026 : return 0;
487 : }
488 : };
489 : template <typename U>
490 : struct EncoderRunTime {
491 6004682 : int operator()(int opt, EncodeContext *context, const T *msg,
492 : uint8_t *data, int size) {
493 6004682 : if (typeid(*msg) == typeid(typename U::ContextType)) {
494 : typedef typename U::ContextType ctx_t;
495 940610 : const ctx_t *ctx = static_cast<const ctx_t *>(msg);
496 :
497 : typedef typename mpl::if_<
498 : boost::is_same<typename Derived::Setter, void>,
499 : EncoderTrue<U, ctx_t>,
500 : EncoderSetter<U, ctx_t>
501 : >::type encoder;
502 940610 : return encoder()(opt, context, ctx, data, size);
503 : }
504 5064132 : return 0;
505 : }
506 : };
507 : struct EncoderNil {
508 : int operator()(int opt, EncodeContext *context, T *msg,
509 : uint8_t *data, int size) {
510 : return 0;
511 : }
512 : };
513 : template <typename U>
514 15686401 : void operator()(U x) {
515 15686401 : if (*resultp < 0 || found) {
516 9432118 : return;
517 : }
518 : // The choice element can be determined by:
519 : // 1. ContextType of the descendent or
520 : // 2. ContextMatch type of the descendent
521 : // In the case of ContextType match, the match can be either
522 : // performed at compile type (in case of exact match) or at run
523 : // type using RTTI.
524 : typedef typename mpl::if_<
525 : boost::is_same<typename U::second::ContextType, T>,
526 : EncoderTrue<typename U::second, T>,
527 : typename mpl::if_<
528 : boost::is_same<typename U::second::ContextType, void>,
529 : EncoderMatch<typename U::second>,
530 : typename mpl::if_<
531 : boost::is_base_of<T, typename U::second::ContextType>,
532 : EncoderRunTime<typename U::second>,
533 : EncoderNil
534 : >::type
535 : >::type
536 : >::type choice_t;
537 : choice_t choice;
538 6254290 : int result = choice(U::first::value, context, msg, data, size);
539 6254432 : if (result < 0) {
540 334 : *resultp = result;
541 6254098 : } else if (result > 0) {
542 1052300 : found = true;
543 1052300 : *resultp += result;
544 : }
545 : }
546 : private:
547 : EncodeContext *context;
548 : const T *msg;
549 : uint8_t *data;
550 : int size;
551 : int *resultp;
552 : bool found;
553 : };
554 : };
555 :
556 : template <class Derived>
557 : class ProtoSequence : public SequenceBase {
558 : public:
559 : template <typename T>
560 : struct SequenceParser {
561 3269279 : SequenceParser(const uint8_t *data, size_t size, ParseContext *context,
562 : T *obj, int *resultp)
563 3269279 : : data(data), size(size), context(context), obj(obj),
564 3269279 : resultp(resultp) {
565 3269279 : }
566 :
567 : template <typename U>
568 7862690 : void operator()(U x) {
569 7862690 : if (*resultp < 0) {
570 9007 : return;
571 : }
572 : typedef detail::DescendentParser<Derived, U> parser_t;
573 7853683 : size_t prev_size = context->size();
574 7853623 : int result = parser_t::Parse(data, size, context, obj);
575 7853654 : if (result < 0) {
576 12393 : *resultp = result;
577 12393 : return;
578 : }
579 :
580 7841261 : data += result;
581 7841261 : size -= result;
582 7841261 : context->advance(result);
583 7841242 : *resultp += result;
584 :
585 7841242 : if (context->size() != prev_size) {
586 2772527 : size = context->size();
587 2772580 : context->set_total_size();
588 : } else {
589 5068663 : context->set_size(prev_size - result);
590 : }
591 : }
592 :
593 : const uint8_t *data;
594 : size_t size;
595 : ParseContext *context;
596 : T *obj;
597 : int *resultp;
598 : };
599 :
600 : template <typename T>
601 2309360 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
602 : T *obj) {
603 2309360 : int min = Derived::kMinOccurs;
604 2309360 : if (min == 0 && size == 0) {
605 205671 : return 0;
606 : }
607 2103689 : if (!Derived::Verifier(obj, data, size, context)) {
608 48 : PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
609 48 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
610 : TYPE_NAME(Derived), data,
611 48 : Derived::kSize > 0 ? Derived::kSize : context->size());
612 48 : return -1;
613 : }
614 2103644 : int lensize = Derived::kSize;
615 2103644 : int length = size;
616 2103644 : if (lensize) {
617 360016 : if (size < (size_t) lensize) {
618 0 : PROTO_DEBUG("Error: size = " << size << " lensize = " << lensize);
619 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
620 : TYPE_NAME(Derived), data, lensize);
621 0 : return -1;
622 : }
623 : // TODO: options for length (include or exclude length field).
624 360016 : length = get_value(data, lensize);
625 360015 : assert(length >= 0);
626 360018 : size -= lensize;
627 360018 : if ((size_t) length > size) {
628 3036 : PROTO_DEBUG("Error: length = " << length << " size = " << size);
629 3036 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
630 : TYPE_NAME(Derived), data, lensize);
631 3036 : return -1;
632 : }
633 356982 : data += lensize;
634 356982 : context->advance(lensize);
635 : }
636 2100614 : int result = lensize;
637 2100614 : int max = Derived::kMaxOccurs;
638 5357487 : for (int i = 0; (max == -1 || i < max) && (length > 0); i++) {
639 3269300 : int sublen = 0;
640 : typedef typename Derived::ContextStorer ctx_access_t;
641 : typedef typename
642 : detail::ContextElementType<ctx_access_t>::ValueType child_obj_t;
643 : typedef typename mpl::if_<boost::is_same<typename Derived::ContextSwap, void>,
644 : detail::ContextPush<T, child_obj_t>,
645 : detail::NoContextPush<T>
646 : >::type ContextPush;
647 : ContextPush pushfn;
648 : typedef typename mpl::if_<boost::is_same<child_obj_t, void>,
649 : T, child_obj_t>::type ctx_t;
650 3269300 : ctx_t *child_obj = pushfn(context, obj);
651 :
652 3269283 : SequenceParser<ctx_t> parser(data, length, context, child_obj, &sublen);
653 3269280 : mpl::for_each<typename Derived::Sequence>(parser);
654 3269253 : if (sublen < 0) {
655 12393 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen);
656 12393 : return -1;
657 : }
658 3256860 : if (sublen < (int)(context->size() + context->lensize())) {
659 0 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen
660 : << " < " << context->size() << "+" << context->lensize());
661 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
662 : TYPE_NAME(Derived), data,
663 0 : context->size()+context->lensize());
664 0 : return -1;
665 : }
666 3256864 : result += sublen;
667 3256864 : data += sublen;
668 3256864 : length -= sublen;
669 :
670 : typedef typename mpl::if_<boost::is_same<typename Derived::ContextSwap, void>,
671 : detail::ContextPop<Derived, T, child_obj_t>,
672 : detail::ContextPop<Derived, void, void>
673 : >::type ContextPop;
674 : ContextPop popfn;
675 3256864 : popfn(context, obj);
676 : }
677 2088187 : return result;
678 : }
679 :
680 : template <typename T>
681 : struct SingleEncoder {
682 : typedef typename Derived::Sequence sequence_t;
683 1768316 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
684 : size_t size) {
685 1768316 : int result = 0;
686 1768316 : SequenceEncoder<T> encoder(context, msg, data, size, &result);
687 1768348 : mpl::for_each<sequence_t>(encoder);
688 1768454 : return result;
689 : }
690 : };
691 :
692 : template <typename T>
693 : struct ListEncoder {
694 : typedef typename Derived::Sequence sequence_t;
695 954065 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
696 : size_t size) {
697 : typedef typename Derived::ContextStorer ctx_access_t;
698 : typedef typename
699 : detail::ContextElementType<ctx_access_t>::ValueType child_obj_t;
700 954065 : int result = 0;
701 :
702 954065 : detail::ContextIterator<ctx_access_t> iter(msg);
703 3281527 : while (iter.HasNext(msg)) {
704 2327626 : child_obj_t *child_obj = iter.Next();
705 2327614 : int subres = 0;
706 2327614 : context->Push();
707 2327608 : SequenceEncoder<child_obj_t> encoder(context, child_obj,
708 : data, size, &subres);
709 2327607 : mpl::for_each<sequence_t>(encoder);
710 2327755 : if (subres < 0) {
711 223 : result = subres;
712 223 : break;
713 : }
714 2327532 : result += subres;
715 2327532 : if (data != NULL) {
716 2327542 : data += subres;
717 2327542 : size -= subres;
718 : }
719 2327532 : context->Pop(data != NULL);
720 : }
721 954016 : return result;
722 : }
723 : };
724 :
725 : template <typename T>
726 2722395 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
727 : size_t size) {
728 2722395 : context->Push();
729 2722388 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
730 : if (Derived::kSize > 0) {
731 : // context push callback
732 393311 : if (data != NULL) {
733 393310 : context->AddCallback(&SequenceLengthWriteLen, data, Derived::kSize);
734 393212 : data += Derived::kSize;
735 393212 : size -= Derived::kSize;
736 : }
737 393213 : context->advance(Derived::kSize);
738 : }
739 : typedef typename mpl::if_<
740 : mpl::or_<
741 : mpl::equal_to<mpl::int_<Derived::kMaxOccurs>,
742 : mpl::int_<-1> >,
743 : mpl::greater<mpl::int_<Derived::kMaxOccurs>,
744 : mpl::int_<1> >
745 : >,
746 : ListEncoder<T>,
747 : SingleEncoder<T> >::type encoder_t;
748 : encoder_t encoder;
749 2722412 : int result = encoder(context, msg, data, size);
750 2722631 : if (result >= 0) {
751 2721912 : result += Derived::kSize;
752 2721912 : context->Pop(data != NULL);
753 : }
754 2722617 : return result;
755 : }
756 :
757 : private:
758 : template <typename T>
759 : struct SequenceEncoder {
760 4095911 : SequenceEncoder(EncodeContext *context, const T *msg, uint8_t *data,
761 : size_t size, int *resultp)
762 4095911 : : context(context), msg(msg), data(data), size(size),
763 4095911 : resultp(resultp) {
764 4095911 : }
765 : template <typename U>
766 9714792 : void operator()(U element) {
767 9714792 : if (*resultp < 0) {
768 241 : return;
769 : }
770 9714551 : int res = U::Encode(context, msg, data, size);
771 9714747 : if (res < 0) {
772 734 : *resultp = res;
773 : } else {
774 9714013 : *resultp += res;
775 : }
776 9714747 : if (data != NULL) {
777 9714779 : data += res;
778 9714779 : size -= res;
779 : }
780 : }
781 :
782 : private:
783 : EncodeContext *context;
784 : const T *msg;
785 : uint8_t *data;
786 : size_t size;
787 : int *resultp;
788 : };
789 :
790 393130 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
791 : int offset, int arg) {
792 393130 : int length = context->length() - Derived::kSize;
793 393119 : put_value(data, Derived::kSize, length);
794 393120 : }
795 : };
796 :
797 : #endif
|