wireshark/epan/wslua/wslua_int64.c

908 lines
32 KiB
C
Raw Normal View History

/*
* A Lua userdata object for 64-bit signed/unsigned integers.
* $Id: wslua_int64.c,v 1.0 2013/03/31 02:08:32 hadrielk Exp $
*
* I, Hadriel Kaplan, the author of wslua_int6464.c, wish to put it in
* the Public Domain. That is not universally accepted, however,
* so you may license it under the FreeBSD License instead, which is an open
* source license approved for GPL use as well as commercial etc.
* It's even less restrictive than the MIT license, because it requires
* no attribution anywhere - I don't *want* attribution.
Copyright (C) 2013 Hadriel Kaplan <hadrielk@yahoo.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
#include "config.h"
#include "wslua.h"
/* WSLUA_MODULE Int64 Handling 64-bit Integers */
#define LUATYPE64_STRING_SIZE 21 /* string to hold 18446744073709551615 */
WSLUA_CLASS_DEFINE_BASE(Int64,NOP,NOP,0);
/*
Int64 represents a 64 bit signed integer.
Lua uses one single number representation which can be chosen at compile time and since
it is often set to IEEE 754 double precision floating point, we cannot store a 64 bit integer
with full precision.
For details, see: http://lua-users.org/wiki/FloatingPoint
*/
/* these declarations are here because some funcs in Int64 need to know about UInt64 */
UInt64 toUInt64(lua_State* L, int i);
gboolean isUInt64(lua_State* L, int i);
UInt64 checkUInt64(lua_State* L, int i);
/* A checkInt64 but that also auto-converts numbers, strings, and UINT64 to a gint64 */
static gint64 getInt64(lua_State *L, int i)
{
gchar *end = NULL;
(void) end;
switch (lua_type(L,i))
{
case LUA_TNUMBER:
return (gint64)luaL_checknumber(L,i);
case LUA_TSTRING:
return g_ascii_strtoll(luaL_checkstring(L,i),&end,10);
case LUA_TUSERDATA:
if (isUInt64(L, i)) {
return (Int64) toUInt64(L, i);
break;
}
/* fall through */
default:
return checkInt64(L,i);
}
}
/* Encodes Int64 userdata into Lua string struct with given endianess */
void Int64_pack(lua_State* L, luaL_Buffer *b, gint idx, gboolean asLittleEndian) {
gint64 value = checkInt64(L,idx);
gint8 buff[sizeof(gint64)];
if (asLittleEndian) {
guint i;
for (i = 0; i < sizeof(gint64); i++) {
buff[i] = (value & 0xff);
value >>= 8;
}
}
else {
gint i;
for (i = sizeof(gint64) - 1; i >= 0; i--) {
buff[i] = (value & 0xff);
value >>= 8;
}
}
luaL_addlstring(b, (char*)buff, sizeof(gint64));
}
WSLUA_METHOD Int64_encode(lua_State* L) {
/* Encodes the Int64 number into an 8-byte Lua string, using given endianess */
#define WSLUA_OPTARG_Int64_encode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
luaL_Buffer b;
gboolean asLittleEndian = (G_BYTE_ORDER == G_LITTLE_ENDIAN)? TRUE : FALSE;
if (lua_gettop(L) >= WSLUA_OPTARG_Int64_encode_ENDIAN) {
if (lua_type(L,WSLUA_OPTARG_Int64_encode_ENDIAN) == LUA_TBOOLEAN)
asLittleEndian = lua_toboolean(L,WSLUA_OPTARG_Int64_encode_ENDIAN);
}
luaL_buffinit(L, &b);
Int64_pack(L, &b, 1, asLittleEndian);
luaL_pushresult(&b);
WSLUA_RETURN(1); /* The Lua string */
}
/* Decodes from string buffer struct into Int64 userdata, with given endianess */
int Int64_unpack(lua_State* L, const gchar *buff, gboolean asLittleEndian) {
gint64 value = 0;
gint i;
if (asLittleEndian) {
for (i = sizeof(gint64) - 1; i >= 0; i--) {
value <<= 8;
value |= (gint64)(guchar)buff[i];
}
}
else {
for (i = 0; i < (gint) sizeof(gint64); i++) {
value <<= 8;
value |= (gint64)(guchar)buff[i];
}
}
pushInt64(L,value);
return 1;
}
WSLUA_CONSTRUCTOR Int64_decode(lua_State* L) {
/* Decodes an 8-byte Lua string, using given endianess, into a new Int64 object */
#define WSLUA_ARG_Int64_decode_STRING 1 /* The Lua string containing a binary 64-bit integer */
#define WSLUA_OPTARG_Int64_decode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
gboolean asLittleEndian = (G_BYTE_ORDER == G_LITTLE_ENDIAN)? TRUE : FALSE;
size_t len = 0;
const gchar *s = luaL_checklstring(L, WSLUA_ARG_Int64_decode_STRING, &len);
if (lua_gettop(L) >= WSLUA_OPTARG_Int64_decode_ENDIAN) {
if (lua_type(L,WSLUA_OPTARG_Int64_decode_ENDIAN) == LUA_TBOOLEAN)
asLittleEndian = lua_toboolean(L,WSLUA_OPTARG_Int64_decode_ENDIAN);
}
if (len == sizeof(gint64)) {
Int64_unpack(L, s, asLittleEndian);
} else {
lua_pushnil(L);
}
WSLUA_RETURN(1); /* The Int64 object created, or nil on failure */
}
WSLUA_CONSTRUCTOR Int64_new(lua_State* L) { /* Creates a Int64 Object */
#define WSLUA_OPTARG_Int64_new_VALUE 1 /* A number, UInt64, Int64, or string of ascii digits to assign the value of the new Int64 (default=0) */
#define WSLUA_OPTARG_Int64_new_HIGHVALUE 2 /* If this is a number and the first argument was a number, then the first will be treated as a lower 32-bits, and this is the high-order 32 bit number */
gint64 value = 0;
if (lua_gettop(L) >= 1) {
switch(lua_type(L, WSLUA_OPTARG_Int64_new_VALUE)) {
case LUA_TNUMBER:
value = (gint64)lua_tonumber(L, WSLUA_OPTARG_Int64_new_VALUE);
if (lua_gettop(L) == 2 && lua_type(L, WSLUA_OPTARG_Int64_new_HIGHVALUE) == LUA_TNUMBER) {
gint64 h = (gint64)lua_tonumber(L, WSLUA_OPTARG_Int64_new_HIGHVALUE);
value &= 0x00000000FFFFFFFF;
h <<= 32; h &= 0xFFFFFFFF00000000;
value += h;
}
break;
case LUA_TSTRING:
case LUA_TUSERDATA:
value = getInt64(L,WSLUA_OPTARG_Int64_new_VALUE);
break;
default:
WSLUA_OPTARG_ERROR(Int64_new,VALUE,"must be a number, UInt64, Int64, or string");
break;
}
}
pushInt64(L,value);
WSLUA_RETURN(1); /* The new Int64 object. */
}
WSLUA_CONSTRUCTOR Int64_max(lua_State* L) { /* Gets the max possible value */
pushInt64(L, G_MAXINT64);
WSLUA_RETURN(1); /* The new Int64 object of the max value. */
}
WSLUA_CONSTRUCTOR Int64_min(lua_State* L) { /* Gets the min possible value */
pushInt64(L, G_MININT64);
WSLUA_RETURN(1); /* The new Int64 object of the min value. */
}
WSLUA_METHOD Int64_tonumber(lua_State* L) {
/* Returns a Lua number of the Int64 value - this may lose precision. */
lua_pushnumber(L, (lua_Number)checkInt64(L,1));
WSLUA_RETURN(1); /* The Lua number */
}
WSLUA_CONSTRUCTOR Int64_fromhex(lua_State* L) { /* Creates an Int64 object from the given hex string */
guint64 result = 0;
size_t len = 0;
const gchar *s = luaL_checklstring(L,1,&len);
if (s && len > 0) {
sscanf(s, "%" G_GINT64_MODIFIER "x", &result);
}
pushInt64(L,(gint64)result);
WSLUA_RETURN(1); /* The new Int64 object. */
}
WSLUA_METHOD Int64_tohex(lua_State* L) {
/* Returns a hex string of the Int64 value. */
#define WSLUA_OPTARG_Int64_new_NUMBYTES 2 /* The number of hex-chars/nibbles to generate, negative means uppercase (default=16) */
gint64 b = getInt64(L,1);
gint n = luaL_optint(L, WSLUA_OPTARG_Int64_new_NUMBYTES, 16);
const gchar *hexdigits = "0123456789abcdef";
gchar buf[16];
gint i;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 16) n = 16;
for (i = n-1; i >= 0; --i) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
WSLUA_RETURN(1); /* The string hex */
}
WSLUA_METHOD Int64_higher(lua_State* L) {
/* Returns a Lua number of the higher 32-bits of the Int64 value. (negative Int64 will return a negative Lua number) */
gint64 num = getInt64(L,1);
gint64 b = num;
lua_Number n;
if (b < 0) b = -b; /* masking/shifting negative int64 isn't working on some platforms */
b &= 0x7FFFFFFF00000000;
b >>= 32;
n = (lua_Number)(guint32)(b & 0x00000000FFFFFFFFF);
if (num < 0) n = -n;
lua_pushnumber(L,n);
WSLUA_RETURN(1); /* The Lua number */
}
WSLUA_METHOD Int64_lower(lua_State* L) {
/* Returns a Lua number of the lower 32-bits of the Int64 value. (always positive) */
gint64 b = getInt64(L,1);
if (b < 0) b = -b; /* masking/shifting negative int64 isn't working on some platforms */
lua_pushnumber(L,(guint32)(b & 0x00000000FFFFFFFFF));
WSLUA_RETURN(1); /* The Lua number */
}
WSLUA_METAMETHOD Int64__tostring(lua_State* L) {
/* Converts the Int64 into a string of decimal digits */
gint64 num = getInt64(L,1);
gchar s[LUATYPE64_STRING_SIZE];
if (sprintf(s, "%" G_GINT64_MODIFIER "d", num) < 0)
luaL_error(L, "Error writing Int64 to a string");
lua_pushstring(L,s);
WSLUA_RETURN(1); /* The Lua string */
}
WSLUA_METAMETHOD Int64__unm(lua_State* L) {
/* Returns the negative of the Int64, in a new Int64 */
pushInt64(L,-(getInt64(L,1)));
WSLUA_RETURN(1); /* The new Int64 */
}
#define WSLUA_MATH_OP_FUNC(obj,op) \
/* use the 'get' form so we can accept numbers as well */ \
obj num1 = get##obj(L,1); \
obj num2 = get##obj(L,2); \
push##obj(L,(num1) op (num2)); \
return 1
WSLUA_METAMETHOD Int64__add(lua_State* L) {
/* Adds two Int64 together and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC(Int64,+);
}
WSLUA_METAMETHOD Int64__sub(lua_State* L) {
/* Subtracts two Int64 and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC(Int64,-);
}
WSLUA_METAMETHOD Int64__mul(lua_State* L) {
/* Multiplies two Int64 and returns a new one (this may truncate the value) */
WSLUA_MATH_OP_FUNC(Int64,*);
}
WSLUA_METAMETHOD Int64__div(lua_State* L) {
/* Divides two Int64 and returns a new one (integer divide, no remainder) */
WSLUA_MATH_OP_FUNC(Int64,/);
}
WSLUA_METAMETHOD Int64__mod(lua_State* L) {
/* Divides two Int64 and returns a new one of the remainder */
WSLUA_MATH_OP_FUNC(Int64,%);
}
WSLUA_METAMETHOD Int64__pow(lua_State* L) {
/* The first Int64 is taken to the power of the second Int64, returning a new one (this may truncate the value) */
gint64 num1 = getInt64(L,1);
gint64 num2 = getInt64(L,2);
gint64 result;
if (num1 == 2) {
result = (num2 >= 8 * (gint64) sizeof(gint64)) ? 0 : ((gint64)1 << num2);
}
else {
for (result = 1; num2 > 0; num2 >>= 1) {
if (num2 & 1) result *= num1;
num1 *= num1;
}
}
pushInt64(L,result);
WSLUA_RETURN(1); /* The Int64 object */
}
#define WSLUA_COMP_OP_FUNC(obj,op) \
obj num1 = get##obj(L,1); \
obj num2 = get##obj(L,2); \
lua_pushboolean(L,(num1) op (num2)); \
return 1
WSLUA_METAMETHOD Int64__eq(lua_State* L) {
/* Returns true if both Int64 are equal */
WSLUA_COMP_OP_FUNC(Int64,==);
}
WSLUA_METAMETHOD Int64__lt(lua_State* L) {
/* Returns true if first Int64 < second */
WSLUA_COMP_OP_FUNC(Int64,<);
}
WSLUA_METAMETHOD Int64__le(lua_State* L) {
/* Returns true if first Int64 <= second */
WSLUA_COMP_OP_FUNC(Int64,<=);
}
WSLUA_METHOD Int64_bnot(lua_State* L) {
/* Returns a Int64 of the bitwise 'not' operation. */
pushInt64(L,~(getInt64(L,1)));
WSLUA_RETURN(1); /* The Int64 object */
}
#define WSLUA_BIT_OP_FUNC(obj,op) \
gint32 i; \
obj num = get##obj(L,1); \
for (i = lua_gettop(L); i > 1; i--) { \
num op get##obj(L,i); \
} \
push##obj(L,num); \
return 1
WSLUA_METHOD Int64_band(lua_State* L) {
/* Returns a Int64 of the bitwise 'and' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC(Int64,&=);
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_bor(lua_State* L) {
/* Returns a Int64 of the bitwise 'or' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC(Int64,|=);
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_bxor(lua_State* L) {
/* Returns a Int64 of the bitwise 'xor' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC(Int64,^=);
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_lshift(lua_State* L) {
/* Returns a Int64 of the bitwise logical left-shift operation, by the given number of bits. */
#define WSLUA_ARG_Int64_lshift_NUMBITS 2 /* The number of bits to left-shift by */
guint64 b = (guint64) getInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_Int64_lshift_NUMBITS);
pushInt64(L,(gint64)(b << n));
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_rshift(lua_State* L) {
/* Returns a Int64 of the bitwise logical right-shift operation, by the given number of bits. */
#define WSLUA_ARG_Int64_rshift_NUMBITS 2 /* The number of bits to right-shift by */
guint64 b = (guint64) getInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_Int64_rshift_NUMBITS);
pushInt64(L,(gint64)(b >> n));
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_arshift(lua_State* L) {
/* Returns a Int64 of the bitwise arithmetic right-shift operation, by the given number of bits. */
#define WSLUA_ARG_Int64_arshift_NUMBITS 2 /* The number of bits to right-shift by */
gint64 b = getInt64(L,1);
gint32 n = (gint32) luaL_checknumber(L,WSLUA_ARG_Int64_arshift_NUMBITS);
pushInt64(L,(b >> n));
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_rol(lua_State* L) {
/* Returns a Int64 of the bitwise left rotation operation, by the given number of bits (up to 63). */
#define WSLUA_ARG_Int64_rol_NUMBITS 2 /* The number of bits to roll left by */
guint64 b = (guint64) getInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_Int64_rol_NUMBITS);
pushInt64(L,(gint64)((b << n) | (b >> (64-n))));
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_ror(lua_State* L) {
/* Returns a Int64 of the bitwise right rotation operation, by the given number of bits (up to 63). */
#define WSLUA_ARG_Int64_ror_NUMBITS 2 /* The number of bits to roll right by */
guint64 b = (guint64) getInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_Int64_ror_NUMBITS);
pushInt64(L,(gint64)((b << (64-n)) | (b >> n)));
WSLUA_RETURN(1); /* The Int64 object */
}
WSLUA_METHOD Int64_bswap(lua_State* L) {
/* Returns a Int64 of the bytes swapped. This can be used to convert little-endian 64 bit numbers to big-endian 64 bit numbers or vice versa. */
guint64 b = (guint64) getInt64(L,1);
guint64 result = 0;
size_t i;
for (i = 0; i < sizeof(gint64); i++) {
result <<= 8;
result |= (b & 0x00000000000000FF);
b >>= 8;
}
pushInt64(L,(gint64)result);
WSLUA_RETURN(1); /* The Int64 object */
}
/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
static int Int64__gc(lua_State* L _U_) {
return 0;
}
static const luaL_Reg Int64_methods[] = {
{ "new", Int64_new },
{ "max", Int64_max },
{ "min", Int64_min },
{ "tonumber", Int64_tonumber },
{ "fromhex", Int64_fromhex },
{ "tohex", Int64_tohex },
{ "higher", Int64_higher },
{ "lower", Int64_lower },
{ "encode", Int64_encode },
{ "decode", Int64_decode },
{ "bnot", Int64_bnot },
{ "band", Int64_band },
{ "bor", Int64_bor },
{ "bxor", Int64_bxor },
{ "lshift", Int64_lshift },
{ "rshift", Int64_rshift },
{ "arshift", Int64_arshift },
{ "rol", Int64_rol },
{ "ror", Int64_ror },
{ "bswap", Int64_bswap },
{ NULL, NULL }
};
static const luaL_Reg Int64_meta[] = {
{"__tostring", Int64__tostring},
{"__concat", wslua__concat},
{"__unm", Int64__unm},
{"__add", Int64__add},
{"__sub", Int64__sub},
{"__mul", Int64__mul},
{"__div", Int64__div},
{"__mod", Int64__mod},
{"__pow", Int64__pow},
{"__eq", Int64__eq},
{"__lt", Int64__lt},
{"__le", Int64__le},
{ NULL, NULL }
};
LUALIB_API int Int64_register(lua_State* L) {
WSLUA_REGISTER_CLASS(Int64);
return 0;
}
WSLUA_CLASS_DEFINE_BASE(UInt64,NOP,NOP,0);
/* UInt64 represents a 64 bit unsigned integer, similar to Int64. */
/* A checkUInt64 but that also auto-converts numbers, strings, and Int64 to a guint64 */
static guint64 getUInt64(lua_State *L, int i)
{
gchar *end = NULL;
(void) end;
switch (lua_type(L,i))
{
case LUA_TNUMBER:
return (guint64) luaL_checknumber(L,i);
case LUA_TSTRING:
return g_ascii_strtoull(luaL_checkstring(L,i), &end, 10);
case LUA_TUSERDATA:
if (isInt64(L, i)) {
return (UInt64) toInt64(L, i);
break;
}
/* fall through */
default:
return checkUInt64(L,i);
}
}
/* Encodes UInt64 userdata into Lua string struct with given endianess */
void UInt64_pack(lua_State* L, luaL_Buffer *b, gint idx, gboolean asLittleEndian) {
guint64 value = checkUInt64(L,idx);
gint8 buff[sizeof(guint64)];
if (asLittleEndian) {
guint i;
for (i = 0; i < sizeof(guint64); i++) {
buff[i] = (value & 0xff);
value >>= 8;
}
}
else {
gint i;
for (i = sizeof(guint64) - 1; i >= 0; i--) {
buff[i] = (value & 0xff);
value >>= 8;
}
}
luaL_addlstring(b, (char*)buff, sizeof(guint64));
}
WSLUA_METHOD UInt64_encode(lua_State* L) {
/* Encodes the UInt64 number into an 8-byte Lua binary string, using given endianess */
#define WSLUA_OPTARG_UInt64_encode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
luaL_Buffer b;
gboolean asLittleEndian = (G_BYTE_ORDER == G_LITTLE_ENDIAN)? TRUE : FALSE;
if (lua_gettop(L) >= 2) {
if (lua_type(L,2) == LUA_TBOOLEAN)
asLittleEndian = lua_toboolean(L,2);
}
luaL_buffinit(L, &b);
UInt64_pack(L, &b, 1, asLittleEndian);
luaL_pushresult(&b);
WSLUA_RETURN(1); /* The Lua binary string */
}
/* Decodes from string buffer struct into UInt64 userdata, with given endianess */
int UInt64_unpack(lua_State* L, const gchar *buff, gboolean asLittleEndian) {
guint64 value = 0;
gint i;
if (asLittleEndian) {
for (i = sizeof(guint64) - 1; i >= 0; i--) {
value <<= 8;
value |= (guint64)(guchar)buff[i];
}
}
else {
for (i = 0; i < (gint) sizeof(guint64); i++) {
value <<= 8;
value |= (guint64)(guchar)buff[i];
}
}
pushUInt64(L,value);
return 1;
}
WSLUA_CONSTRUCTOR UInt64_decode(lua_State* L) {
/* Decodes an 8-byte Lua binary string, using given endianess, into a new UInt64 object */
#define WSLUA_ARG_UInt64_decode_STRING 1 /* The Lua string containing a binary 64-bit integer */
#define WSLUA_OPTARG_UInt64_decode_ENDIAN 2 /* If set to true then little-endian is used, if false then big-endian; if missing/nil, native host endian */
gboolean asLittleEndian = (G_BYTE_ORDER == G_LITTLE_ENDIAN)? TRUE : FALSE;
size_t len = 0;
const gchar *s = luaL_checklstring(L, WSLUA_ARG_UInt64_decode_STRING, &len);
if (lua_gettop(L) >= WSLUA_OPTARG_UInt64_decode_ENDIAN) {
if (lua_type(L,WSLUA_OPTARG_UInt64_decode_ENDIAN) == LUA_TBOOLEAN)
asLittleEndian = lua_toboolean(L,WSLUA_OPTARG_UInt64_decode_ENDIAN);
}
if (len == sizeof(guint64)) {
UInt64_unpack(L, s, asLittleEndian);
} else {
lua_pushnil(L);
}
WSLUA_RETURN(1); /* The UInt64 object created, or nil on failure */
}
WSLUA_CONSTRUCTOR UInt64_new(lua_State* L) { /* Creates a UInt64 Object */
#define WSLUA_OPTARG_UInt64_new_VALUE 1 /* A number, UInt64, Int64, or string of digits to assign the value of the new UInt64 (default=0) */
#define WSLUA_OPTARG_UInt64_new_HIGHVALUE 2 /* If this is a number and the first argument was a number, then the first will be treated as a lower 32-bits, and this is the high-order 32 bit number */
guint64 value = 0;
if (lua_gettop(L) >= 1) {
switch(lua_type(L, WSLUA_OPTARG_UInt64_new_VALUE)) {
case LUA_TNUMBER:
value = (guint64)lua_tonumber(L, WSLUA_OPTARG_UInt64_new_VALUE);
if (lua_gettop(L) == 2 && lua_type(L, WSLUA_OPTARG_UInt64_new_HIGHVALUE) == LUA_TNUMBER) {
guint64 h = (guint64)lua_tonumber(L, WSLUA_OPTARG_UInt64_new_HIGHVALUE);
value &= 0x00000000FFFFFFFF;
h <<= 32; h &= 0xFFFFFFFF00000000;
value += h;
}
break;
case LUA_TSTRING:
case LUA_TUSERDATA:
value = getUInt64(L, WSLUA_OPTARG_UInt64_new_VALUE);
break;
default:
WSLUA_OPTARG_ERROR(UInt64_new,VALUE,"must be a number, UInt64, Int64, or string");
break;
}
}
pushUInt64(L,value);
WSLUA_RETURN(1); /* The new UInt64 object. */
}
WSLUA_CONSTRUCTOR UInt64_max(lua_State* L) { /* Gets the max possible value */
pushUInt64(L,G_MAXUINT64);
WSLUA_RETURN(1); /* The max value. */
}
WSLUA_CONSTRUCTOR UInt64_min(lua_State* L) { /* Gets the min possible value (i.e., 0) */
pushUInt64(L,0);
WSLUA_RETURN(1); /* The min value. */
}
WSLUA_METHOD UInt64_tonumber(lua_State* L) {
/* Returns a Lua number of the UInt64 value - this may lose precision. */
lua_pushnumber(L,(lua_Number)checkUInt64(L,1));
WSLUA_RETURN(1); /* The Lua number */
}
WSLUA_METAMETHOD UInt64__tostring(lua_State* L) {
/* Converts the UInt64 into a string */
guint64 num = getUInt64(L,1);
gchar s[LUATYPE64_STRING_SIZE];
if (sprintf(s, "%" G_GINT64_MODIFIER "u",(guint64)num) < 0)
luaL_error(L, "Error writing UInt64 to a string");
lua_pushstring(L,s);
WSLUA_RETURN(1); /* The Lua string */
}
WSLUA_CONSTRUCTOR UInt64_fromhex(lua_State* L) { /* Creates a UInt64 object from the given hex string */
guint64 result = 0;
size_t len = 0;
const gchar *s = luaL_checklstring(L,1,&len);
if (s && len > 0) {
sscanf(s, "%" G_GINT64_MODIFIER "x", &result);
}
pushUInt64(L,result);
WSLUA_RETURN(1); /* The new UInt64 object. */
}
WSLUA_METHOD UInt64_tohex(lua_State* L) {
/* Returns a hex string of the UInt64 value. */
#define WSLUA_OPTARG_Int64_new_NUMBYTES 2 /* The number of hex-chars/nibbles to generate, negative means uppercase (default=16) */
guint64 b = getUInt64(L,1);
gint n = luaL_optint(L, WSLUA_OPTARG_Int64_new_NUMBYTES, 16);
const gchar *hexdigits = "0123456789abcdef";
gchar buf[16];
gint i;
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
if (n > 16) n = 16;
for (i = n-1; i >= 0; --i) { buf[i] = hexdigits[b & 15]; b >>= 4; }
lua_pushlstring(L, buf, (size_t)n);
WSLUA_RETURN(1); /* The string hex */
}
WSLUA_METHOD UInt64_higher(lua_State* L) {
/* Returns a Lua number of the higher 32-bits of the UInt64 value. */
guint64 num = getUInt64(L,1);
guint64 b = num;
lua_Number n;
b &= 0xFFFFFFFF00000000;
b >>= 32;
n = (lua_Number)(guint32)(b & 0x00000000FFFFFFFFF);
lua_pushnumber(L,n);
WSLUA_RETURN(1); /* The Lua number */
}
WSLUA_METHOD UInt64_lower(lua_State* L) {
/* Returns a Lua number of the lower 32-bits of the UInt64 value. */
guint64 b = getUInt64(L,1);
lua_pushnumber(L,(guint32)(b & 0x00000000FFFFFFFFF));
WSLUA_RETURN(1); /* The Lua number */
}
WSLUA_METAMETHOD UInt64__unm(lua_State* L) {
/* Returns the UInt64, in a new UInt64, since unsigned integers can't be negated. */
pushUInt64(L,getUInt64(L,1));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METAMETHOD UInt64__add(lua_State* L) {
/* Adds two UInt64 together and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC(UInt64,+);
}
WSLUA_METAMETHOD UInt64__sub(lua_State* L) {
/* Subtracts two UInt64 and returns a new one (this may wrap the value) */
WSLUA_MATH_OP_FUNC(UInt64,-);
}
WSLUA_METAMETHOD UInt64__mul(lua_State* L) {
/* Multiplies two UInt64 and returns a new one (this may truncate the value) */
WSLUA_MATH_OP_FUNC(UInt64,*);
}
WSLUA_METAMETHOD UInt64__div(lua_State* L) {
/* Divides two UInt64 and returns a new one (integer divide, no remainder) */
WSLUA_MATH_OP_FUNC(UInt64,/);
}
WSLUA_METAMETHOD UInt64__mod(lua_State* L) {
/* Divides two UInt64 and returns a new one of the remainder */
WSLUA_MATH_OP_FUNC(UInt64,%);
}
WSLUA_METAMETHOD UInt64__pow(lua_State* L) {
/* The first UInt64 is taken to the power of the second UInt64/number, returning a new one (this may truncate the value) */
guint64 num1 = getUInt64(L,1);
guint64 num2 = getUInt64(L,2);
guint64 result;
if (num1 == 2) {
result = (num2 >= 8 * (guint64) sizeof(guint64)) ? 0 : ((guint64)1 << num2);
}
else {
for (result = 1; num2 > 0; num2 >>= 1) {
if (num2 & 1) result *= num1;
num1 *= num1;
}
}
pushUInt64(L,result);
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METAMETHOD UInt64__eq(lua_State* L) {
/* Returns true if both UInt64 are equal */
WSLUA_COMP_OP_FUNC(UInt64,==);
}
WSLUA_METAMETHOD UInt64__lt(lua_State* L) {
/* Returns true if first UInt64 < second */
WSLUA_COMP_OP_FUNC(UInt64,<);
}
WSLUA_METAMETHOD UInt64__le(lua_State* L) {
/* Returns true if first UInt64 <= second */
WSLUA_COMP_OP_FUNC(UInt64,<=);
}
WSLUA_METHOD UInt64_bnot(lua_State* L) {
/* Returns a UInt64 of the bitwise 'not' operation. */
pushUInt64(L,~(getUInt64(L,1)));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_band(lua_State* L) {
/* Returns a UInt64 of the bitwise 'and' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC(UInt64,&=);
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_bor(lua_State* L) {
/* Returns a UInt64 of the bitwise 'or' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC(UInt64,|=);
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_bxor(lua_State* L) {
/* Returns a UInt64 of the bitwise 'xor' operation, with the given number/Int64/UIn64. Note that multiple arguments are allowed. */
WSLUA_BIT_OP_FUNC(UInt64,^=);
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_lshift(lua_State* L) {
/* Returns a UInt64 of the bitwise logical left-shift operation, by the given number of bits. */
#define WSLUA_ARG_UInt64_lshift_NUMBITS 2 /* The number of bits to left-shift by */
guint64 b = getUInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_UInt64_lshift_NUMBITS);
pushUInt64(L,(b << n));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_rshift(lua_State* L) {
/* Returns a UInt64 of the bitwise logical right-shift operation, by the given number of bits. */
#define WSLUA_ARG_UInt64_rshift_NUMBITS 2 /* The number of bits to right-shift by */
guint64 b = getUInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_UInt64_rshift_NUMBITS);
pushUInt64(L,(b >> n));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_arshift(lua_State* L) {
/* Returns a UInt64 of the bitwise arithmetic right-shift operation, by the given number of bits. */
#define WSLUA_ARG_UInt64_arshift_NUMBITS 2 /* The number of bits to right-shift by */
guint64 b = getUInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_UInt64_arshift_NUMBITS);
pushUInt64(L,(b >> n));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_rol(lua_State* L) {
/* Returns a UInt64 of the bitwise left rotation operation, by the given number of bits (up to 63). */
#define WSLUA_ARG_UInt64_rol_NUMBITS 2 /* The number of bits to roll left by */
guint64 b = getUInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_UInt64_rol_NUMBITS);
pushUInt64(L,((b << n) | (b >> (64-n))));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_ror(lua_State* L) {
/* Returns a UInt64 of the bitwise right rotation operation, by the given number of bits (up to 63). */
#define WSLUA_ARG_UInt64_ror_NUMBITS 2 /* The number of bits to roll right by */
guint64 b = getUInt64(L,1);
guint32 n = (guint32) luaL_checknumber(L,WSLUA_ARG_UInt64_ror_NUMBITS);
pushUInt64(L,((b << (64-n)) | (b >> n)));
WSLUA_RETURN(1); /* The UInt64 object */
}
WSLUA_METHOD UInt64_bswap(lua_State* L) {
/* Returns a UInt64 of the bytes swapped. This can be used to convert little-endian 64 bit numbers to big-endian 64 bit numbers or vice versa. */
guint64 b = getUInt64(L,1);
guint64 result = 0;
size_t i;
for (i = 0; i < sizeof(guint64); i++) {
result <<= 8;
result |= (b & 0x00000000000000FF);
b >>= 8;
}
pushUInt64(L,result);
WSLUA_RETURN(1); /* The UInt64 object */
}
/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
static int UInt64__gc(lua_State* L _U_) {
return 0;
}
static const luaL_Reg UInt64_methods[] = {
{ "new", UInt64_new },
{ "max", UInt64_max },
{ "min", UInt64_min },
{ "tonumber", UInt64_tonumber },
{ "fromhex", UInt64_fromhex },
{ "tohex", UInt64_tohex },
{ "higher", UInt64_higher },
{ "lower", UInt64_lower },
{ "encode", UInt64_encode },
{ "decode", UInt64_decode },
{ "bnot", UInt64_bnot },
{ "band", UInt64_band },
{ "bor", UInt64_bor },
{ "bxor", UInt64_bxor },
{ "lshift", UInt64_lshift },
{ "rshift", UInt64_rshift },
{ "arshift", UInt64_arshift },
{ "rol", UInt64_rol },
{ "ror", UInt64_ror },
{ "bswap", UInt64_bswap },
{ NULL, NULL }
};
static const luaL_Reg UInt64_meta[] = {
{"__tostring", UInt64__tostring},
{"__concat", wslua__concat},
{"__unm", UInt64__unm},
{"__add", UInt64__add},
{"__sub", UInt64__sub},
{"__mul", UInt64__mul},
{"__div", UInt64__div},
{"__mod", UInt64__mod},
{"__pow", UInt64__pow},
{"__eq", UInt64__eq},
{"__lt", UInt64__lt},
{"__le", UInt64__le},
{ NULL, NULL }
};
LUALIB_API int UInt64_register(lua_State* L) {
WSLUA_REGISTER_CLASS(UInt64);
return 0;
}