1 /*
2     Copyright (C) 2008-2017, Millistream Market Data <support@millistream.com>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU Lesser General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU Lesser General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 */
18 
19 #include "common.h"
20 #include "encode.h"
21 
grow_buffer(struct mdf_message_s * const message,const int len_to_add)22 static void grow_buffer (struct mdf_message_s * const message, const int len_to_add)
23 {
24 	if (message->data_used + len_to_add > message->data_size) {
25 		message->data_size = message->data_used + len_to_add;
26 		message->data_size += BUFFER_CHUNK_SIZE - (message->data_size % BUFFER_CHUNK_SIZE);
27 
28 		message->data = (uint8_t *) realloc (message->data, message->data_size);
29 	}
30 }
31 
mdf_message_create()32 mdf_message_t mdf_message_create ()
33 {
34 	mdf_message_t message = (struct mdf_message_s *) calloc (1, sizeof (struct mdf_message_s));
35 
36 	if (message == NULL)
37 		return NULL;
38 
39 	message->current_message = -1;
40 	return message;
41 }
42 
mdf_message_add(mdf_message_t message,const uint64_t instrument_reference,const int message_reference)43 int mdf_message_add (mdf_message_t message, const uint64_t instrument_reference, const int message_reference)
44 {
45 	if (message == NULL)
46 		return 0;
47 
48 	/* terminate the current message before we proceed */
49 	if (message->current_message != -1) {
50 		struct message *m = &(message->messages[message->current_message]);
51 
52 		/* the current message is not filled at all, reuse! */
53 		if (m->fields == 0 && m->mref != MDF_M_INSTRUMENTRESET && m->mref != MDF_M_INSTRUMENTDELETE && m->mref != MDF_M_ORDERBOOKFLUSH && m->mref != MDF_M_LOGOFF)
54 			goto reuse;
55 	}
56 
57 	message->current_message++;
58 
59 	/* grow the message chain if current is over the top */
60 	if (message->current_message == message->messages_max) {
61 		message->messages_max++;
62 		message->messages = (struct message *) realloc (message->messages, sizeof *message->messages * message->messages_max);
63 	}
64 
65 reuse:
66 	message->messages[message->current_message].insref = instrument_reference;
67 	message->messages[message->current_message].mref = message_reference;
68 	message->messages[message->current_message].fields = 0;
69 
70 	return 1;
71 }
72 
73 
mdf_message_del(mdf_message_t message)74 int mdf_message_del (mdf_message_t message)
75 {
76 	if (message == NULL)
77 		return 0;
78 
79 	if (message->current_message == -1)
80 		return 0;
81 
82 	message->fields_num -= message->messages[message->current_message].fields;
83 
84 	if (message->messages[message->current_message].fields != 0)
85 		message->data_used = message->fields[message->fields_num].offset;
86 
87 	message->current_message--;
88 
89 	if (message->current_message == -1)
90 		return 0;
91 
92 	return 1;
93 }
94 
mdf_message_reset(mdf_message_t message)95 void mdf_message_reset (mdf_message_t message)
96 {
97 	message->current_message = -1;
98 	message->fields_num = 0;
99 	message->data_used = 0;
100 }
101 
mdf_message_destroy(mdf_message_t message)102 void mdf_message_destroy (mdf_message_t message)
103 {
104 	if (message == NULL)
105 		return;
106 
107 	free (message->messages);
108 	free (message->fields);
109 	free (message->data);
110 	free (message);
111 }
112 
mdf_message_get_num(mdf_message_t message)113 int mdf_message_get_num (mdf_message_t message)
114 {
115 	if (message == NULL)
116 		return 0;
117 
118 	return message->messages_max;
119 }
120 
mdf_message_get_num_active(mdf_message_t message)121 int mdf_message_get_num_active (mdf_message_t message)
122 {
123 	if (message == NULL)
124 		return 0;
125 
126 	return message->current_message + 1;
127 }
128 
mdf_message_deserialize(const mdf_message_t message,const char * const data)129 int mdf_message_deserialize (const mdf_message_t message, const char * const data)
130 {
131 	if (message == NULL || data == NULL)
132 		return 0;
133 
134 	size_t len = strlen (data);
135 
136 	BIO *bio = BIO_new_mem_buf ((const void *)data, len);
137 
138 	if (bio == NULL)
139 		return 0;
140 
141 	BIO *b64 = BIO_new (BIO_f_base64 ());
142 
143 	if (b64 == NULL) {
144 		BIO_free (bio);
145 		return 0;
146 	}
147 
148 	bio = BIO_push(b64, bio);
149 
150 	BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
151 
152 	uint8_t *buf = malloc ((len * 3) / 4 + 1);
153 
154 	if (buf == NULL) {
155 		BIO_free_all(bio);
156 		return 0;
157 	}
158 
159 	const size_t ret = BIO_read (bio, buf, len);
160 
161 	BIO_free_all(bio);
162 
163 	int current_message;
164 	int fields_num;
165 	size_t data_used;
166 
167 	if (sizeof current_message + sizeof fields_num + sizeof data_used > ret) {
168 		free (buf);
169 		return 0;
170 	}
171 
172 	size_t offset = sizeof current_message;
173 	memcpy (&current_message, buf, offset);
174 	memcpy (&fields_num, buf + offset, sizeof fields_num); offset += sizeof fields_num;
175 	memcpy (&data_used, buf + offset, sizeof data_used); offset += sizeof data_used;
176 
177 	if (offset + (current_message + 1) * sizeof *message->messages + fields_num * sizeof *message->fields + data_used != ret) {
178 		free (buf);
179 		return 0;
180 	}
181 
182 	message->current_message = current_message;
183 	message->fields_num = fields_num;
184 	message->data_used = data_used;
185 
186 	if (message->current_message + 1 >= message->messages_max) {
187 		message->messages_max = message->current_message + 1;
188 		message->messages = (struct message *) realloc (message->messages, sizeof *message->messages * message->messages_max);
189 	}
190 
191 	memcpy (message->messages, buf + offset, (message->current_message + 1) * sizeof *message->messages); offset += (message->current_message + 1) * sizeof *message->messages;
192 
193 	if (message->fields_num >= message->fields_max) {
194 		message->fields_max = message->fields_num + 1;
195 		message->fields_max += FIELDS_CHUNK_SIZE - (message->fields_max % FIELDS_CHUNK_SIZE);
196 		message->fields = (struct field *) realloc (message->fields, sizeof *message->fields * message->fields_max);
197 	}
198 
199 	memcpy (message->fields, buf + offset, message->fields_num * sizeof *message->fields); offset += message->fields_num * sizeof *message->fields;
200 
201 	if (message->data_used > message->data_size) {
202 		message->data_size = message->data_used;
203 		message->data_size += BUFFER_CHUNK_SIZE - (message->data_size % BUFFER_CHUNK_SIZE);
204 		free (message->data);
205 		message->data = (uint8_t *) malloc (message->data_size);
206 	}
207 
208 	memcpy (message->data, buf + offset, message->data_used);
209 
210 	free (buf);
211 	return 1;
212 }
213 
mdf_message_serialize(const mdf_message_t message,char ** result)214 int mdf_message_serialize (const mdf_message_t message, char **result)
215 {
216 	if (message == NULL || message->current_message == -1)
217 		return 0;
218 
219 	uint8_t *buf = malloc (sizeof message->current_message + sizeof message->fields_num + sizeof message->data_used + (message->current_message + 1) * sizeof *message->messages + message->fields_num * sizeof *message->fields + message->data_used);
220 
221 	if (buf == NULL)
222 		return 0;
223 
224 	size_t offset = sizeof message->current_message;
225 	memcpy (buf, &message->current_message, offset);
226 	memcpy (buf + offset, &message->fields_num, sizeof message->fields_num); offset += sizeof message->fields_num;
227 	memcpy (buf + offset, &message->data_used, sizeof message->data_used); offset += sizeof message->data_used;
228 	memcpy (buf + offset, message->messages, (message->current_message + 1) * sizeof *message->messages); offset += (message->current_message + 1) * sizeof *message->messages;
229 	memcpy (buf + offset, message->fields, message->fields_num * sizeof *message->fields); offset += message->fields_num * sizeof *message->fields;
230 	memcpy (buf + offset, message->data, message->data_used); offset += message->data_used;
231 
232 	BIO *b64 = BIO_new (BIO_f_base64 ());
233 
234 	if (b64 == NULL) {
235 		free (buf);
236 		return 0;
237 	}
238 
239 	BIO *bio = BIO_new (BIO_s_mem ());
240 
241 	if (bio == NULL) {
242 		BIO_free (b64);
243 		free (buf);
244 		return 0;
245 	}
246 
247 	bio = BIO_push (b64, bio);
248 	BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
249 	BIO_write (bio, buf, offset);
250 	BIO_flush (bio);
251 	free (buf);
252 
253 	BUF_MEM *bptr;
254 	BIO_get_mem_ptr (bio, &bptr);
255 
256 	*result = malloc (bptr->length + 1);
257 
258 	if (*result == NULL) {
259 		BIO_free_all(bio);
260 		return 0;
261 	}
262 
263 	memcpy (*result, bptr->data, bptr->length);
264 	(*result)[bptr->length] = '\0';
265 	BIO_free_all(bio);
266 
267 	return 1;
268 }
269 
mdf_message_move(const mdf_message_t message_src,const mdf_message_t message_dst,const uint64_t insref_src,const uint64_t insref_dst)270 int mdf_message_move (const mdf_message_t message_src, const mdf_message_t message_dst, const uint64_t insref_src, const uint64_t insref_dst)
271 {
272 	if (message_src == NULL)
273 		return 0;
274 
275 	if (message_src->current_message == -1)
276 		return 0;
277 
278 	int i;
279 	int current_field = 0;
280 
281 	for (i = 0; i < message_src->current_message + 1; i++) {
282 		if (message_src->messages[i].insref != insref_src) {
283 			current_field += message_src->messages[i].fields;
284 			continue;
285 		}
286 
287 		if (message_src->messages[i].fields == 0 && message_src->messages[i].mref != MDF_M_INSTRUMENTRESET && message_src->messages[i].mref != MDF_M_INSTRUMENTDELETE && message_src->messages[i].mref != MDF_M_ORDERBOOKFLUSH && message_src->messages[i].mref != MDF_M_LOGOFF)
288 			continue;
289 
290 		/* destination and source is same so we simply change the insref in place */
291 		if (message_src == message_dst || message_dst == NULL) {
292 			message_src->messages[i].insref = insref_dst;
293 			continue;
294 		}
295 
296 		message_dst->current_message++;
297 
298 		if (message_dst->current_message == message_dst->messages_max) {
299 			message_dst->messages_max++;
300 			message_dst->messages = (struct message *) realloc (message_dst->messages, sizeof *message_dst->messages * message_dst->messages_max);
301 		}
302 
303 		message_dst->messages[message_dst->current_message].insref = insref_dst;
304 		message_dst->messages[message_dst->current_message].mref = message_src->messages[i].mref;
305 		message_dst->messages[message_dst->current_message].fields = message_src->messages[i].fields;
306 
307 		if (message_dst->fields_num + message_src->messages[i].fields >= message_dst->fields_max) {
308 			message_dst->fields_max = message_dst->fields_num + message_src->messages[i].fields;
309 			message_dst->fields_max += FIELDS_CHUNK_SIZE - (message_dst->fields_max % FIELDS_CHUNK_SIZE);
310 			message_dst->fields = (struct field *) realloc (message_dst->fields, sizeof *message_dst->fields * message_dst->fields_max);
311 		}
312 
313 		int j, k;
314 		for (j = 0, k = current_field; j < message_src->messages[i].fields; j++, k++) {
315 			message_dst->fields[message_dst->fields_num].offset = message_dst->data_used;
316 			message_dst->fields[message_dst->fields_num].tag = message_src->fields[k].tag;
317 			message_dst->fields[message_dst->fields_num].len = message_src->fields[k].len;
318 
319 			if (message_dst->data_used + message_src->fields[k].len > message_dst->data_size) {
320 				message_dst->data_size = message_dst->data_used + message_src->fields[k].len;
321 				message_dst->data_size += BUFFER_CHUNK_SIZE - (message_dst->data_size % BUFFER_CHUNK_SIZE);
322 				message_dst->data = (uint8_t *) realloc (message_dst->data, message_dst->data_size);
323 			}
324 
325 			memcpy (message_dst->data + message_dst->data_used, message_src->data + message_src->fields[k].offset, message_src->fields[k].len);
326 			message_dst->data_used += message_src->fields[k].len;
327 
328 			message_dst->fields_num++;
329 		}
330 
331 		memmove (message_src->fields + current_field, message_src->fields + current_field + message_src->messages[i].fields, (message_src->fields_num - (current_field + message_src->messages[i].fields)) * sizeof (struct field));
332 		message_src->fields_num -= message_src->messages[i].fields;
333 		memmove (message_src->messages + i, message_src->messages + i + 1, (message_src->current_message - i) * sizeof (struct message));
334 		message_src->current_message--;
335 
336 		if (message_src->current_message == -1)
337 			message_src->data_used = 0;
338 
339 		i--;
340 	}
341 
342 	return 1;
343 }
344 
add_tag(struct mdf_message_s * const message,const uint32_t tag,const size_t offset,const int len)345 static void add_tag (struct mdf_message_s * const message, const uint32_t tag, const size_t offset, const int len)
346 {
347 	message->messages[message->current_message].fields++;
348 
349 	if (message->fields_num == message->fields_max) {
350 		message->fields_max = message->fields_num + 1;
351 		message->fields_max += FIELDS_CHUNK_SIZE - (message->fields_max % FIELDS_CHUNK_SIZE);
352 
353 		message->fields = (struct field *) realloc (message->fields, sizeof *message->fields * message->fields_max);
354 	}
355 
356 	message->fields[message->fields_num].offset = offset;
357 	message->fields[message->fields_num].tag = tag;
358 	message->fields[message->fields_num++].len = len;
359 }
360 
add_null(struct mdf_message_s * const message,const uint32_t tag)361 static int add_null (struct mdf_message_s * const message, const uint32_t tag)
362 {
363 	add_tag (message, tag, message->data_used, 1);
364 	grow_buffer (message, 1);
365 	message->data[message->data_used++] = 240;
366 
367 	return 1;
368 }
369 
add_as_bcd(struct mdf_message_s * const message,const uint32_t tag,const char * value,const int neg)370 static int add_as_bcd (struct mdf_message_s * const message, const uint32_t tag, const char *value, const int neg)
371 {
372 	int even = 0;
373 	size_t oldpos = message->data_used;
374 	size_t len = strlen (value);
375 
376 	grow_buffer (message, ((len + 1) / 2) + 2);
377 	message->data[message->data_used++] = 0xFF;
378 
379 	if (neg == 1) {
380 		message->data[message->data_used] = 0xC0;
381 		even = 1;
382 	}
383 
384 	for (; *value != '\0'; value++) {
385 		int code;
386 
387 		if (*value == '.')
388 			code = 0x0A;
389 		else
390 			code = *value - '0';
391 
392 		if (code > 10 || code < 0)
393 			continue;
394 
395 		if (even == 0) {
396 			even = 1;
397 			message->data[message->data_used] = (uint8_t) (code << 4);
398 		} else {
399 			even = 0;
400 			message->data[message->data_used++] |= code;
401 		}
402 	}
403 
404 	if (even == 0)
405 		message->data[message->data_used++] = 0xDD;
406 	else
407 		message->data[message->data_used++] |= 0x0D;
408 
409 	add_tag (message, tag, oldpos, message->data_used - oldpos);
410 	return 1;
411 }
412 
413 /* buf must be at least 5 bytes for uint32_t and 10 bytes for uint64_t */
add_serialised_integer(uint8_t * buf,uint64_t value)414 static int add_serialised_integer (uint8_t *buf, uint64_t value)
415 {
416 	uint8_t *p = buf;
417 	uint64_t tmp = value;
418 	uint64_t offset = 0;
419 	int d;
420 	int c = 0;
421 
422 	do {
423 		++c;
424 		offset = offset * 128 + 1;
425 		tmp = (tmp - 1) / 128;
426 	} while (tmp != 0);
427 
428 	value -= offset;
429 	d = c - 1;
430 
431 	do {
432 		p[--c] = (uint8_t) (value % 128);
433 		value /= 128;
434 	} while (c != 0);
435 
436 	p += d;
437 
438 	*p++ |= 128;
439 
440 	return p - buf;
441 }
442 
mdf_message_add_list(mdf_message_t message,const uint32_t tag,const char * value)443 int mdf_message_add_list (mdf_message_t message, const uint32_t tag, const char *value)
444 {
445 	const char *p;
446 	size_t oldpos;
447 	uint32_t i;
448 	uint32_t num = 0;
449 
450 	if (message == NULL || message->current_message == -1)
451 		return 0;
452 
453 	if (value == NULL)
454 		return add_null (message, tag);
455 
456 	for (p = value; *p != '\0'; p++) {
457 		if (isdigit ((unsigned char) *p) != 0) {
458 			num++;
459 
460 			while (isdigit ((unsigned char) p[1]) != 0)
461 				p++;
462 		}
463 	}
464 
465 	/* sanity limit */
466 	if (num > 1000000)
467 		return 0;
468 
469 	if (num == 0)
470 		return add_null (message, tag);
471 
472 	oldpos = message->data_used;
473 
474 	grow_buffer (message, num * 10 + 6);
475 
476 	if (isdigit ((unsigned char) *value) != 0) {
477 		message->data[message->data_used++] = 250;
478 	} else if (*value == '=') {
479 		message->data[message->data_used++] = 250;
480 		value++;
481 	} else if (*value == '-') {
482 		message->data[message->data_used++] = 249;
483 		value++;
484 	} else if (*value == '+') {
485 		message->data[message->data_used++] = 248;
486 		value++;
487 	} else {
488 		message->data_used = oldpos;
489 		return 0;
490 	}
491 
492 	message->data_used += add_serialised_integer (message->data + message->data_used, (uint64_t) num);
493 
494 	for (i = 0; i < num; i++) {
495 		uint64_t v;
496 
497 		while (isdigit ((unsigned char) *value) == 0)
498 			value++;
499 
500 		errno = 0;
501 		v = strtoull (value, NULL, 10);
502 
503 		if (errno != 0) {
504 			message->data_used = oldpos;
505 			return 0;
506 		}
507 
508 		message->data_used += add_serialised_integer (message->data + message->data_used, v + 1);
509 
510 		while (isdigit ((unsigned char) *value) != 0)
511 			value++;
512 	}
513 
514 	add_tag (message, tag, oldpos, message->data_used - oldpos);
515 	return 1;
516 }
517 
mdf_message_add_numeric(mdf_message_t message,const uint32_t tag,const char * value)518 int mdf_message_add_numeric (mdf_message_t message, const uint32_t tag, const char *value)
519 {
520 	int neg = 0;
521 	unsigned int decimals = 0;
522 	int bytes = 0;
523 	char *endptr;
524 	uint8_t *p;
525 	uint64_t num;
526 	uint64_t integer;
527 	uint64_t tmpval;
528 	uint64_t offset = 0;
529 	uint64_t dec = 0;
530 
531 	if (message == NULL || message->current_message == -1)
532 		return 0;
533 
534 	if (value == NULL)
535 		return add_null (message, tag);
536 
537 	while (isspace ((unsigned char) *value) != 0)
538 		++value;
539 
540 	if (*value == '-') {
541 		++value;
542 		neg = 1;
543 	} else if (*value == '+') {
544 		++value;
545 	} else if (*value == '=') {
546 		++value;
547 	}
548 
549 	if (*value == '\0')
550 		return add_null (message, tag);
551 
552 	errno = 0;
553 	num = strtoull (value, &endptr, 10);
554 
555 	if (errno != 0)
556 		return add_as_bcd (message, tag, value, neg);
557 
558 	integer = num;
559 
560 	if (*endptr == '.') {
561 		const uint64_t cutoff = __UINT64_C (1844674407370955161);
562 		unsigned char c;
563 		char *ptr = endptr + strlen (endptr);
564 
565 		--ptr;
566 
567 		while (*ptr == '0' || isspace ((unsigned char) *ptr) != 0)
568 			--ptr;
569 
570 		++endptr;
571 
572 		for (c = *endptr; endptr <= ptr; c = *++endptr) {
573 			if (c < '0' || c > '9')
574 				return 0;
575 
576 			c -= '0';
577 
578 			/* do we overflow num? */
579 			if (num > cutoff || (num == cutoff && c > 5))
580 				return add_as_bcd (message, tag, value, neg);
581 
582 			dec = dec * 10 + c;
583 			num = num * 10 + c;
584 			decimals++;
585 		}
586 	} else if (*endptr != '\0')
587 		return 0;
588 
589 	if (decimals > 15)
590 		return add_as_bcd (message, tag, value, neg);
591 
592 	if (neg == 0) {
593 		if (decimals == 0) {
594 			int scale = 0;
595 
596 			if (num < 28) {
597 				add_tag (message, tag, message->data_used, 1);
598 				grow_buffer (message, 1);
599 				message->data[message->data_used++] = (uint8_t) (num + 100);
600 				return 1;
601 			}
602 
603 			if (num < 284) {
604 				add_tag (message, tag, message->data_used, 2);
605 				grow_buffer (message, 2);
606 				message->data[message->data_used++] = 0;
607 				message->data[message->data_used++] = (uint8_t) (num - 28);
608 				return 1;
609 			}
610 
611 			while (integer % 10 == 0) {
612 				integer /= 10;
613 				++scale;
614 
615 				if (scale == 16)
616 					break;
617 			}
618 
619 			if (scale > 0) {
620 				tmpval = integer;
621 
622 				do {
623 					++bytes;
624 					offset = offset * 128 + 1;
625 					tmpval = (tmpval - 1) / 128;
626 				} while (tmpval != 0);
627 
628 				integer -= offset;
629 
630 				add_tag (message, tag, message->data_used, bytes + 1);
631 				grow_buffer (message, bytes + 1);
632 
633 				message->data[message->data_used++] = (uint8_t) (0xA0 + (scale - 1));
634 				p = message->data + message->data_used;
635 				message->data_used += bytes;
636 
637 				do {
638 					p[--bytes] = (uint8_t) (integer % 128);
639 
640 					integer /= 128;
641 				} while (bytes != 0);
642 
643 				message->data[message->data_used - 1] |= 128;
644 				return 1;
645 			}
646 		}
647 
648 		if (decimals < 3 && integer < 256) {
649 			/* decimals == 0 for this price range is taken care of by the previous code */
650 			if (decimals == 1)
651 				dec *= 10;
652 
653 			add_tag (message, tag, message->data_used, 2);
654 			grow_buffer (message, 2);
655 			message->data[message->data_used++] = (uint8_t) dec;
656 			message->data[message->data_used++] = (uint8_t) integer;
657 			return 1;
658 		}
659 
660 		if ((decimals < 5 && (integer < 104 || (integer == 104 && ((decimals == 3 && dec < 858) || (decimals == 4 && dec < 8577)))))) {
661 			/* decimals < 3 for this price range is taken care of by the previous code */
662 			if (decimals == 3)
663 				num *= 10;
664 
665 			--num;
666 
667 			add_tag (message, tag, message->data_used, 3);
668 			grow_buffer (message, 3);
669 			message->data[message->data_used++] = (uint8_t) (0x80 + (num >> 16));
670 			message->data[message->data_used++] = (uint8_t) (num % 256);
671 			message->data[message->data_used++] = (uint8_t) ((num & 0x0000FFFF) / 256);
672 			return 1;
673 		}
674 
675 		if (decimals < 3 && (integer < 10741 || (integer == 10741 && dec < 77 && !(decimals == 1 && dec > 7)))) {
676 			if (decimals == 0)
677 				num *= 100;
678 			else if (decimals == 1)
679 				num *= 10;
680 
681 			num -= 25601;
682 
683 			add_tag (message, tag, message->data_used, 3);
684 			grow_buffer (message, 3);
685 			message->data[message->data_used++] = (uint8_t) (0x90 + (num >> 16));
686 			message->data[message->data_used++] = (uint8_t) (num % 256);
687 			message->data[message->data_used++] = (uint8_t) ((num & 0x0000FFFF) / 256);
688 			return 1;
689 		}
690 	}
691 
692 	/* add +/- integer with up to 15 decimals */
693 	tmpval = num;
694 
695 	do {
696 		++bytes;
697 		offset = offset * 128UL + 1UL;
698 		tmpval = (tmpval - 1UL) / 128UL;
699 	} while (tmpval != 0UL);
700 
701 	num -= offset;
702 
703 	add_tag (message, tag, message->data_used, bytes + 1);
704 	grow_buffer (message, bytes + 1);
705 
706 	if (neg == 0)
707 		message->data[message->data_used++] = (uint8_t) (0xB0 + decimals);
708 	else
709 		message->data[message->data_used++] = (uint8_t) (0xC0 + decimals);
710 
711 	p = message->data + message->data_used;
712 	message->data_used += bytes;
713 
714 	do {
715 		p[--bytes] = (uint8_t) (num % 128);
716 
717 		num /= 128UL;
718 	} while (bytes != 0);
719 
720 	message->data[message->data_used - 1] |= 128;
721 	return 1;
722 }
723 
mdf_message_add_uint(mdf_message_t message,const uint32_t tag,uint64_t value,int decimals)724 int mdf_message_add_uint (mdf_message_t message, const uint32_t tag, uint64_t value, int decimals)
725 {
726 	static const uint64_t divisor[20] = {
727 		1,
728 		10,
729 		100,
730 		1000,
731 		10000,
732 		100000,
733 		1000000,
734 		10000000,
735 		100000000,
736 		1000000000,
737     __UINT64_C (10000000000),
738     __UINT64_C (100000000000),
739     __UINT64_C (1000000000000),
740     __UINT64_C (10000000000000),
741     __UINT64_C (100000000000000),
742     __UINT64_C (1000000000000000),
743     __UINT64_C (10000000000000000),
744     __UINT64_C (100000000000000000),
745     __UINT64_C (1000000000000000000),
746     __UINT64_C (10000000000000000000)
747 	};
748 
749 	int bytes = 0;
750 	uint8_t *p;
751 	uint64_t integer;
752 	uint64_t tmpval;
753 	uint64_t offset = 0;
754 	uint64_t dec = 0;
755 
756 	if (message == NULL || message->current_message == -1 || decimals > 19 || decimals < 0)
757 		return 0;
758 
759 	/* we must normalize the scaled value */
760 	while (decimals > 0 && value % 10 == 0) {
761 		value /= 10;
762 		decimals--;
763 	}
764 
765 	integer = value / divisor[decimals];
766 
767 	if (decimals > 15) {
768 		char string[30];
769 		sprintf (string, "%" PRIu64 ".%0*" PRIu64, integer, decimals, value % divisor[decimals]);
770 		return add_as_bcd (message, tag, string, 0);
771 	}
772 
773 	if (decimals == 0) {
774 		int scale = 0;
775 
776 		if (value < 28) {
777 			add_tag (message, tag, message->data_used, 1);
778 			grow_buffer (message, 1);
779 			message->data[message->data_used++] = (uint8_t) (value + 100);
780 			return 1;
781 		}
782 
783 		if (value < 284) {
784 			add_tag (message, tag, message->data_used, 2);
785 			grow_buffer (message, 2);
786 			message->data[message->data_used++] = 0;
787 			message->data[message->data_used++] = (uint8_t) (value - 28);
788 			return 1;
789 		}
790 
791 		while (integer % 10 == 0) {
792 			integer /= 10;
793 			++scale;
794 
795 			if (scale == 16)
796 				break;
797 		}
798 
799 		if (scale > 0) {
800 			tmpval = integer;
801 
802 			do {
803 				++bytes;
804 				offset = offset * 128 + 1;
805 				tmpval = (tmpval - 1) / 128;
806 			} while (tmpval != 0);
807 
808 			integer -= offset;
809 
810 			add_tag (message, tag, message->data_used, bytes + 1);
811 			grow_buffer (message, bytes + 1);
812 
813 			message->data[message->data_used++] = (uint8_t) (0xA0 + (scale - 1));
814 			p = message->data + message->data_used;
815 			message->data_used += bytes;
816 
817 			do {
818 				p[--bytes] = (uint8_t) (integer % 128);
819 
820 				integer /= 128;
821 			} while (bytes != 0);
822 
823 			message->data[message->data_used - 1] |= 128;
824 			return 1;
825 		}
826 	}
827 
828 	dec = value % divisor[decimals];
829 
830 	if (decimals < 3 && integer < 256) {
831 		/* decimals == 0 for this price range is taken care of by the previous code */
832 		if (decimals == 1)
833 			dec *= 10;
834 
835 		add_tag (message, tag, message->data_used, 2);
836 		grow_buffer (message, 2);
837 		message->data[message->data_used++] = (uint8_t) dec;
838 		message->data[message->data_used++] = (uint8_t) integer;
839 		return 1;
840 	}
841 
842 	if ((decimals < 5 && (integer < 104 || (integer == 104 && ((decimals == 3 && dec < 858) || (decimals == 4 && dec < 8577)))))) {
843 		/* decimals < 3 for this price range is taken care of by the previous code */
844 		if (decimals == 3)
845 			value *= 10;
846 
847 		--value;
848 
849 		add_tag (message, tag, message->data_used, 3);
850 		grow_buffer (message, 3);
851 		message->data[message->data_used++] = (uint8_t) (0x80 + (value >> 16));
852 		message->data[message->data_used++] = (uint8_t) (value % 256);
853 		message->data[message->data_used++] = (uint8_t) ((value & 0x0000FFFF) / 256);
854 		return 1;
855 	}
856 
857 	if (decimals < 3 && (integer < 10741 || (integer == 10741 && dec < 77 && !(decimals == 1 && dec > 7)))) {
858 		if (decimals == 0)
859 			value *= 100;
860 		else if (decimals == 1)
861 			value *= 10;
862 
863 		value -= 25601;
864 
865 		add_tag (message, tag, message->data_used, 3);
866 		grow_buffer (message, 3);
867 		message->data[message->data_used++] = (uint8_t) (0x90 + (value >> 16));
868 		message->data[message->data_used++] = (uint8_t) (value % 256);
869 		message->data[message->data_used++] = (uint8_t) ((value & 0x0000FFFF) / 256);
870 		return 1;
871 	}
872 
873 	/* add +/- integer with up to 15 decimals */
874 	tmpval = value;
875 
876 	do {
877 		++bytes;
878 		offset = offset * 128UL + 1UL;
879 		tmpval = (tmpval - 1UL) / 128UL;
880 	} while (tmpval != 0UL);
881 
882 	value -= offset;
883 
884 	add_tag (message, tag, message->data_used, bytes + 1);
885 	grow_buffer (message, bytes + 1);
886 
887 	message->data[message->data_used++] = (uint8_t) (0xB0 + decimals);
888 	p = message->data + message->data_used;
889 	message->data_used += bytes;
890 
891 	do {
892 		p[--bytes] = (uint8_t) (value % 128);
893 
894 		value /= 128UL;
895 	} while (bytes != 0);
896 
897 	message->data[message->data_used - 1] |= 128;
898 	return 1;
899 }
900 
mdf_message_add_int(mdf_message_t message,const uint32_t tag,int64_t value,int decimals)901 int mdf_message_add_int (mdf_message_t message, const uint32_t tag, int64_t value, int decimals)
902 {
903 	static const uint64_t divisor[20] = {
904 		1,
905 		10,
906 		100,
907 		1000,
908 		10000,
909 		100000,
910 		1000000,
911 		10000000,
912 		100000000,
913 		1000000000,
914     __UINT64_C (10000000000),
915     __UINT64_C (100000000000),
916     __UINT64_C (1000000000000),
917     __UINT64_C (10000000000000),
918     __UINT64_C (100000000000000),
919     __UINT64_C (1000000000000000),
920     __UINT64_C (10000000000000000),
921     __UINT64_C (100000000000000000),
922     __UINT64_C (1000000000000000000),
923     __UINT64_C (10000000000000000000)
924 	};
925 
926 	int bytes = 0;
927 	int neg = 0;
928 	uint8_t *p;
929 	uint64_t integer;
930 	uint64_t tmpval;
931 	uint64_t offset = 0;
932 
933 	if (message == NULL || message->current_message == -1 || decimals > 19 || decimals < 0)
934 		return 0;
935 
936 	if (value < 0) {
937 		neg = 1;
938 		value = -value;
939 	}
940 
941 	/* we must normalize the scaled value */
942 	while (decimals > 0 && value % 10 == 0) {
943 		value /= 10;
944 		decimals--;
945 	}
946 
947 	integer = value / divisor[decimals];
948 
949 	if (decimals > 15) {
950 		char string[30];
951 		sprintf (string, "%" PRIu64 ".%0*" PRIu64, integer, decimals, value % divisor[decimals]);
952 		return add_as_bcd (message, tag, string, neg);
953 	}
954 
955 	if (neg == 0) {
956 		if (decimals == 0) {
957 			int scale = 0;
958 
959 			if (value < 28) {
960 				add_tag (message, tag, message->data_used, 1);
961 				grow_buffer (message, 1);
962 				message->data[message->data_used++] = (uint8_t) (value + 100);
963 				return 1;
964 			}
965 
966 			if (value < 284) {
967 				add_tag (message, tag, message->data_used, 2);
968 				grow_buffer (message, 2);
969 				message->data[message->data_used++] = 0;
970 				message->data[message->data_used++] = (uint8_t) (value - 28);
971 				return 1;
972 			}
973 
974 			while (integer % 10 == 0) {
975 				integer /= 10;
976 				++scale;
977 
978 				if (scale == 16)
979 					break;
980 			}
981 
982 			if (scale > 0) {
983 				tmpval = integer;
984 
985 				do {
986 					++bytes;
987 					offset = offset * 128 + 1;
988 					tmpval = (tmpval - 1) / 128;
989 				} while (tmpval != 0);
990 
991 				integer -= offset;
992 
993 				add_tag (message, tag, message->data_used, bytes + 1);
994 				grow_buffer (message, bytes + 1);
995 
996 				message->data[message->data_used++] = (uint8_t) (0xA0 + (scale - 1));
997 				p = message->data + message->data_used;
998 				message->data_used += bytes;
999 
1000 				do {
1001 					p[--bytes] = (uint8_t) (integer % 128);
1002 
1003 					integer /= 128;
1004 				} while (bytes != 0);
1005 
1006 				message->data[message->data_used - 1] |= 128;
1007 				return 1;
1008 			}
1009 		}
1010 
1011 		uint64_t dec = value % divisor[decimals];
1012 
1013 		if (decimals < 3 && integer < 256) {
1014 			/* decimals == 0 for this price range is taken care of by the previous code */
1015 			if (decimals == 1)
1016 				dec *= 10;
1017 
1018 			add_tag (message, tag, message->data_used, 2);
1019 			grow_buffer (message, 2);
1020 			message->data[message->data_used++] = (uint8_t) dec;
1021 			message->data[message->data_used++] = (uint8_t) integer;
1022 			return 1;
1023 		}
1024 
1025 		if ((decimals < 5 && (integer < 104 || (integer == 104 && ((decimals == 3 && dec < 858) || (decimals == 4 && dec < 8577)))))) {
1026 			/* decimals < 3 for this price range is taken care of by the previous code */
1027 			if (decimals == 3)
1028 				value *= 10;
1029 
1030 			--value;
1031 
1032 			add_tag (message, tag, message->data_used, 3);
1033 			grow_buffer (message, 3);
1034 			message->data[message->data_used++] = (uint8_t) (0x80 + (value >> 16));
1035 			message->data[message->data_used++] = (uint8_t) (value % 256);
1036 			message->data[message->data_used++] = (uint8_t) ((value & 0x0000FFFF) / 256);
1037 			return 1;
1038 		}
1039 
1040 		if (decimals < 3 && (integer < 10741 || (integer == 10741 && dec < 77 && !(decimals == 1 && dec > 7)))) {
1041 			if (decimals == 0)
1042 				value *= 100;
1043 			else if (decimals == 1)
1044 				value *= 10;
1045 
1046 			value -= 25601;
1047 
1048 			add_tag (message, tag, message->data_used, 3);
1049 			grow_buffer (message, 3);
1050 			message->data[message->data_used++] = (uint8_t) (0x90 + (value >> 16));
1051 			message->data[message->data_used++] = (uint8_t) (value % 256);
1052 			message->data[message->data_used++] = (uint8_t) ((value & 0x0000FFFF) / 256);
1053 			return 1;
1054 		}
1055 	}
1056 
1057 	/* add +/- integer with up to 15 decimals */
1058 	tmpval = value;
1059 
1060 	do {
1061 		++bytes;
1062 		offset = offset * 128UL + 1UL;
1063 		tmpval = (tmpval - 1UL) / 128UL;
1064 	} while (tmpval != 0UL);
1065 
1066 	value -= offset;
1067 
1068 	add_tag (message, tag, message->data_used, bytes + 1);
1069 	grow_buffer (message, bytes + 1);
1070 
1071 	if (neg == 0)
1072 		message->data[message->data_used++] = (uint8_t) (0xB0 + decimals);
1073 	else
1074 		message->data[message->data_used++] = (uint8_t) (0xC0 + decimals);
1075 
1076 	p = message->data + message->data_used;
1077 	message->data_used += bytes;
1078 
1079 	do {
1080 		p[--bytes] = (uint8_t) (value % 128);
1081 
1082 		value /= 128UL;
1083 	} while (bytes != 0);
1084 
1085 	message->data[message->data_used - 1] |= 128;
1086 	return 1;
1087 }
1088 
1089 /* Unicode functions modified from files located here: <http://unicode.org/Public/PROGRAMS/CVTUTF/>
1090  *
1091  * Copyright 2001-2004 Unicode, Inc.
1092  *
1093  * Disclaimer
1094  *
1095  * This source code is provided as is by Unicode, Inc. No claims are
1096  * made as to fitness for any particular purpose. No warranties of any
1097  * kind are expressed or implied. The recipient agrees to determine
1098  * applicability of information provided. If this file has been
1099  * purchased on magnetic or optical media from Unicode, Inc., the
1100  * sole remedy for any claim will be exchange of defective media
1101  * within 90 days of receipt.
1102  *
1103  * Limitations on Rights to Redistribute This Code
1104  *
1105  * Unicode, Inc. hereby grants the right to freely use the information
1106  * supplied in this file in the creation of products supporting the
1107  * Unicode Standard, and to make copies of this file in any form
1108  * for internal or external distribution as long as this notice
1109  * remains attached.
1110  *
1111  * The above copyright is for the isLegalUTF8() function, the
1112  * string verification part of mdf_add_string() and the
1113  * accompanying tables.
1114 */
1115 
1116 #define UNI_SUR_HIGH_START   (uint32_t) 0xD800
1117 #define UNI_SUR_LOW_END      (uint32_t) 0xDFFF
1118 #define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD
1119 #define UNI_MAX_LEGAL_UTF32  (uint32_t) 0x0010FFFF
1120 
1121 static const uint8_t trailingBytesForUTF8[256] = {
1122     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1123     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1124     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1125     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1126     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1127     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1128     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1129     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
1130 };
1131 
1132 static const uint32_t offsetsFromUTF8[6] = {
1133 	0x00000000, 0x00003080, 0x000E2080,
1134 	0x03C82080, 0xFA082080, 0x82082080
1135 };
1136 
isLegalUTF8(const uint8_t * source,const int length)1137 static int isLegalUTF8(const uint8_t *source, const int length)
1138 {
1139     uint8_t a;
1140     const uint8_t *srcptr = source+length;
1141     switch (length) {
1142     default: return 0;
1143         /* Everything else falls through when "true"... */
1144 /*  case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; RFC3629 makes 5 & 6 bytes UTF-8 illegal
1145     case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */
1146     case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;	/* FALLTHRU */
1147     case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;	/* FALLTHRU */
1148     case 2: if ((a = (*--srcptr)) > 0xBF) return 0;	/* FALLTHRU */
1149 
1150         switch (*source) {
1151             /* no fall-through in this inner switch */
1152             case 0xE0: if (a < 0xA0) return 0; break;
1153             case 0xED: if (a > 0x9F) return 0; break;
1154             case 0xF0: if (a < 0x90) return 0; break;
1155             case 0xF4: if (a > 0x8F) return 0; break;
1156             default:   if (a < 0x80) return 0; break;
1157         }
1158 
1159     case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
1160     }
1161     if (*source > 0xF4) return 0;
1162     return 1;
1163 }
1164 
mdf_message_add_string(mdf_message_t message,const uint32_t tag,const char * value)1165 int mdf_message_add_string (mdf_message_t message, const uint32_t tag, const char * value)
1166 {
1167 	size_t len, i, oldpos;
1168 
1169 	if (message == NULL || message->current_message == -1)
1170 		return 0;
1171 
1172 	if (value == NULL)
1173 		return add_null (message, tag);
1174 
1175 	len = strlen (value);
1176 
1177 	/* remove any initial BOM */
1178 	if (len > 2 && (unsigned char)value[0] == 0xEF && (unsigned char)value[1] == 0xBB && (unsigned char)value[2] == 0xBF) {
1179 		len -= 3;
1180 		value += 3;
1181 	}
1182 
1183 	/* we don't accept silly values... */
1184 	if (len > 1048510)
1185 		return 0;
1186 
1187 	/* is the string valid UTF-8? */
1188 	for (i = 0; i < len; i++) {
1189 		uint32_t ch = 0;
1190 		uint8_t	extrabytes = trailingBytesForUTF8[(uint8_t) value[i]];
1191 
1192 		if (extrabytes + i > len)
1193 			return 0;
1194 
1195 		if (isLegalUTF8 ((const uint8_t *) (value + i), extrabytes + 1) == 0)
1196 			return 0;
1197 
1198 		switch (extrabytes) {
1199 			case 5 : ch += (uint8_t) value[i++]; ch <<= 6;	/* FALLTHRU */
1200 			case 4 : ch += (uint8_t) value[i++]; ch <<= 6;	/* FALLTHRU */
1201 			case 3 : ch += (uint8_t) value[i++]; ch <<= 6;	/* FALLTHRU */
1202 			case 2 : ch += (uint8_t) value[i++]; ch <<= 6;	/* FALLTHRU */
1203 			case 1 : ch += (uint8_t) value[i++]; ch <<= 6;	/* FALLTHRU */
1204 			case 0 : ch += (uint8_t) value[i];
1205 		}
1206 
1207 		ch -= offsetsFromUTF8[extrabytes];
1208 
1209 		if (ch <= UNI_MAX_LEGAL_UTF32) {
1210 			if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
1211 				return 0;
1212 		} else {
1213 			return 0;
1214 		}
1215 	}
1216 
1217 	/* we need this location if compression fails */
1218 	oldpos = message->data_used;
1219 
1220 	/* trying to compress too small strings is just a big waste of time!
1221 	 * news headlines might be worth it though */
1222 	if (len <= 100 && tag != MDF_F_HEADLINE) {
1223 		len++;	/* compensate for the terminating null */
1224 		grow_buffer (message, len + 1);
1225 		message->data[message->data_used++] = 241;
1226 
1227 		if (tag == MDF_F_MMT) {
1228 			int num_blanks = 0;
1229 
1230 			for (i = 0; i < len - 1; i++) {
1231 				if (value[i] == '-') {
1232 					num_blanks++;
1233 				} else {
1234 					if (num_blanks != 0) {
1235 						message->data[message->data_used++] = num_blanks + 0x60;
1236 						num_blanks = 0;
1237 					}
1238 
1239 					message->data[message->data_used++] = value[i];
1240 				}
1241 			}
1242 
1243 			message->data[message->data_used++] = '\0';
1244 		} else {
1245 			memcpy (message->data + message->data_used, value, len);
1246 			message->data_used += len;
1247 		}
1248 	} else {
1249 		int ret;
1250 		uLongf complen = compressBound (len);
1251 
1252 		grow_buffer (message, complen + 6);
1253 		message->data[message->data_used++] = 242;
1254 		message->data_used += add_serialised_integer (message->data + message->data_used, (uint64_t) len);
1255 		ret = compress2 ((Bytef *) (message->data + message->data_used), &complen, (const Bytef *) value, len, Z_BEST_SPEED);
1256 
1257 		/* compensate for the terminating null */
1258 		len++;
1259 
1260 		if (ret == Z_OK)
1261 			message->data_used += complen;
1262 
1263 		/* compression either failed or increased the size, add the string uncompressed */
1264 		if (message->data_used - oldpos - 1 >= len || ret != Z_OK) {
1265 			message->data_used = oldpos;
1266 			message->data[message->data_used++] = 241;
1267 			memcpy (message->data + message->data_used, value, len);
1268 			message->data_used += len;
1269 		}
1270 	}
1271 
1272 	/* obfuscate the password length if the length is < 50 characters */
1273 	if (tag == MDF_F_PASSWORD) {
1274 		size_t added_len = message->data_used - oldpos;
1275 
1276 		if (added_len < 50) {
1277 			added_len = 50 - added_len;
1278 
1279 			if (added_len > 6) {
1280 				added_len -= 5;
1281 				add_tag (message, tag, oldpos, message->data_used - oldpos);
1282 				add_tag (message, 0xffffffff, message->data_used, added_len);
1283 
1284 				grow_buffer (message, added_len);
1285 
1286 				message->data[message->data_used++] = 241;
1287 				added_len--;
1288 
1289 				memset (message->data + message->data_used, ' ', added_len - 1);
1290 				message->data_used += added_len;
1291 				message->data[message->data_used - 1] = '\0';
1292 				return 1;
1293 			}
1294 		}
1295 	}
1296 
1297 	add_tag (message, tag, oldpos, message->data_used - oldpos);
1298 	return 1;
1299 }
1300 
mdf_message_add_date2(mdf_message_t message,const uint32_t tag,const int year,const int mon,const int day)1301 int mdf_message_add_date2 (mdf_message_t message, const uint32_t tag, const int year, const int mon, const int day)
1302 {
1303 	if (message == NULL || message->current_message == -1)
1304 		return 0;
1305 
1306 	const int num = year * 448 + mon * 32 + day;
1307 
1308 	if (mon > 13 || mon < 0 || day > 31 || day < 0)
1309 		return 0;
1310 
1311 	if (num > 1048575)
1312 		return 0;
1313 
1314 	add_tag (message, tag, message->data_used, 3);
1315 	grow_buffer (message, 3);
1316 
1317 	message->data[message->data_used++] = (uint8_t) (0xD0 + (num >> 16));
1318 	message->data[message->data_used++] = (uint8_t) (num % 256);
1319 	message->data[message->data_used++] = (uint8_t) ((num & 0x0000FFFF) / 256);
1320 
1321 	return 1;
1322 }
1323 
mdf_message_add_date(mdf_message_t message,const uint32_t tag,const char * value)1324 int mdf_message_add_date (mdf_message_t message, const uint32_t tag, const char *value)
1325 {
1326 	int year, mon, day;
1327 	char *endp;
1328 
1329 	if (message == NULL || message->current_message == -1)
1330 		return 0;
1331 
1332 	if (value == NULL)
1333 		return add_null (message, tag);
1334 
1335 	year = strtol (value, &endp, 10);
1336 
1337 	if (year <= 0)
1338 		return 0;
1339 
1340 	if (*endp == '\0') {
1341 		if (year > 2339)
1342 			return mdf_message_add_string (message, tag, value);
1343 
1344 		return mdf_message_add_date2 (message, tag, year, 0, 0);
1345 	} else if (*endp != '-') {
1346 		return 0;
1347 	}
1348 
1349 	endp++;
1350 
1351 	switch (*endp) {
1352 		case 'H' :
1353 			day = strtol (endp + 1, NULL, 10);
1354 
1355 			if (day < 1 || day > 2)
1356 				return 0;
1357 
1358 			if (year > 2339)
1359 				return mdf_message_add_string (message, tag, value);
1360 
1361 			return mdf_message_add_date2 (message, tag, year, 0, day);
1362 
1363 		case 'T' :
1364 			day = strtol (endp + 1, NULL, 10);
1365 
1366 			if (day < 1 || day > 3)
1367 				return 0;
1368 
1369 			if (year > 2339)
1370 				return mdf_message_add_string (message, tag, value);
1371 
1372 			return mdf_message_add_date2 (message, tag, year, 0, day + 2);
1373 
1374 		case 'Q' :
1375 			day = strtol (endp + 1, NULL, 10);
1376 
1377 			if (day < 1 || day > 4)
1378 				return 0;
1379 
1380 			if (year > 2339)
1381 				return mdf_message_add_string (message, tag, value);
1382 
1383 			return mdf_message_add_date2 (message, tag, year, 0, day + 5);
1384 
1385 		case 'W' :
1386 			day = strtol (endp + 1, NULL, 10);
1387 
1388 			if (day < 1 || day > 53)
1389 				return 0;
1390 
1391 			if (year > 2339)
1392 				return mdf_message_add_string (message, tag, value);
1393 
1394 			if (day < 23)
1395 				return mdf_message_add_date2 (message, tag, year, 0, day + 9);
1396 
1397 			return mdf_message_add_date2 (message, tag, year, 13, day - 22);
1398 	}
1399 
1400 	mon = strtol (endp, &endp, 10);
1401 
1402 	if (*endp == '\0')
1403 		day = 0;
1404 	else if (*endp == '-')
1405 		day = strtol (endp + 1, NULL, 10);
1406 	else if (*endp == 'M')
1407 		return mdf_message_add_string (message, tag, value);
1408 	else
1409 		return 0;
1410 
1411 	if (year > 2339)
1412 		return mdf_message_add_string (message, tag, value);
1413 
1414 	return mdf_message_add_date2 (message, tag, year, mon, day);
1415 }
1416 
mdf_message_add_time3(mdf_message_t message,const uint32_t tag,const int hour,const int min,const int sec,int nsec)1417 int mdf_message_add_time3 (mdf_message_t message, const uint32_t tag, const int hour, const int min, const int sec, int nsec)
1418 {
1419 	uint32_t num;
1420 
1421 	if (message == NULL || message->current_message == -1)
1422 		return 0;
1423 
1424 	if (hour > 23 || hour < 0 || min > 59 || min < 0 || sec > 59 || sec < 0 || nsec < 0)
1425 		return 0;
1426 
1427 	/* scale value down to nanoseconds */
1428 	while (nsec > 999999999)
1429 		nsec /= 10;
1430 
1431 	if (nsec != 0) {
1432 		if (nsec % 1000000 == 0) { /* so timestamp was in milliseconds apparantly (mmm000000) */
1433 			add_tag (message, tag, message->data_used, 5);
1434 			grow_buffer (message, 5);
1435 			num = hour * 3600000 + min * 60000 + sec * 1000 + nsec / 1000000; /* 0 - 86399999 */
1436 
1437 			message->data[message->data_used++] = 0xF4;
1438 			*((uint32_t *) (message->data + message->data_used)) = cpu_to_le32 ((uint32_t) num);
1439 			message->data_used += 4;
1440 			return 1;
1441 		}
1442 
1443 		add_tag (message, tag, message->data_used, 7);
1444 		grow_buffer (message, 7);
1445 		const uint64_t num2 = cpu_to_be64 (hour * __UINT64_C(3600000000000) + min * __UINT64_C(60000000000) + sec * __UINT64_C(1000000000) + nsec + __UINT64_C(0x800000000000));
1446 		const uint8_t *num2_ptr = (const uint8_t *) &num2;
1447 
1448 		message->data[message->data_used++] = 0xF4;
1449 		message->data[message->data_used++] = num2_ptr[3];
1450 		message->data[message->data_used++] = num2_ptr[4];
1451 		message->data[message->data_used++] = num2_ptr[5];
1452 		message->data[message->data_used++] = num2_ptr[2];
1453 		message->data[message->data_used++] = num2_ptr[6];
1454 		message->data[message->data_used++] = num2_ptr[7];
1455 		return 1;
1456 	}
1457 	add_tag (message, tag, message->data_used, 3);
1458 	grow_buffer (message, 3);
1459 
1460 	num = hour * 3600 + min * 60 + sec;
1461 
1462 	if (num > 65535) {
1463 		message->data[message->data_used++] = 0xF7;
1464 		num -= 65535;
1465 	} else {
1466 		message->data[message->data_used++] = 0xF6;
1467 	}
1468 
1469 	*((uint16_t *) (message->data + message->data_used)) = cpu_to_le16 ((uint16_t) num);
1470 	message->data_used += 2;
1471 
1472 	return 1;
1473 }
1474 
mdf_message_add_time2(mdf_message_t message,const uint32_t tag,const int hour,const int min,const int sec,int msec)1475 int mdf_message_add_time2 (mdf_message_t message, const uint32_t tag, const int hour, const int min, const int sec, int msec)
1476 {
1477 	uint32_t num;
1478 
1479 	if (message == NULL || message->current_message == -1)
1480 		return 0;
1481 
1482 	if (hour > 23 || hour < 0 || min > 59 || min < 0 || sec > 59 || sec < 0 || msec < 0)
1483 		return 0;
1484 
1485 	while (msec > 999)
1486 		msec /= 10;
1487 
1488 	if (msec != 0) {
1489 		add_tag (message, tag, message->data_used, 5);
1490 		grow_buffer (message, 5);
1491 		num = hour * 3600000 + min * 60000 + sec * 1000 + msec; /* 0 - 86399999 */
1492 
1493 		message->data[message->data_used++] = 0xF4;
1494 		*((uint32_t *) (message->data + message->data_used)) = cpu_to_le32 ((uint32_t) num);
1495 		message->data_used += 4;
1496 		return 1;
1497 	}
1498 
1499 	add_tag (message, tag, message->data_used, 3);
1500 	grow_buffer (message, 3);
1501 
1502 	num = hour * 3600 + min * 60 + sec;
1503 
1504 	if (num > 65535) {
1505 		message->data[message->data_used++] = 0xF7;
1506 		num -= 65535;
1507 	} else {
1508 		message->data[message->data_used++] = 0xF6;
1509 	}
1510 
1511 	*((uint16_t *) (message->data + message->data_used)) = cpu_to_le16 ((uint16_t) num);
1512 	message->data_used += 2;
1513 
1514 	return 1;
1515 }
1516 
mdf_message_add_time(mdf_message_t message,const uint32_t tag,const char * value)1517 int mdf_message_add_time (mdf_message_t message, const uint32_t tag, const char *value)
1518 {
1519 	int hour, min, sec, msec;
1520 	char *endp;
1521 
1522 	if (value == NULL)
1523 		return 0;
1524 
1525 	hour = strtol (value, &endp, 10);
1526 
1527 	if (*endp != ':')
1528 		return 0;
1529 
1530 	min = strtol (endp + 1, &endp, 10);
1531 
1532 	if (*endp != ':')
1533 		return 0;
1534 
1535 	sec = strtol (endp + 1, &endp, 10);
1536 
1537 	if (*endp == '.') {
1538 		int min_digits = 3;
1539 		int num_digits = 0;
1540 		unsigned char c;
1541 		msec = 0;
1542 		++endp;
1543 
1544 		for (c = *endp; c != '\0'; c = *++endp) {
1545 			if (c < '0' || c > '9')
1546 				return 0;
1547 
1548 			c -= '0';
1549 
1550 			msec = msec * 10 + c;
1551 			num_digits++;
1552 
1553 			if (msec > 999)
1554 				break;
1555 		}
1556 
1557 		for (min_digits -= num_digits; min_digits > 0; min_digits--)
1558 			msec *= 10;
1559 
1560 		while (msec > 999)
1561 			msec /= 10;
1562 	} else {
1563 		msec = 0;
1564 	}
1565 
1566 	return mdf_message_add_time2 (message, tag, hour, min, sec, msec);
1567 }
1568 
1569