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 198701 : 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 156963 : 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 2386376 : static void set(C *obj, T value) {
98 2386376 : obj->*Member = value;
99 2386376 : }
100 3051540 : static T get(const C *obj) {
101 3051540 : return obj->*Member;
102 : }
103 : };
104 :
105 : template <class C, std::string C::* Member>
106 : struct Accessor<C, std::string, Member> {
107 5965 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
108 5965 : obj->*Member = std::string((const char *) data, elem_size);
109 5966 : }
110 8694 : static int size(const C *obj) {
111 8694 : return (obj->*Member).size();
112 : }
113 8695 : static std::string::const_iterator begin(const C *obj) {
114 8695 : return (obj->*Member).begin();
115 : }
116 8695 : static std::string::const_iterator end(const C *obj) {
117 8695 : return (obj->*Member).end();
118 : }
119 : };
120 :
121 : template <class C, typename T, std::vector<T> C::* Member>
122 : struct VectorAccessor {
123 1551981 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
124 1551981 : obj->*Member = std::vector<T>();
125 1552039 : size_t size = sizeof(T);
126 13386812 : for (size_t i = 0; i < elem_size; i += size) {
127 11834793 : T value = get_value(data, size);
128 11834774 : data += size;
129 11834774 : (obj->*Member).push_back(value);
130 : }
131 1552019 : }
132 2143795 : static int size(const C *obj) {
133 2143795 : return (obj->*Member).size() * sizeof(T);
134 : }
135 2143673 : static typename std::vector<T>::const_iterator begin(const C *obj) {
136 2143673 : return (obj->*Member).begin();
137 : }
138 2143662 : static typename std::vector<T>::const_iterator end(const C *obj) {
139 2143662 : 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 1801062 : static void insert(Obj *obj, ValueType *element) {
159 1801062 : (obj->*Member).push_back(element);
160 1801030 : }
161 970417 : static iterator begin(const Obj *obj) {
162 970417 : return (obj->*Member).begin();
163 : }
164 3316989 : static iterator end(const Obj *obj) {
165 3316989 : 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 5787403 : void operator()(void *) {
176 5787403 : }
177 : };
178 : struct NoMatch {
179 : bool match(const void *) {
180 : return false;
181 : }
182 : };
183 6254052 : static bool Verifier(const void * obj, const uint8_t *data, size_t size,
184 : ParseContext *context) {
185 6254052 : 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 6999020 : 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 6999020 : writer(data, Derived::kSize, msg);
227 6999189 : }
228 :
229 : template <typename T>
230 5792090 : 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 5792090 : 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 5792079 : 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 5787832 : initializer(obj);
258 :
259 : detail::SequenceLengthSetter<typename Derived::SequenceLength, T> slen;
260 5787831 : int res = slen(context, data, Derived::kSize, size, obj);
261 5787833 : 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 5787670 : res = setter(data, size, context, obj);
283 5787712 : if (res < 0) {
284 2 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
285 : TYPE_NAME(Derived), data,
286 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
287 : }
288 5787712 : return res;
289 : }
290 :
291 : template <typename T>
292 7343246 : 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 7343246 : int element_size = size_value_t::get(msg);
303 7343268 : if (data == NULL) {
304 19 : context->advance(element_size);
305 0 : return element_size;
306 : }
307 7343253 : assert(element_size >= 0);
308 7343253 : if (size < (size_t) element_size) {
309 176 : 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 7343077 : slen(&ProtoElement::SequenceLengthWriteLen, context, data, element_size);
319 :
320 : detail::AddCallback<typename Derived::EncodingCallback> cbadd;
321 7342993 : cbadd(context, data, element_size);
322 :
323 7342996 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
324 :
325 7343048 : Derived::Writer(msg, data, size);
326 :
327 7343201 : context->advance(element_size);
328 7342945 : return element_size;
329 : }
330 :
331 : private:
332 1598592 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
333 : int offset, int element_size) {
334 1598592 : int length = context->length() - offset - element_size;
335 1598520 : put_value(data, element_size, length);
336 1598524 : }
337 : };
338 :
339 : template <typename Setter, typename T>
340 : struct ChoiceSetter {
341 797209 : void operator()(T *obj, int &value) {
342 797209 : Setter::set(obj, value);
343 797208 : }
344 : };
345 :
346 : template <typename T>
347 : struct ChoiceSetter<void, T> {
348 202546 : void operator()(T* obj, int value) { }
349 : };
350 :
351 : template <class Derived>
352 : class ProtoChoice : public ChoiceBase {
353 : public:
354 : template <typename T>
355 999744 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
356 : T *obj) {
357 999744 : int advance = Derived::kSize;
358 999744 : int value = -1;
359 :
360 999744 : 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 999744 : value = get_value(data, advance);
367 :
368 999750 : data += advance;
369 999750 : size -= advance;
370 999750 : 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 999762 : setter(obj, value);
380 :
381 999757 : int result = ParseChoice(data, size, value, context, obj);
382 999754 : 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 995566 : advance += result;
391 995566 : return advance;
392 : }
393 :
394 : template <typename T>
395 1083558 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
396 : size_t size) {
397 : typedef typename Derived::Choice choice_t;
398 1083558 : int result = 0;
399 1083558 : ChoiceEncoder<T> encoder(context, msg, data, size, &result);
400 1083627 : mpl::for_each<choice_t>(encoder);
401 1083793 : return result;
402 : }
403 :
404 : private:
405 : template <typename T>
406 : struct ChoiceMatcher {
407 999755 : ChoiceMatcher(const uint8_t *data, size_t size, int value,
408 : ParseContext *context, T *obj, int *resultp)
409 999755 : : data(data), size(size), value(value), context(context),
410 999755 : obj(obj), resultp(resultp), found(false) {
411 999755 : }
412 : template <typename U>
413 14767246 : void operator()(U x) {
414 14767246 : if (found) return;
415 5820845 : if (U::first::value != -1 && U::first::value != value) {
416 4823848 : return;
417 : }
418 999601 : found = true;
419 : typedef detail::DescendentParser<Derived, typename U::second>
420 : parser_t;
421 999601 : *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 999753 : static int ParseChoice(const uint8_t *data, size_t size, int value,
433 : ParseContext *context, T *obj) {
434 999753 : int result = -2;
435 999753 : ChoiceMatcher<T> match(data, size, value, context, obj, &result);
436 999754 : mpl::for_each<typename Derived::Choice>(match);
437 999752 : return result;
438 : }
439 :
440 : template <typename T>
441 : struct ChoiceEncoder {
442 1083604 : ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
443 : int *resultp)
444 1083604 : : context(context), msg(msg), data(data), size(size),
445 1083604 : resultp(resultp), found(false) {
446 1083604 : }
447 : template <typename U, typename CtxType>
448 : struct EncoderTrue {
449 1083862 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
450 : uint8_t *data, int size) {
451 : if (Derived::kSize) {
452 909845 : if (data != NULL) {
453 909858 : if (size < Derived::kSize) return -1;
454 909858 : put_value(data, Derived::kSize, opt);
455 909859 : data += Derived::kSize;
456 909859 : size -= Derived::kSize;
457 : }
458 909846 : context->advance(Derived::kSize);
459 : }
460 1083841 : int result = U::Encode(context, msg, data, size);
461 1083870 : if (result >= 0) {
462 1083535 : result += Derived::kSize;
463 : }
464 1083870 : return result;
465 : }
466 : };
467 : template <typename U, typename CtxType>
468 : struct EncoderSetter {
469 739837 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
470 : uint8_t *data, int size) {
471 739837 : int value = Derived::Setter::get(msg);
472 739840 : if (value == opt || opt == -1) {
473 682369 : return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
474 : }
475 57471 : return 0;
476 : }
477 : };
478 : template <typename U>
479 : struct EncoderMatch {
480 255683 : int operator()(int opt, EncodeContext *context, const T *msg,
481 : uint8_t *data, int size) {
482 : typename U::ContextMatch matcher;
483 255683 : if (matcher.match(msg)) {
484 184748 : return EncoderTrue<U, T>()(opt, context, msg, data, size);
485 : }
486 70936 : return 0;
487 : }
488 : };
489 : template <typename U>
490 : struct EncoderRunTime {
491 6091311 : int operator()(int opt, EncodeContext *context, const T *msg,
492 : uint8_t *data, int size) {
493 6091311 : if (typeid(*msg) == typeid(typename U::ContextType)) {
494 : typedef typename U::ContextType ctx_t;
495 956433 : 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 956433 : return encoder()(opt, context, ctx, data, size);
503 : }
504 5134916 : 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 15901339 : void operator()(U x) {
515 15901339 : if (*resultp < 0 || found) {
516 9554294 : 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 6347050 : int result = choice(U::first::value, context, msg, data, size);
539 6347136 : if (result < 0) {
540 334 : *resultp = result;
541 6346802 : } else if (result > 0) {
542 1070296 : found = true;
543 1070296 : *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 3300248 : SequenceParser(const uint8_t *data, size_t size, ParseContext *context,
562 : T *obj, int *resultp)
563 3300248 : : data(data), size(size), context(context), obj(obj),
564 3300248 : resultp(resultp) {
565 3300248 : }
566 :
567 : template <typename U>
568 7941424 : void operator()(U x) {
569 7941424 : if (*resultp < 0) {
570 9007 : return;
571 : }
572 : typedef detail::DescendentParser<Derived, U> parser_t;
573 7932417 : size_t prev_size = context->size();
574 7932384 : int result = parser_t::Parse(data, size, context, obj);
575 7932435 : if (result < 0) {
576 12393 : *resultp = result;
577 12393 : return;
578 : }
579 :
580 7920042 : data += result;
581 7920042 : size -= result;
582 7920042 : context->advance(result);
583 7920048 : *resultp += result;
584 :
585 7920048 : if (context->size() != prev_size) {
586 2793557 : size = context->size();
587 2793610 : context->set_total_size();
588 : } else {
589 5126457 : 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 2340151 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
602 : T *obj) {
603 2340151 : int min = Derived::kMinOccurs;
604 2340151 : if (min == 0 && size == 0) {
605 209173 : return 0;
606 : }
607 2130978 : 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 2130940 : int lensize = Derived::kSize;
615 2130940 : int length = size;
616 2130940 : if (lensize) {
617 365513 : 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 365513 : length = get_value(data, lensize);
625 365515 : assert(length >= 0);
626 365517 : size -= lensize;
627 365517 : 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 362481 : data += lensize;
634 362481 : context->advance(lensize);
635 : }
636 2127902 : int result = lensize;
637 2127902 : int max = Derived::kMaxOccurs;
638 5415771 : for (int i = 0; (max == -1 || i < max) && (length > 0); i++) {
639 3300264 : 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 3300264 : ctx_t *child_obj = pushfn(context, obj);
651 :
652 3300252 : SequenceParser<ctx_t> parser(data, length, context, child_obj, &sublen);
653 3300251 : mpl::for_each<typename Derived::Sequence>(parser);
654 3300288 : if (sublen < 0) {
655 12393 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen);
656 12393 : return -1;
657 : }
658 3287895 : 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 3287898 : result += sublen;
667 3287898 : data += sublen;
668 3287898 : 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 3287898 : popfn(context, obj);
676 : }
677 2115507 : return result;
678 : }
679 :
680 : template <typename T>
681 : struct SingleEncoder {
682 : typedef typename Derived::Sequence sequence_t;
683 1795536 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
684 : size_t size) {
685 1795536 : int result = 0;
686 1795536 : SequenceEncoder<T> encoder(context, msg, data, size, &result);
687 1795582 : mpl::for_each<sequence_t>(encoder);
688 1795663 : return result;
689 : }
690 : };
691 :
692 : template <typename T>
693 : struct ListEncoder {
694 : typedef typename Derived::Sequence sequence_t;
695 970440 : 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 970440 : int result = 0;
701 :
702 970440 : detail::ContextIterator<ctx_access_t> iter(msg);
703 3317070 : while (iter.HasNext(msg)) {
704 2346833 : child_obj_t *child_obj = iter.Next();
705 2346825 : int subres = 0;
706 2346825 : context->Push();
707 2346777 : SequenceEncoder<child_obj_t> encoder(context, child_obj,
708 : data, size, &subres);
709 2346787 : mpl::for_each<sequence_t>(encoder);
710 2346896 : if (subres < 0) {
711 224 : result = subres;
712 224 : break;
713 : }
714 2346672 : result += subres;
715 2346672 : if (data != NULL) {
716 2346679 : data += subres;
717 2346679 : size -= subres;
718 : }
719 2346672 : context->Pop(data != NULL);
720 : }
721 970379 : return result;
722 : }
723 : };
724 :
725 : template <typename T>
726 2765995 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
727 : size_t size) {
728 2765995 : context->Push();
729 2766004 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
730 : if (Derived::kSize > 0) {
731 : // context push callback
732 401847 : if (data != NULL) {
733 401854 : context->AddCallback(&SequenceLengthWriteLen, data, Derived::kSize);
734 401789 : data += Derived::kSize;
735 401789 : size -= Derived::kSize;
736 : }
737 401782 : 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 2766015 : int result = encoder(context, msg, data, size);
750 2766167 : if (result >= 0) {
751 2765453 : result += Derived::kSize;
752 2765453 : context->Pop(data != NULL);
753 : }
754 2766127 : return result;
755 : }
756 :
757 : private:
758 : template <typename T>
759 : struct SequenceEncoder {
760 4142316 : SequenceEncoder(EncodeContext *context, const T *msg, uint8_t *data,
761 : size_t size, int *resultp)
762 4142316 : : context(context), msg(msg), data(data), size(size),
763 4142316 : resultp(resultp) {
764 4142316 : }
765 : template <typename U>
766 9829713 : void operator()(U element) {
767 9829713 : if (*resultp < 0) {
768 241 : return;
769 : }
770 9829472 : int res = U::Encode(context, msg, data, size);
771 9829597 : if (res < 0) {
772 735 : *resultp = res;
773 : } else {
774 9828862 : *resultp += res;
775 : }
776 9829597 : if (data != NULL) {
777 9829617 : data += res;
778 9829617 : 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 401664 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
791 : int offset, int arg) {
792 401664 : int length = context->length() - Derived::kSize;
793 401645 : put_value(data, Derived::kSize, length);
794 401654 : }
795 : };
796 :
797 : #endif
|