Skip to content
Snippets Groups Projects
record.c 321 KiB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
Elemer Lelik's avatar
Elemer Lelik committed
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
Elemer Lelik's avatar
Elemer Lelik committed
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
Elemer Lelik's avatar
Elemer Lelik committed
 *
 * Contributors:
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Beres, Szabolcs
 *   Cserveni, Akos
 *   Delic, Adam
 *   Feher, Csaba
 *   Forstner, Matyas
 *   Kovacs, Ferenc
 *   Kremer, Peter
 *   Ormandi, Matyas
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
 *   Szabo, Janos Zoltan – initial implementation
 *   Szalai, Gabor
 *
 ******************************************************************************/
#include <string.h>
#include "datatypes.h"
#include "../common/memory.h"
#include "record.h"
#include "encdec.h"

#include "main.hh"
#include "error.h"
#include "ttcn3/compiler.h"

static void defEmptyRecordClass(const struct_def *sdef,
                                output_struct *output);

static void defEmptyRecordTemplate(const char *name, const char *dispname,
  output_struct *output);

/** this is common code for both empty and non-empty cases, called from
 *  both functions for template generation */
static void defCommonRecordTemplate(const char *name,
  char **def, char **src);

/** code generation for original runtime */
static void defRecordClass1(const struct_def *sdef, output_struct *output);
static void defRecordTemplate1(const struct_def *sdef, output_struct *output);
/** code generation for alternative runtime (TITAN_RUNTIME_2) */
static void defRecordClass2(const struct_def *sdef, output_struct *output);
static void defRecordTemplate2(const struct_def *sdef, output_struct *output);

void defRecordClass(const struct_def *sdef, output_struct *output)
{
  if (use_runtime_2) defRecordClass2(sdef, output);
  else defRecordClass1(sdef, output);
}

void defRecordTemplate(const struct_def *sdef, output_struct *output)
{
  if (use_runtime_2) defRecordTemplate2(sdef, output);
  else defRecordTemplate1(sdef, output);
}

struct raw_option_struct {
  boolean lengthto; /* indicates whether this field contains a length */
  int lengthof; /* how many length indicators this field counted in */
  int *lengthoffield; /* the list of length indicator field indices */
  boolean pointerto;
  int pointerof;
  boolean ptrbase;
  int extbitgroup;
  int tag_type;
  boolean delayed_decode; /* indicates whether the field has to be decoded
			 out of order (later) */
  int nof_dependent_fields; /* list of fields that are to be decoded */
  int *dependent_fields; /* after this field */
};

static char *genRawFieldDecodeLimit(char *src, const struct_def *sdef,
  int i, const struct raw_option_struct *raw_options);

static char *genRawDecodeRecordField(char *src, const struct_def *sdef,
  int i, const struct raw_option_struct *raw_options, boolean delayed_decode,
  int *prev_ext_group);

static void set_raw_options(const struct_def *sdef,
  struct raw_option_struct *raw_options, boolean* haslengthto,
  boolean* haspointer, boolean* hascrosstag, boolean* has_ext_bit);

static char *generate_raw_coding(char *src,
  const struct_def *sdef, struct raw_option_struct *raw_options,
  boolean haspointer, boolean hascrosstag, boolean has_ext_bit);
static char *generate_raw_coding_negtest(char *src,
  const struct_def *sdef, struct raw_option_struct *raw_options);

void set_raw_options(const struct_def *sdef,
  struct raw_option_struct *raw_options, boolean *haslengthto,
  boolean *haspointer, boolean *hascrosstag, boolean *has_ext_bit)
{
Kristof Szabados's avatar
Kristof Szabados committed
    size_t i;
    for (i = 0; i < sdef->nElements; i++) {
      raw_options[i].lengthto = FALSE;
      raw_options[i].lengthof = 0;
      raw_options[i].lengthoffield = NULL;
      raw_options[i].pointerto = FALSE;
      raw_options[i].pointerof = 0;
      raw_options[i].ptrbase = FALSE;
      raw_options[i].extbitgroup = 0;
      raw_options[i].tag_type = 0;
      raw_options[i].delayed_decode = FALSE;
      raw_options[i].nof_dependent_fields = 0;
      raw_options[i].dependent_fields = NULL;
    }
    *haslengthto = FALSE;
    *haspointer = FALSE;
    *hascrosstag = FALSE;
    *has_ext_bit = sdef->hasRaw && sdef->raw.extension_bit!=XDEFNO &&
                                  sdef->raw.extension_bit!=XDEFDEFAULT;
    for(i=0;i<sdef->nElements;i++){
      if(sdef->elements[i].hasRaw &&
                                 sdef->elements[i].raw.crosstaglist.nElements){
        *hascrosstag = TRUE;
        break;
      }
    }
    if(sdef->hasRaw){ /* fill tag_type. 0-No tag, >0 index of the tag + 1 */
      for(i=0;i<sdef->raw.taglist.nElements;i++){
        raw_options[sdef->raw.taglist.list[i].fieldnum].tag_type= i+1;
      }
      for(i=0;i<sdef->raw.ext_bit_goup_num;i++){
        int k;
        for(k=sdef->raw.ext_bit_groups[i].from;
                                    k<=sdef->raw.ext_bit_groups[i].to;k++)
            raw_options[k].extbitgroup=i+1;
      }
    }
    for(i=0;i<sdef->nElements;i++){
      if (sdef->elements[i].hasRaw && sdef->elements[i].raw.lengthto_num > 0) {
        int j;
        *haslengthto = TRUE;
        raw_options[i].lengthto = TRUE;
        for(j = 0; j < sdef->elements[i].raw.lengthto_num; j++) {
	  int field_index = sdef->elements[i].raw.lengthto[j];
	  raw_options[field_index].lengthoffield = (int*)
	    Realloc(raw_options[field_index].lengthoffield,
	      (raw_options[field_index].lengthof + 1) * sizeof(int));
	  raw_options[field_index].lengthoffield[
	    raw_options[field_index].lengthof] = i;
	  raw_options[field_index].lengthof++;
        }
      }
      if(sdef->elements[i].hasRaw && sdef->elements[i].raw.pointerto!=-1){
        raw_options[i].pointerto = TRUE;
        raw_options[sdef->elements[i].raw.pointerto].pointerof=i+1;
        *haspointer = TRUE;
        raw_options[sdef->elements[i].raw.pointerbase].ptrbase = TRUE;
      }
    }
    if (sdef->kind == RECORD && *hascrosstag) {
      /* looking for fields that require delayed decoding because of
	 forward references in CROSSTAG */
      for (i = 0; i < sdef->nElements; i++) {
        int j;
	/* we are looking for a field index that is greater than i */
	size_t max_index = i;
	if (!sdef->elements[i].hasRaw) continue;
	for (j = 0; j < sdef->elements[i].raw.crosstaglist.nElements; j++) {
	  int k;
	  rawAST_coding_taglist *crosstag =
	    sdef->elements[i].raw.crosstaglist.list + j;
	  for (k = 0; k < crosstag->nElements; k++) {
	    rawAST_coding_field_list *keyid = crosstag->fields + k;
	    if (keyid->nElements >= 1) {
	      int field_index = keyid->fields[0].nthfield;
	      if (field_index > max_index) max_index = field_index;
	    }
	  }
	}
	if (max_index > i) {
	  raw_options[i].delayed_decode = TRUE;
	  raw_options[max_index].nof_dependent_fields++;
	  raw_options[max_index].dependent_fields = (int*)
	    Realloc(raw_options[max_index].dependent_fields,
	      raw_options[max_index].nof_dependent_fields *
	      sizeof(*raw_options[max_index].dependent_fields));
	  raw_options[max_index].dependent_fields[
	    raw_options[max_index].nof_dependent_fields - 1] = i;
	}
      }
    }
}

char* generate_raw_coding(char* src,
  const struct_def *sdef, struct raw_option_struct *raw_options,
    boolean haspointer, boolean hascrosstag, boolean has_ext_bit)
{
  int i;
  const char *name = sdef->name;

  if (sdef->kind == SET) { /* set decoder start */
    size_t mand_num = 0;
    for (i = 0; i < sdef->nElements; i++) {
      if (!sdef->elements[i].isOptional) mand_num++;
    }
    src = mputprintf(src, "int %s::RAW_decode(const TTCN_Typedescriptor_t& "
      "p_td, TTCN_Buffer& p_buf, int limit, raw_order_t top_bit_ord, "
      "boolean, int, boolean, const RAW_Force_Omit* force_omit)\n"
      "{\n"
        "int prepaddlength = p_buf.increase_pos_padd(p_td.raw->prepadding);\n"
        "limit -= prepaddlength;\n"
        "int decoded_length = 0;\n"
        "int field_map[%lu];\n"
        "memset(field_map, 0, sizeof(field_map));\n",
        name, (unsigned long) sdef->nElements);
    if (mand_num > 0)
      src = mputstr(src, "size_t nof_mand_fields = 0;\n");
    for (i = 0; i < sdef->nElements; i++) {
      if (sdef->elements[i].isOptional)
        src = mputprintf(src, "field_%s = OMIT_VALUE;\n",
                         sdef->elements[i].name);
    }
      src = mputstr(src,
	"raw_order_t local_top_order;\n"
      "if (p_td.raw->top_bit_order == TOP_BIT_INHERITED) "
	"local_top_order = top_bit_ord;\n"
      "else if (p_td.raw->top_bit_order == TOP_BIT_RIGHT) "
	"local_top_order = ORDER_MSB;\n"
      "else local_top_order = ORDER_LSB;\n"
      "while (limit > 0) {\n"
      "size_t fl_start_pos = p_buf.get_pos_bit();\n"
      );
      for (i = 0; i < sdef->nElements; i++) { /* decoding fields with tag */
	if (raw_options[i].tag_type &&
	    sdef->raw.taglist.list[raw_options[i].tag_type - 1].nElements > 0) {
	  rawAST_coding_taglist* cur_choice =
	    sdef->raw.taglist.list + raw_options[i].tag_type - 1;
	  size_t j;
	  boolean has_fixed = FALSE, has_variable = FALSE, flag_needed = FALSE;
	  for (j = 0; j < cur_choice->nElements; j++) {
	    if (cur_choice->fields[j].start_pos >= 0) {
	      if (has_fixed || has_variable) flag_needed = TRUE;
	      has_fixed = TRUE;
	    } else {
	      if (has_fixed) flag_needed = TRUE;
	      has_variable = TRUE;
	    }
	    if (has_fixed && has_variable) break;
	  }
	  src = mputprintf(src, "if (field_map[%lu] == 0",
            (unsigned long) i);
    if (sdef->elements[i].isOptional) {
      src = mputprintf(src, " && (force_omit == NULL || !(*force_omit)(%d))", i);
    }
    src = mputstr(src, ") {\n");
	  if (flag_needed)
	    src = mputstr(src, "boolean already_failed = FALSE;\n");
	  if (has_fixed) {
	    /* first check the fields we can precode
	     * try to decode those key variables whose position we know
	     * this way we might be able to step over bad values faster
	     */
	    boolean first_fixed = TRUE;
	    src = mputstr(src, "raw_order_t temporal_top_order;\n"
	      "int temporal_decoded_length;\n");
	    for (j = 0; j < cur_choice->nElements; j++) {
	      size_t k;
	      rawAST_coding_field_list *cur_field_list = cur_choice->fields + j;
	      if (cur_field_list->start_pos < 0) continue;
	      if (!first_fixed) src = mputstr(src, "if (!already_failed) {\n");
	      for (k = cur_field_list->nElements - 1; k > 0; k--) {
		src = mputprintf(src, "if (%s_descr_.raw->top_bit_order == "
		  "TOP_BIT_RIGHT) temporal_top_order = ORDER_MSB;\n"
		"else if (%s_descr_.raw->top_bit_order == TOP_BIT_LEFT) "
		  "temporal_top_order = ORDER_LSB;\n"
		"else ", cur_field_list->fields[k - 1].typedescr,
		cur_field_list->fields[k - 1].typedescr);
	      }
	      src = mputprintf(src, "temporal_top_order = top_bit_ord;\n"
		"%s temporal_%lu;\n"
		"p_buf.set_pos_bit(fl_start_pos + %d);\n"
		"temporal_decoded_length = temporal_%lu.RAW_decode(%s_descr_, "
		  "p_buf, limit, temporal_top_order, TRUE);\n"
		"p_buf.set_pos_bit(fl_start_pos);\n"
		"if (temporal_decoded_length > 0 && temporal_%lu == %s) {\n"
    "RAW_Force_Omit field_%d_force_omit(%d, force_omit, "
    "%s_descr_.raw->forceomit);\n"
		"int decoded_field_length = field_%s%s.RAW_decode(%s_descr_, "
		  "p_buf, limit, local_top_order, TRUE, -1, TRUE, &field_%d_force_omit);\n"
		"if (decoded_field_length %s 0 && (",
		cur_field_list->fields[cur_field_list->nElements - 1].type,
		(unsigned long) j, cur_field_list->start_pos, (unsigned long) j,
		cur_field_list->fields[cur_field_list->nElements - 1].typedescr,
		(unsigned long) j, cur_field_list->value,
    i, i, sdef->elements[i].typedescrname,
                sdef->elements[i].name,
		sdef->elements[i].isOptional ? "()" : "",
		sdef->elements[i].typedescrname, i,
		sdef->elements[i].isOptional ? ">" : ">=");
	      src = genRawFieldChecker(src, cur_choice, TRUE);
	      src = mputstr(src, ")) {\n"
		"decoded_length += decoded_field_length;\n"
		"limit -= decoded_field_length;\n");
	      if (!sdef->elements[i].isOptional)
		src = mputstr(src, "nof_mand_fields++;\n");
	      src = mputprintf(src, "field_map[%lu] = 1;\n"
		"continue;\n"
		"} else {\n"
		"p_buf.set_pos_bit(fl_start_pos);\n", (unsigned long) i);
	      if (sdef->elements[i].isOptional)
		src = mputprintf(src, "field_%s = OMIT_VALUE;\n",
		  sdef->elements[i].name);
	      if (flag_needed) src = mputstr(src, "already_failed = TRUE;\n");
	      src = mputstr(src, "}\n"
		"}\n");
	      if (first_fixed) first_fixed = FALSE;
	      else src = mputstr(src, "}\n");
	    }
	  }
	  if (has_variable) {
	    /* if there is one tag key whose position we don't know
	     * and we couldn't decide yet if element can be decoded or not
	     * than we have to decode it.
	     */
	    if (flag_needed) src = mputstr(src, "if (!already_failed) {\n");
	    src = mputprintf(src, 
    "RAW_Force_Omit field_%d_force_omit(%d, force_omit, "
    "%s_descr_.raw->forceomit);\n"
    "int decoded_field_length = "
		"field_%s%s.RAW_decode(%s_descr_, p_buf, limit, "
		"local_top_order, TRUE, -1, TRUE, &field_%d_force_omit);\n"
	      "if (decoded_field_length %s 0 && (",
	      i, i, sdef->elements[i].typedescrname,
        sdef->elements[i].name, sdef->elements[i].isOptional ? "()" : "",
	      sdef->elements[i].typedescrname, i,
	      sdef->elements[i].isOptional ? ">" : ">=");
	    src = genRawFieldChecker(src, cur_choice, TRUE);
	    src = mputstr(src, ")) {\n"
	      "decoded_length += decoded_field_length;\n"
	      "limit -= decoded_field_length;\n");
	    if (!sdef->elements[i].isOptional)
	      src = mputstr(src, "nof_mand_fields++;\n");
	    src = mputprintf(src, "field_map[%lu] = 1;\n"
	      "continue;\n"
	      "} else {\n"
	      "p_buf.set_pos_bit(fl_start_pos);\n", (unsigned long) i);
	    if (sdef->elements[i].isOptional)
	      src = mputprintf(src, "field_%s = OMIT_VALUE;\n",
		sdef->elements[i].name);
	    src = mputstr(src, "}\n");
	    if (flag_needed) src = mputstr(src, "}\n");
	  }
	  src = mputstr(src, "}\n");
	}
      }
      for (i = 0; i < sdef->nElements; i++) {
	/* decoding fields without TAG */
	if (!raw_options[i].tag_type) {
	  boolean repeatable;
	  if (sdef->elements[i].of_type && sdef->elements[i].hasRaw &&
	      sdef->elements[i].raw.repeatable == XDEFYES) {
      repeatable = TRUE;
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src, "if (force_omit == NULL || !(*force_omit)(%d)) ", i);
      }
    }
	  else {
	    repeatable = FALSE;
	    src = mputprintf(src, "if (field_map[%lu] == 0",
            (unsigned long) i);
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src, " && (force_omit == NULL || !(*force_omit)(%d))", i);
      }
      src = mputstr(src, ") ");
	  }
	  src = mputprintf(src, "{\n"
      "RAW_Force_Omit field_%d_force_omit(%d, force_omit, "
      "%s_descr_.raw->forceomit);\n"
	    "int decoded_field_length = field_%s%s.RAW_decode(%s_descr_, "
	      "p_buf, limit, local_top_order, TRUE, %s, ",
      i, i, sdef->elements[i].typedescrname,
	    sdef->elements[i].name, sdef->elements[i].isOptional ? "()" : "",
	    sdef->elements[i].typedescrname, repeatable?"1":"-1");
	  if (repeatable)
            src = mputprintf(src, "field_map[%lu] == 0",
              (unsigned long) i);
    else {
      src = mputstr(src, "TRUE");
    }
	  src = mputprintf(src, ", &field_%d_force_omit);\n"
	    "if (decoded_field_length %s 0) {\n"
	    "decoded_length += decoded_field_length;\n"
	    "limit -= decoded_field_length;\n",
	    i, sdef->elements[i].isOptional ? ">" : ">=");
	  if (repeatable) {
	    if (!sdef->elements[i].isOptional) src = mputprintf(src,
	      "if (field_map[%lu] == 0) nof_mand_fields++;\n",
              (unsigned long) i);
	    src = mputprintf(src, "field_map[%lu]++;\n", (unsigned long) i);
	  } else {
	    if (!sdef->elements[i].isOptional)
	      src = mputstr(src, "nof_mand_fields++;\n");
	    src = mputprintf(src, "field_map[%lu] = 1;\n", (unsigned long) i);
	  }
	  src = mputstr(src, "continue;\n"
	    "} else {\n"
	    "p_buf.set_pos_bit(fl_start_pos);\n");
	  if (sdef->elements[i].isOptional) {
	    if (repeatable)
	      src = mputprintf(src, "if (field_map[%lu] == 0) ",
                (unsigned long) i);
	    src = mputprintf(src, "field_%s = OMIT_VALUE;\n",
	      sdef->elements[i].name);
	  }
	  src = mputstr(src, "}\n"
	    "}\n");
	}
      }
      for (i = 0; i < sdef->nElements; i++){
	/* decoding fields with tag OTHERWISE */
	if (raw_options[i].tag_type &&
	    sdef->raw.taglist.list[raw_options[i].tag_type-1].nElements == 0) {
	  src = mputprintf(src, "if (field_map[%lu] == 0", (unsigned long) i);
    if (sdef->elements[i].isOptional) {
      src = mputprintf(src, " && (force_omit == NULL || !(*force_omit)(%d))", i);
    }
    src = mputprintf(src, ") {\n"
      "RAW_Force_Omit field_%d_force_omit(%d, force_omit, "
      "%s_descr_.raw->forceomit);\n"
	    "int decoded_field_length = field_%s%s.RAW_decode(%s_descr_, "
	      "p_buf, limit, local_top_order, TRUE, -1, TRUE, &field_%d_force_omit);\n"
	    "if (decoded_field_length %s 0) {\n"
	    "decoded_length += decoded_field_length;\n"
	    "limit -= decoded_field_length;\n",
      i, i, sdef->elements[i].typedescrname,
	    sdef->elements[i].name, sdef->elements[i].isOptional ? "()" : "",
	    sdef->elements[i].typedescrname, i,
	    sdef->elements[i].isOptional ? ">" : ">=");
	  if (!sdef->elements[i].isOptional)
	    src = mputstr(src, "nof_mand_fields++;\n");
	  src = mputprintf(src, "field_map[%lu] = 1;\n"
	    "continue;\n"
	    "} else {\n"
	    "p_buf.set_pos_bit(fl_start_pos);\n", (unsigned long) i);
	  if (sdef->elements[i].isOptional)
	    src = mputprintf(src, "field_%s = OMIT_VALUE;\n",
	      sdef->elements[i].name);
	  src = mputstr(src, "}\n"
	    "}\n");
	}
      }
      src = mputstr(src, "break;\n"  /* no field decoded successfully, quit */
        "}\n");
      if (mand_num > 0) src = mputprintf(src,
        "if (nof_mand_fields != %lu) return limit ? -1 : -TTCN_EncDec::ET_INCOMPL_MSG;\n",
        (unsigned long) mand_num);
      /* If not all required fields were decoded and there are no bits left,
       * that means that the last field was decoded successfully but used up
       * the buffer. Signal "incomplete". If there were bits left, that means that
       * no field could be decoded from them; signal an error.
       */
      src = mputstr(src, "return decoded_length + prepaddlength + "
	"p_buf.increase_pos_padd(p_td.raw->padding);\n"
      "}\n\n");
  } else {
    /* set decoder end, record decoder start */
    int prev_ext_group = 0;
    src = mputprintf(src,
      "int %s::RAW_decode(const TTCN_Typedescriptor_t& p_td, "
      "TTCN_Buffer& p_buf, int limit, raw_order_t top_bit_ord, boolean no_err, "
      "int, boolean, const RAW_Force_Omit* force_omit)\n"
      "{ (void)no_err;\n"
	"  int prepaddlength=p_buf.increase_pos_padd(p_td.raw->prepadding);\n"
	"  limit-=prepaddlength;\n"
	"  size_t last_decoded_pos = p_buf.get_pos_bit();\n"
	"  int decoded_length = 0;\n"
	"  int decoded_field_length = 0;\n"
	"  raw_order_t local_top_order;\n"
	, name);
      if (hascrosstag) {
	src = mputstr(src, "  int selected_field = -1;\n");
      }
      if (sdef->raw.ext_bit_goup_num) {
        src=mputstr(src, "  int group_limit = 0;\n");
      }
      src=mputstr(src,
      "  if(p_td.raw->top_bit_order==TOP_BIT_INHERITED)"
      "local_top_order=top_bit_ord;\n"
      "  else if(p_td.raw->top_bit_order==TOP_BIT_RIGHT)local_top_order"
      "=ORDER_MSB;\n"
      "  else local_top_order=ORDER_LSB;\n"
      );
      if(has_ext_bit){
        src=mputstr(src,
          "  {\n"
          "  cbyte* data=p_buf.get_read_data();\n"
          "  int count=1;\n"
          "  unsigned mask = 1 << (local_top_order==ORDER_LSB ? 0 : 7);\n"
          "  if(p_td.raw->extension_bit==EXT_BIT_YES){\n"
          "    while((data[count-1] & mask)==0 && count*8<(int)limit) count++;\n"
          "  }\n"
          "  else{\n"
          "    while((data[count-1] & mask)!=0 && count*8<(int)limit) count++;\n"
          "  }\n"
          "  if(limit) limit=count*8;\n"
          "  }\n"
        );
      }
      if(haspointer)
       src=mputstr(src,
         "  int end_of_available_data=last_decoded_pos+limit;\n");
      for(i=0;i<sdef->nElements;i++){
        if(raw_options[i].pointerof)
          src=mputprintf(src,
          "  int start_of_field%lu=-1;\n"
          ,(unsigned long) i
          );
        if(raw_options[i].ptrbase)
          src=mputprintf(src,
          "  int start_pos_of_field%lu=-1;\n"
          ,(unsigned long) i
          );
        if(raw_options[i].lengthto)
          src=mputprintf(src,
          "  int value_of_length_field%lu = 0;\n"
          ,(unsigned long) i
          );
      }
      for(i=0;i<sdef->nElements;i++){ /* decoding fields */
	if (raw_options[i].delayed_decode) {
	  int j;
	  /* checking whether there are enough bits in the buffer to decode
	     the field */
	  src = mputstr(src, "  if (");
	  src = genRawFieldDecodeLimit(src, sdef, i, raw_options);
	  src = mputprintf(src, " < %d) return -TTCN_EncDec::ET_LEN_ERR;\n",
	    sdef->elements[i].raw.length);
	  /* skipping over the field that has to be decoded later because of
	     forward referencing in CROSSTAG */
	  src = mputprintf(src,
	    "  size_t start_of_field%lu = p_buf.get_pos_bit();\n"
	    "  p_buf.set_pos_bit(start_of_field%lu + %d);\n"
	    "  decoded_length += %d;\n"
	    "  last_decoded_pos += %d;\n"
	    "  limit -= %d;\n",
	    (unsigned long) i, (unsigned long) i, sdef->elements[i].raw.length,
            sdef->elements[i].raw.length,
	    sdef->elements[i].raw.length, sdef->elements[i].raw.length);
	  for (j = 0; j < raw_options[i].lengthof; j++) {
	    src = mputprintf(src,
	      "  value_of_length_field%d -= %d;\n",
	      raw_options[i].lengthoffield[j], sdef->elements[i].raw.length);
	  }
	} else {
	  src = genRawDecodeRecordField(src, sdef, i, raw_options, FALSE,
	   &prev_ext_group);
	  if (raw_options[i].nof_dependent_fields > 0) {
	    int j;
	    for (j = 0; j < raw_options[i].nof_dependent_fields; j++) {
	      int dependent_field_index = raw_options[i].dependent_fields[j];
	      /* seek to the beginning of the dependent field */
	      src = mputprintf(src,
		"  p_buf.set_pos_bit(start_of_field%d);\n",
		dependent_field_index);
	      /* decode the dependent field */
	      src = genRawDecodeRecordField(src, sdef, dependent_field_index,
		raw_options, TRUE, &prev_ext_group);
	    }
	    if (i < sdef->nElements - 1) {
	      /* seek back if there are more regular fields to decode */
	      src = mputstr(src,
		"  p_buf.set_pos_bit(last_decoded_pos);\n");
	    }
	  }
	}
      } /* decoding fields*/

      if(sdef->hasRaw && sdef->raw.presence.nElements > 0)
      {
	src = mputstr(src, "  if (");
	src = genRawFieldChecker(src, &sdef->raw.presence, FALSE);
	src = mputstr(src, ") return -1;\n");
      }

      src=mputstr(src,
      "  p_buf.set_pos_bit(last_decoded_pos);\n"
      "  return decoded_length+prepaddlength+"
      "p_buf.increase_pos_padd(p_td.raw->padding);\n}\n\n");
  } /* record decoder end */

  src = mputprintf(src, /* encoder */
    "int %s::RAW_encode(const TTCN_Typedescriptor_t&%s, "
    "RAW_enc_tree& myleaf) const {\n", name,
    use_runtime_2 ? " p_td" : "");
  if (use_runtime_2) {
    src = mputstr(src, "  if (err_descr) return RAW_encode_negtest(err_descr, p_td, myleaf);\n");
  }
  src = mputprintf(src,
    "  if (!is_bound()) TTCN_EncDec_ErrorContext::error"
    "(TTCN_EncDec::ET_UNBOUND, \"Encoding an unbound value.\");\n"
    "  int encoded_length = 0;\n"
    "  myleaf.isleaf = FALSE;\n"
    "  myleaf.body.node.num_of_nodes = %lu;\n"
    "  myleaf.body.node.nodes = init_nodes_of_enc_tree(%lu);\n",
    (unsigned long)sdef->nElements, (unsigned long)sdef->nElements);
  /* init nodes */
  for (i = 0; i < sdef->nElements; i++) {
    if (sdef->elements[i].isOptional) {
      src = mputprintf(src,
        "  if (field_%s.ispresent()) {\n", sdef->elements[i].name);
    }
    src = mputprintf(src,
      "  myleaf.body.node.nodes[%lu] = new RAW_enc_tree(TRUE, &myleaf, "
      "&(myleaf.curr_pos), %lu, %s_descr_.raw);\n",
      (unsigned long)i, (unsigned long)i, sdef->elements[i].typedescrname);
    if (sdef->elements[i].isOptional) {
      src = mputprintf(src,
        "  }\n"
        "  else myleaf.body.node.nodes[%lu] = NULL;\n", (unsigned long)i);
    }
  }
  for (i = 0; i < sdef->raw.ext_bit_goup_num; i++) {
    if (sdef->raw.ext_bit_groups[i].ext_bit != XDEFNO) {
      src = mputprintf(src,
        "  {\n"
        "   int node_idx = %d;\n"
        "   while (node_idx <= %d && myleaf.body.node.nodes[node_idx] == NULL) node_idx++;\n"
        "   if (myleaf.body.node.nodes[node_idx]) {\n"
        "     myleaf.body.node.nodes[node_idx]->ext_bit_handling = 1;\n"
        "     myleaf.body.node.nodes[node_idx]->ext_bit = %s;\n  }\n"
        "   node_idx = %d;\n"
        "   while (node_idx >= %d && myleaf.body.node.nodes[node_idx] == NULL) node_idx--;\n"
        "   if (myleaf.body.node.nodes[node_idx]) myleaf.body.node.nodes[node_idx]"
        "->ext_bit_handling += 2;\n"
        "  }\n",
        sdef->raw.ext_bit_groups[i].from,
        sdef->raw.ext_bit_groups[i].to,
        sdef->raw.ext_bit_groups[i].ext_bit == XDEFYES ? "EXT_BIT_YES" : "EXT_BIT_REVERSE",
        sdef->raw.ext_bit_groups[i].to,
        sdef->raw.ext_bit_groups[i].from);
    }
  }
  for (i = 0; i < sdef->nElements; i++) {
    /* encoding fields */
    if (sdef->elements[i].isOptional) {
      src = mputprintf(src,
        "  if (field_%s.ispresent()) {\n", sdef->elements[i].name);
    }
    if (raw_options[i].lengthto && sdef->elements[i].raw.lengthindex == NULL
        && sdef->elements[i].raw.union_member_num == 0) {
      /* encoding of lenghto fields */
      int a;
      src = mputprintf(src,
        "  encoded_length += %d;\n"
        "  myleaf.body.node.nodes[%lu]->calc = CALC_LENGTH;\n"
        "  myleaf.body.node.nodes[%lu]->coding_descr = &%s_descr_;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.lengthto.num_of_fields = %d;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.lengthto.unit = %d;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.lengthto.offset = %d;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.lengthto.fields = "
        "init_lengthto_fields_list(%d);\n"
        "  myleaf.body.node.nodes[%lu]->length = %d;\n",
        sdef->elements[i].raw.fieldlength, (unsigned long)i,
        (unsigned long)i, sdef->elements[i].typedescrname,
        (unsigned long)i, sdef->elements[i].raw.lengthto_num,
        (unsigned long)i, sdef->elements[i].raw.unit,
        (unsigned long)i, sdef->elements[i].raw.lengthto_offset,
        (unsigned long)i, sdef->elements[i].raw.lengthto_num,
        (unsigned long)i, sdef->elements[i].raw.fieldlength);
      for (a = 0; a < sdef->elements[i].raw.lengthto_num; a++) {
        if (sdef->elements[sdef->elements[i].raw.lengthto[a]].isOptional) {
          src = mputprintf(src,
            "  if (field_%s.ispresent()) {\n",
            sdef->elements[sdef->elements[i].raw.lengthto[a]].name);
        }
        src = mputprintf(src,
          "  myleaf.body.node.nodes[%lu]->calcof.lengthto.fields[%d].level = "
          "myleaf.body.node.nodes[%d]->curr_pos.level;\n"
          "  myleaf.body.node.nodes[%lu]->calcof.lengthto.fields[%d].pos = "
          "myleaf.body.node.nodes[%d]->curr_pos.pos;\n",
          (unsigned long)i, a, sdef->elements[i].raw.lengthto[a],
          (unsigned long)i, a, sdef->elements[i].raw.lengthto[a]);
        if (sdef->elements[sdef->elements[i].raw.lengthto[a]].isOptional) {
          src = mputprintf(src,
            "  } else {\n"
            "  myleaf.body.node.nodes[%lu]->calcof.lengthto.fields[%d].level = 0;\n"
            "  myleaf.body.node.nodes[%lu]->calcof.lengthto.fields[%d].pos = 0;\n"
            "  }\n", (unsigned long)i, a, (unsigned long)i, a);
        }
      }
    } else if (raw_options[i].pointerto) {
      /* encoding of pointerto fields */
      if (sdef->elements[sdef->elements[i].raw.pointerto].isOptional) {
        src = mputprintf(src,
          "  if (field_%s.ispresent()) {\n",
          sdef->elements[sdef->elements[i].raw.pointerto].name);
      }
      src = mputprintf(src,
        "  encoded_length += %d;\n"
        "  myleaf.body.node.nodes[%lu]->calc = CALC_POINTER;\n"
        "  myleaf.body.node.nodes[%lu]->coding_descr = &%s_descr_;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.pointerto.unit = %d;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.pointerto.ptr_offset = %d;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.pointerto.ptr_base = %d;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.pointerto.target.level = "
        "myleaf.body.node.nodes[%d]->curr_pos.level;\n"
        "  myleaf.body.node.nodes[%lu]->calcof.pointerto.target.pos = "
        "myleaf.body.node.nodes[%d]->curr_pos.pos;\n"
        "  myleaf.body.node.nodes[%lu]->length = %d;\n",
        sdef->elements[i].raw.fieldlength,(unsigned long)i,
        (unsigned long)i, sdef->elements[i].typedescrname,
        (unsigned long)i, sdef->elements[i].raw.unit,
        (unsigned long)i, sdef->elements[i].raw.ptroffset,
        (unsigned long)i, sdef->elements[i].raw.pointerbase,
        (unsigned long)i, sdef->elements[i].raw.pointerto,
        (unsigned long)i, sdef->elements[i].raw.pointerto,
        (unsigned long)i, sdef->elements[i].raw.fieldlength);
      if (sdef->elements[sdef->elements[i].raw.pointerto].isOptional) {
        src = mputprintf(src,
          "  } else {\n"
          "    INTEGER atm;\n"
          "    atm = 0;\n"
          "    encoded_length += atm.RAW_encode(%s_descr_"
          ", *myleaf.body.node.nodes[%lu]);\n"
          "  }\n",
          sdef->elements[i].typedescrname, (unsigned long)i);
      }
    } else {
      /* encoding of normal fields */
      src = mputprintf(src,
        "  encoded_length += field_%s%s.RAW_encode(%s_descr_"
        ", *myleaf.body.node.nodes[%lu]);\n",
        sdef->elements[i].name, sdef->elements[i].isOptional ? "()" : "",
        sdef->elements[i].typedescrname, (unsigned long)i);
    }
    if (sdef->elements[i].isOptional) {
      src = mputstr(src, "  }\n");
    }
  }
  for (i = 0; i < sdef->nElements; i++) {
    /* fill presence, tag and crosstag */
    if (raw_options[i].lengthto && sdef->elements[i].raw.lengthindex) {
      /* encoding of lenghto fields */
      int a;
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src,
          "  if (field_%s.ispresent()) {\n",
          sdef->elements[i].name);
      }
      src = mputprintf(src,
        "  if (myleaf.body.node.nodes[%lu]->body.node.nodes[%d]) {\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
        "calc = CALC_LENGTH;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
        "coding_descr = &%s_descr_;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
        "calcof.lengthto.num_of_fields = %d;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
        "calcof.lengthto.unit = %d;\n"
         "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
        "calcof.lengthto.offset = %d;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
        "calcof.lengthto.fields = "
        "init_lengthto_fields_list(%d);\n",
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        sdef->elements[i].raw.lengthindex->typedescr,
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        sdef->elements[i].raw.lengthto_num,
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        sdef->elements[i].raw.unit,
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        sdef->elements[i].raw.lengthto_offset,
        (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield,
        sdef->elements[i].raw.lengthto_num);
      for (a = 0; a < sdef->elements[i].raw.lengthto_num; a++) {
        if (sdef->elements[sdef->elements[i].raw.lengthto[a]].isOptional) {
          src = mputprintf(src,
            "  if (field_%s.ispresent()) {\n",
            sdef->elements[sdef->elements[i].raw.lengthto[a]].name);
        }
        src = mputprintf(src,
          "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]"
          "->calcof.lengthto.fields[%d].level = "
          "myleaf.body.node.nodes[%d]->curr_pos.level;\n"
          "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]"
          "->calcof.lengthto.fields[%d].pos = "
          "myleaf.body.node.nodes[%d]->curr_pos.pos;\n",
          (unsigned long)i,sdef->elements[i].raw.lengthindex->nthfield,
          a, sdef->elements[i].raw.lengthto[a],
          (unsigned long)i,sdef->elements[i].raw.lengthindex->nthfield,
          a, sdef->elements[i].raw.lengthto[a]);
        if (sdef->elements[sdef->elements[i].raw.lengthto[a]].isOptional) {
           src = mputprintf(src,
           "  } else {\n"
           "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
           "calcof.lengthto.fields[%d].level = 0;\n"
           "  myleaf.body.node.nodes[%lu]->body.node.nodes[%d]->"
           "calcof.lengthto.fields[%d].pos = 0;\n"
           "  }\n",
           (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield, a,
           (unsigned long)i, sdef->elements[i].raw.lengthindex->nthfield, a);
        }
      }
      src = mputstr(src, "  }\n");
      if (sdef->elements[i].isOptional) {
        src = mputstr(src, "  }\n");
      }
    }
    if (raw_options[i].lengthto && sdef->elements[i].raw.union_member_num) {
      /* encoding of lenghto fields */
      int a;
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src,
          "  if (field_%s.ispresent()) ", sdef->elements[i].name);
      }

      src = mputprintf(src,
        "  {\n"
        "  int sel_field = 0;\n"
        "  while (myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field] == NULL) "
        "{ sel_field++; }\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]->"
        "calc = CALC_LENGTH;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]->"
        "calcof.lengthto.num_of_fields = %d;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]->"
        "calcof.lengthto.unit = %d;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]->"
        "calcof.lengthto.offset = %d;\n"
        "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]->"
        "calcof.lengthto.fields = init_lengthto_fields_list(%d);\n",
        (unsigned long)i,(unsigned long)i,
        (unsigned long)i,sdef->elements[i].raw.lengthto_num,
        (unsigned long)i,sdef->elements[i].raw.unit,
        (unsigned long)i,sdef->elements[i].raw.lengthto_offset,
        (unsigned long)i,sdef->elements[i].raw.lengthto_num);
      for (a = 0; a < sdef->elements[i].raw.lengthto_num; a++) {
        if (sdef->elements[sdef->elements[i].raw.lengthto[a]].isOptional) {
          src = mputprintf(src,
            "  if (field_%s.ispresent()) {\n",
            sdef->elements[sdef->elements[i].raw.lengthto[a]].name);
        }
        src = mputprintf(src,
          "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]"
          "->calcof.lengthto.fields[%d].level = "
          "myleaf.body.node.nodes[%d]->curr_pos.level;\n"
          "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]"
          "->calcof.lengthto.fields[%d].pos = "
          "myleaf.body.node.nodes[%d]->curr_pos.pos;\n",
          (unsigned long)i, a, sdef->elements[i].raw.lengthto[a],
          (unsigned long)i, a, sdef->elements[i].raw.lengthto[a]);
        if (sdef->elements[sdef->elements[i].raw.lengthto[a]].isOptional) {
          src = mputprintf(src,
            "  }else{\n"
            "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]"
            "->calcof.lengthto.fields[%d].level = 0;\n"
            "  myleaf.body.node.nodes[%lu]->body.node.nodes[sel_field]"
            "->calcof.lengthto.fields[%d].pos = 0;\n"
            "  }\n",
            (unsigned long)i, a,
            (unsigned long)i, a);
        }
      }
      src = mputstr(src,
        "  }\n");
    }
    if (raw_options[i].tag_type && sdef->raw.taglist.list[raw_options[i].tag_type - 1].nElements) {
      /* tag */
      rawAST_coding_taglist *cur_choice =
        sdef->raw.taglist.list + raw_options[i].tag_type - 1;
      src = mputstr(src, "  if (");
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src, "field_%s.ispresent() && (", sdef->elements[i].name);
      }
      src = genRawFieldChecker(src, cur_choice, FALSE);
      if (sdef->elements[i].isOptional) src = mputstr(src, ")");
      src = mputstr(src,") {\n");
      src = genRawTagChecker(src, cur_choice);
      src=mputstr(src,"  }\n");
    }
    if (sdef->elements[i].hasRaw && sdef->elements[i].raw.presence.nElements) {
      /* presence */
      src = mputstr(src, "  if (");
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src, "field_%s.ispresent() && (", sdef->elements[i].name);
      }
      src = genRawFieldChecker(src, &sdef->elements[i].raw.presence, FALSE);
      if (sdef->elements[i].isOptional) src = mputstr(src, ")");
      src = mputstr(src, ") {\n");
      src = genRawTagChecker(src, &sdef->elements[i].raw.presence);
      src = mputstr(src,"  }\n");
    }
    if (sdef->elements[i].hasRaw &&
        sdef->elements[i].raw.crosstaglist.nElements) {
      /* crosstag */
      int a;
      if (sdef->elements[i].isOptional) {
        src = mputprintf(src,
          "  if (field_%s.ispresent()) {\n",
          sdef->elements[i].name);
      }
      src = mputprintf(src,
        "  switch (field_%s%s.get_selection()) {\n",
        sdef->elements[i].name,sdef->elements[i].isOptional ? "()" : "");
      for (a = 0; a < sdef->elements[i].raw.crosstaglist.nElements; a++) {
        rawAST_coding_taglist *cur_choice =
	  sdef->elements[i].raw.crosstaglist.list + a;
        if (cur_choice->nElements > 0) {
	    src = mputprintf(src, "  case %s%s%s:\n"
	      "  if (", sdef->elements[i].type,
	      "::ALT_", cur_choice->fieldName);
	    src = genRawFieldChecker(src, cur_choice, FALSE);
	    src = mputstr(src, ") {\n");
	    if (!strcmp(cur_choice->fields[0].value, "OMIT_VALUE")) {
	      if (cur_choice->fields[0].nElements != 1)
		NOTSUPP("omit value with multiple fields in CROSSTAG");
	      /* eliminating the corresponding encoded leaf, which will have
	         the same effect as if the referred field had been omit */
	      src = mputprintf(src,
		"  encoded_length -= myleaf.body.node.nodes[%d]->length;\n"
		"  delete myleaf.body.node.nodes[%d];\n"
		"  myleaf.body.node.nodes[%d] = NULL;\n",
		cur_choice->fields[0].fields[0].nthfield,
		cur_choice->fields[0].fields[0].nthfield,
		cur_choice->fields[0].fields[0].nthfield);
	    } else {
	      int ll;
	      src = mputprintf(src,
		"  RAW_enc_tr_pos pr_pos;\n"
		"  pr_pos.level = myleaf.curr_pos.level + %d;\n"
		"  int new_pos[] = { ",
		cur_choice->fields[0].nElements);
              for (ll = 0; ll < cur_choice->fields[0].nElements; ll++) {
		if (ll > 0) src = mputstr(src, ", ");
		src = mputprintf(src, "%d",
		  cur_choice->fields[0].fields[ll].nthfield);
              }
	      src = mputprintf(src, " };\n"
		"  pr_pos.pos = init_new_tree_pos(myleaf.curr_pos, %d, "
		  "new_pos);\n",
		cur_choice->fields[0].nElements);
              if (cur_choice->fields[0].value[0] == ' ') {
	        /* the value is a string literal (the encoder can be called
		   on that object directly */
		src = mputprintf(src,
		  "  RAW_enc_tree* temp_leaf = myleaf.get_node(pr_pos);\n"
                  "  if (temp_leaf != NULL)\n"
                  "    %s.RAW_encode(%s_descr_,*temp_leaf);\n"
                  "  else\n"
                  "    TTCN_EncDec_ErrorContext::error\n"
                  "      (TTCN_EncDec::ET_OMITTED_TAG, \"Encoding a tagged,"
                  " but omitted value.\");\n",
		  cur_choice->fields[0].value,
		  cur_choice->fields[0].fields[
		    cur_choice->fields[0].nElements - 1].typedescr);
	      } else {
	        /* a temporary object needs to be created for encoding */
		src = mputprintf(src,
		  "  %s new_val(%s);\n"
                  "  RAW_enc_tree* temp_leaf = myleaf.get_node(pr_pos);\n"
                  "  if (temp_leaf != NULL)\n"
                  "    new_val.RAW_encode(%s_descr_,*temp_leaf);\n"
                  "  else\n"
                  "    TTCN_EncDec_ErrorContext::error\n"
                  "      (TTCN_EncDec::ET_OMITTED_TAG, \"Encoding a tagged,"
                  " but omitted value.\");\n",
		  cur_choice->fields[0].fields[
		    cur_choice->fields[0].nElements - 1].type,
		  cur_choice->fields[0].value,
		  cur_choice->fields[0].fields[
		    cur_choice->fields[0].nElements - 1].typedescr);
              }
              src = mputstr(src, "  free_tree_pos(pr_pos.pos);\n");
	    }
	    src = mputstr(src, "  }\n"
	      "  break;\n");
          }
        }
        src = mputstr(src, "  default:;\n"
          "  }\n");
        if (sdef->elements[i].isOptional) src = mputstr(src, "  }\n");
      }
    }
  /* presence */
  if (sdef->hasRaw && sdef->raw.presence.nElements > 0) {
    src = mputstr(src, "  if (");
    src = genRawFieldChecker(src, &sdef->raw.presence, FALSE);
    src = mputstr(src,") {\n");
    src = genRawTagChecker(src, &sdef->raw.presence);
    src = mputstr(src,"  }\n");
  }
  src = mputstr(src, "  return myleaf.length = encoded_length;\n}\n\n");

  if (use_runtime_2)
    src = generate_raw_coding_negtest(src, sdef, raw_options);
  return src;