1 /* Pack objects as a binary string */
2 /* Copyright (c) 1998, 1999, 2001, 2002 John E. Davis
3 * This file is part of the S-Lang library.
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Perl Artistic License.
7 */
8 #include "slinclud.h"
9
10 #include <ctype.h>
11
12 #include "slang.h"
13 #include "_slang.h"
14
15 #ifndef isdigit
16 # define isdigit(c) (((c)>='0')&&((c)<= '9'))
17 #endif
18 #ifndef isspace
19 # define isspace(c) (((c)==' ') || ((c)=='\t') || ((c)=='\n'))
20 #endif
21
22 /* format description:
23 *
24 * s = string (null padded)
25 * S = string (space padded)
26 * c = signed char
27 * C = unsigned char
28 * h = short
29 * H = unsigned short
30 * i = int
31 * I = unsigned int
32 * l = long
33 * L = unsigned long
34 * j = 16 bit signed integer (short)
35 * J = 16 bit unsigned integer (short)
36 * k = 32 bit signed integer (long)
37 * K = 32 bit unsigned integer (long)
38 * f = float (native format)
39 * F = 32 bit double
40 * d = double (native format)
41 * D = 64 bit double
42 * x = null pad byte
43 * > = big-endian mode
44 * < = little-endian mode
45 * = = native mode
46 */
47
48 #define NATIVE_ORDER 0
49 #define BIGENDIAN_ORDER 1
50 #define LILENDIAN_ORDER 2
51 static int Native_Byte_Order = NATIVE_ORDER;
52
53 typedef struct
54 {
55 char format_type;
56 unsigned char data_type;
57 unsigned int repeat;
58 unsigned int sizeof_type;
59 char pad;
60 int byteorder;
61 int is_scalar;
62 }
63 Format_Type;
64
get_int_type_for_size(unsigned int size,unsigned char * s,unsigned char * u)65 static int get_int_type_for_size (unsigned int size, unsigned char *s, unsigned char *u)
66 {
67 if (sizeof (int) == size)
68 {
69 if (s != NULL) *s = SLANG_INT_TYPE;
70 if (u != NULL) *u = SLANG_UINT_TYPE;
71 return 0;
72 }
73
74 if (sizeof (short) == size)
75 {
76 if (s != NULL) *s = SLANG_SHORT_TYPE;
77 if (u != NULL) *u = SLANG_USHORT_TYPE;
78 return 1;
79 }
80
81 if (sizeof (long) == size)
82 {
83 if (s != NULL) *s = SLANG_LONG_TYPE;
84 if (u != NULL) *u = SLANG_ULONG_TYPE;
85 return 1;
86 }
87
88 if (s != NULL) *s = 0;
89 if (u != NULL) *u = 0;
90 SLang_verror (SL_NOT_IMPLEMENTED,
91 "This OS does not support a %u byte int", size);
92 return -1;
93 }
94
get_float_type_for_size(unsigned int size,unsigned char * s)95 static int get_float_type_for_size (unsigned int size, unsigned char *s)
96 {
97 if (sizeof (float) == size)
98 {
99 *s = SLANG_FLOAT_TYPE;
100 return 0;
101 }
102
103 if (sizeof (double) == size)
104 {
105 *s = SLANG_DOUBLE_TYPE;
106 return 0;
107 }
108
109 SLang_verror (SL_NOT_IMPLEMENTED,
110 "This OS does not support a %u byte float", size);
111 return -1;
112 }
113
parse_a_format(char ** format,Format_Type * ft)114 static int parse_a_format (char **format, Format_Type *ft)
115 {
116 char *f;
117 char ch;
118 unsigned repeat;
119
120 f = *format;
121
122 while (((ch = *f++) != 0)
123 && isspace (ch))
124 ;
125
126 switch (ch)
127 {
128 default:
129 ft->byteorder = NATIVE_ORDER;
130 break;
131
132 case '=':
133 ft->byteorder = NATIVE_ORDER;
134 ch = *f++;
135 break;
136
137 case '>':
138 ft->byteorder = BIGENDIAN_ORDER;
139 ch = *f++;
140 break;
141
142 case '<':
143 ft->byteorder = LILENDIAN_ORDER;
144 ch = *f++;
145 break;
146 }
147
148 if (ch == 0)
149 {
150 f--;
151 *format = f;
152 return 0;
153 }
154
155 ft->format_type = ch;
156 ft->repeat = 1;
157
158 if (isdigit (*f))
159 {
160 repeat = (unsigned int) (*f - '0');
161 f++;
162
163 while (isdigit (*f))
164 {
165 unsigned int repeat10 = 10 * repeat + (unsigned int)(*f - '0');
166
167 /* Check overflow */
168 if (repeat != repeat10 / 10)
169 {
170 SLang_verror (SL_OVERFLOW,
171 "Repeat count too large in [un]pack format");
172 return -1;
173 }
174 repeat = repeat10;
175 f++;
176 }
177 ft->repeat = repeat;
178 }
179
180 *format = f;
181
182 ft->is_scalar = 1;
183 ft->pad = 0;
184
185 switch (ft->format_type)
186 {
187 default:
188 SLang_verror (SL_NOT_IMPLEMENTED,
189 "[un]pack format character '%c' not supported", ft->format_type);
190 return -1;
191
192 case 'D':
193 ft->sizeof_type = 8;
194 if (-1 == get_float_type_for_size (8, &ft->data_type))
195 return -1;
196 break;
197
198 case 'd':
199 ft->data_type = SLANG_DOUBLE_TYPE;
200 ft->sizeof_type = sizeof (double);
201 break;
202
203 case 'F':
204 ft->sizeof_type = 4;
205 if (-1 == get_float_type_for_size (4, &ft->data_type))
206 return -1;
207 break;
208 case 'f':
209 ft->data_type = SLANG_FLOAT_TYPE;
210 ft->sizeof_type = sizeof (float);
211 break;
212
213 case 'h':
214 ft->data_type = SLANG_SHORT_TYPE;
215 ft->sizeof_type = sizeof (short);
216 break;
217 case 'H':
218 ft->data_type = SLANG_USHORT_TYPE;
219 ft->sizeof_type = sizeof (unsigned short);
220 break;
221 case 'i':
222 ft->data_type = SLANG_INT_TYPE;
223 ft->sizeof_type = sizeof (int);
224 break;
225 case 'I':
226 ft->data_type = SLANG_UINT_TYPE;
227 ft->sizeof_type = sizeof (unsigned int);
228 break;
229 case 'l':
230 ft->data_type = SLANG_LONG_TYPE;
231 ft->sizeof_type = sizeof (long);
232 break;
233 case 'L':
234 ft->data_type = SLANG_ULONG_TYPE;
235 ft->sizeof_type = sizeof (unsigned long);
236 break;
237
238 /* 16 bit ints */
239 case 'j':
240 ft->sizeof_type = 2;
241 if (-1 == get_int_type_for_size (2, &ft->data_type, NULL))
242 return -1;
243 break;
244 case 'J':
245 ft->sizeof_type = 2;
246 if (-1 == get_int_type_for_size (2, NULL, &ft->data_type))
247 return -1;
248 break;
249
250 /* 32 bit ints */
251 case 'k':
252 ft->sizeof_type = 4;
253 if (-1 == get_int_type_for_size (4, &ft->data_type, NULL))
254 return -1;
255 break;
256 case 'K':
257 ft->sizeof_type = 4;
258 if (-1 == get_int_type_for_size (4, NULL, &ft->data_type))
259 return -1;
260 break;
261
262 case 'x':
263 ft->sizeof_type = 1;
264 ft->data_type = 0;
265 break;
266
267 case 'c':
268 ft->sizeof_type = 1;
269 ft->data_type = SLANG_CHAR_TYPE;
270 break;
271
272 case 'C':
273 ft->data_type = SLANG_UCHAR_TYPE;
274 ft->sizeof_type = 1;
275 break;
276
277 case 'S':
278 case 'A':
279 ft->pad = ' ';
280 case 'a':
281 case 's':
282 ft->data_type = SLANG_BSTRING_TYPE;
283 ft->sizeof_type = 1;
284 ft->is_scalar = 0;
285 break;
286 }
287 return 1;
288 }
289
compute_size_for_format(char * format,unsigned int * num_bytes)290 static int compute_size_for_format (char *format, unsigned int *num_bytes)
291 {
292 unsigned int size;
293 Format_Type ft;
294 int status;
295
296 *num_bytes = size = 0;
297
298 while (1 == (status = parse_a_format (&format, &ft)))
299 size += ft.repeat * ft.sizeof_type;
300
301 *num_bytes = size;
302 return status;
303 }
304
byte_swap64(unsigned char * ss,unsigned int n)305 static void byte_swap64 (unsigned char *ss, unsigned int n) /*{{{*/
306 {
307 unsigned char *p, *pmax, ch;
308
309 if (n == 0) return;
310 p = (unsigned char *) ss;
311 pmax = p + 8 * n;
312 while (p < pmax)
313 {
314 ch = *p;
315 *p = *(p + 7);
316 *(p + 7) = ch;
317
318 ch = *(p + 6);
319 *(p + 6) = *(p + 1);
320 *(p + 1) = ch;
321
322 ch = *(p + 5);
323 *(p + 5) = *(p + 2);
324 *(p + 2) = ch;
325
326 ch = *(p + 4);
327 *(p + 4) = *(p + 3);
328 *(p + 3) = ch;
329
330 p += 8;
331 }
332 }
333
334 /*}}}*/
byte_swap32(unsigned char * ss,unsigned int n)335 static void byte_swap32 (unsigned char *ss, unsigned int n) /*{{{*/
336 {
337 unsigned char *p, *pmax, ch;
338
339 p = (unsigned char *) ss;
340 pmax = p + 4 * n;
341 while (p < pmax)
342 {
343 ch = *p;
344 *p = *(p + 3);
345 *(p + 3) = ch;
346
347 ch = *(p + 1);
348 *(p + 1) = *(p + 2);
349 *(p + 2) = ch;
350 p += 4;
351 }
352 }
353
354 /*}}}*/
byte_swap16(unsigned char * p,unsigned int nread)355 static void byte_swap16 (unsigned char *p, unsigned int nread) /*{{{*/
356 {
357 unsigned char *pmax, ch;
358
359 pmax = p + 2 * nread;
360 while (p < pmax)
361 {
362 ch = *p;
363 *p = *(p + 1);
364 *(p + 1) = ch;
365 p += 2;
366 }
367 }
368
369 /*}}}*/
370
byteswap(int order,unsigned char * b,unsigned int size,unsigned int num)371 static int byteswap (int order, unsigned char *b, unsigned int size, unsigned int num)
372 {
373 if (Native_Byte_Order == order)
374 return 0;
375
376 switch (size)
377 {
378 case 2:
379 byte_swap16 (b, num);
380 break;
381 case 4:
382 byte_swap32 (b, num);
383 break;
384 case 8:
385 byte_swap64 (b, num);
386 break;
387 default:
388 return -1;
389 }
390
391 return 0;
392 }
393
check_native_byte_order(void)394 static void check_native_byte_order (void)
395 {
396 unsigned short x;
397
398 if (Native_Byte_Order != NATIVE_ORDER)
399 return;
400
401 x = 0xFF;
402 if (*(unsigned char *)&x == 0xFF)
403 Native_Byte_Order = LILENDIAN_ORDER;
404 else
405 Native_Byte_Order = BIGENDIAN_ORDER;
406 }
407
408 static SLang_BString_Type *
pack_according_to_format(char * format,unsigned int nitems)409 pack_according_to_format (char *format, unsigned int nitems)
410 {
411 unsigned int size, num;
412 unsigned char *buf, *b;
413 SLang_BString_Type *bs;
414 Format_Type ft;
415
416 buf = NULL;
417
418 if (-1 == compute_size_for_format (format, &size))
419 goto return_error;
420
421 if (NULL == (buf = (unsigned char *) SLmalloc (size + 1)))
422 goto return_error;
423
424 b = buf;
425
426 while (1 == parse_a_format (&format, &ft))
427 {
428 unsigned char *ptr;
429 unsigned int repeat;
430
431 repeat = ft.repeat;
432 if (ft.data_type == 0)
433 {
434 memset ((char *) b, ft.pad, repeat);
435 b += repeat;
436 continue;
437 }
438
439 if (ft.is_scalar)
440 {
441 unsigned char *bstart;
442 num = repeat;
443
444 bstart = b;
445 while (repeat != 0)
446 {
447 unsigned int nelements;
448 SLang_Array_Type *at;
449
450 if (nitems == 0)
451 {
452 SLang_verror (SL_INVALID_PARM,
453 "Not enough items for pack format");
454 goto return_error;
455 }
456
457 if (-1 == SLang_pop_array_of_type (&at, ft.data_type))
458 goto return_error;
459
460 nelements = at->num_elements;
461 if (repeat < nelements)
462 nelements = repeat;
463 repeat -= nelements;
464
465 nelements = nelements * ft.sizeof_type;
466 memcpy ((char *)b, (char *)at->data, nelements);
467
468 b += nelements;
469 SLang_free_array (at);
470 nitems--;
471 }
472
473 if (ft.byteorder != NATIVE_ORDER)
474 byteswap (ft.byteorder, bstart, ft.sizeof_type, num);
475
476 continue;
477 }
478
479 /* Otherwise we have a string */
480 if (-1 == SLang_pop_bstring (&bs))
481 goto return_error;
482
483 ptr = SLbstring_get_pointer (bs, &num);
484 if (repeat < num) num = repeat;
485 memcpy ((char *)b, (char *)ptr, num);
486 b += num;
487 repeat -= num;
488 memset ((char *)b, ft.pad, repeat);
489 SLbstring_free (bs);
490 b += repeat;
491 nitems--;
492 }
493
494 *b = 0;
495 bs = SLbstring_create_malloced (buf, size, 0);
496 if (bs == NULL)
497 goto return_error;
498
499 SLdo_pop_n (nitems);
500 return bs;
501
502 return_error:
503 SLdo_pop_n (nitems);
504 if (buf != NULL)
505 SLfree ((char *) buf);
506
507 return NULL;
508 }
509
_SLpack(void)510 void _SLpack (void)
511 {
512 SLang_BString_Type *bs;
513 char *fmt;
514 int nitems;
515
516 check_native_byte_order ();
517
518 nitems = SLang_Num_Function_Args;
519 if (nitems <= 0)
520 {
521 SLang_verror (SL_SYNTAX_ERROR,
522 "pack: not enough arguments");
523 return;
524 }
525
526 if ((-1 == SLreverse_stack (nitems))
527 || (-1 == SLang_pop_slstring (&fmt)))
528 bs = NULL;
529 else
530 {
531 bs = pack_according_to_format (fmt, (unsigned int)nitems - 1);
532 SLang_free_slstring (fmt);
533 }
534
535 SLang_push_bstring (bs);
536 SLbstring_free (bs);
537 }
538
_SLunpack(char * format,SLang_BString_Type * bs)539 void _SLunpack (char *format, SLang_BString_Type *bs)
540 {
541 Format_Type ft;
542 unsigned char *b;
543 unsigned int len;
544 unsigned int num_bytes;
545
546 check_native_byte_order ();
547
548 if (-1 == compute_size_for_format (format, &num_bytes))
549 return;
550
551 b = SLbstring_get_pointer (bs, &len);
552 if (b == NULL)
553 return;
554
555 if (len < num_bytes)
556 {
557 SLang_verror (SL_INVALID_PARM,
558 "unpack format %s is too large for input string",
559 format);
560 return;
561 }
562
563 while (1 == parse_a_format (&format, &ft))
564 {
565 char *str, *s;
566
567 if (ft.repeat == 0)
568 continue;
569
570 if (ft.data_type == 0)
571 { /* skip padding */
572 b += ft.repeat;
573 continue;
574 }
575
576 if (ft.is_scalar)
577 {
578 SLang_Array_Type *at;
579 int dims;
580
581 if (ft.repeat == 1)
582 {
583 SLang_Class_Type *cl;
584
585 cl = _SLclass_get_class (ft.data_type);
586 memcpy ((char *)cl->cl_transfer_buf, (char *)b, ft.sizeof_type);
587 if (ft.byteorder != NATIVE_ORDER)
588 byteswap (ft.byteorder, (unsigned char *)cl->cl_transfer_buf, ft.sizeof_type, 1);
589
590 if (-1 == (cl->cl_apush (ft.data_type, cl->cl_transfer_buf)))
591 return;
592 b += ft.sizeof_type;
593 continue;
594 }
595
596 dims = (int) ft.repeat;
597 at = SLang_create_array (ft.data_type, 0, NULL, &dims, 1);
598 if (at == NULL)
599 return;
600
601 num_bytes = ft.repeat * ft.sizeof_type;
602 memcpy ((char *)at->data, (char *)b, num_bytes);
603 if (ft.byteorder != NATIVE_ORDER)
604 byteswap (ft.byteorder, (unsigned char *)at->data, ft.sizeof_type, ft.repeat);
605
606 if (-1 == SLang_push_array (at, 1))
607 return;
608
609 b += num_bytes;
610 continue;
611 }
612
613 len = ft.repeat;
614 str = SLmalloc (len + 1);
615 if (str == NULL)
616 return;
617
618 memcpy ((char *) str, (char *)b, len);
619 str [len] = 0;
620
621 if (ft.pad == ' ')
622 {
623 unsigned int new_len;
624
625 s = str + len;
626 while (s > str)
627 {
628 s--;
629 if ((*s != ' ') && (*s != 0))
630 {
631 s++;
632 break;
633 }
634 *s = 0;
635 }
636 new_len = (unsigned int) (s - str);
637
638 if (new_len != len)
639 {
640 s = SLrealloc (str, new_len + 1);
641 if (s == NULL)
642 {
643 SLfree (str);
644 return;
645 }
646 str = s;
647 len = new_len;
648 }
649 }
650
651 /* Avoid a bstring if possible */
652 s = SLmemchr (str, 0, len);
653 if (s == NULL)
654 {
655 if (-1 == SLang_push_malloced_string (str))
656 return;
657 }
658 else
659 {
660 SLang_BString_Type *new_bs;
661
662 new_bs = SLbstring_create_malloced ((unsigned char *)str, len, 1);
663 if (new_bs == NULL)
664 return;
665
666 if (-1 == SLang_push_bstring (new_bs))
667 {
668 SLfree (str);
669 return;
670 }
671 SLbstring_free (new_bs);
672 }
673
674 b += ft.repeat;
675 }
676 }
677
_SLpack_compute_size(char * format)678 unsigned int _SLpack_compute_size (char *format)
679 {
680 unsigned int n;
681
682 n = 0;
683 (void) compute_size_for_format (format, &n);
684 return n;
685 }
686
_SLpack_pad_format(char * format)687 void _SLpack_pad_format (char *format)
688 {
689 unsigned int len, max_len;
690 Format_Type ft;
691 char *buf, *b;
692
693 check_native_byte_order ();
694
695 /* Just check the syntax */
696 if (-1 == compute_size_for_format (format, &max_len))
697 return;
698
699 /* This should be sufficient to handle any needed xyy padding characters.
700 * I cannot see how this will be overrun
701 */
702 max_len = 4 * (strlen (format) + 1);
703 if (NULL == (buf = SLmalloc (max_len + 1)))
704 return;
705
706 b = buf;
707 len = 0;
708 while (1 == parse_a_format (&format, &ft))
709 {
710 struct { char a; short b; } s_h;
711 struct { char a; int b; } s_i;
712 struct { char a; long b; } s_l;
713 struct { char a; float b; } s_f;
714 struct { char a; double b; } s_d;
715 unsigned int pad;
716
717 if (ft.repeat == 0)
718 continue;
719
720 if (ft.data_type == 0)
721 { /* pad */
722 sprintf (b, "x%u", ft.repeat);
723 b += strlen (b);
724 len += ft.repeat;
725 continue;
726 }
727
728 switch (ft.data_type)
729 {
730 default:
731 case SLANG_STRING_TYPE:
732 case SLANG_BSTRING_TYPE:
733 case SLANG_CHAR_TYPE:
734 case SLANG_UCHAR_TYPE:
735 pad = 0;
736 break;
737
738 case SLANG_SHORT_TYPE:
739 case SLANG_USHORT_TYPE:
740 pad = ((unsigned int) ((char *)&s_h.b - (char *)&s_h.a));
741 break;
742
743 case SLANG_INT_TYPE:
744 case SLANG_UINT_TYPE:
745 pad = ((unsigned int) ((char *)&s_i.b - (char *)&s_i.a));
746 break;
747
748 case SLANG_LONG_TYPE:
749 case SLANG_ULONG_TYPE:
750 pad = ((unsigned int) ((char *)&s_l.b - (char *)&s_l.a));
751 break;
752
753 case SLANG_FLOAT_TYPE:
754 pad = ((unsigned int) ((char *)&s_f.b - (char *)&s_f.a));
755 break;
756
757 case SLANG_DOUBLE_TYPE:
758 pad = ((unsigned int) ((char *)&s_d.b - (char *)&s_d.a));
759 break;
760 }
761
762 /* Pad to a length that is an integer multiple of pad. */
763 if (pad)
764 pad = pad * ((len + pad - 1)/pad) - len;
765
766 if (pad)
767 {
768 sprintf (b, "x%u", pad);
769 b += strlen (b);
770 len += pad;
771 }
772
773 *b++ = ft.format_type;
774 if (ft.repeat > 1)
775 {
776 sprintf (b, "%u", ft.repeat);
777 b += strlen (b);
778 }
779
780 len += ft.repeat * ft.sizeof_type;
781 }
782 *b = 0;
783
784 (void) SLang_push_malloced_string (buf);
785 }
786