Enhanced SIM for E2AP v1 for TS UC
[sim/e2-interface.git] / e2sim / e2apv1sim / src / ASN1 / asn / ber / tag.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
25 #define IE_CLASS_SHIFT                          6
26 #define IE_PC_SHIFT                                     5
27 #define IE_BIG_TAG_FST_OCTET            0b011111
28
29 namespace asn {
30 namespace ber {
31
32 constexpr tag_value_t invalid_tag = std::numeric_limits<tag_value_t>::max();
33
34 /***************************************************************************************
35 * Tag
36 ***************************************************************************************/
37 template <class IE, bool constructed, class Enable=void>
38 struct Tag;
39
40 template <class IE, bool constructed>
41 struct Tag<IE, constructed, std::enable_if_t< (IE::asn_identifier_t::tag_value < 31) > >
42 {
43         static constexpr tag_value_t value()
44         {
45                 tag_value_t v = static_cast<uint8_t>(IE::asn_identifier_t::class_type);
46                 v <<= IE_CLASS_SHIFT;
47                 v = constructed ? (v | (1u << IE_PC_SHIFT)) : v;
48                 v |= static_cast<uint8_t>(IE::asn_identifier_t::tag_value);
49                 return v;
50         }
51         
52         static void inline encode(EncoderCtx& ctx)
53         {
54                 ctx.refBuffer().putByte(static_cast<uint8_t>(value()));
55         }
56 };
57
58
59 template <class IE, bool constructed>
60 struct Tag<IE, constructed, std::enable_if_t< (IE::asn_identifier_t::tag_value >= 31) > >
61 {
62         static constexpr tag_value_t value()
63         {
64                 static_assert(IE::asn_identifier_t::tag_value > 0, "null tag value");
65                 
66                 tag_value_t v = static_cast<uint8_t>(IE::asn_identifier_t::class_type);
67                 v <<= IE_CLASS_SHIFT;
68                 v = constructed ? (v | (1u << IE_PC_SHIFT)) : v;
69                 v |= IE_BIG_TAG_FST_OCTET;
70                 
71                 size_t leadbits = __builtin_clzll(IE::asn_identifier_t::tag_value);
72                 tag_value_t tv = IE::asn_identifier_t::tag_value << leadbits;
73                 size_t length = sizeof(tag_value_t)*CHAR_BIT - leadbits;
74                                 
75                 size_t shift = sizeof(tag_value_t)*CHAR_BIT - 7;
76                         
77                 size_t lb = length % 7;
78                 if(lb)
79                 {
80                         v <<= 8;
81                         v |= 0x80;
82                         v |= static_cast<uint8_t>(tv >> (shift + 7 - lb));
83                         tv <<= lb;
84                         length -= lb;
85                 }
86                 
87                 while(length)
88                 {
89                         v <<= 8;
90                         v |= 0x80;
91                         v |= static_cast<uint8_t>(tv >> shift);
92                         tv <<= 7;
93                         length -= 7;
94                 }
95                 v &= ((tag_value_t)-1) & ~((tag_value_t) 0x80);
96                 
97                 return v;
98         }
99         
100         static void inline encode(EncoderCtx& ctx)
101         {
102                 size_t size = 0;
103                 tag_value_t tv = data(size);
104                 ctx.refBuffer().putBytes(reinterpret_cast<uint8_t*>(&tv), size);
105         }
106         
107 private:
108         
109         static constexpr tag_value_t data(size_t& size)
110         {
111                 tag_value_t rv = 0;
112                 tag_value_t tv = value();
113                 size = sizeof(tag_value_t) - (__builtin_clzll(tv) >> 3);
114                 
115                 uint8_t* ptr = reinterpret_cast<uint8_t*>(&rv);
116                 
117                 size_t shift = (size - 1) * 8;
118                 for(size_t i = 0; i < size; ++i)
119                 {
120                         ptr[i] = static_cast<uint8_t>(tv >> shift);
121                         shift -= 8;
122                 }
123                 
124                 return rv;
125         }
126 };
127
128 inline
129 tag_value_t get_tag(DecoderCtx& ctx)
130 {
131         tag_value_t rv = 0;
132         auto & buffer = ctx.refBuffer();
133         uint8_t const* data = buffer.getBytes(1);
134         
135         if (data)
136         {
137                 rv = data[0];
138                 if((data[0] & 0x1F) == IE_BIG_TAG_FST_OCTET)
139                 {
140                         size_t limit = sizeof(tag_value_t) - 1;
141                         while((data = buffer.getBytes(1)))
142                         {
143                                 if(!limit)
144                                 {
145                                         ctx.refErrorCtx().sizeRangeError(0);
146                                         break;
147                                 }
148                                 
149                                 rv <<= 8;
150                                 rv |= data[0];
151                                 --limit;
152                                 
153                                 if(!(data[0] & 0x80))
154                                         break;
155                         }
156                 }
157         }
158         return rv;
159 }
160
161 } //namespace ber
162 } //namespace asn
163