فهرست منبع

added hl mysql library

ncannasse 7 سال پیش
والد
کامیت
f7ab3eee8c
13فایلهای تغییر یافته به همراه2414 افزوده شده و 1 حذف شده
  1. 19 1
      hl.sln
  2. 519 0
      libs/mysql/my_api.c
  3. 415 0
      libs/mysql/my_proto.c
  4. 184 0
      libs/mysql/my_proto.h
  5. 6 0
      libs/mysql/mysq.vcxproj.filters
  6. 373 0
      libs/mysql/mysql.c
  7. 131 0
      libs/mysql/mysql.h
  8. 258 0
      libs/mysql/mysql.vcxproj
  9. 70 0
      libs/mysql/osdef.h
  10. 128 0
      libs/mysql/sha1.c
  11. 40 0
      libs/mysql/sha1.h
  12. 212 0
      libs/mysql/socket.c
  13. 59 0
      libs/mysql/socket.h

+ 19 - 1
hl.sln

@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+VisualStudioVersion = 14.0.25420.1
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdl", "libs\sdl\sdl.vcxproj", "{12049F27-EA26-4A33-ADF8-E542C4167C00}"
 	ProjectSection(ProjectDependencies) = postProject
@@ -60,6 +60,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openal", "libs\openal\opena
 		{C6213FBF-BC2B-4235-A827-84A60E848C52} = {C6213FBF-BC2B-4235-A827-84A60E848C52}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql", "libs\mysql\mysql.vcxproj", "{540E0E11-B7B1-43F8-B107-0867B2D97F74}"
+	ProjectSection(ProjectDependencies) = postProject
+		{C6213FBF-BC2B-4235-A827-84A60E848C52} = {C6213FBF-BC2B-4235-A827-84A60E848C52}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -190,6 +195,18 @@ Global
 		{EC2DCE5C-267A-4050-8DDE-5BF58FF08E31}.ReleaseVS2013|Win32.Build.0 = ReleaseVS2013|Win32
 		{EC2DCE5C-267A-4050-8DDE-5BF58FF08E31}.ReleaseVS2013|x64.ActiveCfg = ReleaseVS2013|x64
 		{EC2DCE5C-267A-4050-8DDE-5BF58FF08E31}.ReleaseVS2013|x64.Build.0 = ReleaseVS2013|x64
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Debug|Win32.ActiveCfg = Debug|Win32
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Debug|Win32.Build.0 = Debug|Win32
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Debug|x64.ActiveCfg = Debug|x64
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Debug|x64.Build.0 = Debug|x64
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Release|Win32.ActiveCfg = Release|Win32
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Release|Win32.Build.0 = Release|Win32
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Release|x64.ActiveCfg = Release|x64
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.Release|x64.Build.0 = Release|x64
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.ReleaseVS2013|Win32.ActiveCfg = ReleaseVS2013|Win32
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.ReleaseVS2013|Win32.Build.0 = ReleaseVS2013|Win32
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.ReleaseVS2013|x64.ActiveCfg = ReleaseVS2013|x64
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74}.ReleaseVS2013|x64.Build.0 = ReleaseVS2013|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -203,5 +220,6 @@ Global
 		{76E4DB00-8114-4B96-BA76-39D800F8D5EE} = {0EC4330B-6B61-45F8-B297-CA7097AFFD98}
 		{EC79BC9F-9947-4BCC-92F9-14F90CDE4B04} = {0EC4330B-6B61-45F8-B297-CA7097AFFD98}
 		{EC2DCE5C-267A-4050-8DDE-5BF58FF08E31} = {0EC4330B-6B61-45F8-B297-CA7097AFFD98}
+		{540E0E11-B7B1-43F8-B107-0867B2D97F74} = {0EC4330B-6B61-45F8-B297-CA7097AFFD98}
 	EndGlobalSection
 EndGlobal

+ 519 - 0
libs/mysql/my_api.c

@@ -0,0 +1,519 @@
+/*
+ * MYSQL 5.0 Protocol Implementation
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include "my_proto.h"
+
+#ifdef OS_WINDOWS
+#define strdup _strdup
+#endif
+
+static void error( MYSQL *m, const char *err, const char *param ) {
+	if( param ) {
+		unsigned int max = MAX_ERR_SIZE - (strlen(err) + 3);
+		if( strlen(param) > max ) {
+			char *p2 = (char*)malloc(max + 1);
+			memcpy(p2,param,max-3);
+			p2[max - 3] = '.';
+			p2[max - 2] = '.';
+			p2[max - 1] = '.';
+			p2[max] = 0;
+			sprintf(m->last_error,err,param);
+			free(p2);
+			return;
+		}
+	}
+	sprintf(m->last_error,err,param);
+	m->errcode = -1;
+}
+
+static void save_error( MYSQL *m, MYSQL_PACKET *p ) {
+	int ecode;
+	p->pos = 0;
+	// seems like we sometimes get some FFFFFF sequences before
+	// the actual error...
+	do {
+		if( myp_read_byte(p) != 0xFF ) {
+			m->errcode = -1;
+			error(m,"Failed to decode error",NULL);
+			return;
+		}
+		ecode = myp_read_ui16(p);
+	} while( ecode == 0xFFFF );
+	if( m->is41 && p->buf[p->pos] == '#' )
+		p->pos += 6; // skip sqlstate marker
+	error(m,"%s",myp_read_string(p));
+	m->errcode = ecode;
+}
+
+static int myp_ok( MYSQL *m, int allow_others ) {
+	int code;
+	MYSQL_PACKET *p = &m->packet;
+	if( !myp_read_packet(m,p) ) {
+		error(m,"Failed to read packet",NULL);
+		return 0;
+	}
+	code = myp_read_byte(p);
+	if( code == 0x00 )
+		return 1;
+	if( code == 0xFF )
+		save_error(m,p);
+	else if( allow_others )
+		return 1;
+	else
+		error(m,"Invalid packet error",NULL);
+	return 0;
+}
+
+static void myp_close( MYSQL *m ) {
+	psock_close(m->s);
+	m->s = INVALID_SOCKET;
+}
+
+MYSQL *mysql_init( void *unused ) {
+	MYSQL *m = (MYSQL*)malloc(sizeof(struct _MYSQL));
+	psock_init();
+	memset(m,0,sizeof(struct _MYSQL));
+	m->s = INVALID_SOCKET;
+	error(m,"NO ERROR",NULL);
+	m->errcode = 0;
+	m->last_field_count = -1;
+	m->last_insert_id = -1;
+	m->affected_rows = -1;
+	return m;
+}
+
+MYSQL *mysql_real_connect( MYSQL *m, const char *host, const char *user, const char *pass, void *unused, int port, const char *socket, int options ) {
+	PHOST h;
+	char scramble_buf[21];
+	MYSQL_PACKET *p = &m->packet;
+	int pcount = 1;
+	if( socket && *socket ) {
+		error(m,"Unix Socket connections are not supported",NULL);
+		return NULL;
+	}
+	h = phost_resolve(host);
+	if( h == UNRESOLVED_HOST ) {
+		error(m,"Failed to resolve host '%s'",host);
+		return NULL;
+	}
+	m->s = psock_create();
+	if( m->s == INVALID_SOCKET ) {
+		error(m,"Failed to create socket",NULL);
+		return NULL;
+	}
+	psock_set_fastsend(m->s,1);
+	psock_set_timeout(m->s,50); // 50 seconds
+	if( psock_connect(m->s,h,port) != PS_OK ) {
+		myp_close(m);
+		error(m,"Failed to connect on host '%s'",host);
+		return NULL;
+	}
+	if( !myp_read_packet(m,p) ) {
+		myp_close(m);
+		error(m,"Failed to read handshake packet",NULL);
+		return NULL;
+	}
+	// process handshake packet
+	{
+		char filler[13];
+		unsigned int len;
+		m->infos.proto_version = myp_read_byte(p);
+		// this seems like an error packet
+		if( m->infos.proto_version == 0xFF ) {
+			myp_close(m);
+			save_error(m,p);
+			return NULL;
+		}	
+		m->infos.server_version = strdup(myp_read_string(p));
+		m->infos.thread_id = myp_read_int(p);
+		myp_read(p,scramble_buf,8);
+		myp_read_byte(p); // should be 0
+		m->infos.server_flags = myp_read_ui16(p);
+		m->infos.server_charset = myp_read_byte(p);
+		m->infos.server_status = myp_read_ui16(p);
+		m->infos.server_flags |= myp_read_ui16(p) << 16;
+		len = myp_read_byte(p);
+		myp_read(p,filler,10);
+		// try to disable 41
+		m->is41 = (m->infos.server_flags & FL_PROTOCOL_41) != 0;
+		if( !p->error && m->is41 )
+			myp_read(p,scramble_buf + 8,13);
+		if( p->pos != p->size )
+			myp_read_string(p); // 5.5+
+		if( p->error ) {
+			myp_close(m);
+			error(m,"Failed to decode server handshake",NULL);
+			return NULL;
+		}
+		// fill answer packet
+		{
+			unsigned int flags = m->infos.server_flags;
+			int max_packet_size = 0x01000000;
+			SHA1_DIGEST hpass;
+			char filler[23];
+			flags &= (FL_PROTOCOL_41 | FL_TRANSACTIONS | FL_SECURE_CONNECTION);
+			myp_begin_packet(p,128);
+			if( m->is41 ) {
+				myp_write_int(p,flags);
+				myp_write_int(p,max_packet_size);
+				myp_write_byte(p,m->infos.server_charset);
+				memset(filler,0,23);
+				myp_write(p,filler,23);
+				myp_write_string(p,user);
+				if( *pass ) {
+					myp_encrypt_password(pass,scramble_buf,hpass);
+					myp_write_bin(p,SHA1_SIZE);
+					myp_write(p,hpass,SHA1_SIZE);
+					myp_write_byte(p,0);
+				} else
+					myp_write_bin(p,0);
+			} else {
+				myp_write_ui16(p,flags);
+				// max_packet_size
+				myp_write_byte(p,0xFF);
+				myp_write_byte(p,0xFF);
+				myp_write_byte(p,0xFF);
+				myp_write_string(p,user);
+				if( *pass ) {
+					char hpass[SEED_LENGTH_323 + 1];
+					myp_encrypt_pass_323(pass,scramble_buf,hpass);
+					hpass[SEED_LENGTH_323] = 0;
+					myp_write(p,hpass,SEED_LENGTH_323 + 1);
+				} else
+					myp_write_bin(p,0);
+			}
+		}
+	}
+	// send connection packet
+send_cnx_packet:
+	if( !myp_send_packet(m,p,&pcount) ) {
+		myp_close(m);
+		error(m,"Failed to send connection packet",NULL);
+		return NULL;
+	}
+	// read answer packet
+	if( !myp_read_packet(m,p) ) {
+		myp_close(m);
+		error(m,"Failed to read packet",NULL);
+		return NULL;
+	}
+	// increase packet counter (because we read one packet)
+	pcount++;
+	// process answer
+	{
+		int code = myp_read_byte(p);
+		switch( code ) {
+		case 0: // OK packet
+			break;
+		case 0xFF: // ERROR
+			myp_close(m);
+			save_error(m,p);
+			return NULL;
+		case 0xFE: // EOF
+			// we are asked to send old password authentification
+			if( p->size == 1 ) {
+				char hpass[SEED_LENGTH_323 + 1];
+				myp_encrypt_pass_323(pass,scramble_buf,hpass);
+				hpass[SEED_LENGTH_323] = 0;
+				myp_begin_packet(p,0);
+				myp_write(p,hpass,SEED_LENGTH_323 + 1);
+				goto send_cnx_packet;
+			}
+			// fallthrough
+		default:
+			myp_close(m);
+			error(m,"Invalid packet error",NULL);
+			return NULL;
+		}
+	}
+	// we are connected, setup a longer timeout
+	psock_set_timeout(m->s,18000);
+	return m;
+}
+
+int mysql_select_db( MYSQL *m, const char *dbname ) {
+	MYSQL_PACKET *p = &m->packet;
+	int pcount = 0;
+	myp_begin_packet(p,0);
+	myp_write_byte(p,COM_INIT_DB);
+	myp_write_string_eof(p,dbname);
+	if( !myp_send_packet(m,p,&pcount) ) {
+		error(m,"Failed to send packet",NULL);
+		return -1;
+	}
+	return myp_ok(m,0) ? 0 : -1;
+}
+
+int mysql_real_query( MYSQL *m, const char *query, int qlength ) {
+	MYSQL_PACKET *p = &m->packet;
+	int pcount = 0;
+	myp_begin_packet(p,0);
+	myp_write_byte(p,COM_QUERY);
+	myp_write(p,query,qlength);
+	m->last_field_count = -1;
+	m->affected_rows = -1;
+	m->last_insert_id = -1;
+	if( !myp_send_packet(m,p,&pcount) ) {
+		error(m,"Failed to send packet",NULL);
+		return -1;
+	}
+	if( !myp_ok(m,1) )
+		return -1;
+	p->id = IS_QUERY;
+	return 0;
+}
+
+static int do_store( MYSQL *m, MYSQL_RES *r ) {
+	int i;
+	MYSQL_PACKET *p = &m->packet;
+	p->pos = 0;
+	r->nfields = myp_read_bin(p);
+	if( p->error ) return 0;
+	r->fields = (MYSQL_FIELD*)malloc(sizeof(MYSQL_FIELD) * r->nfields);
+	memset(r->fields,0,sizeof(MYSQL_FIELD) * r->nfields);
+	for(i=0;i<r->nfields;i++) {
+		if( !myp_read_packet(m,p) )
+			return 0;
+		{
+			MYSQL_FIELD *f = r->fields + i;
+			f->catalog = m->is41 ? myp_read_bin_str(p) : NULL;
+			f->db = m->is41 ? myp_read_bin_str(p) : NULL;
+			f->table = myp_read_bin_str(p);
+			f->org_table = m->is41 ? myp_read_bin_str(p) : NULL;
+			f->name = myp_read_bin_str(p);
+			f->org_name = m->is41 ? myp_read_bin_str(p) : NULL;
+			if( m->is41 ) myp_read_byte(p);
+			f->charset = m->is41 ? myp_read_ui16(p) : 0x08;
+			f->length = m->is41 ? myp_read_int(p) : myp_read_bin(p);
+			f->type = m->is41 ? myp_read_byte(p) : myp_read_bin(p);
+			f->flags = m->is41 ? myp_read_ui16(p) : myp_read_bin(p);
+			f->decimals = myp_read_byte(p);
+			if( m->is41 ) myp_read_byte(p); // should be 0
+			if( m->is41 ) myp_read_byte(p); // should be 0
+			if( p->error )
+				return 0;
+		}
+	}
+	// first EOF packet
+	if( !myp_read_packet(m,p) )
+		return 0;
+	if( myp_read_byte(p) != 0xFE || p->size >= 9 )
+		return 0;
+	// reset packet buffer (to prevent to store large buffer in row data)
+	free(p->buf);
+	p->buf = NULL;
+	p->mem = 0;
+	// datas
+	while( 1 ) {
+		if( !myp_read_packet(m,p) )
+			return 0;
+		// EOF : end of datas
+		if( (unsigned char)p->buf[0] == 0xFE && p->size < 9 )
+			break;
+		// ERROR ?
+		if( (unsigned char)p->buf[0] == 0xFF ) {
+			save_error(m,p);
+			return 0;
+		}
+		// allocate one more row
+		if( r->row_count == r->memory_rows ) {
+			MYSQL_ROW_DATA *rows;
+			r->memory_rows = r->memory_rows ? (r->memory_rows << 1) : 1;
+			rows = (MYSQL_ROW_DATA*)malloc(r->memory_rows * sizeof(MYSQL_ROW_DATA));
+			memcpy(rows,r->rows,r->row_count * sizeof(MYSQL_ROW_DATA));
+			free(r->rows);
+			r->rows = rows;
+		}
+		// read row fields
+		{
+			MYSQL_ROW_DATA *current = r->rows + r->row_count++;
+			int prev = 0;			
+			current->raw = p->buf;
+			current->lengths = (unsigned long*)malloc(sizeof(unsigned long) * r->nfields);
+			current->datas = (char**)malloc(sizeof(char*) * r->nfields);
+			for(i=0;i<r->nfields;i++) {
+				int l = myp_read_bin(p);
+				if( !p->error )
+					p->buf[prev] = 0;
+				if( l == -1 ) {
+					current->lengths[i] = 0;
+					current->datas[i] = NULL;
+				} else {
+					current->lengths[i] = l;
+					current->datas[i] = p->buf + p->pos;
+					p->pos += l;
+				}
+				prev = p->pos;
+			}
+			if( !p->error )
+				p->buf[prev] = 0;
+		}
+		// the packet buffer as been stored, don't reuse it
+		p->buf = NULL;
+		p->mem = 0;
+		if( p->error )
+			return 0;
+	}
+	return 1;
+}
+
+MYSQL_RES *mysql_store_result( MYSQL *m ) {
+	MYSQL_RES *r;
+	MYSQL_PACKET *p = &m->packet;
+	if( p->id != IS_QUERY )
+		return NULL;
+	// OK without result
+	if( p->buf[0] == 0 ) {
+		p->pos = 0;
+		m->last_field_count = myp_read_byte(p); // 0
+		m->affected_rows = myp_read_bin(p);
+		m->last_insert_id = myp_read_bin(p);
+		return NULL;
+	}
+	r = (MYSQL_RES*)malloc(sizeof(struct _MYSQL_RES));
+	memset(r,0,sizeof(struct _MYSQL_RES));
+	m->errcode = 0;
+	if( !do_store(m,r) ) {
+		mysql_free_result(r);
+		if( !m->errcode )
+			error(m,"Failure while storing result",NULL);
+		return NULL;
+	}
+	m->last_field_count = r->nfields;
+	return r;
+}
+
+int mysql_field_count( MYSQL *m ) {
+	return m->last_field_count;
+}
+
+int mysql_affected_rows( MYSQL *m ) {
+	return m->affected_rows;
+}
+
+int mysql_escape_string( MYSQL *m, char *sout, const char *sin, int length ) {
+	return myp_escape_string(m->infos.server_charset,sout,sin,length);
+}
+
+const char *mysql_character_set_name( MYSQL *m ) {
+	const char *name = myp_charset_name(m->infos.server_charset);
+	if( name == NULL ) {
+		static char tmp[512];
+		sprintf(tmp,"#%d",m->infos.server_charset);
+		return tmp;
+	}
+	return name;
+}
+
+int mysql_real_escape_string( MYSQL *m, char *sout, const char *sin, int length ) {
+	if( !myp_supported_charset(m->infos.server_charset) )
+		return -1;
+	if( m->infos.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES )
+		return myp_escape_quotes(m->infos.server_charset,sout,sin,length);
+	return myp_escape_string(m->infos.server_charset,sout,sin,length);
+}
+
+void mysql_close( MYSQL *m ) {
+	myp_close(m);
+	free(m->packet.buf);
+	free(m->infos.server_version);
+	free(m);
+}
+
+const char *mysql_error( MYSQL *m ) {
+	return m->last_error;
+}
+
+// RESULTS API
+
+unsigned int mysql_num_rows( MYSQL_RES *r ) {
+	return r->row_count;
+}
+
+int mysql_num_fields( MYSQL_RES *r ) {
+	return r->nfields;
+}
+
+MYSQL_FIELD *mysql_fetch_fields( MYSQL_RES *r ) {
+	return r->fields;
+}
+
+unsigned long *mysql_fetch_lengths( MYSQL_RES *r ) {
+	return r->current ? r->current->lengths : NULL;
+}
+
+MYSQL_ROW mysql_fetch_row( MYSQL_RES * r ) {
+	MYSQL_ROW_DATA *cur = r->current;
+	if( cur == NULL )
+		cur = r->rows;
+	else {
+		// free the previous result, since we're done with it
+		free(cur->datas);
+		free(cur->lengths);
+		free(cur->raw);
+		cur->datas = NULL;
+		cur->lengths = NULL;
+		cur->raw = NULL;
+		// next
+		cur++;
+	}
+	if( cur >= r->rows + r->row_count ) {		
+		free(r->rows);
+		r->rows = NULL;
+		r->memory_rows = 0;
+		cur = NULL;	
+	}
+	r->current = cur;
+	return cur ? cur->datas : NULL;
+}
+
+void mysql_free_result( MYSQL_RES *r ) {
+	if( r->fields ) {
+		int i;
+		for(i=0;i<r->nfields;i++) {
+			MYSQL_FIELD *f = r->fields + i;
+			free(f->catalog);
+			free(f->db);
+			free(f->table);
+			free(f->org_table);
+			free(f->name);
+			free(f->org_name);
+		}
+		free(r->fields);
+	}
+	if( r->rows ) {
+		int i;
+		for(i=0;i<r->row_count;i++) {
+			MYSQL_ROW_DATA *row = r->rows + i;
+			free(row->datas);
+			free(row->lengths);
+			free(row->raw);
+		}
+		free(r->rows);
+	}
+	free(r);
+}
+
+/* ************************************************************************ */

+ 415 - 0
libs/mysql/my_proto.c

@@ -0,0 +1,415 @@
+/*
+ * MYSQL 5.0 Protocol Implementation
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "my_proto.h"
+
+#define MAX_PACKET_LENGTH 0xFFFFFF
+
+int myp_recv( MYSQL *m, void *buf, int size ) {
+	while( size ) {
+		int len = psock_recv(m->s,(char*)buf,size);
+		if( len <= 0 ) return size == 0 ? 1 : 0;
+		buf = ((char*)buf) + len;
+		size -= len;
+	}
+	return 1;
+}
+
+
+int myp_send( MYSQL *m, void *buf, int size ) {
+	while( size ) {
+		int len = psock_send(m->s,(char*)buf,size);
+		if( len <= 0 ) return size == 0 ? 1 : 0;
+		buf = ((char*)buf) + len;
+		size -= len;
+	}
+	return 1;
+}
+
+int myp_read( MYSQL_PACKET *p, void *buf, int size ) {
+	if( p->size - p->pos < size ) {
+		p->error = 1;
+		return 0;
+	}
+	memcpy(buf,p->buf + p->pos,size);
+	p->pos += size;
+	return 1;
+}
+
+unsigned char myp_read_byte( MYSQL_PACKET *p ) {
+	unsigned char c;
+	if( !myp_read(p,&c,1) )
+		return 0;
+	return c;
+}
+
+unsigned short myp_read_ui16( MYSQL_PACKET *p ) {
+	unsigned short i;
+	if( !myp_read(p,&i,2) )
+		return 0;
+	return i;
+}
+
+int myp_read_int( MYSQL_PACKET *p ) {
+	int i;
+	if( !myp_read(p,&i,4) )
+		return 0;
+	return i;
+}
+
+int myp_read_bin( MYSQL_PACKET *p ) {
+	int c = myp_read_byte(p);
+	if( c <= 250 )
+		return c;
+	if( c == 251 )
+		return -1; // NULL
+	if( c == 252 )
+		return myp_read_ui16(p);
+	if( c == 253 ) {
+		c = 0;
+		myp_read(p,&c,3);
+		return c;
+	}
+	if( c == 254 )
+		return myp_read_int(p);
+	p->error = 1;
+	return 0;
+}
+
+const char *myp_read_string( MYSQL_PACKET *p ) {
+	char *str;
+	if( p->pos >= p->size ) {
+		p->error = 1;
+		return "";
+	}
+	str = p->buf + p->pos;
+	p->pos += strlen(str) + 1;
+	return str;
+}
+
+char *myp_read_bin_str( MYSQL_PACKET *p ) {
+	int size = myp_read_bin(p);
+	char *str;
+	if( size == -1 )
+		return NULL;
+	if( p->error || p->pos + size > p->size ) {
+		p->error = 1;
+		return NULL;
+	}
+	str = (char*)malloc(size + 1);
+	memcpy(str,p->buf + p->pos, size);
+	str[size] = 0;
+	p->pos += size;
+	return str;
+}
+
+int myp_read_packet( MYSQL *m, MYSQL_PACKET *p ) {
+	unsigned int psize;
+	p->pos = 0;
+	p->error = 0;
+	if( !myp_recv(m,&psize,4) ) {
+		p->error = 1;
+		p->size = 0;
+		return 0;
+	}
+	//p->id = (psize >> 24);
+	psize &= 0xFFFFFF;
+	p->size = psize;
+	if( p->mem < (int)psize ) {
+		free(p->buf);
+		p->buf = (char*)malloc(psize + 1);
+		p->mem = psize;
+	}
+	p->buf[psize] = 0;
+	if( psize == 0 || !myp_recv(m,p->buf,psize) ) {
+		p->error = 1;
+		p->size = 0;
+		p->buf[0] = 0;
+		return 0;
+	}
+	return 1;
+}
+
+int myp_send_packet( MYSQL *m, MYSQL_PACKET *p, int *packet_counter ) {
+	unsigned int header;
+	char *buf = p->buf;
+	int size = p->size;
+	int next = 1;
+	while( next ) {
+		int psize;
+		if( size >= MAX_PACKET_LENGTH )
+			psize = MAX_PACKET_LENGTH;
+		else {
+			psize = size;
+			next = 0;
+		}
+		header = psize | (((*packet_counter)++) << 24);
+		if( !myp_send(m,&header,4) || !myp_send(m,buf,psize) ) {
+			p->error = 1;
+			return 0;
+		}
+		buf += psize;
+		size -= psize;
+	}
+	return 1;
+}
+
+void myp_begin_packet( MYSQL_PACKET *p, int minsize ) {
+	if( p->mem < minsize ) {
+		free(p->buf);
+		p->buf = (char*)malloc(minsize + 1);
+		p->mem = minsize;
+	}
+	p->error = 0;
+	p->size = 0;
+}
+
+void myp_write( MYSQL_PACKET *p, const void *data, int size ) {
+	if( p->size + size > p->mem ) {
+		char *buf2;
+		if( p->mem == 0 ) p->mem = 32;
+		do {
+			p->mem <<= 1;
+		} while( p->size + size > p->mem );
+		buf2 = (char*)malloc(p->mem + 1);
+		memcpy(buf2,p->buf,p->size);
+		free(p->buf);
+		p->buf = buf2;
+	}
+	memcpy( p->buf + p->size , data, size );
+	p->size += size;
+}
+
+void myp_write_byte( MYSQL_PACKET *p, int i ) {
+	unsigned char c = (unsigned char)i;
+	myp_write(p,&c,1);
+}
+
+void myp_write_ui16( MYSQL_PACKET *p, int i ) {
+	unsigned short c = (unsigned char)i;
+	myp_write(p,&c,2);
+}
+
+void myp_write_int( MYSQL_PACKET *p, int i ) {
+	myp_write(p,&i,4);
+}
+
+void myp_write_string( MYSQL_PACKET *p, const char *str ) {
+	myp_write(p,str,strlen(str) + 1);
+}
+
+void myp_write_string_eof( MYSQL_PACKET *p, const char *str ) {
+	myp_write(p,str,strlen(str));
+}
+
+void myp_write_bin( MYSQL_PACKET *p, int size ) {
+	if( size <= 250 ) {
+		unsigned char l = (unsigned char)size;
+		myp_write(p,&l,1);
+	} else if( size < 0x10000 ) {
+		unsigned char c = 252;
+		unsigned short l = (unsigned short)size;
+		myp_write(p,&c,1);
+		myp_write(p,&l,2);
+	} else if( size < 0x1000000 ) {
+		unsigned char c = 253;
+		unsigned int l = (unsigned short)size;
+		myp_write(p,&c,1);
+		myp_write(p,&l,3);
+	} else {
+		unsigned char c = 254;
+		myp_write(p,&c,1);
+		myp_write(p,&size,4);
+	}
+}
+
+void myp_crypt( unsigned char *out, const unsigned char *s1, const unsigned char *s2, unsigned int len ) {
+	unsigned int i;
+	for(i=0;i<len;i++)
+		out[i] = s1[i] ^ s2[i];
+}
+
+void myp_encrypt_password( const char *pass, const char *seed, SHA1_DIGEST out ) {
+	SHA1_CTX ctx;
+	SHA1_DIGEST hash_stage1, hash_stage2;
+	// stage 1: hash password
+	sha1_init(&ctx);
+	sha1_update(&ctx,pass,strlen(pass));;
+	sha1_final(&ctx,hash_stage1);
+	// stage 2: hash stage 1; note that hash_stage2 is stored in the database
+	sha1_init(&ctx);
+	sha1_update(&ctx, hash_stage1, SHA1_SIZE);
+	sha1_final(&ctx, hash_stage2);
+	// create crypt string as sha1(message, hash_stage2)
+	sha1_init(&ctx);
+	sha1_update(&ctx, seed, SHA1_SIZE);
+	sha1_update(&ctx, hash_stage2, SHA1_SIZE);
+	sha1_final( &ctx, out );
+	// xor the result
+	myp_crypt(out,out,hash_stage1,SHA1_SIZE);
+}
+
+typedef struct {
+	unsigned long seed1;
+	unsigned long seed2;
+	unsigned long max_value;
+	double max_value_dbl;
+} rand_ctx;
+
+static void random_init( rand_ctx *r, unsigned long seed1, unsigned long seed2 ) {
+	r->max_value = 0x3FFFFFFFL;
+	r->max_value_dbl = (double)r->max_value;
+	r->seed1 = seed1 % r->max_value ;
+	r->seed2 = seed2 % r->max_value;
+}
+
+static double myp_rnd( rand_ctx *r ) {
+	r->seed1 = (r->seed1 * 3 + r->seed2) % r->max_value;
+	r->seed2 = (r->seed1 + r->seed2 + 33) % r->max_value;
+	return (((double) r->seed1)/r->max_value_dbl);
+}
+
+static void hash_password( unsigned long *result, const char *password, int password_len ) {
+	register unsigned long nr = 1345345333L, add = 7, nr2 = 0x12345671L;
+	unsigned long tmp;
+	const char *password_end = password + password_len;
+	for(; password < password_end; password++) {
+		if( *password == ' ' || *password == '\t' )
+			continue;
+		tmp = (unsigned long)(unsigned char)*password;
+		nr ^= (((nr & 63)+add)*tmp)+(nr << 8);
+		nr2 += (nr2 << 8) ^ nr;
+		add += tmp;
+	}
+	result[0] = nr & (((unsigned long) 1L << 31) -1L);
+	result[1] = nr2 & (((unsigned long) 1L << 31) -1L);
+}
+
+void myp_encrypt_pass_323( const char *password, const char seed[SEED_LENGTH_323], char to[SEED_LENGTH_323] ) {
+	rand_ctx r;
+	unsigned long hash_pass[2], hash_seed[2];
+	char extra, *to_start = to;
+	const char *seed_end = seed + SEED_LENGTH_323;
+	hash_password(hash_pass,password,(unsigned int)strlen(password));
+	hash_password(hash_seed,seed,SEED_LENGTH_323);
+	random_init(&r,hash_pass[0] ^ hash_seed[0],hash_pass[1] ^ hash_seed[1]);
+	while( seed < seed_end ) {
+		*to++ = (char)(floor(myp_rnd(&r)*31)+64);
+		seed++;
+	}
+	extra= (char)(floor(myp_rnd(&r)*31));
+	while( to_start != to )
+		*(to_start++) ^= extra;
+}
+
+// defined in mysql/strings/ctype-*.c
+const char *myp_charset_name( int charset ) {
+	switch( charset ) {
+	case 8:
+	case 31:
+	case 47:
+		return "latin1";
+	case 63:
+		return "binary";
+	// 101+ : utf16
+	// 160+ : utf32
+	case 33:
+	case 83:
+	case 223:
+	case 254:
+		return "utf8";
+	case 45:
+	case 46:
+		return "utf8mb4"; // superset of utf8 with up to 4 bytes per-char
+	default:
+		if( charset >= 192 && charset <= 211 )
+			return "utf8";
+		if( charset >= 224 && charset <= 243 )
+			return "utf8mb4";
+	}
+	return NULL;
+}
+
+int myp_supported_charset( int charset ) {
+	return myp_charset_name(charset) != NULL;
+}
+
+int myp_escape_string( int charset, char *sout, const char *sin, int length ) {
+	// this is safe for UTF8 as well since mysql protects against invalid UTF8 char injection
+	const char *send = sin + length;
+	char *sbegin = sout;
+	while( sin != send ) {
+		char c = *sin++;
+		switch( c ) {
+		case 0:
+			*sout++ = '\\';
+			*sout++ = '0';
+			break;
+		case '\n':
+			*sout++ = '\\';
+			*sout++ = 'n';
+			break;
+		case '\r':
+			*sout++ = '\\';
+			*sout++ = 'r';
+			break;
+		case '\\':
+			*sout++ = '\\';
+			*sout++ = '\\';
+			break;
+		case '\'':
+			*sout++ = '\\';
+			*sout++ = '\'';
+			break;
+		case '"':
+			*sout++ = '\\';
+			*sout++ = '"';
+			break;
+		case '\032':
+			*sout++ = '\\';
+			*sout++ = 'Z';
+			break;
+		default:
+			*sout++ = c;
+		}
+	}
+	*sout = 0;
+	return sout - sbegin;
+}
+
+int myp_escape_quotes( int charset, char *sout, const char *sin, int length ) {
+	const char *send = sin + length;
+	char *sbegin = sout;
+	while( sin != send ) {
+		char c = *sin++;
+		*sout++ = c;
+		if( c == '\'' )
+			*sout++ = c;
+	}
+	*sout = 0;
+	return sout - sbegin;
+}
+
+/* ************************************************************************ */

+ 184 - 0
libs/mysql/my_proto.h

@@ -0,0 +1,184 @@
+/*
+ * MYSQL 5.0 Protocol Implementation
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#ifndef MY_PROTO_H
+#define MY_PROTO_H
+
+#include "mysql.h"
+#include "socket.h"
+#include "sha1.h"
+
+typedef enum {
+	FL_LONG_PASSWORD = 1,
+	FL_FOUND_ROWS = 2,
+	FL_LONG_FLAG = 4,
+	FL_CONNECT_WITH_DB = 8,
+	FL_NO_SCHEMA = 16,
+	FL_COMPRESS = 32,
+	FL_ODBC = 64,
+	FL_LOCAL_FILES = 128,
+	FL_IGNORE_SPACE	= 256,
+	FL_PROTOCOL_41 = 512,
+	FL_INTERACTIVE = 1024,
+	FL_SSL = 2048,
+	FL_IGNORE_SIGPIPE = 4096,
+	FL_TRANSACTIONS = 8192,
+	FL_RESERVED = 16384,
+	FL_SECURE_CONNECTION = 32768,
+	FL_MULTI_STATEMENTS  = 65536,
+	FL_MULTI_RESULTS = 131072,
+} MYSQL_FLAG;
+
+typedef enum {
+	COM_SLEEP = 0x00,
+	COM_QUIT = 0x01,
+	COM_INIT_DB = 0x02,
+	COM_QUERY = 0x03,
+	COM_FIELD_LIST = 0x04,
+	//COM_CREATE_DB = 0x05,
+	//COM_DROP_DB = 0x06
+	COM_REFRESH = 0x07,
+	COM_SHUTDOWN = 0x08,
+	COM_STATISTICS = 0x09,
+	COM_PROCESS_INFO = 0x0A,
+	//COM_CONNECT = 0x0B,
+	COM_PROCESS_KILL = 0x0C,
+	COM_DEBUG = 0x0D,
+	COM_PING = 0x0E,
+	//COM_TIME = 0x0F,
+	//COM_DELAYED_INSERT = 0x10,
+	COM_CHANGE_USER = 0x11,
+	COM_BINLOG_DUMP = 0x12,
+	COM_TABLE_DUMP = 0x13,
+	COM_CONNECT_OUT = 0x14,
+	COM_REGISTER_SLAVE = 0x15,
+	COM_STMT_PREPARE = 0x16,
+	COM_STMT_EXECUTE = 0x17,
+	COM_STMT_SEND_LONG_DATA = 0x18,
+	COM_STMT_CLOSE = 0x19,
+	COM_STMT_RESET = 0x1A,
+	COM_SET_OPTION = 0x1B,
+	COM_STMT_FETCH = 0x1C,
+} MYSQL_COMMAND;
+
+typedef enum {
+	SERVER_STATUS_IN_TRANS = 1,
+	SERVER_STATUS_AUTOCOMMIT = 2,
+	SERVER_MORE_RESULTS_EXISTS = 8,
+	SERVER_QUERY_NO_GOOD_INDEX_USED = 16,
+	SERVER_QUERY_NO_INDEX_USED = 32,
+	SERVER_STATUS_CURSOR_EXISTS = 64,
+	SERVER_STATUS_LAST_ROW_SENT = 128,
+	SERVER_STATUS_DB_DROPPED = 256,
+	SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512,
+} MYSQL_SERVER_STATUS;
+
+typedef struct {
+	unsigned char proto_version;
+	char *server_version;
+	unsigned int thread_id;
+	unsigned int server_flags;
+	unsigned char server_charset;
+	unsigned short server_status;
+} MYSQL_INFOS;
+
+typedef struct {
+	int id;
+	int error;
+	int size;
+	int pos;
+	int mem;
+	char *buf;
+} MYSQL_PACKET;
+
+#define MAX_ERR_SIZE	1024
+#define	IS_QUERY		-123456
+
+struct _MYSQL {
+	PSOCK s;
+	MYSQL_INFOS infos;
+	MYSQL_PACKET packet;
+	int is41;
+	int errcode;
+	int last_field_count;
+	int affected_rows;
+	int last_insert_id;
+	char last_error[MAX_ERR_SIZE];
+};
+
+typedef struct {
+	char *raw;
+	unsigned long *lengths;
+	char **datas;
+} MYSQL_ROW_DATA;
+
+struct _MYSQL_RES {
+	int nfields;
+	MYSQL_FIELD *fields;
+	MYSQL_ROW_DATA *rows;
+	MYSQL_ROW_DATA *current;
+	int row_count;
+	int memory_rows;
+};
+
+
+// network
+int myp_recv( MYSQL *m, void *buf, int size );
+int myp_send( MYSQL *m, void *buf, int size );
+int myp_read_packet( MYSQL *m, MYSQL_PACKET *p );
+int myp_send_packet( MYSQL *m, MYSQL_PACKET *p, int *packet_counter );
+
+// packet read
+int myp_read( MYSQL_PACKET *p, void *buf, int size );
+unsigned char myp_read_byte( MYSQL_PACKET *p );
+unsigned short myp_read_ui16( MYSQL_PACKET *p );
+int myp_read_int( MYSQL_PACKET *p );
+const char *myp_read_string( MYSQL_PACKET *p );
+int myp_read_bin( MYSQL_PACKET *p );
+char *myp_read_bin_str( MYSQL_PACKET *p );
+
+// packet write
+void myp_begin_packet( MYSQL_PACKET *p, int minsize );
+void myp_write( MYSQL_PACKET *p, const void *data, int size );
+void myp_write_byte( MYSQL_PACKET *p, int b );
+void myp_write_ui16( MYSQL_PACKET *p, int b );
+void myp_write_int( MYSQL_PACKET *p, int b );
+
+void myp_write_string( MYSQL_PACKET *p, const char *str );
+void myp_write_string_eof( MYSQL_PACKET *p, const char *str );
+void myp_write_bin( MYSQL_PACKET *p, int size );
+
+// passwords
+#define SEED_LENGTH_323 8
+
+void myp_crypt( unsigned char *out, const unsigned char *s1, const unsigned char *s2, unsigned int len );
+void myp_encrypt_password( const char *pass, const char *seed, SHA1_DIGEST out );
+void myp_encrypt_pass_323( const char *pass, const char seed[SEED_LENGTH_323], char out[SEED_LENGTH_323] );
+
+// escaping
+int myp_supported_charset( int charset );
+const char *myp_charset_name( int charset );
+int myp_escape_string( int charset, char *sout, const char *sin, int length );
+int myp_escape_quotes( int charset, char *sout, const char *sin, int length );
+
+#endif
+/* ************************************************************************ */

+ 6 - 0
libs/mysql/mysq.vcxproj.filters

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="mysql.c" />
+  </ItemGroup>
+</Project>

+ 373 - 0
libs/mysql/mysql.c

@@ -0,0 +1,373 @@
+/*
+ * Copyright (C)2005-2018 Haxe Foundation
+ *
+ * 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.
+ */
+#define HL_NAME(n)	mysql_ ## n
+#include <hl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "mysql.h"
+#include <string.h>
+
+HL_PRIM void error( MYSQL *m, const char *msg ) {
+	hl_buffer *b = hl_alloc_buffer();
+	hl_buffer_cstr(b,msg);
+	hl_buffer_cstr(b," ");
+	hl_buffer_cstr(b,mysql_error(m));
+	hl_throw_buffer(b);
+}
+
+// ---------------------------------------------------------------
+// Result
+
+#undef CONV_FLOAT
+typedef enum {
+	CONV_INT,
+	CONV_STRING,
+	CONV_FLOAT,
+	CONV_BINARY,
+	CONV_DATE,
+	CONV_DATETIME,
+	CONV_BOOL
+} CONV;
+
+typedef struct {
+	void (*free)( void * );
+	MYSQL_RES *r;
+	int nfields;
+	CONV *fields_convs;
+	int *fields_ids;
+	MYSQL_ROW current;
+} result;
+
+typedef struct {
+	void (*free)( void * );
+	MYSQL *c;
+} connection;
+
+static vclosure *conv_string = NULL;
+static vclosure *conv_bytes = NULL;
+static vclosure *conv_date = NULL;
+
+static void free_result( result *r ) {
+	mysql_free_result(r->r);
+	free(r->fields_ids);
+	free(r->fields_convs);
+}
+
+HL_PRIM int HL_NAME(result_get_length)( result *r ) {
+	if( r->r == NULL )
+		return r->nfields;	
+	return (int)mysql_num_rows(r->r);
+}
+
+HL_PRIM int HL_NAME(result_get_nfields)( result *r ) {
+	return r->nfields;
+}
+
+HL_PRIM varray *HL_NAME(result_get_fields_names)( result *r ) {
+	int k;
+	MYSQL_FIELD *fields = mysql_fetch_fields(r->r);
+	varray *a = hl_alloc_array(&hlt_bytes,r->nfields);
+	for(k=0;k<r->nfields;k++)
+		hl_aptr(a,vbyte*)[k] = fields[k].name;
+	return a;
+}
+
+HL_PRIM vdynamic *HL_NAME(result_next)( result *r ) {
+	unsigned long *lengths = NULL;
+	MYSQL_ROW row = mysql_fetch_row(r->r);
+	if( row == NULL )
+		return NULL;
+	int i;
+	struct tm t;
+	vdynamic *obj = (vdynamic*)hl_alloc_dynobj();
+	vdynamic arg;
+	vdynamic length;
+	vdynamic *pargs[2];	
+	pargs[0] = &arg;
+	pargs[1] = &length;
+	length.t = &hlt_i32;
+	r->current = row;
+	for(i=0;i<r->nfields;i++) {
+		if( row[i] == NULL ) continue;		
+		vdynamic *value = NULL;
+		switch( r->fields_convs[i] ) {
+		case CONV_INT:
+			hl_dyn_seti(obj, r->fields_ids[i], &hlt_i32, atoi(row[i]));
+			break;
+		case CONV_STRING:
+			arg.t = &hlt_bytes;
+			arg.v.ptr = row[i];
+			value = hl_dyn_call(conv_string, pargs, 1);
+			break;
+		case CONV_BOOL:
+			hl_dyn_seti(obj, r->fields_ids[i], &hlt_bool, (int)(*row[i] != '0'));
+			break;
+		case CONV_FLOAT:
+			hl_dyn_setd(obj, r->fields_ids[i], atof(row[i]));
+			break;
+		case CONV_BINARY:
+			if( lengths == NULL ) {
+				lengths = mysql_fetch_lengths(r->r);
+				if( lengths == NULL ) hl_error("mysql_fetch_lengths");
+			}
+			arg.t = &hlt_bytes;
+			arg.v.ptr = row[i];
+			length.v.i = lengths[i];
+			value = hl_dyn_call(conv_bytes, pargs, 2);
+			break;
+		case CONV_DATE:
+			sscanf(row[i],"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday);
+			t.tm_hour = 0;
+			t.tm_min = 0;
+			t.tm_sec = 0;
+			t.tm_isdst = -1;
+			t.tm_year -= 1900;
+			t.tm_mon--;
+			arg.t = &hlt_i32;
+			arg.v.i = (int)mktime(&t);
+			value = hl_dyn_call(conv_date,pargs, 1);
+			break;
+		case CONV_DATETIME:
+			sscanf(row[i],"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+			t.tm_isdst = -1;
+			t.tm_year -= 1900;
+			t.tm_mon--;
+			arg.t = &hlt_i32;
+			arg.v.i = (int)mktime(&t);
+			value = hl_dyn_call(conv_date,pargs, 1);
+			break;
+		default:
+			break;
+		}
+		if( value ) hl_dyn_setp(obj, r->fields_ids[i], &hlt_dyn, value);
+
+	}
+	return obj;
+}
+
+
+HL_PRIM vbyte *HL_NAME(result_get)( result *r, int n ) {
+	const char *str;
+	if( n < 0 || n >= r->nfields )
+		return NULL;
+	if( !r->current ) {
+		HL_NAME(result_next)(r);
+		if( !r->current )
+			return NULL;
+	}
+	str = r->current[n];
+	return (vbyte*)(str ? str : "");
+}
+
+HL_PRIM int HL_NAME(result_get_int)( result *r, int n ) {
+	const char *str;
+	if( n < 0 || n >= r->nfields )
+		return 0;
+	if( !r->current ) {
+		HL_NAME(result_next)(r);
+		if( !r->current )
+			return 0;
+	}
+	str = r->current[n];
+	return str ? atoi(str) : 0;
+}
+
+HL_PRIM double HL_NAME(result_get_float)( result *r, int n ) {
+	const char *str;
+	if( n < 0 || n >= r->nfields )
+		return 0.;
+	if( !r->current ) {
+		HL_NAME(result_next)(r);
+		if( !r->current )
+			return 0.;
+	}
+	str = r->current[n];
+	return str ? atof(str) : 0.;
+}
+
+static CONV convert_type( enum enum_field_types t, int flags, unsigned int length ) {
+	// FIELD_TYPE_TIME
+	// FIELD_TYPE_YEAR
+	// FIELD_TYPE_NEWDATE
+	// FIELD_TYPE_NEWDATE + 2: // 5.0 MYSQL_TYPE_BIT
+	switch( t ) {
+	case FIELD_TYPE_TINY:
+		if( length == 1 )
+			return CONV_BOOL;
+	case FIELD_TYPE_SHORT:
+	case FIELD_TYPE_LONG:
+	case FIELD_TYPE_INT24:
+		return CONV_INT;
+	case FIELD_TYPE_LONGLONG:
+	case FIELD_TYPE_DECIMAL:
+	case FIELD_TYPE_FLOAT:
+	case FIELD_TYPE_DOUBLE:
+	case 246: // 5.0 MYSQL_NEW_DECIMAL
+		return CONV_FLOAT;
+	case 245: // JSON
+		return CONV_STRING;
+	case FIELD_TYPE_BLOB:
+	case FIELD_TYPE_TINY_BLOB:
+	case FIELD_TYPE_MEDIUM_BLOB:
+	case FIELD_TYPE_LONG_BLOB:
+		if( (flags & BINARY_FLAG) != 0 )
+			return CONV_BINARY;
+		return CONV_STRING;
+	case FIELD_TYPE_DATETIME:
+	case FIELD_TYPE_TIMESTAMP:
+		return CONV_DATETIME;
+	case FIELD_TYPE_DATE:
+		return CONV_DATE;
+	case FIELD_TYPE_NULL:
+	case FIELD_TYPE_ENUM:
+	case FIELD_TYPE_SET:
+	//case FIELD_TYPE_VAR_STRING:
+	//case FIELD_TYPE_GEOMETRY:
+	// 5.0 MYSQL_TYPE_VARCHAR
+	default:
+		if( (flags & BINARY_FLAG) != 0 )
+			return CONV_BINARY;
+		return CONV_STRING;
+	}
+}
+
+static result *alloc_result( connection *c, MYSQL_RES *r ) {
+	result *res = (result*)hl_gc_alloc_finalizer(sizeof(result));
+	int num_fields = mysql_num_fields(r);
+	int i;
+	MYSQL_FIELD *fields = mysql_fetch_fields(r);
+	res->free = free_result;
+	res->r = r;
+	res->current = NULL;
+	res->nfields = num_fields;
+	res->fields_ids = (int*)malloc(sizeof(int)*num_fields);
+	res->fields_convs = (CONV*)malloc(sizeof(CONV)*num_fields);	
+	for(i=0;i<num_fields;i++) {
+		int id;
+		if( strchr(fields[i].name,'(') )
+			id = hl_hash_gen(USTR("???"),true); // looks like an inner request : prevent hashing + cashing it
+		else
+			id = hl_hash_gen(hl_to_utf16(fields[i].name),true);
+		res->fields_ids[i] = id;
+		res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length);
+	}
+	return res;
+}
+
+// ---------------------------------------------------------------
+// Connection
+
+HL_PRIM void HL_NAME(close_wrap)( connection *c ) {	
+	if( c->c ) {
+		mp_close(c->c);
+		c->c = NULL;
+	}
+}
+
+HL_PRIM bool HL_NAME(select_db_wrap)( connection *c, const char *db ) {
+	return mysql_select_db(c->c,db) == 0;
+}
+
+HL_PRIM result *HL_NAME(request)( connection *c, const char *rq, int rqLen  ) {
+	if( mysql_real_query(c->c,rq,rqLen) != 0 )
+		error(c->c,rq);
+	MYSQL_RES *res = mysql_store_result(c->c);
+	if( res == NULL ) {
+		if( mysql_field_count(c->c) != 0 )
+			error(c->c,rq);
+		result *r = (result*)hl_gc_alloc_noptr(sizeof(result));
+		memset(r,0,sizeof(result));
+		r->nfields = (int)mysql_affected_rows(c->c);
+		return r;
+	}
+	return alloc_result(c,res);
+}
+
+
+HL_PRIM const char *HL_NAME(escape)( connection *c, const char *str, int len ) {
+	int wlen = len * 2;
+	vbyte *sout = hl_gc_alloc_noptr(wlen);
+	wlen = mysql_real_escape_string(c->c,sout,str,len);
+	if( wlen < 0 ) {
+		hl_buffer *b = hl_alloc_buffer();
+		hl_buffer_cstr(b,"Unsupported charset : ");
+		hl_buffer_cstr(b,mysql_character_set_name(c->c));
+		hl_throw_buffer(b);
+	}
+	sout[len] = 0;
+	return sout;
+}
+
+typedef struct {
+	hl_type *t;
+	const char *host;
+	const char *user;
+	const char *pass;
+	const char *socket;
+	int port;
+} cnx_params;
+
+HL_PRIM connection *HL_NAME(connect_wrap)( cnx_params *p ) {
+	connection *c = (connection*)hl_gc_alloc_finalizer(sizeof(connection));
+	memset(c,0,sizeof(connection));
+	c->free = HL_NAME(close_wrap);
+	c->c = mysql_init(NULL);
+	if( mysql_real_connect(c->c,p->host,p->user,p->pass,NULL,p->port,p->socket,0) == NULL ) {
+		hl_buffer *b = hl_alloc_buffer();
+		hl_buffer_cstr(b, "Failed to connect to mysql server : ");
+		hl_buffer_cstr(b,mysql_error(c->c));
+		mysql_close(c->c);
+		hl_throw_buffer(b);
+	}
+	return c;
+}
+
+HL_PRIM void HL_NAME(set_conv_funs)( vclosure *fstring, vclosure *fbytes, vclosure *fdate ) {
+	conv_string = fstring;
+	conv_bytes = fbytes;
+	conv_date = fdate;
+}
+
+// ---------------------------------------------------------------
+// Registers
+
+#define _CNX _ABSTRACT(mysql_cnx)
+#define _RESULT _ABSTRACT(mysql_result)
+
+DEFINE_PRIM(_CNX, connect_wrap, _OBJ(_BYTES _BYTES _BYTES _BYTES _I32) );
+DEFINE_PRIM(_VOID, close_wrap, _CNX);
+DEFINE_PRIM(_RESULT, request, _CNX _BYTES _I32);
+DEFINE_PRIM(_BOOL, select_db_wrap, _CNX _BYTES);
+DEFINE_PRIM(_BYTES, escape, _CNX _BYTES _I32);
+
+DEFINE_PRIM(_I32, result_get_length, _RESULT);
+DEFINE_PRIM(_I32, result_get_nfields, _RESULT);
+DEFINE_PRIM(_ARR, result_get_fields_names, _RESULT);
+DEFINE_PRIM(_DYN, result_next, _RESULT);
+DEFINE_PRIM(_BYTES, result_get, _RESULT _I32);
+DEFINE_PRIM(_I32, result_get_int, _RESULT _I32);
+DEFINE_PRIM(_F64, result_get_float, _RESULT _I32);
+
+DEFINE_PRIM(_VOID, set_conv_funs, _DYN _DYN _DYN);
+
+/* ************************************************************************ */

+ 131 - 0
libs/mysql/mysql.h

@@ -0,0 +1,131 @@
+/*
+ * MYSQL 5.0 Protocol Implementation
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#ifndef MYSQL_H
+#define MYSQL_H
+
+struct _MYSQL;
+struct _MYSQL_RES;
+typedef struct _MYSQL MYSQL; 
+typedef struct _MYSQL_RES MYSQL_RES;
+typedef char **MYSQL_ROW;
+
+typedef enum enum_field_types {
+	FIELD_TYPE_DECIMAL = 0x00,
+	FIELD_TYPE_TINY = 0x01,
+	FIELD_TYPE_SHORT = 0x02,
+	FIELD_TYPE_LONG = 0x03,
+	FIELD_TYPE_FLOAT = 0x04,
+	FIELD_TYPE_DOUBLE = 0x05,
+	FIELD_TYPE_NULL = 0x06,
+	FIELD_TYPE_TIMESTAMP = 0x07,
+	FIELD_TYPE_LONGLONG = 0x08,
+	FIELD_TYPE_INT24 = 0x09,
+	FIELD_TYPE_DATE = 0x0A,
+	FIELD_TYPE_TIME = 0x0B,
+	FIELD_TYPE_DATETIME = 0x0C,
+	FIELD_TYPE_YEAR = 0x0D,
+	FIELD_TYPE_NEWDATE = 0x0E,
+	FIELD_TYPE_VARCHAR = 0x0F,
+	FIELD_TYPE_BIT = 0x10,
+	FIELD_TYPE_NEWDECIMAL = 0xF6,
+	FIELD_TYPE_ENUM = 0xF7,
+	FIELD_TYPE_SET = 0xF8,
+	FIELD_TYPE_TINY_BLOB = 0xF9,
+	FIELD_TYPE_MEDIUM_BLOB = 0xFA,
+	FIELD_TYPE_LONG_BLOB = 0xFB,
+	FIELD_TYPE_BLOB = 0xFC,
+	FIELD_TYPE_VAR_STRING = 0xFD,
+	FIELD_TYPE_STRING = 0xFE,
+	FIELD_TYPE_GEOMETRY = 0xFF
+} FIELD_TYPE;
+
+typedef enum {
+	NOT_NULL_FLAG =	1,
+	PRI_KEY_FLAG = 2,
+	UNIQUE_KEY_FLAG = 4,
+	MULTIPLE_KEY_FLAG = 8,
+	BLOB_FLAG = 16,
+	UNSIGNED_FLAG = 32,
+	ZEROFILL_FLAG = 64,
+	BINARY_FLAG	= 128,
+	ENUM_FLAG = 256,
+	AUTO_INCREMENT_FLAG = 512,
+	TIMESTAMP_FLAG = 1024,
+	SET_FLAG = 2048,
+	NUM_FLAG = 32768,
+} __FIELD_FLAG;
+
+typedef struct {
+	char *catalog;
+	char *db;
+	char *table;
+	char *org_table;
+	char *name;
+	char *org_name;
+	int charset;
+	int length;
+	int flags;
+	int decimals;
+	FIELD_TYPE type;
+} MYSQL_FIELD;
+
+#define	mysql_init			mp_init
+#define mysql_real_connect	mp_real_connect
+#define mysql_select_db		mp_select_db
+#define mysql_real_query	mp_real_query
+#define mysql_store_result	mp_store_result
+#define mysql_field_count	mp_field_count
+#define mysql_affected_rows	mp_affected_rows
+#define mysql_escape_string	mp_escape_string
+#define mysql_real_escape_string mp_real_escape_string
+#define mysql_close			mp_close
+#define mysql_error			mp_error
+#define mysql_num_rows		mp_num_rows
+#define mysql_num_fields	mp_num_fields
+#define mysql_fetch_fields	mp_fetch_fields
+#define mysql_fetch_lengths	mp_fetch_lengths
+#define mysql_fetch_row		mp_fetch_row
+#define mysql_free_result	mp_free_result
+
+MYSQL *mysql_init( void * );
+MYSQL *mysql_real_connect( MYSQL *m, const char *host, const char *user, const char *pass, void *unused, int port, const char *socket, int options );
+int mysql_select_db( MYSQL *m, const char *dbname );
+int mysql_real_query( MYSQL *m, const char *query, int qlength );
+MYSQL_RES *mysql_store_result( MYSQL *m );
+int mysql_field_count( MYSQL *m );
+int mysql_affected_rows( MYSQL *m );
+int mysql_escape_string( MYSQL *m, char *sout, const char *sin, int length );
+int mysql_real_escape_string( MYSQL *m, char *sout, const char *sin, int length );
+void mysql_close( MYSQL *m );
+const char *mysql_error( MYSQL *m );
+const char *mysql_character_set_name( MYSQL *m );
+
+unsigned int mysql_num_rows( MYSQL_RES *r );
+int mysql_num_fields( MYSQL_RES *r );
+MYSQL_FIELD *mysql_fetch_fields( MYSQL_RES *r );
+unsigned long *mysql_fetch_lengths( MYSQL_RES *r );
+MYSQL_ROW mysql_fetch_row( MYSQL_RES * r );
+void mysql_free_result( MYSQL_RES *r );
+
+#endif
+/* ************************************************************************ */

+ 258 - 0
libs/mysql/mysql.vcxproj

@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="ReleaseVS2013|Win32">
+      <Configuration>ReleaseVS2013</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="ReleaseVS2013|x64">
+      <Configuration>ReleaseVS2013</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="mysql.c" />
+    <ClCompile Include="my_api.c" />
+    <ClCompile Include="my_proto.c" />
+    <ClCompile Include="sha1.c" />
+    <ClCompile Include="socket.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="mysql.h" />
+    <ClInclude Include="my_proto.h" />
+    <ClInclude Include="sha1.h" />
+    <ClInclude Include="socket.h" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{540E0E11-B7B1-43F8-B107-0867B2D97F74}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>mysql</RootNamespace>
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetExt>.hdll</TargetExt>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../src</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;../../$(Configuration)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetExt>.hdll</TargetExt>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../src</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;../../x64/$(Configuration)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetExt>.hdll</TargetExt>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../src</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;../../$(Configuration)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetExt>.hdll</TargetExt>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../src</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;../../$(Configuration)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetExt>.hdll</TargetExt>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../src</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;../../x64/$(Configuration)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetExt>.hdll</TargetExt>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);../../src</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;../../x64/$(Configuration)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <OutputFile>../../$(Configuration)/$(TargetName).hdll</OutputFile>
+      <AdditionalDependencies>libhl.lib;ws2_32.lib;advapi32.lib;psapi.lib;user32.lib;iphlpapi.lib;userenv.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <AdditionalDependencies>libhl.lib;ws2_32.lib;advapi32.lib;psapi.lib;user32.lib;iphlpapi.lib;userenv.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <OutputFile>../../$(Configuration)/$(TargetName).hdll</OutputFile>
+      <AdditionalDependencies>libhl.lib;ws2_32.lib;advapi32.lib;psapi.lib;user32.lib;iphlpapi.lib;userenv.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+      <OutputFile>../../$(Configuration)/$(TargetName).hdll</OutputFile>
+      <AdditionalDependencies>libhl.lib;ws2_32.lib;advapi32.lib;psapi.lib;user32.lib;iphlpapi.lib;userenv.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>libhl.lib;ws2_32.lib;advapi32.lib;psapi.lib;user32.lib;iphlpapi.lib;userenv.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseVS2013|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MYSQL_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>libhl.lib;ws2_32.lib;advapi32.lib;psapi.lib;user32.lib;iphlpapi.lib;userenv.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 70 - 0
libs/mysql/osdef.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#ifndef OS_H
+#define OS_H
+
+#if defined(_WIN32)
+#	define OS_WINDOWS
+#endif
+
+#if defined(__APPLE__) || defined(macintosh)
+#	define OS_MAC
+#endif
+
+#if defined(linux) || defined(__linux__)
+#	define OS_LINUX
+#endif
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#	define OS_BSD
+#endif
+
+#if defined(__GNU__)
+#	define OS_HURD
+#endif
+
+#if defined(__CYGWIN__)
+#	define OS_CYGWIN
+#endif
+
+#if defined(OS_LINUX) || defined(OS_MAC) || defined(OS_BSD) || defined(OS_GNUKBSD) || defined (OS_HURD) || defined (OS_CYGWIN)
+#	define OS_POSIX
+#endif
+
+#if defined(OS_MAC) || defined(OS_BSD)
+#	include <machine/endian.h>
+#elif !defined(OS_WINDOWS)
+#	include <endian.h>
+#endif
+
+#ifndef TARGET_BIG_ENDIAN
+#	define TARGET_LITTLE_ENDIAN
+#endif
+
+#ifndef true
+#	define true 1
+#	define false 0
+	typedef int bool;
+#endif
+
+#endif
+/* ************************************************************************ */

+ 128 - 0
libs/mysql/sha1.c

@@ -0,0 +1,128 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#include "osdef.h"
+#include "sha1.h"
+#include <stdio.h>
+#include <string.h>
+
+// original code by Steve Reid
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+#ifdef TARGET_BIG_ENDIAN
+#	define blk0(i) block[i]
+#else
+#	define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \
+		|(rol(block[i],8)&0x00FF00FF))
+#endif
+#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
+    ^block[(i+2)&15]^block[i&15],1))
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+static void sha1_transform( unsigned int state[5], unsigned char buffer[64] ) {
+	unsigned int a, b, c, d, e;
+	unsigned int block[16];
+	memcpy(block, buffer, 64);
+	/* Copy context->state[] to working vars */
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+	e = state[4];
+	/* 4 rounds of 20 operations each. Loop unrolled. */
+	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+	/* Add the working vars back into context.state[] */
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+	state[4] += e;
+}
+
+void sha1_init( SHA1_CTX *context ) {
+	/* SHA1 initialization constants */
+	context->state[0] = 0x67452301;
+	context->state[1] = 0xEFCDAB89;
+	context->state[2] = 0x98BADCFE;
+	context->state[3] = 0x10325476;
+	context->state[4] = 0xC3D2E1F0;
+	context->count[0] = context->count[1] = 0;
+}
+
+void sha1_update( SHA1_CTX *context, const unsigned char *data, unsigned int len ) {
+	unsigned int i, j;
+	j = (context->count[0] >> 3) & 63;
+	if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+	context->count[1] += (len >> 29);
+	if ((j + len) > 63) {
+		memcpy(&context->buffer[j], data, (i = 64-j));
+		sha1_transform(context->state, context->buffer);
+		for ( ; i + 63 < len; i += 64 )
+			sha1_transform(context->state, (unsigned char *)&data[i]);
+		j = 0;
+	} else
+		i = 0;
+	memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+void sha1_final( SHA1_CTX *context, unsigned char digest[SHA1_SIZE] ) {
+	unsigned int i;
+	unsigned char finalcount[8];
+	for (i = 0; i < 8; i++) {
+		finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+			>> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+	}
+	sha1_update(context, (unsigned char *)"\200", 1);
+	while ((context->count[0] & 504) != 448) {
+		sha1_update(context, (unsigned char *)"\0", 1);
+	}
+	sha1_update(context, finalcount, 8);
+	for (i = 0; i < SHA1_SIZE; i++) {
+		digest[i] = (unsigned char)
+			((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+	}
+	sha1_transform(context->state, context->buffer);
+}
+

+ 40 - 0
libs/mysql/sha1.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#ifndef SHA1_H
+#define SHA1_H
+
+#define SHA1_SIZE 20
+
+typedef unsigned char SHA1_DIGEST[SHA1_SIZE];
+
+typedef struct {
+	unsigned int state[5];
+	unsigned int count[2];
+	unsigned char buffer[64];
+} SHA1_CTX;
+
+void sha1_init( SHA1_CTX *c );
+void sha1_update( SHA1_CTX *c, const unsigned char *data, unsigned int len );
+void sha1_final( SHA1_CTX *c, SHA1_DIGEST digest );
+
+#endif
+/* ************************************************************************ */

+ 212 - 0
libs/mysql/socket.c

@@ -0,0 +1,212 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#include "socket.h"
+#include <string.h>
+
+#ifdef OS_WINDOWS
+	static int init_done = 0;
+	static WSADATA init_data;
+#	define POSIX_LABEL(x)
+#	define HANDLE_EINTR(x)
+
+#else
+#	include <sys/types.h>
+#	include <sys/socket.h>
+#	include <sys/time.h>
+#	include <netinet/in.h>
+#	include <netinet/tcp.h>
+#	include <arpa/inet.h>
+#	include <unistd.h>
+#	include <netdb.h>
+#	include <fcntl.h>
+#	include <errno.h>
+#	include <stdio.h>
+#	include <poll.h>
+#	define closesocket close
+#	define SOCKET_ERROR (-1)
+#	define POSIX_LABEL(x)	x:
+#	define HANDLE_EINTR(x)	if( errno == EINTR ) goto x
+#endif
+
+#if defined(OS_WINDOWS) || defined(OS_MAC)
+#	define MSG_NOSIGNAL 0
+#endif
+
+static int block_error() {
+#ifdef OS_WINDOWS
+	int err = WSAGetLastError();
+	if( err == WSAEWOULDBLOCK || err == WSAEALREADY )
+#else
+	if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
+#endif
+		return PS_BLOCK;
+	return PS_ERROR;
+}
+
+void psock_init() {
+#ifdef OS_WINDOWS
+	if( !init_done ) {
+		WSAStartup(MAKEWORD(2,0),&init_data);
+		init_done = 1;
+	}
+#endif
+}
+
+PSOCK psock_create() {
+	PSOCK s = socket(AF_INET,SOCK_STREAM,0);
+#	if defined(OS_MAC) || defined(OS_BSD)
+	if( s != INVALID_SOCKET )
+		setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0);
+#	endif
+#	ifdef OS_POSIX
+	// we don't want sockets to be inherited in case of exec
+	{
+		int old = fcntl(s,F_GETFD,0);
+		if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC);
+	}
+#	endif
+	return s;
+}
+
+void psock_close( PSOCK s ) {
+	POSIX_LABEL(close_again);
+	if( closesocket(s) ) {
+		HANDLE_EINTR(close_again);
+	}
+}
+
+int psock_send( PSOCK s, const char *buf, int size ) {
+	int ret;
+	POSIX_LABEL(send_again);
+	ret = send(s,buf,size,MSG_NOSIGNAL);
+	if( ret == SOCKET_ERROR ) {
+		HANDLE_EINTR(send_again);
+		return block_error();
+	}
+	return ret;
+}
+
+int psock_recv( PSOCK s, char *buf, int size ) {
+	int ret;
+	POSIX_LABEL(recv_again);
+	ret = recv(s,buf,size,MSG_NOSIGNAL);
+	if( ret == SOCKET_ERROR ) {
+		HANDLE_EINTR(recv_again);
+		return block_error();
+	}
+	return ret;
+}
+
+PHOST phost_resolve( const char *host ) {
+	PHOST ip = inet_addr(host);
+	if( ip == INADDR_NONE ) {
+		struct hostent *h;
+#	if defined(OS_WINDOWS) || defined(OS_MAC) || defined(OS_CYGWIN)
+		h = gethostbyname(host);
+#	else
+		struct hostent hbase;
+		char buf[1024];
+		int errcode;
+		gethostbyname_r(host,&hbase,buf,1024,&h,&errcode);
+#	endif
+		if( h == NULL )
+			return UNRESOLVED_HOST;
+		ip = *((unsigned int*)h->h_addr);
+	}
+	return ip;
+}
+
+SERR psock_connect( PSOCK s, PHOST host, int port ) {
+	struct sockaddr_in addr;
+	memset(&addr,0,sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	*(int*)&addr.sin_addr.s_addr = host;
+	if( connect(s,(struct sockaddr*)&addr,sizeof(addr)) != 0 )
+		return block_error();
+	return PS_OK;
+}
+
+SERR psock_set_timeout( PSOCK s, double t ) {
+#ifdef OS_WINDOWS
+	int time = (int)(t * 1000);
+#else
+	struct timeval time;
+	time.tv_usec = (int)((t - (int)t)*1000000);
+	time.tv_sec = (int)t;
+#endif
+	if( setsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&time,sizeof(time)) != 0 )
+		return PS_ERROR;
+	if( setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&time,sizeof(time)) != 0 )
+		return PS_ERROR;
+	return PS_OK;
+}
+
+
+SERR psock_set_blocking( PSOCK s, int block ) {
+#ifdef OS_WINDOWS
+	{
+		unsigned long arg = !block;
+		if( ioctlsocket(s,FIONBIO,&arg) != 0 )
+			return PS_ERROR;
+	}
+#else
+	{
+		int rights = fcntl(s,F_GETFL);
+		if( rights == -1 )
+			return PS_ERROR;
+		if( block )
+			rights &= ~O_NONBLOCK;
+		else
+			rights |= O_NONBLOCK;
+		if( fcntl(s,F_SETFL,rights) == -1 )
+			return PS_ERROR;
+	}
+#endif
+	return PS_OK;
+}
+
+SERR psock_set_fastsend( PSOCK s, int fast ) {
+	if( setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) )
+		return block_error();
+	return PS_OK;
+}
+
+void psock_wait( PSOCK s ) {
+#	ifdef OS_WINDOWS
+	fd_set set;
+	FD_ZERO(&set);
+	FD_SET(s,&set);
+	select((int)s+1,&set,NULL,NULL,NULL);
+#	else
+	struct pollfd fds;
+	POSIX_LABEL(poll_again);
+	fds.fd = s;
+	fds.events = POLLIN;
+	fds.revents = 0;
+	if( poll(&fds,1,-1) < 0 ) {
+		HANDLE_EINTR(poll_again);
+	}
+#	endif
+}
+
+/* ************************************************************************ */

+ 59 - 0
libs/mysql/socket.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * 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.
+ */
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include "osdef.h"
+
+#ifdef OS_WINDOWS
+#	include <winsock2.h>
+	typedef SOCKET PSOCK;
+#else
+	typedef int PSOCK;
+#	define INVALID_SOCKET (-1)
+#endif
+
+typedef unsigned int PHOST;
+
+#define UNRESOLVED_HOST ((PHOST)-1)
+
+typedef enum {
+	PS_OK = 0,
+	PS_ERROR = -1,
+	PS_BLOCK = -2,
+} SERR;
+
+void psock_init();
+PSOCK psock_create();
+void psock_close( PSOCK s );
+SERR psock_connect( PSOCK s, PHOST h, int port );
+SERR psock_set_timeout( PSOCK s, double timeout );
+SERR psock_set_blocking( PSOCK s, int block );
+SERR psock_set_fastsend( PSOCK s, int fast );
+
+int psock_send( PSOCK s, const char *buf, int size );
+int psock_recv( PSOCK s, char *buf, int size );
+
+PHOST phost_resolve( const char *hostname );
+
+#endif
+/* ************************************************************************ */