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 195952 : 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 155593 : 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 2371552 : static void set(C *obj, T value) {
98 2371552 : obj->*Member = value;
99 2371552 : }
100 3031612 : static T get(const C *obj) {
101 3031612 : return obj->*Member;
102 : }
103 : };
104 :
105 : template <class C, std::string C::* Member>
106 : struct Accessor<C, std::string, Member> {
107 5329 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
108 5329 : obj->*Member = std::string((const char *) data, elem_size);
109 5329 : }
110 8126 : static int size(const C *obj) {
111 8126 : return (obj->*Member).size();
112 : }
113 8127 : static std::string::const_iterator begin(const C *obj) {
114 8127 : return (obj->*Member).begin();
115 : }
116 8126 : static std::string::const_iterator end(const C *obj) {
117 8126 : return (obj->*Member).end();
118 : }
119 : };
120 :
121 : template <class C, typename T, std::vector<T> C::* Member>
122 : struct VectorAccessor {
123 1548188 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
124 1548188 : obj->*Member = std::vector<T>();
125 1548221 : size_t size = sizeof(T);
126 13351559 : for (size_t i = 0; i < elem_size; i += size) {
127 11803338 : T value = get_value(data, size);
128 11803332 : data += size;
129 11803332 : (obj->*Member).push_back(value);
130 : }
131 1548221 : }
132 2136217 : static int size(const C *obj) {
133 2136217 : return (obj->*Member).size() * sizeof(T);
134 : }
135 2136087 : static typename std::vector<T>::const_iterator begin(const C *obj) {
136 2136087 : return (obj->*Member).begin();
137 : }
138 2136053 : static typename std::vector<T>::const_iterator end(const C *obj) {
139 2136053 : 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 1793337 : static void insert(Obj *obj, ValueType *element) {
159 1793337 : (obj->*Member).push_back(element);
160 1793320 : }
161 960688 : static iterator begin(const Obj *obj) {
162 960688 : return (obj->*Member).begin();
163 : }
164 3295563 : static iterator end(const Obj *obj) {
165 3295563 : 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 5753684 : void operator()(void *) {
176 5753684 : }
177 : };
178 : struct NoMatch {
179 : bool match(const void *) {
180 : return false;
181 : }
182 : };
183 6215520 : static bool Verifier(const void * obj, const uint8_t *data, size_t size,
184 : ParseContext *context) {
185 6215520 : 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 6958564 : 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 6958564 : writer(data, Derived::kSize, msg);
227 6958731 : }
228 :
229 : template <typename T>
230 5758271 : 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 5758271 : 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 5758263 : 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 5754024 : initializer(obj);
258 :
259 : detail::SequenceLengthSetter<typename Derived::SequenceLength, T> slen;
260 5754018 : int res = slen(context, data, Derived::kSize, size, obj);
261 5754035 : 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 5753872 : res = setter(data, size, context, obj);
283 5753897 : if (res < 0) {
284 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
285 : TYPE_NAME(Derived), data,
286 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
287 : }
288 5753898 : return res;
289 : }
290 :
291 : template <typename T>
292 7298189 : 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 7298189 : int element_size = size_value_t::get(msg);
303 7298247 : if (data == NULL) {
304 10 : context->advance(element_size);
305 0 : return element_size;
306 : }
307 7298240 : assert(element_size >= 0);
308 7298240 : 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 7298065 : slen(&ProtoElement::SequenceLengthWriteLen, context, data, element_size);
319 :
320 : detail::AddCallback<typename Derived::EncodingCallback> cbadd;
321 7297966 : cbadd(context, data, element_size);
322 :
323 7297960 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
324 :
325 7298007 : Derived::Writer(msg, data, size);
326 :
327 7298131 : context->advance(element_size);
328 7297916 : return element_size;
329 : }
330 :
331 : private:
332 1589229 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
333 : int offset, int element_size) {
334 1589229 : int length = context->length() - offset - element_size;
335 1589174 : put_value(data, element_size, length);
336 1589168 : }
337 : };
338 :
339 : template <typename Setter, typename T>
340 : struct ChoiceSetter {
341 790566 : void operator()(T *obj, int &value) {
342 790566 : Setter::set(obj, value);
343 790566 : }
344 : };
345 :
346 : template <typename T>
347 : struct ChoiceSetter<void, T> {
348 199479 : void operator()(T* obj, int value) { }
349 : };
350 :
351 : template <class Derived>
352 : class ProtoChoice : public ChoiceBase {
353 : public:
354 : template <typename T>
355 990039 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
356 : T *obj) {
357 990039 : int advance = Derived::kSize;
358 990039 : int value = -1;
359 :
360 990039 : 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 990039 : value = get_value(data, advance);
367 :
368 990043 : data += advance;
369 990043 : size -= advance;
370 990043 : 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 990048 : setter(obj, value);
380 :
381 990044 : int result = ParseChoice(data, size, value, context, obj);
382 990056 : 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 985868 : advance += result;
391 985868 : return advance;
392 : }
393 :
394 : template <typename T>
395 1073661 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
396 : size_t size) {
397 : typedef typename Derived::Choice choice_t;
398 1073661 : int result = 0;
399 1073661 : ChoiceEncoder<T> encoder(context, msg, data, size, &result);
400 1073698 : mpl::for_each<choice_t>(encoder);
401 1073922 : return result;
402 : }
403 :
404 : private:
405 : template <typename T>
406 : struct ChoiceMatcher {
407 990042 : ChoiceMatcher(const uint8_t *data, size_t size, int value,
408 : ParseContext *context, T *obj, int *resultp)
409 990042 : : data(data), size(size), value(value), context(context),
410 990042 : obj(obj), resultp(resultp), found(false) {
411 990042 : }
412 : template <typename U>
413 14643622 : void operator()(U x) {
414 14643622 : if (found) return;
415 5772112 : if (U::first::value != -1 && U::first::value != value) {
416 4784770 : return;
417 : }
418 989933 : found = true;
419 : typedef detail::DescendentParser<Derived, typename U::second>
420 : parser_t;
421 989933 : *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 990041 : static int ParseChoice(const uint8_t *data, size_t size, int value,
433 : ParseContext *context, T *obj) {
434 990041 : int result = -2;
435 990041 : ChoiceMatcher<T> match(data, size, value, context, obj, &result);
436 990042 : mpl::for_each<typename Derived::Choice>(match);
437 990053 : return result;
438 : }
439 :
440 : template <typename T>
441 : struct ChoiceEncoder {
442 1073686 : ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
443 : int *resultp)
444 1073686 : : context(context), msg(msg), data(data), size(size),
445 1073686 : resultp(resultp), found(false) {
446 1073686 : }
447 : template <typename U, typename CtxType>
448 : struct EncoderTrue {
449 1073930 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
450 : uint8_t *data, int size) {
451 : if (Derived::kSize) {
452 901517 : if (data != NULL) {
453 901520 : if (size < Derived::kSize) return -1;
454 901520 : put_value(data, Derived::kSize, opt);
455 901520 : data += Derived::kSize;
456 901520 : size -= Derived::kSize;
457 : }
458 901517 : context->advance(Derived::kSize);
459 : }
460 1073896 : int result = U::Encode(context, msg, data, size);
461 1073993 : if (result >= 0) {
462 1073658 : result += Derived::kSize;
463 : }
464 1073993 : return result;
465 : }
466 : };
467 : template <typename U, typename CtxType>
468 : struct EncoderSetter {
469 734513 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
470 : uint8_t *data, int size) {
471 734513 : int value = Derived::Setter::get(msg);
472 734526 : if (value == opt || opt == -1) {
473 677767 : return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
474 : }
475 56759 : return 0;
476 : }
477 : };
478 : template <typename U>
479 : struct EncoderMatch {
480 252303 : int operator()(int opt, EncodeContext *context, const T *msg,
481 : uint8_t *data, int size) {
482 : typename U::ContextMatch matcher;
483 252303 : if (matcher.match(msg)) {
484 182461 : return EncoderTrue<U, T>()(opt, context, msg, data, size);
485 : }
486 69846 : return 0;
487 : }
488 : };
489 : template <typename U>
490 : struct EncoderRunTime {
491 6047935 : int operator()(int opt, EncodeContext *context, const T *msg,
492 : uint8_t *data, int size) {
493 6047935 : if (typeid(*msg) == typeid(typename U::ContextType)) {
494 : typedef typename U::ContextType ctx_t;
495 948110 : 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 948110 : return encoder()(opt, context, ctx, data, size);
503 : }
504 5099859 : 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 15786228 : void operator()(U x) {
515 15786228 : if (*resultp < 0 || found) {
516 9485957 : 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 6300294 : int result = choice(U::first::value, context, msg, data, size);
539 6300426 : if (result < 0) {
540 334 : *resultp = result;
541 6300092 : } else if (result > 0) {
542 1060644 : found = true;
543 1060644 : *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 3280011 : SequenceParser(const uint8_t *data, size_t size, ParseContext *context,
562 : T *obj, int *resultp)
563 3280011 : : data(data), size(size), context(context), obj(obj),
564 3280011 : resultp(resultp) {
565 3280011 : }
566 :
567 : template <typename U>
568 7889561 : void operator()(U x) {
569 7889561 : if (*resultp < 0) {
570 9007 : return;
571 : }
572 : typedef detail::DescendentParser<Derived, U> parser_t;
573 7880554 : size_t prev_size = context->size();
574 7880509 : int result = parser_t::Parse(data, size, context, obj);
575 7880578 : if (result < 0) {
576 12393 : *resultp = result;
577 12393 : return;
578 : }
579 :
580 7868185 : data += result;
581 7868185 : size -= result;
582 7868185 : context->advance(result);
583 7868179 : *resultp += result;
584 :
585 7868179 : if (context->size() != prev_size) {
586 2780127 : size = context->size();
587 2780165 : context->set_total_size();
588 : } else {
589 5088010 : 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 2319358 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
602 : T *obj) {
603 2319358 : int min = Derived::kMinOccurs;
604 2319358 : if (min == 0 && size == 0) {
605 206722 : return 0;
606 : }
607 2112636 : 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 2112586 : int lensize = Derived::kSize;
615 2112586 : int length = size;
616 2112586 : if (lensize) {
617 361677 : 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 361677 : length = get_value(data, lensize);
625 361679 : assert(length >= 0);
626 361680 : size -= lensize;
627 361680 : 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 358644 : data += lensize;
634 358644 : context->advance(lensize);
635 : }
636 2109557 : int result = lensize;
637 2109557 : int max = Derived::kMaxOccurs;
638 5377171 : for (int i = 0; (max == -1 || i < max) && (length > 0); i++) {
639 3280031 : 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 3280031 : ctx_t *child_obj = pushfn(context, obj);
651 :
652 3280011 : SequenceParser<ctx_t> parser(data, length, context, child_obj, &sublen);
653 3280010 : mpl::for_each<typename Derived::Sequence>(parser);
654 3280037 : if (sublen < 0) {
655 12393 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen);
656 12393 : return -1;
657 : }
658 3267644 : 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 3267631 : result += sublen;
667 3267631 : data += sublen;
668 3267631 : 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 3267631 : popfn(context, obj);
676 : }
677 2097140 : return result;
678 : }
679 :
680 : template <typename T>
681 : struct SingleEncoder {
682 : typedef typename Derived::Sequence sequence_t;
683 1780307 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
684 : size_t size) {
685 1780307 : int result = 0;
686 1780307 : SequenceEncoder<T> encoder(context, msg, data, size, &result);
687 1780341 : mpl::for_each<sequence_t>(encoder);
688 1780444 : return result;
689 : }
690 : };
691 :
692 : template <typename T>
693 : struct ListEncoder {
694 : typedef typename Derived::Sequence sequence_t;
695 960698 : 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 960698 : int result = 0;
701 :
702 960698 : detail::ContextIterator<ctx_access_t> iter(msg);
703 3295666 : while (iter.HasNext(msg)) {
704 2335106 : child_obj_t *child_obj = iter.Next();
705 2335096 : int subres = 0;
706 2335096 : context->Push();
707 2335056 : SequenceEncoder<child_obj_t> encoder(context, child_obj,
708 : data, size, &subres);
709 2335061 : mpl::for_each<sequence_t>(encoder);
710 2335232 : if (subres < 0) {
711 223 : result = subres;
712 223 : break;
713 : }
714 2335009 : result += subres;
715 2335009 : if (data != NULL) {
716 2335014 : data += subres;
717 2335014 : size -= subres;
718 : }
719 2335009 : context->Pop(data != NULL);
720 : }
721 960695 : return result;
722 : }
723 : };
724 :
725 : template <typename T>
726 2741008 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
727 : size_t size) {
728 2741008 : context->Push();
729 2741030 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
730 : if (Derived::kSize > 0) {
731 : // context push callback
732 397250 : if (data != NULL) {
733 397230 : context->AddCallback(&SequenceLengthWriteLen, data, Derived::kSize);
734 397182 : data += Derived::kSize;
735 397182 : size -= Derived::kSize;
736 : }
737 397202 : 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 2741030 : int result = encoder(context, msg, data, size);
750 2741244 : if (result >= 0) {
751 2740540 : result += Derived::kSize;
752 2740540 : context->Pop(data != NULL);
753 : }
754 2741278 : return result;
755 : }
756 :
757 : private:
758 : template <typename T>
759 : struct SequenceEncoder {
760 4115356 : SequenceEncoder(EncodeContext *context, const T *msg, uint8_t *data,
761 : size_t size, int *resultp)
762 4115356 : : context(context), msg(msg), data(data), size(size),
763 4115356 : resultp(resultp) {
764 4115356 : }
765 : template <typename U>
766 9763829 : void operator()(U element) {
767 9763829 : if (*resultp < 0) {
768 241 : return;
769 : }
770 9763588 : int res = U::Encode(context, msg, data, size);
771 9763816 : if (res < 0) {
772 734 : *resultp = res;
773 : } else {
774 9763082 : *resultp += res;
775 : }
776 9763816 : if (data != NULL) {
777 9763830 : data += res;
778 9763830 : 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 397106 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
791 : int offset, int arg) {
792 397106 : int length = context->length() - Derived::kSize;
793 397095 : put_value(data, Derived::kSize, length);
794 397094 : }
795 : };
796 :
797 : #endif
|