Enhanced SIM for E2AP v1 for TS UC
[sim/e2-interface.git] / e2sim / e2apv1sim / src / ASN1 / asn / ber / codec.hpp
1 #pragma once
2 /******************************************************************************
3 *
4 *   Copyright (c) 2019 AT&T Intellectual Property.
5 *   Copyright (c) 2018-2019 Nokia.
6 *
7 *   Licensed under the Apache License, Version 2.0 (the "License");
8 *   you may not use this file except in compliance with the License.
9 *   You may obtain a copy of the License at
10 *
11 *       http://www.apache.org/licenses/LICENSE-2.0
12 *
13 *   Unless required by applicable law or agreed to in writing, software
14 *   distributed under the License is distributed on an "AS IS" BASIS,
15 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 *   See the License for the specific language governing permissions and
17 *   limitations under the License.
18 *
19 ******************************************************************************/
20
21 // Standard Includes: ANSI C/C++, MSA, and Third-Party Libraries
22
23 // Local Includes: Application specific classes, functions, and libraries
24 #include "asn/elements.hpp"
25 #include "asn/ber/common.hpp"
26 #include "asn/ber/context.hpp"
27 #include "asn/ber/tag.hpp"
28 #include "asn/ber/length.hpp"
29 #include "asn/ber/visitor.hpp"
30 #include "asn/ber/opentype.hpp"
31
32 namespace asn {
33 namespace ber {
34
35 /********************************************************************************
36 pack (X.690)
37 *********************************************************************************/
38 template <class IE>
39 bool pack(IE const& ie, EncoderCtx& ctx)
40 {
41         ctx.refErrorCtx().reset();
42         Element<IE>::run(ie, ctx);
43
44         if (ctx)
45                 Tools::bit_accessor::padByte(ctx.refBuffer());
46
47         return static_cast<bool>(ctx);
48 }
49 /********************************************************************************
50 unpack (X.690)
51 *********************************************************************************/
52 template <class IE>
53 bool unpack(IE& ie, DecoderCtx& ctx)
54 {
55         Element<IE>::run(ie, ctx);
56
57         if (ctx)
58                 Tools::bit_accessor::padByte(ctx.refBuffer());
59
60         if(ctx && ctx.refBuffer().getBytesLeft())
61         {
62                 ctx.ie_name(IE::name());
63                 ctx.refErrorCtx().lengthErrorBytes(ctx.refBuffer().getBytesLeft(), 0);
64         }
65
66         return static_cast<bool>(ctx);
67 }
68
69 /***************************************************************************************
70 * ElementType
71 ***************************************************************************************/
72 template <class IE, class Enabler = void>
73 struct ElementType;
74
75 /***************************************************************************************
76 * ExplicitCodec: Codec for elements with EXPLICIT tag
77 ***************************************************************************************/
78 template <class IE>
79 struct ExplicitCodec
80 {
81         using tag_t = Tag<IE, true>;
82         static bool inline is_matched(tag_value_t _tag) {return _tag == tag_t::value();}
83
84         static void inline run(IE const& ie, EncoderCtx& ctx)
85         {
86                 auto & buffer = ctx.refBuffer();
87
88                 tag_t::encode(ctx);
89     u8* len_ptr = buffer.advance(1); //reserve for the length
90
91                 Element<typename IE::parent_t>::run(static_cast<typename IE::parent_t const&>(ie), ctx);
92
93     size_t len = buffer.begin() - len_ptr - 1;
94     if(len > 127)
95     {
96       len_ptr[0] = 0x80; //undefinite length form per X.690 8.1.3.6
97                   uint8_t buff[2] = {0}; // end-of-contents octets (X.690 8.1.5)
98                   buffer.putBytes(buff, sizeof(buff));
99     }
100     else
101     {
102       len_ptr[0] = static_cast<u8>(len); //one byte form per X.690 8.1.3.4
103     }
104         }
105
106         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
107         {
108                 if(tag_t::value() != tag)
109                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
110                 else
111                 {
112                         auto & buffer = ctx.refBuffer();
113                         size_t length = Length::decode(ctx);
114
115       ASN_DECODER_TRACE("EX<tag=0x%x length=%zu> buffer: %s", static_cast<int>(tag), length, ctx.refBuffer().toString());
116
117                         if(length == indefinite_length)
118                         {
119                                 Element<typename IE::parent_t>::run(static_cast<typename IE::parent_t&>(ie), ctx);
120
121                                 if(ctx)
122                                 {
123                                         uint8_t const* data_in = ctx.refBuffer().getBytes(2);
124                                         if(data_in && (data_in[0] || data_in[1]))
125                                         {
126                                                 ctx.refErrorCtx().errorWrongEndOfContent();
127                                         }
128                                 }
129                         }
130                         else
131                         {
132                                 if (buffer.getBytesLeft() < length)
133                                 {
134                                         ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), length);
135                                 }
136                                 else
137                                 {
138                                         DecoderCtx::buf_type::pointer end = buffer.end();
139                                         buffer.set_end(buffer.begin() + length);
140
141                                         Element<typename IE::parent_t>::run(static_cast<typename IE::parent_t&>(ie), ctx);
142
143                                         buffer.set_end(end);
144                                 }
145                         }
146
147                 }
148         }
149 };
150
151 /***************************************************************************************
152 * BOOLEAN: Encoding the boolean type  (X.690 8.2)
153 ***************************************************************************************/
154 template <class IE>
155 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_BOOLEAN> >
156 {
157         using tag_t = Tag<IE, false>;
158
159         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();}
160
161         static void inline run(IE const& ie, EncoderCtx& ctx)
162         {
163                 tag_t::encode(ctx);
164                 Length::encode(1, ctx);
165                 if(ie.get())
166                         Tools::put_bytes(0xFF, 1, ctx);
167                 else
168                         Tools::put_bytes(0, 1, ctx);
169         }
170
171         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
172         {
173                 if(tag_t::value() != tag)
174                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
175                 else
176                 {
177                         size_t length = Length::decode(ctx);
178                         if(length != 1)
179                         {
180                                 ctx.refErrorCtx().sizeRangeError(length, 1, 1);
181                         }
182                         else
183                         {
184         ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
185                                 uint8_t value;
186                                 Tools::get_bytes(value, 1, ctx);
187                                 ie.set(value > 0);
188                         }
189                 }
190         }
191 };
192 /***************************************************************************************
193 * INTEGER: Encoding the integer type  (X.690 8.3)
194 ***************************************************************************************/
195 template <class IE>
196 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_INTEGER> >
197 {
198         using tag_t = Tag<IE, false>;
199
200         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();}
201
202         static void inline run(IE const& ie, EncoderCtx& ctx)
203         {
204                 tag_t::encode(ctx);
205                 size_t length = Length::get(ie.get());
206                 Length::encode(length, ctx);
207                 Tools::put_bytes(ie.get(), length, ctx);
208         }
209         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
210         {
211                 if(tag_t::value() != tag)
212     {
213                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
214     }
215                 else
216                 {
217                         size_t length = Length::decode(ctx);
218                         if(!length || length == indefinite_length)
219                                 ctx.refErrorCtx().sizeRangeError(length);
220                         else
221                         {
222         ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
223                                 typename IE::value_type value;
224                                 Tools::get_bytes(value, length, ctx);
225                                 ie.set(value);
226                         }
227                 }
228         }
229 };
230 /***************************************************************************************
231 * ENUMERATED: Encoding the enumerated type  (X.690 8.4)
232 ***************************************************************************************/
233 template <class IE>
234 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_ENUMERATED> >
235 {
236         using tag_t = Tag<IE, false>;
237
238         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();}
239
240         static void inline run(IE const& ie, EncoderCtx& ctx)
241         {
242                 tag_t::encode(ctx);
243                 size_t length = Length::get(ie.get());
244                 Length::encode(length, ctx);
245                 Tools::put_bytes(ie.get(), length, ctx);
246         }
247         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
248         {
249                 if(tag_t::value() != tag)
250                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
251                 else
252                 {
253                         size_t length = Length::decode(ctx);
254                         if(!length || length == indefinite_length)
255                                 ctx.refErrorCtx().sizeRangeError(length);
256                         else
257                         {
258         ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
259                                 typename IE::value_type value;
260                                 Tools::get_bytes(value, length, ctx);
261                                 ie.set(value);
262                         }
263                 }
264         }
265 };
266 /***************************************************************************************
267 * REAL: Encoding the real type  (X.690 8.5)
268 ***************************************************************************************/
269 //missing...
270 /***************************************************************************************
271 * BIT STRING: Encoding the bitstring type (X.690 8.6)
272 ***************************************************************************************/
273 template <class IE>
274 struct ElementType<IE, std::enable_if_t<(IE::ie_type == element_type::T_BITSTRING)> >
275 {
276         using tag_t = Tag<IE, false>;
277         using ctag_t = Tag<IE, true>;
278
279         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value() || tag == ctag_t::value();}
280
281         static void inline run(IE const& ie, EncoderCtx& ctx)
282         {
283                 tag_t::encode(ctx);
284
285                 uint8_t tail = ie.get_bitqty() % 8;
286
287                 size_t length = ie.get_buffer().size();
288                 Length::encode(length + 1, ctx);
289
290                 auto & buffer = ctx.refBuffer();
291                 buffer.putByte((8 - tail) & 0x7F);
292
293                 if (tail)
294                 {
295                         buffer.putBytes(ie.get_buffer().data(), length - 1);
296                         u8 last_byte = *(ie.get_buffer().data() + length - 1);
297
298                         last_byte <<= 8 - tail;
299                         buffer.putBytes(&last_byte, 1);
300                 }
301                 else
302                 {
303                         buffer.putBytes(ie.get_buffer().data(), length);
304                 }
305         }
306         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
307         {
308                 ie.clear();
309                 if(tag_t::value() == tag)
310                 {
311                         size_t length = Length::decode(ctx);
312                         if(!length || length == indefinite_length)
313                         {
314                                 ctx.refErrorCtx().sizeRangeError(length);
315                         }
316                         else
317                         {
318                                 ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
319                                 uint8_t const* data_in = ctx.refBuffer().getBytes(length);
320                                 if(data_in)
321                                 {
322                                         size_t len_bytes = length - 1;
323                                         size_t bitqty    = len_bytes << 3;
324
325                                         if((data_in[0] & 0x80) || (bitqty < data_in[0]))
326                                         {
327                                                 ctx.refErrorCtx().valueRangeError(data_in[0]);
328                                         }
329                                         else
330                                         {
331                                                 bitqty = bitqty - data_in[0];
332                                                 uint8_t* data_out = ctx.refAllocator().alloc_bytes(len_bytes);
333                                                 if (data_out)
334                                                 {
335                                                         memcpy(data_out, &data_in[1], len_bytes);
336                                                         const u8 shift = bitqty % 8;
337                                                         if (shift)
338                                                         {
339                                                                 data_out[len_bytes - 1] >>= 8 - shift;
340                                                         }
341                                                         ie.set_buffer(bitqty, data_out);
342                                                 }
343                                                 else
344                                                 {
345                                                         ctx.refErrorCtx().allocatorNoMem(0, len_bytes);
346                                                 }
347                                         }
348                                 }
349                         }
350                 }
351                 else if(ctag_t::value() == tag)
352                 {
353                         //todo: implement the segmented data
354                         ctx.refErrorCtx().errorUnsupported();
355                 }
356                 else
357                 {
358                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
359                 }
360         }
361 };
362 /***************************************************************************************
363 * OCTET STRING: Encoding the octetstring type (X.690 8.7)
364 * Restricted Character string types (X.690 8.23)
365 ***************************************************************************************/
366 template <class IE>
367 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_OCTETSTRING> >
368 {
369         using tag_t = Tag<IE, false>;
370         using ctag_t = Tag<IE, true>;
371
372         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value() || tag == ctag_t::value();}
373
374         static void inline run(IE const& ie, EncoderCtx& ctx)
375         {
376                 tag_t::encode(ctx);
377                 size_t length = ie.get().size();
378                 Length::encode(length, ctx);
379                 ctx.refBuffer().putBytes(ie.get().data(), length);
380         }
381         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
382         {
383                 ie.clear();
384                 if(tag_t::value() == tag)
385                 {
386                         size_t length = Length::decode(ctx);
387                         if(length == indefinite_length)
388                         {
389                                 ctx.refErrorCtx().sizeRangeError(length);
390                         }
391                         else
392                         {
393         ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
394                                 uint8_t const* data_in = ctx.refBuffer().getBytes(length);
395                                 if(data_in)
396                                 {
397                                         ie.set(length, data_in);
398                                 }
399                         }
400                 }
401                 else if(ctag_t::value() == tag)
402                 {
403                         //todo: implement the segmented data
404                         ctx.refErrorCtx().errorUnsupported();
405                 }
406                 else
407                 {
408                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
409                 }
410         }
411 };
412 /***************************************************************************************
413 * NULL: Encoding the null type (X.690 8.8)
414 ***************************************************************************************/
415 template <class IE>
416 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_NULL> >
417 {
418         using tag_t = Tag<IE, false>;
419
420         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();}
421
422         static void inline run(IE const& ie, EncoderCtx& ctx)
423         {
424                 tag_t::encode(ctx);
425                 Length::encode(0, ctx);
426         }
427
428         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
429         {
430                 if(tag_t::value() != tag)
431                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
432                 else
433                 {
434                         size_t length = Length::decode(ctx);
435                         if(length)
436                                 ctx.refErrorCtx().sizeRangeError(length);
437       ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
438                 }
439         }
440 };
441 /***************************************************************************************
442 * SEQUENCE: Encoding the sequence type (X.690 8.9)
443 * SET:          Encoding the set type (X.690 8.11)
444 ***************************************************************************************/
445 template <class IE>
446 struct ElementType<IE, std::enable_if_t<(IE::ie_type == element_type::T_SEQUENCE) || (IE::ie_type == element_type::T_SET)> >
447 {
448         using tag_t = Tag<IE, true>;
449
450         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();}
451
452         static void inline run(IE const& ie, EncoderCtx& ctx)
453         {
454     auto & buffer = ctx.refBuffer();
455
456                 tag_t::encode(ctx);
457     u8* len_ptr = buffer.advance(1); //reserve for the length
458
459                 VisitorEncoderSeq<IE> ve(ctx, ie);
460                 ie.encode(ve);
461
462     size_t len = buffer.begin() - len_ptr - 1;
463     if(len > 127)
464     {
465       len_ptr[0] = 0x80; //undefinite length form per X.690 8.1.3.6
466                   uint8_t buff[2] = {0}; // end-of-contents octets (X.690 8.1.5)
467                   buffer.putBytes(buff, sizeof(buff));
468     }
469     else
470       len_ptr[0] = static_cast<u8>(len); //one byte form per X.690 8.1.3.4
471         }
472
473         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) //todo: support arbitrary order of IEs in SET
474         {
475                 if(tag_t::value() != tag)
476                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
477                 else
478                 {
479                         VisitorDecoderSeq<IE> vd(ctx, ie);
480                         auto & buffer = ctx.refBuffer();
481
482                         size_t length = Length::decode(ctx);
483
484       ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
485
486                         if(length == indefinite_length)
487                         {
488                                 ie.decode(vd);
489                                 if(ctx)
490                                 {
491                                         if(invalid_tag != vd.get_unhandled_tag())
492                                         {
493                                                 tag_value_t _tag = vd.get_unhandled_tag();
494                                                 if(IE::constraint_t::extended) //skip the unknown extension now
495                                                 {
496                                                         tag_value_t const* tag_ptr = &_tag;
497                                                         size_t _length;
498                                                         do
499                                                         {
500                                                                 _tag = OpenType::decode(ctx, _length, tag_ptr);
501                                                                 tag_ptr = nullptr;
502
503                                                         } while(ctx && !(_tag == 0 && _length == 0));
504                                                 }
505                                                 else // it should be the end-of-contents octets (8.1.5)
506                                                 {
507                                                         uint8_t const* data_in = ctx.refBuffer().getBytes(1);
508                                                         if(data_in && (_tag || data_in[0]))
509                                                         {
510                                                                 ctx.refErrorCtx().errorWrongEndOfContent();
511                                                         }
512                                                 }
513                                         }
514                                         else
515                                         {
516                                                 uint8_t const* data_in = ctx.refBuffer().getBytes(2);
517                                                 if(data_in && (data_in[0] || data_in[1]))
518                                                 {
519                                                         ctx.refErrorCtx().errorWrongEndOfContent();
520                                                 }
521                                         }
522                                 }
523                         }
524                         else
525                         {
526                                 if (buffer.getBytesLeft() < length)
527                                 {
528                                         ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), length);
529                                 }
530                                 else
531                                 {
532                                         DecoderCtx::buf_type::pointer end = buffer.end();
533                                         buffer.set_end(buffer.begin() + length);
534                                         ie.decode(vd);
535                                         tag_value_t _tag = vd.get_unhandled_tag();
536                                         if(invalid_tag != _tag)
537                                         {
538                                                 if(IE::constraint_t::extended) //skip the unknown extension now
539                                                 {
540                                                         tag_value_t const* tag_ptr = &_tag;
541                                                         size_t _length;
542                                                         do
543                                                         {
544                                                                 _tag = OpenType::decode(ctx, _length, tag_ptr);
545                                                                 tag_ptr = nullptr;
546
547                                                         } while(ctx && buffer.getBytesLeft() > 0);
548                                                 }
549                                                 else
550                                                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag)); // unexpected tag
551                                         }
552                                         buffer.set_end(end);
553                                 }
554                         }
555
556                 }
557         }
558 };
559 /***************************************************************************************
560 * SEQUENCE OF:  Encoding the sequence-of type (X.690 8.10)
561 * SET OF:               Encoding the set-of type (X.690 8.12)
562 ***************************************************************************************/
563 template <class IE>
564 struct ElementType<IE, std::enable_if_t<(IE::ie_type == element_type::T_SEQUENCE_OF) || (IE::ie_type == element_type::T_SET_OF)> >
565 {
566         using tag_t = Tag<IE, true>;
567
568         static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();}
569
570         static void inline run(IE const& ie, EncoderCtx& ctx)
571         {
572     auto & buffer = ctx.refBuffer();
573
574                 tag_t::encode(ctx);
575     u8* len_ptr = buffer.advance(1); //reserve for the length
576
577                 for (auto& elem : ie)
578                 {
579                         Element<typename IE::element_t>::run(elem, ctx);
580                 }
581
582     size_t len = buffer.begin() - len_ptr - 1;
583     if(len > 127)
584     {
585       len_ptr[0] = 0x80; //undefinite length form per X.690 8.1.3.6
586                   uint8_t buff[2] = {0}; // end-of-contents octets (X.690 8.1.5)
587                   buffer.putBytes(buff, sizeof(buff));
588     }
589     else
590       len_ptr[0] = static_cast<u8>(len); //one byte form per X.690 8.1.3.4
591         }
592         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
593         {
594                 ie.clear();
595
596                 if(tag_t::value() != tag)
597                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
598                 else
599                 {
600                         auto & buffer = ctx.refBuffer();
601
602                         size_t length = Length::decode(ctx);
603
604       ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
605
606                         if(length == indefinite_length)
607                         {
608                                 tag_value_t elm_tag = get_tag(ctx);
609
610                                 while(ctx && Element<typename IE::element_t>::is_matched(elm_tag))
611                                 {
612                                         add_element(ie, ctx, &elm_tag);
613                                         elm_tag = get_tag(ctx);
614                                 }
615
616                                 if(ctx)
617                                 {
618                                         uint8_t const* data_in = ctx.refBuffer().getBytes(1);
619                                         if(data_in && (elm_tag || data_in[0]))
620                                         {
621                                                 ctx.refErrorCtx().errorWrongEndOfContent();
622                                         }
623                                 }
624                         }
625                         else
626                         {
627                                 if (buffer.getBytesLeft() < length)
628                                 {
629                                         ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), length);
630                                 }
631                                 else
632                                 {
633                                         DecoderCtx::buf_type::pointer end = buffer.end();
634                                         buffer.set_end(buffer.begin() + length);
635
636                                         while(ctx && buffer.getBytesLeft() > 0)
637                                                 add_element(ie, ctx);
638
639                                         buffer.set_end(end);
640                                 }
641                         }
642                 }
643         }
644
645 private:
646         static void inline add_element(IE& ie, DecoderCtx& ctx, tag_value_t const* elm_tag = nullptr)
647         {
648                 uint8_t* data = ctx.refAllocator().alloc_bytes(sizeof(typename IE::value_type));
649                 if (data)
650                 {
651                         typename IE::value_type * v = new (data) typename IE::value_type;
652                         v->clear();
653                         ie.push_back(*v);
654                         Element<typename IE::element_t>::run(*v, ctx, elm_tag);
655                 }
656                 else
657                 {
658                         ctx.refErrorCtx().allocatorNoMem(0, sizeof(typename IE::value_type));
659                 }
660         }
661 };
662
663 /***************************************************************************************
664 * CHOICE: Encoding the choice type
665 ***************************************************************************************/
666 struct ChoiceVisitorEncoder
667 {
668         ChoiceVisitorEncoder(EncoderCtx& ctx) : m_ctx(ctx) {}
669
670         template<typename IE>
671         bool operator()(IE const& ie)
672         {
673                 Element<IE>::run(ie, m_ctx);
674                 return static_cast<bool>(m_ctx);
675         }
676
677         EncoderCtx&             m_ctx;
678 };
679
680 struct ChoiceVisitorDecoder
681 {
682         ChoiceVisitorDecoder(DecoderCtx& ctx, tag_value_t tag) : m_ctx(ctx), m_tag(tag) {}
683
684         template<typename IE> bool operator()(IE& ie)
685         {
686                 Element<IE>::run(ie, m_ctx, &m_tag);
687                 return static_cast<bool>(m_ctx);
688         }
689
690         DecoderCtx&             m_ctx;
691         tag_value_t     m_tag;
692 };
693
694 template <class IE>
695 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_CHOICE && IE::asn_identifier_t::class_type == class_type_t::UNSPECIFIED> >
696 {
697         struct Selector
698         {
699                 Selector(tag_value_t tag) : m_tag(tag) {}
700
701                 template<typename ELM> void operator()(size_t idx)
702                 {
703                         if(!m_valid && Element<ELM>::is_matched(m_tag))
704                         {
705                                 m_index = idx;
706                                 m_valid = true;
707                         }
708                 }
709
710                 size_t get_idx() const {return m_index;}
711                 bool is_valid() const {return m_valid;}
712
713         private:
714                 tag_value_t m_tag;
715                 size_t          m_index {0};
716                 bool            m_valid {false};
717         };
718
719   static bool inline is_matched(tag_value_t tag)
720         {
721     Selector selector {tag};
722         IE::enumerate(selector);
723         return selector.is_valid();
724         }
725
726         static void inline run(IE const& ie, EncoderCtx& ctx)
727         {
728                 ChoiceVisitorEncoder ve(ctx);
729
730                 if(ctx && !ie.encode(ve))
731                         ctx.refErrorCtx().tagError(ie.get_index());
732         }
733         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
734         {
735                 ie.clear();
736
737                 Selector selector {tag};
738                 IE::enumerate(selector);
739
740                 if(!selector.is_valid())
741                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
742                 else
743                 {
744                         ChoiceVisitorDecoder vd {ctx, tag};
745                         if(ctx && !ie.decode(selector.get_idx(), vd))
746                                 ctx.refErrorCtx().tagError(ie.get_index());
747                 }
748         }
749 };
750
751 template <class IE>
752 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_CHOICE && IE::asn_identifier_t::class_type != class_type_t::UNSPECIFIED> >
753 {
754         static bool inline is_matched(tag_value_t _tag) {return ExplicitCodec<IE>::is_matched(_tag);}
755
756         static void inline run(IE const& ie, EncoderCtx& ctx)
757         {
758     ExplicitCodec<IE>::run(ie, ctx);
759         }
760
761         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
762         {
763     ExplicitCodec<IE>::run(ie, ctx, tag);
764         }
765 };
766
767 /***************************************************************************************
768 * IE_OBJECT_IDENTIFIER: Encoding the object identifier type
769 ***************************************************************************************/
770 template <class IE>
771 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_OBJECTIDENTIFIER> >
772 {
773         using tag_t = Tag<IE, false>;
774
775         static bool inline is_matched(tag_value_t _tag) {return _tag == tag_t::value();}
776
777         static void inline run(IE const& ie, EncoderCtx& ctx)
778         {
779                 tag_t::encode(ctx);
780                 size_t length = ie.get().size();
781                 Length::encode(length, ctx);
782                 ctx.refBuffer().putBytes(ie.get().data(), length);
783         }
784         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
785         {
786                 ie.clear();
787                 if(tag_t::value() == tag)
788                 {
789                         size_t length = Length::decode(ctx);
790                         if(!length || length == indefinite_length)
791                         {
792                                 ctx.refErrorCtx().sizeRangeError(length);
793                         }
794                         else
795                         {
796         ASN_DECODER_TRACE("IE<type=%d name=%s tag=0x%x length=%zu> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), static_cast<int>(tag), length, ctx.refBuffer().toString());
797                                 uint8_t const* data_in = ctx.refBuffer().getBytes(length);
798                                 if(data_in)
799                                 {
800                                         ie.set(length, data_in);
801                                 }
802                         }
803                 }
804                 else
805                 {
806                         ctx.refErrorCtx().tagError(static_cast<uint32_t>(tag));
807                 }
808         }
809 };
810
811 /***************************************************************************************
812 * T_OBJFIELD_FTV
813 ***************************************************************************************/
814 template <class IE>
815 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_OBJFIELD_FTV> >
816 {
817         using tag_t = Tag<IE, false>;
818
819         static bool inline is_matched(tag_value_t _tag) {return _tag == tag_t::value();}
820 };
821
822 /***************************************************************************************
823 * T_OBJFIELD_TF
824 ***************************************************************************************/
825 template <class IE>
826 struct ElementType<IE, std::enable_if_t<IE::ie_type == element_type::T_OBJFIELD_TF> >
827 {
828         struct Selector
829         {
830                 Selector(tag_value_t tag) : m_tag(tag) {}
831
832                 template<typename ELM> void operator()(size_t idx)
833                 {
834                         if(Element<ELM>::is_matched(m_tag))
835                         {
836                                 m_index = idx;
837                                 m_valid = true;
838                         }
839                 }
840
841                 size_t get_idx() const {return m_index;}
842                 bool is_valid() const {return m_valid;}
843
844         private:
845                 tag_value_t m_tag;
846                 size_t          m_index {0};
847                 bool            m_valid {false};
848         };
849
850         static bool inline is_matched(tag_value_t tag)
851         {
852                 Selector selector(tag);
853                 IE::enumerate(selector);
854
855                 return selector.is_valid();
856         }
857 };
858
859 /***************************************************************************************
860 * Identifier
861 ***************************************************************************************/
862 template <class IE, class Enabler = void>
863 struct Identifier
864 {
865         static bool inline is_matched(tag_value_t _tag)
866         {
867                 return ElementType<IE>::is_matched(_tag);
868         }
869
870         static void inline run(IE const& ie, EncoderCtx& ctx)
871         {
872                 ElementType<IE>::run(ie, ctx);
873         }
874
875         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
876         {
877                 ElementType<IE>::run(ie, ctx, tag);
878         }
879 };
880
881 template <class IE>
882 struct Identifier<IE, std::enable_if_t<IE::asn_identifier_t::tag_type == tag_type_t::EXPLICIT> >
883 {
884         static bool inline is_matched(tag_value_t _tag) {return ExplicitCodec<IE>::is_matched(_tag);}
885
886         static void inline run(IE const& ie, EncoderCtx& ctx)
887         {
888     ExplicitCodec<IE>::run(ie, ctx);
889         }
890
891         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag)
892         {
893     ExplicitCodec<IE>::run(ie, ctx, tag);
894         }
895 };
896
897 /***************************************************************************************
898 * COMMON: Element
899 ***************************************************************************************/
900 template <class IE>
901 struct Element
902 {
903         static bool inline is_matched(tag_value_t _tag)
904         {
905                 return Identifier<IE>::is_matched(_tag);
906         }
907
908         static void inline run(IE const& ie, EncoderCtx& ctx)
909         {
910                 if (ctx)
911                 {
912                         ASN_ENCODER_TRACE("IE<type=%d name=%s> buffer: %s", static_cast<int>(IE::ie_type), IE::name(), ctx.refBuffer().toString());
913                         ctx.ie_name(IE::name());
914                         Identifier<IE>::run(ie, ctx);
915                 }
916         }
917         static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t const* tag_ptr = nullptr)
918         {
919                 if (ctx)
920                 {
921                         ctx.ie_name(IE::name());
922
923                         tag_value_t tag = tag_ptr ? *tag_ptr : get_tag(ctx);
924                         if(ctx)
925                                 Identifier<IE>::run(ie, ctx, tag);
926                 }
927         }
928 };
929
930 } //namespace ber
931 } //namespace asn