Enhanced SIM for E2AP v1 for TS UC
[sim/e2-interface.git] / e2sim / e2apv1sim / src / ASN1 / asn / ber / tag.hpp
diff --git a/e2sim/e2apv1sim/src/ASN1/asn/ber/tag.hpp b/e2sim/e2apv1sim/src/ASN1/asn/ber/tag.hpp
new file mode 100755 (executable)
index 0000000..dba9733
--- /dev/null
@@ -0,0 +1,163 @@
+#pragma once
+/******************************************************************************
+*
+*   Copyright (c) 2019 AT&T Intellectual Property.
+*   Copyright (c) 2018-2019 Nokia.
+*
+*   Licensed under the Apache License, Version 2.0 (the "License");
+*   you may not use this file except in compliance with the License.
+*   You may obtain a copy of the License at
+*
+*       http://www.apache.org/licenses/LICENSE-2.0
+*
+*   Unless required by applicable law or agreed to in writing, software
+*   distributed under the License is distributed on an "AS IS" BASIS,
+*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*   See the License for the specific language governing permissions and
+*   limitations under the License.
+*
+******************************************************************************/
+
+// Standard Includes: ANSI C/C++, MSA, and Third-Party Libraries
+
+// Local Includes: Application specific classes, functions, and libraries
+
+#define IE_CLASS_SHIFT                         6
+#define IE_PC_SHIFT                                    5
+#define IE_BIG_TAG_FST_OCTET           0b011111
+
+namespace asn {
+namespace ber {
+
+constexpr tag_value_t invalid_tag = std::numeric_limits<tag_value_t>::max();
+
+/***************************************************************************************
+* Tag
+***************************************************************************************/
+template <class IE, bool constructed, class Enable=void>
+struct Tag;
+
+template <class IE, bool constructed>
+struct Tag<IE, constructed, std::enable_if_t< (IE::asn_identifier_t::tag_value < 31) > >
+{
+       static constexpr tag_value_t value()
+       {
+               tag_value_t v = static_cast<uint8_t>(IE::asn_identifier_t::class_type);
+               v <<= IE_CLASS_SHIFT;
+               v = constructed ? (v | (1u << IE_PC_SHIFT)) : v;
+               v |= static_cast<uint8_t>(IE::asn_identifier_t::tag_value);
+               return v;
+       }
+       
+       static void inline encode(EncoderCtx& ctx)
+       {
+               ctx.refBuffer().putByte(static_cast<uint8_t>(value()));
+       }
+};
+
+
+template <class IE, bool constructed>
+struct Tag<IE, constructed, std::enable_if_t< (IE::asn_identifier_t::tag_value >= 31) > >
+{
+       static constexpr tag_value_t value()
+       {
+               static_assert(IE::asn_identifier_t::tag_value > 0, "null tag value");
+               
+               tag_value_t v = static_cast<uint8_t>(IE::asn_identifier_t::class_type);
+               v <<= IE_CLASS_SHIFT;
+               v = constructed ? (v | (1u << IE_PC_SHIFT)) : v;
+               v |= IE_BIG_TAG_FST_OCTET;
+               
+               size_t leadbits = __builtin_clzll(IE::asn_identifier_t::tag_value);
+               tag_value_t tv = IE::asn_identifier_t::tag_value << leadbits;
+               size_t length = sizeof(tag_value_t)*CHAR_BIT - leadbits;
+                               
+               size_t shift = sizeof(tag_value_t)*CHAR_BIT - 7;
+                       
+               size_t lb = length % 7;
+               if(lb)
+               {
+                       v <<= 8;
+                       v |= 0x80;
+                       v |= static_cast<uint8_t>(tv >> (shift + 7 - lb));
+                       tv <<= lb;
+                       length -= lb;
+               }
+               
+               while(length)
+               {
+                       v <<= 8;
+                       v |= 0x80;
+                       v |= static_cast<uint8_t>(tv >> shift);
+                       tv <<= 7;
+                       length -= 7;
+               }
+               v &= ((tag_value_t)-1) & ~((tag_value_t) 0x80);
+               
+               return v;
+       }
+       
+       static void inline encode(EncoderCtx& ctx)
+       {
+               size_t size = 0;
+               tag_value_t tv = data(size);
+               ctx.refBuffer().putBytes(reinterpret_cast<uint8_t*>(&tv), size);
+       }
+       
+private:
+       
+       static constexpr tag_value_t data(size_t& size)
+       {
+               tag_value_t rv = 0;
+               tag_value_t tv = value();
+               size = sizeof(tag_value_t) - (__builtin_clzll(tv) >> 3);
+               
+               uint8_t* ptr = reinterpret_cast<uint8_t*>(&rv);
+               
+               size_t shift = (size - 1) * 8;
+               for(size_t i = 0; i < size; ++i)
+               {
+                       ptr[i] = static_cast<uint8_t>(tv >> shift);
+                       shift -= 8;
+               }
+               
+               return rv;
+       }
+};
+
+inline
+tag_value_t get_tag(DecoderCtx& ctx)
+{
+       tag_value_t rv = 0;
+       auto & buffer = ctx.refBuffer();
+       uint8_t const* data = buffer.getBytes(1);
+       
+       if (data)
+       {
+               rv = data[0];
+               if((data[0] & 0x1F) == IE_BIG_TAG_FST_OCTET)
+               {
+                       size_t limit = sizeof(tag_value_t) - 1;
+                       while((data = buffer.getBytes(1)))
+                       {
+                               if(!limit)
+                               {
+                                       ctx.refErrorCtx().sizeRangeError(0);
+                                       break;
+                               }
+                               
+                               rv <<= 8;
+                               rv |= data[0];
+                               --limit;
+                               
+                               if(!(data[0] & 0x80))
+                                       break;
+                       }
+               }
+       }
+       return rv;
+}
+
+} //namespace ber
+} //namespace asn
+