Merge pull request #83 from eadrkir/master
[deliverable/titan.core.git] / core / Textbuf.cc
CommitLineData
d44e3c4f 1/******************************************************************************
2 * Copyright (c) 2000-2016 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 * Contributors:
9 * Balasko, Jeno
10 * Forstner, Matyas
11 * Kovacs, Ferenc
12 * Raduly, Csaba
13 * Szabo, Janos Zoltan – initial implementation
14 * Szalai, Gabor
15 *
16 ******************************************************************************/
970ed795
EL
17#include <stdio.h>
18#include <stdlib.h> // for atof
19#include <string.h>
20#include <errno.h>
21
22#include "Textbuf.hh"
23#include "../common/memory.h"
24#include "Error.hh"
25
26#include <openssl/bn.h>
27
28// Note: Do not use dbgnew.hh; it doesn't play well with Qt in mctr_gui
29
30#define BUF_SIZE 1000
31#define BUF_HEAD 24
32
33
34Text_Buf::Text_Buf()
35: buf_size()
36, buf_begin(BUF_HEAD)
37, buf_pos(BUF_HEAD)
38, buf_len(0)
39{
40 Allocate(BUF_SIZE);
41}
42
43Text_Buf::~Text_Buf()
44{
45 Free(data_ptr);
46}
47
48void Text_Buf::Allocate(int size)
49{
50 int new_buf_size = BUF_SIZE + BUF_HEAD;
51 while(new_buf_size < size + buf_begin) new_buf_size *= 2;
52 data_ptr = Malloc(new_buf_size);
53 buf_size = new_buf_size; // always a power of 2, from 1024 up
54}
55
56void Text_Buf::Reallocate(int size)
57{
58 int new_buf_size = BUF_SIZE + BUF_HEAD;
59 while (new_buf_size < size + buf_begin) new_buf_size *= 2;
60 if (new_buf_size != buf_size) {
61 data_ptr = Realloc(data_ptr, new_buf_size);
62 buf_size = new_buf_size; // always a power of 2, from 1024 up
63 }
64}
65
66void Text_Buf::reset()
67{
68 buf_begin = BUF_HEAD;
69 Reallocate(BUF_SIZE);
70 buf_pos = BUF_HEAD;
71 buf_len = 0;
72}
73
74/** Encode a native integer in the buffer
75 *
76 * @param value native integer
77 */
78void Text_Buf::push_int(const RInt& value)
79{
80 int_val_t tmp(value);
81 push_int(tmp);
82}
83
84/** Encode an integer (may be bigint) into the text buffer
85 *
86 * @param value may be big integer
87 */
88void Text_Buf::push_int(const int_val_t& value)
89{
90 if (value.is_native()) {
91 boolean is_negative = value < 0;
92 unsigned int unsigned_value = is_negative ? -value.get_val() :
93 value.get_val();
94 unsigned int bytes_needed = 1;
95 for (unsigned int tmp = unsigned_value >> 6; tmp != 0; tmp >>= 7)
96 bytes_needed++;
97 Reallocate(buf_len + bytes_needed);
98 unsigned char *buf = (unsigned char *)data_ptr + buf_begin + buf_len;
99 for (unsigned int i = bytes_needed - 1; ; i--) {
100 // The top bit is always 1 for a "middle" byte, 0 for the last byte.
101 // That leaves 7 bits, except for the first byte where the 2nd highest
102 // bit is the sign bit, so only 6 payload bits are available.
103 if (i > 0) {
104 buf[i] = unsigned_value & 0x7f;
105 unsigned_value >>= 7;
106 } else buf[i] = unsigned_value & 0x3f;
107 // Set the top bit for all but the last byte
108 if (i < bytes_needed - 1) buf[i] |= 0x80;
109 if (i == 0) break;
110 }
111 if (is_negative) buf[0] |= 0x40; // Put in the sign bit
112 buf_len += bytes_needed;
113 } else {
114 BIGNUM *D = BN_new();
115 BN_copy(D, value.get_val_openssl());
116 unsigned num_bits = BN_num_bits(D);
117 // Calculation
118 // first 6 bit +the sign bit are stored in the first octet
119 // the remaining bits stored in 7 bit group + continuation bit
120 // So how many octest needed to store the (num_bits + 1) many bits
121 // in 7 bit ber octet form?
122 // ((num_bits+1)+6)/7 =>
123 // (num_bits+7)/7 =>
124 // (num_bits / 7)+1
125
126 unsigned num_bytes = (num_bits / 7)+1;
127 Reallocate(buf_len + num_bytes);
128 unsigned char *buf = (unsigned char *)data_ptr + buf_begin + buf_len;
43eeb72d 129 // Alloc once, free once
130 unsigned char* buf2 = (unsigned char*)Malloc(BN_num_bytes(D) * sizeof(unsigned char));
970ed795 131 for (unsigned i = num_bytes - 1; ; i--) {
43eeb72d 132 BN_bn2bin(D, buf2); // TODO: query once and then get the 7 loads
133 unsigned temp_num_bytes = BN_num_bytes(D);
970ed795
EL
134 // Seven bits at a time, except the first byte has only 6 payload bits
135 if (i > 0) {
43eeb72d 136 buf[i] = buf2[temp_num_bytes-1] & 0x7f;
970ed795
EL
137 if (!BN_rshift(D, D, 7)) return;
138 } else {
43eeb72d 139 buf[i] = (BN_is_zero(D) ? 0 : buf2[temp_num_bytes-1]) & 0x3f;
970ed795
EL
140 }
141 if (i < num_bytes - 1) buf[i] |= 0x80;
142 if (i == 0) break;
143 }
144 if (BN_is_negative(D)) buf[0] |= 0x40; // Put in the sign bit
145 BN_free(D);
43eeb72d 146 Free(buf2);
970ed795
EL
147 buf_len += num_bytes;
148 }
149}
150
151/** Extract an integer from the buffer.
152 *
153 * @return the extracted value
154 * @pre An integer must be available, else dynamic testcase error
155 */
156const int_val_t Text_Buf::pull_int()
157{
158 int_val_t value;
159 if (!safe_pull_int(value))
160 TTCN_error("Text decoder: Decoding of integer failed.");
161 return value;
162}
163
164/** Extract an integer if it's safe to do so.
165 *
166 * @param[out] value set to the extracted value if successful
167 * @return TRUE if an integer could be extracted, FALSE otherwise
168 */
169boolean Text_Buf::safe_pull_int(int_val_t& value)
170{
171 int buf_end = buf_begin + buf_len;
172 if (buf_pos >= buf_end) return FALSE;
173 int pos = buf_pos;
174 // Count continuation flags.
175 while (pos < buf_end && ((unsigned char *)data_ptr)[pos] & 0x80) pos++;
176 if (pos >= buf_end) return FALSE;
177 unsigned int bytes_needed = pos - buf_pos + 1;
178 const unsigned char *buf = (unsigned char *)data_ptr + buf_pos;
179 if (bytes_needed > sizeof(RInt)) {
180 BIGNUM *D = BN_new();
181 int neg = 0;
182 BN_clear(D);
183 for (unsigned i = 0; i < bytes_needed; i++) {
184 // TTCN-TCC-INTERNAL-0026 (HJ87126)
185 if (i > 0) BN_add_word(D, buf[i] & 0x7f);
186 else BN_add_word(D, buf[i] & 0x3f);
187 if (i < bytes_needed - 1)
188 BN_lshift(D, D, 7);
189 }
190 if (buf[0] & 0x40) { neg = 1; BN_set_negative(D, 1); }
191 if (BN_num_bits(D) > (RInt)sizeof(RInt) * 8 - 1) {
192 value = int_val_t(D);
193 } else {
43eeb72d 194 BN_ULONG num = BN_get_word(D); // BN_ULONG is unsigned long
195 value = int_val_t(neg ? -num : num);
970ed795
EL
196 BN_free(D);
197 }
198 } else {
199 unsigned long loc_value = 0;
200 for (unsigned i = 0; i < bytes_needed; i++) {
201 if (i > 0) loc_value |= buf[i] & 0x7f;
202 else loc_value |= buf[i] & 0x3f;
203 if (i < bytes_needed - 1) loc_value <<= 7;
204 }
205 if (buf[0] & 0x40) value = -loc_value;
206 else value = loc_value;
207 }
208 buf_pos = pos + 1;
209 return TRUE;
210}
211
212/** Encode a double precision floating point number in the buffer.
213 *
214 * @param value
215 */
216void Text_Buf::push_double(double value)
217{
3abe9331 218 Reallocate(buf_len + 8);
219 union{
220 double d;
221 unsigned char c[8];
222 } m;
223 m.d=value;
224 unsigned char *st=(unsigned char *)data_ptr + buf_begin + buf_len;
225#if defined __sparc__ || defined __sparc
226 st[0]=m.c[0];
227 st[1]=m.c[1];
228 st[2]=m.c[2];
229 st[3]=m.c[3];
230 st[4]=m.c[4];
231 st[5]=m.c[5];
232 st[6]=m.c[6];
233 st[7]=m.c[7];
234#else
235 st[0]=m.c[7];
236 st[1]=m.c[6];
237 st[2]=m.c[5];
238 st[3]=m.c[4];
239 st[4]=m.c[3];
240 st[5]=m.c[2];
241 st[6]=m.c[1];
242 st[7]=m.c[0];
243#endif
244 buf_len += 8;
970ed795
EL
245}
246
247/** Extract a double precision floating point number
248 *
249 * @return the extracted value
250 * @pre A suitably formatted float value must be in the buffer, else
251 * dynamic testcase error
252 */
253double Text_Buf::pull_double()
254{
3abe9331 255 if (buf_pos + 8 > buf_begin + buf_len) TTCN_error("Text decoder: Decoding of float failed. "
970ed795 256 "(End of buffer reached)");
3abe9331 257 const unsigned char *st = (unsigned char *)data_ptr+buf_pos;
258
259 union{
260 double d;
261 unsigned char c[8];
262 } m;
263#if defined __sparc__ || defined __sparc
264 m.c[0]=st[0];
265 m.c[1]=st[1];
266 m.c[2]=st[2];
267 m.c[3]=st[3];
268 m.c[4]=st[4];
269 m.c[5]=st[5];
270 m.c[6]=st[6];
271 m.c[7]=st[7];
272#else
273 m.c[0]=st[7];
274 m.c[1]=st[6];
275 m.c[2]=st[5];
276 m.c[3]=st[4];
277 m.c[4]=st[3];
278 m.c[5]=st[2];
279 m.c[6]=st[1];
280 m.c[7]=st[0];
281#endif
282buf_pos += 8;
283return m.d;
970ed795
EL
284}
285
286/** Write a fixed number of bytes in the buffer.
287 *
288 * @param len number of bytes to write
289 * @param data pointer to the data
290 */
291void Text_Buf::push_raw(int len, const void *data)
292{
293 if (len < 0) TTCN_error("Text encoder: Encoding raw data with negative "
294 "length (%d).", len);
295 Reallocate(buf_len + len);
296 memcpy((char*)data_ptr + buf_begin + buf_len, data, len);
297 buf_len += len;
298}
299
016a1a93
BB
300void Text_Buf::push_raw_front(int len, const void* data)
301{
302 if (len < 0) TTCN_error("Text encoder: Encoding raw data with negative "
303 "length (%d).", len);
304 Reallocate(buf_len + len);
305 for (int i = buf_len - 1; i >= 0; --i) {
306 ((char*)data_ptr)[buf_begin + len + i] = ((char*)data_ptr)[buf_begin + i];
307 }
308 memcpy((char*)data_ptr + buf_begin, data, len);
309 buf_len += len;
310}
311
970ed795
EL
312/** Extract a fixed number of bytes from the buffer.
313 *
314 * @param len number of bytes to read
315 * @param data pointer to the data
316 * @pre at least \a len bytes are available, else dynamic testcase error
317 */
318void Text_Buf::pull_raw(int len, void *data)
319{
320 if (len < 0) TTCN_error("Text decoder: Decoding raw data with negative "
321 "length (%d).", len);
322 if (buf_pos + len > buf_begin + buf_len)
323 TTCN_error("Text decoder: End of buffer reached.");
324 memcpy(data, (char*)data_ptr + buf_pos, len);
325 buf_pos += len;
326}
327
328/** Write a 0-terminated string
329 *
330 * Writes the length followed by the raw bytes (no end marker)
331 *
332 * @param string_ptr pointer to the string
333 */
334void Text_Buf::push_string(const char *string_ptr)
335{
336 if (string_ptr != NULL) {
337 int len = strlen(string_ptr);
338 push_int(len);
339 push_raw(len, string_ptr);
340 } else push_int((RInt)0);
341}
342
343/** Extract a string
344 *
345 * @return the string allocated with new[], must be freed by the caller
346 */
347char *Text_Buf::pull_string()
348{
349 int len = pull_int().get_val();
350 if (len < 0)
351 TTCN_error("Text decoder: Negative string length (%d).", len);
352 char *string_ptr = new char[len + 1];
353 pull_raw(len, string_ptr);
354 string_ptr[len] = '\0';
355 return string_ptr;
356}
357
358/// Push two strings
359void Text_Buf::push_qualified_name(const qualified_name& name)
360{
361 push_string(name.module_name);
362 push_string(name.definition_name);
363}
364
365/// Extract two strings
366void Text_Buf::pull_qualified_name(qualified_name& name)
367{
368 name.module_name = pull_string();
369 if (name.module_name[0] == '\0') {
370 delete [] name.module_name;
371 name.module_name = NULL;
372 }
373 name.definition_name = pull_string();
374 if (name.definition_name[0] == '\0') {
375 delete [] name.definition_name;
376 name.definition_name = NULL;
377 }
378}
379
380/** Calculate the length of the buffer and write it at the beginning.
381 *
382 */
383void Text_Buf::calculate_length()
384{
385 unsigned int value = buf_len;
386 unsigned int bytes_needed = 1;
387 for (unsigned int tmp = value >> 6; tmp != 0; tmp >>= 7) bytes_needed++;
388 if ((unsigned int)buf_begin < bytes_needed)
389 TTCN_error("Text encoder: There is not enough space to calculate message "
390 "length.");
391 unsigned char *buf = (unsigned char*)data_ptr + buf_begin - bytes_needed;
392 for (unsigned int i = bytes_needed - 1; ; i--) {
393 if (i > 0) {
394 buf[i] = value & 0x7F;
395 value >>= 7;
396 } else buf[i] = value & 0x3F;
397 if (i < bytes_needed - 1) buf[i] |= 0x80;
398 if (i == 0) break;
399 }
400 buf_begin -= bytes_needed;
401 buf_len += bytes_needed;
402}
403
404
405void Text_Buf::get_end(char*& end_ptr, int& end_len)
406{
407 int buf_end = buf_begin + buf_len;
408 if (buf_size - buf_end < BUF_SIZE) Reallocate(buf_len + BUF_SIZE);
409 end_ptr = (char*)data_ptr + buf_end;
410 end_len = buf_size - buf_end;
411}
412
413void Text_Buf::increase_length(int add_len)
414{
415 if (add_len < 0) TTCN_error("Text decoder: Addition is negative (%d) when "
416 "increasing length.", add_len);
417 if (buf_begin + buf_len + add_len > buf_size)
418 TTCN_error("Text decoder: Addition is too big when increasing length.");
419 buf_len += add_len;
420}
421
422/** Check if a known message is in the buffer
423 *
424 * @return TRUE if an int followed by the number of bytes specified
425 * by that int is in the buffer; FALSE otherwise.
426 * @post buf_pos == buf_begin
427 */
428boolean Text_Buf::is_message()
429{
430 rewind();
431 int_val_t msg_len;
432 boolean ret_val = FALSE;
433 if (safe_pull_int(msg_len)) {
434 if (msg_len < 0) {
435 char *tmp_str = msg_len.as_string();
436 TTCN_error("Text decoder: Negative message length (%s).", tmp_str);
437 Free(tmp_str); // ???
438 }
439 ret_val = buf_pos + msg_len.get_val() <= buf_begin + buf_len;
440 }
441 rewind();
442 return ret_val;
443}
444
445/** Overwrite the extracted message with the rest of the buffer
446 * @post buf_pos == buf_begin
447 */
448void Text_Buf::cut_message()
449{
450 if (is_message()) {
451 int msg_len = pull_int().get_val();
452 int msg_end = buf_pos + msg_len;
453 buf_len -= msg_end - buf_begin;
454 memmove((char*)data_ptr + buf_begin, (char*)data_ptr + msg_end,
455 buf_len);
456 Reallocate(buf_len);
457 rewind();
458 }
459}
This page took 0.041153 seconds and 5 git commands to generate.