| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
| 3 | // All rights reserved. This program and the accompanying materials |
| 4 | // are made available under the terms of the Eclipse Public License v1.0 |
| 5 | // which accompanies this distribution, and is available at |
| 6 | // http://www.eclipse.org/legal/epl-v10.html |
| 7 | /////////////////////////////////////////////////////////////////////////////// |
| 8 | #include "../common/memory.h" |
| 9 | #include "datatypes.h" |
| 10 | #include "main.hh" |
| 11 | #include "encdec.h" |
| 12 | |
| 13 | void def_encdec(const char *p_classname, |
| 14 | char **p_classdef, char **p_classsrc, |
| 15 | boolean ber, boolean raw, boolean text, boolean xer, |
| 16 | boolean json, boolean is_leaf) |
| 17 | { |
| 18 | char *def=NULL; |
| 19 | char *src=NULL; |
| 20 | |
| 21 | def=mputstr |
| 22 | (def, |
| 23 | "void encode(const TTCN_Typedescriptor_t&, TTCN_Buffer&," |
| 24 | " TTCN_EncDec::coding_t, ...) const;\n" |
| 25 | "void decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&," |
| 26 | " TTCN_EncDec::coding_t, ...);\n"); |
| 27 | if(ber) |
| 28 | def=mputstr(def, |
| 29 | "ASN_BER_TLV_t* BER_encode_TLV(const TTCN_Typedescriptor_t& p_td," |
| 30 | " unsigned p_coding) const;\n" |
| 31 | "boolean BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, const" |
| 32 | " ASN_BER_TLV_t& p_tlv, unsigned L_form);\n" |
| 33 | ); |
| 34 | if(raw) |
| 35 | def=mputprintf(def, |
| 36 | "int RAW_encode(const TTCN_Typedescriptor_t&, RAW_enc_tree&) const;\n" |
| 37 | "int RAW_decode(const TTCN_Typedescriptor_t&, TTCN_Buffer&," |
| 38 | " int, raw_order_t, boolean no_err=FALSE," |
| 39 | "int sel_field=-1, boolean first_call=TRUE);\n" |
| 40 | ); |
| 41 | if(text) |
| 42 | def=mputprintf(def, |
| 43 | "int TEXT_encode(const TTCN_Typedescriptor_t&, TTCN_Buffer&) const;\n" |
| 44 | "int TEXT_decode(const TTCN_Typedescriptor_t&," |
| 45 | "TTCN_Buffer&, Limit_Token_List&, boolean no_err=FALSE," |
| 46 | "boolean first_call=TRUE);\n" |
| 47 | ); |
| 48 | if (xer) /* XERSTUFF encdec function headers */ |
| 49 | def=mputprintf(def, |
| 50 | #ifndef NDEBUG |
| 51 | "// written by %s in " __FILE__ " at %d\n" |
| 52 | #endif |
| 53 | "int XER_encode(const XERdescriptor_t&, TTCN_Buffer&, unsigned int, int, " |
| 54 | "embed_values_enc_struct_t*) const;\n" |
| 55 | "int XER_decode(const XERdescriptor_t&, XmlReaderWrap&, unsigned int, " |
| 56 | "embed_values_dec_struct_t*);\n" |
| 57 | "static boolean can_start(const char *name, const char *uri, " |
| 58 | "XERdescriptor_t const& xd, unsigned int);\n" |
| 59 | "%s" |
| 60 | #ifndef NDEBUG |
| 61 | , __FUNCTION__, __LINE__ |
| 62 | #endif |
| 63 | , use_runtime_2 ? |
| 64 | "boolean can_start_v(const char *name, const char *uri, " |
| 65 | "XERdescriptor_t const& xd, unsigned int);\n" : "" |
| 66 | ); |
| 67 | if(json) { |
| 68 | def = mputprintf(def, |
| 69 | "int JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&) const;\n" |
| 70 | "int JSON_decode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&, boolean);\n"); |
| 71 | } |
| 72 | |
| 73 | src=mputprintf(src, |
| 74 | "void %s::encode(const TTCN_Typedescriptor_t& p_td," |
| 75 | " TTCN_Buffer& p_buf, TTCN_EncDec::coding_t p_coding, ...) const\n" |
| 76 | "{\n" |
| 77 | " va_list pvar;\n" |
| 78 | " va_start(pvar, p_coding);\n" |
| 79 | " switch(p_coding) {\n" |
| 80 | " case TTCN_EncDec::CT_BER: {\n" |
| 81 | " TTCN_EncDec_ErrorContext ec(\"While BER-encoding type" |
| 82 | " '%%s': \", p_td.name);\n" |
| 83 | " unsigned BER_coding=va_arg(pvar, unsigned);\n" |
| 84 | " BER_encode_chk_coding(BER_coding);\n" |
| 85 | " ASN_BER_TLV_t *tlv=BER_encode_TLV(p_td, BER_coding);\n" |
| 86 | " tlv->put_in_buffer(p_buf);\n" |
| 87 | " ASN_BER_TLV_t::destruct(tlv);\n" |
| 88 | " break;}\n" |
| 89 | " case TTCN_EncDec::CT_RAW: {\n" |
| 90 | " TTCN_EncDec_ErrorContext ec(\"While RAW-encoding type" |
| 91 | " '%%s': \", p_td.name);\n" |
| 92 | " if(!p_td.raw)\n" |
| 93 | " TTCN_EncDec_ErrorContext::error_internal\n" |
| 94 | " (\"No RAW descriptor available for type '%%s'.\", p_td.name);\n" |
| 95 | " RAW_enc_tr_pos rp;\n" |
| 96 | " rp.level=0;\n" |
| 97 | " rp.pos=NULL;\n" |
| 98 | " RAW_enc_tree root(%s, NULL, &rp, 1, p_td.raw);\n" |
| 99 | " RAW_encode(p_td, root);\n" |
| 100 | " root.put_to_buf(p_buf);\n" |
| 101 | " break;}\n" |
| 102 | " case TTCN_EncDec::CT_TEXT: {\n" |
| 103 | " TTCN_EncDec_ErrorContext ec(" |
| 104 | "\"While TEXT-encoding type '%%s': \", p_td.name);\n" |
| 105 | " if(!p_td.text)\n" |
| 106 | " TTCN_EncDec_ErrorContext::error_internal\n" |
| 107 | " (\"No TEXT descriptor available for type '%%s'.\", p_td.name);\n" |
| 108 | " TEXT_encode(p_td,p_buf);\n" |
| 109 | " break;}\n" |
| 110 | /* XERSTUFF encoder */ |
| 111 | " case TTCN_EncDec::CT_XER: {\n" |
| 112 | " TTCN_EncDec_ErrorContext ec(" |
| 113 | "\"While XER-encoding type '%%s': \", p_td.name);\n" |
| 114 | " unsigned XER_coding=va_arg(pvar, unsigned);\n" |
| 115 | " XER_encode_chk_coding(XER_coding, p_td);\n" |
| 116 | /* Do not use %s_xer_ here. It supplies the XER descriptor of oldtype |
| 117 | * even if encoding newtype for: |
| 118 | * <ttcn>type newtype oldtype;</ttcn> */ |
| 119 | " XER_encode(*(p_td.xer),p_buf, XER_coding, 0, 0);\n" |
| 120 | " p_buf.put_c('\\n');\n" /* make sure it has a newline */ |
| 121 | " break;}\n" |
| 122 | " case TTCN_EncDec::CT_JSON: {\n" |
| 123 | " TTCN_EncDec_ErrorContext ec(" |
| 124 | "\"While JSON-encoding type '%%s': \", p_td.name);\n" |
| 125 | " if(!p_td.json)\n" |
| 126 | " TTCN_EncDec_ErrorContext::error_internal\n" |
| 127 | " (\"No JSON descriptor available for type '%%s'.\", p_td.name);\n" |
| 128 | " JSON_Tokenizer tok(va_arg(pvar, int) != 0);\n" |
| 129 | " JSON_encode(p_td, tok);\n" |
| 130 | " p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer());\n" |
| 131 | " break;}\n" |
| 132 | " default:\n" |
| 133 | " TTCN_error(\"Unknown coding method requested to encode" |
| 134 | " type '%%s'\", p_td.name);\n" |
| 135 | " }\n" |
| 136 | " va_end(pvar);\n" |
| 137 | "}\n" |
| 138 | "\n" |
| 139 | , p_classname, is_leaf?"TRUE":"FALSE" |
| 140 | ); |
| 141 | |
| 142 | src=mputprintf(src, |
| 143 | #ifndef NDEBUG |
| 144 | "// written by %s in " __FILE__ " at %d\n" |
| 145 | #endif |
| 146 | "void %s::decode(const TTCN_Typedescriptor_t& p_td," |
| 147 | " TTCN_Buffer& p_buf, TTCN_EncDec::coding_t p_coding, ...)\n" |
| 148 | "{\n" |
| 149 | " va_list pvar;\n" |
| 150 | " va_start(pvar, p_coding);\n" |
| 151 | " switch(p_coding) {\n" |
| 152 | " case TTCN_EncDec::CT_BER: {\n" |
| 153 | " TTCN_EncDec_ErrorContext ec(\"While BER-decoding type" |
| 154 | " '%%s': \", p_td.name);\n" |
| 155 | " unsigned L_form=va_arg(pvar, unsigned);\n" |
| 156 | " ASN_BER_TLV_t tlv;\n" |
| 157 | " BER_decode_str2TLV(p_buf, tlv, L_form);\n" |
| 158 | " BER_decode_TLV(p_td, tlv, L_form);\n" |
| 159 | " if(tlv.isComplete) p_buf.increase_pos(tlv.get_len());\n" |
| 160 | " break;}\n" |
| 161 | " case TTCN_EncDec::CT_RAW: {\n" |
| 162 | " TTCN_EncDec_ErrorContext ec(\"While RAW-decoding" |
| 163 | " type '%%s': \", p_td.name);\n" |
| 164 | " if(!p_td.raw)\n" |
| 165 | " TTCN_EncDec_ErrorContext::error_internal\n" |
| 166 | " (\"No RAW descriptor available for type '%%s'.\", p_td.name);\n" |
| 167 | " raw_order_t r_order;\n" |
| 168 | " switch(p_td.raw->top_bit_order) {\n" |
| 169 | " case TOP_BIT_LEFT:\n" |
| 170 | " r_order=ORDER_LSB;\n" |
| 171 | " break;\n" |
| 172 | " case TOP_BIT_RIGHT:\n" |
| 173 | " default:\n" |
| 174 | " r_order=ORDER_MSB;\n" |
| 175 | " }\n" |
| 176 | " int rawr = RAW_decode(p_td, p_buf, p_buf.get_len()*8, r_order);\n" |
| 177 | " if(rawr<0) switch (-rawr) {\n" |
| 178 | " case TTCN_EncDec::ET_INCOMPL_MSG:\n" |
| 179 | " case TTCN_EncDec::ET_LEN_ERR:\n" |
| 180 | " ec.error((TTCN_EncDec::error_type_t)-rawr, " |
| 181 | "\"Can not decode type '%%s', because incomplete message was received\", " |
| 182 | "p_td.name);\n" |
| 183 | " break;\n" |
| 184 | " case 1:\n" /* from the generic -1 return value */ |
| 185 | " default:\n" |
| 186 | " ec.error(TTCN_EncDec::ET_INVAL_MSG, " |
| 187 | "\"Can not decode type '%%s', because invalid " |
| 188 | "message was received\", p_td.name);\n" |
| 189 | " break;\n" |
| 190 | " }\n" |
| 191 | " break;}\n" |
| 192 | " case TTCN_EncDec::CT_TEXT: {\n" |
| 193 | " Limit_Token_List limit;\n" |
| 194 | " TTCN_EncDec_ErrorContext ec(\"While TEXT-decoding type '%%s': \"," |
| 195 | " p_td.name);\n" |
| 196 | " if(!p_td.text)\n" |
| 197 | " TTCN_EncDec_ErrorContext::error_internal\n" |
| 198 | " (\"No TEXT descriptor available for type '%%s'.\", p_td.name);\n" |
| 199 | " const unsigned char *b_data=p_buf.get_data();\n" |
| 200 | " if(b_data[p_buf.get_len()-1]!='\\0'){\n" |
| 201 | " p_buf.set_pos(p_buf.get_len());\n" |
| 202 | " p_buf.put_zero(8,ORDER_LSB);\n" |
| 203 | " p_buf.rewind();\n" |
| 204 | " }\n" |
| 205 | " if(TEXT_decode(p_td,p_buf,limit)<0)\n" |
| 206 | " ec.error(TTCN_EncDec::ET_INCOMPL_MSG," |
| 207 | "\"Can not decode type '%%s', because invalid or incomplete" |
| 208 | " message was received\", p_td.name);\n" |
| 209 | " break;}\n" |
| 210 | /* XERSTUFF decoder */ |
| 211 | " case TTCN_EncDec::CT_XER: {\n" |
| 212 | " TTCN_EncDec_ErrorContext ec(" |
| 213 | "\"While XER-decoding type '%%s': \", p_td.name);\n" |
| 214 | " unsigned XER_coding=va_arg(pvar, unsigned);\n" |
| 215 | " XER_encode_chk_coding(XER_coding, p_td);\n" |
| 216 | " XmlReaderWrap reader(p_buf);\n" |
| 217 | " for (int rd_ok=reader.Read(); rd_ok==1; rd_ok=reader.Read()) {\n" |
| 218 | " if (reader.NodeType() == XML_READER_TYPE_ELEMENT) break;\n" |
| 219 | " }\n" |
| 220 | " XER_decode(*(p_td.xer), reader, XER_coding | XER_TOPLEVEL, 0);\n" |
| 221 | " size_t bytes = reader.ByteConsumed();\n" |
| 222 | " p_buf.set_pos(bytes);\n" |
| 223 | " break;}\n" |
| 224 | " case TTCN_EncDec::CT_JSON: {\n" |
| 225 | " TTCN_EncDec_ErrorContext ec(\"While JSON-decoding type '%%s': \"," |
| 226 | " p_td.name);\n" |
| 227 | " if(!p_td.json)\n" |
| 228 | " TTCN_EncDec_ErrorContext::error_internal\n" |
| 229 | " (\"No JSON descriptor available for type '%%s'.\", p_td.name);\n" |
| 230 | " JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len());\n" |
| 231 | " if(JSON_decode(p_td, tok, false)<0)\n" |
| 232 | " ec.error(TTCN_EncDec::ET_INCOMPL_MSG," |
| 233 | "\"Can not decode type '%%s', because invalid or incomplete" |
| 234 | " message was received\", p_td.name);\n" |
| 235 | " p_buf.set_pos(tok.get_buf_pos());\n" |
| 236 | " break;}\n" |
| 237 | " default:\n" |
| 238 | " TTCN_error(\"Unknown coding method requested to decode" |
| 239 | " type '%%s'\", p_td.name);\n" |
| 240 | " }\n" |
| 241 | " va_end(pvar);\n" |
| 242 | "}\n\n" |
| 243 | #ifndef NDEBUG |
| 244 | , __FUNCTION__, __LINE__ |
| 245 | #endif |
| 246 | , p_classname); |
| 247 | |
| 248 | *p_classdef=mputstr(*p_classdef, def); |
| 249 | Free(def); |
| 250 | *p_classsrc=mputstr(*p_classsrc, src); |
| 251 | Free(src); |
| 252 | } |
| 253 | |
| 254 | char *genRawFieldChecker(char *src, const rawAST_coding_taglist *taglist, |
| 255 | boolean is_equal) |
| 256 | { |
| 257 | int i; |
| 258 | for (i = 0; i < taglist->nElements; i++) { |
| 259 | rawAST_coding_field_list *fields = taglist->fields + i; |
| 260 | char *field_name = NULL; |
| 261 | boolean first_expr = TRUE; |
| 262 | int j; |
| 263 | if (i > 0) src = mputstr(src, is_equal ? " || " : " && "); |
| 264 | for (j = 0; j < fields->nElements; j++) { |
| 265 | rawAST_coding_fields *field = fields->fields + j; |
| 266 | if (j == 0) { |
| 267 | /* this is the first field reference */ |
| 268 | if (field->fieldtype == UNION_FIELD) |
| 269 | field_name = mputprintf(field_name,"(*field_%s)",field->nthfieldname); |
| 270 | else |
| 271 | field_name = mputprintf(field_name,"field_%s", field->nthfieldname); |
| 272 | } |
| 273 | else { |
| 274 | /* this is not the first field reference */ |
| 275 | if (field->fieldtype == UNION_FIELD) { |
| 276 | /* checking for the right selection within the union */ |
| 277 | if (first_expr) { |
| 278 | if (taglist->nElements > 1) src = mputc(src, '('); |
| 279 | first_expr = FALSE; |
| 280 | } |
| 281 | else src = mputstr(src, is_equal ? " && " : " || "); |
| 282 | src = mputprintf(src, "%s.get_selection() %s %s%s%s", field_name, |
| 283 | is_equal ? "==" : "!=", fields->fields[j - 1].type, |
| 284 | "::ALT_", field->nthfieldname); |
| 285 | } |
| 286 | /* appending the current field name to the field reference */ |
| 287 | field_name = mputprintf(field_name, ".%s()", field->nthfieldname); |
| 288 | } |
| 289 | if (j < fields->nElements - 1 && field->fieldtype == OPTIONAL_FIELD) { |
| 290 | /* this is not the last field in the chain and it is optional */ |
| 291 | if (first_expr) { |
| 292 | if (taglist->nElements > 1) src = mputc(src, '('); |
| 293 | first_expr = FALSE; |
| 294 | } |
| 295 | else src = mputstr(src, is_equal ? " && " : " || "); |
| 296 | /* check for the presence */ |
| 297 | if (!is_equal) src = mputc(src, '!'); |
| 298 | src = mputprintf(src, "%s.ispresent()", field_name); |
| 299 | /* add an extra () to the field reference */ |
| 300 | field_name = mputstr(field_name, "()"); |
| 301 | } |
| 302 | } |
| 303 | if (!first_expr) src = mputstr(src, is_equal ? " && " : " || "); |
| 304 | /* compare the referred field with the given value */ |
| 305 | src = mputprintf(src, "%s %s %s", field_name, is_equal ? "==" : "!=", |
| 306 | fields->value); |
| 307 | if (!first_expr && taglist->nElements > 1) src = mputc(src, ')'); |
| 308 | Free(field_name); |
| 309 | } |
| 310 | return src; |
| 311 | } |
| 312 | |
| 313 | char *genRawTagChecker(char *src, const rawAST_coding_taglist *taglist) |
| 314 | { |
| 315 | int temp_tag, l; |
| 316 | rawAST_coding_field_list temp_field; |
| 317 | src = mputstr(src, " RAW_enc_tree* temp_leaf;\n"); |
| 318 | for (temp_tag = 0; temp_tag < taglist->nElements; temp_tag++) { |
| 319 | temp_field = taglist->fields[temp_tag]; |
| 320 | src = mputprintf(src, " {\n" |
| 321 | " RAW_enc_tr_pos pr_pos%d;\n" |
| 322 | " pr_pos%d.level=myleaf.curr_pos.level+%d;\n" |
| 323 | " int new_pos%d[]={", temp_tag, temp_tag, temp_field.nElements, temp_tag); |
| 324 | for (l = 0; l < temp_field.nElements; l++) { |
| 325 | src= mputprintf(src, "%s%d", l ? "," : "", temp_field.fields[l].nthfield); |
| 326 | } |
| 327 | src = mputprintf(src, "};\n" |
| 328 | " pr_pos%d.pos=init_new_tree_pos(myleaf.curr_pos,%d,new_pos%d);\n" |
| 329 | " temp_leaf = myleaf.get_node(pr_pos%d);\n" |
| 330 | " if(temp_leaf != NULL){\n", temp_tag, temp_field.nElements, temp_tag, temp_tag); |
| 331 | if (temp_field.value[0] != ' ') { |
| 332 | src = mputprintf(src, " %s new_val = %s;\n" |
| 333 | " new_val.RAW_encode(%s_descr_,*temp_leaf);\n", |
| 334 | temp_field.fields[temp_field.nElements - 1].type, temp_field.value, |
| 335 | temp_field.fields[temp_field.nElements - 1].typedescr); |
| 336 | } |
| 337 | else { |
| 338 | src = mputprintf(src, " %s.RAW_encode(%s_descr_,*temp_leaf);\n", |
| 339 | temp_field.value, temp_field.fields[temp_field.nElements - 1].typedescr); |
| 340 | } |
| 341 | src = mputstr(src, " } else"); |
| 342 | } |
| 343 | src = mputstr(src, " {\n" |
| 344 | " TTCN_EncDec_ErrorContext::error\n" |
| 345 | " (TTCN_EncDec::ET_OMITTED_TAG, \"Encoding a tagged, but omitted" |
| 346 | " value.\");\n" |
| 347 | " }\n"); |
| 348 | for (temp_tag = taglist->nElements - 1; temp_tag >= 0 ; temp_tag--) { |
| 349 | src = mputprintf(src, " free_tree_pos(pr_pos%d.pos);\n" |
| 350 | " }\n", temp_tag); |
| 351 | } |
| 352 | return src; |
| 353 | } |