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