Просмотр исходного кода

Add some extensions to squirrel
sq_axtls is to provide a glue with the lightweight AXTLS library
sqbase64 is a port of lbase64 from a Lua extension
sq_sqlite3 is an sqlite3 module to squirrel
sqmix is a port of luamix template module for Lua

mingodad 13 лет назад
Родитель
Сommit
d741b7b403
5 измененных файлов с 2966 добавлено и 0 удалено
  1. 355 0
      ext/code_mix_prep.c
  2. 461 0
      ext/sq_axtls.c
  3. 1864 0
      ext/sq_sqlite3.cpp
  4. 150 0
      ext/sqbase64.cpp
  5. 136 0
      ext/sqmix.cpp

+ 355 - 0
ext/code_mix_prep.c

@@ -0,0 +1,355 @@
+/* Copyright (c) 2007-2008 Thomas Lavergne
+ *
+ * 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.
+ *
+ * Adapted by Domingo Alvarez Duarte
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef MixInteger
+#define MixInteger int
+#endif
+
+#define mix_tempsize 4096
+
+static const char *err_badeof = "unexpected end of file";
+
+enum mix_token_e {
+	tok_sh,
+	tok_code_start, tok_code_end, tok_expr_start, tok_expr_end,
+	tok_data, tok_code, tok_expr,
+	tok_eof
+};
+
+typedef struct mix_state_s {
+	size_t      size;
+	const char *buffer;
+
+	const char *code_start;
+	size_t      code_startsize;
+	const char *code_end;
+	size_t      code_endsize;
+	const char *expr;
+	size_t      exprsize;
+	char       print_out[64];
+	size_t      print_outsize;
+
+	size_t      pos;
+	int         token;
+	char        temp[mix_tempsize];
+
+	char        sq_reader_buf[mix_tempsize];
+	char        *sq_reader_last_pos;
+	char        *sq_reader_pos;
+
+	const char *error;
+	MixInteger result_size, result_pos;
+	const char *result;
+	size_t new_lines;
+} mix_state_t;
+
+/* Read an open bracket of the form [=*[ and return the number of = found.
+ * if there is no string like this at the current pos return -1.
+ * after this call the cursor is set at the first char after the bracket.
+ */
+static int mix_bracket_open(mix_state_t *S) {
+	size_t pos, cnt;
+	if (S->buffer[S->pos] != '[')
+		return -1;
+	pos = S->pos + 1;
+	cnt = 0;
+	while (pos < S->size && S->buffer[pos] == '=')
+		++pos, ++cnt;
+	if (pos == S->size || S->buffer[pos] != '[')
+		return -1;
+	S->pos = pos + 1;
+	return cnt;
+}
+
+/* Read a close bracket of the form ]=*] and return the number of = found.
+ * if there is no string like this at the current pos return -1.
+ * after this call the cursor is set at the first char after the bracket.
+ */
+static int mix_bracket_close(mix_state_t *S) {
+	size_t pos, cnt;
+	if (S->buffer[S->pos] != ']')
+		return -1;
+	pos = S->pos + 1;
+	cnt = 0;
+	while (pos < S->size && S->buffer[pos] == '=')
+		++pos, ++cnt;
+	if (pos == S->size || S->buffer[pos] != ']')
+		return -1;
+	S->pos = pos + 1;
+	return cnt;
+}
+
+/* Skip a lua string enclosed by type (who can be either \" or \') taking
+ * account of escape chars. after a call to this the cursor is set at the
+ * first character after the string.
+ * Beware that on enter the cursor must be on the first char of the string
+ * not on the openning char.
+ */
+static int mix_skip_string(mix_state_t *S, char type) {
+	while (S->pos < S->size) {
+		if (S->buffer[S->pos] == type) {
+			++S->pos;
+			return 0;
+		}
+		if (S->buffer[S->pos] == '\\')
+			++S->pos;
+		++S->pos;
+	}
+	return -1;
+}
+
+/* Skip a lua long string wich is enclosed by square bracket and level = signs
+ * after the call the cursor is set on the first character after the string.
+ * Beware that on enter the cursor must be on the first char of the string
+ * not on the openning bracket.
+ */
+static int mix_skip_lstring(mix_state_t *S, int level) {
+	while (S->pos < S->size) {
+		int tmp = mix_bracket_close(S);
+		if (tmp == -1)
+			++S->pos;
+		else if (tmp == level)
+			return 0;
+	}
+	return -1;
+}
+
+/* Skip a squirrel comment either one line or long. after the call the cursor is set
+ * to the first character after the coment.
+ * Beware that on enter the cursor must be set on the first char after the //
+ * comment prefix.
+ */
+static int mix_skip_comment(mix_state_t *S) {
+	int level = mix_bracket_open(S);
+	if (level != -1)
+		return mix_skip_string(S, level);
+	while (S->pos < S->size && S->buffer[S->pos] != '\n')
+		++S->pos;
+    ++S->new_lines;
+    return 0;
+}
+
+#define mix_iscode_start(s) (!strncmp((s)->code_start, (s)->buffer + (s)->pos, (s)->code_startsize))
+#define mix_iscode_end(s) (!strncmp((s)->code_end, (s)->buffer + (s)->pos, (s)->code_endsize))
+#define mix_isexpr(s) (!strncmp((s)->expr, (s)->buffer + (s)->pos, (s)->exprsize))
+
+#define result_literal(s) S->result_size = sizeof(s)-1, S->result = s;
+
+static const char * sq_mix_reader_str(void *ud) {
+	mix_state_t *S = (mix_state_t *)ud;
+
+	if (S->error != NULL)
+		return 0;
+
+	/* Data chunk are sent to lua by block cause we must escape some char
+	 * and we cannot modify the buffer itself. So we must use another
+	 * buffer sending escaped block one by one.
+	 * If there is no data to send in the chunk, change the state and go
+	 * directly to the tok_code_start part.
+	 */
+	if (S->token == tok_data) {
+		S->result_size = 0;
+		while (S->pos < S->size) {
+			char c = S->buffer[S->pos];
+			if (c == S->code_start[0])
+				if (mix_iscode_start(S))
+					break;
+			if (c == '\\' || c == '"')
+				S->temp[S->result_size++] = '\\';
+			if (c == '\r' || c == '\n'){
+				S->temp[S->result_size++] = '\\';
+				if(c == '\r') c = 'r';
+				else {
+				    S->new_lines++;
+				    c = 'n';
+				}
+            }
+
+			S->temp[S->result_size++] = c;
+			++S->pos;
+			if (S->result_size >= mix_tempsize - 1) {
+				if (S->pos == S->size)
+					S->token = tok_code_start;
+				return S->result = S->temp;
+			}
+		}
+		if (S->pos < S->size)
+			S->pos += S->code_startsize;
+		S->token = tok_code_start;
+		if (S->result_size != 0)
+			return S->result = S->temp;
+	}
+
+	/* Send the termination of the string and the function call before
+	 * going in tok_code/tok_expr state or if at eof go to tok_eof.
+	 */
+	if (S->token == tok_code_start) {
+		if (S->pos == S->size) {
+			S->token = tok_eof;
+		} else if (mix_isexpr(S)) {
+			S->token = tok_expr_start;
+			S->pos += S->exprsize;
+		} else {
+			S->token = tok_code;
+		}
+		return result_literal("\");");
+	}
+
+	/* Send the output function, but without the string start character, so
+	 * the result of the lua code will be send as parameters to the output
+	 * function.
+	 */
+	if (S->token == tok_expr_start) {
+	    if(S->new_lines){
+	        --S->new_lines;
+	        return result_literal("\n");
+	    }
+		S->token = tok_expr;
+		S->result_size = S->print_outsize - 1;
+		return S->result = S->print_out;
+	}
+
+	/* Send a lua chunk in one block to the lua engine. No escaping are
+	 * needed here so we can send the full block. Then switch to the
+	 * tok_code_end. (this correctly skip all form of lua string and comments)
+	 * If no lua code is found, go directly to the tok_code_end part.
+	 */
+	if (S->token == tok_code || S->token == tok_expr) {
+	    if(S->new_lines){
+	        --S->new_lines;
+	        return result_literal("\n");
+	    }
+		size_t old = S->pos;
+		while (S->pos < S->size) {
+			char c = S->buffer[S->pos];
+			if (c == '\'') {
+				++S->pos;
+				mix_skip_string(S, '\'');
+			} else if (c == '"') {
+				++S->pos;
+				mix_skip_string(S, '"');
+			} else if (c == '[') {
+				int level = mix_bracket_open(S);
+				if (level != -1)
+					mix_skip_lstring(S, level);
+				else
+					++S->pos;
+			} else if (c == '/') {
+				++S->pos;
+				if (S->buffer[S->pos] == '/') {
+					++S->pos;
+					mix_skip_comment(S);
+				}
+			} else if (c == S->code_end[0]) {
+				if (mix_iscode_end(S))
+					break;
+				++S->pos;
+			} else {
+				++S->pos;
+			}
+		}
+		S->result_size = S->pos - old;
+		if (S->pos == S->size) {
+			S->error = err_badeof;
+			return NULL;
+		}
+		S->token = S->token == tok_code ? tok_code_end : tok_expr_end;
+		S->pos += S->code_endsize;
+		if (S->result_size != 0)
+			return S->result = S->buffer + old;
+	}
+
+	/* Send the data output function name and (' that start a data block to
+	 * the lua engine and switch to the tok_data state.
+	 */
+	if (S->token == tok_code_end) {
+	    if(S->new_lines){
+	        --S->new_lines;
+	        return result_literal("\n");
+	    }
+		S->token = tok_data;
+		S->result_size = S->print_outsize;
+		return S->result = S->print_out;
+	}
+
+	/* Close the output function call on end of expression and go to the lua
+	 * to data transition.
+	 */
+	if (S->token == tok_expr_end) {
+		S->token = tok_code_end;
+		return result_literal(");");
+	}
+
+	/* If we skipped a sh-bang line we must send an empty line to keep the
+	 * lua line counter correct.
+	 */
+	if (S->token == tok_sh) {
+		S->token = tok_code_end;
+		++S->new_lines;
+		return result_literal("\n");
+	}
+
+	return NULL;
+}
+
+static MixInteger sq_mix_reader_char(void *ud) {
+	mix_state_t *S = (mix_state_t *)ud;
+
+	if (S->error != NULL) return 0;
+start:
+	if (S->result_size){
+	    MixInteger c = S->result[S->result_pos++];
+	    if(S->result_pos >= S->result_size){
+	        S->result_pos = S->result_size = 0;
+	    }
+	    return c;
+	}
+	if(sq_mix_reader_str(ud)) goto start;
+	return 0;
+}
+
+static void sq_mix_init(mix_state_t *S,
+                        char *buffer, int buffer_size,
+                        const char *print_out,
+                        const char *code_start,
+                        const char *code_end,
+                        const char *expr){
+	memset(S, 0, sizeof(mix_state_t));
+	snprintf(S->print_out, sizeof(S->print_out), "%s(\"",  print_out ? print_out : "mix_write");
+	S->print_outsize = strlen(S->print_out);
+	S->code_start = code_start ? code_start : "{%";
+	S->code_startsize = strlen(S->code_start);
+	S->code_end = code_end ? code_end : "%}";
+	S->code_endsize = strlen(S->code_end);
+	S->expr = expr ? expr : "=";
+	S->exprsize = strlen(S->expr);
+	S->buffer = buffer;
+	S->size = buffer_size;
+	S->token = tok_code_end;
+}
+

+ 461 - 0
ext/sq_axtls.c

@@ -0,0 +1,461 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "squirrel.h"
+#include <stdlib.h>  /* for malloc */
+#include <assert.h>  /* for a few sanity tests */
+
+#define GET_INT(idx, var) int var; sq_getinteger(sqvm, idx, &var)
+#define GET_STR(idx, var) const SQChar *var; sq_getstring(sqvm, idx, &var)
+
+#include "ssl.h"
+
+#define SQ_NETLIBNAME "axtlsl"
+
+typedef struct {
+	SSL_CTX *ptr;
+} SSL_CTX_ptr;
+
+static const char *SSL_CTX_metaTag   = "sq_axtls";
+
+static SSL_CTX_ptr *sq_ssl_get_ctx(HSQUIRRELVM sqvm, int index) {
+    SSL_CTX_ptr *ssl_ctx_ptr = (SSL_CTX_ptr*)luaL_checkudata(sqvm, index, SSL_CTX_metaTag);
+    if (ssl_ctx_ptr == NULL)
+        luaL_argerror(sqvm, index, "bad SSL CONTEXT");
+    if (ssl_ctx_ptr->ptr == NULL)
+        luaL_argerror(sqvm, index, "SSL CONTEXT has NULL value");
+    return ssl_ctx_ptr;
+}
+
+
+typedef struct {
+	SSL *ptr;
+	int free_ptr_on_gc;
+} SSL_ptr;
+
+static const char *SSL_metaTag   = "axtls.ssl";
+
+static SSL_ptr *sq_ssl_get_ssl(HSQUIRRELVM sqvm, int index) {
+    SSL_ptr *ssl_ptr = (SSL_ptr*)luaL_checkudata(sqvm, index, SSL_metaTag);
+    if (ssl_ptr == NULL)
+        luaL_argerror(sqvm, index, "bad SSL");
+    if (ssl_ptr->ptr == NULL)
+        luaL_argerror(sqvm, index, "SSL has NULL value");
+    return ssl_ptr;
+}
+
+
+static int sq_ssl_ctx_new(HSQUIRRELVM sqvm){
+	int options = sq_getinteger(sqvm, 1);
+	int num_sessions = sq_getinteger(sqvm, 2);
+    SSL_CTX *ssl_ctx = ssl_ctx_new(options, num_sessions);
+    if(ssl_ctx) {
+        SSL_CTX_ptr *ssl_ctx_ptr = (SSL_CTX_ptr*)sq_newuserdata(sqvm, sizeof(SSL_CTX_ptr));
+        ssl_ctx_ptr->ptr = ssl_ctx;
+        luaL_newmetatable(sqvm, SSL_CTX_metaTag);
+        sq_setmetatable(sqvm, -2);        /* set metatable */
+    } else sq_pushnil(L);
+
+	return 1;
+}
+
+static int sq_ssl_ctx_free(HSQUIRRELVM sqvm){
+	SSL_CTX_ptr *ssl_ctx_ptr = sq_ssl_get_ctx(sqvm, 1);
+	if(ssl_ctx_ptr->ptr){
+		ssl_ctx_free(ssl_ctx_ptr->ptr);
+		ssl_ctx_ptr->ptr = NULL;
+	}
+	return 0;
+}
+
+static int sq_ssl_server_new(HSQUIRRELVM sqvm){
+	SSL_CTX_ptr *ssl_ctx_ptr = sq_ssl_get_ctx(sqvm, 1);
+	int client_fd = sq_getinteger(sqvm, 2);
+    SSL *ssl = ssl_server_new(ssl_ctx_ptr->ptr, client_fd);
+
+    if(ssl) {
+        SSL_ptr *ssl_ptr = (SSL_ptr*)sq_newuserdata(sqvm, sizeof(SSL_ptr));
+        ssl_ptr->ptr = ssl;
+        ssl_ptr->free_ptr_on_gc = 1;
+
+        luaL_newmetatable(sqvm, SSL_metaTag);
+        sq_setmetatable(sqvm, -2);        /* set metatable */
+    } else sq_pushnil(L);
+
+	return 1;
+}
+
+static int sq_ssl_client_new(HSQUIRRELVM sqvm){
+	SSL_CTX_ptr *ssl_ctx_ptr = sq_ssl_get_ctx(sqvm, 1);
+	int client_fd = sq_getinteger(sqvm, 2);
+	uint8_t *session_id = (uint8_t *)luaL_optstring(sqvm, 3, NULL);
+	uint8_t sess_id_size= luaL_optint(sqvm, 4, 0);
+	SSL *ssl = ssl_client_new(ssl_ctx_ptr->ptr, client_fd, session_id, sess_id_size);
+
+    if(ssl) {
+        SSL_ptr *ssl_ptr = (SSL_ptr*)sq_newuserdata(sqvm, sizeof(SSL_ptr));
+        ssl_ptr->ptr = ssl;
+        ssl_ptr->free_ptr_on_gc = 1;
+
+        luaL_newmetatable(sqvm, SSL_metaTag);
+        sq_setmetatable(sqvm, -2);        /* set metatable */
+    } else sq_pushnil(L);
+
+	return 1;
+}
+
+static int sq_ssl_free(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	if(ssl_ptr->ptr && ssl_ptr->free_ptr_on_gc){
+		ssl_free(ssl_ptr->ptr);
+		ssl_ptr->ptr = NULL;
+	}
+	return 0;
+}
+
+static int sq_ssl_read(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	uint8_t *in_data;
+	int result = ssl_read(ssl_ptr->ptr, &in_data);
+	sq_pushinteger(sqvm, result);
+	int return_params = 1;
+	if (result > SSL_OK) {
+	  sq_pushlstring(sqvm, (char *)in_data, result);
+      return_params++;
+    }
+	return return_params;
+}
+
+static int sq_ssl_write(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	uint8_t *out_data;
+	sq_getstring(sqvm, 2, &out_data);
+	int out_len;
+	if(sq_gettop(sqvm) > 2) sq_getinteger(sqvm, 3, &out_len);
+	else out_len = sq_getsize(sqvm, 2);
+	sq_pushinteger(sqvm, ssl_write(ssl_ptr->ptr, out_data, out_len));
+	return 1;
+}
+
+static int sq_ssl_find(HSQUIRRELVM sqvm){
+	SSL_CTX_ptr *ssl_ctx_ptr = sq_ssl_get_ctx(sqvm, 1);
+	GET_INT(2, client_fd);
+    SSL *ssl = ssl_find(ssl_ctx_ptr->ptr, client_fd);
+
+    if(ssl){
+        SSL_ptr *ssl_ptr = (SSL_ptr*)sq_newuserdata(sqvm, sizeof(SSL_ptr));
+        ssl_ptr->ptr = ssl;
+        //we don't want to free this SSL when collecting garbage
+        ssl_ptr->free_ptr_on_gc = 0;
+
+        luaL_newmetatable(sqvm, SSL_metaTag);
+        sq_setmetatable(sqvm, -2);        /* set metatable */
+    } else sq_pushnil(L);
+
+	return 1;
+}
+
+static int sq_ssl_get_session_id(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	const uint8_t * result = ssl_get_session_id(ssl_ptr->ptr);
+    sq_pushlstring(sqvm, (char *)result, ssl_get_session_id_size(ssl_ptr->ptr));
+	return 1;
+}
+
+static int sq_ssl_get_session_id_size(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	uint8_t result = ssl_get_session_id_size(ssl_ptr->ptr);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_get_cipher_id(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	uint8_t result = ssl_get_cipher_id(ssl_ptr->ptr);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_handshake_status(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	int result = ssl_handshake_status(ssl_ptr->ptr);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_get_config(HSQUIRRELVM sqvm){
+    GET_INT(1, info);
+	sq_pushinteger(sqvm, ssl_get_config(info));
+	return 1;
+}
+
+static int sq_ssl_display_error(HSQUIRRELVM sqvm){
+    GET_INT(1, error);
+	ssl_display_error(error);
+	return 0;
+}
+
+static int sq_ssl_verify_cert(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	int result = ssl_verify_cert(ssl_ptr->ptr);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_get_cert_dn(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	GET_INT(2, component);
+	const char* result = ssl_get_cert_dn(ssl_ptr->ptr, component);
+	sq_pushstring(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_get_cert_subject_alt_dnsname(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	GET_INT(2, dnsindex);
+	const char* result = ssl_get_cert_subject_alt_dnsname(ssl_ptr->ptr, dnsindex);
+	sq_pushstring(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_renegotiate(HSQUIRRELVM sqvm){
+	SSL_ptr *ssl_ptr = sq_ssl_get_ssl(sqvm, 1);
+	int result = ssl_renegotiate(ssl_ptr->ptr);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_obj_load(HSQUIRRELVM sqvm){
+	SSL_CTX_ptr *ssl_ctx_ptr = sq_ssl_get_ctx(sqvm, 1);
+	GET_INT(2, obj_type);
+	GET_STR(3, filename);
+	GET_STR(4, password);
+	int result = ssl_obj_load(ssl_ctx_ptr->ptr, obj_type,filename,password);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_obj_memory_load(HSQUIRRELVM sqvm){
+	SSL_CTX_ptr *ssl_ctx_ptr = sq_ssl_get_ctx(sqvm, 1);
+	GET_INT(2, obj_type);
+	uint8_t *data;
+	sq_getstring(sqvm, 3, &data);
+	GET_INT(4, data_len);
+	GET_STR(5, password);
+	int result = ssl_obj_memory_load(ssl_ctx_ptr->ptr, obj_type,data,data_len, password);
+	sq_pushinteger(sqvm, result);
+	return 1;
+}
+
+static int sq_ssl_version(HSQUIRRELVM sqvm){
+	sq_pushstring(sqvm,(const char*)ssl_version());
+	return 1;
+}
+
+static SQInteger ssl_ctx_release_hook(SQUserPointer p, SQInteger size)
+{
+	ssl_ctx_free((SSL_CTX *)p);
+	return 1;
+}
+
+static SQInteger ssl_ctx_constructor(HSQUIRRELVM sqvm)
+{
+	SQInteger options, num_sessions;
+    sq_getinteger(sqvm, 2, &options);
+    sq_getinteger(sqvm, 3, &num_sessions);
+
+	SSL_CTX *ssl_ctx = ssl_ctx_new(options, num_sessions);
+    if(!ssl_ctx)
+        return sq_throwerror(sqvm, _SC("Could'nt create an ssl context."))
+
+    sq_setinstanceup(sqvm, 1, ssl_ctx);
+    RELEASE_HOOK(sq_setreleasehook(sqvm,1, ssl_ctx_release_hook));
+	return 1;
+}
+
+static SQInteger ssl_release_hook(SQUserPointer p, SQInteger size)
+{
+	ssl_free((SSL *)p);
+	return 1;
+}
+
+static SQInteger ssl_constructor(HSQUIRRELVM sqvm)
+{
+	SQInteger socket_fd, num_sessions;
+    sq_getinteger(sqvm, 2, &options);
+    sq_getinteger(sqvm, 3, &num_sessions);
+
+	SSL *ssl = ssl_new(options, num_sessions);
+    if(!ssl)
+        return sq_throwerror(sqvm, _SC("Could'nt create an ssl server/client."))
+
+    sq_setinstanceup(sqvm, 1, ssl);
+    RELEASE_HOOK(sq_setreleasehook(sqvm,1, ssl_release_hook));
+	return 1;
+}
+
+#define _DECL_FL_FUNC(name,nparams,pmask) {_SC(#name),sq_##name,nparams,pmask}
+static SQRegFunction ssl_ctx_obj_funcs[]={
+	_DECL_FL_BOX_FUNC(constructor,3,_SC("xii")),
+	_DECL_FL_FUNC(server_new,2,_SC("xx")),
+	_DECL_FL_FUNC(client_new,2,_SC("xxii")),
+	_DECL_FL_FUNC(find,2,_SC("tu")),
+	_DECL_FL_FUNC(get_session_id,2,_SC("tu")),
+	_DECL_FL_FUNC(get_session_id_size,2,_SC("tu")),
+	_DECL_FL_FUNC(get_cipher_id,2,_SC("tu")),
+	_DECL_FL_FUNC(handshake_status,2,_SC("tu")),
+	_DECL_FL_FUNC(get_config,2,_SC("tu")),
+	_DECL_FL_FUNC(display_error,2,_SC("tu")),
+	_DECL_FL_FUNC(verify_cert,2,_SC("tu")),
+	_DECL_FL_FUNC(get_cert_dn,2,_SC("tu")),
+	_DECL_FL_FUNC(get_cert_subject_alt_dnsname,2,_SC("tu")),
+	_DECL_FL_FUNC(renegotiate,2,_SC("tu")),
+	_DECL_FL_FUNC(obj_load,2,_SC("tu")),
+	_DECL_FL_FUNC(obj_memory_load,2,_SC("tu")),
+	_DECL_FL_FUNC(version,2,_SC("tu")),
+	{0,0}
+};
+#undef _DECL_FL_FUNC
+
+#define _DECL_FL_FUNC(name,nparams,pmask) {_SC(#name),sq_##name,nparams,pmask}
+static SQRegFunction ssl_obj_funcs[]={
+	_DECL_FL_FUNC(ctx_new,3,_SC("tii")),
+	_DECL_FL_FUNC(ctx_free,2,_SC("tu")),
+	_DECL_FL_FUNC(server_new,2,_SC("tu")),
+	_DECL_FL_FUNC(client_new,2,_SC("tu")),
+	_DECL_FL_FUNC(free,2,_SC("tu")),
+	_DECL_FL_FUNC(read,2,_SC("tu")),
+	_DECL_FL_FUNC(write,2,_SC("tu")),
+	_DECL_FL_FUNC(find,2,_SC("tu")),
+	_DECL_FL_FUNC(get_session_id,2,_SC("tu")),
+	_DECL_FL_FUNC(get_session_id_size,2,_SC("tu")),
+	_DECL_FL_FUNC(get_cipher_id,2,_SC("tu")),
+	_DECL_FL_FUNC(handshake_status,2,_SC("tu")),
+	_DECL_FL_FUNC(get_config,2,_SC("tu")),
+	_DECL_FL_FUNC(display_error,2,_SC("tu")),
+	_DECL_FL_FUNC(verify_cert,2,_SC("tu")),
+	_DECL_FL_FUNC(get_cert_dn,2,_SC("tu")),
+	_DECL_FL_FUNC(get_cert_subject_alt_dnsname,2,_SC("tu")),
+	_DECL_FL_FUNC(renegotiate,2,_SC("tu")),
+	_DECL_FL_FUNC(obj_load,2,_SC("tu")),
+	_DECL_FL_FUNC(obj_memory_load,2,_SC("tu")),
+	_DECL_FL_FUNC(version,2,_SC("tu")),
+	{0,0}
+};
+#undef _DECL_FL_FUNC
+
+typedef struct {
+  const SQChar *Str;
+  SQInteger Val;
+} KeyIntType, * KeyIntPtrType;
+
+static KeyIntType axtls_constants[] = {
+    #define MK_CONST(c) {_SC(#c), c}
+    MK_CONST(SSL_SESSION_ID_SIZE),
+    MK_CONST(SSL_CLIENT_AUTHENTICATION),
+    MK_CONST(SSL_SERVER_VERIFY_LATER),
+    MK_CONST(SSL_NO_DEFAULT_KEY),
+    MK_CONST(SSL_DISPLAY_STATES),
+    MK_CONST(SSL_DISPLAY_BYTES),
+    MK_CONST(SSL_DISPLAY_CERTS),
+    MK_CONST(SSL_DISPLAY_RSA),
+    MK_CONST(SSL_CONNECT_IN_PARTS),
+    MK_CONST(SSL_OK),
+    MK_CONST(SSL_NOT_OK),
+    MK_CONST(SSL_ERROR_DEAD),
+    MK_CONST(SSL_CLOSE_NOTIFY),
+    MK_CONST(SSL_ERROR_CONN_LOST),
+    MK_CONST(SSL_ERROR_SOCK_SETUP_FAILURE),
+    MK_CONST(SSL_ERROR_INVALID_HANDSHAKE),
+    MK_CONST(SSL_ERROR_INVALID_PROT_MSG),
+    MK_CONST(SSL_ERROR_INVALID_HMAC),
+    MK_CONST(SSL_ERROR_INVALID_VERSION),
+    MK_CONST(SSL_ERROR_INVALID_SESSION),
+    MK_CONST(SSL_ERROR_NO_CIPHER),
+    MK_CONST(SSL_ERROR_BAD_CERTIFICATE),
+    MK_CONST(SSL_ERROR_INVALID_KEY),
+    MK_CONST(SSL_ERROR_FINISHED_INVALID),
+    MK_CONST(SSL_ERROR_NO_CERT_DEFINED),
+    MK_CONST(SSL_ERROR_NO_CLIENT_RENOG),
+    MK_CONST(SSL_ERROR_NOT_SUPPORTED),
+    MK_CONST(SSL_X509_OFFSET),
+    MK_CONST(SSL_ALERT_TYPE_WARNING),
+    MK_CONST(SLL_ALERT_TYPE_FATAL),
+    MK_CONST(SSL_ALERT_CLOSE_NOTIFY),
+    MK_CONST(SSL_ALERT_UNEXPECTED_MESSAGE),
+    MK_CONST(SSL_ALERT_BAD_RECORD_MAC),
+    MK_CONST(SSL_ALERT_HANDSHAKE_FAILURE),
+    MK_CONST(SSL_ALERT_BAD_CERTIFICATE),
+    MK_CONST(SSL_ALERT_ILLEGAL_PARAMETER),
+    MK_CONST(SSL_ALERT_DECODE_ERROR),
+    MK_CONST(SSL_ALERT_DECRYPT_ERROR),
+    MK_CONST(SSL_ALERT_INVALID_VERSION),
+    MK_CONST(SSL_ALERT_NO_RENEGOTIATION),
+    MK_CONST(SSL_AES128_SHA),
+    MK_CONST(SSL_AES256_SHA),
+    MK_CONST(SSL_RC4_128_SHA),
+    MK_CONST(SSL_RC4_128_MD5),
+    MK_CONST(SSL_BUILD_SKELETON_MODE),
+    MK_CONST(SSL_BUILD_SERVER_ONLY),
+    MK_CONST(SSL_BUILD_ENABLE_VERIFICATION),
+    MK_CONST(SSL_BUILD_ENABLE_CLIENT),
+    MK_CONST(SSL_BUILD_FULL_MODE),
+    MK_CONST(SSL_BUILD_MODE),
+    MK_CONST(SSL_MAX_CERT_CFG_OFFSET),
+    MK_CONST(SSL_MAX_CA_CERT_CFG_OFFSET),
+    MK_CONST(SSL_HAS_PEM),
+    MK_CONST(SSL_DEFAULT_SVR_SESS),
+    MK_CONST(SSL_DEFAULT_CLNT_SESS),
+    MK_CONST(SSL_X509_CERT_COMMON_NAME),
+    MK_CONST(SSL_X509_CERT_ORGANIZATION),
+    MK_CONST(SSL_X509_CERT_ORGANIZATIONAL_NAME),
+    MK_CONST(SSL_X509_CA_CERT_COMMON_NAME),
+    MK_CONST(SSL_X509_CA_CERT_ORGANIZATION),
+    MK_CONST(SSL_X509_CA_CERT_ORGANIZATIONAL_NAME),
+    MK_CONST(SSL_OBJ_X509_CERT),
+    MK_CONST(SSL_OBJ_X509_CACERT),
+    MK_CONST(SSL_OBJ_RSA_KEY),
+    MK_CONST(SSL_OBJ_PKCS8),
+    MK_CONST(SSL_OBJ_PKCS12),
+    {0,0}
+};
+
+/* This defines a function that opens up your library. */
+SQRESULT sq_register_axtlsl (HSQUIRRELVM sqvm) {
+    //add constants
+    sq_pushconsttable(sqvm);    //get the constants table first
+    for (KeyIntPtrType KeyIntPtr = axtls_constants; KeyIntPtr->Str; KeyIntPtr++) {
+        sq_pushstring(sqvm, KeyIntPtr->Str, -1);    //first the key
+        sq_pushinteger(sqvm, KeyIntPtr->Val);       //then the value
+        sq_newslot(sqvm, -3, SQFalse);              //store then
+    }
+    sq_poptop(sqvm); //pop remove constants table when we finished
+
+    //add a namespace axtls
+	sq_pushstring(sqvm,_SC("axtls"),-1);
+	sq_newtable(sqvm);
+
+    //now create the SSL Context class
+	sq_pushstring(sqvm,_SC("ssl_ctx"),-1);
+	sq_newclass(sqvm,SQFalse);
+	sq_settypetag(sqvm,-1,(void*)SSL_CTX_TAG(Fl));
+	insertFuncs(sqvm, ssl_ctx_obj_funcs);
+	sq_newslot(sqvm,-3,SQFalse);
+
+    //now create the SSL class
+	sq_pushstring(sqvm,_SC("ssl"),-1);
+	sq_newclass(sqvm,SQFalse);
+	sq_settypetag(sqvm,-1,(void*)SSL_TAG(Fl));
+	insertFuncs(sqvm, ssl_obj_funcs);
+	sq_newslot(sqvm,-3,SQFalse);
+
+	sq_newslot(sqvm,-3,SQFalse); //add axtls table to the root table
+    sq_poptop(sqvm); //removes axtls table
+
+    return SQ_OK;
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 1864 - 0
ext/sq_sqlite3.cpp

@@ -0,0 +1,1864 @@
+/* Code generated by script */
+#include "squirrel.h"
+#include "sqlite3.h"
+#include <string.h>
+#include <stdio.h>
+#include "sqstdblobimpl.h"
+
+typedef struct sq_sqlite3_sdb sq_sqlite3_sdb;
+typedef struct sq_sqlite3_sdb_func sq_sqlite3_sdb_func;
+
+/* to use as C user data so i know what function sqlite is calling */
+struct sq_sqlite3_sdb_func {
+    /* references to associated lua values */
+    HSQOBJECT fn_step;
+    HSQOBJECT fn_finalize;
+    HSQOBJECT udata;
+
+    sq_sqlite3_sdb *sdb;
+    sq_sqlite3_sdb_func *next;
+};
+
+/* information about database */
+struct sq_sqlite3_sdb {
+    /* associated squirrel vm */
+    HSQUIRRELVM v;
+    /* sqlite database handle */
+    sqlite3 *db;
+
+    /* sql functions stack usage */
+    sq_sqlite3_sdb_func *func;         /* top SQL function being called */
+
+    /* references */
+    HSQOBJECT busy_cb;        /* busy callback */
+    HSQOBJECT busy_udata;
+
+    HSQOBJECT progress_cb;    /* progress handler */
+    HSQOBJECT progress_udata;
+
+    HSQOBJECT trace_cb;       /* trace callback */
+    HSQOBJECT trace_udata;
+    HSQOBJECT null_value;
+};
+
+SQ_OPT_STRING_STRLEN();
+
+static const SQChar *SQLite3_TAG = "sqlite3";
+static const SQChar *SQLite3_Stmt_TAG = "sqlite3_stmt";
+
+static const SQChar sqlite3_NULL_Name[] = _SC("sqlite3_NULL");
+static const SQChar nullName[] = _SC("NULL");
+static SQRESULT sqlite3_NULL_tostring(HSQUIRRELVM v){
+    sq_pushstring(v, "", 0);
+    return 1;
+}
+SQRegFunction sqlite3_NULL_methods[]={
+	{_SC("_tostring"),sqlite3_NULL_tostring,1, _SC(".")},
+	{0,0}
+};
+//#define push_sqlite3_null(v) sq_getonregistrytable(v, sqlite3_NULL_Name, sizeof(sqlite3_NULL_Name)-1);
+//#define push_sqlite3_null(v) sq_pushobject(v, sqlite3_NULL);
+//#define push_sqlite3_null(v) sq_getbyname(v, 1, nullName, sizeof(nullName)-1)
+//#define push_sqlite3_null(v) sq_pushfromregistrytable(v, nullName, sizeof(nullName)-1)
+//#define push_sqlite3_null(v) {sq_pushregistrytable(v);sq_pushstring(v, sqlite3_NULL_Name, sizeof(sqlite3_NULL_Name)-1);sq_get(v, -2);sq_remove(v,-2);}
+//the line bellow is the fastest one, any other attempt till now was slower
+#define push_sqlite3_null(v) {sq_pushstring(v, nullName, sizeof(nullName)-1);sq_get(v, 1);}
+
+#define GET_sqlite3_INSTANCE_AT(idx) \
+	sq_sqlite3_sdb *sdb; \
+	if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)&sdb,(void*)SQLite3_TAG)) < 0) return _rc_;\
+	sqlite3 *self = sdb->db;
+
+#define GET_sqlite3_INSTANCE() GET_sqlite3_INSTANCE_AT(1)
+
+//#define GET_sqlite3_INSTANCE() SQ_GET_INSTANCE(v, 1, sqlite3, SQLite3_TAG)
+#define GET_sqlite3_stmt_INSTANCE() SQ_GET_INSTANCE(v, 1, sqlite3_stmt, SQLite3_Stmt_TAG)
+
+enum e_type_result {tr_first_row_first_col, tr_first_row, tr_all_rows, tr_ddml};
+
+#define AS_STRING_ALWAYS 0x01
+#define NULL_AS_EMPTY_STR 0x02
+
+static void sqlite3_stmt_push_string(HSQUIRRELVM v, sqlite3_stmt *stmt, int col, int flags){
+    const char *value = (const char*) sqlite3_column_text(stmt, col);
+    if(value) sq_pushstring(v, value, sqlite3_column_bytes(stmt, col));
+    else push_sqlite3_null(v);
+}
+
+static SQRESULT sqlite3_stmt_push_value(HSQUIRRELVM v, sqlite3_stmt *stmt, int col, int flags){
+    const char *value;
+
+    if(flags & AS_STRING_ALWAYS) sqlite3_stmt_push_string(v, stmt, col, flags);
+    else
+    {
+        switch (sqlite3_column_type(stmt, col)) {
+            case SQLITE_INTEGER:
+                {
+                    sqlite_int64 i64 = sqlite3_column_int64(stmt, col);
+                    SQInteger n = (SQInteger)i64;
+                    if (n == i64)
+                        sq_pushinteger(v, n);
+                    else
+                        sq_pushstring(v, (const char*) sqlite3_column_text(stmt, col), sqlite3_column_bytes(stmt, col));
+                }
+                break;
+            case SQLITE_FLOAT:
+                sq_pushfloat(v, sqlite3_column_double(stmt, col));
+                break;
+            case SQLITE_TEXT:
+                sqlite3_stmt_push_string(v, stmt, col, flags);
+                break;
+            case SQLITE_BLOB:
+                value = (const char*) sqlite3_column_blob(stmt, col);
+                if(value) sq_pushstring(v, value, sqlite3_column_bytes(stmt, col));
+                else push_sqlite3_null(v);
+                break;
+            case SQLITE_NULL:
+                push_sqlite3_null(v);
+                break;
+            default:
+                push_sqlite3_null(v);
+                break;
+        }
+    }
+    return 1;
+}
+
+static void sqlite3_stmt_row_asArray(HSQUIRRELVM v, sqlite3_stmt *stmt, int flags){
+    int col_count = sqlite3_column_count(stmt);
+    sq_newarray(v, col_count);
+    for(int i=0; i<col_count; ++i){
+        sq_pushinteger(v, i);
+        sqlite3_stmt_push_value(v, stmt, i, flags);
+        sq_rawset(v, -3);
+    }
+}
+
+static void sqlite3_stmt_row_asTable(HSQUIRRELVM v, sqlite3_stmt *stmt, int flags){
+    int col_count = sqlite3_column_count(stmt);
+    sq_newtable(v);
+    for(int i=0; i<col_count; ++i){
+        sq_pushstring(v, sqlite3_column_name(stmt, i), -1);
+        sqlite3_stmt_push_value(v, stmt, i, flags);
+        sq_rawset(v, -3);
+    }
+}
+
+static void sqlite3_stmt_asArrayOfArrays(HSQUIRRELVM v, sqlite3_stmt *stmt, int flags){
+    sq_newarray(v, 0);
+    while(sqlite3_step(stmt) == SQLITE_ROW){
+        sqlite3_stmt_row_asArray(v, stmt, flags);
+        sq_arrayappend(v, -2);
+    }
+}
+
+static void sqlite3_stmt_asArrayOfTables(HSQUIRRELVM v, sqlite3_stmt *stmt, int flags){
+    sq_newarray(v, 0);
+    while(sqlite3_step(stmt) == SQLITE_ROW){
+        sqlite3_stmt_row_asTable(v, stmt, flags);
+        sq_arrayappend(v, -2);
+    }
+}
+
+static SQRESULT sqlite3_stmt_bind_value(HSQUIRRELVM v, sqlite3_stmt *stmt, int npar, int argn){
+    int _rc_;
+    SQObjectType ptype = sq_gettype(v, argn);
+    switch(ptype){
+        case OT_BOOL:
+            SQ_GET_BOOL(v, argn, param_bool);
+            _rc_ = sqlite3_bind_int(stmt, npar, param_bool ? 1 : 0);
+            break;
+        case OT_INTEGER:
+            SQ_GET_INTEGER(v, argn, param_integer);
+            _rc_ = sqlite3_bind_int64(stmt, npar, param_integer);
+            break;
+        case OT_FLOAT:
+            SQ_GET_FLOAT(v, argn, param_float);
+            _rc_ = sqlite3_bind_double(stmt, npar, param_float);
+            break;
+        case OT_STRING:
+            SQ_GET_STRING(v, argn, param_string);
+            _rc_ = sqlite3_bind_text(stmt, npar, param_string, param_string_size, 0);
+            break;
+        case OT_NULL:
+            _rc_ = sqlite3_bind_null(stmt, npar);
+            break;
+        default:
+            return sq_throwerror(v, "Invalid bind parameter %d", npar);
+    }
+    return 1;
+}
+
+static SQRESULT sqlite3_stmt_prepare(HSQUIRRELVM v, sqlite3 *db, sqlite3_stmt **stmt, int params_start){
+    SQ_FUNC_VARS(v);
+	SQ_GET_STRING(v, params_start, szSQL);
+	const char* szTail=0;
+    if(sqlite3_prepare_v2(db, szSQL, -1, stmt, &szTail) != SQLITE_OK)
+    {
+        return sq_throwerror(v, sqlite3_errmsg(db));
+    }
+
+    if(_top_ > params_start){
+        int nparams = sqlite3_bind_parameter_count(*stmt);
+        int nparams_given = _top_-params_start;
+        if(nparams != nparams_given){
+            return sq_throwerror(v, "expect %d parameters but only %d given", nparams, nparams_given);
+        }
+        for(int i=1; i <= nparams; ++i){
+            int argn = i+params_start;
+            _rc_ = sqlite3_stmt_bind_value(v, *stmt, i, argn);
+            if(_rc_ < 0) return _rc_;
+        }
+    }
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_releasehook(SQUserPointer p, SQInteger size)
+{
+	sqlite3_stmt *stmt = ((sqlite3_stmt *)p);
+	sqlite3_finalize(stmt);
+	return 0;
+}
+
+static SQRESULT sq_sqlite3_stmt_constructor(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    GET_sqlite3_INSTANCE_AT(2);
+	sqlite3_stmt *stmt = 0;
+	if(_top_ > 2){
+        _rc_ = sqlite3_stmt_prepare(v, self, &stmt, 3);
+	}
+	else
+	{
+        const char* szTail=0;
+        if(sqlite3_prepare_v2(self, "select 'statement not prepared';", -1, &stmt, &szTail) != SQLITE_OK)
+        {
+            return sq_throwerror(v, sqlite3_errmsg(self));
+        }
+	}
+    if(stmt){
+        sq_setinstanceup(v, 1, stmt); //replace self for this instance with this new sqlite3_stmt
+        sq_setreleasehook(v,1, sq_sqlite3_stmt_releasehook);
+    }
+	return _rc_;
+}
+
+static SQRESULT sq_sqlite3_stmt_close(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sq_pushbool(v, sqlite3_finalize(self) == SQLITE_OK);
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_prepare(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sqlite3 *db = sqlite3_db_handle(self);
+	sqlite3_stmt *stmt = 0;
+	_rc_ = sqlite3_stmt_prepare(v, db, &stmt, 2);
+    if(stmt){
+        sqlite3_finalize(self); //finalize the previous sqlite3_stmt
+        sq_setinstanceup(v, 1, stmt); //replace self for this instance with this new sqlite3_stmt
+    }
+	return _rc_;
+}
+
+static SQRESULT sq_sqlite3_stmt_get_sql(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sq_pushstring(v, sqlite3_sql(self), -1);
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_bind(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+    SQ_GET_INTEGER(v, 2, npar);
+	return sqlite3_stmt_bind_value(v, self, npar, 3);
+}
+
+static SQRESULT sq_sqlite3_stmt_reset(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sq_pushinteger(v, sqlite3_reset(self));
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_step(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sq_pushinteger(v, sqlite3_step(self));
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_next_row(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sq_pushbool(v, sqlite3_step(self) == SQLITE_ROW);
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_col_count(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	sq_pushinteger(v, sqlite3_column_count(self));
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_colsAsArray(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col_count = sqlite3_column_count(self);
+	sq_newarray(v, col_count);
+	for(int i=0; i<col_count; ++i){
+	    sq_pushinteger(v, i);
+	    sq_pushstring(v, sqlite3_column_name(self, i), -1);
+	    sq_rawset(v, -3);
+	}
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_colsAsTable(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col_count = sqlite3_column_count(self);
+	sq_newtable(v);
+	for(int i=0; i<col_count; ++i){
+	    sq_pushstring(v, sqlite3_column_name(self, i), -1);
+	    sq_pushinteger(v, i);
+	    sq_rawset(v, -3);
+	}
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_col_name(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_GET_INTEGER(v, 2, col);
+	sq_pushstring(v, sqlite3_column_name(self, col), -1);
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_col_type(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_GET_INTEGER(v, 2, col);
+	sq_pushinteger(v, sqlite3_column_type(self, col));
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_col_declared_type(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_GET_INTEGER(v, 2, col);
+	sq_pushstring(v, sqlite3_column_decltype(self, col), -1);
+	return 1;
+}
+
+static int get_col_index(HSQUIRRELVM v, sqlite3_stmt *self){
+	SQInteger _rc_, col;
+	switch(sq_gettype(v, 2)){
+	    case OT_INTEGER:
+            sq_getinteger(v, 2, &col);
+	    break;
+	    case OT_STRING:
+            SQ_GET_STRING(v, 2, col_name);
+            if(col_name_size == 0) return sq_throwerror(v, "column name can not be empty");
+            col = -1;
+            for(int i=0, len=sqlite3_column_count(self); i<len; ++i){
+                if(strcasecmp(col_name, sqlite3_column_name(self, i)) == 0){
+                    col = i;
+                    break;
+                }
+            }
+            if(col == -1) return sq_throwerror(v, "column name not found \"%s\"", col_name);
+	    break;
+	    default:
+            return sq_throwerror(v, "wrong parameter expected integer|string");
+	}
+	return col;
+}
+
+static SQRESULT sq_sqlite3_stmt_col(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col = get_col_index(v, self);
+	if(col < 0) return col;
+	sqlite3_stmt_push_value(v, self, col, 0);
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asBool(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col = get_col_index(v, self);
+	if(col < 0) return col;
+    const unsigned char *b = sqlite3_column_text(self, col);
+    sq_pushbool(v,  b && *b == '1');
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asInteger(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col = get_col_index(v, self);
+	if(col < 0) return col;
+    sq_pushinteger(v,  sqlite3_column_int64(self, col));
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asFloat(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col = get_col_index(v, self);
+	if(col < 0) return col;
+    sq_pushfloat(v,  sqlite3_column_double(self, col));
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_StringOrNull(HSQUIRRELVM v, int withNull){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+	int col = get_col_index(v, self);
+	if(col < 0) return col;
+	sqlite3_stmt_push_string(v, self, col, withNull ? 0 : NULL_AS_EMPTY_STR);
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asString(HSQUIRRELVM v){
+    return sq_sqlite3_stmt_StringOrNull(v, 0);
+}
+
+static SQRESULT sq_sqlite3_stmt_asStringOrNull(HSQUIRRELVM v){
+    return sq_sqlite3_stmt_StringOrNull(v, 1);
+}
+
+static SQRESULT sq_sqlite3_stmt_asTable(HSQUIRRELVM v){
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_OPT_INTEGER(v, 2, flags, 0);
+	sqlite3_stmt_row_asTable(v, self, flags);
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asArray(HSQUIRRELVM v){
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_OPT_INTEGER(v, 2, flags, 0);
+	sqlite3_stmt_row_asArray(v, self, flags);
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asArrayOfArrays(HSQUIRRELVM v){
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_OPT_INTEGER(v, 2, flags, 0);
+	sqlite3_stmt_asArrayOfArrays(v, self, flags);
+	sqlite3_reset(self);
+
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asArrayOfTables(HSQUIRRELVM v){
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_stmt_INSTANCE();
+	SQ_OPT_INTEGER(v, 2, flags, 0);
+	sqlite3_stmt_asArrayOfTables(v, self, flags);
+	sqlite3_reset(self);
+
+	return 1;
+}
+
+/*utility functions*/
+static void append_escaping_json(SQBlob &json, const char *sz){
+    if(sz){ //escape string
+        int last_idx, idx;
+        idx = last_idx = 0;
+        for(; sz[idx]; ++idx){
+            char c = sz[idx];
+            switch(c){
+                case '"':
+                case '\n':
+                case '\r':
+                case '\\':{
+                    json.Write(sz+last_idx, idx-last_idx);
+                    last_idx = idx;
+                    if(c == '\n') {
+                        json.Write("\\n", 2);
+                        ++last_idx;
+                    }
+                    else if(c == '\r'){
+                        //skip it
+                        ++last_idx;
+                    }
+                    else
+                    {
+                        json.Write("\\", 1);
+                    }
+                }
+            }
+        }
+        //last part
+        json.Write(sz+last_idx, idx-last_idx);
+    }
+}
+
+static SQRESULT sq_sqlite3_stmt_asJsonArray(HSQUIRRELVM v) {
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_stmt_INSTANCE();
+    SQ_OPT_INTEGER(v, 3, withMetadata, 0);
+    int col_count = sqlite3_column_count(self);
+    int i;
+    const char* value;
+
+    SQBlob json(0, 8192);
+
+    if(withMetadata){
+        json.WriteZstr("{\n\"columns\":[\n");
+        for(i=0; i < col_count; ++i){
+            json.WriteZstr((i == 0 ? "\"" : ",\""));
+            json.WriteZstr(sqlite3_column_name(self, i));
+            json.WriteZstr("\"");
+        }
+
+        json.WriteZstr("\n],\n\"column_types\":[\n");
+        for(i=0; i < col_count; ++i){
+            json.WriteZstr((i == 0 ? "\"" : ",\""));
+            json.WriteZstr(sqlite3_column_decltype(self, i));
+            json.WriteZstr("\"");
+        }
+
+        json.WriteZstr("\n],\n\"rows\":[\n");
+    }
+    else {
+        json.WriteZstr("[\n");
+    }
+    int row_count = 0;
+    while(sqlite3_step(self) == SQLITE_ROW){
+        json.WriteZstr((row_count++ == 0 ? "[" : ",["));
+        for(i=0; i < col_count; ++i){
+            json.WriteZstr((i == 0 ? "\"" : ",\""));
+            value = (const char*)sqlite3_column_text(self, i);
+            if(value)
+            {
+                switch(sqlite3_column_type(self, i))
+                {
+                case SQLITE_TEXT:
+                {
+                    append_escaping_json(json, value);
+                }
+                break;
+                default:
+                    json.WriteZstr(value);
+                }
+            }
+            json.WriteZstr("\"");
+        }
+        json.WriteZstr("]\n");
+    }
+    json.WriteZstr("]");
+    if(withMetadata) json.WriteZstr("\n}");
+
+    sq_pushstring(v, (const SQChar*)json.GetBuf(), json.Len());
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_stmt_asJsonObject(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+    int col_count = sqlite3_column_count(self);
+    int i;
+    const char* value;
+
+    SQBlob json(0, 8192);
+
+    json.WriteZstr("{");
+    if(sqlite3_step(self) == SQLITE_ROW){
+        for(i=0; i < col_count; ++i){
+            json.WriteZstr((i == 0 ? "\"" : "\",\""));
+            append_escaping_json(json, (const char*)sqlite3_column_name(self, i));
+            json.WriteZstr("\":\"");
+            value = (const char*)sqlite3_column_text(self, i);
+            if(value)
+            {
+                switch(sqlite3_column_type(self, i))
+                {
+                case SQLITE_TEXT:
+                {
+                    append_escaping_json(json, value);
+                }
+                break;
+                default:
+                    json.WriteZstr(value);
+                }
+            }
+        }
+        json.WriteZstr("\"");
+    }
+    json.WriteZstr("}");
+
+    sq_pushstring(v, (const SQChar*)json.GetBuf(), json.Len());
+    return 1;
+}
+
+#define UNSIGNED(n) n##U
+#define IBYTE1 UNSIGNED(255)
+#define IBYTE2 UNSIGNED(255*255)
+#define IBYTE3 UNSIGNED(255*255*255)
+#define IBYTE4 UNSIGNED(255*255*255*255)
+
+#define SIZE1BYTE 250
+#define SIZE2BYTE 251
+#define SIZE3BYTE 252
+#define SIZE4BYTE 253
+
+#define SLEMARK 254
+#define SLEEND 255
+
+static SQRESULT sle2array(HSQUIRRELVM v, const unsigned char *p, size_t sle_size, const unsigned char **next)
+{
+    size_t size, data_count = 1, data_len = 0;
+
+    if(sle_size == 0) {
+        *next = 0;
+        return 0;
+    }
+
+    while(*p != SLEEND) //data finished now follow digest
+    {
+        size = *p++;
+        if(size >= SIZE1BYTE)
+        {
+            if(size == SIZE1BYTE)
+            {
+                //data bigger than 250 and less 500 next byte has more info
+                size += *p++;
+            }
+            else if(size == SIZE2BYTE)
+            {
+                //data bigger than 250 next two bytes has more info
+                size = (*p++ * IBYTE1);
+                size += *p++;
+            }
+            else if(size == SIZE3BYTE)
+            {
+                //data bigger than 250 next three bytes has more info
+                size = (*p++ * IBYTE2);
+                size += (*p++ * IBYTE1);
+                size += *p++;
+            }
+            else if(size == SIZE4BYTE)
+            {
+                //data bigger than 250 next four bytes has more info
+                size = (*p++ * IBYTE3);
+                size += (*p++ * IBYTE2);
+                size += (*p++ * IBYTE1);
+                size += *p++;
+            }
+            else if(size == SLEMARK)
+            {
+                //reserved can be used for multi part data, metadata, digest, ...
+                break;
+            }
+        }
+
+        sq_pushstring(v, (const char*)p, size);
+        sq_arrayappend(v, -2);
+        p += size;
+        data_len += size;
+        if(data_len > sle_size)
+        {
+            //something went wrong here
+            return sq_throwerror(v, "We got more data than expected !");
+        }
+    }
+    *next = ++p;
+    return 0;
+}
+
+static SQRESULT sle2vec(HSQUIRRELVM v, const unsigned char *sle,
+                                         size_t sle_size,
+                                         const unsigned char **next)
+{
+    int rc;
+    sq_newarray(v, 0);
+    if(sle[0] != '[') {
+        return sq_throwerror(v, "Invalid encoded vector !");
+    }
+    if(sle[1] == ']') {
+        *next = sle+2; //empty array
+        return 0;
+    }
+    if((rc = sle2array(v, sle+1, sle_size-1, next)) < 0) return rc;
+    if(!*next || *next[0] != ']'){
+        return sq_throwerror(v, "Invalid end of vector !");
+    }
+    *next++;
+    return 0;
+}
+
+static SQRESULT sle2vecOfvec(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    SQ_GET_STRING(v, 2, sle);
+    SQ_OPT_INTEGER(v, 3, start, 0);
+
+    int rc, data_count = 1;
+
+    sq_newarray(v, 0);
+    const unsigned char *next;
+    if(sle[0] != '[') {
+        return sq_throwerror(v, "Invalid encoded vector !");
+    }
+    if(sle[1] == ']') {
+        //sq_pushinteger(v, start+2);
+        return 1; //empty array
+    }
+    int saved_top = sq_gettop(v);
+    if((rc=sle2vec(v, (const unsigned char *)sle+1, sle_size-1, &next)) < 0) return rc;
+    while(next && *next == '['){
+        sq_arrayappend(v, -2);
+        data_count++;
+        if((rc=sle2vec(v, next, sle_size - (next - (const unsigned char *)sle), &next)) < 0) return rc;
+    }
+    if(sq_gettop(v) != saved_top){
+        //last added table left
+        sq_arrayappend(v, -2);
+        data_count++;
+    }
+    if(!next || *next != ']'){
+        return sq_throwerror(v, "Invalid end of vector !");
+    }
+    //sq_pushinteger(v, ++next - sle);
+    return 1;
+}
+
+typedef unsigned char slebuf_t[8];
+
+static int sleSize2buf(slebuf_t sle, size_t size){
+    size_t next_size, tmp_size;
+    if(size < SIZE1BYTE)
+    {
+        sle[0] = size;
+        return 1;
+    }
+    else if(size < (SIZE1BYTE*2))
+    {
+        sle[0] = SIZE1BYTE;
+        next_size = size - 250;
+        sle[1] = next_size;
+        return 2;
+    }
+    else if(size < IBYTE2)
+    {
+        sle[0] = SIZE2BYTE;
+        next_size = size/IBYTE1;
+        sle[1] = next_size;
+        next_size = size%IBYTE1;
+        sle[2] = next_size;
+        return 3;
+    }
+    else if(size < IBYTE3)
+    {
+        sle[0] = SIZE3BYTE;
+        next_size = size/IBYTE2;
+        sle[1] = next_size;
+        tmp_size = size%IBYTE2;
+        next_size = tmp_size/IBYTE1;
+        sle[2] = next_size;
+        next_size = tmp_size%IBYTE1;
+        sle[3] = next_size;
+        return 4;
+    }
+    else if(size < IBYTE4)
+    {
+        sle[0] = SIZE4BYTE;
+        next_size = size/IBYTE3;
+        sle[1] = next_size;
+        tmp_size = size%IBYTE3;
+        next_size = tmp_size/IBYTE2;
+        sle[2] = next_size;
+        tmp_size = tmp_size%IBYTE2;
+        next_size = tmp_size/IBYTE1;
+        sle[3] = next_size;
+        next_size = tmp_size%IBYTE1;
+        sle[5] = next_size;
+        return 5;
+    }
+    return 0;
+}
+
+static SQRESULT get_sle_size(HSQUIRRELVM v){
+    SQ_FUNC_VARS_NO_TOP(v);
+    slebuf_t slebuf;
+    SQ_GET_INTEGER(v, 2, size);
+    int slesize = sleSize2buf(slebuf, size);
+    if(slesize) {
+        sq_pushstring(v, (const char *)slebuf, slesize);
+        return 1;
+    }
+    return 0;
+}
+
+static int add2sle(SQBlob &sle, const char *str, size_t size){
+    slebuf_t slebuf;
+    int slesize = sleSize2buf(slebuf, size);
+    if(slesize) sle.Write((const char *)slebuf, slesize);
+    if(size) sle.Write(str, size);
+    return size;
+}
+
+static SQRESULT sq_sqlite3_stmt_asSleArray(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_stmt_INSTANCE();
+    int col_count = sqlite3_column_count(self);
+    int i;
+    const char *value;
+
+    SQBlob sle(0, 8192);
+
+    sle.WriteZstr("[[");
+    for(i=0; i < col_count; ++i){
+        value = sqlite3_column_name(self, i);
+        add2sle(sle, value, strlen(value));
+    }
+    sle.WriteChar(SLEEND);
+    sle.WriteChar(']');
+
+    while(sqlite3_step(self) == SQLITE_ROW){
+        sle.WriteChar('[');
+        for(i=0; i < col_count; ++i){
+            switch(sqlite3_column_type(self, i))
+            {
+            case SQLITE_BLOB:
+            {
+                add2sle(sle, (const char*)sqlite3_column_blob(self, i),
+                                sqlite3_column_bytes(self, i));
+            }
+            break;
+            default:
+                add2sle(sle, (const char*)sqlite3_column_text(self, i),
+                                sqlite3_column_bytes(self, i));
+            }
+        }
+        sle.WriteChar(SLEEND);
+        sle.WriteChar(']');
+    }
+    sle.WriteChar(']');
+
+    sq_pushstring(v, (const SQChar*)sle.GetBuf(), sle.Len());
+    return 1;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),  sq_sqlite3_stmt_##name,nparams,tycheck}
+static SQRegFunction sq_sqlite3_stmt_methods[] =
+{
+	_DECL_FUNC(constructor,  -2, _SC("xxs s|n|b|o")),
+
+	_DECL_FUNC(prepare,  -2, _SC("xs s|n|b|o")),
+	_DECL_FUNC(get_sql,  1, _SC("x")),
+	_DECL_FUNC(bind,  3, _SC("xi s|n|b|o")),
+	_DECL_FUNC(step,  1, _SC("x")),
+	_DECL_FUNC(reset,  1, _SC("x")),
+	_DECL_FUNC(next_row,  1, _SC("x")),
+	_DECL_FUNC(colsAsArray,  1, _SC("x")),
+	_DECL_FUNC(colsAsTable,  1, _SC("x")),
+	_DECL_FUNC(col_count,  1, _SC("x")),
+	_DECL_FUNC(col_name,  2, _SC("xi")),
+	_DECL_FUNC(col_type,  2, _SC("xi")),
+	_DECL_FUNC(col_declared_type,  2, _SC("xi")),
+	_DECL_FUNC(asArray,  -1, _SC("xi")),
+	_DECL_FUNC(asTable,  -1, _SC("xi")),
+	_DECL_FUNC(asArrayOfArrays,  -1, _SC("xi")),
+	_DECL_FUNC(asArrayOfTables,  -1, _SC("xi")),
+	_DECL_FUNC(col,  2, _SC("x i|s")),
+	_DECL_FUNC(asString,  2, _SC("x i|s")),
+	_DECL_FUNC(asStringOrNull, 2, _SC("x i|s")),
+	_DECL_FUNC(asInteger,  2, _SC("x i|s")),
+	_DECL_FUNC(asBool,  2, _SC("x i|s")),
+	_DECL_FUNC(asFloat,  2, _SC("x i|s")),
+	{0,0}
+};
+#undef _DECL_FUNC
+
+static SQRESULT sqlite3_exec_fmt(HSQUIRRELVM v, e_type_result type_result, int null_as_empty_str=1){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	SQ_GET_STRING(v, 2, szSQL);
+	sqlite3_stmt *stmt = 0;
+	_rc_ = sqlite3_stmt_prepare(v, self, &stmt, 2);
+    if(_rc_ < 0){
+        if(stmt) sqlite3_finalize(stmt);
+        return _rc_;
+    }
+
+    int rc = sqlite3_step(stmt);
+
+    if(type_result == tr_ddml) {
+        if(rc != SQLITE_DONE) {
+            sqlite3_finalize(stmt);
+            return sq_throwerror(v, "SQL is not a DDML %d %s", rc, sqlite3_errmsg(self));
+        }
+        sq_pushinteger(v, sqlite3_changes(sqlite3_db_handle(stmt)));
+    }
+    else
+    {
+        if(rc != SQLITE_ROW) {
+            sqlite3_finalize(stmt);
+            return sq_throwerror(v, "%d %s", rc, sqlite3_errmsg(self));
+        }
+        switch(type_result){
+            case tr_first_row_first_col:
+                sqlite3_stmt_push_value(v, stmt, 0, 0);
+            break;
+            case tr_first_row:
+                sqlite3_stmt_row_asArray(v, stmt, NULL_AS_EMPTY_STR|AS_STRING_ALWAYS);
+            break;
+            case tr_all_rows:
+                sqlite3_stmt_asArrayOfArrays(v, stmt, NULL_AS_EMPTY_STR|AS_STRING_ALWAYS);
+            break;
+            default:
+                sqlite3_finalize(stmt);
+                return sq_throwerror(v, "Unknown requested return type %d", type_result);
+        }
+    }
+    sqlite3_finalize(stmt);
+	return 1;
+}
+
+
+static SQRESULT sq_sqlite3_releasehook(SQUserPointer p, SQInteger size)
+{
+	sq_sqlite3_sdb *sdb = ((sq_sqlite3_sdb *)p);
+	sqlite3_close_v2(sdb->db);
+	if(sdb->func){
+        sq_sqlite3_sdb_func *func, *func_next;
+        func = sdb->func;
+        while (func) {
+            func_next = func->next;
+            sq_release(sdb->v, &func->fn_step);
+            sq_release(sdb->v, &func->fn_finalize);
+            sq_release(sdb->v, &func->udata);
+            sq_free(func, sizeof(sq_sqlite3_sdb_func));
+            func = func_next;
+        }
+        sdb->func = NULL;
+	}
+    /* 'free' all references */
+    sq_release(sdb->v, &sdb->busy_cb);
+    sq_release(sdb->v, &sdb->busy_udata);
+    sq_release(sdb->v, &sdb->progress_cb);
+    sq_release(sdb->v, &sdb->progress_udata);
+    sq_release(sdb->v, &sdb->trace_cb);
+    sq_release(sdb->v, &sdb->trace_udata);
+    sq_release(sdb->v, &sdb->null_value);
+
+	sq_free(sdb, sizeof(sq_sqlite3_sdb));
+	return 0;
+}
+
+static SQRESULT sq_sqlite3_constructor(HSQUIRRELVM v)
+{
+    SQ_FUNC_VARS(v);
+    SQ_GET_STRING(v, 2, dbname);
+    SQ_OPT_INTEGER(v, 3, flags, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_SUBLATIN_NA_LIKE);
+    sqlite3 *db;
+    int rc = sqlite3_open_v2(dbname, &db, flags, 0);
+    if(rc != SQLITE_OK) return sq_throwerror(v, "Failed to open database ! %d", rc);
+    sq_sqlite3_sdb *sdb = (sq_sqlite3_sdb *)sq_malloc(sizeof(sq_sqlite3_sdb));
+    memset(sdb, 0, sizeof(sq_sqlite3_sdb));
+    sdb->db = db;
+    sdb->v = v;
+    sq_resetobject(&sdb->busy_cb);
+    sq_resetobject(&sdb->busy_udata);
+    sq_resetobject(&sdb->progress_cb);
+    sq_resetobject(&sdb->progress_udata);
+    sq_resetobject(&sdb->trace_cb);
+    sq_resetobject(&sdb->trace_udata);
+
+    sq_setinstanceup(v, 1, sdb);
+    sq_setreleasehook(v,1, sq_sqlite3_releasehook);
+    return 1;
+}
+
+
+/* bool IsAutoCommitOn(  ) */
+static SQRESULT sq_sqlite3_IsAutoCommitOn(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	sq_pushbool(v, sqlite3_get_autocommit(self) ? SQTrue : SQFalse);
+	return 1;
+}
+
+/* int changes(  ) */
+static SQRESULT sq_sqlite3_changes(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	sq_pushinteger(v, sqlite3_total_changes(self));
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_exec(HSQUIRRELVM v){
+    return sqlite3_exec_fmt(v, tr_all_rows);
+}
+
+/* int exec_dml( const char * szSQL  ) */
+static SQRESULT sq_sqlite3_exec_dml(HSQUIRRELVM v){
+    return sqlite3_exec_fmt(v, tr_ddml);
+}
+
+/* bool exec_get_one( std::string & result  , const char * szSQL  ) */
+static SQRESULT sq_sqlite3_exec_get_one(HSQUIRRELVM v){
+    return sqlite3_exec_fmt(v, tr_first_row_first_col);
+}
+
+static SQRESULT sq_sqlite3_exec_get_first_row(HSQUIRRELVM v){
+    return sqlite3_exec_fmt(v, tr_first_row);
+}
+
+/* const char * get_db_name(  ) */
+static SQRESULT sq_sqlite3_get_db_name(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	sq_pushstring(v, sqlite3_db_filename(self, "main"), -1);
+	return 1;
+}
+
+/* sqlite3_int64 last_row_id(  ) */
+static SQRESULT sq_sqlite3_last_row_id(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	sq_pushinteger(v, sqlite3_last_insert_rowid(self));
+	return 1;
+}
+
+/* stmt * prepare( const char * sql  ) */
+static SQRESULT sq_sqlite3_prepare(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	SQ_GET_STRING(v, 2, sql);
+	//sq_pushstring(v, self->prepare(sql));
+	return 1;
+}
+
+/* void set_busy_timeout( int nMillisecs  ) */
+static SQRESULT sq_sqlite3_set_busy_timeout(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	SQ_GET_INTEGER(v, 2, nMillisecs);
+	//self->set_busy_timeout(nMillisecs);
+	return 0;
+}
+
+/* int total_changes(  ) */
+static SQRESULT sq_sqlite3_total_changes(HSQUIRRELVM v){
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	sq_pushinteger(v, sqlite3_total_changes(self));
+	return 1;
+}
+
+static SQRESULT sq_sqlite3_enable_shared_cache(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	SQ_GET_BOOL(v, 2, bhow);
+    sq_pushbool(v, sqlite3_enable_shared_cache(bhow) == SQLITE_OK);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_sleep(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	SQ_GET_INTEGER(v, 2, n);
+    sqlite3_sleep(n);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_version(HSQUIRRELVM v) {
+    sq_pushstring(v, sqlite3_libversion(), -1);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_errcode(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+    sq_pushinteger(v, sqlite3_errcode(self));
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_errmsg(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+    sq_pushstring(v, sqlite3_errmsg(self), -1);
+    return 1;
+}
+
+#ifndef WIN32
+static SQRESULT sq_sqlite3_temp_directory(HSQUIRRELVM v) {
+    SQ_FUNC_VARS(v);
+    const char *oldtemp = sqlite3_temp_directory;
+
+    if (_top_ > 1) {
+        SQ_GET_STRING(v, 2, temp);
+        if (sqlite3_temp_directory) {
+            sqlite3_free((char*)sqlite3_temp_directory);
+        }
+        if (temp && temp_size) {
+            sqlite3_temp_directory = sqlite3_mprintf("%s", temp);
+        }
+        else {
+            sqlite3_temp_directory = NULL;
+        }
+    }
+    sq_pushstring(v, oldtemp, -1);
+    return 1;
+}
+#endif
+
+#ifdef SQLITE_HAS_CODEC
+
+//#include "codecext.h"
+/*
+** Params: db, sql
+** returns: code, compiled length or error message
+*/
+static SQRESULT sq_sqlite3_key(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	SQ_GET_STRING(v, 2, key);
+    sq_pushinteger(v, sqlite3_key(self, key, key_size));
+    return 1;
+}
+
+/*
+** Params: db, sql
+** returns: code, compiled length or error message
+*/
+static SQRESULT sq_sqlite3_rekey(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	SQ_GET_STRING(v, 2, key);
+    sq_pushinteger(v, sqlite3_rekey(self, key, key_size));
+    return 1;
+}
+
+#endif
+
+#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK
+
+/*
+** progress handler:
+** Params: database, number of opcodes, callback function, userdata
+**
+** callback function:
+** Params: userdata
+** returns: 0 to return immediatly and return SQLITE_ABORT, non-zero to continue
+*/
+static int db_progress_callback(void *user) {
+    int result = 1; /* abort by default */
+    sq_sqlite3_sdb *sdb = (sq_sqlite3_sdb*)user;
+    HSQUIRRELVM v = sdb->v;
+    int top = sq_gettop(v);
+
+    sq_pushobject(v, sdb->progress_cb);
+    sq_pushroottable(v); //this
+    sq_pushobject(v, sdb->progress_udata);
+
+    /* call lua function */
+    if (sq_call(v, 2, SQTrue, SQFalse) == SQ_OK)
+        sq_getinteger(v, -1, &result);
+
+    sq_settop(v, top);
+    return result;
+}
+
+static SQRESULT sq_sqlite3_progress_handler(HSQUIRRELVM v) {
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_INSTANCE();
+
+    if (_top_ < 2 || sq_gettype(v, 2) == OT_NULL) {
+        sq_release(v, &sdb->progress_cb);
+        sq_release(v, &sdb->progress_udata);
+
+        sq_resetobject(&sdb->progress_cb);
+        sq_resetobject(&sdb->progress_udata);
+
+        /* clear busy handler */
+        sqlite3_progress_handler(self, 0, NULL, NULL);
+    }
+    else {
+        SQ_GET_INTEGER(v, 2, nop);
+        if(sq_gettype(v, 3) != OT_CLOSURE)
+            return sq_throwerror(v, _SC("invalid second parameter expected closure"));
+
+        sq_getstackobj(v, 3, &sdb->progress_cb);
+        sq_addref(v, &sdb->progress_cb);
+        if(_top_ > 3){
+            sq_getstackobj(v, 4, &sdb->progress_udata);
+            sq_addref(v, &sdb->progress_udata);
+        }
+
+        /* set progress callback */
+        sqlite3_progress_handler(self, nop, db_progress_callback, sdb);
+    }
+
+    return 0;
+}
+
+#else /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
+
+static SQRESULT sq_sqlite3_progress_handler(HSQUIRRELVM v) {
+    return sq_throwerror(v, _SC("progress callback support disabled at compile time"));
+    return 0;
+}
+
+#endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
+
+/*
+** trace callback:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata, sql
+*/
+static void db_trace_callback(void *user, const char *sql) {
+    sq_sqlite3_sdb *sdb = (sq_sqlite3_sdb*)user;
+    HSQUIRRELVM v = sdb->v;
+    int top = sq_gettop(v);
+
+    /* setup squirrel callback call */
+    sq_pushobject(v, sdb->trace_cb);
+    sq_pushroottable(v);
+    sq_pushobject(v, sdb->trace_udata);
+    sq_pushstring(v, sql, -1); /* traced sql statement */
+
+    /* call squirrel function */
+    sq_call(v, 3, SQFalse, SQFalse);
+    /* ignore any error generated by this function */
+
+    sq_settop(v, top);
+}
+
+static SQRESULT sq_sqlite3_trace(HSQUIRRELVM v) {
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_INSTANCE();
+
+    if (_top_ < 2 || sq_gettype(v, 2) == OT_NULL) {
+        sq_release(v, &sdb->trace_cb);
+        sq_release(v, &sdb->trace_udata);
+
+        sq_resetobject(&sdb->trace_cb);
+        sq_resetobject(&sdb->trace_udata);
+
+        /* clear trace handler */
+        sqlite3_trace(self, NULL, NULL);
+    }
+    else {
+        if(sq_gettype(v, 2) != OT_CLOSURE)
+            return sq_throwerror(v, _SC("invalid fisrt parameter expected closure"));
+
+        sq_getstackobj(v, 2, &sdb->trace_cb);
+        sq_addref(v, &sdb->trace_cb);
+        if(_top_ > 2){
+            sq_getstackobj(v, 3, &sdb->trace_udata);
+            sq_addref(v, &sdb->trace_udata);
+        }
+
+        /* set trace callback */
+        sqlite3_trace(self, db_trace_callback, sdb);
+    }
+
+    return 0;
+}
+
+/*
+** busy handler:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata, number of tries
+** returns: 0 to return immediatly and return SQLITE_BUSY, non-zero to try again
+*/
+static int db_busy_callback(void *user, int tries) {
+    SQBool retry = SQFalse; /* abort by default */
+    sq_sqlite3_sdb *sdb = (sq_sqlite3_sdb*)user;
+    HSQUIRRELVM v = sdb->v;
+    int top = sq_gettop(v);
+
+    sq_pushobject(v, sdb->busy_cb);
+    sq_pushroottable(v);
+    sq_pushobject(v, sdb->busy_udata);
+    sq_pushinteger(v, tries);
+
+    /* call lua function */
+    if (sq_call(v, 3, SQTrue, SQFalse) == SQ_OK)
+        sq_getbool(v, -1, &retry);
+
+    sq_settop(v, top);
+    return retry == SQTrue;
+}
+
+static SQRESULT sq_sqlite3_busy_handler(HSQUIRRELVM v) {
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_INSTANCE();
+
+    if (_top_ < 2 || sq_gettype(v, 2) == OT_NULL) {
+        sq_release(v, &sdb->busy_cb);
+        sq_release(v, &sdb->busy_udata);
+
+        sq_resetobject(&sdb->busy_cb);
+        sq_resetobject(&sdb->busy_udata);
+
+        /* clear busy handler */
+        sqlite3_busy_handler(self, NULL, NULL);
+    }
+    else {
+        if(sq_gettype(v, 2) != OT_CLOSURE)
+            return sq_throwerror(v, _SC("invalid fisrt parameter expected closure"));
+
+        sq_getstackobj(v, 2, &sdb->busy_cb);
+        sq_addref(v, &sdb->busy_cb);
+        if(_top_ > 2){
+            sq_getstackobj(v, 3, &sdb->busy_udata);
+            sq_addref(v, &sdb->busy_udata);
+        }
+
+        /* set busy callback */
+        sqlite3_busy_handler(self, db_busy_callback, sdb);
+    }
+
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_busy_timeout(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+	SQ_GET_INTEGER(v, 2, timeout);
+
+    sqlite3_busy_timeout(self, timeout);
+
+    /* if there was a timeout callback registered, it is now
+    ** invalid/useless. free any references we may have */
+    sq_release(v, &sdb->busy_cb);
+    sq_resetobject(&sdb->busy_cb);
+    sq_release(v, &sdb->busy_udata);
+    sq_resetobject(&sdb->busy_udata);
+
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_interrupt(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_INSTANCE();
+    sqlite3_interrupt(self);
+    return 0;
+}
+
+/*
+** =======================================================
+** User Defined Functions - Context Methods
+** =======================================================
+*/
+typedef struct {
+    sqlite3_context *ctx;
+    HSQOBJECT udata;
+} sq_sqlite3_context_st;
+
+static const SQChar sq_sqlite3_context_TAG[]  = _SC(":sqlite3:ctx");
+
+static SQRESULT sq_sqlite3_context_releasehook(SQUserPointer p, SQInteger size)
+{
+	sq_sqlite3_context_st *ctx = ((sq_sqlite3_context_st *)p);
+    /* 'free' all references */
+	sq_free(ctx, sizeof(sq_sqlite3_context_st));
+	return 0;
+}
+
+static SQRESULT sq_sqlite3_context_constructor(HSQUIRRELVM v) {
+    sq_sqlite3_context_st *ctx = (sq_sqlite3_context_st*)sq_malloc(sizeof(sq_sqlite3_context_st));
+    ctx->ctx = NULL;
+    sq_resetobject(&ctx->udata);
+    sq_setinstanceup(v, 1, ctx);
+    sq_setreleasehook(v,1, sq_sqlite3_context_releasehook);
+    return 1;
+}
+
+#define SQ_SQLITE3_GETCONTEXT(v, idx) \
+    sq_sqlite3_context_st *self;\
+    if((_rc_ = sq_getinstanceup(v, idx, (void**)&self, (void*)sq_sqlite3_context_TAG)) < 0) return _rc_;
+
+#define GET_sqlite3_context_INSTANCE() SQ_SQLITE3_GETCONTEXT(v,1)
+
+static SQRESULT sq_sqlite3_context__tostring(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+    char buff[64];
+    snprintf(buff, sizeof(buff), "sqlite function context (%p)", self);
+    sq_pushstring(v, buff, -1);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_context_check_aggregate(HSQUIRRELVM v, sq_sqlite3_context_st *ctx) {
+    sq_sqlite3_sdb_func *func = (sq_sqlite3_sdb_func*)sqlite3_user_data(ctx->ctx);
+    if (sq_isclosure(func->fn_finalize)) {
+        return sq_throwerror(v, "attempt to call aggregate method from scalar function");
+    }
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_context_user_data(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+    sq_sqlite3_sdb_func *func = (sq_sqlite3_sdb_func*)sqlite3_user_data(self->ctx);
+    sq_pushobject(v, func->udata);
+    return 1;
+}
+
+static SQRESULT sq_sqlite3_context_aggregate_data(HSQUIRRELVM v) {
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_context_INSTANCE();
+    sq_sqlite3_context_check_aggregate(v, self);
+    if(_top_ < 2){
+        sq_pushobject(v, self->udata);
+    }
+    else
+    {
+        sq_release(v, &self->udata);
+        sq_getstackobj(v, 2, &self->udata);
+        sq_addref(v, &self->udata);
+    }
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_context_aggregate_count(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+    sq_sqlite3_context_check_aggregate(v, self);
+    sq_pushinteger(v, sqlite3_aggregate_count(self->ctx));
+    return 1;
+}
+
+#if 0
+void *sqlite3_get_auxdata(sqlite3_context*, int);
+void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
+#endif
+
+static SQRESULT sq_sqlite3_context_result_blob(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+	SQ_GET_STRING(v, 2, blob);
+    sqlite3_result_blob(self->ctx, (const void*)blob, blob_size, SQLITE_TRANSIENT);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_context_result_double(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+	SQ_GET_FLOAT(v, 2, d);
+    sqlite3_result_double(self->ctx, d);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_context_result_error(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+	SQ_GET_STRING(v,2, err);
+    sqlite3_result_error(self->ctx, err, err_size);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_context_result_int(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+	SQ_GET_INTEGER(v, 2, i);
+    sqlite3_result_int(self->ctx, i);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_context_result_null(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+    sqlite3_result_null(self->ctx);
+    return 0;
+}
+
+static SQRESULT sq_sqlite3_context_result_text(HSQUIRRELVM v) {
+	SQ_FUNC_VARS_NO_TOP(v);
+	GET_sqlite3_context_INSTANCE();
+	SQ_GET_STRING(v, 2, text);
+    sqlite3_result_text(self->ctx, text, text_size, SQLITE_TRANSIENT);
+    return 0;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),  sq_sqlite3_context_##name,nparams,tycheck}
+static SQRegFunction sq_sqlite3_context_methods[] =
+{
+	_DECL_FUNC(constructor,  1, _SC("x")),
+
+	_DECL_FUNC(user_data,  1, _SC("x")),
+	_DECL_FUNC(aggregate_data,  -1, _SC("x.")),
+	_DECL_FUNC(aggregate_count,  1, _SC("x")),
+	_DECL_FUNC(result_null,  1, _SC("x")),
+	_DECL_FUNC(result_double,  2, _SC("xf")),
+	_DECL_FUNC(result_int,  2, _SC("xi")),
+	_DECL_FUNC(result_text,  2, _SC("xs")),
+	_DECL_FUNC(result_blob,  2, _SC("xs")),
+	_DECL_FUNC(result_error,  2, _SC("xs")),
+	_DECL_FUNC(_tostring,  -1, _SC("x")),
+	{0,0}
+};
+#undef _DECL_FUNC
+
+/*
+** callback functions used when calling registered sql functions
+*/
+
+static void sqlite3_push_value(HSQUIRRELVM v, sqlite3_value *value) {
+    const char *tmp_value;
+    switch (sqlite3_value_type(value)) {
+        case SQLITE_TEXT:
+            tmp_value = (const char*) sqlite3_value_text(value);
+            if(tmp_value) sq_pushstring(v, tmp_value, sqlite3_value_bytes(value));
+            else push_sqlite3_null(v);
+            break;
+
+        case SQLITE_INTEGER:
+            {
+                sqlite_int64 i64 = sqlite3_value_int64(value);
+                SQInteger n = (SQInteger)i64;
+                if (n == i64)
+                    sq_pushinteger(v, n);
+                else
+                    sq_pushstring(v, (const char*) sqlite3_value_text(value), sqlite3_value_bytes(value));
+            }
+            break;
+
+        case SQLITE_FLOAT:
+            sq_pushfloat(v, sqlite3_value_double(value));
+            break;
+
+        case SQLITE_BLOB:
+            tmp_value = (const char*) sqlite3_value_blob(value);
+            if(tmp_value) sq_pushstring(v, tmp_value, sqlite3_value_bytes(value));
+            else push_sqlite3_null(v);
+            break;
+
+        case SQLITE_NULL:
+            push_sqlite3_null(v);
+            break;
+
+        default:
+            /* things done properly (SQLite + Lua SQLite)
+            ** this should never happen */
+            push_sqlite3_null(v);
+            break;
+    }
+}
+//#if 0
+
+static SQRESULT new_context_instance(HSQUIRRELVM v, sq_sqlite3_context_st **ctx){
+    sq_pushregistrytable(v);
+    sq_pushstring(v,_SC("sqite3_context"),-1);
+    int rc = sq_rawget(v, -2);
+    sq_remove(v, -2); //remove registrytable
+    sq_pushroottable(v);
+    rc = sq_call(v, 1, SQTrue, SQFalse);
+    sq_remove(v, -2); //class
+    rc = sq_getinstanceup(v, -1, (void**)ctx, (void*)sq_sqlite3_context_TAG);
+}
+/* scalar function to be called
+** callback params: context, values... */
+static void db_sql_normal_function(sqlite3_context *context, int argc, sqlite3_value **argv) {
+    sq_sqlite3_sdb_func *func = (sq_sqlite3_sdb_func*)sqlite3_user_data(context);
+    HSQUIRRELVM v = func->sdb->v;
+
+    int n, rc;
+    sq_sqlite3_context_st *ctx;
+    int top = sq_gettop(v);
+
+    /* ensure there is enough space in the stack */
+    sq_reservestack(v, argc + 5);
+
+    sq_pushobject(v, func->fn_step);
+    sq_pushroottable(v);
+
+    if (!sq_isclosure(func->fn_finalize)) {
+        new_context_instance(v, &ctx);
+    }
+    else {
+        /* reuse context userdata value */
+        void *p = sqlite3_aggregate_context(context, 1);
+        /* i think it is OK to use assume that using a light user data
+        ** as an entry on LUA REGISTRY table will be unique */
+        sq_pushregistrytable(v);
+        sq_pushuserpointer(v, p);
+        /* context table */
+        if(sq_rawget(v, -2) != SQ_OK){
+            /* not yet created? */
+            sq_poptop(v); //remove null
+            new_context_instance(v, &ctx);
+            sq_pushuserpointer(v, p);
+            sq_push(v, -2);
+            sq_rawset(v, -4); //insert into registrytable
+        }
+        sq_remove(v, -2); //remove registrytable
+    }
+
+    /* push params */
+    for (n = 0; n < argc; ++n) {
+        sqlite3_push_value(v, argv[n]);
+    }
+
+    /* set context */
+    ctx->ctx = context;
+
+    if (sq_call(v, argc + 2, SQFalse, SQFalse) != SQ_OK) { //2 = roottable + ctx
+        sqlite3_result_error(context, sq_getlasterror_str(v), -1);
+    }
+
+    /* invalidate context */
+    ctx->ctx = NULL;
+
+    if (!sq_isclosure(func->fn_finalize)) {
+        sq_release(v, &ctx->udata);
+        sq_resetobject(&ctx->udata);
+    }
+
+    sq_settop(v, top);
+}
+
+static void db_sql_finalize_function(sqlite3_context *context) {
+    sq_sqlite3_sdb_func *func = (sq_sqlite3_sdb_func*)sqlite3_user_data(context);
+    HSQUIRRELVM v = func->sdb->v;
+    void *p = sqlite3_aggregate_context(context, 1); /* minimal mem usage */
+    sq_sqlite3_context_st *ctx;
+    int top = sq_gettop(v);
+
+    sq_pushobject(v, func->fn_finalize);
+    sq_pushroottable(v);
+
+    /* i think it is OK to use assume that using a light user data
+    ** as an entry on LUA REGISTRY table will be unique */
+    sq_pushregistrytable(v);
+    sq_pushuserpointer(v, p);
+    /* remove it from registry but we'll use it last time here */
+    /* context table */
+    if(sq_deleteslot(v, -2, SQTrue) != SQ_OK){
+        /* not yet created? - shouldn't happen in finalize function */
+        sq_pop(v, 1);
+        new_context_instance(v, &ctx);
+        sq_pushuserpointer(v, p);
+        sq_push(v, -2);
+        sq_rawset(v, -4);
+    }
+    sq_remove(v, -2); //registrytable
+
+    /* set context */
+    ctx->ctx = context;
+
+    if (sq_call(v, 1, SQFalse, SQFalse) != SQ_OK) {
+        sqlite3_result_error(context, sq_getlasterror_str(v), -1);
+    }
+
+    /* invalidate context */
+    ctx->ctx = NULL;
+
+    /* cleanup context */
+    sq_release(v, &ctx->udata);
+    sq_resetobject(&ctx->udata);
+    sq_settop(v, top);
+}
+
+/*
+** Register a normal function
+** Params: db, function name, number arguments, [ callback | step, finalize], user data
+** Returns: true on sucess
+**
+** Normal function:
+** Params: context, params
+**
+** Aggregate function:
+** Params of step: context, params
+** Params of finalize: context
+*/
+static SQRESULT db_register_function(HSQUIRRELVM v, int aggregate) {
+	SQ_FUNC_VARS(v);
+	GET_sqlite3_INSTANCE();
+    SQ_GET_STRING(v, 2, name);
+    SQ_GET_INTEGER(v, 3, nargs);
+    if(sq_gettype(v, 4) != OT_CLOSURE)
+        return sq_throwerror(v, "invalid parameter 3 expected closure");
+    if (aggregate) {
+        if(sq_gettype(v,5) != OT_CLOSURE)
+            return sq_throwerror(v, "invalid parameter 4 expected closure");
+    }
+
+    sq_sqlite3_sdb_func *func;
+    /* maybe an alternative way to allocate memory should be used/avoided */
+    func = (sq_sqlite3_sdb_func*)sq_malloc(sizeof(sq_sqlite3_sdb_func));
+    memset(func, 0, sizeof(sq_sqlite3_sdb_func));
+    _rc_ = sqlite3_create_function(
+        self, name, nargs, SQLITE_UTF8, func,
+        aggregate ? NULL : db_sql_normal_function,
+        aggregate ? db_sql_normal_function : NULL,
+        aggregate ? db_sql_finalize_function : NULL
+    );
+
+    if (_rc_ == SQLITE_OK) {
+        /* save registered function in db function list */
+        func->sdb = sdb;
+        func->next = sdb->func;
+        sdb->func = func;
+
+        /* save the setp/normal function callback */
+        sq_resetobject(&func->fn_step);
+        sq_getstackobj(v, 4, &func->fn_step);
+        sq_addref(v, &func->fn_step);
+        /* save the finalize function callback */
+        sq_resetobject(&func->fn_finalize);
+        if (aggregate) {
+            sq_getstackobj(v, 5, &func->fn_finalize);
+            sq_addref(v, &func->fn_finalize);
+        }
+
+        /* save user data */
+        sq_resetobject(&func->udata);
+        int udata_idx = aggregate ? 6 : 5;
+        if(_top_ >= udata_idx){
+            sq_getstackobj(v, udata_idx, &func->udata);
+            sq_addref(v, &func->udata);
+        }
+    }
+    else {
+        /* free allocated memory */
+        sq_free(func, sizeof(sq_sqlite3_sdb_func));
+    }
+
+    sq_pushbool(v, _rc_ == SQLITE_OK ? 1 : 0);
+    return 1;
+}
+//#endif
+
+static SQRESULT sq_sqlite3_create_function(HSQUIRRELVM v) {
+    return db_register_function(v, 0);
+}
+
+static SQRESULT sq_sqlite3_create_aggregate(HSQUIRRELVM v) {
+    return db_register_function(v, 1);
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),  sq_sqlite3_##name,nparams,tycheck}
+static SQRegFunction sq_sqlite3_methods[] =
+{
+	_DECL_FUNC(constructor,  2, _SC("xsi")),
+
+	_DECL_FUNC(IsAutoCommitOn,  1, _SC("x")),
+	_DECL_FUNC(version,  1, _SC("x")),
+	_DECL_FUNC(errcode,  1, _SC("x")),
+	_DECL_FUNC(errmsg,  1, _SC("x")),
+	_DECL_FUNC(sleep,  1, _SC("x")),
+	_DECL_FUNC(interrupt,  1, _SC("x")),
+	_DECL_FUNC(progress_handler,  -2, _SC("x i|o c .")),
+	_DECL_FUNC(trace,  -2, _SC("x c|o .")),
+	_DECL_FUNC(busy_handler,  -2, _SC("x c|o .")),
+	_DECL_FUNC(busy_timeout,  2, _SC("xi")),
+	_DECL_FUNC(create_function,  4, _SC("xsic")),
+	_DECL_FUNC(create_aggregate,  5, _SC("xsicc")),
+	_DECL_FUNC(temp_directory,  -2, _SC("xs")),
+	_DECL_FUNC(enable_shared_cache,  2, _SC("xb")),
+	_DECL_FUNC(changes,  1, _SC("x")),
+	_DECL_FUNC(exec,  -2, _SC("xs")),
+	_DECL_FUNC(exec_dml,  -2, _SC("xs")),
+	_DECL_FUNC(exec_get_first_row,  -2, _SC("xs")),
+	_DECL_FUNC(exec_get_one,  -2, _SC("xs")),
+	_DECL_FUNC(get_db_name,  1, _SC("x")),
+	_DECL_FUNC(last_row_id,  1, _SC("x")),
+	_DECL_FUNC(prepare,  -2, _SC("xs")),
+	_DECL_FUNC(set_busy_timeout,  -1, _SC("xi")),
+	_DECL_FUNC(total_changes,  1, _SC("x")),
+#ifdef SQLITE_HAS_CODEC
+	_DECL_FUNC(key,  2, _SC("xs")),
+	_DECL_FUNC(rekey,  2, _SC("xs")),
+#endif
+	{0,0}
+};
+
+#undef _DECL_FUNC
+
+#define INT_CONST(v,num) 	sq_pushstring(v,_SC(#num),-1);sq_pushinteger(v,num);sq_newslot(v,-3,SQTrue);
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    SQRESULT sqstd_register_SQLite3(HSQUIRRELVM v)
+    {
+        HSQOBJECT sqlite3_NULL;
+        sq_pushregistrytable(v);
+        sq_pushstring(v, sqlite3_NULL_Name,-1);
+        sq_newuserdata(v, sizeof(void*));
+        sq_resetobject(&sqlite3_NULL);
+        sq_getstackobj(v, -1, &sqlite3_NULL);
+        sq_newtable(v);
+        sq_insert_reg_funcs(v, sqlite3_NULL_methods);
+        sq_setdelegate(v, -2);
+        sq_newslot(v,-3,SQTrue);
+
+        sq_pushstring(v,_SC("sqite3_context"),-1);
+        sq_newclass(v,SQFalse);
+        sq_settypetag(v,-1,(void*)sq_sqlite3_context_TAG);
+        sq_insert_reg_funcs(v, sq_sqlite3_context_methods);
+        sq_newslot(v,-3,SQTrue);
+
+        sq_poptop(v); //remove registrytable
+
+        sq_pushstring(v,_SC("SQLite3"),-1);
+        sq_newclass(v,SQFalse);
+        sq_settypetag(v,-1,(void*)SQLite3_TAG);
+        sq_insert_reg_funcs(v, sq_sqlite3_methods);
+
+        INT_CONST(v,SQLITE_OPEN_CREATE);
+        INT_CONST(v,SQLITE_OPEN_READWRITE);
+        INT_CONST(v,SQLITE_OPEN_SHAREDCACHE);
+        INT_CONST(v,SQLITE_OPEN_SUBLATIN_NA_LIKE);
+
+        INT_CONST(v,SQLITE_OK);
+
+        //push sqlite3_NULL as a member
+        sq_pushstring(v, nullName,-1);
+        sq_pushobject(v, sqlite3_NULL);
+        sq_newslot(v,-3,SQTrue);
+
+        sq_newslot(v,-3,SQTrue);
+
+        sq_pushstring(v,_SC("SQLite3Stmt"),-1);
+        sq_newclass(v,SQFalse);
+        sq_settypetag(v,-1,(void*)SQLite3_Stmt_TAG);
+        sq_insert_reg_funcs(v, sq_sqlite3_stmt_methods);
+
+        INT_CONST(v,SQLITE_OK);
+        INT_CONST(v,SQLITE_ROW);
+        INT_CONST(v,SQLITE_DONE);
+        INT_CONST(v,AS_STRING_ALWAYS);
+        INT_CONST(v,NULL_AS_EMPTY_STR);
+
+        //push sqlite3_NULL as a member
+        sq_pushstring(v, nullName,-1);
+        sq_pushobject(v, sqlite3_NULL);
+        sq_newslot(v,-3,SQTrue);
+
+        sq_newslot(v,-3,SQTrue);
+        return 1;
+    }
+
+#ifdef __cplusplus
+}
+#endif
+

+ 150 - 0
ext/sqbase64.cpp

@@ -0,0 +1,150 @@
+/*
+* lbase64.c
+* base64 encoding and decoding for Lua 5.1
+* Luiz Henrique de Figueiredo <[email protected]>
+* 27 Jun 2007 19:04:40
+* This code is hereby placed in the public domain.
+* Ported to Squrrel by Domingo Alvarez Duarte
+*/
+
+#include "squirrel.h"
+#include <string.h>
+#include "sqstdblobimpl.h"
+
+#define MYNAME		_SC("base64")
+#define MYVERSION	_SC(MYNAME " library for " LUA_VERSION " / Jun 2007")
+
+#define uint unsigned int
+
+static const char code[]=
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void encode(SQBlob &b, uint c1, uint c2, uint c3, int n)
+{
+    unsigned long tuple=c3+256UL*(c2+256UL*c1);
+    int i;
+    char s[4];
+    for (i=0; i<4; i++)
+    {
+        s[3-i] = code[tuple % 64];
+        tuple /= 64;
+    }
+    for (i=n+1; i<4; i++) s[i]='=';
+    b.Write(s,4);
+}
+
+static SQRESULT base64_encode(HSQUIRRELVM v)		/** encode(s) */
+{
+    SQInteger l;
+    const unsigned char *s;
+    SQRESULT rc;
+    if((rc = sq_getstr_and_size(v,2, (const char **)&s, &l)) != SQ_OK) return rc;
+    SQBlob b(0, l*2);
+    int n;
+    for (n=l/3; n--; s+=3) encode(b,s[0],s[1],s[2],3);
+    switch (l%3)
+    {
+    case 1:
+        encode(b,s[0],0,0,1);
+        break;
+    case 2:
+        encode(b,s[0],s[1],0,2);
+        break;
+    }
+    sq_pushstring(v, (SQChar*)b.GetBuf(), b.Len());
+    return 1;
+}
+
+static void decode(SQBlob &b, int c1, int c2, int c3, int c4, int n)
+{
+    unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1));
+    char s[3];
+    switch (--n)
+    {
+    case 3:
+        s[2]=tuple;
+    case 2:
+        s[1]=tuple >> 8;
+    case 1:
+        s[0]=tuple >> 16;
+    }
+    b.Write(s,n);
+}
+
+static SQRESULT base64_decode(HSQUIRRELVM v)		/** decode(s) */
+{
+    SQInteger l;
+    const unsigned char *s;
+    SQRESULT rc;
+    if((rc = sq_getstr_and_size(v,2, (const char **)&s, &l)) != SQ_OK) return rc;
+    SQBlob b(0, l*2);
+    int n=0;
+    char t[4];
+    for (;;)
+    {
+        int c=*s++;
+        switch (c)
+        {
+            const char *p;
+        default:
+            p=strchr(code,c);
+            if (p==NULL) return 0;
+            t[n++]= p-code;
+            if (n==4)
+            {
+                decode(b,t[0],t[1],t[2],t[3],4);
+                n=0;
+            }
+            break;
+        case '=':
+            switch (n)
+            {
+            case 1:
+                decode(b,t[0],0,0,0,1);
+                break;
+            case 2:
+                decode(b,t[0],t[1],0,0,2);
+                break;
+            case 3:
+                decode(b,t[0],t[1],t[2],0,3);
+                break;
+            }
+        case 0:
+            sq_pushstring(v, (SQChar*)b.GetBuf(), b.Len());
+            return 1;
+        case '\n':
+        case '\r':
+        case '\t':
+        case ' ':
+        case '\f':
+        case '\b':
+            break;
+        }
+    }
+    return 0;
+}
+
+#define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),base64_##name,nparams,tycheck}
+static SQRegFunction base64_methods[] =
+{
+    _DECL_FUNC(encode,2,_SC(".s")),
+    _DECL_FUNC(decode,2,_SC(".s")),
+    {0,0}
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    SQRESULT sqstd_register_base64(HSQUIRRELVM v)
+    {
+        sq_pushstring(v,_SC("base64"),-1);
+        sq_newclass(v,SQFalse);
+        sq_insert_reg_funcs(v, base64_methods);
+        sq_newslot(v,-3,SQTrue);
+        return 1;
+    }
+
+#ifdef __cplusplus
+}
+#endif

+ 136 - 0
ext/sqmix.cpp

@@ -0,0 +1,136 @@
+#include "squirrel.h"
+#include "sqstdblobimpl.h"
+
+#define MixInteger SQInteger
+#include "code_mix_prep.c"
+
+/* Generic loader function. Load the data found in the state in the lua engine
+ */
+static SQRESULT mix_loadbuffer(HSQUIRRELVM sqvm, mix_state_t *S, const SQChar *name) {
+	SQRESULT res;
+	S->pos = 0;
+
+	if (S->size > 0 && S->buffer[0] == '#') {
+		while (S->pos < S->size && S->buffer[S->pos] != '\n')
+			++S->pos;
+		++S->pos;
+		S->token = tok_sh;
+	} else {
+		S->token = tok_code_end;
+	}
+
+	S->error = NULL;
+	res = sq_compile(sqvm, sq_mix_reader_char, S, name, SQTrue);
+	if (S->error != NULL) {
+		return sq_throwerror(sqvm, S->error);
+	} else if (res != 0) {
+		sq_pushnull(sqvm);
+		//lua_insert(sqvm, -2);
+		return 2;
+	}
+	return 1;
+}
+
+SQ_OPT_STRING_STRLEN();
+
+/* Read the options common to mix_loadbuffer and mix_loadfile and store them in
+ * the state.
+ */
+static SQRESULT mix_stateopt(HSQUIRRELVM sqvm, mix_state_t *S) {
+    SQ_FUNC_VARS(sqvm);
+
+	SQ_OPT_STRING(sqvm, 3, code_start, "{%");
+	S->code_start = code_start;
+	S->code_startsize = code_start_size;
+	if (S->code_startsize == 0)
+		return sq_throwerror(sqvm, _SC("code_start separator cannot be empty"));
+
+	SQ_OPT_STRING(sqvm, 4, code_end, "%}");
+	S->code_end = code_end;
+	S->code_endsize = code_end_size;
+	if (S->code_endsize == 0)
+		return sq_throwerror(sqvm, _SC("code_end separator cannot be empty"));
+
+	SQ_OPT_STRING(sqvm, 5, expr_code, "=");
+	S->expr = expr_code;
+	S->exprsize = expr_code_size;
+    if (S->exprsize == 0)
+            return sq_throwerror(sqvm, _SC("expr separator cannot be empty"));
+
+	SQ_OPT_STRING(sqvm, 6, print_code, "mix_write");
+    if (print_code_size == 0)
+            return sq_throwerror(sqvm, _SC("mix_write function name cannot be empty"));
+
+
+    snprintf(S->print_out, sizeof(S->print_out), "%s(\"", print_code);
+	S->print_outsize = strlen(S->print_out);
+	S->result_size = 0;
+	return 0;
+}
+
+static SQRESULT mix_loadfile(HSQUIRRELVM sqvm) {
+	const SQChar  *filename;
+	FILE        *file;
+	mix_state_t  S;
+    sq_mix_init(&S, 0, 0, 0,0,0,0);
+
+	sq_getstring(sqvm, 2, &filename);
+	SQRESULT rc = mix_stateopt(sqvm, &S);
+	if(rc) return rc;
+
+	file = fopen(filename, _SC("r"));
+	if (file == NULL) {
+		return sq_throwerror(sqvm, _SC("cannot open file <%s>"), filename);
+	}
+
+	fseek(file, 0, SEEK_END);
+	S.size = ftell(file);
+	fseek(file, 0, SEEK_SET);
+
+	SQBlob buffer(0, S.size);
+	if (fread(buffer.GetBuf(), S.size, 1, file) != 1) {
+		fclose(file);
+		return sq_throwerror(sqvm, _SC("cannot read file <%s>"), filename);
+	}
+	S.buffer = (const char*)buffer.GetBuf();
+	fclose(file);
+
+	return mix_loadbuffer(sqvm, &S, filename);
+}
+
+static SQRESULT mix_loadstring(HSQUIRRELVM sqvm) {
+	mix_state_t S;
+	sq_mix_init(&S, 0, 0, 0,0,0,0);
+
+	sq_getstring(sqvm, 2, &S.buffer);
+	S.size = sq_getsize(sqvm, 2);
+	mix_stateopt(sqvm, &S);
+
+	return mix_loadbuffer(sqvm, &S, "chunk");
+}
+
+#define _DECL_MIX_FUNC(name,nparams,pmask) {_SC(#name), mix_##name,nparams,pmask}
+static SQRegFunction mix_obj_funcs[]={
+	_DECL_MIX_FUNC(loadfile,-2,_SC(".sssss")),
+	_DECL_MIX_FUNC(loadstring,-2,_SC(".sssss")),
+	{0,0}
+};
+#undef _DECL_MIX_FUNC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* This defines a function that opens up your library. */
+SQRESULT sq_register_mix (HSQUIRRELVM sqvm) {
+    //add a namespace sqmix
+	sq_pushstring(sqvm,_SC("sqmix"),-1);
+	sq_newclass(sqvm,SQFalse);
+    sq_insert_reg_funcs(sqvm, mix_obj_funcs);
+	sq_newslot(sqvm,-3,SQTrue); //add sqmix table to the root table
+
+	return SQ_OK;
+}
+
+#ifdef __cplusplus
+}
+#endif