Merge pull request #48 from BotondBaranyi/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;
129 for (unsigned i = num_bytes - 1; ; i--) {
130 // Seven bits at a time, except the first byte has only 6 payload bits
131 if (i > 0) {
132 buf[i] = D->d[0] & 0x7f;
133 if (!BN_rshift(D, D, 7)) return;
134 } else {
135 buf[i] = (D->top ? D->d[0] : 0) & 0x3f;
136 }
137 if (i < num_bytes - 1) buf[i] |= 0x80;
138 if (i == 0) break;
139 }
140 if (BN_is_negative(D)) buf[0] |= 0x40; // Put in the sign bit
141 BN_free(D);
142 buf_len += num_bytes;
143 }
144}
145
146/** Extract an integer from the buffer.
147 *
148 * @return the extracted value
149 * @pre An integer must be available, else dynamic testcase error
150 */
151const int_val_t Text_Buf::pull_int()
152{
153 int_val_t value;
154 if (!safe_pull_int(value))
155 TTCN_error("Text decoder: Decoding of integer failed.");
156 return value;
157}
158
159/** Extract an integer if it's safe to do so.
160 *
161 * @param[out] value set to the extracted value if successful
162 * @return TRUE if an integer could be extracted, FALSE otherwise
163 */
164boolean Text_Buf::safe_pull_int(int_val_t& value)
165{
166 int buf_end = buf_begin + buf_len;
167 if (buf_pos >= buf_end) return FALSE;
168 int pos = buf_pos;
169 // Count continuation flags.
170 while (pos < buf_end && ((unsigned char *)data_ptr)[pos] & 0x80) pos++;
171 if (pos >= buf_end) return FALSE;
172 unsigned int bytes_needed = pos - buf_pos + 1;
173 const unsigned char *buf = (unsigned char *)data_ptr + buf_pos;
174 if (bytes_needed > sizeof(RInt)) {
175 BIGNUM *D = BN_new();
176 int neg = 0;
177 BN_clear(D);
178 for (unsigned i = 0; i < bytes_needed; i++) {
179 // TTCN-TCC-INTERNAL-0026 (HJ87126)
180 if (i > 0) BN_add_word(D, buf[i] & 0x7f);
181 else BN_add_word(D, buf[i] & 0x3f);
182 if (i < bytes_needed - 1)
183 BN_lshift(D, D, 7);
184 }
185 if (buf[0] & 0x40) { neg = 1; BN_set_negative(D, 1); }
186 if (BN_num_bits(D) > (RInt)sizeof(RInt) * 8 - 1) {
187 value = int_val_t(D);
188 } else {
189 value = int_val_t(neg ? -D->d[0] : D->d[0]);
190 BN_free(D);
191 }
192 } else {
193 unsigned long loc_value = 0;
194 for (unsigned i = 0; i < bytes_needed; i++) {
195 if (i > 0) loc_value |= buf[i] & 0x7f;
196 else loc_value |= buf[i] & 0x3f;
197 if (i < bytes_needed - 1) loc_value <<= 7;
198 }
199 if (buf[0] & 0x40) value = -loc_value;
200 else value = loc_value;
201 }
202 buf_pos = pos + 1;
203 return TRUE;
204}
205
206/** Encode a double precision floating point number in the buffer.
207 *
208 * @param value
209 */
210void Text_Buf::push_double(double value)
211{
3abe9331 212 Reallocate(buf_len + 8);
213 union{
214 double d;
215 unsigned char c[8];
216 } m;
217 m.d=value;
218 unsigned char *st=(unsigned char *)data_ptr + buf_begin + buf_len;
219#if defined __sparc__ || defined __sparc
220 st[0]=m.c[0];
221 st[1]=m.c[1];
222 st[2]=m.c[2];
223 st[3]=m.c[3];
224 st[4]=m.c[4];
225 st[5]=m.c[5];
226 st[6]=m.c[6];
227 st[7]=m.c[7];
228#else
229 st[0]=m.c[7];
230 st[1]=m.c[6];
231 st[2]=m.c[5];
232 st[3]=m.c[4];
233 st[4]=m.c[3];
234 st[5]=m.c[2];
235 st[6]=m.c[1];
236 st[7]=m.c[0];
237#endif
238 buf_len += 8;
970ed795
EL
239}
240
241/** Extract a double precision floating point number
242 *
243 * @return the extracted value
244 * @pre A suitably formatted float value must be in the buffer, else
245 * dynamic testcase error
246 */
247double Text_Buf::pull_double()
248{
3abe9331 249 if (buf_pos + 8 > buf_begin + buf_len) TTCN_error("Text decoder: Decoding of float failed. "
970ed795 250 "(End of buffer reached)");
3abe9331 251 const unsigned char *st = (unsigned char *)data_ptr+buf_pos;
252
253 union{
254 double d;
255 unsigned char c[8];
256 } m;
257#if defined __sparc__ || defined __sparc
258 m.c[0]=st[0];
259 m.c[1]=st[1];
260 m.c[2]=st[2];
261 m.c[3]=st[3];
262 m.c[4]=st[4];
263 m.c[5]=st[5];
264 m.c[6]=st[6];
265 m.c[7]=st[7];
266#else
267 m.c[0]=st[7];
268 m.c[1]=st[6];
269 m.c[2]=st[5];
270 m.c[3]=st[4];
271 m.c[4]=st[3];
272 m.c[5]=st[2];
273 m.c[6]=st[1];
274 m.c[7]=st[0];
275#endif
276buf_pos += 8;
277return m.d;
970ed795
EL
278}
279
280/** Write a fixed number of bytes in the buffer.
281 *
282 * @param len number of bytes to write
283 * @param data pointer to the data
284 */
285void Text_Buf::push_raw(int len, const void *data)
286{
287 if (len < 0) TTCN_error("Text encoder: Encoding raw data with negative "
288 "length (%d).", len);
289 Reallocate(buf_len + len);
290 memcpy((char*)data_ptr + buf_begin + buf_len, data, len);
291 buf_len += len;
292}
293
294/** Extract a fixed number of bytes from the buffer.
295 *
296 * @param len number of bytes to read
297 * @param data pointer to the data
298 * @pre at least \a len bytes are available, else dynamic testcase error
299 */
300void Text_Buf::pull_raw(int len, void *data)
301{
302 if (len < 0) TTCN_error("Text decoder: Decoding raw data with negative "
303 "length (%d).", len);
304 if (buf_pos + len > buf_begin + buf_len)
305 TTCN_error("Text decoder: End of buffer reached.");
306 memcpy(data, (char*)data_ptr + buf_pos, len);
307 buf_pos += len;
308}
309
310/** Write a 0-terminated string
311 *
312 * Writes the length followed by the raw bytes (no end marker)
313 *
314 * @param string_ptr pointer to the string
315 */
316void Text_Buf::push_string(const char *string_ptr)
317{
318 if (string_ptr != NULL) {
319 int len = strlen(string_ptr);
320 push_int(len);
321 push_raw(len, string_ptr);
322 } else push_int((RInt)0);
323}
324
325/** Extract a string
326 *
327 * @return the string allocated with new[], must be freed by the caller
328 */
329char *Text_Buf::pull_string()
330{
331 int len = pull_int().get_val();
332 if (len < 0)
333 TTCN_error("Text decoder: Negative string length (%d).", len);
334 char *string_ptr = new char[len + 1];
335 pull_raw(len, string_ptr);
336 string_ptr[len] = '\0';
337 return string_ptr;
338}
339
340/// Push two strings
341void Text_Buf::push_qualified_name(const qualified_name& name)
342{
343 push_string(name.module_name);
344 push_string(name.definition_name);
345}
346
347/// Extract two strings
348void Text_Buf::pull_qualified_name(qualified_name& name)
349{
350 name.module_name = pull_string();
351 if (name.module_name[0] == '\0') {
352 delete [] name.module_name;
353 name.module_name = NULL;
354 }
355 name.definition_name = pull_string();
356 if (name.definition_name[0] == '\0') {
357 delete [] name.definition_name;
358 name.definition_name = NULL;
359 }
360}
361
362/** Calculate the length of the buffer and write it at the beginning.
363 *
364 */
365void Text_Buf::calculate_length()
366{
367 unsigned int value = buf_len;
368 unsigned int bytes_needed = 1;
369 for (unsigned int tmp = value >> 6; tmp != 0; tmp >>= 7) bytes_needed++;
370 if ((unsigned int)buf_begin < bytes_needed)
371 TTCN_error("Text encoder: There is not enough space to calculate message "
372 "length.");
373 unsigned char *buf = (unsigned char*)data_ptr + buf_begin - bytes_needed;
374 for (unsigned int i = bytes_needed - 1; ; i--) {
375 if (i > 0) {
376 buf[i] = value & 0x7F;
377 value >>= 7;
378 } else buf[i] = value & 0x3F;
379 if (i < bytes_needed - 1) buf[i] |= 0x80;
380 if (i == 0) break;
381 }
382 buf_begin -= bytes_needed;
383 buf_len += bytes_needed;
384}
385
386
387void Text_Buf::get_end(char*& end_ptr, int& end_len)
388{
389 int buf_end = buf_begin + buf_len;
390 if (buf_size - buf_end < BUF_SIZE) Reallocate(buf_len + BUF_SIZE);
391 end_ptr = (char*)data_ptr + buf_end;
392 end_len = buf_size - buf_end;
393}
394
395void Text_Buf::increase_length(int add_len)
396{
397 if (add_len < 0) TTCN_error("Text decoder: Addition is negative (%d) when "
398 "increasing length.", add_len);
399 if (buf_begin + buf_len + add_len > buf_size)
400 TTCN_error("Text decoder: Addition is too big when increasing length.");
401 buf_len += add_len;
402}
403
404/** Check if a known message is in the buffer
405 *
406 * @return TRUE if an int followed by the number of bytes specified
407 * by that int is in the buffer; FALSE otherwise.
408 * @post buf_pos == buf_begin
409 */
410boolean Text_Buf::is_message()
411{
412 rewind();
413 int_val_t msg_len;
414 boolean ret_val = FALSE;
415 if (safe_pull_int(msg_len)) {
416 if (msg_len < 0) {
417 char *tmp_str = msg_len.as_string();
418 TTCN_error("Text decoder: Negative message length (%s).", tmp_str);
419 Free(tmp_str); // ???
420 }
421 ret_val = buf_pos + msg_len.get_val() <= buf_begin + buf_len;
422 }
423 rewind();
424 return ret_val;
425}
426
427/** Overwrite the extracted message with the rest of the buffer
428 * @post buf_pos == buf_begin
429 */
430void Text_Buf::cut_message()
431{
432 if (is_message()) {
433 int msg_len = pull_int().get_val();
434 int msg_end = buf_pos + msg_len;
435 buf_len -= msg_end - buf_begin;
436 memmove((char*)data_ptr + buf_begin, (char*)data_ptr + msg_end,
437 buf_len);
438 Reallocate(buf_len);
439 rewind();
440 }
441}
This page took 0.038536 seconds and 5 git commands to generate.