/*
** Library for packing/unpacking structures.
**
** Valid formats:
** x - pading
** b/B - signed/unsigned byte
** h/H - signed/unsigned short
** l/L - signed/unsigned long
** i/In - signed/unsigned integer with size `n‘ (default is size of int)
** cn - sequence of `n‘ chars (from/to a string); when packing, n==0 means
the whole string; when unpacking, n==0 means use the previous
read number as the string length
** s - zero-terminated string
** f - float
** d - doulbe
*/
#include <ctype.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
/* dummy structure to get alignment requirements */
struct cD {
char c;
double d;
};
static int getmaxalign (void) {
int ma = sizeof(int);
int e = sizeof(struct cD) - sizeof(double);
if (ma < e) ma = e;
return ma;
}
static int getendianess (const char **s, int *native_out) {
int endian; /* 0 = little; 1 = big */
int native = 1;
if (*(char *)&native == 1)
native = 0;
if (**s == ‘>‘) {
endian = 1;
(*s)++;
}
else if (**s == ‘<‘) {
endian = 0;
(*s)++;
}
else
endian = native;
*native_out = native;
return endian;
}
static int getnum (const char **fmt, int df) {
if (!isdigit(**fmt))
return df; /* no number */
else {
int a = 0;
do {
a = a*10 + *((*fmt)++) - ‘0‘;
} while (isdigit(**fmt));
return a;
}
}
static int optsize (char opt, const char **fmt) {
switch (opt) {
case ‘B‘: case ‘b‘: return 1;
case ‘H‘: case ‘h‘: return 2;
case ‘L‘: case ‘l‘: return 4;
case ‘f‘: return sizeof(float);
case ‘d‘: return sizeof(double);
case ‘x‘: return 1;
case ‘i‘: return getnum(fmt, sizeof(int));
case ‘c‘: return getnum(fmt, 1);
case ‘s‘: return 0;
default: return 1; /* invalid code */
}
}
static int getalign (const char **fmt) {
if (**fmt != ‘!‘) return 1; /* no alignment */
else {
(*fmt)++;
return getnum(fmt, getmaxalign());
}
}
static int gettoalign (lua_State *L, int align, int opt, int size) {
int toalign = (opt == ‘c‘ || opt == ‘s‘) ? 1 : size;
if (toalign > align) toalign = align;
if (toalign == 0 || (toalign & (toalign - 1)) != 0)
luaL_error(L, "alignment must be power of 2");
return toalign;
}
static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
int size) {
unsigned char buff[sizeof(long)];
lua_Number n = luaL_checknumber(L, arg);
unsigned long value;
unsigned char *s;
int inc, i;
if (n < 0) {
value = (unsigned long)(-n);
value = (~value) + 1; /* 2‘s complement */
}
else
value = (unsigned long)n;
if (endian == 0) {
inc = 1;
s = buff;
}
else {
inc = -1;
s = buff+(size-1);
}
for (i=0; i<size; i++) {
*s = (unsigned char)(value & 0xff);
s += inc;
value >>= 8;
}
luaL_addlstring(b, (char *)buff, size);
}
static void invertbytes (char *b, int size) {
int i = 0;
while (i < --size) {
char temp = b[i];
b[i++] = b[size];
b[size] = temp;
}
}