unpack.c (2424B)
1 /* 2 * ISC License 3 * 4 * (c) 2019 Roberto E. Vargas Caballero <k0ga@shike2.com> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <ctype.h> 20 #include <stdarg.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 24 static int 25 lunpack(unsigned char *src, char *fmt, va_list va) 26 { 27 unsigned char *bp, *cp; 28 unsigned short *sp; 29 unsigned s; 30 unsigned long *lp, l; 31 unsigned long long *qp, q; 32 int n; 33 34 bp = src; 35 while (*fmt) { 36 switch (*fmt++) { 37 case '\'': 38 n = atoi(fmt); 39 while (isdigit(*fmt)) 40 fmt++; 41 cp = va_arg(va, unsigned char *); 42 while (n--) 43 *cp++ = *bp++; 44 break; 45 case 'c': 46 cp = va_arg(va, unsigned char *); 47 *cp = *bp++; 48 break; 49 case 's': 50 sp = va_arg(va, unsigned short *); 51 s = (unsigned) *bp++; 52 s |= (unsigned) *bp++ << 8; 53 *sp = s; 54 break; 55 case 'l': 56 lp = va_arg(va, unsigned long *); 57 l = (unsigned long) *bp++; 58 l |= (unsigned long) *bp++ << 8; 59 l |= (unsigned long) *bp++ << 16; 60 l |= (unsigned long) *bp++ << 24; 61 *lp = l; 62 break; 63 case 'q': 64 qp = va_arg(va, unsigned long long *); 65 q = (unsigned long long) *bp++; 66 q |= (unsigned long long) *bp++ << 8; 67 q |= (unsigned long long) *bp++ << 16; 68 q |= (unsigned long long) *bp++ << 24; 69 q |= (unsigned long long) *bp++ << 32; 70 q |= (unsigned long long) *bp++ << 40; 71 q |= (unsigned long long) *bp++ << 48; 72 q |= (unsigned long long) *bp++ << 56; 73 *qp = q; 74 break; 75 default: 76 va_end(va); 77 return -1; 78 } 79 } 80 81 return bp - src; 82 } 83 84 int 85 unpack(unsigned char *src, char *fmt, ...) 86 { 87 int r; 88 int (*fn)(unsigned char *dst, char *fmt, va_list va); 89 va_list va; 90 91 va_start(va, fmt); 92 fn = lunpack; 93 r = (*fn)(src, fmt, va); 94 va_end(va); 95 96 return r; 97 }