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 21015 : 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 0 : 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 17162 : 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 158686 : static void set(C *obj, T value) {
98 158686 : obj->*Member = value;
99 158686 : }
100 175606 : static T get(const C *obj) {
101 175606 : return obj->*Member;
102 : }
103 : };
104 :
105 : template <class C, std::string C::* Member>
106 : struct Accessor<C, std::string, Member> {
107 1005 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
108 1005 : obj->*Member = std::string((const char *) data, elem_size);
109 1005 : }
110 1225 : static int size(const C *obj) {
111 1225 : return (obj->*Member).size();
112 : }
113 1223 : static std::string::const_iterator begin(const C *obj) {
114 1223 : return (obj->*Member).begin();
115 : }
116 1224 : static std::string::const_iterator end(const C *obj) {
117 1224 : return (obj->*Member).end();
118 : }
119 : };
120 :
121 : template <class C, typename T, std::vector<T> C::* Member>
122 : struct VectorAccessor {
123 60611 : static void set(C*obj, const uint8_t *data, size_t elem_size) {
124 60611 : obj->*Member = std::vector<T>();
125 60620 : size_t size = sizeof(T);
126 767929 : for (size_t i = 0; i < elem_size; i += size) {
127 707309 : T value = get_value(data, size);
128 707305 : data += size;
129 707305 : (obj->*Member).push_back(value);
130 : }
131 60620 : }
132 65367 : static int size(const C *obj) {
133 65367 : return (obj->*Member).size() * sizeof(T);
134 : }
135 65371 : static typename std::vector<T>::const_iterator begin(const C *obj) {
136 65371 : return (obj->*Member).begin();
137 : }
138 65370 : static typename std::vector<T>::const_iterator end(const C *obj) {
139 65370 : 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 99180 : static void insert(Obj *obj, ValueType *element) {
159 99180 : (obj->*Member).push_back(element);
160 99182 : }
161 96525 : static iterator begin(const Obj *obj) {
162 96525 : return (obj->*Member).begin();
163 : }
164 202396 : static iterator end(const Obj *obj) {
165 202396 : 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 372450 : void operator()(void *) {
176 372450 : }
177 : };
178 : struct NoMatch {
179 : bool match(const void *) {
180 : return false;
181 : }
182 : };
183 408223 : static bool Verifier(const void * obj, const uint8_t *data, size_t size,
184 : ParseContext *context) {
185 408223 : 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 359779 : 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 359779 : writer(data, Derived::kSize, msg);
227 359807 : }
228 :
229 : template <typename T>
230 372521 : 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 372521 : if (!cmp(size)) {
241 0 : PROTO_DEBUG("Error: cmp(size) failed");
242 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
243 : TYPE_NAME(Derived), data,
244 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
245 0 : return -1;
246 : }
247 372522 : if (!Derived::Verifier(obj, data, size, context)) {
248 0 : PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
249 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
250 : TYPE_NAME(Derived), data,
251 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
252 0 : return -1;
253 : }
254 :
255 : typedef typename Derived::ContextInit ctx_init_t;
256 : ctx_init_t initializer;
257 372517 : initializer(obj);
258 :
259 : detail::SequenceLengthSetter<typename Derived::SequenceLength, T> slen;
260 372519 : int res = slen(context, data, Derived::kSize, size, obj);
261 372526 : if (res < 0) {
262 0 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: Length Setter failed");
263 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
264 : TYPE_NAME(Derived), data, context->lensize());
265 0 : 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 372526 : res = setter(data, size, context, obj);
283 372537 : 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 372538 : return res;
289 : }
290 :
291 : template <typename T>
292 397851 : 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 397851 : int element_size = size_value_t::get(msg);
303 397859 : if (data == NULL) {
304 3 : context->advance(element_size);
305 0 : return element_size;
306 : }
307 397856 : assert(element_size >= 0);
308 397856 : if (size < (size_t) element_size) {
309 0 : 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 397856 : slen(&ProtoElement::SequenceLengthWriteLen, context, data, element_size);
319 :
320 : detail::AddCallback<typename Derived::EncodingCallback> cbadd;
321 397823 : cbadd(context, data, element_size);
322 :
323 397823 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
324 :
325 397863 : Derived::Writer(msg, data, size);
326 :
327 397895 : context->advance(element_size);
328 397752 : return element_size;
329 : }
330 :
331 : private:
332 95485 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
333 : int offset, int element_size) {
334 95485 : int length = context->length() - offset - element_size;
335 95472 : put_value(data, element_size, length);
336 95471 : }
337 : };
338 :
339 : template <typename Setter, typename T>
340 : struct ChoiceSetter {
341 79229 : void operator()(T *obj, int &value) {
342 79229 : Setter::set(obj, value);
343 79229 : }
344 : };
345 :
346 : template <typename T>
347 : struct ChoiceSetter<void, T> {
348 22301 : void operator()(T* obj, int value) { }
349 : };
350 :
351 : template <class Derived>
352 : class ProtoChoice : public ChoiceBase {
353 : public:
354 : template <typename T>
355 101531 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
356 : T *obj) {
357 101531 : int advance = Derived::kSize;
358 101531 : int value = -1;
359 :
360 101531 : 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 101531 : value = get_value(data, advance);
367 :
368 101531 : data += advance;
369 101531 : size -= advance;
370 101531 : 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 101532 : setter(obj, value);
380 :
381 101532 : int result = ParseChoice(data, size, value, context, obj);
382 101533 : if (result < 0) {
383 0 : PROTO_DEBUG(TYPE_NAME(Derived) << " ParseChoice failed");
384 0 : if (result == -2) {
385 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
386 0 : TYPE_NAME(Derived), data - advance, advance);
387 : }
388 0 : return result;
389 : }
390 101533 : advance += result;
391 101533 : return advance;
392 : }
393 :
394 : template <typename T>
395 107309 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
396 : size_t size) {
397 : typedef typename Derived::Choice choice_t;
398 107309 : int result = 0;
399 107309 : ChoiceEncoder<T> encoder(context, msg, data, size, &result);
400 107339 : mpl::for_each<choice_t>(encoder);
401 107409 : return result;
402 : }
403 :
404 : private:
405 : template <typename T>
406 : struct ChoiceMatcher {
407 101533 : ChoiceMatcher(const uint8_t *data, size_t size, int value,
408 : ParseContext *context, T *obj, int *resultp)
409 101533 : : data(data), size(size), value(value), context(context),
410 101533 : obj(obj), resultp(resultp), found(false) {
411 101533 : }
412 : template <typename U>
413 1457210 : void operator()(U x) {
414 1457210 : if (found) return;
415 573742 : if (U::first::value != -1 && U::first::value != value) {
416 472209 : return;
417 : }
418 101533 : found = true;
419 : typedef detail::DescendentParser<Derived, typename U::second>
420 : parser_t;
421 101533 : *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 101532 : static int ParseChoice(const uint8_t *data, size_t size, int value,
433 : ParseContext *context, T *obj) {
434 101532 : int result = -2;
435 101532 : ChoiceMatcher<T> match(data, size, value, context, obj, &result);
436 101532 : mpl::for_each<typename Derived::Choice>(match);
437 101532 : return result;
438 : }
439 :
440 : template <typename T>
441 : struct ChoiceEncoder {
442 107331 : ChoiceEncoder(EncodeContext *context, const T *msg, uint8_t *data, int size,
443 : int *resultp)
444 107331 : : context(context), msg(msg), data(data), size(size),
445 107331 : resultp(resultp), found(false) {
446 107331 : }
447 : template <typename U, typename CtxType>
448 : struct EncoderTrue {
449 107457 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
450 : uint8_t *data, int size) {
451 : if (Derived::kSize) {
452 88623 : if (data != NULL) {
453 88623 : if (size < Derived::kSize) return -1;
454 88623 : put_value(data, Derived::kSize, opt);
455 88626 : data += Derived::kSize;
456 88626 : size -= Derived::kSize;
457 : }
458 88626 : context->advance(Derived::kSize);
459 : }
460 107427 : int result = U::Encode(context, msg, data, size);
461 107428 : if (result >= 0) {
462 107426 : result += Derived::kSize;
463 : }
464 107428 : return result;
465 : }
466 : };
467 : template <typename U, typename CtxType>
468 : struct EncoderSetter {
469 69356 : int operator()(int opt, EncodeContext *context, const CtxType *msg,
470 : uint8_t *data, int size) {
471 69356 : int value = Derived::Setter::get(msg);
472 69358 : if (value == opt || opt == -1) {
473 63681 : return EncoderTrue<U, CtxType>()(value, context, msg, data, size);
474 : }
475 5677 : return 0;
476 : }
477 : };
478 : template <typename U>
479 : struct EncoderMatch {
480 28190 : int operator()(int opt, EncodeContext *context, const T *msg,
481 : uint8_t *data, int size) {
482 : typename U::ContextMatch matcher;
483 28190 : if (matcher.match(msg)) {
484 20503 : return EncoderTrue<U, T>()(opt, context, msg, data, size);
485 : }
486 7687 : return 0;
487 : }
488 : };
489 : template <typename U>
490 : struct EncoderRunTime {
491 582819 : int operator()(int opt, EncodeContext *context, const T *msg,
492 : uint8_t *data, int size) {
493 582819 : if (typeid(*msg) == typeid(typename U::ContextType)) {
494 : typedef typename U::ContextType ctx_t;
495 92601 : 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 92601 : return encoder()(opt, context, ctx, data, size);
503 : }
504 490234 : 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 1506653 : void operator()(U x) {
515 1506653 : if (*resultp < 0 || found) {
516 895621 : 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 611033 : int result = choice(U::first::value, context, msg, data, size);
539 611002 : if (result < 0) {
540 0 : *resultp = result;
541 611002 : } else if (result > 0) {
542 105758 : found = true;
543 105758 : *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 218444 : SequenceParser(const uint8_t *data, size_t size, ParseContext *context,
562 : T *obj, int *resultp)
563 218444 : : data(data), size(size), context(context), obj(obj),
564 218444 : resultp(resultp) {
565 218444 : }
566 :
567 : template <typename U>
568 556644 : void operator()(U x) {
569 556644 : if (*resultp < 0) {
570 0 : return;
571 : }
572 : typedef detail::DescendentParser<Derived, U> parser_t;
573 556644 : size_t prev_size = context->size();
574 556612 : int result = parser_t::Parse(data, size, context, obj);
575 556645 : if (result < 0) {
576 0 : *resultp = result;
577 0 : return;
578 : }
579 :
580 556645 : data += result;
581 556645 : size -= result;
582 556645 : context->advance(result);
583 556636 : *resultp += result;
584 :
585 556636 : if (context->size() != prev_size) {
586 173091 : size = context->size();
587 173095 : context->set_total_size();
588 : } else {
589 383547 : 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 205237 : static int Parse(const uint8_t *data, size_t size, ParseContext *context,
602 : T *obj) {
603 205237 : int min = Derived::kMinOccurs;
604 205237 : if (min == 0 && size == 0) {
605 18845 : return 0;
606 : }
607 186392 : if (!Derived::Verifier(obj, data, size, context)) {
608 0 : PROTO_DEBUG(TYPE_NAME(Derived) << " Verifier failed");
609 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
610 : TYPE_NAME(Derived), data,
611 0 : Derived::kSize > 0 ? Derived::kSize : context->size());
612 0 : return -1;
613 : }
614 186392 : int lensize = Derived::kSize;
615 186392 : int length = size;
616 186392 : if (lensize) {
617 36920 : 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 36920 : length = get_value(data, lensize);
625 36920 : assert(length >= 0);
626 36920 : size -= lensize;
627 36920 : if ((size_t) length > size) {
628 0 : PROTO_DEBUG("Error: length = " << length << " size = " << size);
629 0 : context->SetError(Derived::kErrorCode, Derived::kErrorSubcode,
630 : TYPE_NAME(Derived), data, lensize);
631 0 : return -1;
632 : }
633 36920 : data += lensize;
634 36920 : context->advance(lensize);
635 : }
636 186389 : int result = lensize;
637 186389 : int max = Derived::kMaxOccurs;
638 404839 : for (int i = 0; (max == -1 || i < max) && (length > 0); i++) {
639 218436 : 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 218436 : ctx_t *child_obj = pushfn(context, obj);
651 :
652 218445 : SequenceParser<ctx_t> parser(data, length, context, child_obj, &sublen);
653 218444 : mpl::for_each<typename Derived::Sequence>(parser);
654 218450 : if (sublen < 0) {
655 0 : PROTO_DEBUG(TYPE_NAME(Derived) << ": error: sublen " << sublen);
656 0 : return -1;
657 : }
658 218450 : 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 218446 : result += sublen;
667 218446 : data += sublen;
668 218446 : 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 218446 : popfn(context, obj);
676 : }
677 186403 : return result;
678 : }
679 :
680 : template <typename T>
681 : struct SingleEncoder {
682 : typedef typename Derived::Sequence sequence_t;
683 129034 : int operator()(EncodeContext *context, const T *msg, uint8_t *data,
684 : size_t size) {
685 129034 : int result = 0;
686 129034 : SequenceEncoder<T> encoder(context, msg, data, size, &result);
687 129039 : mpl::for_each<sequence_t>(encoder);
688 129058 : return result;
689 : }
690 : };
691 :
692 : template <typename T>
693 : struct ListEncoder {
694 : typedef typename Derived::Sequence sequence_t;
695 96524 : 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 96524 : int result = 0;
701 :
702 96524 : detail::ContextIterator<ctx_access_t> iter(msg);
703 202435 : while (iter.HasNext(msg)) {
704 105893 : child_obj_t *child_obj = iter.Next();
705 105895 : int subres = 0;
706 105895 : context->Push();
707 105860 : SequenceEncoder<child_obj_t> encoder(context, child_obj,
708 : data, size, &subres);
709 105865 : mpl::for_each<sequence_t>(encoder);
710 105910 : if (subres < 0) {
711 0 : result = subres;
712 0 : break;
713 : }
714 105910 : result += subres;
715 105910 : if (data != NULL) {
716 105911 : data += subres;
717 105911 : size -= subres;
718 : }
719 105910 : context->Pop(data != NULL);
720 : }
721 96510 : return result;
722 : }
723 : };
724 :
725 : template <typename T>
726 225558 : static int Encode(EncodeContext *context, const T *msg, uint8_t *data,
727 : size_t size) {
728 225558 : context->Push();
729 225560 : detail::SaveOffset<typename Derived::SaveOffset>()(context);
730 : if (Derived::kSize > 0) {
731 : // context push callback
732 40994 : if (data != NULL) {
733 40995 : context->AddCallback(&SequenceLengthWriteLen, data, Derived::kSize);
734 40988 : data += Derived::kSize;
735 40988 : size -= Derived::kSize;
736 : }
737 40987 : 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 225566 : int result = encoder(context, msg, data, size);
750 225619 : if (result >= 0) {
751 225620 : result += Derived::kSize;
752 225620 : context->Pop(data != NULL);
753 : }
754 225592 : return result;
755 : }
756 :
757 : private:
758 : template <typename T>
759 : struct SequenceEncoder {
760 234894 : SequenceEncoder(EncodeContext *context, const T *msg, uint8_t *data,
761 : size_t size, int *resultp)
762 234894 : : context(context), msg(msg), data(data), size(size),
763 234894 : resultp(resultp) {
764 234894 : }
765 : template <typename U>
766 595133 : void operator()(U element) {
767 595133 : if (*resultp < 0) {
768 0 : return;
769 : }
770 595133 : int res = U::Encode(context, msg, data, size);
771 595153 : if (res < 0) {
772 0 : *resultp = res;
773 : } else {
774 595153 : *resultp += res;
775 : }
776 595153 : if (data != NULL) {
777 595160 : data += res;
778 595160 : 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 40989 : static void SequenceLengthWriteLen(EncodeContext *context, uint8_t *data,
791 : int offset, int arg) {
792 40989 : int length = context->length() - Derived::kSize;
793 40980 : put_value(data, Derived::kSize, length);
794 40980 : }
795 : };
796 :
797 : #endif
|