X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=sim%2Fe2-interface.git;a=blobdiff_plain;f=e2sim%2Fe2apv1sim%2Fricsim%2Fsrc%2FASN1%2Fasn%2Fbuffer.hpp;fp=e2sim%2Fe2apv1sim%2Fricsim%2Fsrc%2FASN1%2Fasn%2Fbuffer.hpp;h=4022b48d09f3ea3b0c7e2d328df839d7a084d058;hp=0000000000000000000000000000000000000000;hb=3ebf932d23dcbec9ed19f4a51f9d00a0a54f5124;hpb=6896318f2b4ff01b4a88b16019c3dc93b0b693f5 diff --git a/e2sim/e2apv1sim/ricsim/src/ASN1/asn/buffer.hpp b/e2sim/e2apv1sim/ricsim/src/ASN1/asn/buffer.hpp new file mode 100755 index 0000000..4022b48 --- /dev/null +++ b/e2sim/e2apv1sim/ricsim/src/ASN1/asn/buffer.hpp @@ -0,0 +1,689 @@ +#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 +#include + +// Local Includes: Application specific classes, functions, and libraries +#include "asn/error_context.hpp" +#include "value_traits.hpp" + +//#define CODEC_BIT_TRACE_ENABLE +#ifdef CODEC_BIT_TRACE_ENABLE + #define CODEC_BIT_TRACE(FMT, args...) printf("%s[%u]:" FMT "\n", std::strrchr(__FILE__, '/') + 1, __LINE__, ##args) +#else + #define CODEC_BIT_TRACE(...) +#endif + +namespace asn { + +template +struct bit_accessor; + +template +struct bit_accessor_cross_byte; + +template +class buffer +{ +public: + typedef PTR pointer; + + explicit buffer(error_context& err) + : m_errCtx(err) + {} + + void reset(pointer data, u32 size) + { + m_start = data; + m_end = m_start + size; + m_current = m_start; + m_shift = 0; + } + + u32 getOffset() const { return begin() - m_start; } + + u32 getBytesLeft() const { return end() - begin(); } + u32 getBytesUsed() const { return getOffset() + (get_shift() ? 1 : 0); } + + u8 get_shift() const { return m_shift; } + void reset_shift() { m_shift = 0; } + void byte_align() { if (get_shift()) { m_shift = 0; ++m_current; } } + + pointer advance(u32 delta) { pointer p = begin(); m_current += delta; return p; } + + pointer begin() const { return m_current; } + + void set_begin(pointer ptr, u8 bit_shift) + { + if (m_start <= ptr && ptr <= end()) + { + m_current = ptr; + m_shift = bit_shift; + } + } + + pointer end() const { return m_end; } + void set_end(pointer v) { m_end = v; } + + bool checkAlignment(char const* name, u8 const mask = 0xFF) + { + if (0 == (get_shift() & mask)) return true; + m_errCtx.alignmentError(name, get_shift()); + return false; + } + + bool checkBytesLeft(char const* name, u32 const num_bytes) + { + if (getBytesLeft() >= num_bytes) return true; + m_errCtx.lengthErrorBytes(name, getBytesLeft(), num_bytes); + return false; + } + + bool checkBitsLeft(char const* name, u32 const num_bits) + { + if (getBitsLeft() >= num_bits) return true; + m_errCtx.lengthErrorBits(name, getBitsLeft(), num_bits); + return false; + } + + bool checkBytesAndAlignment(char const* name, u32 const num_bytes, u8 const mask = 0xFF) + { + if (getBytesLeft() >= num_bytes) + { + if (0 == (get_shift() & mask)) return true; + m_errCtx.alignmentError(name, get_shift()); + } + else + { + m_errCtx.lengthErrorBytes(name, getBytesLeft(), num_bytes); + } + return false; + } + + pointer getBytes(char const* name, u32 num_bytes) + { + if (checkBytesAndAlignment(name, num_bytes)) + { + return advance(num_bytes); + } + return nullptr; + } + + //NOTE! num_bytes should be set to minimal number of bytes expected + pointer getBytes(char const* name, u32 max_requested, u32& num_bytes) + { + if (checkAlignment(name)) + { + u32 const left = getBytesLeft(); + if (left >= num_bytes) + { + num_bytes = (left > max_requested) ? max_requested : left; + return advance(num_bytes); + } + + m_errCtx.lengthErrorBytes(name, getBytesLeft(), num_bytes); + } + return nullptr; + } + + bool putByte(char const* name, u8 byte) + { + if (checkBytesAndAlignment(name, 1)) + { + begin()[0] = byte; + ++m_current; + return true; + } + return false; + } + + bool putBytes(char const* name, void const* in, u32 num_bytes) + { + if (checkBytesAndAlignment(name, num_bytes)) + { + std::memcpy(begin(), in, num_bytes); + m_current += num_bytes; + return true; + } + return false; + } + + bool checkAlignment(u8 const mask = 0xFF) + { + if (0 == (get_shift() & mask)) return true; + m_errCtx.alignmentError(get_shift()); + return false; + } + + bool checkBytesLeft(u32 const num_bytes) + { + if (getBytesLeft() >= num_bytes) return true; + m_errCtx.lengthErrorBytes(getBytesLeft(), num_bytes); + return false; + } + + bool checkBitsLeft(u32 const num_bits) + { + if (getBitsLeft() >= num_bits) return true; + m_errCtx.lengthErrorBits(getBitsLeft(), num_bits); + return false; + } + + bool checkBytesAndAlignment(u32 const num_bytes, u8 const mask = 0xFF) + { + if (getBytesLeft() >= num_bytes) + { + if (0 == (get_shift() & mask)) return true; + m_errCtx.alignmentError(get_shift()); + } + else + { + m_errCtx.lengthErrorBytes(getBytesLeft(), num_bytes); + } + return false; + } + + pointer getBytes(u32 num_bytes) + { + if (checkBytesAndAlignment(num_bytes)) + { + return advance(num_bytes); + } + return nullptr; + } + + //NOTE! num_bytes should be set to minimal number of bytes expected + pointer getBytes(u32 max_requested, u32& num_bytes) + { + if (checkAlignment()) + { + u32 const left = getBytesLeft(); + if (left >= num_bytes) + { + num_bytes = (left > max_requested) ? max_requested : left; + return advance(num_bytes); + } + + m_errCtx.lengthErrorBytes(getBytesLeft(), num_bytes); + } + return nullptr; + } + + bool putByte(u8 byte) + { + if (checkBytesAndAlignment(1)) + { + begin()[0] = byte; + ++m_current; + return true; + } + return false; + } + + bool putBytes(void const* in, u32 num_bytes) + { + if (num_bytes) + { + if(checkBytesAndAlignment(num_bytes)) + { + std::memcpy(begin(), in, num_bytes); + m_current += num_bytes; + } + else + return false; + } + return true; + } + + char const* toString() const + { + static char sz[64]; + u8 const* p = begin(); + snprintf(sz, sizeof(sz), "%02X %02X %02X %02X [%02X]=%p@%u..%p -%u bits: +%u bytes", p[-4], p[-3], p[-2], p[-1], p[0], p + , getOffset(), end(), get_shift(), getBytesLeft()); + return sz; + } + +private: + template + friend class bit_accessor; + + template + friend struct bit_accessor_cross_byte; + + template + void push_u8(U value) { *m_current++ = static_cast(value); } + template + void put_u8(U value) { m_current[0] = static_cast(value); } + +//khxm68: TODO: won't compile without it. WTF?! +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + u8 get_u8() const { return m_current[0]; } +#pragma GCC diagnostic pop + u8 extract_u8(u8 value, u8 mask, u8 shift) const + { return (get_u8() & ~(mask << shift)) | ((value & mask) << shift); } + + u16 get_u16() const { return (static_cast(m_current[0]) << 8) | m_current[1]; } + u16 extract_u16(u16 value, u16 mask, u16 shift) const + { return (get_u16() & ~(mask << shift)) | ((value & mask) << shift); } + + u32 get_u24() const { return (static_cast(m_current[0]) << 16) | (static_cast(m_current[1]) << 8) | m_current[2]; } + u32 extract_u24(u32 value, u32 mask, u32 shift) const + { return (get_u24() & ~(mask << shift)) | ((value & mask) << shift); } + + u32 get_u32() const { return (static_cast(m_current[0]) << 24) | (static_cast(m_current[1]) << 16) | (static_cast(m_current[2]) << 8) | m_current[3]; } + u32 extract_u32(u32 value, u32 mask, u32 shift) const + { return (get_u32() & ~(mask << shift)) | ((value & mask) << shift); } + + u32 getBitsLeft() const { return begin() == end() ? 0 : (getBytesLeft()*8 - get_shift()); } + + void bit_advance(u8 num_bits) + { + m_shift += num_bits; + if (get_shift() > 7) + { + reset_shift(); + m_current++; + } + } + + pointer m_current; + pointer m_end; + pointer m_start; + u8 m_shift; + error_context& m_errCtx; +}; + +template //LSB 1..7 bits +struct bit_accessor +{ + static_assert(IE::length::value > 0 && IE::length::value < 8, "something wrong with traits!"); + + static void put(u8 value, buffer& buf) + { + u8 const mask = static_cast((1u << IE::length::value) - 1); + u8 const shift = buf.get_shift(); + u8 const data = buf.extract_u8(value, mask, shift); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%02X(%02X) mask=%04X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value); + } + + static u8 get(buffer& buf) + { + u8 const mask = static_cast((1u << IE::length::value) - 1); + u8 const shift = buf.get_shift(); + u8 const data = (buf.get_u8() >> shift) & mask; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%02X mask=%02X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value); + return data; + } +}; + +template //LSB 9..15 bits +struct bit_accessor +{ + static_assert(IE::length::value > 8 && IE::length::value < 16, "something wrong with traits!"); + + static void put(u16 value, buffer& buf) + { + u16 const mask = static_cast((1u << IE::length::value) - 1); + u16 const shift = buf.get_shift(); + u16 const data = buf.extract_u16(value, mask, shift); + buf.push_u8(data >> 8); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%04X(%04X) mask=%04X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 8); + } + + static u16 get(buffer& buf) + { + u16 const mask = static_cast((1u << IE::length::value) - 1); + u16 const shift = buf.get_shift(); + u16 const data = (buf.get_u16() >> shift) & mask; + buf.m_current += 1; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%04X mask=%04X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 8); + return data; + } +}; + +template //LSB 17..24 bits +struct bit_accessor +{ + static_assert(IE::length::value > 16 && IE::length::value <= 24, "something wrong with traits!"); + + static void put(u32 value, buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = buf.get_shift(); + u32 const data = buf.extract_u24(value, mask, shift); + + buf.push_u8(data >> 16); + buf.push_u8(data >> 8); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%06X(%06X) mask=%06X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 16); + } + + static u32 get(buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = buf.get_shift(); + u32 const data = (buf.get_u24() >> shift) & mask; + buf.m_current += 2; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%06X mask=%06X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 16); + return data; + } +}; + +template //LSB 25..31 bits +struct bit_accessor +{ + static_assert(IE::length::value > 24 && IE::length::value < 32, "something wrong with traits!"); + + static void put(u32 value, buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = buf.get_shift(); + u32 const data = buf.extract_u32(value, mask, shift); + + buf.push_u8(data >> 24); + buf.push_u8(data >> 16); + buf.push_u8(data >> 8); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%08X(%08X) mask=%08X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 24); + } + + static u32 get(buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = buf.get_shift(); + u32 const data = (buf.get_u32() >> shift) & mask; + buf.m_current += 3; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%08X mask=%08X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 24); + return data; + } +}; + + +template //MSB 1..7 bits +struct bit_accessor +{ + static_assert(IE::length::value > 0 && IE::length::value < 8, "something wrong with traits!"); + + static void put(u8 value, buffer& buf) + { + u8 const mask = static_cast((1u << IE::length::value) - 1); + u8 const shift = 8 - buf.get_shift() - IE::length::value; + u8 const data = buf.extract_u8(value, mask, shift); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%02X(%02X) mask=%04X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value); + } + + static u8 get(buffer& buf) + { + u8 const mask = static_cast((1u << IE::length::value) - 1); + u8 const shift = 8 - buf.get_shift() - IE::length::value; + u8 const data = (buf.get_u8() >> shift) & mask; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%02X mask=%02X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value); + return data; + } +}; + +template //MSB 9..15 bits +struct bit_accessor +{ + static_assert(IE::length::value > 8 && IE::length::value < 16, "something wrong with traits!"); + + static void put(u16 value, buffer& buf) + { + u16 const mask = static_cast((1u << IE::length::value) - 1); + u16 const shift = 16 - buf.get_shift() - IE::length::value; + u16 const data = buf.extract_u16(value, mask, shift); + + buf.push_u8(data >> 8); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%04X(%04X) mask=%04X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 8); + } + + static u16 get(buffer& buf) + { + u16 const mask = static_cast((1u << IE::length::value) - 1); + u16 const shift = 16 - buf.get_shift() - IE::length::value; + u16 const data = (buf.get_u16() >> shift) & mask; + buf.m_current += 1; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%04X mask=%04X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 8); + return data; + } +}; + + +template //MSB 17..24 bits +struct bit_accessor +{ + static_assert(IE::length::value > 16 && IE::length::value <= 24, "something wrong with traits!"); + + static void put(u32 value, buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = 24 - buf.get_shift() - IE::length::value; + u32 const data = buf.extract_u24(value, mask, shift); + + buf.push_u8(data >> 16); + buf.push_u8(data >> 8); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%06X(%06X) mask=%06X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 16); + } + + static u32 get(buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = 24 - buf.get_shift() - IE::length::value; + u32 const data = (buf.get_u24() >> shift) & mask; + buf.m_current += 2; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%06X mask=%06X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 16); + return data; + } +}; + +template //MSB 25..31 bits +struct bit_accessor +{ + static_assert(IE::length::value > 24 && IE::length::value < 32, "something wrong with traits!"); + + static void put(u32 value, buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = 32 - buf.get_shift() - IE::length::value; + u32 const data = buf.extract_u32(value, mask, shift); + + buf.push_u8(data >> 24); + buf.push_u8(data >> 16); + buf.push_u8(data >> 8); + buf.put_u8(data); + + CODEC_BIT_TRACE("put shift=%u(%u) data[%u]=%08X(%08X) mask=%08X: %s", shift, buf.get_shift() + , IE::length::value, data, value, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 24); + } + + static u32 get(buffer& buf) + { + u32 const mask = static_cast((1u << IE::length::value) - 1); + u32 const shift = 32 - buf.get_shift() - IE::length::value; + u32 const data = (buf.get_u32() >> shift) & mask; + buf.m_current += 3; + + CODEC_BIT_TRACE("get shift=%u(%u) data[%u]=%08X mask=%08X: %s", shift, buf.get_shift() + , IE::length::value, data, mask, buf.toString()); + + buf.bit_advance(IE::length::value - 24); + return data; + } +}; + +/******************************************************************************** +bit_accessor_cross_byte +*********************************************************************************/ +template<> +struct bit_accessor_cross_byte //MSB +{ + static bool put(u8 value, u8 length, buffer& buf) + { + u8 spare = 8 - buf.get_shift(); + + if (spare < length) + { + length -= spare; + u8 chunk = value >> length; + u8 const mask = static_cast((1u << spare) - 1); + u8 data = buf.extract_u8(chunk, mask, 0); + buf.put_u8(data); + + buf.bit_advance(spare); + } + if (buf.checkBytesLeft(1)) + { + u8 const mask = static_cast((1u << length) - 1); + u8 const shift = 8 - buf.get_shift() - length; + u8 data = buf.extract_u8(value, mask, shift); + buf.put_u8(data); + + buf.bit_advance(length); + + return true; + } + return false; + } + + static u8 get(u8 length, buffer& buf) + { + u8 rval {0}; + u8 const mask = static_cast((1u << length) - 1); + u8 const spare = 8 - buf.get_shift(); + if (spare < length) + { + length -= spare; + rval = buf.get_u8() << length; + buf.bit_advance(spare); + } + if (length && buf.checkBytesLeft(1)) + { + u8 val = buf.get_u8(); + val = val >> (8 - length - buf.get_shift()); + rval |= val; + rval &= mask; + buf.bit_advance(length); + } + return rval; + } + + static void padByte(buffer& buf) + { + if (buf.get_shift()) + { + u8 mask = static_cast((1u << buf.get_shift()) - 1); + mask = mask << (8 - buf.get_shift()); + buf.begin()[0] &= mask; + buf.bit_advance(8 - buf.get_shift()); + } + } + + static void padByte(buffer& buf) + { + if(buf.get_shift()) + buf.bit_advance(8 - buf.get_shift()); + } + + static bool put(const u8* in, size_t len, buffer& buf, u8 trail_bitsqty) + { + if (len) + { + if (trail_bitsqty) + { + buf.putBytes(in, len - 1); + u8 last_byte = in[len - 1]; + last_byte = last_byte >> (8 - trail_bitsqty); + return put(last_byte, trail_bitsqty, buf); + } + buf.putBytes(in, len); + } + return true; + } +}; + +} //end: namespace asn + +