Titan Core Initial Contribution
[deliverable/titan.core.git] / core / Textbuf.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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 + 32);
204 buf_len += sprintf((char*)data_ptr + buf_begin + buf_len, "%.16g ", value);
205 }
206
207 /** Extract a double precision floating point number
208 *
209 * @return the extracted value
210 * @pre A suitably formatted float value must be in the buffer, else
211 * dynamic testcase error
212 */
213 double Text_Buf::pull_double()
214 {
215 int buf_end = buf_begin + buf_len;
216 const char *char_ptr = (const char*)data_ptr;
217 // check for the proper format (printed in ascii, followed by a space)
218 if (buf_pos >= buf_end) TTCN_error("Text decoder: Decoding of float failed. "
219 "(End of buffer reached)");
220 else if (char_ptr[buf_pos] == ' ') TTCN_error("Text decoder: Decoding of "
221 "float failed. (No data before the end marker)");
222 int end_pos = buf_pos + 1;
223 for ( ; ; end_pos++) {
224 if (end_pos >= buf_end) TTCN_error("Text decoder: Decoding of float "
225 "failed. (Missing end marker)");
226 else if (char_ptr[end_pos] == ' ') break;
227 }
228 // perform the decoding
229 errno = 0;
230 double ret_val = atof(char_ptr + buf_pos);
231 if (ret_val == 0.0 && errno != 0) TTCN_error("Text decoder: Decoding of "
232 "float failed.");
233 // increment the read pointer
234 buf_pos = end_pos + 1;
235 return ret_val;
236 }
237
238 /** Write a fixed number of bytes in the buffer.
239 *
240 * @param len number of bytes to write
241 * @param data pointer to the data
242 */
243 void Text_Buf::push_raw(int len, const void *data)
244 {
245 if (len < 0) TTCN_error("Text encoder: Encoding raw data with negative "
246 "length (%d).", len);
247 Reallocate(buf_len + len);
248 memcpy((char*)data_ptr + buf_begin + buf_len, data, len);
249 buf_len += len;
250 }
251
252 /** Extract a fixed number of bytes from the buffer.
253 *
254 * @param len number of bytes to read
255 * @param data pointer to the data
256 * @pre at least \a len bytes are available, else dynamic testcase error
257 */
258 void Text_Buf::pull_raw(int len, void *data)
259 {
260 if (len < 0) TTCN_error("Text decoder: Decoding raw data with negative "
261 "length (%d).", len);
262 if (buf_pos + len > buf_begin + buf_len)
263 TTCN_error("Text decoder: End of buffer reached.");
264 memcpy(data, (char*)data_ptr + buf_pos, len);
265 buf_pos += len;
266 }
267
268 /** Write a 0-terminated string
269 *
270 * Writes the length followed by the raw bytes (no end marker)
271 *
272 * @param string_ptr pointer to the string
273 */
274 void Text_Buf::push_string(const char *string_ptr)
275 {
276 if (string_ptr != NULL) {
277 int len = strlen(string_ptr);
278 push_int(len);
279 push_raw(len, string_ptr);
280 } else push_int((RInt)0);
281 }
282
283 /** Extract a string
284 *
285 * @return the string allocated with new[], must be freed by the caller
286 */
287 char *Text_Buf::pull_string()
288 {
289 int len = pull_int().get_val();
290 if (len < 0)
291 TTCN_error("Text decoder: Negative string length (%d).", len);
292 char *string_ptr = new char[len + 1];
293 pull_raw(len, string_ptr);
294 string_ptr[len] = '\0';
295 return string_ptr;
296 }
297
298 /// Push two strings
299 void Text_Buf::push_qualified_name(const qualified_name& name)
300 {
301 push_string(name.module_name);
302 push_string(name.definition_name);
303 }
304
305 /// Extract two strings
306 void Text_Buf::pull_qualified_name(qualified_name& name)
307 {
308 name.module_name = pull_string();
309 if (name.module_name[0] == '\0') {
310 delete [] name.module_name;
311 name.module_name = NULL;
312 }
313 name.definition_name = pull_string();
314 if (name.definition_name[0] == '\0') {
315 delete [] name.definition_name;
316 name.definition_name = NULL;
317 }
318 }
319
320 /** Calculate the length of the buffer and write it at the beginning.
321 *
322 */
323 void Text_Buf::calculate_length()
324 {
325 unsigned int value = buf_len;
326 unsigned int bytes_needed = 1;
327 for (unsigned int tmp = value >> 6; tmp != 0; tmp >>= 7) bytes_needed++;
328 if ((unsigned int)buf_begin < bytes_needed)
329 TTCN_error("Text encoder: There is not enough space to calculate message "
330 "length.");
331 unsigned char *buf = (unsigned char*)data_ptr + buf_begin - bytes_needed;
332 for (unsigned int i = bytes_needed - 1; ; i--) {
333 if (i > 0) {
334 buf[i] = value & 0x7F;
335 value >>= 7;
336 } else buf[i] = value & 0x3F;
337 if (i < bytes_needed - 1) buf[i] |= 0x80;
338 if (i == 0) break;
339 }
340 buf_begin -= bytes_needed;
341 buf_len += bytes_needed;
342 }
343
344
345 void Text_Buf::get_end(char*& end_ptr, int& end_len)
346 {
347 int buf_end = buf_begin + buf_len;
348 if (buf_size - buf_end < BUF_SIZE) Reallocate(buf_len + BUF_SIZE);
349 end_ptr = (char*)data_ptr + buf_end;
350 end_len = buf_size - buf_end;
351 }
352
353 void Text_Buf::increase_length(int add_len)
354 {
355 if (add_len < 0) TTCN_error("Text decoder: Addition is negative (%d) when "
356 "increasing length.", add_len);
357 if (buf_begin + buf_len + add_len > buf_size)
358 TTCN_error("Text decoder: Addition is too big when increasing length.");
359 buf_len += add_len;
360 }
361
362 /** Check if a known message is in the buffer
363 *
364 * @return TRUE if an int followed by the number of bytes specified
365 * by that int is in the buffer; FALSE otherwise.
366 * @post buf_pos == buf_begin
367 */
368 boolean Text_Buf::is_message()
369 {
370 rewind();
371 int_val_t msg_len;
372 boolean ret_val = FALSE;
373 if (safe_pull_int(msg_len)) {
374 if (msg_len < 0) {
375 char *tmp_str = msg_len.as_string();
376 TTCN_error("Text decoder: Negative message length (%s).", tmp_str);
377 Free(tmp_str); // ???
378 }
379 ret_val = buf_pos + msg_len.get_val() <= buf_begin + buf_len;
380 }
381 rewind();
382 return ret_val;
383 }
384
385 /** Overwrite the extracted message with the rest of the buffer
386 * @post buf_pos == buf_begin
387 */
388 void Text_Buf::cut_message()
389 {
390 if (is_message()) {
391 int msg_len = pull_int().get_val();
392 int msg_end = buf_pos + msg_len;
393 buf_len -= msg_end - buf_begin;
394 memmove((char*)data_ptr + buf_begin, (char*)data_ptr + msg_end,
395 buf_len);
396 Reallocate(buf_len);
397 rewind();
398 }
399 }
This page took 0.040332 seconds and 6 git commands to generate.