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 (¤t_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