/******************************************************************************
 * Copyright (c) 2000-2025 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Beres, Szabolcs
 *   Delic, Adam
 *   Forstner, Matyas
 *   Kovacs, Ferenc
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
 *   Szabo, Janos Zoltan – initial implementation
 *   Szalai, Gabor
 *   Tatarka, Gabor
 *
 ******************************************************************************/
#include <string.h>

#include "Bitstring.hh"
#include "../common/memory.h"
#include "Integer.hh"
#include "String_struct.hh"
#include "Error.hh"
#include "Encdec.hh"
#include "Optional.hh"

#ifndef TITAN_ASN1ENC
#include "Parameters.h"
#include "Param_Types.hh"
#include "Logger.hh"
#include "Addfunc.hh"
#endif

#include "../common/dbgnew.hh"
#include "OER.hh"
#include "PER.hh"

// bitstring value class

/** The amount of memory needed for a bitstring containing n bits. */
#define MEMORY_SIZE(n) (sizeof(bitstring_struct) - sizeof(int) + ((n) + 7) / 8)

void BITSTRING::init_struct(int n_bits)
{
  if (n_bits < 0) {
    val_ptr = NULL;
    TTCN_error("Initializing a bitstring with a negative length.");
  } else if (n_bits == 0) {
    /** This will represent the empty strings so they won't need allocated
      * memory, this delays the memory allocation until it is really needed.
      */
    static bitstring_struct empty_string = { 1, 0, "" };
    val_ptr = &empty_string;
    empty_string.ref_count++;
  } else {
    val_ptr = (bitstring_struct*)Malloc(MEMORY_SIZE(n_bits));
    val_ptr->ref_count = 1;
    val_ptr->n_bits = n_bits;
  }
}

boolean BITSTRING::get_bit(int bit_index) const
{
  return val_ptr->bits_ptr[bit_index / 8] & (1 << (bit_index % 8));
}

void BITSTRING::set_bit(int bit_index, boolean new_value)
{
  unsigned char mask = 1 << (bit_index % 8);
  if (new_value) val_ptr->bits_ptr[bit_index / 8] |= mask;
  else           val_ptr->bits_ptr[bit_index / 8] &= ~mask;
}

void BITSTRING::copy_value()
{
  if (val_ptr == NULL || val_ptr->n_bits <= 0)
    TTCN_error("Internal error: Invalid internal data structure when copying "
      "the memory area of a bitstring value.");
  if (val_ptr->ref_count > 1) {
    bitstring_struct *old_ptr = val_ptr;
    old_ptr->ref_count--;
    init_struct(old_ptr->n_bits);
    memcpy(val_ptr->bits_ptr, old_ptr->bits_ptr, (old_ptr->n_bits + 7) / 8);
  }
}

void BITSTRING::clear_unused_bits() const
{
  int n_bits = val_ptr->n_bits;
  if (n_bits % 8 != 0) val_ptr->bits_ptr[(n_bits - 1) / 8] &=
                         (unsigned char)'\377' >> (7 - (n_bits - 1) % 8);
}

BITSTRING::BITSTRING(int n_bits)
{
  init_struct(n_bits);
}

BITSTRING::BITSTRING()
{
  val_ptr = NULL;
}

BITSTRING::BITSTRING(int n_bits, const unsigned char *bits_ptr)
{
  init_struct(n_bits);
  memcpy(val_ptr->bits_ptr, bits_ptr, (n_bits + 7) / 8);
  clear_unused_bits();
}

BITSTRING::BITSTRING(const char* str)
{
  if (str == NULL) {
    TTCN_error("Cannot convert NULL pointer to BIT STRING.");
  }
  size_t len = strlen(str);
  init_struct(len);
  for (size_t i = 0; i < len; ++i) {
    if (str[i] == '0') {
      set_bit(i, FALSE);
    }
    else if (str[i] == '1') {
      set_bit(i, TRUE);
    }
    else {
      clean_up();
      TTCN_error("Cannot convert `%s' to BIT STRING.", str);
    }
  }
}

BITSTRING::BITSTRING(const BITSTRING& other_value)
: Base_Type(other_value)
{
  other_value.must_bound("Copying an unbound bitstring value.");
  val_ptr = other_value.val_ptr;
  val_ptr->ref_count++;
}

BITSTRING::BITSTRING(const BITSTRING_ELEMENT& other_value)
{
  other_value.must_bound("Copying an unbound bitstring element.");
  init_struct(1);
  val_ptr->bits_ptr[0] = other_value.get_bit() ? 1 : 0;
}

BITSTRING::~BITSTRING()
{
  clean_up();
}

void BITSTRING::clean_up()
{
  if (val_ptr != NULL) {
    if (val_ptr->ref_count > 1) val_ptr->ref_count--;
    else if (val_ptr->ref_count == 1) Free(val_ptr);
    else TTCN_error("Internal error: Invalid reference counter in a bitstring "
      "value.");
    val_ptr = NULL;
  }
}

BITSTRING& BITSTRING::operator=(const BITSTRING& other_value)
{
  other_value.must_bound("Assignment of an unbound bitstring value.");
  if (&other_value != this) {
    clean_up();
    val_ptr = other_value.val_ptr;
    val_ptr->ref_count++;
  }
  return *this;
}

BITSTRING& BITSTRING::operator=(const BITSTRING_ELEMENT& other_value)
{
  other_value.must_bound("Assignment of an unbound bitstring element to a "
    "bitstring.");
  boolean bit_value = other_value.get_bit();
  clean_up();
  init_struct(1);
  val_ptr->bits_ptr[0] = bit_value ? 1 : 0;
  return *this;
}

#ifndef TITAN_ASN1ENC
BITSTRING& BITSTRING::operator=(const INTEGER& other_value)
{
  return this->operator=(int2bit(other_value, val_ptr->n_bits));
}
#endif

boolean BITSTRING::operator==(const BITSTRING& other_value) const
{
  must_bound("Unbound left operand of bitstring comparison.");
  other_value.must_bound("Unbound right operand of bitstring comparison.");
  int n_bits = val_ptr->n_bits;
  if (n_bits != other_value.val_ptr->n_bits) return FALSE;
  if (n_bits == 0) return TRUE;
  clear_unused_bits();
  other_value.clear_unused_bits();
  return !memcmp(val_ptr->bits_ptr, other_value.val_ptr->bits_ptr,
                 (n_bits + 7) / 8);
}

boolean BITSTRING::operator==(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Unbound left operand of bitstring comparison.");
  other_value.must_bound("Unbound right operand of bitstring element "
    "comparison.");
  if (val_ptr->n_bits != 1) return FALSE;
  return get_bit(0) == other_value.get_bit();
}

BITSTRING BITSTRING::operator+(const BITSTRING& other_value) const
{
  must_bound("Unbound left operand of bitstring concatenation.");
  other_value.must_bound("Unbound right operand of bitstring concatenation.");

  int left_n_bits = val_ptr->n_bits;
  if (left_n_bits == 0) return other_value;

  int right_n_bits = other_value.val_ptr->n_bits;
  if (right_n_bits == 0) return *this;

  // the length of result
  int n_bits = left_n_bits + right_n_bits;

  // the number of bytes used
  int left_n_bytes = (left_n_bits + 7) / 8;
  int right_n_bytes = (right_n_bits + 7) / 8;

  // the number of bits used in the last incomplete octet of the left operand
  int left_empty_bits = left_n_bits % 8;

  // the result
  BITSTRING ret_val(n_bits);

  // pointers to the data areas
  const unsigned char *left_ptr = val_ptr->bits_ptr;
  const unsigned char *right_ptr = other_value.val_ptr->bits_ptr;
  unsigned char *dest_ptr = ret_val.val_ptr->bits_ptr;

  // copying the left fragment into the result
  memcpy(dest_ptr, left_ptr, left_n_bytes);

  if (left_empty_bits != 0) {
    // non-trivial case: the length of left fragment is not a multiply of 8
    // the bytes used in the result
    int n_bytes = (n_bits + 7) / 8;
    // placing the bytes from the right fragment until the result is filled
    for (int i = left_n_bytes; i < n_bytes; i++) {
      unsigned char right_byte = right_ptr[i - left_n_bytes];
      // finish filling the previous byte
      dest_ptr[i - 1] |= right_byte << left_empty_bits;
      // start filling the actual byte
      dest_ptr[i] = right_byte >> (8 - left_empty_bits);
    }
    if (left_n_bytes + right_n_bytes > n_bytes) {
      // if the result data area is shorter than the two operands together
      // the last bits of right fragment were not placed into the result
      // in the previous for loop
      dest_ptr[n_bytes - 1] |= right_ptr[right_n_bytes - 1] << left_empty_bits;
    }
  } else {
    // trivial case: just append the bytes of the right fragment
    memcpy(dest_ptr + left_n_bytes, right_ptr, right_n_bytes);
  }
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING BITSTRING::operator+(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Unbound left operand of bitstring concatenation.");
  other_value.must_bound("Unbound right operand of bitstring element "
                         "concatenation.");

  int n_bits = val_ptr->n_bits;
  BITSTRING ret_val(n_bits + 1);
  memcpy(ret_val.val_ptr->bits_ptr, val_ptr->bits_ptr, (n_bits + 7) / 8);
  ret_val.set_bit(n_bits, other_value.get_bit());
  return ret_val;
}

BITSTRING BITSTRING::operator~() const
{
  must_bound("Unbound bitstring operand of operator not4b.");
  int n_bytes = (val_ptr->n_bits + 7) / 8;
  if (n_bytes == 0) return *this;
  BITSTRING ret_val(val_ptr->n_bits);
  for (int i = 0; i < n_bytes; i++)
    ret_val.val_ptr->bits_ptr[i] = ~val_ptr->bits_ptr[i];
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING BITSTRING::operator&(const BITSTRING& other_value) const
{
  must_bound("Left operand of operator and4b is an unbound bitstring value.");
  other_value.must_bound("Right operand of operator and4b is an unbound "
    "bitstring value.");
  int n_bits = val_ptr->n_bits;
  if (n_bits != other_value.val_ptr->n_bits)
    TTCN_error("The bitstring operands of operator and4b must have the "
               "same length.");
  if (n_bits == 0) return *this;
  BITSTRING ret_val(n_bits);
  int n_bytes = (n_bits + 7) / 8;
  for (int i = 0; i < n_bytes; i++)
    ret_val.val_ptr->bits_ptr[i] = val_ptr->bits_ptr[i] &
      other_value.val_ptr->bits_ptr[i];
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING BITSTRING::operator&(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Left operand of operator and4b is an unbound bitstring value.");
  other_value.must_bound("Right operand of operator and4b is an unbound "
    "bitstring element.");
  if (val_ptr->n_bits != 1)
    TTCN_error("The bitstring operands of "
               "operator and4b must have the same length.");
  unsigned char result = get_bit(0) && other_value.get_bit() ? 1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING::operator|(const BITSTRING& other_value) const
{
  must_bound("Left operand of operator or4b is an unbound bitstring value.");
  other_value.must_bound("Right operand of operator or4b is an unbound "
    "bitstring value.");
  int n_bits = val_ptr->n_bits;
  if (n_bits != other_value.val_ptr->n_bits)
    TTCN_error("The bitstring operands of operator or4b must have the "
               "same length.");
  if (n_bits == 0) return *this;
  BITSTRING ret_val(n_bits);
  int n_bytes = (n_bits + 7) / 8;
  for (int i = 0; i < n_bytes; i++)
    ret_val.val_ptr->bits_ptr[i] = val_ptr->bits_ptr[i] |
      other_value.val_ptr->bits_ptr[i];
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING BITSTRING::operator|(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Left operand of operator or4b is an unbound bitstring value.");
  other_value.must_bound("Right operand of operator or4b is an unbound "
    "bitstring element.");
  if (val_ptr->n_bits != 1)
    TTCN_error("The bitstring operands of "
               "operator or4b must have the same length.");
  unsigned char result = get_bit(0) || other_value.get_bit() ? 1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING::operator^(const BITSTRING& other_value) const
{
  must_bound("Left operand of operator xor4b is an unbound bitstring value.");
  other_value.must_bound("Right operand of operator xor4b is an unbound "
    "bitstring value.");
  int n_bits = val_ptr->n_bits;
  if (n_bits != other_value.val_ptr->n_bits)
    TTCN_error("The bitstring operands of operator xor4b must have the "
               "same length.");
  if (n_bits == 0) return *this;
  BITSTRING ret_val(n_bits);
  int n_bytes = (n_bits + 7) / 8;
  for (int i = 0; i < n_bytes; i++)
    ret_val.val_ptr->bits_ptr[i] = val_ptr->bits_ptr[i] ^
      other_value.val_ptr->bits_ptr[i];
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING BITSTRING::operator^(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Left operand of operator xor4b is an unbound bitstring value.");
  other_value.must_bound("Right operand of operator xor4b is an unbound "
    "bitstring element.");
  if (val_ptr->n_bits != 1)
    TTCN_error("The bitstring operands of "
               "operator xor4b must have the same length.");
  unsigned char result = get_bit(0) != other_value.get_bit() ? 1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING::operator<<(int shift_count) const
{
  must_bound("Unbound bitstring operand of shift left operator.");
  if (shift_count > 0) {
    int n_bits = val_ptr->n_bits;
    if (n_bits == 0) return *this;
    BITSTRING ret_val(n_bits);
    int n_bytes = (n_bits + 7) / 8;
    clear_unused_bits();
    if (shift_count > n_bits) shift_count = n_bits;
    int shift_bytes = shift_count / 8,
      shift_bits = shift_count % 8;
    if (shift_bits != 0) {
      int byte_count = 0;
      for ( ; byte_count < n_bytes - shift_bytes - 1; byte_count++) {
        ret_val.val_ptr->bits_ptr[byte_count] =
          (val_ptr->bits_ptr[byte_count + shift_bytes] >> shift_bits)|
          (val_ptr->bits_ptr[byte_count + shift_bytes + 1] <<
           (8 - shift_bits));
      }
      ret_val.val_ptr->bits_ptr[n_bytes - shift_bytes - 1] =
        val_ptr->bits_ptr[n_bytes - 1] >> shift_bits;
    } else {
      memcpy(ret_val.val_ptr->bits_ptr, val_ptr->bits_ptr + shift_bytes,
             n_bytes - shift_bytes);
    }
    memset(ret_val.val_ptr->bits_ptr + n_bytes - shift_bytes, 0,
           shift_bytes);
    ret_val.clear_unused_bits();
    return ret_val;
  } else if (shift_count == 0) return *this;
  else return *this >> (-shift_count);
}

BITSTRING BITSTRING::operator<<(const INTEGER& shift_count) const
{
  shift_count.must_bound("Unbound right operand of bitstring shift left "
    "operator.");
  return *this << (int)shift_count;
}

BITSTRING BITSTRING::operator>>(int shift_count) const
{
  must_bound("Unbound bitstring operand of shift right operator.");
  if (shift_count > 0) {
    int n_bits = val_ptr->n_bits;
    if (n_bits == 0) return *this;
    BITSTRING ret_val(n_bits);
    int n_bytes = (n_bits + 7) / 8;
    clear_unused_bits();
    if (shift_count > n_bits) shift_count = n_bits;
    int shift_bytes = shift_count / 8, shift_bits = shift_count % 8;
    memset(ret_val.val_ptr->bits_ptr, 0, shift_bytes);
    if (shift_bits != 0) {
      ret_val.val_ptr->bits_ptr[shift_bytes] =
        val_ptr->bits_ptr[0] << shift_bits;
      for (int byte_count = shift_bytes + 1; byte_count < n_bytes; byte_count++)
      {
        ret_val.val_ptr->bits_ptr[byte_count] =
          (val_ptr->bits_ptr[byte_count - shift_bytes - 1] >> (8 - shift_bits))
	  | (val_ptr->bits_ptr[byte_count - shift_bytes] << shift_bits);
      }
    } else {
      memcpy(ret_val.val_ptr->bits_ptr + shift_bytes, val_ptr->bits_ptr,
             n_bytes - shift_bytes);
    }
    ret_val.clear_unused_bits();
    return ret_val;
  } else if (shift_count == 0) return *this;
  else return *this << (-shift_count);
}

BITSTRING BITSTRING::operator>>(const INTEGER& shift_count) const
{
  shift_count.must_bound("Unbound right operand of bitstring shift right "
    "operator.");
  return *this >> (int)shift_count;
}

BITSTRING BITSTRING::operator<<=(int rotate_count) const
{
  must_bound("Unbound bitstring operand of rotate left operator.");
  int n_bits = val_ptr->n_bits;
  if (n_bits == 0) return *this;
  if (rotate_count >= 0) {
    rotate_count %= n_bits;
    if (rotate_count == 0) return *this;
    else return (*this << rotate_count) |
           (*this >> (n_bits - rotate_count));
  } else return *this >>= (-rotate_count);
}

BITSTRING BITSTRING::operator<<=(const INTEGER& rotate_count) const
{
  rotate_count.must_bound("Unbound right operand of bitstring rotate left "
    "operator.");
  return *this <<= (int)rotate_count;
}

BITSTRING BITSTRING::operator>>=(int rotate_count) const
{
  must_bound("Unbound bitstring operand of rotate right operator.");
  int n_bits = val_ptr->n_bits;
  if (n_bits == 0) return *this;
  if (rotate_count >= 0) {
    rotate_count %= n_bits;
    if (rotate_count == 0) return *this;
    else return (*this >> rotate_count) |
           (*this << (n_bits - rotate_count));
  } else return *this <<= (-rotate_count);
}

BITSTRING BITSTRING::operator>>=(const INTEGER& rotate_count) const
{
  rotate_count.must_bound("Unbound right operand of bitstring rotate right "
    "operator.");
  return *this >>= (int)rotate_count;
}

BITSTRING_ELEMENT BITSTRING::operator[](int index_value)
{
  if (val_ptr == NULL && index_value == 0) {
    init_struct(1);
    clear_unused_bits();
    return BITSTRING_ELEMENT(FALSE, *this, 0);
  } else {
    must_bound("Accessing an element of an unbound bitstring value.");
    if (index_value < 0) TTCN_error("Accessing an bitstring element using "
      "a negative index (%d).", index_value);
    int n_bits = val_ptr->n_bits;
    if (index_value > n_bits) TTCN_error("Index overflow when accessing a "
      "bitstring element: The index is %d, but the string has only %d bits.",
      index_value, n_bits);
    if (index_value == n_bits) {
      if (val_ptr->ref_count == 1) {
	if (n_bits % 8 == 0) val_ptr = (bitstring_struct*)
	  Realloc(val_ptr, MEMORY_SIZE(n_bits + 1));
	val_ptr->n_bits++;
      } else {
	bitstring_struct *old_ptr = val_ptr;
	old_ptr->ref_count--;
	init_struct(n_bits + 1);
	memcpy(val_ptr->bits_ptr, old_ptr->bits_ptr, (n_bits + 7) / 8);
      }
      clear_unused_bits();
      return BITSTRING_ELEMENT(FALSE, *this, index_value);
    } else return BITSTRING_ELEMENT(TRUE, *this, index_value);
  }
}

BITSTRING_ELEMENT BITSTRING::operator[](const INTEGER& index_value)
{
  index_value.must_bound("Indexing a bitstring value with an unbound integer "
    "value.");
  return (*this)[(int)index_value];
}

const BITSTRING_ELEMENT BITSTRING::operator[](int index_value) const
{
  must_bound("Accessing an element of an unbound bitstring value.");
  if (index_value < 0) TTCN_error("Accessing an bitstring element using a "
    "negative index (%d).", index_value);
  if (index_value >= val_ptr->n_bits) TTCN_error("Index overflow when "
    "accessing a bitstring element: The index is %d, but the string has only "
    "%d bits.", index_value, val_ptr->n_bits);
  return BITSTRING_ELEMENT(TRUE, const_cast<BITSTRING&>(*this), index_value);
}

const BITSTRING_ELEMENT BITSTRING::operator[](const INTEGER& index_value) const
{
  index_value.must_bound("Indexing a bitstring value with an unbound integer "
    "value.");
  return (*this)[(int)index_value];
}

int BITSTRING::lengthof() const
{
  must_bound("Getting the length of an unbound bitstring value.");
  return val_ptr->n_bits;
}

BITSTRING::operator const unsigned char*() const
{
  must_bound("Casting an unbound bitstring value to const unsigned char*.");
  return val_ptr->bits_ptr;
}

#ifdef TITAN_ASN1ENC
CHARSTRING BITSTRING::log() const
{
  if (val_ptr != NULL) {
    char* buf = mcopystr("'");
    for (int bit_count = 0; bit_count < val_ptr->n_bits; bit_count++) {
      buf = mputc(buf, get_bit(bit_count) ? '1' : '0');
    }
    buf = mputstr(buf, "'B");
    CHARSTRING ret_val(buf);
    Free(buf);
    return ret_val;
  }
  else {
    return UNBOUND_VALUE_LOG;
  }
}
#else
void BITSTRING::log() const
{
  if (val_ptr != NULL) {
    TTCN_Logger::log_char('\'');
    for (int bit_count = 0; bit_count < val_ptr->n_bits; bit_count++)
      TTCN_Logger::log_char(get_bit(bit_count) ? '1' : '0');
    TTCN_Logger::log_event_str("'B");
  } else TTCN_Logger::log_event_unbound();
}

INTEGER BITSTRING::convert_to_Integer(const TTCN_Typedescriptor_t& p_td)
{
  TTCN_EncDec_ErrorContext ec("While converting to integer type '%s': ", p_td.name);
  return bit2int(*this);
}

void BITSTRING::set_param(Module_Param& param) {
  param.basic_check(Module_Param::BC_VALUE|Module_Param::BC_LIST, "bitstring value");
  Module_Param_Ptr mp = &param;
#ifdef TITAN_RUNTIME_2
  if (param.get_type() == Module_Param::MP_Reference) {
    mp = param.get_referenced_param();
  }
#endif
  switch (mp->get_type()) {
  case Module_Param::MP_Bitstring:
    switch (param.get_operation_type()) {
    case Module_Param::OT_ASSIGN:
      clean_up();
      init_struct(mp->get_string_size());
      memcpy(val_ptr->bits_ptr, mp->get_string_data(), (val_ptr->n_bits + 7) / 8);
      clear_unused_bits();
      break;
    case Module_Param::OT_CONCAT:
      if (is_bound()) {
        *this = *this + BITSTRING(mp->get_string_size(), (unsigned char*)mp->get_string_data());
      } else {
        *this = BITSTRING(mp->get_string_size(), (unsigned char*)mp->get_string_data());
      }
      break;
    default:
      TTCN_error("Internal error: BITSTRING::set_param()");
    }
    break;
  case Module_Param::MP_Expression:
    if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
      BITSTRING operand1, operand2;
      operand1.set_param(*mp->get_operand1());
      operand2.set_param(*mp->get_operand2());
      if (param.get_operation_type() == Module_Param::OT_CONCAT) {
        *this = *this + operand1 + operand2;
      }
      else {
        *this = operand1 + operand2;
      }
    }
    else {
      param.expr_type_error("a bitstring");
    }
    break;
  default:
    param.type_error("bitstring value");
    break;
  }
}

#ifdef TITAN_RUNTIME_2
Module_Param* BITSTRING::get_param(Module_Param_Name& /* param_name */) const
{
  if (!is_bound()) {
    return new Module_Param_Unbound();
  }
  int n_bytes = (val_ptr->n_bits + 7) / 8;
  unsigned char* val_cpy = (unsigned char *)Malloc(n_bytes);
  memcpy(val_cpy, val_ptr->bits_ptr, n_bytes);
  return new Module_Param_Bitstring(val_ptr->n_bits, val_cpy);
}
#endif

void BITSTRING::encode_text(Text_Buf& text_buf) const
{
  must_bound("Text encoder: Encoding an unbound bitstring value.");
  int n_bits = val_ptr->n_bits;
  text_buf.push_int(n_bits);
  if (n_bits > 0) text_buf.push_raw((n_bits + 7) / 8, val_ptr->bits_ptr);
}

void BITSTRING::decode_text(Text_Buf& text_buf)
{
  int n_bits = text_buf.pull_int().get_val();
  if (n_bits < 0)
    TTCN_error("Text decoder: Invalid length was received for a bitstring.");
  clean_up();
  init_struct(n_bits);
  if (n_bits > 0) {
    text_buf.pull_raw((n_bits + 7) / 8, val_ptr->bits_ptr);
    clear_unused_bits();
  }
}
#endif

void BITSTRING::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
                       int p_coding, ...) const
{
  va_list pvar;
  va_start(pvar, p_coding);
  switch(p_coding) {
  case TTCN_EncDec::CT_BER: {
    TTCN_EncDec_ErrorContext ec("While BER-encoding type '%s': ", p_td.name);
    unsigned BER_coding=va_arg(pvar, unsigned);
    BER_encode_chk_coding(BER_coding);
    ASN_BER_TLV_t *tlv=BER_encode_TLV(p_td, BER_coding);
    tlv->put_in_buffer(p_buf);
    ASN_BER_TLV_t::destruct(tlv);
    break;}
#ifndef TITAN_ASN1ENC
  case TTCN_EncDec::CT_RAW: {
    TTCN_EncDec_ErrorContext ec("While RAW-encoding type '%s': ", p_td.name);
    if(!p_td.raw)
    TTCN_EncDec_ErrorContext::error_internal
      ("No RAW descriptor available for type '%s'.", p_td.name);
    RAW_enc_tr_pos rp;
    rp.level=0;
    rp.pos=NULL;
    RAW_enc_tree root(TRUE,NULL,&rp,1,p_td.raw);
    RAW_encode(p_td, root);
    root.put_to_buf(p_buf);
    break;}
  case TTCN_EncDec::CT_XER: {
    TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name);
    unsigned XER_coding=va_arg(pvar, unsigned);
    XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0, 0);
    break;}
#endif
  case TTCN_EncDec::CT_JSON: {
    TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name);
    if(!p_td.json)
      TTCN_EncDec_ErrorContext::error_internal
        ("No JSON descriptor available for type '%s'.", p_td.name);
    JSON_Tokenizer tok(va_arg(pvar, int) != 0);
    JSON_encode(p_td, tok, FALSE);
    p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer());
    break;}
  case TTCN_EncDec::CT_OER: {
    TTCN_EncDec_ErrorContext ec("While OER-encoding type '%s': ", p_td.name);
    if(!p_td.oer)  TTCN_EncDec_ErrorContext::error_internal(
      "No OER descriptor available for type '%s'.", p_td.name);
    OER_encode(p_td, p_buf);
    break;}
  case TTCN_EncDec::CT_PER: {
    TTCN_EncDec_ErrorContext ec("While PER-encoding type '%s': ", p_td.name);
    if (!p_td.per) TTCN_EncDec_ErrorContext::error_internal(
      "No PER descriptor available for type '%s'.", p_td.name);
    int opt = va_arg(pvar, int);
    PER_encode(p_td, p_buf, opt);
    break; }
  default:
    TTCN_error("Unknown coding method requested to encode type '%s'",
               p_td.name);
  }
  va_end(pvar);
}

void BITSTRING::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
                       int p_coding, ...)
{
  va_list pvar;
  va_start(pvar, p_coding);
  switch(p_coding) {
  case TTCN_EncDec::CT_BER: {
    TTCN_EncDec_ErrorContext ec("While BER-decoding type '%s': ", p_td.name);
    unsigned L_form=va_arg(pvar, unsigned);
    ASN_BER_TLV_t tlv;
    BER_decode_str2TLV(p_buf, tlv, L_form);
    BER_decode_TLV(p_td, tlv, L_form);
    if(tlv.isComplete) p_buf.increase_pos(tlv.get_len());
    break;}
#ifndef TITAN_ASN1ENC
  case TTCN_EncDec::CT_RAW: {
    TTCN_EncDec_ErrorContext ec("While RAW-decoding type '%s': ", p_td.name);
    if(!p_td.raw)
    TTCN_EncDec_ErrorContext::error_internal
      ("No RAW descriptor available for type '%s'.", p_td.name);
    raw_order_t order;
    switch(p_td.raw->top_bit_order){
    case TOP_BIT_LEFT:
      order=ORDER_LSB;
      break;
    case TOP_BIT_RIGHT:
    default:
        order=ORDER_MSB;
    }
    if(RAW_decode(p_td, p_buf, p_buf.get_len()*8, order)<0)
      ec.error(TTCN_EncDec::ET_INCOMPL_MSG,
        "Can not decode type '%s', because invalid or incomplete"
        " message was received"
        , p_td.name);
    break;}
  case TTCN_EncDec::CT_XER: {
    TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name);
    unsigned XER_coding=va_arg(pvar, unsigned);
    XmlReaderWrap reader(p_buf);
    int success = reader.Read();
    for (; success==1; success=reader.Read()) {
      int type = reader.NodeType();
      if (type==XML_READER_TYPE_ELEMENT)
	break;
    }
    XER_decode(*p_td.xer, reader, XER_coding, XER_NONE, 0);
    size_t bytes = reader.ByteConsumed();
    p_buf.set_pos(bytes);
    break;}
#endif
  case TTCN_EncDec::CT_JSON: {
    TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name);
    if(!p_td.json)
      TTCN_EncDec_ErrorContext::error_internal
        ("No JSON descriptor available for type '%s'.", p_td.name);
    JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len());
    if(JSON_decode(p_td, tok, FALSE, FALSE)<0)
      ec.error(TTCN_EncDec::ET_INCOMPL_MSG,
               "Can not decode type '%s', because invalid or incomplete"
               " message was received"
               , p_td.name);
    p_buf.set_pos(tok.get_buf_pos());
    break;}
  case TTCN_EncDec::CT_OER: {
    TTCN_EncDec_ErrorContext ec("While OER-decoding type '%s': ", p_td.name);
    if(!p_td.oer)  TTCN_EncDec_ErrorContext::error_internal(
      "No OER descriptor available for type '%s'.", p_td.name);
    OER_struct p_oer;
    OER_decode(p_td, p_buf, p_oer);
    break;}
  case TTCN_EncDec::CT_PER: {
    TTCN_EncDec_ErrorContext ec("While PER-decoding type '%s': ", p_td.name);
    if(!p_td.per)  TTCN_EncDec_ErrorContext::error_internal(
      "No PER descriptor available for type '%s'.", p_td.name);
    int opt = va_arg(pvar, int);
    try {
      PER_decode(p_td, p_buf, opt);
      p_buf.PER_octet_align(FALSE);
    }
    catch (PER_Buffer_Exception) { }
    break; }
  default:
    TTCN_error("Unknown coding method requested to decode type '%s'",
               p_td.name);
  }
  va_end(pvar);
}

void BITSTRING::BER_encode_putbits(unsigned char *target,
                                   unsigned int bitnum_start,
                                   unsigned int bit_count) const
{
  unsigned int nof_bits, nof_octets, i, j;
  unsigned char c;

  nof_bits=val_ptr->n_bits;
  if(bitnum_start>nof_bits
     || bitnum_start+bit_count>nof_bits)
    TTCN_EncDec_ErrorContext::error_internal
      ("In BITSTRING::BER_encode_putbits(): Index overflow.");
  nof_octets=(bit_count+7)/8;
  if(!nof_octets) {
    target[0]=0x00;
    return;
  }
  target[0] = static_cast<unsigned char>(nof_octets*8-bit_count);
  for(i=0; i<nof_octets-1; i++) {
    c=0;
    for(j=0; j<8; j++) {
      c<<=1;
      if(get_bit(bitnum_start+8*i+j)) c|=0x01;
    }
    target[1+i]=c;
  } // for
  c=0;
  for(j=0; j<8; j++) {
    c<<=1;
    if(8*i+j<bit_count)
      if(get_bit(bitnum_start+8*i+j)) c|=0x01;
  }
  target[1+i]=c;
}

ASN_BER_TLV_t*
BITSTRING::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td,
                          unsigned p_coding) const
{
  BER_chk_descr(p_td);
  ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound());
  if(!new_tlv) {
    unsigned char *V_ptr;
    size_t V_len;
    unsigned int nof_bits=val_ptr->n_bits;
    unsigned int nof_octets=(nof_bits+7)/8;
    unsigned int nof_fragments=0;
    if(p_coding==BER_ENCODE_CER) {
      nof_fragments=(nof_octets+998)/999;
      if(!nof_fragments) nof_fragments=1;
    }
    else /*if(coding==BER_ENCODE_DER)*/ {
      nof_fragments=1;
    }

    boolean is_constructed=nof_fragments>1;
    if(!is_constructed) {
      V_len=nof_octets+1;
      V_ptr=(unsigned char*)Malloc(V_len);
      BER_encode_putbits(V_ptr, 0, nof_bits);
      new_tlv=ASN_BER_TLV_t::construct(V_len, V_ptr);
    }
    else { // is constructed
      ASN_BER_TLV_t *tmp_tlv=NULL;
      new_tlv=ASN_BER_TLV_t::construct(NULL);
      unsigned int rest_octets=nof_octets-(nof_fragments-1)*999;
      /*
      V_len=(nof_fragments-1)*1004;
      V_len+=rest_octets<128?2:4;
      V_len+=rest_octets+1;
      V_ptr=(unsigned char*)Malloc(V_len);
      */
      V_len=999;
      unsigned int nof_bits_curr=8*999;
      for(unsigned int i=0; i<nof_fragments; i++) {
        if(i==nof_fragments-1) {
          V_len=rest_octets;
          nof_bits_curr=nof_bits-i*8*999;
        }
        V_ptr=(unsigned char*)Malloc(V_len+1); // because of unused bits-octet
        /*
        V_ptr[0]=0x03;
        V_ptr[1]=0x82;
        V_ptr[2]=0x03;
        V_ptr[3]=0xE8;
        */
        BER_encode_putbits(V_ptr, i*8*999, nof_bits_curr);
        /*
        V_ptr+=1004;
        */
        tmp_tlv=ASN_BER_TLV_t::construct(V_len+1, V_ptr);
        tmp_tlv=ASN_BER_V2TLV(tmp_tlv, BITSTRING_descr_, p_coding);
        new_tlv->add_TLV(tmp_tlv);
      }
      /*
      V_ptr[0]=0x03;
      if(rest_octets<128) {
        V_ptr[1]=(rest_octets+1) & '\x7F';
        V_ptr+=2;
      }
      else {
        V_ptr[1]=0x82;
        V_ptr[2]=((rest_octets+1)/256) & 0xFF;
        V_ptr[3]=(rest_octets+1) & 0xFF;
        V_ptr+=4;
      }
      BER_encode_putbits(V_ptr, i*8*999, nof_bits-i*8*999);
      */
    }
  }
  new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding);
  return new_tlv;
}

void BITSTRING::BER_decode_getbits(const unsigned char *source,
                                   size_t s_len, unsigned int& bitnum_start)
{
  unsigned int i, j;
  unsigned char c;
  if(s_len<1) {
    TTCN_EncDec_ErrorContext::error
      (TTCN_EncDec::ET_INVAL_MSG, "Length of V-part of bitstring"
       " cannot be 0.");
    return;
  }
  unsigned int nof_octets=s_len-1;
  unsigned int nof_restbits=8-source[0];
  if(nof_octets==0) {
    if(nof_restbits!=8)
      TTCN_EncDec_ErrorContext::error
        (TTCN_EncDec::ET_INVAL_MSG,
         "If the bitstring is empty,"
         " the initial octet shall be 0, not %u [see X.690 clause 8.6.2.3].",
         source[0]);
    return;
  }
  if(source[0]>7) {
    TTCN_EncDec_ErrorContext::error
      (TTCN_EncDec::ET_INVAL_MSG, "The number of unused bits in bitstring"
       " cannot be %u (should be less than 8) [see X.690 clause 8.6.2.2].",
       source[0]);
    nof_restbits=1;
  }
  // And what about overflow? :)
  i = (nof_octets - 1) * 8 + nof_restbits;
  if (i > 0) {
    if (val_ptr->ref_count > 1) {
      bitstring_struct *old_ptr = val_ptr;
      old_ptr->ref_count--;
      init_struct(bitnum_start + i);
      memcpy(val_ptr->bits_ptr, old_ptr->bits_ptr, (old_ptr->n_bits + 7) / 8);
    } else {
      if ((bitnum_start + i + 7) / 8 > ((unsigned int)val_ptr->n_bits + 7) / 8)
	val_ptr = (bitstring_struct*)Realloc(val_ptr,
	  MEMORY_SIZE(bitnum_start + i));
      val_ptr->n_bits = bitnum_start + i;
    }
  }
  for(i=0; i<nof_octets-1; i++) {
    c=source[1+i];
    for(j=0; j<8; j++) {
      set_bit(bitnum_start+8*i+j, c & 0x80?TRUE:FALSE);
      c<<=1;
    }
  }
  c=source[1+i];
  for(j=0; j<nof_restbits; j++) {
    set_bit(bitnum_start+8*i+j, c & 0x80?TRUE:FALSE);
    c<<=1;
  }
  bitnum_start+=(nof_octets-1)*8+nof_restbits;
}

void BITSTRING::BER_decode_TLV_(const ASN_BER_TLV_t& p_tlv, unsigned L_form,
                                unsigned int& bitnum_start)
{
  if(!p_tlv.isConstructed) {
    if (p_tlv.isComplete || p_tlv.V.str.Vlen > 0)
      BER_decode_getbits(p_tlv.V.str.Vstr, p_tlv.V.str.Vlen, bitnum_start);
  }
  else { // is constructed
    ASN_BER_TLV_t tlv2;
    size_t V_pos=0;
    boolean doit=TRUE;
    while(doit) {
      if(!ASN_BER_str2TLV(p_tlv.V.str.Vlen-V_pos, p_tlv.V.str.Vstr+V_pos,
                          tlv2, L_form)) {
        TTCN_EncDec_ErrorContext::error
          (TTCN_EncDec::ET_INCOMPL_MSG,
           "Incomplete TLV in a constructed BITSTRING TLV.");
        return;
      }
      if(!p_tlv.isLenDefinite && tlv2.tagnumber==0
         && tlv2.tagclass==ASN_TAG_UNIV)
        doit=FALSE; // End-of-contents
      if(doit) {
        ASN_BER_TLV_t stripped_tlv;
        BER_decode_strip_tags(BITSTRING_ber_, tlv2, L_form, stripped_tlv);
	BER_decode_TLV_(tlv2, L_form, bitnum_start);
	V_pos+=tlv2.get_len();
	if(V_pos>=p_tlv.V.str.Vlen) doit=FALSE;
      }
    } // while(doit)
  } // else / is constructed
}

boolean BITSTRING::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td,
                                  const ASN_BER_TLV_t& p_tlv,
                                  unsigned L_form)
{
  clean_up();
  BER_chk_descr(p_td);
  ASN_BER_TLV_t stripped_tlv;
  BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv);
  TTCN_EncDec_ErrorContext ec("While decoding BITSTRING type: ");
  init_struct(0);
  unsigned int bitnum_start = 0;
  BER_decode_TLV_(stripped_tlv, L_form, bitnum_start);
  return TRUE;
}

#ifndef TITAN_ASN1ENC
int BITSTRING::RAW_encode(const TTCN_Typedescriptor_t& p_td, RAW_enc_tree& myleaf) const
{
  if (!is_bound()) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
      "Encoding an unbound value.");
  }
  int bl = val_ptr->n_bits;
  int align_length = p_td.raw->fieldlength ? p_td.raw->fieldlength - bl : 0;
  if ((bl + align_length) < val_ptr->n_bits) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
      "There is no sufficient bits to encode '%s': ", p_td.name);
    bl = p_td.raw->fieldlength;
    align_length = 0;
  }
//  myleaf.ext_bit=EXT_BIT_NO;
  if (myleaf.must_free) Free(myleaf.body.leaf.data_ptr);
  myleaf.must_free = FALSE;
  myleaf.data_ptr_used = TRUE;
  myleaf.body.leaf.data_ptr = val_ptr->bits_ptr;
  boolean orders = p_td.raw->byteorder == ORDER_MSB;
  if (p_td.raw->bitorderinfield == ORDER_LSB) orders = !orders;
  myleaf.coding_par.byteorder = orders ? ORDER_MSB : ORDER_LSB;
  orders = p_td.raw->bitorderinoctet == ORDER_MSB;
  if (p_td.raw->bitorderinfield == ORDER_LSB) orders = !orders;
  myleaf.coding_par.bitorder = orders ? ORDER_MSB : ORDER_LSB;
  myleaf.coding_par.csn1lh = p_td.raw->csn1lh;

  if (p_td.raw->endianness == ORDER_MSB) myleaf.align =  align_length;
  else                                   myleaf.align = -align_length;

  return myleaf.length = bl + align_length;
}

int BITSTRING::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff,
  int limit, raw_order_t top_bit_ord, boolean no_err, int /*sel_field*/,
  boolean /*first_call*/, const RAW_Force_Omit* /*force_omit*/)
{
  int prepaddlength = buff.increase_pos_padd(p_td.raw->prepadding);
  limit -= prepaddlength;
  int decode_length = p_td.raw->fieldlength == 0
    ? limit : p_td.raw->fieldlength;
  if ( p_td.raw->fieldlength > limit
    || p_td.raw->fieldlength > (int) buff.unread_len_bit()) {
    if (no_err) return -TTCN_EncDec::ET_LEN_ERR;
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
      "There is not enough bits in the buffer to decode type %s.", p_td.name);
    decode_length = limit > (int) buff.unread_len_bit()
      ? buff.unread_len_bit() : limit;
  }
  clean_up();
  init_struct(decode_length);
  RAW_coding_par cp;
  boolean orders = p_td.raw->bitorderinoctet == ORDER_MSB;
  if (p_td.raw->bitorderinfield == ORDER_LSB) orders = !orders;
  cp.bitorder = orders ? ORDER_MSB : ORDER_LSB;
  orders = p_td.raw->byteorder == ORDER_MSB;
  if (p_td.raw->bitorderinfield == ORDER_LSB) orders = !orders;
  cp.byteorder = orders ? ORDER_MSB : ORDER_LSB;
  cp.fieldorder = p_td.raw->fieldorder;
  cp.hexorder = ORDER_LSB;
  cp.csn1lh = p_td.raw->csn1lh;
  buff.get_b((size_t) decode_length, val_ptr->bits_ptr, cp, top_bit_ord);
  if (p_td.raw->length_restrition != -1 &&
      decode_length > p_td.raw->length_restrition) {
    val_ptr->n_bits = p_td.raw->length_restrition;
    if (p_td.raw->endianness == ORDER_LSB) {
      if ((decode_length - val_ptr->n_bits) % 8) {
        int bound = (decode_length - val_ptr->n_bits) % 8;
        int maxindex = (decode_length - 1) / 8;
        for (int a = 0, b = (decode_length - val_ptr->n_bits - 1) / 8;
          a < (val_ptr->n_bits + 7) / 8; a++, b++) {
          val_ptr->bits_ptr[a] = val_ptr->bits_ptr[b] >> bound;
          if (b < maxindex) {
            val_ptr->bits_ptr[a] = val_ptr->bits_ptr[b + 1] << (8 - bound);
          }
        }
      }
      else memmove(val_ptr->bits_ptr,
        val_ptr->bits_ptr + (decode_length - val_ptr->n_bits) / 8,
        val_ptr->n_bits / 8 * sizeof(unsigned char));
    }
  }
  decode_length += buff.increase_pos_padd(p_td.raw->padding);
  clear_unused_bits();
  return decode_length + prepaddlength;
}

int BITSTRING::XER_encode(const XERdescriptor_t& p_td,
  TTCN_Buffer& p_buf, unsigned int flavor, unsigned int /*flavor2*/, int indent, embed_values_enc_struct_t*) const
{
  if(!is_bound()) {
    TTCN_EncDec_ErrorContext::error
      (TTCN_EncDec::ET_UNBOUND, "Encoding an unbound bitstring value.");
  }

  int encoded_length=(int)p_buf.get_len();
  int empty_element = val_ptr==NULL || val_ptr->n_bits == 0;
  flavor |= SIMPLE_TYPE;
  flavor &= ~XER_RECOF; // bitstring doesn't care

  begin_xml(p_td, p_buf, flavor, indent, empty_element);

  if (!empty_element) {
    for (int bit_count = 0; bit_count < val_ptr->n_bits; bit_count++)
      p_buf.put_c(get_bit(bit_count) ? '1' : '0');
  }

  end_xml(p_td, p_buf, flavor, indent, empty_element);
  return (int)p_buf.get_len() - encoded_length;
}

int BITSTRING::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
                          unsigned int flavor, unsigned int /*flavor2*/, embed_values_dec_struct_t*)
{
  boolean exer  = is_exer(flavor);
  int success = reader.Ok(), depth = -1, type;
  boolean own_tag = !is_exerlist(flavor) && !(exer && (p_td.xer_bits & UNTAGGED));

  if (exer && (p_td.xer_bits & XER_ATTRIBUTE)) {
    const char * name = verify_name(reader, p_td, exer);
    (void)name;
  }
  else if (own_tag) {
    for (; success == 1; success = reader.Read()) {
      type = reader.NodeType();
      if (XML_READER_TYPE_ELEMENT == type) {
        // If our parent is optional and there is an unexpected tag then return and
        // we stay unbound.
        if ((flavor & XER_OPTIONAL) && !check_name((const char*)reader.LocalName(), p_td, exer)) {
          return -1;
        }
        verify_name(reader, p_td, exer);
        depth = reader.Depth();
        if (reader.IsEmptyElement()) {
          init_struct(0);
          reader.Read();
          return 1;
        }
      }
      else if (XML_READER_TYPE_TEXT == type && depth != -1) break;
      else if (XML_READER_TYPE_END_ELEMENT == type) {
        // End tag without intervening #text == empty content
        verify_end(reader, p_td, depth, exer);
        init_struct(0);
        reader.Read();
        return 1;
      }
    }
  }

  type = reader.NodeType();
  if (success == 1 && (XML_READER_TYPE_TEXT == type || XML_READER_TYPE_ATTRIBUTE == type)) {
    const char* value = (const char *)reader.Value();
    size_t num_bits = strlen(value);
    init_struct(num_bits);
    for (size_t i = 0; i < num_bits; ++i) {
      if (value[i] < '0' || value[i] > '1') {
        if (exer && (flavor & EXIT_ON_ERROR)) {
          clean_up();
          return -1;
        } else {
          TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG,
            "The bitstring value may only contain ones and zeros.");
        }
      }
      set_bit(i, value[i] - '0');
    }
  }
  
  if (exer && (p_td.xer_bits & XER_ATTRIBUTE)) {
    // Let the caller do reader.AdvanceAttribute();
  }
  else if (own_tag) {
    for (success = reader.Read(); success == 1; success = reader.Read()) {
      type = reader.NodeType();
      if (XML_READER_TYPE_END_ELEMENT == type) {
        verify_end(reader, p_td, depth, exer);
        reader.Read(); // one last time
        break;
      }
    }
  }
  return 1;
}
#endif

int BITSTRING::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok, boolean) const
{
  if (!is_bound()) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
      "Encoding an unbound bitstring value.");
    return -1;
  }
  
  char* tmp_str = (char*)Malloc(val_ptr->n_bits + 3);
  tmp_str[0] = '\"';
  tmp_str[val_ptr->n_bits + 1] = '\"';
  for (int i = 0; i < val_ptr->n_bits; ++i) {
    tmp_str[i + 1] = get_bit(i) ? '1' : '0';
  }
  tmp_str[val_ptr->n_bits + 2] = 0;
  int enc_len = p_tok.put_next_token(JSON_TOKEN_STRING, tmp_str);
  Free(tmp_str);
  return enc_len;
}

int BITSTRING::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)
{
  json_token_t token = JSON_TOKEN_NONE;
  char* value = 0;
  size_t value_len = 0;
  boolean error = FALSE;
  size_t dec_len = 0;
  boolean use_default = FALSE;
  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
    *this = *static_cast<const BITSTRING*>(p_td.json->default_value.val);
    return dec_len;
  }
  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
    // No JSON data in the buffer -> use default value
    value = const_cast<char*>(p_td.json->default_value.str);
    value_len = strlen(value);
    use_default = TRUE;
  } else {
    dec_len = p_tok.get_next_token(&token, &value, &value_len);
  }
  if (JSON_TOKEN_ERROR == token) {
    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, "");
    return JSON_ERROR_FATAL;
  }
  else if (JSON_TOKEN_STRING == token || use_default) {
    if (use_default || (value_len >= 2 && value[0] == '\"' && value[value_len - 1] == '\"')) {
      if (!use_default) {
        // The default value doesn't have quotes around it
        value_len -= 2;
        ++value;
      }
      // White spaces are ignored, so the resulting bitstring might be shorter
      // than the extracted JSON string
      int bits = value_len;
      for (size_t i = 0; i < value_len; ++i) {
        if (value[i] == ' ') {
          --bits;
        }
        else if (value[i] != '0' && value[i] != '1') {
          if (value[i] == '\\' && i + 1 < value_len &&
              (value[i + 1] == 'n' || value[i + 1] == 'r' || value[i + 1] == 't')) {
            // Escaped white space character
            ++i;
            bits -= 2;
          }
          else {
            error = TRUE;
            break;
          }
        }
      }
      if (!error) {
        clean_up();
        init_struct(bits);
        int bit_index = 0;
        for (size_t i = 0; i < value_len; ++i) {
          if (value[i] == '0' || value[i] == '1') {
            set_bit(bit_index, value[i] - '0');
            ++bit_index;
          }
        }
        clear_unused_bits();
      }
    } else {
      error = TRUE;
    }
  } else {
    return JSON_ERROR_INVALID_TOKEN;
  }
  
  if (error) {
    JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, "string", "bitstring");
    return JSON_ERROR_FATAL;    
  }
  return (int)dec_len;
}

int BITSTRING::OER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf) const {
  if (!is_bound()) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
      "Encoding an unbound bitstring value.");
    return -1;
  }
  if (p_td.oer->length == -1) {
    size_t bytes = 1 + val_ptr->n_bits / 8;
    int rem = (val_ptr->n_bits % 8);
    if (rem != 0) {
      bytes++;
    }
    encode_oer_length(bytes, p_buf, FALSE);
    p_buf.put_c(rem == 0 ? 0 : 8 - rem);
  }
  char c = 0;
  int pos = 8;
  for (int i = 0; i < val_ptr->n_bits; i++) {
    pos--;
    c += get_bit(i) << pos;
    if (pos == 0) {
      p_buf.put_c(c);
      c = 0;
      pos = 8;
    }
  }
  if (pos != 8) {
    p_buf.put_c(c);
  }
  return 0;
}

int BITSTRING::OER_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, OER_struct&) {
  
  size_t bytes;
  if (p_td.oer->length == -1) {
    bytes = decode_oer_length(p_buf, FALSE) - 1;
    const unsigned char* uc = p_buf.get_read_data();
    init_struct((bytes * 8) - uc[0]);
    p_buf.increase_pos(1);
  } else {
    bytes = p_td.oer->length / 8;
    if (p_td.oer->length % 8 != 0) {
      bytes++;
    }
    init_struct(p_td.oer->length);
  }

  const unsigned char* uc = p_buf.get_read_data();
  int bit_pos = 0;
  for (size_t i = 0; i < bytes; i++) {
    for (int j = 7; j >= 0 && bit_pos < val_ptr->n_bits; j--) {
      set_bit(bit_pos, (uc[i] & (1 << j)));
      bit_pos++;
    }
  }
  p_buf.increase_pos(bytes);
  return 0;
}

void BITSTRING::PER_encode_bits(TTCN_Buffer& p_buf, int p_start, int p_end) const
{
  int actual_bits_end = (p_end > val_ptr->n_bits) ? val_ptr->n_bits : p_end;
  for (int i = p_start; i < actual_bits_end; ++i) {
    p_buf.PER_put_bit(get_bit(i));
  }
  for (int i = actual_bits_end; i < p_end; ++i) {
    p_buf.PER_put_bit(FALSE);
  }
}

void BITSTRING::PER_encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, int p_options) const
{
  if (!is_bound()) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
      "Encoding an unbound BIT STRING value.");
    return;
  }
  const Per_BitString_Constraint* cons = dynamic_cast<const Per_BitString_Constraint*>(p_td.per->c);
  if (cons == NULL) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INTERNAL,
      "Internal error: Invalid constraint in PER descriptor.");
    return;
  }
  INTEGER length(val_ptr->n_bits);
  boolean extendable = cons->has_extension_marker();
  const Per_Integer_Constraint* size_cons = cons->get_size_constraint();
  if (cons->has_named_bits()) {
    // remove as many trailing zeros as possible or add trailing zeros to reach the minimum length
    INTEGER lb = size_cons->get_lower_bound();
    if (length > lb) {
      boolean found_one = FALSE;
      for (size_t i = val_ptr->n_bits - 1; i >= 0; --i) {
        if (get_bit(i)) { // find the last '1' bit
          length = i + 1;
          found_one = TRUE;
          break;
        }
      }
      if (!found_one) {
        length = 0;
      }
    }
    if (length < lb) {
      length = lb;
    }
  }
  boolean within_ext_root = size_cons->is_within_extension_root(length);
  if (!within_ext_root && !extendable) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT,
      "Encoding an invalid BIT STRING value (does not match PER-visible constraints).");
    return;
  }
  boolean ext_bit = extendable && !within_ext_root;
  if (extendable) {
    p_buf.PER_put_bit(ext_bit);
  }
  INTEGER range = ext_bit ? INTEGER(0) : size_cons->get_nof_values();
  if (range == 1 && length < PER_64K) { // length is constrained to a single value
    if (length == 0) {
      return; // nothing to encode
    }
    if (length > 16 && (p_options & PER_ALIGNED)) {
      p_buf.PER_octet_align(TRUE);
    }
    PER_encode_bits(p_buf, 0, length);
    return;
  }

  INTEGER length_ub = size_cons->has_upper_bound() ? size_cons->get_upper_bound() : INTEGER(-1);
  int mul_16k;
  int pos = 0;
  do {
    mul_16k = length.PER_encode_length(p_buf, p_options, range, size_cons->get_lower_bound(), length_ub);
    if (mul_16k == 0) {
      if (p_options & PER_ALIGNED) {
        p_buf.PER_octet_align(TRUE);
      }
      PER_encode_bits(p_buf, pos, pos + (int)length);
    }
    else {
      // encode mul * 16k octets (partial value)
      int bits_encoded = mul_16k * PER_16K;
      PER_encode_bits(p_buf, pos, pos + bits_encoded);
      pos += bits_encoded;
      length = length - bits_encoded;
      range = 0; // make sure future partial lengths are not encoded as constrained integers
    }
  }
  while (mul_16k > 0);
}

void BITSTRING::PER_decode_bits(TTCN_Buffer& p_buf, int p_len)
{
  init_struct(p_len);
  for (int i = 0; i < p_len; ++i) {
    set_bit(i, p_buf.PER_get_bit());
  }
}

void BITSTRING::PER_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, int p_options)
{
  const Per_BitString_Constraint* cons = dynamic_cast<const Per_BitString_Constraint*>(p_td.per->c);
  if (cons == NULL) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INTERNAL,
      "Internal error: Invalid constraint in PER descriptor.");
    return;
  }
  clean_up();
  boolean extendable = cons->has_extension_marker();
  boolean ext_bit = extendable ? p_buf.PER_get_bit() : FALSE;
  const Per_Integer_Constraint* size_cons = cons->get_size_constraint();
  INTEGER range = ext_bit ? INTEGER(0) : size_cons->get_nof_values();
  INTEGER length_ub = size_cons->has_upper_bound() ? size_cons->get_upper_bound() : INTEGER(-1);
  if (range == 1 && length_ub < PER_64K) { // length is constrained to a single value
    if (length_ub > 16 && (p_options & PER_ALIGNED)) {
      p_buf.PER_octet_align(FALSE);
    }
    PER_decode_bits(p_buf, length_ub);
    return;
  }

  int mul_16k;
  INTEGER length;
  do {
    mul_16k = length.PER_decode_length(p_buf, p_options, range, size_cons->get_lower_bound(), length_ub);
    if (mul_16k != 0) {
      range = 0; // make sure future partial lengths are not encoded as constrained integers
    }
    else if (p_options & PER_ALIGNED) {
      p_buf.PER_octet_align(FALSE);
    }
    BITSTRING dec_val;
    dec_val.PER_decode_bits(p_buf, length);
    if (is_bound()) {
      *this = *this + dec_val;
    }
    else {
      *this = dec_val;
    }
  }
  while (mul_16k > 0);

  if (!ext_bit && !size_cons->is_within_extension_root(val_ptr->n_bits)) {
    TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_CONSTRAINT,
      "Decoded BIT STRING value does not match PER-visible constraints.");
  }
}

// bitstring element class

BITSTRING_ELEMENT::BITSTRING_ELEMENT(boolean par_bound_flag,
  BITSTRING& par_str_val, int par_bit_pos)
  : bound_flag(par_bound_flag), str_val(par_str_val), bit_pos(par_bit_pos)
{
}

BITSTRING_ELEMENT& BITSTRING_ELEMENT::operator=(const BITSTRING& other_value)
{
  other_value.must_bound("Assignment of an unbound bitstring value.");
  if(other_value.val_ptr->n_bits != 1)
    TTCN_error("Assignment of a bitstring "
               "value with length other than 1 to a bitstring element.");
  bound_flag = TRUE;
  str_val.copy_value();
  str_val.set_bit(bit_pos, other_value.get_bit(0));
  return *this;
}

BITSTRING_ELEMENT& BITSTRING_ELEMENT::operator=
(const BITSTRING_ELEMENT& other_value)
{
  other_value.must_bound("Assignment of an unbound bitstring element.");
  bound_flag = TRUE;
  str_val.copy_value();
  str_val.set_bit(bit_pos, other_value.str_val.get_bit(other_value.bit_pos));
  return *this;
}

boolean BITSTRING_ELEMENT::operator==(const BITSTRING& other_value) const
{
  must_bound("Unbound left operand of bitstring element comparison.");
  other_value.must_bound("Unbound right operand of bitstring comparison.");
  if(other_value.val_ptr->n_bits != 1) return FALSE;
  return str_val.get_bit(bit_pos) == other_value.get_bit(0);
}

boolean BITSTRING_ELEMENT::operator==
(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Unbound left operand of bitstring element comparison.");
  other_value.must_bound("Unbound right operand of bitstring element "
    "comparison.");
  return str_val.get_bit(bit_pos) ==
    other_value.str_val.get_bit(other_value.bit_pos);
}

BITSTRING BITSTRING_ELEMENT::operator+(const BITSTRING& other_value) const
{
  must_bound("Unbound left operand of bitstring element concatenation.");
  other_value.must_bound("Unbound right operand of bitstring concatenation.");
  int n_bits = other_value.val_ptr->n_bits;
  BITSTRING ret_val(n_bits + 1);
  ret_val.val_ptr->bits_ptr[0] = str_val.get_bit(bit_pos) ? 1 : 0;
  int n_bytes = (n_bits + 7) / 8;
  for (int byte_count = 0; byte_count < n_bytes; byte_count++) {
    ret_val.val_ptr->bits_ptr[byte_count] |=
      other_value.val_ptr->bits_ptr[byte_count] << 1;
    if (n_bits > byte_count * 8 + 7)
      ret_val.val_ptr->bits_ptr[byte_count + 1] =
	other_value.val_ptr->bits_ptr[byte_count] >> 7;
  }
  ret_val.clear_unused_bits();
  return ret_val;
}

BITSTRING BITSTRING_ELEMENT::operator+(const BITSTRING_ELEMENT& other_value)
  const
{
  must_bound("Unbound left operand of bitstring element concatenation.");
  other_value.must_bound("Unbound right operand of bitstring element "
                         "concatenation.");
  unsigned char result = str_val.get_bit(bit_pos) ? 1 : 0;
  if (other_value.str_val.get_bit(other_value.bit_pos)) result |= 2;
  return BITSTRING(2, &result);
}

BITSTRING BITSTRING_ELEMENT::operator~() const
{
  must_bound("Unbound bitstring element operand of operator not4b.");
  unsigned char result = str_val.get_bit(bit_pos) ? 0 : 1;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator&(const BITSTRING& other_value) const
{
  must_bound("Left operand of operator and4b is an unbound bitstring element.");
  other_value.must_bound("Right operand of operator and4b is an unbound "
    "bitstring value.");
  if (other_value.val_ptr->n_bits != 1)
    TTCN_error("The bitstring operands "
               "of operator and4b must have the same length.");
  unsigned char result = str_val.get_bit(bit_pos) && other_value.get_bit(0) ?
    1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator&
(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Left operand of operator and4b is an unbound bitstring element.");
  other_value.must_bound("Right operand of operator and4b is an unbound "
    "bitstring element.");
  unsigned char result = str_val.get_bit(bit_pos) &&
    other_value.str_val.get_bit(other_value.bit_pos) ? 1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator|(const BITSTRING& other_value) const
{
  must_bound("Left operand of operator or4b is an unbound bitstring element.");
  other_value.must_bound("Right operand of operator or4b is an unbound "
    "bitstring value.");
  if (other_value.val_ptr->n_bits != 1)
    TTCN_error("The bitstring operands "
               "of operator or4b must have the same length.");
  unsigned char result = str_val.get_bit(bit_pos) || other_value.get_bit(0) ?
    1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator|
(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Left operand of operator or4b is an unbound bitstring element.");
  other_value.must_bound("Right operand of operator or4b is an unbound "
    "bitstring element.");
  unsigned char result = str_val.get_bit(bit_pos) ||
    other_value.str_val.get_bit(other_value.bit_pos) ? 1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator^(const BITSTRING& other_value) const
{
  must_bound("Left operand of operator xor4b is an unbound bitstring element.");
  other_value.must_bound("Right operand of operator xor4b is an unbound "
    "bitstring value.");
  if (other_value.val_ptr->n_bits != 1)
    TTCN_error("The bitstring operands "
               "of operator xor4b must have the same length.");
  unsigned char result = str_val.get_bit(bit_pos) != other_value.get_bit(0) ?
    1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator^
(const BITSTRING_ELEMENT& other_value) const
{
  must_bound("Left operand of operator xor4b is an unbound bitstring element.");
  other_value.must_bound("Right operand of operator xor4b is an unbound "
    "bitstring element.");
  unsigned char result = str_val.get_bit(bit_pos) !=
    other_value.str_val.get_bit(other_value.bit_pos) ? 1 : 0;
  return BITSTRING(1, &result);
}

BITSTRING BITSTRING_ELEMENT::operator<<(int shift_count) const
{
  must_bound("Unbound bitstring element operand of shift left operator.");
  if (shift_count == 0) {
    return BITSTRING(*this);
  }
  else {
    unsigned char zero = 0;
    return BITSTRING(1, &zero);
  }
}

BITSTRING BITSTRING_ELEMENT::operator<<(const INTEGER& shift_count) const
{
  shift_count.must_bound("Unbound right operand of bitstring element shift left "
    "operator.");
  return *this << (int)shift_count;
}

BITSTRING BITSTRING_ELEMENT::operator>>(int shift_count) const
{
  must_bound("Unbound bitstring element operand of shift right operator.");
  if (shift_count == 0) {
    return BITSTRING(*this);
  }
  else {
    unsigned char zero = 0;
    return BITSTRING(1, &zero);
  }
}

BITSTRING BITSTRING_ELEMENT::operator>>(const INTEGER& shift_count) const
{
  shift_count.must_bound("Unbound right operand of bitstring element shift right "
    "operator.");
  return *this >> (int)shift_count;
}

BITSTRING BITSTRING_ELEMENT::operator<<=(int rotate_count) const
{
  must_bound("Unbound bitstring element operand of rotate left operator.");
  return BITSTRING(*this);
}

BITSTRING BITSTRING_ELEMENT::operator<<=(const INTEGER& rotate_count) const
{
  rotate_count.must_bound("Unbound right operand of bitstring element rotate left "
    "operator.");
  return BITSTRING(*this);
}

BITSTRING BITSTRING_ELEMENT::operator>>=(int rotate_count) const
{
  must_bound("Unbound bitstring element operand of rotate right operator.");
  return BITSTRING(*this);
}

BITSTRING BITSTRING_ELEMENT::operator>>=(const INTEGER& rotate_count) const
{
  rotate_count.must_bound("Unbound right operand of bitstring element rotate right "
    "operator.");
  return BITSTRING(*this);
}

boolean BITSTRING_ELEMENT::get_bit() const
{
  return str_val.get_bit(bit_pos);
}

#ifndef TITAN_ASN1ENC
void BITSTRING_ELEMENT::log() const
{
  if (bound_flag) TTCN_Logger::log_event("'%c'B", str_val.get_bit(bit_pos) ?
    '1' : '0');
  else TTCN_Logger::log_event_unbound();
}
#else
CHARSTRING BITSTRING_ELEMENT::log() const
{
  if (bound_flag) {
    char* buf = mprintf("'%c'B", str_val.get_bit(bit_pos) ? '1' : '0');
    CHARSTRING ret_val(buf);
    Free(buf);
    return ret_val;
  }
  else {
    return UNBOUND_VALUE_LOG;
  }
}
#endif

// bitstring template class

#ifndef TITAN_ASN1ENC
void BITSTRING_template::clean_up()
{
  switch (template_selection) {
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
  case CONJUNCTION_MATCH:
    delete [] value_list.list_value;
    break;
  case STRING_PATTERN:
    if (pattern_value->ref_count > 1) pattern_value->ref_count--;
    else if (pattern_value->ref_count == 1) Free(pattern_value);
    else TTCN_error("Internal error: Invalid reference counter in a bitstring "
      "pattern.");
    break;
  case DECODE_MATCH:
    if (dec_match->ref_count > 1) {
      dec_match->ref_count--;
    }
    else if (dec_match->ref_count == 1) {
      delete dec_match->instance;
      delete dec_match;
    }
    else {
      TTCN_error("Internal error: Invalid reference counter in a "
        "decoded content match.");
    }
    break;
  case IMPLICATION_MATCH:
    delete implication_.precondition;
    delete implication_.implied_template;
    break;
  case DYNAMIC_MATCH:
    dyn_match->ref_count--;
    if (dyn_match->ref_count == 0) {
      delete dyn_match->ptr;
      delete dyn_match;
    }
    break;
  default:
    break;
  }
  template_selection = UNINITIALIZED_TEMPLATE;
}

void BITSTRING_template::copy_template(const BITSTRING_template& other_value)
{
  switch (other_value.template_selection) {
  case SPECIFIC_VALUE:
    single_value = other_value.single_value;
    break;
  case OMIT_VALUE:
  case ANY_VALUE:
  case ANY_OR_OMIT:
    break;
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
  case CONJUNCTION_MATCH:
    value_list.n_values = other_value.value_list.n_values;
    value_list.list_value = new BITSTRING_template[value_list.n_values];
    for (unsigned int i = 0; i < value_list.n_values; i++)
      value_list.list_value[i].copy_template(
        other_value.value_list.list_value[i]);
    break;
  case STRING_PATTERN:
    pattern_value = other_value.pattern_value;
    pattern_value->ref_count++;
    break;
  case DECODE_MATCH:
    dec_match = other_value.dec_match;
    dec_match->ref_count++;
    break;
  case IMPLICATION_MATCH:
    implication_.precondition = new BITSTRING_template(*other_value.implication_.precondition);
    implication_.implied_template = new BITSTRING_template(*other_value.implication_.implied_template);
    break;
  case DYNAMIC_MATCH:
    dyn_match = other_value.dyn_match;
    dyn_match->ref_count++;
    break;
  default:
    TTCN_error("Copying an uninitialized/unsupported bitstring template.");
  }
  set_selection(other_value);
}

/*
  This is the same algorithm that match_array uses
    to match 'record of' types.
  The only differences are: how two elements are matched and
    how an asterisk or ? is identified in the template
*/
boolean BITSTRING_template::match_pattern(
  const bitstring_pattern_struct *string_pattern,
  const BITSTRING::bitstring_struct *string_value)
{
  if(string_pattern->n_elements == 0) return string_value->n_bits == 0;

  int value_index = 0;
  unsigned int template_index = 0;
  int last_asterisk = -1;
  int last_value_to_asterisk = -1;

  for(;;)
  {
    switch(string_pattern->elements_ptr[template_index]) {
      case 0:
        if (!(string_value->bits_ptr[value_index / 8] &
          (1 << (value_index % 8))))
        {
          value_index++;
          template_index++;
        }else{
          if(last_asterisk == -1) return FALSE;
          template_index = last_asterisk +1;
          value_index = ++last_value_to_asterisk;
        }
        break;
      case 1:
        if (string_value->bits_ptr[value_index / 8] & (1 << (value_index % 8)))
        {
          value_index++;
          template_index++;
        }else {
          if(last_asterisk == -1) return FALSE;
          template_index = last_asterisk +1;
          value_index = ++last_value_to_asterisk;
        }
        break;
      case 2:
        //we found a ? element, it matches anything
        value_index++;
        template_index++;
        break;
      case 3:
        //we found an asterisk
        last_asterisk = template_index++;
        last_value_to_asterisk = value_index;
        break;
      default:
        TTCN_error("Internal error: invalid element in bitstring pattern.");
    }

    if(value_index == string_value->n_bits
      && template_index == string_pattern->n_elements)
    {
      return TRUE;
    }else if(template_index == string_pattern->n_elements)
    {
      if(string_pattern->elements_ptr[template_index-1] == 3)
      {
        return TRUE;
      } else if (last_asterisk == -1){
        return FALSE;
      } else{
        template_index = last_asterisk+1;
        value_index = ++last_value_to_asterisk;
      }
    } else if(value_index == string_value->n_bits)
    {
      while(template_index < string_pattern->n_elements &&
            string_pattern->elements_ptr[template_index] == 3)
        template_index++;

      return template_index == string_pattern->n_elements;
    }
  }
}

BITSTRING_template::BITSTRING_template()
{
}

BITSTRING_template::BITSTRING_template(template_sel other_value)
  : Restricted_Length_Template(other_value)
{
  check_single_selection(other_value);
}

BITSTRING_template::BITSTRING_template(const BITSTRING& other_value)
  : Restricted_Length_Template(SPECIFIC_VALUE), single_value(other_value)
{
}

BITSTRING_template::BITSTRING_template(const BITSTRING_ELEMENT& other_value)
  : Restricted_Length_Template(SPECIFIC_VALUE), single_value(other_value)
{
}

BITSTRING_template::~BITSTRING_template()
{
  clean_up();
}

BITSTRING_template::BITSTRING_template(const OPTIONAL<BITSTRING>& other_value)
{
  switch (other_value.get_selection()) {
  case OPTIONAL_PRESENT:
    set_selection(SPECIFIC_VALUE);
    single_value = (const BITSTRING&)other_value;
    break;
  case OPTIONAL_OMIT:
    set_selection(OMIT_VALUE);
    break;
  case OPTIONAL_UNBOUND:
    TTCN_error("Creating a bitstring template from an unbound optional field.");
  }
}

BITSTRING_template::BITSTRING_template(unsigned int n_elements,
  const unsigned char *pattern_elements)
  : Restricted_Length_Template(STRING_PATTERN)
{
  pattern_value = (bitstring_pattern_struct*)
    Malloc(sizeof(bitstring_pattern_struct) + n_elements - 1);
  pattern_value->ref_count = 1;
  pattern_value->n_elements = n_elements;
  memcpy(pattern_value->elements_ptr, pattern_elements, n_elements);
}

BITSTRING_template::BITSTRING_template(const BITSTRING_template& other_value)
: Restricted_Length_Template()
{
  copy_template(other_value);
}

BITSTRING_template::BITSTRING_template(BITSTRING_template* p_precondition, BITSTRING_template* p_implied_template)
: Restricted_Length_Template(IMPLICATION_MATCH)
{
  implication_.precondition = p_precondition;
  implication_.implied_template = p_implied_template;
}

BITSTRING_template::BITSTRING_template(Dynamic_Match_Interface<BITSTRING>* p_dyn_match)
: Restricted_Length_Template(DYNAMIC_MATCH)
{
  dyn_match = new dynmatch_struct<BITSTRING>;
  dyn_match->ptr = p_dyn_match;
  dyn_match->ref_count = 1;
}

BITSTRING_template& BITSTRING_template::operator=(template_sel other_value)
{
  check_single_selection(other_value);
  clean_up();
  set_selection(other_value);
  return *this;
}

BITSTRING_template& BITSTRING_template::operator=(const BITSTRING& other_value)
{
  other_value.must_bound("Assignment of an unbound bitstring value to a "
                         "template.");
  clean_up();
  set_selection(SPECIFIC_VALUE);
  single_value = other_value;
  return *this;
}

BITSTRING_template& BITSTRING_template::operator=
  (const BITSTRING_ELEMENT& other_value)
{
  other_value.must_bound("Assignment of an unbound bitstring element to a "
                         "template.");
  clean_up();
  set_selection(SPECIFIC_VALUE);
  single_value = other_value;
  return *this;
}

BITSTRING_template& BITSTRING_template::operator=
  (const OPTIONAL<BITSTRING>& other_value)
{
  clean_up();
  switch (other_value.get_selection()) {
  case OPTIONAL_PRESENT:
    set_selection(SPECIFIC_VALUE);
    single_value = (const BITSTRING&)other_value;
    break;
  case OPTIONAL_OMIT:
    set_selection(OMIT_VALUE);
    break;
  case OPTIONAL_UNBOUND:
    TTCN_error("Assignment of an unbound optional field to a bitstring "
      "template.");
  }
  return *this;
}

BITSTRING_template& BITSTRING_template::operator=
(const BITSTRING_template& other_value)
{
  if (&other_value != this) {
    clean_up();
    copy_template(other_value);
  }
  return *this;
}

#ifdef TITAN_RUNTIME_2
void BITSTRING_template::concat(Vector<unsigned char>& v) const
{
  switch (template_selection) {
  case ANY_VALUE:
  case ANY_OR_OMIT:
    switch (length_restriction_type) {
    case NO_LENGTH_RESTRICTION:
      if (template_selection == ANY_VALUE) {
        // ? => '*'
        if (v.size() == 0 || v[v.size() - 1] != 3) {
          // '**' == '*', so just ignore the second '*'
          v.push_back(3);
        }
      }
      else {
        TTCN_error("Operand of bitstring template concatenation is an "
          "AnyValueOrNone (*) matching mechanism with no length restriction");
      }
      break;
    case RANGE_LENGTH_RESTRICTION:
      if (!length_restriction.range_length.max_length ||
          length_restriction.range_length.max_length != length_restriction.range_length.min_length) {
        TTCN_error("Operand of bitstring template concatenation is an %s "
          "matching mechanism with non-fixed length restriction",
          template_selection == ANY_VALUE ? "AnyValue (?)" : "AnyValueOrNone (*)");
      }
      // else fall through (range length restriction is allowed if the minimum
      // and maximum value are the same)
    case SINGLE_LENGTH_RESTRICTION: {
      // ? length(N) or * length(N) => '??...?' N times
      int len = length_restriction_type == SINGLE_LENGTH_RESTRICTION ?
        length_restriction.single_length : length_restriction.range_length.min_length;
      for (int i = 0; i < len; ++i) {
        v.push_back(2);
      }
      break; }
    }
    break;
  case SPECIFIC_VALUE:
    concat(v, single_value);
    break;
  case STRING_PATTERN:
    for (unsigned int i = 0; i < pattern_value->n_elements; ++i) {
      v.push_back(pattern_value->elements_ptr[i]);
    }
    break;
  default:
    TTCN_error("Operand of bitstring template concatenation is an "
      "uninitialized or unsupported template.");
  }
}

void BITSTRING_template::concat(Vector<unsigned char>& v, const BITSTRING& val)
{
  if (!val.is_bound()) {
    TTCN_error("Operand of bitstring template concatenation is an "
      "unbound value.");
  }
  for (int i = 0; i < val.val_ptr->n_bits; ++i) {
    v.push_back(val.get_bit(i));
  }
}

void BITSTRING_template::concat(Vector<unsigned char>& v, template_sel sel)
{
  if (sel == ANY_VALUE) {
    // ? => '*'
    if (v.size() == 0 || v[v.size() - 1] != 3) {
      // '**' == '*', so just ignore the second '*'
      v.push_back(3);
    }
  }
  else {
    TTCN_error("Operand of bitstring template concatenation is an "
      "uninitialized or unsupported template.");
  }
}


BITSTRING_template BITSTRING_template::operator+(
  const BITSTRING_template& other_value) const
{
  if (template_selection == SPECIFIC_VALUE &&
      other_value.template_selection == SPECIFIC_VALUE) {
    // result is a specific value template
    return single_value + other_value.single_value;
  }
  if (template_selection == ANY_VALUE &&
      other_value.template_selection == ANY_VALUE &&
      length_restriction_type == NO_LENGTH_RESTRICTION &&
      other_value.length_restriction_type == NO_LENGTH_RESTRICTION) {
    // special case: ? & ? => ?
    return BITSTRING_template(ANY_VALUE);
  }
  // otherwise the result is an bitstring pattern
  Vector<unsigned char> v;
  concat(v);
  other_value.concat(v);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template BITSTRING_template::operator+(
  const BITSTRING& other_value) const
{
  if (template_selection == SPECIFIC_VALUE) {
    // result is a specific value template
    return single_value + other_value;
  }
  // otherwise the result is an bitstring pattern
  Vector<unsigned char> v;
  concat(v);
  concat(v, other_value);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template BITSTRING_template::operator+(
  const BITSTRING_ELEMENT& other_value) const
{
  return *this + BITSTRING(other_value);
}

BITSTRING_template BITSTRING_template::operator+(
  template_sel other_template_sel) const
{
  if (template_selection == ANY_VALUE && other_template_sel == ANY_VALUE &&
      length_restriction_type == NO_LENGTH_RESTRICTION) {
    // special case: ? & ? => ?
    return BITSTRING_template(ANY_VALUE);
  }
  // the result is always an bitstring pattern
  Vector<unsigned char> v;
  concat(v);
  concat(v, other_template_sel);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template operator+(const BITSTRING& left_value,
  const BITSTRING_template& right_template)
{
  if (right_template.template_selection == SPECIFIC_VALUE) {
    // result is a specific value template
    return left_value + right_template.single_value;
  }
  // otherwise the result is an bitstring pattern
  Vector<unsigned char> v;
  BITSTRING_template::concat(v, left_value);
  right_template.concat(v);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template operator+(const BITSTRING_ELEMENT& left_value,
  const BITSTRING_template& right_template)
{
  return BITSTRING(left_value) + right_template;
}

BITSTRING_template operator+(template_sel left_template_sel,
  const BITSTRING_template& right_template)
{
  if (left_template_sel == ANY_VALUE &&
      right_template.template_selection == ANY_VALUE &&
      right_template.length_restriction_type ==
      Restricted_Length_Template::NO_LENGTH_RESTRICTION) {
    // special case: ? & ? => ?
    return BITSTRING_template(ANY_VALUE);
  }
  // the result is always an bitstring pattern
  Vector<unsigned char> v;
  BITSTRING_template::concat(v, left_template_sel);
  right_template.concat(v);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template operator+(const BITSTRING& left_value,
  template_sel right_template_sel)
{
  // the result is always an bitstring pattern
  Vector<unsigned char> v;
  BITSTRING_template::concat(v, left_value);
  BITSTRING_template::concat(v, right_template_sel);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template operator+(const BITSTRING_ELEMENT& left_value,
  template_sel right_template_sel)
{
  return BITSTRING(left_value) + right_template_sel;
}

BITSTRING_template operator+(template_sel left_template_sel,
  const BITSTRING& right_value)
{
  // the result is always an bitstring pattern
  Vector<unsigned char> v;
  BITSTRING_template::concat(v, left_template_sel);
  BITSTRING_template::concat(v, right_value);
  return BITSTRING_template(v.size(), v.data_ptr());
}

BITSTRING_template operator+(template_sel left_template_sel,
  const BITSTRING_ELEMENT& right_value)
{
  return left_template_sel + BITSTRING(right_value);
}
#endif // TITAN_RUNTIME_2

BITSTRING_ELEMENT BITSTRING_template::operator[](int index_value)
{
  if (template_selection != SPECIFIC_VALUE || is_ifpresent)
    TTCN_error("Accessing a bitstring element of a non-specific bitstring "
               "template.");
  return single_value[index_value];
}

BITSTRING_ELEMENT BITSTRING_template::operator[](const INTEGER& index_value)
{
  index_value.must_bound("Indexing a bitstring template with an unbound "
                         "integer value.");
  return (*this)[(int)index_value];
}

const BITSTRING_ELEMENT BITSTRING_template::operator[](int index_value) const
{
  if (template_selection != SPECIFIC_VALUE || is_ifpresent)
    TTCN_error("Accessing a bitstring element of a non-specific bitstring "
               "template.");
  return single_value[index_value];
}

const BITSTRING_ELEMENT BITSTRING_template::operator[](const INTEGER& index_value) const
{
  index_value.must_bound("Indexing a bitstring template with an unbound "
                         "integer value.");
  return (*this)[(int)index_value];
}

boolean BITSTRING_template::match(const BITSTRING& other_value,
                                  boolean /* legacy */) const
{
  if (!other_value.is_bound()) return FALSE;
  if (!match_length(other_value.val_ptr->n_bits)) return FALSE;
  switch (template_selection) {
  case SPECIFIC_VALUE:
    return single_value == other_value;
  case OMIT_VALUE:
    return FALSE;
  case ANY_VALUE:
  case ANY_OR_OMIT:
    return TRUE;
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
    for (unsigned int i = 0; i < value_list.n_values; i++)
      if (value_list.list_value[i].match(other_value))
	return template_selection == VALUE_LIST;
    return template_selection == COMPLEMENTED_LIST;
  case STRING_PATTERN:
    return match_pattern(pattern_value, other_value.val_ptr);
  case DECODE_MATCH: {
    TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);
    TTCN_EncDec::clear_error();
    OCTETSTRING os(bit2oct(other_value));
    TTCN_Buffer buff(os);
    boolean ret_val = dec_match->instance->match(buff);
    TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL,TTCN_EncDec::EB_DEFAULT);
    TTCN_EncDec::clear_error();
    return ret_val; }
  case CONJUNCTION_MATCH:
    for (unsigned int i = 0; i < value_list.n_values; i++) {
      if (!value_list.list_value[i].match(other_value)) {
        return FALSE;
      }
    }
    return TRUE;
  case IMPLICATION_MATCH:
    return !implication_.precondition->match(other_value) || implication_.implied_template->match(other_value);
  case DYNAMIC_MATCH:
    return dyn_match->ptr->match(other_value);
  default:
    TTCN_error("Matching an uninitialized/unsupported bitstring template.");
  }
  return FALSE;
}

const BITSTRING& BITSTRING_template::valueof() const
{
  if (template_selection != SPECIFIC_VALUE || is_ifpresent)
    TTCN_error("Performing a valueof or send operation on a non-specific "
      "bitstring template.");
  return single_value;
}

int BITSTRING_template::lengthof() const
{
  int min_length;
  boolean has_any_or_none;
  if (is_ifpresent)
    TTCN_error("Performing lengthof() operation on a bitstring template "
               "which has an ifpresent attribute.");
  switch (template_selection)
  {
  case SPECIFIC_VALUE:
    min_length = single_value.lengthof();
    has_any_or_none = FALSE;
    break;
  case OMIT_VALUE:
    TTCN_error("Performing lengthof() operation on a bitstring template "
               "containing omit value.");
  case ANY_VALUE:
  case ANY_OR_OMIT:
    min_length = 0;
    has_any_or_none = TRUE; // max. length is infinity
    break;
  case VALUE_LIST:
  {
    // error if any element does not have length or the lengths differ
    if (value_list.n_values<1)
      TTCN_error("Internal error: "
                 "Performing lengthof() operation on a bitstring template "
                 "containing an empty list.");
    int item_length = value_list.list_value[0].lengthof();
    for (unsigned int i = 1; i < value_list.n_values; i++) {
      if (value_list.list_value[i].lengthof()!=item_length)
        TTCN_error("Performing lengthof() operation on a bitstring template "
                   "containing a value list with different lengths.");
    }
    min_length = item_length;
    has_any_or_none = FALSE;
    break;
  }
  case COMPLEMENTED_LIST:
    TTCN_error("Performing lengthof() operation on a bitstring template "
               "containing complemented list.");
  case CONJUNCTION_MATCH:
    TTCN_error("Performing lengthof() operation on a bitstring template "
               "containing a conjunction list match.");
  case IMPLICATION_MATCH:
    TTCN_error("Performing lengthof() operation on a bitstring template "
               "containing an implication match.");
  case DYNAMIC_MATCH:
    TTCN_error("Performing lengthof() operation on a bitstring template "
               "containing a dynamic match.");
  case STRING_PATTERN:
    min_length = 0;
    has_any_or_none = FALSE; // TRUE if * chars in the pattern
    for (unsigned int i = 0; i < pattern_value->n_elements; i++)
    {
      if (pattern_value->elements_ptr[i] < 3) min_length++; // case of 1, 0, ?
      else has_any_or_none = TRUE;   // case of * character
    }
    break;
  default:
    TTCN_error("Performing lengthof() operation on an "
               "uninitialized/unsupported bitstring template.");
  }
  return check_section_is_single(min_length, has_any_or_none,
                                 "length", "a", "bitstring template");
}

void BITSTRING_template::set_type(template_sel template_type,
  unsigned int list_length /* = 0 */)
{
  if (template_type != VALUE_LIST && template_type != COMPLEMENTED_LIST &&
      template_type != DECODE_MATCH && template_type != CONJUNCTION_MATCH)
    TTCN_error("Setting an invalid list type for a bitstring template.");
  clean_up();
  set_selection(template_type);
  if (template_type != DECODE_MATCH) {
    value_list.n_values = list_length;
    value_list.list_value = new BITSTRING_template[list_length];
  }
}

BITSTRING_template& BITSTRING_template::list_item(unsigned int list_index)
{
  if (template_selection != VALUE_LIST &&
      template_selection != COMPLEMENTED_LIST &&
      template_selection != CONJUNCTION_MATCH)
    TTCN_error("Accessing a list element of a non-list bitstring template.");
  if (list_index >= value_list.n_values)
    TTCN_error("Index overflow in a bitstring value list template.");
  return value_list.list_value[list_index];
}

void BITSTRING_template::set_decmatch(Dec_Match_Interface* new_instance)
{
  if (template_selection != DECODE_MATCH) {
    TTCN_error("Setting the decoded content matching mechanism of a non-decmatch "
      "bitstring template.");
  }
  dec_match = new decmatch_struct;
  dec_match->ref_count = 1;
  dec_match->instance = new_instance;
}

void* BITSTRING_template::get_decmatch_dec_res() const
{
  if (template_selection != DECODE_MATCH) {
    TTCN_error("Retrieving the decoding result of a non-decmatch bitstring "
      "template.");
  }
  return dec_match->instance->get_dec_res();
}

const TTCN_Typedescriptor_t* BITSTRING_template::get_decmatch_type_descr() const
{
  if (template_selection != DECODE_MATCH) {
    TTCN_error("Retrieving the decoded type's descriptor in a non-decmatch "
      "bitstring template.");
  }
  return dec_match->instance->get_type_descr();
}

static const char patterns[] = { '0', '1', '?', '*' };

void BITSTRING_template::log() const
{
  switch (template_selection) {
  case SPECIFIC_VALUE:
    single_value.log();
    break;
  case COMPLEMENTED_LIST:
    TTCN_Logger::log_event_str("complement");
    // no break
  case CONJUNCTION_MATCH:
    if (template_selection == CONJUNCTION_MATCH) {
      TTCN_Logger::log_event_str("conjunct");
    }
    // no break
  case VALUE_LIST:
    TTCN_Logger::log_char('(');
    for (unsigned int i = 0; i < value_list.n_values; i++) {
      if (i > 0) TTCN_Logger::log_event_str(", ");
      value_list.list_value[i].log();
    }
    TTCN_Logger::log_char(')');
    break;
  case STRING_PATTERN:
    TTCN_Logger::log_char('\'');
    for (unsigned int i = 0; i < pattern_value->n_elements; i++) {
      unsigned char pattern = pattern_value->elements_ptr[i];
      if (pattern < 4) TTCN_Logger::log_char(patterns[pattern]);
      else TTCN_Logger::log_event_str("<unknown>");
    }
    TTCN_Logger::log_event_str("'B");
    break;
  case DECODE_MATCH:
    TTCN_Logger::log_event_str("decmatch ");
    dec_match->instance->log();
    break;
  case IMPLICATION_MATCH:
    implication_.precondition->log();
    TTCN_Logger::log_event_str(" implies ");
    implication_.implied_template->log();
    break;
  case DYNAMIC_MATCH:
    TTCN_Logger::log_event_str("@dynamic template");
    break;
  default:
    log_generic();
    break;
  }
  log_restricted();
  log_ifpresent();
}

void BITSTRING_template::log_match(const BITSTRING& match_value,
                                   boolean /* legacy */) const
{
  if (TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity()
  &&  TTCN_Logger::get_logmatch_buffer_len() != 0) {
    TTCN_Logger::print_logmatch_buffer();
    TTCN_Logger::log_event_str(" := ");
  }
  match_value.log();
  TTCN_Logger::log_event_str(" with ");
  log();
  if (match(match_value)) TTCN_Logger::log_event_str(" matched");
  else TTCN_Logger::log_event_str(" unmatched");
}

void BITSTRING_template::set_param(Module_Param& param) {
  param.basic_check(Module_Param::BC_TEMPLATE|Module_Param::BC_LIST, "bitstring template");
  Module_Param_Ptr mp = &param;
#ifdef TITAN_RUNTIME_2
  if (param.get_type() == Module_Param::MP_Reference) {
    mp = param.get_referenced_param();
  }
#endif
  switch (mp->get_type()) {
  case Module_Param::MP_Omit:
    *this = OMIT_VALUE;
    break;
  case Module_Param::MP_Any:
    *this = ANY_VALUE;
    break;
  case Module_Param::MP_AnyOrNone:
    *this = ANY_OR_OMIT;
    break;
  case Module_Param::MP_List_Template:
  case Module_Param::MP_ComplementList_Template:
  case Module_Param::MP_ConjunctList_Template:  {
    BITSTRING_template temp;
    temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
      VALUE_LIST : (mp->get_type() == Module_Param::MP_ConjunctList_Template ?
      CONJUNCTION_MATCH : COMPLEMENTED_LIST), mp->get_size());
    for (size_t i=0; i<mp->get_size(); i++) {
      temp.list_item(i).set_param(*mp->get_elem(i));
    }
    *this = temp;
    break; }
  case Module_Param::MP_Bitstring:
    *this = BITSTRING(mp->get_string_size(), (unsigned char*)mp->get_string_data());
    break;
  case Module_Param::MP_Bitstring_Template:
    *this = BITSTRING_template(mp->get_string_size(), (unsigned char*)mp->get_string_data());
    break;
  case Module_Param::MP_Implication_Template: {
    BITSTRING_template* precondition = new BITSTRING_template;
    precondition->set_param(*mp->get_elem(0));
    BITSTRING_template* implied_template = new BITSTRING_template;
    implied_template->set_param(*mp->get_elem(1));
    *this = BITSTRING_template(precondition, implied_template);
  } break;
  case Module_Param::MP_Expression:
    if (mp->get_expr_type() == Module_Param::EXPR_CONCATENATE) {
      BITSTRING operand1, operand2;
      operand1.set_param(*mp->get_operand1());
      operand2.set_param(*mp->get_operand2());
      *this = operand1 + operand2;
    }
    else {
      param.expr_type_error("a bitstring");
    }
    break;
  default:
    param.type_error("bitstring template");
  }
  is_ifpresent = param.get_ifpresent() || mp->get_ifpresent();
  if (param.get_length_restriction() != NULL) {
    set_length_range(param);
  }
  else {
    set_length_range(*mp);
  }
}

#ifdef TITAN_RUNTIME_2
Module_Param* BITSTRING_template::get_param(Module_Param_Name& param_name) const
{
  Module_Param* mp = NULL;
  switch (template_selection) {
  case UNINITIALIZED_TEMPLATE:
    mp = new Module_Param_Unbound();
    break;
  case OMIT_VALUE:
    mp = new Module_Param_Omit();
    break;
  case ANY_VALUE:
    mp = new Module_Param_Any();
    break;
  case ANY_OR_OMIT:
    mp = new Module_Param_AnyOrNone();
    break;
  case SPECIFIC_VALUE:
    mp = single_value.get_param(param_name);
    break;
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
  case CONJUNCTION_MATCH: {
    if (template_selection == VALUE_LIST) {
      mp = new Module_Param_List_Template();
    }
    else if (template_selection == CONJUNCTION_MATCH) {
      mp = new Module_Param_ConjunctList_Template();
    }
    else {
      mp = new Module_Param_ComplementList_Template();
    }
    for (size_t i = 0; i < value_list.n_values; ++i) {
      mp->add_elem(value_list.list_value[i].get_param(param_name));
    }
    break; }
  case STRING_PATTERN: {
    unsigned char* val_cpy = (unsigned char*)Malloc(pattern_value->n_elements);
    memcpy(val_cpy, pattern_value->elements_ptr, pattern_value->n_elements);
    mp = new Module_Param_Bitstring_Template(pattern_value->n_elements, val_cpy);
    break; }
  case IMPLICATION_MATCH:
    mp = new Module_Param_Implication_Template();
    mp->add_elem(implication_.precondition->get_param(param_name));
    mp->add_elem(implication_.implied_template->get_param(param_name));
    break;
  case DECODE_MATCH:
    TTCN_error("Referencing a decoded content matching template is not supported.");
    break;
  default:
    TTCN_error("Referencing an uninitialized/unsupported bitstring template.");
    break;
  }
  if (is_ifpresent) {
    mp->set_ifpresent();
  }
  mp->set_length_restriction(get_length_range());
  return mp;
}
#endif

void BITSTRING_template::encode_text(Text_Buf& text_buf) const
{
  encode_text_restricted(text_buf);
  switch (template_selection) {
  case OMIT_VALUE:
  case ANY_VALUE:
  case ANY_OR_OMIT:
    break;
  case SPECIFIC_VALUE:
    single_value.encode_text(text_buf);
    break;
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
    text_buf.push_int(value_list.n_values);
    for (unsigned int i = 0; i < value_list.n_values; i++)
      value_list.list_value[i].encode_text(text_buf);
    break;
  case STRING_PATTERN:
    text_buf.push_int(pattern_value->n_elements);
    text_buf.push_raw(pattern_value->n_elements, pattern_value->elements_ptr);
    break;
  default:
    TTCN_error("Text encoder: Encoding an uninitialized/unsupported "
               "bitstring template.");
  }
}

void BITSTRING_template::decode_text(Text_Buf& text_buf)
{
  clean_up();
  decode_text_restricted(text_buf);
  switch (template_selection) {
  case OMIT_VALUE:
  case ANY_VALUE:
  case ANY_OR_OMIT:
    break;
  case SPECIFIC_VALUE:
    single_value.decode_text(text_buf);
    break;
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
    value_list.n_values = text_buf.pull_int().get_val();
    value_list.list_value = new BITSTRING_template[value_list.n_values];
    for (unsigned int i = 0; i < value_list.n_values; i++)
      value_list.list_value[i].decode_text(text_buf);
    break;
  case STRING_PATTERN: {
    unsigned int n_elements = text_buf.pull_int().get_val();
    pattern_value = (bitstring_pattern_struct*)
      Malloc(sizeof(bitstring_pattern_struct) + n_elements - 1);
    pattern_value->ref_count = 1;
    pattern_value->n_elements = n_elements;
    text_buf.pull_raw(n_elements, pattern_value->elements_ptr);
    break;}
  default:
    TTCN_error("Text decoder: An unknown/unsupported selection was "
               "received for a bitstring template.");
  }
}

boolean BITSTRING_template::is_present(boolean legacy /* = FALSE */) const
{
  if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE;
  return !match_omit(legacy);
}

boolean BITSTRING_template::match_omit(boolean legacy /* = FALSE */) const
{
  if (is_ifpresent) return TRUE;
  switch (template_selection) {
  case OMIT_VALUE:
  case ANY_OR_OMIT:
    return TRUE;
  case IMPLICATION_MATCH:
    return !implication_.precondition->match_omit() || implication_.implied_template->match_omit();
  case VALUE_LIST:
  case COMPLEMENTED_LIST:
    if (legacy) {
      // legacy behavior: 'omit' can appear in the value/complement list
      for (unsigned int i=0; i<value_list.n_values; i++)
        if (value_list.list_value[i].match_omit())
          return template_selection==VALUE_LIST;
      return template_selection==COMPLEMENTED_LIST;
    }
    // else fall through
  default:
    return FALSE;
  }
  return FALSE;
}

#ifndef TITAN_RUNTIME_2
void BITSTRING_template::check_restriction(template_res t_res, const char* t_name,
                                           boolean legacy /* = FALSE */) const
{
  if (template_selection==UNINITIALIZED_TEMPLATE) return;
  switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) {
  case TR_VALUE:
    if (!is_ifpresent && template_selection==SPECIFIC_VALUE) return;
    break;
  case TR_OMIT:
    if (!is_ifpresent && (template_selection==OMIT_VALUE ||
        template_selection==SPECIFIC_VALUE)) return;
    break;
  case TR_PRESENT:
    if (!match_omit(legacy)) return;
    break;
  default:
    return;
  }
  TTCN_error("Restriction `%s' on template of type %s violated.",
             get_res_name(t_res), t_name ? t_name : "bitstring");
}
#else
int BITSTRING::RAW_encode_negtest_raw(RAW_enc_tree& p_myleaf) const
{
  if (p_myleaf.must_free)
    Free(p_myleaf.body.leaf.data_ptr);
  p_myleaf.must_free = FALSE;
  p_myleaf.data_ptr_used = TRUE;
  p_myleaf.body.leaf.data_ptr = val_ptr->bits_ptr;
  return p_myleaf.length = val_ptr->n_bits;
}
#endif

#endif // #ifndef TITAN_ASN1ENC
