tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[patch] Lua data library



Hi Folks,

I've implemented the core features of the Lua data library; the patch
is attached. Luadata provides C and Lua APIs to handle binary data
using Lua scripts. Here is a briefly description of those:

1. Lua API:

1.1 creation

- data.new(table)

Returns a new data object initialized with the given byte array. For example:

d1 = data.new{0xFF, 0xFE, 0x00} --> returns a data object with 3 bytes.

1.2 layout

- data.layout(table)

Returns a new layout table based on table argument, which should have
the following formats for its fields:

(i) field = {<offset>, <length> [, <endian>]} or
(ii) field = {offset = <offset>, length = <length> [endian = <endian>]}

Where, field is the name of the field, <offset> is the offset in bits
(MSB 0), <length> is the length in bits, endian is a string that
indicates the field endianness ('host', 'net', 'little', 'big'). The
default value for endian is 'big'.

Here are a couple examples:

(i) l1 = data.layout{msb = {0, 1}, uint32 = {0, 32}, uint64le = {0,
64, 'little'}}

(ii) l2 = data.layout{msb = {offset = 0, length = 1},
  net_unaligned_uint16 = {offset = 1, length = 16, endian = 'net'}}

- d:layout(layout | table)

Applies a layout table on a given data object. If a regular table is
passed, it calls data.layout(table) first. For example:

d1:layout(l1) -- applies l1 layout into d1 data object
d2:layout{byte = {0, 8}} -- creates and applies a new layout into d2 data object

2. API C

2.1 creation

- int ldata_newref(lua_State *L, void *ptr, size_t size);

Creates a new data object pointing to ptr (without copying it), leaves
the data object on the top of the Lua stack and returns a reference
for it. The data object will not be garbage-collected until it is
unreferred.

2.2 deletion

- void ldata_unref(lua_State *L, int ref);

Removes the ptr from the data object and releases the data-object
reference, allowing it to be garbage-collected. After that, it is safe
to free the ptr pointer.

Regards,
--
Lourival Vieira Neto
Index: lib/lua/data/Makefile
===================================================================
RCS file: lib/lua/data/Makefile
diff -N lib/lua/data/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/Makefile       17 Jan 2014 11:47:53 -0000
@@ -0,0 +1,9 @@
+LUA_MODULES=   data
+
+LUA_SRCS.data= luadata.c
+LUA_SRCS.data+=        data.c
+LUA_SRCS.data+=        layout.c
+LUA_SRCS.data+=        luautil.c
+LUA_SRCS.data+=        binary.c
+
+.include <bsd.lua.mk>
Index: lib/lua/data/binary.c
===================================================================
RCS file: lib/lua/data/binary.c
diff -N lib/lua/data/binary.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/binary.c       17 Jan 2014 11:47:53 -0000
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#include <limits.h>
+
+#include <sys/param.h>
+
+#include "binary.h"
+
+#define BYTE_MAX       UCHAR_MAX
+#define UINT64_BIT     (64)
+
+inline static void
+set_bits(uint64_t *value, uint64_t clear_mask, uint64_t set_mask)
+{
+       *value &= clear_mask;
+       *value |= set_mask;
+}
+
+#define CONTIGUOUS_BITS(widt, truncated)       (width - truncated)
+
+static void
+expand(uint64_t *value, size_t width, size_t msb_offset, byte_t truncated)
+{
+       size_t contiguous = CONTIGUOUS_BITS(width, truncated);
+
+       size_t trunc_msb_offset = BYTE_BIT - truncated;
+       size_t trunc_lsb_offset = contiguous + trunc_msb_offset;
+
+       size_t clear_offset = msb_offset + truncated;
+
+       uint64_t clear_mask = UINT64_MAX >> clear_offset;
+       uint64_t trunc_mask = *value >> trunc_lsb_offset << contiguous;
+
+       set_bits(value, clear_mask, trunc_mask);
+}
+
+static void
+contract(uint64_t *value, size_t width, size_t msb_offset, byte_t truncated)
+{
+       size_t contiguous = CONTIGUOUS_BITS(width, truncated);
+
+       size_t trunc_lsb_offset = BYTE_BIT - truncated;
+       size_t trunc_msb_offset = contiguous + trunc_lsb_offset;
+
+       size_t clear_offset = msb_offset + truncated;
+
+       uint64_t clear_mask = UINT64_MAX << clear_offset;
+       uint64_t trunc_mask = *value << trunc_msb_offset >> contiguous;
+
+       set_bits(value, clear_mask, trunc_mask);
+}
+
+#define TRUNCATED_BITS(width)          (width % BYTE_BIT)
+
+#define VALUE_MSB_OFFSET(width)                (UINT64_BIT - width)
+
+static void
+swap_bytes_in(uint64_t *value, size_t width)
+{
+       size_t msb_offset = VALUE_MSB_OFFSET(width);
+
+       *value <<= msb_offset;
+
+       *value = bswap64(*value);
+
+       byte_t truncated = TRUNCATED_BITS(width);
+       if (truncated > 0)
+               expand(value, width, msb_offset, truncated);
+}
+
+static void
+swap_bytes_out(uint64_t *value, size_t width)
+{
+       size_t msb_offset = VALUE_MSB_OFFSET(width);
+
+       *value = bswap64(*value);
+
+       byte_t truncated = TRUNCATED_BITS(width);
+       if (truncated > 0)
+               contract(value, width, msb_offset, truncated);
+
+       *value >>= msb_offset;
+}
+
+#define MSB_OFFSET(offset)             (offset % BYTE_BIT)
+
+#define LSB_OFFSET(width, msb_offset)                                  \
+       MAX((ssize_t) (BYTE_BIT - msb_offset - width), 0)
+
+#define BYTE_POSITION(offset)          (offset / BYTE_BIT)
+
+#define OVERFLOW_BITS(width, msb_offset, lsb_offset)                   \
+       (width - (BYTE_BIT - msb_offset - lsb_offset))
+
+#define MASK(msb_offset, lsb_offset)                                   \
+       ((byte_t) BYTE_MAX >> (msb_offset + lsb_offset) << lsb_offset)
+
+#define OVERFLOW_LSB_OFFSET(overflow)  (BYTE_BIT - overflow)
+
+#define NEED_SWAP(width, endian)                                       \
+       (width > BYTE_BIT && endian == LITTLE_ENDIAN)
+
+uint64_t
+binary_get_uint64(byte_t *bytes, size_t offset, size_t width, int endian)
+{
+       size_t msb_offset = MSB_OFFSET(offset);
+       size_t lsb_offset = LSB_OFFSET(width, msb_offset);
+       size_t pos        = BYTE_POSITION(offset);
+       size_t overflow   = OVERFLOW_BITS(width, msb_offset, lsb_offset);
+       byte_t mask       = MASK(msb_offset, lsb_offset);
+
+       uint64_t value = (byte_t) (bytes[ pos ] & mask) >> lsb_offset;
+
+       for (; overflow >= BYTE_BIT; overflow -= BYTE_BIT)
+               value = (value << BYTE_BIT) | bytes[ ++pos ];
+
+       if (overflow > 0) {
+               /* assertion: overflow < BYTE_BIT */
+               size_t overflow_lsb_offset = OVERFLOW_LSB_OFFSET(overflow);
+
+               value <<= overflow;
+               value  |= (byte_t) bytes[ ++pos ] >> overflow_lsb_offset;
+       }
+
+       if (NEED_SWAP(width, endian))
+               swap_bytes_in(&value, width);
+
+       return value;
+}
+
+void
+binary_set_uint64(byte_t *bytes, size_t offset, size_t width, int endian, 
uint64_t value)
+{
+       size_t msb_offset = MSB_OFFSET(offset);
+       size_t lsb_offset = LSB_OFFSET(width, msb_offset);
+       size_t pos        = BYTE_POSITION(offset);
+       size_t overflow   = OVERFLOW_BITS(width, msb_offset, lsb_offset);
+       byte_t clear_mask = ~MASK(msb_offset, lsb_offset);
+
+       if (NEED_SWAP(width, endian))
+               swap_bytes_out(&value, width);
+
+       bytes[ pos ] &= clear_mask;
+       bytes[ pos ] |= (uint64_t) value << lsb_offset >> overflow;
+
+       for (; overflow >= BYTE_BIT; overflow -= BYTE_BIT)
+               bytes[ ++pos ] = (uint64_t) value >> (overflow - BYTE_BIT);
+
+       if (overflow > 0) {
+               /* assertion: overflow < BYTE_BIT */
+               size_t overflow_lsb_offset = OVERFLOW_LSB_OFFSET(overflow);
+               byte_t overflow_clear_mask = ~(BYTE_MAX << overflow_lsb_offset);
+
+               bytes[ ++pos ] &= overflow_clear_mask;
+               bytes[   pos ] |= value << overflow_lsb_offset;
+       }
+}
Index: lib/lua/data/binary.h
===================================================================
RCS file: lib/lua/data/binary.h
diff -N lib/lua/data/binary.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/binary.h       17 Jan 2014 11:47:53 -0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#ifndef _BINARY_H_
+#define _BINARY_H_
+
+#include <sys/endian.h>
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#else
+#include <stddef.h>
+#include <stdint.h>
+#endif
+
+#define BYTE_BIT       CHAR_BIT
+
+typedef unsigned char byte_t;
+
+uint64_t binary_get_uint64(byte_t *, size_t, size_t, int);
+
+void binary_set_uint64(byte_t *, size_t, size_t, int, uint64_t);
+
+#endif /* _BINARY_H_ */
Index: lib/lua/data/data.c
===================================================================
RCS file: lib/lua/data/data.c
diff -N lib/lua/data/data.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/data.c 17 Jan 2014 11:47:53 -0000
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#include <lauxlib.h>
+
+#include "luautil.h"
+
+#include "data.h"
+
+#include "binary.h"
+#include "layout.h"
+
+#define LUA_INTEGER_BYTE       (sizeof(lua_Integer))
+#define LUA_INTEGER_BIT                (LUA_INTEGER_BYTE * BYTE_BIT)
+
+inline static bool
+check_limits(data_t *data, layout_entry_t *entry)
+{
+       return entry->length <= LUA_INTEGER_BIT &&
+               entry->offset + entry->length <= data->length;
+}
+
+inline static bool
+check_entry(data_t *data, layout_entry_t *entry)
+{
+       return entry != NULL && check_limits(data, entry);
+}
+
+inline static layout_entry_t *
+get_entry(lua_State *L, data_t *data, int key_ix)
+{
+       if (!luau_isvalidref(data->layout))
+               return NULL;
+
+       return layout_get_entry(L, data->layout, key_ix);
+}
+
+data_t *
+data_new(lua_State *L, void *ptr, size_t size, bool free)
+{
+       data_t *data = lua_newuserdata(L, sizeof(data_t));
+
+       data->ptr    = ptr;
+       data->size   = size;
+       data->length = size * BYTE_BIT;
+       data->layout = LUA_REFNIL;
+       data->free   = free;
+
+       luaL_getmetatable(L, DATA_USERDATA);
+       lua_setmetatable(L, -2);
+       return data;
+}
+
+inline data_t *
+data_check(lua_State *L, int index)
+{
+       return (data_t *) luaL_checkudata(L, index, DATA_USERDATA);
+}
+
+inline void
+data_apply_layout(lua_State *L, data_t *data, int layout_ix)
+{
+       luau_unref(L, data->layout);
+       lua_pushvalue(L, layout_ix);
+       data->layout = luau_ref(L);
+}
+
+#define BINARY_PARMS(data, entry)                                      \
+       data->ptr, entry->offset, entry->length, entry->endian
+
+int
+data_get_field(lua_State *L, data_t *data, int key_ix)
+{
+       if (data->ptr == NULL)
+               return 0;
+
+       layout_entry_t *entry = get_entry(L, data, key_ix);
+       if (!check_entry(data, entry))
+               return 0;
+
+       /* assertion: LUA_INTEGER_BIT <= 64 */
+       lua_Integer value = binary_get_uint64(BINARY_PARMS(data, entry));
+       lua_pushinteger(L, value);
+       return 1;
+}
+
+void
+data_set_field(lua_State *L, data_t *data, int key_ix, lua_Integer value)
+{
+       if (data->ptr == NULL)
+               return;
+
+       layout_entry_t *entry = get_entry(L, data, key_ix);
+       if (!check_entry(data, entry))
+               return;
+
+       binary_set_uint64(BINARY_PARMS(data, entry), value);
+}
Index: lib/lua/data/data.h
===================================================================
RCS file: lib/lua/data/data.h
diff -N lib/lua/data/data.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/data.h 17 Jan 2014 11:47:53 -0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#ifndef _DATA_H_
+#define _DATA_H_
+
+#ifndef _KERNEL
+#include <stddef.h>
+#include <stdbool.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <lua.h>
+
+#include "layout.h"
+
+#define DATA_LIB       "data"
+#define DATA_USERDATA  "data.data"
+
+typedef struct {
+       void  *ptr;
+       size_t size;
+       size_t length;
+       int    layout;
+       bool   free;
+} data_t;
+
+data_t * data_new(lua_State *, void *, size_t, bool);
+
+data_t * data_check(lua_State *, int);
+
+void data_apply_layout(lua_State *, data_t *, int);
+
+int data_get_field(lua_State *, data_t *, int);
+
+void data_set_field(lua_State *, data_t *, int, lua_Integer);
+
+#endif /* _DATA_H_ */
Index: lib/lua/data/filter.lua
===================================================================
RCS file: lib/lua/data/filter.lua
diff -N lib/lua/data/filter.lua
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/filter.lua     17 Jan 2014 11:47:53 -0000
@@ -0,0 +1,20 @@
+function filter(d)
+       -- store d in a global
+       gd = d
+       d:layout{
+               -- most significant 4-bytes
+               uint4_msb = {0,4},
+               -- inner 16-bytes
+               uint16    = {4, 16},
+               -- least significant 4-bytes
+               uint4_lsb = {20, 4}
+       }
+       return  d.uint4_msb == 0xa    and
+               d.uint16    == 0xbcde and
+               d.uint4_lsb == 0xf
+end
+
+function access_global_data()
+       -- should return nil if ldata_unref(d) has been called from C
+       return gd.uint16
+end
Index: lib/lua/data/layout.c
===================================================================
RCS file: lib/lua/data/layout.c
diff -N lib/lua/data/layout.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/layout.c       17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#include <lauxlib.h>
+
+#include "luautil.h"
+
+#include "layout.h"
+
+inline static layout_entry_t *
+check_entry(lua_State *L, int index)
+{
+       return (layout_entry_t *) luaL_checkudata(L, index, 
LAYOUT_ENTRY_USERDATA);
+}
+
+inline static void
+init_layout(layout_entry_t *entry)
+{
+       entry->offset = 0;
+       entry->length = 0;
+       entry->endian = LAYOUT_ENDIAN_DEFAULT;
+}
+
+static void
+load_endian(lua_State *L, layout_entry_t *entry)
+{
+       const char *endian = lua_tostring(L, -1);
+
+       if (endian[0] == 'n' || endian[0] == 'b')
+               entry->endian = BIG_ENDIAN;
+       else if (endian[0] == 'l')
+               entry->endian = LITTLE_ENDIAN;
+       else if (endian[0] == 'h')
+               entry->endian = BYTE_ORDER;
+}
+
+/* format: {<offset>, <length>, <endian>, <step>} */
+static void
+load_entry_numbered(lua_State *L, layout_entry_t *entry)
+{
+       size_t array_len = lua_objlen(L, -1);
+
+       if (array_len >= 1)
+               entry->offset = luau_getarray_integer(L, -1, 1);
+       if (array_len >= 2)
+               entry->length = luau_getarray_integer(L, -1, 2);
+       if (array_len >= 3) {
+               luau_getarray(L, -1, 3);
+               load_endian(L, entry);
+               lua_pop(L, 1);
+       }
+}
+
+/* format: {offset = <offset>, length = <length>, endian = <endian>, step = 
<step>} */
+static void
+load_entry_named(lua_State *L, layout_entry_t *entry)
+{
+       lua_getfield(L, -1, "offset");
+       if (lua_isnumber(L, -1))
+               entry->offset = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+
+       lua_getfield(L, -1, "length");
+       if (lua_isnumber(L, -1))
+               entry->length = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+
+       lua_getfield(L, -1, "endian");
+       if (lua_isstring(L, -1))
+               load_endian(L, entry);
+       lua_pop(L, 1);
+}
+
+static void
+load_entry(lua_State *L, layout_entry_t *entry)
+{
+       init_layout(entry);
+       load_entry_numbered(L, entry);
+       load_entry_named(L, entry);
+}
+
+static int
+new_entry(lua_State *L, layout_entry_t *entry)
+{
+       layout_entry_t *nentry =
+               (layout_entry_t *) lua_newuserdata(L, sizeof(layout_entry_t));
+
+       luaL_getmetatable(L, LAYOUT_ENTRY_USERDATA);
+       lua_setmetatable(L, -2);
+
+       layout_copy_entry(nentry, entry);
+       return 1;
+}
+
+void
+layout_load(lua_State *L, int index)
+{
+       layout_entry_t entry;
+
+       lua_pushnil(L);  /* first key */
+       while (lua_next(L, index) != 0) {
+               /* uses 'key' (at index -2) and 'value' (at index -1) */
+               load_entry(L, &entry);
+               if (entry.length == 0)
+                       lua_pushnil(L);
+               else
+                       new_entry(L, &entry);
+
+               /* layout[ key ] = entry */
+               luau_settable(L, index, -3, -1);
+
+               /* removes 'value' and 'entry'; keeps 'key' for next iteration 
*/
+               lua_pop(L, 2);
+       }
+
+       lua_pushboolean(L, true);
+       lua_setfield(L, index, LAYOUT_STAMP);
+}
+
+layout_entry_t *
+layout_get_entry(lua_State *L, int layout_ix, int key_ix)
+{
+       void *entry = NULL;
+
+       luau_getref(L, layout_ix);
+       luau_gettable(L, -1, key_ix);
+       if (lua_isnil(L, -1))
+               goto end;
+
+       entry = check_entry(L, -1);
+
+end:
+       lua_pop(L, 2);
+       return entry;
+}
+
+void
+layout_copy_entry(layout_entry_t *dst, layout_entry_t *src)
+{
+       dst->offset = src->offset;
+       dst->length = src->length;
+       dst->endian = src->endian;
+}
Index: lib/lua/data/layout.h
===================================================================
RCS file: lib/lua/data/layout.h
diff -N lib/lua/data/layout.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/layout.h       17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#ifndef _LAYOUT_H_
+#define _LAYOUT_H_
+
+#ifndef _KERNEL
+#include <stdint.h>
+#include <stdbool.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <sys/endian.h>
+
+#include <lua.h>
+
+#define LAYOUT_ENTRY_USERDATA  "data.layout.entry"
+
+#define LAYOUT_STAMP           "__layout_stamp"
+
+#define LAYOUT_ENDIAN_DEFAULT  BIG_ENDIAN
+
+typedef struct {
+       size_t  offset;
+       size_t  length;
+       int     endian;
+} layout_entry_t;
+
+void layout_load(lua_State *, int);
+
+layout_entry_t * layout_get_entry(lua_State *, int, int);
+
+void layout_copy_entry(layout_entry_t *, layout_entry_t *);
+
+#endif /* _LAYOUT_H_ */
Index: lib/lua/data/luadata.c
===================================================================
RCS file: lib/lua/data/luadata.c
diff -N lib/lua/data/luadata.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/luadata.c      17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2013, 2014 Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "luadata.h"
+
+#include "luautil.h"
+
+#include "data.h"
+#include "layout.h"
+
+static int
+new_data(lua_State *L)
+{
+       if(!lua_istable(L, 1))
+               return 0;
+
+       size_t len   = lua_objlen(L, 1);
+       char   *data = (char *) luau_malloc(L, len);
+
+       size_t i = 0;
+       lua_pushnil(L);  /* first key */
+       while (lua_next(L, 1) != 0 && i < len) {
+               /* uses 'key' (at index -2) and 'value' (at index -1) */
+               data[ i++ ] = (char) lua_tointeger(L, -1);
+               /* removes 'value'; keeps 'key' for next iteration */
+               lua_pop(L, 1);
+       }
+       data_new(L, (void *) data, len, true);
+
+       return 1;
+}
+
+static int
+new_layout(lua_State *L)
+{
+       if (!lua_istable(L, 1))
+               return 0;
+
+       layout_load(L, 1);
+       return 1;
+}
+
+static int
+apply_layout(lua_State *L)
+{
+       data_t *data = data_check(L, 1);
+
+       if (!lua_istable(L, 2))
+               return 0;
+
+       lua_getfield(L, 2, LAYOUT_STAMP);
+       bool is_layout = (bool) lua_toboolean(L, -1);
+       lua_pop(L, 1);
+
+       if (!is_layout)
+               layout_load(L, 2);
+
+       data_apply_layout(L, data, 2);
+
+       /* return data object */
+       lua_pushvalue(L, 1);
+       return 1;
+}
+
+static int
+gc(lua_State *L)
+{
+       data_t *data = data_check(L, 1);
+
+       if (data->free)
+               luau_free(L, data->ptr, data->size);
+       return 0;
+}
+
+static int
+get_field(lua_State *L)
+{
+       data_t *data = data_check(L, 1);
+
+       lua_getmetatable(L, 1);
+       if (lua_isstring(L, 2)) {
+               /* try object-oriented access first */
+               luau_gettable(L, -1, 2);
+               if (lua_iscfunction(L, -1))
+                       /* return this method */
+                       return 1;
+               lua_pop(L, 1);
+       }
+
+       return data_get_field(L, data, 2);
+}
+
+static int
+set_field(lua_State *L)
+{
+       data_t *data = data_check(L, 1);
+
+       lua_getmetatable(L, 1);
+       if (lua_isstring(L, 2)) {
+               /* try object-oriented access first */
+               luau_gettable(L, -1, 2);
+               if (lua_iscfunction(L, -1)) {
+                       /* shouldn't overwrite a method */
+                       lua_pop(L, 1);
+                       return 0;
+               }
+       }
+
+       lua_Integer value = lua_tointeger(L, 3);
+
+       data_set_field(L, data, 2, value);
+       return 0;
+}
+
+static const luaL_Reg data_lib[ ] = {
+       {"new"  , new_data},
+       {"layout", new_layout},
+       {NULL    , NULL}
+};
+
+static const luaL_Reg data_m[ ] = {
+       {"layout"    , apply_layout},
+       {"__index"   , get_field},
+       {"__newindex", set_field},
+       {"__gc"      , gc},
+       {NULL        , NULL}
+};
+
+static const luaL_Reg layout_entry_m[ ] = {
+       {NULL, NULL}
+};
+
+int
+luaopen_data(lua_State *L);
+
+int
+luaopen_data(lua_State *L)
+{
+       luaL_newmetatable(L, DATA_USERDATA);
+       luaL_register(L, NULL, data_m);
+       luaL_register(L, DATA_LIB, data_lib);
+
+       luaL_newmetatable(L, LAYOUT_ENTRY_USERDATA);
+       luaL_register(L, NULL, layout_entry_m);
+
+       return 1;
+}
+
+int
+ldata_newref(lua_State *L, void *ptr, size_t size)
+{
+       data_new(L, ptr, size, false);
+       /* keep the new data object on the stack */
+       lua_pushvalue(L, -1);
+       return luau_ref(L);
+}
+
+void
+ldata_unref(lua_State *L, int r)
+{
+       luau_getref(L, r);
+       data_t *data = data_check(L, -1);
+
+       data->ptr = NULL;
+
+       lua_pop(L, 1);
+       luau_unref(L, r);
+}
+
+#ifdef _MODULE
+#include <sys/lua.h>
+#include <sys/module.h>
+
+MODULE(MODULE_CLASS_MISC, luadata, "lua");
+
+typedef int (*kluaopen_t)(void *) ;
+
+static int
+luadata_modcmd(modcmd_t cmd, void *opaque)
+{
+       int error;
+
+       switch (cmd) {
+       case MODULE_CMD_INIT:
+               error = lua_mod_register(DATA_LIB, (kluaopen_t) luaopen_data);
+               break;
+       case MODULE_CMD_FINI:
+               error = lua_mod_unregister(DATA_LIB);
+               break;
+       default:
+               error = ENOTTY;
+       }
+       return error;
+}
+#endif
Index: lib/lua/data/luadata.h
===================================================================
RCS file: lib/lua/data/luadata.h
diff -N lib/lua/data/luadata.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/luadata.h      17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#ifndef _LUA_DATA_H_
+#define _LUA_DATA_H_
+
+#ifndef _KERNEL
+#include <stddef.h>
+#include <stdbool.h>
+#endif
+
+#include <lua.h>
+
+extern int ldata_newref(lua_State *, void *, size_t);
+
+extern void ldata_unref(lua_State *, int);
+
+extern int luaopen_data(lua_State *L);
+
+#endif /* _LUA_DATA_H_ */
Index: lib/lua/data/luautil.c
===================================================================
RCS file: lib/lua/data/luautil.c
diff -N lib/lua/data/luautil.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/luautil.c      17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, 2014, Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#include "luautil.h"
+
+inline static void
+adjust_index(int *index, int factor)
+{
+       if (*index < 0)
+               (*index) -= factor;
+}
+
+void
+luau_getarray(lua_State *L, int index, lua_Integer n)
+{
+       lua_pushinteger(L, n);
+       adjust_index(&index, 1);
+       lua_gettable(L, index);
+}
+
+lua_Integer
+luau_getarray_integer(lua_State *L, int index, lua_Integer n)
+{
+       luau_getarray(L, index, n);
+       lua_Integer result = lua_tointeger(L, -1);
+       lua_pop(L, 1);
+       return result;
+}
+
+void
+luau_gettable(lua_State *L, int index, int field_index)
+{
+       lua_pushvalue(L, field_index);
+       adjust_index(&index, 1);
+       lua_gettable(L, index);
+}
+
+void
+luau_settable(lua_State *L, int index, int field_index, int value_index)
+{
+       lua_pushvalue(L, field_index);
+       adjust_index(&value_index, 1);
+       lua_pushvalue(L, value_index);
+       adjust_index(&index, 2);
+       lua_settable(L, index);
+}
+
+void *
+luau_malloc(lua_State *L, size_t size)
+{
+       void * ud = NULL;
+       lua_Alloc alloc = lua_getallocf(L, &ud);
+       return alloc(ud, NULL, 0, size);
+}
+
+void
+luau_free(lua_State *L, void * ptr, size_t size)
+{
+       void * ud = NULL;
+       lua_Alloc alloc = lua_getallocf(L, &ud);
+       alloc(ud, ptr, size, 0);
+}
Index: lib/lua/data/luautil.h
===================================================================
RCS file: lib/lua/data/luautil.h
diff -N lib/lua/data/luautil.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/luautil.h      17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013, 2014 Lourival Vieira Neto <lneto%NetBSD.org@localhost>.
+ * 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.
+ * 3. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 REGENTS 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.
+ */
+#ifndef _LUA_UTIL_H_
+#define _LUA_UTIL_H_
+
+#ifndef _KERNEL
+#include <stddef.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#define luau_isvalidref(ref)   (ref != LUA_REFNIL && ref != LUA_NOREF)
+
+#define luau_ref(L)            luaL_ref(L, LUA_REGISTRYINDEX)
+#define luau_unref(L, r)       luaL_unref(L, LUA_REGISTRYINDEX, r)
+#define luau_getref(L, r)      lua_rawgeti(L, LUA_REGISTRYINDEX, r)
+
+void luau_getarray(lua_State *, int, lua_Integer);
+
+lua_Integer luau_getarray_integer(lua_State *, int, lua_Integer);
+
+void luau_gettable(lua_State *, int, int);
+
+void luau_settable(lua_State *, int, int, int);
+
+void * luau_malloc(lua_State *, size_t);
+
+void luau_free(lua_State *, void *, size_t);
+
+#endif /* _LUA_UTIL_H_ */
Index: lib/lua/data/test.c
===================================================================
RCS file: lib/lua/data/test.c
diff -N lib/lua/data/test.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/test.c 17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "luadata.h"
+
+typedef unsigned char byte_t;
+
+int main(void)
+{
+       /* create a new Lua state */
+       lua_State *L = luaL_newstate();
+
+       /* open luadata library */
+       luaopen_data(L);
+
+       /* load a script */
+       if (luaL_dofile(L, "filter.lua") != 0)
+               goto err;
+       
+       /* get the filter function */
+       lua_getglobal(L, "filter");
+
+       /* create a new data ptr */
+       size_t  data_size = 3;
+       byte_t *data_ptr  = (byte_t *) malloc(data_size);
+       data_ptr[0] = 0xAB;
+       data_ptr[1] = 0xCD;
+       data_ptr[2] = 0xEF;
+
+       /* create a new data object */
+       int rd = ldata_newref(L, data_ptr, data_size);
+
+       /* call filter(d)*/
+       if (lua_pcall(L, 1, 1, 0) != 0)
+               goto err;
+
+       /* get filter result */
+       bool passed = (bool) lua_toboolean(L, -1);
+
+       /* unregister the Lua data object */
+       ldata_unref(L, rd);
+
+       /* now we can safely free the data pointer */
+       free(data_ptr);
+
+       /* get the access_global_data function */
+       lua_getglobal(L, "access_global_data");
+
+       /* call access_global_data() */
+       if (lua_pcall(L, 0, 1, 0) != 0)
+               goto err;
+
+       /* if global access returned nil and filter has passed; then test 
passed */
+       if (lua_isnil(L, -1) && passed)
+               printf("test passed ;-)\n");
+
+       return 0;
+err:
+       return 1;
+}
+
Index: lib/lua/data/test.lua
===================================================================
RCS file: lib/lua/data/test.lua
diff -N lib/lua/data/test.lua
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ lib/lua/data/test.lua       17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,45 @@
+require "data"
+
+-- create a new data object
+d1 = data.new{0x0f}
+
+-- create and apply a data layout
+d1:layout{byte = {0, 8}, lsb = {7, 1}}
+
+-- access the whole byte 
+assert(d1.byte == 0x0f)
+
+-- set 0 to the least significant bit
+d1.lsb = 0
+
+-- access the whole byte again
+assert(d1.byte == 0x0e)
+
+-- create a new layout
+l = data.layout{
+       uint16be = {0, 16},
+       uint16le = {0, 16, 'l'},
+       uint4    = {16, 4},
+       uint9    = {20, 9},
+       overflow = {32, 1},
+}
+
+-- create a new data object
+d2 = data.new{0xaa, 0xbb, 0xcc, 0xdd}
+
+-- apply the layout 'l' to data 'd2'
+d2:layout(l)
+
+-- access 2 bytes using big-endian ordering
+assert(d2.uint16be == 0xaabb)
+
+-- access 2 bytes using little-endian ordering
+assert(d2.uint16le == 0xbbaa)
+
+-- access 4 bits 
+assert(d2.uint4 == 0xc)
+
+-- access out of bounds
+assert(d2.overflow == nil)
+
+print("test passed ;-)")
Index: sys/modules/luadata/Makefile
===================================================================
RCS file: sys/modules/luadata/Makefile
diff -N sys/modules/luadata/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/modules/luadata/Makefile        17 Jan 2014 11:47:54 -0000
@@ -0,0 +1,18 @@
+.include       "../Makefile.inc"
+
+.PATH:         ${S}/../lib/lua/data
+
+KMOD=          luadata
+
+SRCS=          luadata.c
+SRCS+=         data.c
+SRCS+=         layout.c
+SRCS+=         luautil.c
+SRCS+=         binary.c
+
+CPPFLAGS+=     -I${S}/../external/mit/lua/dist/src
+CPPFLAGS+=     -I${S}/modules/lua 
+CPPFLAGS+=     -I${S}/sys
+
+.include <bsd.kmodule.mk>
+


Home | Main Index | Thread Index | Old Index