Browse Source

[Feature] Backport pack/unpack routines from Lua 5.3

tags/1.4.0
Vsevolod Stakhov 7 years ago
parent
commit
a8780ddc7c
1 changed files with 789 additions and 1 deletions
  1. 789
    1
      src/lua/lua_util.c

+ 789
- 1
src/lua/lua_util.c View File

@@ -324,7 +324,7 @@ LUA_FUNCTION_DEF (util, create_file);
*/
LUA_FUNCTION_DEF (util, close_file);

/**
/***
* @function util.random_hex(size)
* Returns random hex string of the specified size
*
@@ -333,6 +333,79 @@ LUA_FUNCTION_DEF (util, close_file);
*/
LUA_FUNCTION_DEF (util, random_hex);

/***
* @function util.pack(fmt, ...)
*
* Backport of Lua 5.3 `string.pack` function:
* Returns a binary string containing the values v1, v2, etc. packed (that is,
* serialized in binary form) according to the format string `fmt`
* A format string is a sequence of conversion options. The conversion
* options are as follows:
* * <: sets little endian
* * >: sets big endian
* * =: sets native endian
* * ![n]: sets maximum alignment to n (default is native alignment)
* * b: a signed byte (char)
* * B: an unsigned byte (char)
* * h: a signed short (native size)
* * H: an unsigned short (native size)
* * l: a signed long (native size)
* * L: an unsigned long (native size)
* * j: a lua_Integer
* * J: a lua_Unsigned
* * T: a size_t (native size)
* * i[n]: a signed int with n bytes (default is native size)
* * I[n]: an unsigned int with n bytes (default is native size)
* * f: a float (native size)
* * d: a double (native size)
* * n: a lua_Number
* * cn: a fixed-sized string with n bytes
* * z: a zero-terminated string
* * s[n]: a string preceded by its length coded as an unsigned integer with
* * n bytes (default is a size_t)
* * x: one byte of padding
* * Xop: an empty item that aligns according to option op (which is otherwise ignored)
* * ' ': (empty space) ignored
*
* (A "[n]" means an optional integral numeral.) Except for padding, spaces,
* and configurations (options "xX <=>!"), each option corresponds to an
* argument (in string.pack) or a result (in string.unpack).
*
* For options "!n", "sn", "in", and "In", n can be any integer between 1 and
* All integral options check overflows; string.pack checks whether the given
* value fits in the given size; string.unpack checks whether the read value
* fits in a Lua integer.
*
* Any format string starts as if prefixed by "!1=", that is, with maximum
* alignment of 1 (no alignment) and native endianness.
*
* Alignment works as follows: For each option, the format gets extra padding
* until the data starts at an offset that is a multiple of the minimum
* between the option size and the maximum alignment; this minimum must be a
* power of 2. Options "c" and "z" are not aligned; option "s" follows the
* alignment of its starting integer.
*
* All padding is filled with zeros by string.pack (and ignored by unpack).
*/
LUA_FUNCTION_DEF (util, pack);

/***
* @function util.packsize(fmt)
*
* Returns size of the packed binary string returned for the same `fmt` argument
* by @see util.pack
*/
LUA_FUNCTION_DEF (util, packsize);

/***
* @function util.unpack(fmt, s [, pos])
* Unpacks string `s` according to the format string `fmt` as described in
* @see util.pack
*
* @returns {multiple} list of unpacked values according to `fmt`
*/
LUA_FUNCTION_DEF (util, unpack);

static const struct luaL_reg utillib_f[] = {
LUA_INTERFACE_DEF (util, create_event_base),
LUA_INTERFACE_DEF (util, load_rspamd_config),
@@ -368,6 +441,9 @@ static const struct luaL_reg utillib_f[] = {
LUA_INTERFACE_DEF (util, create_file),
LUA_INTERFACE_DEF (util, close_file),
LUA_INTERFACE_DEF (util, random_hex),
LUA_INTERFACE_DEF (util, pack),
LUA_INTERFACE_DEF (util, unpack),
LUA_INTERFACE_DEF (util, packsize),
{NULL, NULL}
};

@@ -1500,6 +1576,718 @@ lua_util_random_hex (lua_State *L)
return 1;
}

/* Backport from Lua 5.3 */

/******************************************************************************
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/

/*
** {======================================================
** PACK/UNPACK
** =======================================================
*/


/* value used for padding */
#if !defined(LUA_PACKPADBYTE)
#define LUA_PACKPADBYTE 0x00
#endif

/* maximum size for the binary representation of an integer */
#define MAXINTSIZE 16

/* number of bits in a character */
#define NB CHAR_BIT

/* mask for one character (NB 1's) */
#define MC ((1 << NB) - 1)

/* size of a lua_Integer */
#define SZINT ((int)sizeof(lua_Integer))

#define MAX_SIZET ((size_t)(~(size_t)0))

#define MAXSIZE \
(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))


/* dummy union to get native endianness */
static const union {
int dummy;
char little; /* true if machine is little endian */
} nativeendian = {1};


/* dummy structure to get native alignment requirements */
struct cD {
char c;
union {
double d;
void *p;
lua_Integer i;
lua_Number n;
} u;
};

#define MAXALIGN (offsetof(struct cD, u))

/*
** Union for serializing floats
*/
typedef union Ftypes {
float f;
double d;
lua_Number n;
char buff[5 * sizeof (lua_Number)]; /* enough for any float type */
} Ftypes;


/*
** information to pack/unpack stuff
*/
typedef struct Header {
lua_State *L;
int islittle;
int maxalign;
} Header;

/*
** options for pack/unpack
*/
typedef enum KOption {
Kint, /* signed integers */
Kuint, /* unsigned integers */
Kfloat, /* floating-point numbers */
Kchar, /* fixed-length strings */
Kstring, /* strings with prefixed length */
Kzstr, /* zero-terminated strings */
Kpadding, /* padding */
Kpaddalign, /* padding for alignment */
Knop /* no-op (configuration or spaces) */
} KOption;

#if LUA_VERSION_NUM < 503
#define lua_Unsigned size_t

typedef struct luaL_Buffer_53 {
luaL_Buffer b; /* make incorrect code crash! */
char *ptr;
size_t nelems;
size_t capacity;
lua_State *L2;
} luaL_Buffer_53;

#define luaL_Buffer luaL_Buffer_53
#define COMPAT53_PREFIX lua
#undef COMPAT53_API
#if defined(__GNUC__) || defined(__clang__)
# define COMPAT53_API __attribute__((__unused__)) static
#else
# define COMPAT53_API static
#endif

#define COMPAT53_CONCAT_HELPER(a, b) a##b
#define COMPAT53_CONCAT(a, b) COMPAT53_CONCAT_HELPER(a, b)

#define luaL_buffinit COMPAT53_CONCAT(COMPAT53_PREFIX, _buffinit_53)
COMPAT53_API void luaL_buffinit (lua_State *L, luaL_Buffer_53 *B);
#define luaL_prepbuffsize COMPAT53_CONCAT(COMPAT53_PREFIX, _prepbufsize_53)
COMPAT53_API char *luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s);
#define luaL_addlstring COMPAT53_CONCAT(COMPAT53_PREFIX, _addlstring_53)
COMPAT53_API void luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l);
#define luaL_addvalue COMPAT53_CONCAT(COMPAT53_PREFIX, _addvalue_53)
COMPAT53_API void luaL_addvalue (luaL_Buffer_53 *B);
#define luaL_pushresult COMPAT53_CONCAT(COMPAT53_PREFIX, _pushresult_53)
COMPAT53_API void luaL_pushresult (luaL_Buffer_53 *B);
#undef luaL_buffinitsize
#define luaL_buffinitsize(L, B, s) \
(luaL_buffinit(L, B), luaL_prepbuffsize(B, s))

#undef luaL_prepbuffer
#define luaL_prepbuffer(B) \
luaL_prepbuffsize(B, LUAL_BUFFERSIZE)

#undef luaL_addchar
#define luaL_addchar(B, c) \
((void)((B)->nelems < (B)->capacity || luaL_prepbuffsize(B, 1)), \
((B)->ptr[(B)->nelems++] = (c)))

#undef luaL_addsize
#define luaL_addsize(B, s) \
((B)->nelems += (s))

#undef luaL_addstring
#define luaL_addstring(B, s) \
luaL_addlstring(B, s, strlen(s))

#undef luaL_pushresultsize
#define luaL_pushresultsize(B, s) \
(luaL_addsize(B, s), luaL_pushresult(B))

COMPAT53_API void
luaL_buffinit (lua_State *L, luaL_Buffer_53 *B)
{
/* make it crash if used via pointer to a 5.1-style luaL_Buffer */
B->b.p = NULL;
B->b.L = NULL;
B->b.lvl = 0;
/* reuse the buffer from the 5.1-style luaL_Buffer though! */
B->ptr = B->b.buffer;
B->capacity = LUAL_BUFFERSIZE;
B->nelems = 0;
B->L2 = L;
}


COMPAT53_API char *
luaL_prepbuffsize (luaL_Buffer_53 *B, size_t s)
{
if (B->capacity - B->nelems < s) { /* needs to grow */
char *newptr = NULL;
size_t newcap = B->capacity * 2;
if (newcap - B->nelems < s)
newcap = B->nelems + s;
if (newcap < B->capacity) /* overflow */
luaL_error (B->L2, "buffer too large");
newptr = (char *) lua_newuserdata (B->L2, newcap);
memcpy(newptr, B->ptr, B->nelems);
if (B->ptr != B->b.buffer)
lua_replace (B->L2, -2); /* remove old buffer */
B->ptr = newptr;
B->capacity = newcap;
}
return B->ptr + B->nelems;
}


COMPAT53_API void
luaL_addlstring (luaL_Buffer_53 *B, const char *s, size_t l)
{
memcpy(luaL_prepbuffsize (B, l), s, l);
luaL_addsize(B, l);
}


COMPAT53_API void
luaL_addvalue (luaL_Buffer_53 *B)
{
size_t len = 0;
const char *s = lua_tolstring (B->L2, -1, &len);
if (!s)
luaL_error (B->L2, "cannot convert value to string");
if (B->ptr != B->b.buffer)
lua_insert (B->L2, -2); /* userdata buffer must be at stack top */
luaL_addlstring (B, s, len);
lua_remove (B->L2, B->ptr != B->b.buffer ? -2 : -1);
}


COMPAT53_API void
luaL_pushresult (luaL_Buffer_53 *B)
{
lua_pushlstring (B->L2, B->ptr, B->nelems);
if (B->ptr != B->b.buffer)
lua_replace (B->L2, -2); /* remove userdata buffer */
}

#endif

/*
** Read an integer numeral from string 'fmt' or return 'df' if
** there is no numeral
*/
static int
digit (int c)
{
return '0' <= c && c <= '9';
}

static int
getnum (const char **fmt, int df)
{
if (!digit (**fmt)) /* no number? */
return df; /* return default value */
else {
int a = 0;
do {
a = a * 10 + (*((*fmt)++) - '0');
} while (digit (**fmt) && a <= ((int) MAXSIZE - 9) / 10);
return a;
}
}


/*
** Read an integer numeral and raises an error if it is larger
** than the maximum size for integers.
*/
static int
getnumlimit (Header *h, const char **fmt, int df)
{
int sz = getnum (fmt, df);
if (sz > MAXINTSIZE || sz <= 0)
luaL_error (h->L, "integral size (%d) out of limits [1,%d]",
sz, MAXINTSIZE);
return sz;
}


/*
** Initialize Header
*/
static void
initheader (lua_State *L, Header *h)
{
h->L = L;
h->islittle = nativeendian.little;
h->maxalign = 1;
}


/*
** Read and classify next option. 'size' is filled with option's size.
*/
static KOption
getoption (Header *h, const char **fmt, int *size)
{
int opt = *((*fmt)++);
*size = 0; /* default */
switch (opt) {
case 'b':
*size = sizeof (char);
return Kint;
case 'B':
*size = sizeof (char);
return Kuint;
case 'h':
*size = sizeof (short);
return Kint;
case 'H':
*size = sizeof (short);
return Kuint;
case 'l':
*size = sizeof (long);
return Kint;
case 'L':
*size = sizeof (long);
return Kuint;
case 'j':
*size = sizeof (lua_Integer);
return Kint;
case 'J':
*size = sizeof (lua_Integer);
return Kuint;
case 'T':
*size = sizeof (size_t);
return Kuint;
case 'f':
*size = sizeof (float);
return Kfloat;
case 'd':
*size = sizeof (double);
return Kfloat;
case 'n':
*size = sizeof (lua_Number);
return Kfloat;
case 'i':
*size = getnumlimit (h, fmt, sizeof (int));
return Kint;
case 'I':
*size = getnumlimit (h, fmt, sizeof (int));
return Kuint;
case 's':
*size = getnumlimit (h, fmt, sizeof (size_t));
return Kstring;
case 'c':
*size = getnum (fmt, -1);
if (*size == -1)
luaL_error (h->L, "missing size for format option 'c'");
return Kchar;
case 'z':
return Kzstr;
case 'x':
*size = 1;
return Kpadding;
case 'X':
return Kpaddalign;
case ' ':
break;
case '<':
h->islittle = 1;
break;
case '>':
h->islittle = 0;
break;
case '=':
h->islittle = nativeendian.little;
break;
case '!':
h->maxalign = getnumlimit (h, fmt, MAXALIGN);
break;
default:
luaL_error (h->L, "invalid format option '%c'", opt);
}
return Knop;
}


/*
** Read, classify, and fill other details about the next option.
** 'psize' is filled with option's size, 'notoalign' with its
** alignment requirements.
** Local variable 'size' gets the size to be aligned. (Kpadal option
** always gets its full alignment, other options are limited by
** the maximum alignment ('maxalign'). Kchar option needs no alignment
** despite its size.
*/
static KOption
getdetails (Header *h, size_t totalsize,
const char **fmt, int *psize, int *ntoalign)
{
KOption opt = getoption (h, fmt, psize);
int align = *psize; /* usually, alignment follows size */
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
if (**fmt == '\0' || getoption (h, fmt, &align) == Kchar || align == 0)
luaL_argerror (h->L, 1, "invalid next option for option 'X'");
}
if (align <= 1 || opt == Kchar) /* need no alignment? */
*ntoalign = 0;
else {
if (align > h->maxalign) /* enforce maximum alignment */
align = h->maxalign;
if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */
luaL_argerror (h->L, 1, "format asks for alignment not power of 2");
*ntoalign = (align - (int) (totalsize & (align - 1))) & (align - 1);
}
return opt;
}


/*
** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
** The final 'if' handles the case when 'size' is larger than
** the size of a Lua integer, correcting the extra sign-extension
** bytes if necessary (by default they would be zeros).
*/
static void
packint (luaL_Buffer *b, lua_Unsigned n,
int islittle, int size, int neg)
{
char *buff = luaL_prepbuffsize (b, size);
int i;
buff[islittle ? 0 : size - 1] = (char) (n & MC); /* first byte */
for (i = 1; i < size; i++) {
n >>= NB;
buff[islittle ? i : size - 1 - i] = (char) (n & MC);
}
if (neg && size > SZINT) { /* negative number need sign extension? */
for (i = SZINT; i < size; i++) /* correct extra bytes */
buff[islittle ? i : size - 1 - i] = (char) MC;
}
luaL_addsize(b, size); /* add result to buffer */
}


/*
** Copy 'size' bytes from 'src' to 'dest', correcting endianness if
** given 'islittle' is different from native endianness.
*/
static void
copywithendian (volatile char *dest, volatile const char *src,
int size, int islittle)
{
if (islittle == nativeendian.little) {
while (size-- != 0)
*(dest++) = *(src++);
}
else {
dest += size - 1;
while (size-- != 0)
*(dest--) = *(src++);
}
}


static int
lua_util_pack (lua_State *L)
{
luaL_Buffer b;
Header h;
const char *fmt = luaL_checkstring(L, 1); /* format string */
int arg = 1; /* current argument to pack */
size_t totalsize = 0; /* accumulate total size of result */
initheader (L, &h);
lua_pushnil (L); /* mark to separate arguments from string buffer */
luaL_buffinit (L, &b);

while (*fmt != '\0') {
int size, ntoalign;
KOption opt = getdetails (&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size;
while (ntoalign-- > 0)
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
arg++;
switch (opt) {
case Kint: { /* signed integers */
lua_Integer n = luaL_checkinteger (L, arg);
if (size < SZINT) { /* need overflow check? */
lua_Integer lim = (lua_Integer) 1 << ((size * NB) - 1);
luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
}
packint (&b, (lua_Unsigned) n, h.islittle, size, (n < 0));
break;
}
case Kuint: { /* unsigned integers */
lua_Integer n = luaL_checkinteger (L, arg);
if (size < SZINT) /* need overflow check? */
luaL_argcheck(L,
(lua_Unsigned) n < ((lua_Unsigned) 1 << (size * NB)),
arg,
"unsigned overflow");
packint (&b, (lua_Unsigned) n, h.islittle, size, 0);
break;
}
case Kfloat: { /* floating-point options */
volatile Ftypes u;
char *buff = luaL_prepbuffsize (&b, size);
lua_Number n = luaL_checknumber (L, arg); /* get argument */
if (size == sizeof (u.f))
u.f = (float) n; /* copy it into 'u' */
else if (size == sizeof (u.d))
u.d = (double) n;
else
u.n = n;
/* move 'u' to final result, correcting endianness if needed */
copywithendian (buff, u.buff, size, h.islittle);
luaL_addsize(&b, size);
break;
}
case Kchar: { /* fixed-size string */
size_t len;
const char *s = luaL_checklstring (L, arg, &len);
if ((size_t) size <=
len) /* string larger than (or equal to) needed? */
luaL_addlstring (&b,
s,
size); /* truncate string to asked size */
else { /* string smaller than needed */
luaL_addlstring (&b, s, len); /* add it all */
while (len++ < (size_t) size) /* pad extra space */
luaL_addchar(&b, LUA_PACKPADBYTE);
}
break;
}
case Kstring: { /* strings with length count */
size_t len;
const char *s = luaL_checklstring (L, arg, &len);
luaL_argcheck(L, size >= (int) sizeof (size_t) ||
len < ((size_t) 1 << (size * NB)),
arg, "string length does not fit in given size");
packint (&b,
(lua_Unsigned) len,
h.islittle,
size,
0); /* pack length */
luaL_addlstring (&b, s, len);
totalsize += len;
break;
}
case Kzstr: { /* zero-terminated string */
size_t len;
const char *s = luaL_checklstring (L, arg, &len);
luaL_argcheck(L, strlen (s) == len, arg, "string contains zeros");
luaL_addlstring (&b, s, len);
luaL_addchar(&b, '\0'); /* add zero at the end */
totalsize += len + 1;
break;
}
case Kpadding:
luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign:
case Knop:
arg--; /* undo increment */
break;
}
}
luaL_pushresult (&b);
return 1;
}


static int
lua_util_packsize (lua_State *L)
{
Header h;
const char *fmt = luaL_checkstring(L, 1); /* format string */
size_t totalsize = 0; /* accumulate total size of result */
initheader (L, &h);
while (*fmt != '\0') {
int size, ntoalign;
KOption opt = getdetails (&h, totalsize, &fmt, &size, &ntoalign);
size += ntoalign; /* total space used by option */
luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
"format result too large");
totalsize += size;
switch (opt) {
case Kstring: /* strings with length count */
case Kzstr: /* zero-terminated string */
luaL_argerror (L, 1, "variable-length format");
/* call never return, but to avoid warnings: *//* FALLTHROUGH */
default:
break;
}
}
lua_pushinteger (L, (lua_Integer) totalsize);
return 1;
}


/*
** Unpack an integer with 'size' bytes and 'islittle' endianness.
** If size is smaller than the size of a Lua integer and integer
** is signed, must do sign extension (propagating the sign to the
** higher bits); if size is larger than the size of a Lua integer,
** it must check the unread bytes to see whether they do not cause an
** overflow.
*/
static lua_Integer
unpackint (lua_State *L, const char *str,
int islittle, int size, int issigned)
{
lua_Unsigned res = 0;
int i;
int limit = (size <= SZINT) ? size : SZINT;
for (i = limit - 1; i >= 0; i--) {
res <<= NB;
res |= (lua_Unsigned) (
unsigned char)str[islittle ? i : size - 1 - i];
}
if (size < SZINT) { /* real size smaller than lua_Integer? */
if (issigned) { /* needs sign extension? */
lua_Unsigned mask = (lua_Unsigned) 1 << (size * NB - 1);
res = ((res ^ mask) - mask); /* do sign extension */
}
}
else if (size > SZINT) { /* must check unread bytes */
int mask = (!issigned || (lua_Integer) res >= 0) ? 0 : MC;
for (i = limit; i < size; i++) {
if ((unsigned char) str[islittle ? i : size - 1 - i] != mask)
luaL_error (L,
"%d-byte integer does not fit into Lua Integer",
size);
}
}
return (lua_Integer) res;
}

static lua_Integer
posrelat (lua_Integer pos, size_t len)
{
if (pos >= 0)
return pos;
else if (0u - (size_t) pos > len)
return 0;
else
return (lua_Integer) len + pos + 1;
}

static int
lua_util_unpack (lua_State *L)
{
Header h;
const char *fmt = luaL_checkstring(L, 1);
size_t ld;
const char *data = luaL_checklstring (L, 2, &ld);
size_t pos = (size_t) posrelat (luaL_optinteger (L, 3, 1), ld) - 1;
int n = 0; /* number of results */
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
initheader (L, &h);
while (*fmt != '\0') {
int size, ntoalign;
KOption opt = getdetails (&h, pos, &fmt, &size, &ntoalign);
if ((size_t) ntoalign + size > ~pos || pos + ntoalign + size > ld)
luaL_argerror (L, 2, "data string too short");
pos += ntoalign; /* skip alignment */
/* stack space for item + next position */
luaL_checkstack (L, 2, "too many results");
n++;
switch (opt) {
case Kint:
case Kuint: {
lua_Integer res = unpackint (L, data + pos, h.islittle, size,
(opt == Kint));
lua_pushinteger (L, res);
break;
}
case Kfloat: {
volatile Ftypes u;
lua_Number num;
copywithendian (u.buff, data + pos, size, h.islittle);
if (size == sizeof (u.f))
num = (lua_Number) u.f;
else if (size == sizeof (u.d))
num = (lua_Number) u.d;
else
num = u.n;
lua_pushnumber (L, num);
break;
}
case Kchar: {
lua_pushlstring (L, data + pos, size);
break;
}
case Kstring: {
size_t len = (size_t) unpackint (L,
data + pos,
h.islittle,
size,
0);
luaL_argcheck(L,
pos + len + size <= ld,
2,
"data string too short");
lua_pushlstring (L, data + pos + size, len);
pos += len; /* skip string */
break;
}
case Kzstr: {
size_t len = (int) strlen (data + pos);
lua_pushlstring (L, data + pos, len);
pos += len + 1; /* skip string plus final '\0' */
break;
}
case Kpaddalign:
case Kpadding:
case Knop:
n--; /* undo increment */
break;
}
pos += size;
}
lua_pushinteger (L, pos + 1); /* next position */
return n + 1;
}

static gint
lua_load_util (lua_State * L)
{

Loading…
Cancel
Save