Commit | Line | Data |
---|---|---|
970ed795 | 1 | /////////////////////////////////////////////////////////////////////////////// |
3abe9331 | 2 | // Copyright (c) 2000-2015 Ericsson Telecom AB |
970ed795 EL |
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 "Objid.hh" | |
9 | ||
10 | #include "../common/dbgnew.hh" | |
11 | #include <errno.h> | |
12 | #include <limits.h> | |
13 | #include "../common/static_check.h" | |
14 | #include "Integer.hh" | |
15 | ||
16 | static const size_t MIN_COMPONENTS = 2; | |
17 | ||
18 | struct OBJID::objid_struct { | |
19 | unsigned int ref_count; | |
20 | int n_components; ///< number of elements in \a components_ptr (min. 2) | |
21 | int overflow_idx; ///< index of the first overflow, or -1 | |
22 | objid_element components_ptr[MIN_COMPONENTS]; | |
23 | }; | |
24 | ||
25 | #define OBJID_FMT "%u" | |
26 | //#define OBJID_FMT "%lu" | |
27 | ||
28 | void OBJID::init_struct(int n_components) | |
29 | { | |
30 | if (n_components < 0) { | |
31 | val_ptr = NULL; | |
32 | TTCN_error("Initializing an objid value with a negative number of " | |
33 | "components."); | |
34 | } | |
35 | // TODO check n_components >= 2 | |
36 | val_ptr = (objid_struct*)Malloc(sizeof(objid_struct) | |
37 | + (n_components - MIN_COMPONENTS) * sizeof(objid_element)); | |
38 | val_ptr->ref_count = 1; | |
39 | val_ptr->n_components = n_components; | |
40 | val_ptr->overflow_idx = -1; | |
41 | } | |
42 | ||
43 | void OBJID::copy_value() | |
44 | { | |
45 | if (val_ptr != NULL && val_ptr->ref_count > 1) { | |
46 | objid_struct *old_ptr = val_ptr; | |
47 | old_ptr->ref_count--; | |
48 | init_struct(old_ptr->n_components); // val_ptr reallocated | |
49 | memcpy(val_ptr->components_ptr, old_ptr->components_ptr, | |
50 | old_ptr->n_components * sizeof(objid_element)); | |
51 | val_ptr->overflow_idx = old_ptr->overflow_idx; | |
52 | } | |
53 | } | |
54 | ||
55 | void OBJID::clean_up() | |
56 | { | |
57 | if (val_ptr != NULL) { | |
58 | if (val_ptr->ref_count > 1) val_ptr->ref_count--; | |
59 | else if (val_ptr->ref_count == 1) Free(val_ptr); | |
60 | else TTCN_error("Internal error: Invalid reference counter in an objid " | |
61 | "value."); | |
62 | val_ptr = NULL; | |
63 | } | |
64 | } | |
65 | ||
66 | OBJID::OBJID() | |
67 | { | |
68 | val_ptr = NULL; // unbound | |
69 | } | |
70 | ||
71 | OBJID::OBJID(int init_n_components, ...) | |
72 | { | |
73 | init_struct(init_n_components); | |
74 | va_list ap; | |
75 | va_start(ap, init_n_components); | |
76 | for (int i = 0; i < init_n_components; i++) { | |
77 | val_ptr->components_ptr[i] = va_arg(ap, objid_element); | |
78 | } | |
79 | va_end(ap); | |
80 | } | |
81 | ||
82 | ||
83 | OBJID::OBJID(int init_n_components, const objid_element *init_components) | |
84 | { | |
85 | init_struct(init_n_components); | |
86 | memcpy(val_ptr->components_ptr, init_components, init_n_components * | |
87 | sizeof(objid_element)); | |
88 | } | |
89 | ||
90 | OBJID::OBJID(const OBJID& other_value) | |
91 | : Base_Type(other_value) | |
92 | { | |
93 | if (other_value.val_ptr == NULL) | |
94 | TTCN_error("Copying an unbound objid value."); | |
95 | val_ptr = other_value.val_ptr; | |
96 | val_ptr->ref_count++; | |
97 | } | |
98 | ||
99 | OBJID::~OBJID() | |
100 | { | |
101 | clean_up(); | |
102 | } | |
103 | ||
104 | OBJID& OBJID::operator=(const OBJID& other_value) | |
105 | { | |
106 | if (other_value.val_ptr == NULL) | |
107 | TTCN_error("Assignment of an unbound objid value."); | |
108 | if (&other_value != this) { | |
109 | clean_up(); | |
110 | val_ptr = other_value.val_ptr; | |
111 | val_ptr->ref_count++; | |
112 | } | |
113 | return *this; | |
114 | } | |
115 | ||
116 | boolean OBJID::operator==(const OBJID& other_value) const | |
117 | { | |
118 | if (val_ptr == NULL) TTCN_error("The left operand of comparison is an " | |
119 | "unbound objid value."); | |
120 | if (other_value.val_ptr == NULL) TTCN_error("The right operand of comparison " | |
121 | "is an unbound objid value."); | |
122 | if (val_ptr->n_components != other_value.val_ptr->n_components) return FALSE; | |
123 | if (val_ptr->overflow_idx != other_value.val_ptr->overflow_idx) return FALSE; | |
124 | return !memcmp(val_ptr->components_ptr, | |
125 | other_value.val_ptr->components_ptr, | |
126 | val_ptr->n_components * sizeof(objid_element)); | |
127 | } | |
128 | ||
129 | OBJID::objid_element& OBJID::operator[](int index_value) | |
130 | { | |
131 | if (val_ptr == NULL) { | |
132 | if (index_value != 0) | |
133 | TTCN_error("Accessing a component of an unbound objid value."); | |
134 | init_struct(1); | |
135 | return val_ptr->components_ptr[0]; | |
136 | } else { | |
137 | if (index_value < 0) TTCN_error("Accessing an objid component using " | |
138 | "a negative index (%d).", index_value); | |
139 | int n_components = val_ptr->n_components; | |
140 | if (index_value > n_components) TTCN_error("Index overflow when accessing " | |
141 | "an objid component: the index is %d, but the value has only %d " | |
142 | "components.", index_value, n_components); | |
143 | else if (index_value == n_components) { | |
144 | if (val_ptr->ref_count == 1) { | |
145 | val_ptr = (objid_struct*) | |
146 | Realloc(val_ptr, sizeof(objid_struct) | |
147 | + n_components * sizeof(objid_element)); | |
148 | val_ptr->n_components++; | |
149 | } else { | |
150 | objid_struct *old_ptr = val_ptr; | |
151 | old_ptr->ref_count--; | |
152 | init_struct(n_components + 1); | |
153 | memcpy(val_ptr->components_ptr, old_ptr->components_ptr, | |
154 | n_components * sizeof(objid_element)); | |
155 | } | |
156 | } | |
157 | return val_ptr->components_ptr[index_value]; | |
158 | } | |
159 | } | |
160 | ||
161 | OBJID::objid_element OBJID::operator[](int index_value) const | |
162 | { | |
163 | if (val_ptr == NULL) | |
164 | TTCN_error("Accessing a component of an unbound objid value."); | |
165 | if (index_value < 0) | |
166 | TTCN_error("Accessing an objid component using a negative index (%d).", | |
167 | index_value); | |
168 | if (index_value >= val_ptr->n_components) TTCN_error("Index overflow when " | |
169 | "accessing an objid component: the index is %d, but the value has only %d " | |
170 | "components.", index_value, val_ptr->n_components); | |
171 | return val_ptr->components_ptr[index_value]; | |
172 | } | |
173 | ||
174 | int OBJID::size_of() const | |
175 | { | |
176 | if (val_ptr == NULL) | |
177 | TTCN_error("Getting the size of an unbound objid value."); | |
178 | return val_ptr->n_components; | |
179 | } | |
180 | ||
181 | OBJID::operator const objid_element*() const | |
182 | { | |
183 | if (val_ptr == NULL) | |
184 | TTCN_error("Casting an unbound objid value to const int*."); | |
185 | return val_ptr->components_ptr; | |
186 | } | |
187 | ||
188 | OBJID::objid_element OBJID::from_INTEGER(const INTEGER& p_int) | |
189 | { | |
190 | int_val_t i_val = p_int.get_val(); | |
191 | if (i_val.is_negative()) { | |
192 | TTCN_error("An OBJECT IDENTIFIER component cannot be negative"); | |
193 | } | |
194 | if (!i_val.is_native()) { | |
195 | TTCN_error("The value of an OBJECT IDENTIFIER component cannot exceed %u", | |
196 | INT_MAX); | |
197 | } | |
198 | return (OBJID::objid_element)i_val.get_val(); | |
199 | } | |
200 | ||
201 | void OBJID::log() const | |
202 | { | |
203 | if (val_ptr != NULL) { | |
204 | TTCN_Logger::log_event_str("objid { "); | |
205 | for (int i = 0; i < val_ptr->n_components; i++) { | |
206 | if (i == val_ptr->overflow_idx) { | |
207 | TTCN_Logger::log_event_str("overflow:"); | |
208 | } | |
209 | ||
210 | TTCN_Logger::log_event(OBJID_FMT " ", val_ptr->components_ptr[i]); | |
211 | } | |
212 | TTCN_Logger::log_char('}'); | |
213 | } else TTCN_Logger::log_event_unbound(); | |
214 | } | |
215 | ||
216 | void OBJID::set_param(Module_Param& param) { | |
217 | param.basic_check(Module_Param::BC_VALUE, "objid value"); | |
3abe9331 | 218 | Module_Param_Ptr mp = ¶m; |
219 | if (param.get_type() == Module_Param::MP_Reference) { | |
220 | mp = param.get_referenced_param(); | |
221 | } | |
222 | if (mp->get_type()!=Module_Param::MP_Objid) param.type_error("objid value"); | |
970ed795 EL |
223 | if (sizeof(objid_element)!=sizeof(int)) TTCN_error("Internal error: OBJID::set_param()"); |
224 | clean_up(); | |
3abe9331 | 225 | init_struct(mp->get_string_size()); |
226 | memcpy(val_ptr->components_ptr, mp->get_string_data(), val_ptr->n_components * sizeof(objid_element)); | |
227 | } | |
228 | ||
229 | Module_Param* OBJID::get_param(Module_Param_Name& /* param_name */) const | |
230 | { | |
231 | if (!is_bound()) { | |
232 | return new Module_Param_Unbound(); | |
233 | } | |
234 | int* val_cpy = (int *)Malloc(val_ptr->n_components); | |
235 | memcpy(val_cpy, val_ptr->components_ptr, val_ptr->n_components * sizeof(int)); | |
236 | return new Module_Param_Objid(val_ptr->n_components, val_cpy); | |
970ed795 EL |
237 | } |
238 | ||
239 | void OBJID::encode_text(Text_Buf& text_buf) const | |
240 | { | |
241 | if (val_ptr == NULL) | |
242 | TTCN_error("Text encoder: Encoding an unbound objid value."); | |
243 | text_buf.push_int(val_ptr->n_components); | |
244 | for (int i = 0; i < val_ptr->n_components; i++) | |
245 | text_buf.push_int(val_ptr->components_ptr[i]); | |
246 | } | |
247 | ||
248 | void OBJID::decode_text(Text_Buf& text_buf) | |
249 | { | |
250 | int n_components = text_buf.pull_int().get_val(); | |
251 | if (n_components < 0) TTCN_error("Text decoder: Negative number of " | |
252 | "components was received for an objid value."); | |
253 | clean_up(); | |
254 | init_struct(n_components); | |
255 | for (int i = 0; i < n_components; i++) | |
256 | val_ptr->components_ptr[i] = text_buf.pull_int().get_val(); | |
257 | } | |
258 | ||
259 | void OBJID::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, | |
260 | TTCN_EncDec::coding_t p_coding, ...) const | |
261 | { | |
262 | va_list pvar; | |
263 | va_start(pvar, p_coding); | |
264 | switch(p_coding) { | |
265 | case TTCN_EncDec::CT_BER: { | |
266 | TTCN_EncDec_ErrorContext ec("While BER-encoding type '%s': ", p_td.name); | |
267 | unsigned BER_coding=va_arg(pvar, unsigned); | |
268 | BER_encode_chk_coding(BER_coding); | |
269 | ASN_BER_TLV_t *tlv=BER_encode_TLV(p_td, BER_coding); | |
270 | tlv->put_in_buffer(p_buf); | |
271 | ASN_BER_TLV_t::destruct(tlv); | |
272 | break;} | |
273 | case TTCN_EncDec::CT_RAW: { | |
274 | TTCN_EncDec_ErrorContext ec("While RAW-encoding type '%s': ", p_td.name); | |
275 | TTCN_EncDec_ErrorContext::error_internal | |
276 | ("No RAW descriptor available for type '%s'.", p_td.name); | |
277 | break;} | |
278 | case TTCN_EncDec::CT_XER: { | |
279 | TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name); | |
280 | unsigned XER_coding=va_arg(pvar, unsigned); | |
af710487 | 281 | XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0); |
282 | break;} | |
283 | case TTCN_EncDec::CT_JSON: { | |
284 | TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name); | |
285 | if(!p_td.json) | |
286 | TTCN_EncDec_ErrorContext::error_internal | |
287 | ("No JSON descriptor available for type '%s'.", p_td.name); | |
288 | JSON_Tokenizer tok(va_arg(pvar, int) != 0); | |
289 | JSON_encode(p_td, tok); | |
290 | p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer()); | |
970ed795 EL |
291 | break;} |
292 | default: | |
293 | TTCN_error("Unknown coding method requested to encode type '%s'", | |
294 | p_td.name); | |
295 | } | |
296 | va_end(pvar); | |
297 | } | |
298 | ||
299 | void OBJID::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf, | |
300 | TTCN_EncDec::coding_t p_coding, ...) | |
301 | { | |
302 | va_list pvar; | |
303 | va_start(pvar, p_coding); | |
304 | switch(p_coding) { | |
305 | case TTCN_EncDec::CT_BER: { | |
306 | TTCN_EncDec_ErrorContext ec("While BER-decoding type '%s': ", p_td.name); | |
307 | unsigned L_form=va_arg(pvar, unsigned); | |
308 | ASN_BER_TLV_t tlv; | |
309 | BER_decode_str2TLV(p_buf, tlv, L_form); | |
310 | BER_decode_TLV(p_td, tlv, L_form); | |
311 | if(tlv.isComplete) p_buf.increase_pos(tlv.get_len()); | |
312 | break;} | |
313 | case TTCN_EncDec::CT_RAW: { | |
314 | TTCN_EncDec_ErrorContext ec("While RAW-decoding type '%s': ", p_td.name); | |
315 | TTCN_EncDec_ErrorContext::error_internal | |
316 | ("No RAW descriptor available for type '%s'.", p_td.name); | |
317 | break;} | |
318 | case TTCN_EncDec::CT_XER: { | |
af710487 | 319 | TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name); |
970ed795 EL |
320 | unsigned XER_coding=va_arg(pvar, unsigned); |
321 | XmlReaderWrap reader(p_buf); | |
322 | int success = reader.Read(); | |
323 | for (; success==1; success=reader.Read()) { | |
324 | int type = reader.NodeType(); | |
325 | if (type==XML_READER_TYPE_ELEMENT) | |
326 | break; | |
327 | } | |
af710487 | 328 | XER_decode(*p_td.xer, reader, XER_coding, 0); |
970ed795 EL |
329 | size_t bytes = reader.ByteConsumed(); |
330 | p_buf.set_pos(bytes); | |
331 | break;} | |
af710487 | 332 | case TTCN_EncDec::CT_JSON: { |
333 | TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name); | |
334 | if(!p_td.json) | |
335 | TTCN_EncDec_ErrorContext::error_internal | |
336 | ("No JSON descriptor available for type '%s'.", p_td.name); | |
337 | JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len()); | |
338 | if(JSON_decode(p_td, tok, false)<0) | |
339 | ec.error(TTCN_EncDec::ET_INCOMPL_MSG, | |
340 | "Can not decode type '%s', because invalid or incomplete" | |
341 | " message was received" | |
342 | , p_td.name); | |
343 | p_buf.set_pos(tok.get_buf_pos()); | |
344 | break;} | |
970ed795 EL |
345 | default: |
346 | TTCN_error("Unknown coding method requested to decode type '%s'", | |
347 | p_td.name); | |
348 | } | |
349 | va_end(pvar); | |
350 | } | |
351 | ||
352 | ASN_BER_TLV_t* | |
353 | OBJID::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td, | |
354 | unsigned p_coding) const | |
355 | { | |
356 | BER_chk_descr(p_td); | |
357 | ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound()); | |
358 | if(!new_tlv) { | |
359 | size_t V_len=0; | |
360 | switch(p_td.asnbasetype) { | |
361 | case TTCN_Typedescriptor_t::OBJID: | |
362 | if(val_ptr->n_components<2) | |
363 | TTCN_EncDec_ErrorContext::error_internal | |
364 | ("OBJID must have at least 2 components."); | |
365 | V_len=(min_needed_bits(val_ptr->components_ptr[0]*40 | |
366 | +val_ptr->components_ptr[1])+6)/7; | |
367 | for(int i=2; i<val_ptr->n_components; i++) | |
368 | V_len+=(min_needed_bits(val_ptr->components_ptr[i])+6)/7; | |
369 | break; | |
370 | case TTCN_Typedescriptor_t::ROID: | |
371 | for(int i=0; i<val_ptr->n_components; i++) | |
372 | V_len+=(min_needed_bits(val_ptr->components_ptr[i])+6)/7; | |
373 | break; | |
374 | default: | |
375 | TTCN_EncDec_ErrorContext::error_internal | |
376 | ("Missing/wrong basetype info for type '%s'.", p_td.name); | |
377 | } // switch | |
378 | new_tlv=ASN_BER_TLV_t::construct(V_len, NULL); | |
379 | unsigned char *Vptr=new_tlv->V.str.Vstr; | |
380 | for(int i=0; i<val_ptr->n_components; i++) { | |
381 | unsigned long ul; | |
382 | if(i==0 && p_td.asnbasetype==TTCN_Typedescriptor_t::OBJID) { | |
383 | ul=val_ptr->components_ptr[0]*40+val_ptr->components_ptr[1]; | |
384 | i++; | |
385 | } | |
386 | else ul=val_ptr->components_ptr[i]; | |
387 | size_t noo=(min_needed_bits(ul)+6)/7; | |
388 | for(size_t j=noo; j>0; j--) { | |
389 | Vptr[j-1]=(ul & 0x7F) | 0x80; | |
390 | ul>>=7; | |
391 | } | |
392 | Vptr[noo-1]&=0x7F; | |
393 | Vptr+=noo; | |
394 | } // for i | |
395 | } | |
396 | new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding); | |
397 | return new_tlv; | |
398 | } | |
399 | ||
400 | ||
401 | boolean OBJID::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td, | |
402 | const ASN_BER_TLV_t& p_tlv, | |
403 | unsigned L_form) | |
404 | { | |
405 | clean_up(); | |
406 | BER_chk_descr(p_td); | |
407 | ASN_BER_TLV_t stripped_tlv; | |
408 | BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv); | |
409 | TTCN_EncDec_ErrorContext ec("While decoding OBJID type: "); | |
410 | stripped_tlv.chk_constructed_flag(FALSE); | |
411 | if (!stripped_tlv.isComplete) return FALSE; | |
412 | if (!stripped_tlv.V_tlvs_selected && stripped_tlv.V.str.Vlen==0) { | |
413 | ec.error(TTCN_EncDec::ET_INVAL_MSG, "Length of V-part is 0."); | |
414 | return FALSE; | |
415 | } | |
416 | switch(p_td.asnbasetype) { | |
417 | case TTCN_Typedescriptor_t::OBJID: | |
418 | case TTCN_Typedescriptor_t::ROID: | |
419 | break; | |
420 | default: | |
421 | TTCN_EncDec_ErrorContext::error_internal | |
422 | ("Missing/wrong basetype info for type '%s'.", p_td.name); | |
423 | } // switch | |
424 | unsigned char *Vptr=stripped_tlv.V.str.Vstr; | |
425 | boolean eoc=FALSE; // end-of-component | |
426 | int i=0; | |
427 | unsigned long long ull=0; | |
428 | STATIC_ASSERT(sizeof(ull) > sizeof(objid_element)); | |
429 | ||
430 | boolean err_repr=FALSE; | |
431 | while (Vptr < stripped_tlv.V.str.Vstr + stripped_tlv.V.str.Vlen) { | |
432 | ull |= *Vptr & 0x7F; | |
433 | if ((*Vptr & 0x80) && err_repr==FALSE) { // not-eoc | |
434 | if (ull & unsigned_llong_7msb) { | |
435 | ec.error(TTCN_EncDec::ET_REPR, | |
436 | "Value of the #%d component is too big.", i+1); | |
437 | err_repr=TRUE; | |
438 | } | |
439 | ull<<=7; | |
440 | eoc=FALSE; | |
441 | } | |
442 | else { // eoc | |
443 | if (i==0 && p_td.asnbasetype==TTCN_Typedescriptor_t::OBJID) { | |
444 | // first two component of objid | |
445 | switch(ull/40ul) { | |
446 | case 0: | |
447 | (*this)[0]=0; break; | |
448 | case 1: | |
449 | (*this)[0]=1; break; | |
450 | default: | |
451 | (*this)[0]=2; break; | |
452 | } | |
453 | (*this)[1]=(int)(ull-40*(*this)[0]); | |
454 | i=1; | |
455 | } | |
456 | else { // other components (>2) | |
457 | // objid_element is UINT/ULONG; the result of the cast is Uxxx_MAX. | |
458 | // It's computed at compile time. | |
459 | if(ull > ((objid_element)-1)) { | |
460 | if(err_repr==FALSE) | |
461 | ec.error(TTCN_EncDec::ET_REPR, | |
462 | "Value of the #%d component is too big.", i+1); | |
463 | (*this)[i]=(objid_element)-1; | |
464 | // remember the first overflow | |
465 | if (val_ptr->overflow_idx < 0) val_ptr->overflow_idx = i; | |
466 | } // if ul too big | |
467 | else | |
468 | (*this)[i]=(objid_element)ull; | |
469 | } | |
470 | err_repr=FALSE; | |
471 | ull=0; | |
472 | eoc=TRUE; | |
473 | i++; | |
474 | } // eoc | |
475 | Vptr++; | |
476 | } // while Vptr... | |
477 | if(eoc==FALSE) | |
478 | ec.error(TTCN_EncDec::ET_INVAL_MSG, | |
479 | "The last component (#%d) is unterminated.", i+1); | |
480 | return TRUE; | |
481 | } | |
482 | ||
483 | ||
484 | int OBJID::XER_encode(const XERdescriptor_t& p_td, | |
af710487 | 485 | TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const |
970ed795 EL |
486 | { |
487 | if(!is_bound()) { | |
488 | TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, | |
489 | "Encoding an unbound object identifier value."); | |
490 | } | |
491 | int encoded_length=(int)p_buf.get_len(); | |
492 | ||
493 | flavor |= SIMPLE_TYPE; | |
494 | flavor &= ~XER_RECOF; // object identifier doesn't care | |
495 | begin_xml(p_td, p_buf, flavor, indent, false); | |
496 | ||
497 | static char str_buf[64]; | |
498 | for (int i = 0; i < val_ptr->n_components; ++i ) { | |
499 | // output dot before the second and subsequent components | |
500 | if (i > 0) p_buf.put_c('.'); | |
501 | // output current component | |
502 | int str_len = snprintf(str_buf, sizeof(str_buf), OBJID_FMT, | |
503 | val_ptr->components_ptr[i]); | |
504 | if (str_len < 0 || str_len >= (int)sizeof(str_buf)) { | |
505 | TTCN_error("Internal error: system call snprintf() returned " | |
506 | "unexpected status code %d when converting value " OBJID_FMT, | |
507 | str_len, val_ptr->components_ptr[i]); | |
508 | } | |
509 | else p_buf.put_s(str_len, (const unsigned char*)str_buf); | |
510 | } | |
511 | ||
512 | end_xml(p_td, p_buf, flavor, indent, false); | |
513 | ||
514 | return (int)p_buf.get_len() - encoded_length; | |
515 | } | |
516 | ||
af710487 | 517 | void OBJID::from_string(char* p_str) |
518 | { | |
519 | // Count dots to find number of components. (1 dot = 2 components, etc.) | |
520 | unsigned comps = 1; | |
521 | const char *p; | |
522 | for (p = p_str; *p != 0; ++p) { | |
523 | if (*p == '.') ++comps; | |
524 | } | |
525 | // p now points at the end of the string. If it was empty, then there were | |
526 | // no components; compensate the fact that we started at 1. | |
527 | init_struct((p != p_str) ? comps : 0); | |
528 | ||
529 | char *beg, *end = 0; | |
530 | comps = 0; | |
531 | for (beg = p_str; beg < p; ++beg) { | |
532 | errno = 0; | |
533 | long ret = strtol(beg, &end, 10); | |
534 | if (errno) break; | |
535 | ||
536 | // TODO check value for too big ? | |
537 | (*this)[comps++] = ret; | |
538 | beg = end; // move to the dot; will move past it when incremented | |
539 | } | |
540 | } | |
541 | ||
970ed795 | 542 | int OBJID::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader, |
af710487 | 543 | unsigned int flavor, embed_values_dec_struct_t*) |
970ed795 EL |
544 | { |
545 | int exer = is_exer(flavor); | |
546 | int success = reader.Ok(), depth = -1; | |
547 | for (; success == 1; success = reader.Read()) { | |
548 | int type = reader.NodeType(); | |
549 | if (XML_READER_TYPE_ELEMENT == type) { | |
550 | verify_name(reader, p_td, exer); | |
551 | depth = reader.Depth(); | |
552 | break; | |
553 | } | |
554 | } | |
555 | if (success == 1) { | |
556 | char * val = (char *)reader.ReadString(); // We own this (writable) string | |
557 | if (0 == val) { | |
558 | TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_INVAL_MSG, "Bogus object identifier"); | |
559 | return 0; | |
560 | } | |
af710487 | 561 | |
562 | from_string(val); | |
970ed795 EL |
563 | |
564 | xmlFree(val); | |
565 | } | |
566 | for (success = reader.Read(); success == 1; success = reader.Read()) { | |
567 | int type = reader.NodeType(); | |
568 | if (XML_READER_TYPE_END_ELEMENT == type) { | |
569 | verify_end(reader, p_td, depth, exer); | |
570 | reader.Read(); | |
571 | break; | |
572 | } | |
573 | } | |
574 | return 1; // decode successful | |
575 | } | |
576 | ||
af710487 | 577 | int OBJID::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const |
578 | { | |
579 | if (!is_bound()) { | |
580 | TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND, | |
581 | "Encoding an unbound object identifier value."); | |
582 | return -1; | |
583 | } | |
584 | ||
585 | char* objid_str = mcopystrn("\"", 1); | |
586 | for (int i = 0; i < val_ptr->n_components; ++i) { | |
587 | objid_str = mputprintf(objid_str, "%s" OBJID_FMT, (i > 0 ? "." : ""), val_ptr->components_ptr[i]); | |
588 | } | |
589 | objid_str = mputstrn(objid_str, "\"", 1); | |
590 | int enc_len = p_tok.put_next_token(JSON_TOKEN_STRING, objid_str); | |
591 | Free(objid_str); | |
592 | return enc_len; | |
593 | } | |
594 | ||
595 | int OBJID::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent) | |
596 | { | |
597 | json_token_t token = JSON_TOKEN_NONE; | |
598 | char* value = 0; | |
599 | size_t value_len = 0; | |
600 | boolean error = false; | |
601 | int dec_len = 0; | |
602 | boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length(); | |
603 | if (use_default) { | |
604 | // No JSON data in the buffer -> use default value | |
605 | value = (char*)p_td.json->default_value; | |
606 | value_len = strlen(value); | |
607 | } else { | |
608 | dec_len = p_tok.get_next_token(&token, &value, &value_len); | |
609 | } | |
610 | if (JSON_TOKEN_ERROR == token) { | |
611 | JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, ""); | |
612 | return JSON_ERROR_FATAL; | |
613 | } | |
614 | else if (JSON_TOKEN_STRING == token || use_default) { | |
615 | if (use_default || (value_len > 2 && value[0] == '\"' && value[value_len - 1] == '\"')) { | |
616 | if (!use_default) { | |
617 | // The default value doesn't have quotes around it | |
618 | value_len -= 2; | |
619 | ++value; | |
620 | } | |
621 | // need a null-terminated string | |
622 | char* value2 = mcopystrn(value, value_len); | |
623 | from_string(value2); | |
624 | Free(value2); | |
625 | } | |
626 | } | |
627 | else { | |
628 | return JSON_ERROR_INVALID_TOKEN; | |
629 | } | |
630 | ||
631 | if (error) { | |
632 | JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, "string", "object identifier"); | |
633 | if (p_silent) { | |
634 | clean_up(); | |
635 | } | |
636 | return JSON_ERROR_FATAL; | |
637 | } | |
638 | return dec_len; | |
639 | } | |
970ed795 EL |
640 | |
641 | void OBJID_template::clean_up() | |
642 | { | |
643 | if (template_selection == VALUE_LIST || | |
644 | template_selection == COMPLEMENTED_LIST) delete [] value_list.list_value; | |
645 | template_selection = UNINITIALIZED_TEMPLATE; | |
646 | } | |
647 | ||
648 | void OBJID_template::copy_template(const OBJID_template& other_value) | |
649 | { | |
650 | switch (other_value.template_selection) { | |
651 | case SPECIFIC_VALUE: | |
652 | single_value = other_value.single_value; | |
653 | break; | |
654 | case OMIT_VALUE: | |
655 | case ANY_VALUE: | |
656 | case ANY_OR_OMIT: | |
657 | break; | |
658 | case VALUE_LIST: | |
659 | case COMPLEMENTED_LIST: | |
660 | value_list.n_values = other_value.value_list.n_values; | |
661 | value_list.list_value = new OBJID_template[value_list.n_values]; | |
662 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
663 | value_list.list_value[i].copy_template( | |
664 | other_value.value_list.list_value[i]); | |
665 | break; | |
666 | default: | |
667 | TTCN_error("Copying an uninitialized/unsupported objid template."); | |
668 | } | |
669 | set_selection(other_value); | |
670 | } | |
671 | ||
672 | OBJID_template::OBJID_template() | |
673 | { | |
674 | ||
675 | } | |
676 | ||
677 | OBJID_template::OBJID_template(template_sel other_value) | |
678 | : Base_Template(other_value) | |
679 | { | |
680 | check_single_selection(other_value); | |
681 | } | |
682 | ||
683 | OBJID_template::OBJID_template(const OBJID& other_value) | |
684 | : Base_Template(SPECIFIC_VALUE), single_value(other_value) | |
685 | { | |
686 | ||
687 | } | |
688 | ||
689 | OBJID_template::OBJID_template(const OPTIONAL<OBJID>& other_value) | |
690 | { | |
691 | switch (other_value.get_selection()) { | |
692 | case OPTIONAL_PRESENT: | |
693 | set_selection(SPECIFIC_VALUE); | |
694 | single_value = (const OBJID&)other_value; | |
695 | break; | |
696 | case OPTIONAL_OMIT: | |
697 | set_selection(OMIT_VALUE); | |
698 | break; | |
699 | default: | |
700 | TTCN_error("Creating an objid template from an unbound optional field."); | |
701 | } | |
702 | } | |
703 | ||
704 | OBJID_template::OBJID_template(const OBJID_template& other_value) | |
705 | : Base_Template() | |
706 | { | |
707 | copy_template(other_value); | |
708 | } | |
709 | ||
710 | OBJID_template::~OBJID_template() | |
711 | { | |
712 | clean_up(); | |
713 | } | |
714 | ||
715 | OBJID_template& OBJID_template::operator=(template_sel other_value) | |
716 | { | |
717 | check_single_selection(other_value); | |
718 | clean_up(); | |
719 | set_selection(other_value); | |
720 | return *this; | |
721 | } | |
722 | ||
723 | OBJID_template& OBJID_template::operator=(const OBJID& other_value) | |
724 | { | |
725 | if (!other_value.is_bound()) | |
726 | TTCN_error("Assignment of an unbound objid value to a template."); | |
727 | clean_up(); | |
728 | set_selection(SPECIFIC_VALUE); | |
729 | single_value = other_value; | |
730 | return *this; | |
731 | } | |
732 | ||
733 | OBJID_template& OBJID_template::operator=(const OPTIONAL<OBJID>& other_value) | |
734 | { | |
735 | clean_up(); | |
736 | switch (other_value.get_selection()) { | |
737 | case OPTIONAL_PRESENT: | |
738 | set_selection(SPECIFIC_VALUE); | |
739 | single_value = (const OBJID&)other_value; | |
740 | break; | |
741 | case OPTIONAL_OMIT: | |
742 | set_selection(OMIT_VALUE); | |
743 | break; | |
744 | default: | |
745 | TTCN_error("Assignment of an unbound optional field to an objid template."); | |
746 | } | |
747 | return *this; | |
748 | } | |
749 | ||
750 | OBJID_template& OBJID_template::operator=(const OBJID_template& other_value) | |
751 | { | |
752 | if (&other_value != this) { | |
753 | clean_up(); | |
754 | copy_template(other_value); | |
755 | } | |
756 | return *this; | |
757 | } | |
758 | ||
3abe9331 | 759 | boolean OBJID_template::match(const OBJID& other_value, boolean /* legacy */) const |
970ed795 EL |
760 | { |
761 | if (!other_value.is_bound()) return FALSE; | |
762 | switch (template_selection) { | |
763 | case SPECIFIC_VALUE: | |
764 | return single_value == other_value; | |
765 | case OMIT_VALUE: | |
766 | return FALSE; | |
767 | case ANY_VALUE: | |
768 | case ANY_OR_OMIT: | |
769 | return TRUE; | |
770 | case VALUE_LIST: | |
771 | case COMPLEMENTED_LIST: | |
772 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
773 | if (value_list.list_value[i].match(other_value)) | |
774 | return template_selection == VALUE_LIST; | |
775 | return template_selection == COMPLEMENTED_LIST; | |
776 | default: | |
777 | TTCN_error("Matching with an uninitialized/unsupported objid template."); | |
778 | } | |
779 | return FALSE; | |
780 | } | |
781 | ||
782 | const OBJID& OBJID_template::valueof() const | |
783 | { | |
784 | if (template_selection != SPECIFIC_VALUE || is_ifpresent) | |
785 | TTCN_error("Performing a valueof " | |
786 | "or send operation on a non-specific objid template."); | |
787 | return single_value; | |
788 | } | |
789 | ||
790 | int OBJID_template::size_of() const | |
791 | { | |
792 | switch (template_selection) | |
793 | { | |
794 | case SPECIFIC_VALUE: | |
795 | return single_value.size_of(); | |
796 | case OMIT_VALUE: | |
797 | TTCN_error("Performing sizeof() operation on an objid template " | |
798 | "containing omit value."); | |
799 | case ANY_VALUE: | |
800 | case ANY_OR_OMIT: | |
801 | TTCN_error("Performing sizeof() operation on a */? objid template."); | |
802 | case VALUE_LIST: | |
803 | { | |
804 | if (value_list.n_values<1) | |
805 | TTCN_error("Internal error: " | |
806 | "Performing sizeof() operation on an objid template " | |
807 | "containing an empty list."); | |
808 | int item_size = value_list.list_value[0].size_of(); | |
809 | for (unsigned int i = 1; i < value_list.n_values; i++) { | |
810 | if (value_list.list_value[i].size_of()!=item_size) | |
811 | TTCN_error("Performing sizeof() operation on an objid template " | |
812 | "containing a value list with different sizes."); | |
813 | } | |
814 | return item_size; | |
815 | } | |
816 | case COMPLEMENTED_LIST: | |
817 | TTCN_error("Performing sizeof() operation on an objid template " | |
818 | "containing complemented list."); | |
819 | default: | |
820 | TTCN_error("Performing sizeof() operation on an " | |
821 | "uninitialized/unsupported objid template."); | |
822 | } | |
823 | return 0; | |
824 | } | |
825 | ||
826 | void OBJID_template::set_type(template_sel template_type, | |
827 | unsigned int list_length) | |
828 | { | |
829 | if (template_type != VALUE_LIST && template_type != COMPLEMENTED_LIST) | |
830 | TTCN_error("Setting an invalid list type for an objid template."); | |
831 | clean_up(); | |
832 | set_selection(template_type); | |
833 | value_list.n_values = list_length; | |
834 | value_list.list_value = new OBJID_template[list_length]; | |
835 | } | |
836 | ||
837 | OBJID_template& OBJID_template::list_item(unsigned int list_index) | |
838 | { | |
839 | if (template_selection != VALUE_LIST && | |
840 | template_selection != COMPLEMENTED_LIST) | |
841 | TTCN_error("Accessing a list element of a non-list objid template."); | |
842 | if (list_index >= value_list.n_values) | |
843 | TTCN_error("Index overflow in an objid value list template."); | |
844 | return value_list.list_value[list_index]; | |
845 | } | |
846 | ||
847 | void OBJID_template::log() const | |
848 | { | |
849 | switch (template_selection) { | |
850 | case SPECIFIC_VALUE: | |
851 | single_value.log(); | |
852 | break; | |
853 | case COMPLEMENTED_LIST: | |
854 | TTCN_Logger::log_event_str("complement "); | |
855 | // no break | |
856 | case VALUE_LIST: | |
857 | TTCN_Logger::log_char('('); | |
858 | for(unsigned int i = 0; i < value_list.n_values; i++) { | |
859 | if (i > 0) TTCN_Logger::log_event_str(", "); | |
860 | value_list.list_value[i].log(); | |
861 | } | |
862 | TTCN_Logger::log_char(')'); | |
863 | break; | |
864 | default: | |
865 | log_generic(); | |
866 | break; | |
867 | } | |
868 | log_ifpresent(); | |
869 | } | |
870 | ||
3abe9331 | 871 | void OBJID_template::log_match(const OBJID& match_value, |
872 | boolean /* legacy */) const | |
970ed795 EL |
873 | { |
874 | if (TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity() | |
875 | && TTCN_Logger::get_logmatch_buffer_len() != 0) { | |
876 | TTCN_Logger::print_logmatch_buffer(); | |
877 | TTCN_Logger::log_event_str(" := "); | |
878 | } | |
879 | match_value.log(); | |
880 | TTCN_Logger::log_event_str(" with "); | |
881 | log(); | |
882 | if (match(match_value)) TTCN_Logger::log_event_str(" matched"); | |
883 | else TTCN_Logger::log_event_str(" unmatched"); | |
884 | } | |
885 | ||
886 | void OBJID_template::set_param(Module_Param& param) { | |
887 | param.basic_check(Module_Param::BC_TEMPLATE, "objid template"); | |
3abe9331 | 888 | Module_Param_Ptr mp = ¶m; |
889 | if (param.get_type() == Module_Param::MP_Reference) { | |
890 | mp = param.get_referenced_param(); | |
891 | } | |
892 | switch (mp->get_type()) { | |
970ed795 EL |
893 | case Module_Param::MP_Omit: |
894 | *this = OMIT_VALUE; | |
895 | break; | |
896 | case Module_Param::MP_Any: | |
897 | *this = ANY_VALUE; | |
898 | break; | |
899 | case Module_Param::MP_AnyOrNone: | |
900 | *this = ANY_OR_OMIT; | |
901 | break; | |
902 | case Module_Param::MP_List_Template: | |
3abe9331 | 903 | case Module_Param::MP_ComplementList_Template: { |
904 | OBJID_template temp; | |
905 | temp.set_type(mp->get_type() == Module_Param::MP_List_Template ? | |
906 | VALUE_LIST : COMPLEMENTED_LIST, mp->get_size()); | |
907 | for (size_t i=0; i<mp->get_size(); i++) { | |
908 | temp.list_item(i).set_param(*mp->get_elem(i)); | |
970ed795 | 909 | } |
3abe9331 | 910 | *this = temp; |
911 | break; } | |
970ed795 EL |
912 | case Module_Param::MP_Objid: |
913 | if (sizeof(OBJID::objid_element)!=sizeof(int)) TTCN_error("Internal error: OBJID_template::set_param()"); | |
3abe9331 | 914 | *this = OBJID(mp->get_string_size(), (OBJID::objid_element*)mp->get_string_data()); |
970ed795 EL |
915 | break; |
916 | //case Module_Param::MP_Objid_Template: | |
917 | // TODO | |
918 | //break; | |
919 | default: | |
920 | param.type_error("objid template"); | |
921 | } | |
3abe9331 | 922 | is_ifpresent = param.get_ifpresent() || mp->get_ifpresent(); |
923 | } | |
924 | ||
925 | Module_Param* OBJID_template::get_param(Module_Param_Name& param_name) const | |
926 | { | |
927 | Module_Param* mp = NULL; | |
928 | switch (template_selection) { | |
929 | case UNINITIALIZED_TEMPLATE: | |
930 | mp = new Module_Param_Unbound(); | |
931 | break; | |
932 | case OMIT_VALUE: | |
933 | mp = new Module_Param_Omit(); | |
934 | break; | |
935 | case ANY_VALUE: | |
936 | mp = new Module_Param_Any(); | |
937 | break; | |
938 | case ANY_OR_OMIT: | |
939 | mp = new Module_Param_AnyOrNone(); | |
940 | break; | |
941 | case SPECIFIC_VALUE: | |
942 | mp = single_value.get_param(param_name); | |
943 | break; | |
944 | case VALUE_LIST: | |
945 | case COMPLEMENTED_LIST: { | |
946 | if (template_selection == VALUE_LIST) { | |
947 | mp = new Module_Param_List_Template(); | |
948 | } | |
949 | else { | |
950 | mp = new Module_Param_ComplementList_Template(); | |
951 | } | |
952 | for (size_t i = 0; i < value_list.n_values; ++i) { | |
953 | mp->add_elem(value_list.list_value[i].get_param(param_name)); | |
954 | } | |
955 | break; } | |
956 | default: | |
957 | break; | |
958 | } | |
959 | if (is_ifpresent) { | |
960 | mp->set_ifpresent(); | |
961 | } | |
962 | return mp; | |
970ed795 EL |
963 | } |
964 | ||
965 | void OBJID_template::encode_text(Text_Buf& text_buf) const | |
966 | { | |
967 | encode_text_base(text_buf); | |
968 | switch (template_selection) { | |
969 | case OMIT_VALUE: | |
970 | case ANY_VALUE: | |
971 | case ANY_OR_OMIT: | |
972 | break; | |
973 | case SPECIFIC_VALUE: | |
974 | single_value.encode_text(text_buf); | |
975 | break; | |
976 | case VALUE_LIST: | |
977 | case COMPLEMENTED_LIST: | |
978 | text_buf.push_int(value_list.n_values); | |
979 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
980 | value_list.list_value[i].encode_text(text_buf); | |
981 | break; | |
982 | default: | |
983 | TTCN_error("Text encoder: Encoding an undefined/unsupported objid " | |
984 | "template."); | |
985 | } | |
986 | } | |
987 | ||
988 | void OBJID_template::decode_text(Text_Buf& text_buf) | |
989 | { | |
990 | clean_up(); | |
991 | decode_text_base(text_buf); | |
992 | switch (template_selection) { | |
993 | case OMIT_VALUE: | |
994 | case ANY_VALUE: | |
995 | case ANY_OR_OMIT: | |
996 | break; | |
997 | case SPECIFIC_VALUE: | |
998 | single_value.decode_text(text_buf); | |
999 | break; | |
1000 | case VALUE_LIST: | |
1001 | case COMPLEMENTED_LIST: | |
1002 | value_list.n_values = text_buf.pull_int().get_val(); | |
1003 | value_list.list_value = new OBJID_template[value_list.n_values]; | |
1004 | for (unsigned int i = 0; i < value_list.n_values; i++) | |
1005 | value_list.list_value[i].decode_text(text_buf); | |
1006 | break; | |
1007 | default: | |
1008 | TTCN_error("Text decoder: An unknown/unsupported selection was " | |
1009 | "received for an objid template."); | |
1010 | } | |
1011 | } | |
1012 | ||
3abe9331 | 1013 | boolean OBJID_template::is_present(boolean legacy /* = FALSE */) const |
970ed795 EL |
1014 | { |
1015 | if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE; | |
3abe9331 | 1016 | return !match_omit(legacy); |
970ed795 EL |
1017 | } |
1018 | ||
3abe9331 | 1019 | boolean OBJID_template::match_omit(boolean legacy /* = FALSE */) const |
970ed795 EL |
1020 | { |
1021 | if (is_ifpresent) return TRUE; | |
1022 | switch (template_selection) { | |
1023 | case OMIT_VALUE: | |
1024 | case ANY_OR_OMIT: | |
1025 | return TRUE; | |
1026 | case VALUE_LIST: | |
1027 | case COMPLEMENTED_LIST: | |
3abe9331 | 1028 | if (legacy) { |
1029 | // legacy behavior: 'omit' can appear in the value/complement list | |
1030 | for (unsigned int i=0; i<value_list.n_values; i++) | |
1031 | if (value_list.list_value[i].match_omit()) | |
1032 | return template_selection==VALUE_LIST; | |
1033 | return template_selection==COMPLEMENTED_LIST; | |
1034 | } | |
1035 | // else fall through | |
970ed795 EL |
1036 | default: |
1037 | return FALSE; | |
1038 | } | |
1039 | return FALSE; | |
1040 | } | |
1041 | ||
1042 | #ifndef TITAN_RUNTIME_2 | |
3abe9331 | 1043 | void OBJID_template::check_restriction(template_res t_res, const char* t_name, |
1044 | boolean legacy /* = FALSE */) const | |
970ed795 EL |
1045 | { |
1046 | if (template_selection==UNINITIALIZED_TEMPLATE) return; | |
1047 | switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) { | |
1048 | case TR_VALUE: | |
1049 | if (!is_ifpresent && template_selection==SPECIFIC_VALUE) return; | |
1050 | break; | |
1051 | case TR_OMIT: | |
1052 | if (!is_ifpresent && (template_selection==OMIT_VALUE || | |
1053 | template_selection==SPECIFIC_VALUE)) return; | |
1054 | break; | |
1055 | case TR_PRESENT: | |
3abe9331 | 1056 | if (!match_omit(legacy)) return; |
970ed795 EL |
1057 | break; |
1058 | default: | |
1059 | return; | |
1060 | } | |
1061 | TTCN_error("Restriction `%s' on template of type %s violated.", | |
1062 | get_res_name(t_res), t_name ? t_name : "objid"); | |
1063 | } | |
1064 | #endif |