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