forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
24
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/Build.xml
Normal file
24
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/Build.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<xml>
|
||||
|
||||
<files id="hxcpp_mysql" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<depend name="${this_dir}/sha1.h" />
|
||||
<depend name="${this_dir}/socket.h" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<file name="Mysql.cpp"/>
|
||||
<file name="my_api.cpp"/>
|
||||
<file name="my_proto.cpp"/>
|
||||
<file name="socket.cpp"/>
|
||||
<file name="sha1.cpp"/>
|
||||
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_mysql"/>
|
||||
<lib name="ws2_32.lib" if="windows" unless="static_link" />
|
||||
</target>
|
||||
|
||||
|
||||
</xml>
|
555
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/Mysql.cpp
Normal file
555
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/Mysql.cpp
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 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 <hxcpp.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "mysql.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#define atof(x) strtod((x),0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>MySQL</h1>
|
||||
<p>
|
||||
API to connect and use MySQL database
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
|
||||
#define HXTHROW(x) hx::Throw(HX_CSTRING(x))
|
||||
|
||||
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Connection : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdMysql };
|
||||
|
||||
|
||||
MYSQL *m;
|
||||
|
||||
|
||||
void create(MYSQL *inM)
|
||||
{
|
||||
m = inM;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (m)
|
||||
{
|
||||
mysql_close(m);
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((Connection *)(obj.mPtr))->destroy();
|
||||
}
|
||||
};
|
||||
|
||||
Connection *getConnection(Dynamic o)
|
||||
{
|
||||
Connection *connection = dynamic_cast<Connection *>(o.mPtr);
|
||||
if (!connection || !connection->m)
|
||||
hx::Throw( HX_CSTRING("Invalid Connection") );
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
static void error( MYSQL *m, const char *msg )
|
||||
{
|
||||
hx::Throw( String(msg) + HX_CSTRING(" ") + String(mysql_error(m)) );
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Result
|
||||
|
||||
/**
|
||||
<doc><h2>Result</h2></doc>
|
||||
**/
|
||||
|
||||
#undef CONV_FLOAT
|
||||
typedef enum {
|
||||
CONV_INT,
|
||||
CONV_STRING,
|
||||
CONV_FLOAT,
|
||||
CONV_BINARY,
|
||||
CONV_DATE,
|
||||
CONV_DATETIME,
|
||||
CONV_BOOL
|
||||
} CONV;
|
||||
|
||||
struct Result : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdMysqlResult };
|
||||
|
||||
MYSQL_RES *r;
|
||||
int nfields;
|
||||
CONV *fields_convs;
|
||||
String *field_names;
|
||||
MYSQL_ROW current;
|
||||
|
||||
void create(MYSQL_RES *inR)
|
||||
{
|
||||
r = inR;
|
||||
fields_convs = 0;
|
||||
field_names = 0;
|
||||
nfields = 0;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (r)
|
||||
{
|
||||
if (fields_convs)
|
||||
free(fields_convs);
|
||||
if (field_names)
|
||||
free(field_names);
|
||||
fields_convs = 0;
|
||||
field_names = 0;
|
||||
mysql_free_result(r);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int numRows() { return mysql_num_rows(r); }
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((Result *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Result *getResult(Dynamic o)
|
||||
{
|
||||
Result *result = dynamic_cast<Result *>(o.mPtr);
|
||||
if (!result)
|
||||
HXTHROW("Invalid result");
|
||||
return result;
|
||||
}
|
||||
|
||||
cpp::Function< Dynamic(Dynamic) > gDataToBytes;
|
||||
cpp::Function< Dynamic(Float) > gDateFromSeconds;
|
||||
|
||||
}
|
||||
|
||||
void _hx_mysql_set_conversion(
|
||||
cpp::Function< Dynamic(Dynamic) > inDataToBytes,
|
||||
cpp::Function< Dynamic(Float) > inDateFromSeconds )
|
||||
{
|
||||
gDataToBytes = inDataToBytes;
|
||||
gDateFromSeconds = inDateFromSeconds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
result_get_length : 'result -> int
|
||||
<doc>Return the number of rows returned or affected</doc>
|
||||
**/
|
||||
int _hx_mysql_result_get_length(Dynamic handle)
|
||||
{
|
||||
if( handle->__GetType() == vtInt )
|
||||
return handle;
|
||||
|
||||
return getResult(handle)->numRows();
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_nfields : 'result -> int
|
||||
<doc>Return the number of fields in a result row</doc>
|
||||
**/
|
||||
int _hx_mysql_result_get_nfields(Dynamic handle)
|
||||
{
|
||||
if( handle->__GetType() == vtInt )
|
||||
return 0;
|
||||
|
||||
return getResult(handle)->nfields;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_fields_names : 'result -> string array
|
||||
<doc>Return the fields names corresponding results columns</doc>
|
||||
**/
|
||||
Array<String> _hx_mysql_result_get_fields_names(Dynamic handle)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
|
||||
MYSQL_FIELD *fields = mysql_fetch_fields(r->r);
|
||||
int count = r->nfields;
|
||||
Array<String> output = Array_obj<String>::__new(count);
|
||||
|
||||
for(int k=0;k<count;k++)
|
||||
output[k] = String(fields[k].name);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
result_next : 'result -> object?
|
||||
<doc>
|
||||
Return the next row if available. A row is represented
|
||||
as an object, which fields have been converted to the
|
||||
corresponding Neko value (int, float or string). For
|
||||
Date and DateTime you can specify your own conversion
|
||||
function using [result_set_conv_date]. By default they're
|
||||
returned as plain strings. Additionally, the TINYINT(1) will
|
||||
be converted to either true or false if equal to 0.
|
||||
</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_result_next(Dynamic handle)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
MYSQL_ROW row = mysql_fetch_row(r->r);
|
||||
if( !row )
|
||||
return null();
|
||||
|
||||
int count = r->nfields;
|
||||
hx::Anon cur = hx::Anon_obj::Create(0);
|
||||
|
||||
r->current = row;
|
||||
unsigned long *lengths = 0;
|
||||
for(int i=0;i<r->nfields;i++)
|
||||
{
|
||||
if( row[i] )
|
||||
{
|
||||
Dynamic v;
|
||||
switch( r->fields_convs[i] )
|
||||
{
|
||||
case CONV_INT:
|
||||
v = atoi(row[i]);
|
||||
break;
|
||||
case CONV_STRING:
|
||||
v = String(row[i]);
|
||||
break;
|
||||
case CONV_BOOL:
|
||||
v = *row[i] != '0';
|
||||
break;
|
||||
case CONV_FLOAT:
|
||||
v = atof(row[i]);
|
||||
break;
|
||||
case CONV_BINARY:
|
||||
{
|
||||
if( lengths == NULL )
|
||||
{
|
||||
lengths = mysql_fetch_lengths(r->r);
|
||||
if( lengths == NULL )
|
||||
HXTHROW("mysql_fetch_lengths");
|
||||
}
|
||||
Array<unsigned char> buf = Array_obj<unsigned char>::__new(lengths[i],lengths[i]);
|
||||
memcpy(&buf[0],row[i],lengths[i]);
|
||||
v = gDataToBytes.call(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case CONV_DATE:
|
||||
{
|
||||
struct tm t;
|
||||
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--;
|
||||
v = gDateFromSeconds.call((int)mktime(&t));
|
||||
}
|
||||
break;
|
||||
case CONV_DATETIME:
|
||||
{
|
||||
struct tm t;
|
||||
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--;
|
||||
v = gDateFromSeconds.call(mktime(&t));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cur->__SetField(r->field_names[i],v, hx::paccDynamic );
|
||||
}
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
result_get : 'result -> n:int -> string
|
||||
<doc>Return the [n]th field of the current row</doc>
|
||||
**/
|
||||
String _hx_mysql_result_get(Dynamic handle,int n)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
if( n < 0 || n >= r->nfields )
|
||||
HXTHROW("Invalid index");
|
||||
|
||||
if( !r->current )
|
||||
{
|
||||
_hx_mysql_result_next(handle);
|
||||
if( !r->current )
|
||||
HXTHROW("No more results");
|
||||
}
|
||||
|
||||
return String(r->current[n]);
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_int : 'result -> n:int -> int
|
||||
<doc>Return the [n]th field of the current row as an integer (or 0)</doc>
|
||||
**/
|
||||
int _hx_mysql_result_get_int(Dynamic handle,int n)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
if( n < 0 || n >= r->nfields )
|
||||
HXTHROW("Invalid index");
|
||||
|
||||
if( !r->current )
|
||||
{
|
||||
_hx_mysql_result_next(handle);
|
||||
if( !r->current )
|
||||
HXTHROW("No more results");
|
||||
}
|
||||
|
||||
const char *s = r->current[n];
|
||||
return s?atoi(s):0;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_float : 'result -> n:int -> float
|
||||
<doc>Return the [n]th field of the current row as a float (or 0)</doc>
|
||||
**/
|
||||
Float _hx_mysql_result_get_float(Dynamic handle,int n)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
if( n < 0 || n >= r->nfields )
|
||||
HXTHROW("Invalid index");
|
||||
|
||||
if( !r->current )
|
||||
{
|
||||
_hx_mysql_result_next(handle);
|
||||
if( !r->current )
|
||||
HXTHROW("No more results");
|
||||
}
|
||||
|
||||
const char *s = r->current[n];
|
||||
return s?atof(s):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 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 = new Result();
|
||||
res->create(r);
|
||||
|
||||
int num_fields = mysql_num_fields(r);
|
||||
int i,j;
|
||||
MYSQL_FIELD *fields = mysql_fetch_fields(r);
|
||||
res->current = 0;
|
||||
res->nfields = num_fields;
|
||||
res->field_names = (String *)malloc(sizeof(String)*num_fields);
|
||||
res->fields_convs = (CONV*)malloc(sizeof(CONV)*num_fields);
|
||||
|
||||
for(i=0;i<num_fields;i++)
|
||||
{
|
||||
String name;
|
||||
if( strchr(fields[i].name,'(') )
|
||||
name = String::createPermanent("???",3); // looks like an inner request : prevent hashing + cashing it
|
||||
else
|
||||
name = String::createPermanent(fields[i].name, -1);
|
||||
|
||||
res->field_names[i] = name;
|
||||
res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Connection
|
||||
|
||||
/** <doc><h2>Connection</h2></doc> **/
|
||||
|
||||
/**
|
||||
close : 'connection -> void
|
||||
<doc>Close the connection. Any subsequent operation will fail on it</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_close(Dynamic handle)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
connection->destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
select_db : 'connection -> string -> void
|
||||
<doc>Select the database</doc>
|
||||
**/
|
||||
void _hx_mysql_select_db(Dynamic handle,String db)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
|
||||
if( mysql_select_db(connection->m,db.utf8_str()) != 0 )
|
||||
error(connection->m,"Failed to select database :");
|
||||
}
|
||||
|
||||
/**
|
||||
request : 'connection -> string -> 'result
|
||||
<doc>Execute an SQL request. Exception on error</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_request(Dynamic handle,String req)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
|
||||
if( mysql_real_query(connection->m,req.utf8_str(),req.length) != 0 )
|
||||
error(connection->m,req);
|
||||
|
||||
MYSQL_RES *res = mysql_store_result(connection->m);
|
||||
if( !res )
|
||||
{
|
||||
if( mysql_field_count(connection->m) == 0 )
|
||||
return mysql_affected_rows(connection->m);
|
||||
else
|
||||
error(connection->m,req);
|
||||
}
|
||||
|
||||
return alloc_result(connection,res);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
escape : 'connection -> string -> string
|
||||
<doc>Escape the string for inserting into a SQL request</doc>
|
||||
**/
|
||||
struct AutoBuf
|
||||
{
|
||||
AutoBuf(int inLen) { buffer = new char[inLen]; }
|
||||
~AutoBuf() { delete [] buffer; }
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
|
||||
String _hx_mysql_escape(Dynamic handle,String str)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
int len = str.length * 2 + 1;
|
||||
AutoBuf sout(len);
|
||||
|
||||
int finalLen = mysql_real_escape_string(connection->m,sout.buffer,str.utf8_str(),str.length);
|
||||
if( finalLen < 0 )
|
||||
hx::Throw( HX_CSTRING("Unsupported charset : ") + String(mysql_character_set_name(connection->m)) );
|
||||
|
||||
return String::create(sout.buffer,finalLen);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Sql
|
||||
|
||||
|
||||
/**
|
||||
connect : { host => string, port => int, user => string, pass => string, socket => string? } -> 'connection
|
||||
<doc>Connect to a database using the connection informations</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_connect(Dynamic params)
|
||||
{
|
||||
String host = params->__Field(HX_CSTRING("host"), hx::paccDynamic );
|
||||
int port = params->__Field(HX_CSTRING("port"), hx::paccDynamic);
|
||||
String user = params->__Field(HX_CSTRING("user"), hx::paccDynamic);
|
||||
String pass = params->__Field(HX_CSTRING("pass"), hx::paccDynamic);
|
||||
String socket = params->__Field(HX_CSTRING("socket"), hx::paccDynamic );
|
||||
|
||||
MYSQL *cnx = mysql_init(NULL);
|
||||
if( mysql_real_connect(cnx,host.utf8_str(),user.utf8_str(),pass.utf8_str(),NULL,port,socket.utf8_str(),0) == NULL )
|
||||
{
|
||||
String error = HX_CSTRING("Failed to connect to mysql server : ") + String(mysql_error(cnx));
|
||||
mysql_close(cnx);
|
||||
hx::Throw(error);
|
||||
}
|
||||
|
||||
Connection *connection = new Connection();
|
||||
connection->create(cnx);
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
511
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/my_api.cpp
Normal file
511
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/my_api.cpp
Normal file
@ -0,0 +1,511 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include "my_proto.h"
|
||||
|
||||
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);
|
||||
// send dbname without trailing 0x00
|
||||
myp_write(p,dbname,strlen(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 = (FIELD_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 ) {
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
int pcount = 0;
|
||||
myp_begin_packet(p,0);
|
||||
myp_write_byte(p,COM_QUIT);
|
||||
myp_send_packet(m,p,&pcount);
|
||||
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);
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
414
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/my_proto.cpp
Normal file
414
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/my_proto.cpp
Normal file
@ -0,0 +1,414 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
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 <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
#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 ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
return myp_recv_no_gc(m,buf,size);
|
||||
}
|
||||
|
||||
int myp_recv_no_gc( MYSQL *m, void *buf, int size ) {
|
||||
while( size ) {
|
||||
int len = psock_recv_no_gc(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 ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
return myp_send_no_gc(m,buf,size);
|
||||
}
|
||||
|
||||
int myp_send_no_gc( MYSQL *m, void *buf, int size ) {
|
||||
while( size ) {
|
||||
int len = psock_send_no_gc(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 ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
unsigned int psize;
|
||||
p->pos = 0;
|
||||
p->error = 0;
|
||||
if( !myp_recv_no_gc(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_no_gc(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 ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
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_no_gc(m,&header,4) || !myp_send_no_gc(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_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,(const unsigned char *)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, (const unsigned char *)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 ) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
174
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/my_proto.h
Normal file
174
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/my_proto.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
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_no_gc( MYSQL *m, void *buf, int size );
|
||||
int myp_send_no_gc( MYSQL *m, void *buf, int size );
|
||||
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_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
|
||||
/* ************************************************************************ */
|
120
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/mysql.h
Normal file
120
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/mysql.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
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
|
||||
/* ************************************************************************ */
|
128
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/sha1.cpp
Normal file
128
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/sha1.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 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 <hxcpp.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 HXCPP_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
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/sha1.h
Normal file
40
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/sha1.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 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
|
||||
/* ************************************************************************ */
|
224
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/socket.cpp
Normal file
224
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/socket.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 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 <hxcpp.h>
|
||||
#include "socket.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
static int init_done = 0;
|
||||
static WSADATA init_data;
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#if (defined(NEKO_WINDOWS) || defined(NEKO_MAC)) && !defined(MSG_NOSIGNAL)
|
||||
# define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
static SERR block_error() {
|
||||
#ifdef NEKO_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 NEKO_WINDOWS
|
||||
if( !init_done ) {
|
||||
WSAStartup(MAKEWORD(2,0),&init_data);
|
||||
init_done = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PSOCK psock_create() {
|
||||
hx::AutoGCFreeZone block;
|
||||
PSOCK s = socket(AF_INET,SOCK_STREAM,0);
|
||||
# if defined(NEKO_MAC) || defined(NEKO_BSD)
|
||||
if( s != INVALID_SOCKET )
|
||||
setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0);
|
||||
# endif
|
||||
# ifdef NEKO_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 ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
POSIX_LABEL(close_again);
|
||||
if( closesocket(s) ) {
|
||||
HANDLE_EINTR(close_again);
|
||||
}
|
||||
}
|
||||
|
||||
int psock_send( PSOCK s, const char *buf, int size ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
return psock_send_no_gc(s,buf,size);
|
||||
}
|
||||
|
||||
int psock_send_no_gc( 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 ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
return psock_recv_no_gc(s,buf,size);
|
||||
}
|
||||
|
||||
int psock_recv_no_gc( 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 ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
PHOST ip = inet_addr(host);
|
||||
if( ip == INADDR_NONE ) {
|
||||
struct hostent *h;
|
||||
# if defined(NEKO_WINDOWS) || defined(NEKO_MAC) || defined(BLACKBERRY)
|
||||
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 ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
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 NEKO_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 NEKO_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 ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
# ifdef NEKO_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
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
62
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/socket.h
Normal file
62
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/mysql/socket.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 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 <hx/OS.h>
|
||||
|
||||
#ifdef NEKO_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 );
|
||||
|
||||
int psock_send_no_gc( PSOCK s, const char *buf, int size );
|
||||
int psock_recv_no_gc( PSOCK s, char *buf, int size );
|
||||
|
||||
PHOST phost_resolve( const char *hostname );
|
||||
|
||||
#endif
|
||||
/* ************************************************************************ */
|
45
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/regexp/Build.xml
Normal file
45
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/regexp/Build.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="PCRE_DIR" value="${HXCPP}/project/thirdparty/pcre2-10.42/src" />
|
||||
|
||||
<files id="pcre2-8" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-DPCRE2_CODE_UNIT_WIDTH=8" />
|
||||
<compilerflag value="-DSUPPORT_PCRE2_8" />
|
||||
|
||||
<include name="${this_dir}/pcre2_sources.xml" />
|
||||
</files>
|
||||
|
||||
<files id="pcre2-16" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-DPCRE2_CODE_UNIT_WIDTH=16" />
|
||||
<compilerflag value="-DSUPPORT_PCRE2_16" />
|
||||
|
||||
<include name="${this_dir}/pcre2_sources.xml" />
|
||||
</files>
|
||||
|
||||
<files id="hxcpp_regexp">
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-I${PCRE_DIR}"/>
|
||||
|
||||
<file name="${this_dir}/RegExp.cpp"/>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_regexp" />
|
||||
<files id="pcre2-8" />
|
||||
<files id="pcre2-16" if="hxcpp_smart_strings" />
|
||||
</target>
|
||||
|
||||
</xml>
|
294
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/regexp/RegExp.cpp
Normal file
294
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/regexp/RegExp.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
#include <hxcpp.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define PCRE2_STATIC
|
||||
#define PCRE2_CODE_UNIT_WIDTH 0
|
||||
|
||||
//#include <pcre2.h>
|
||||
#include "../../../../project/thirdparty/pcre2-10.42-8/src/pcre2.h"
|
||||
|
||||
#define PCRE(o) ((pcredata*)o.mPtr)
|
||||
|
||||
static void regexp_compilation_error(String pattern, int error_code, size_t error_offset) {
|
||||
PCRE2_UCHAR8 error_buffer[128];
|
||||
pcre2_get_error_message_8(error_code, error_buffer, sizeof(error_buffer));
|
||||
hx::Throw(HX_CSTRING("Regexp compilation error : ") + String((const char*)error_buffer) + HX_CSTRING(" in ") + pattern);
|
||||
}
|
||||
|
||||
struct pcredata : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdPcreData };
|
||||
|
||||
pcre2_code_8 *rUtf8;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
pcre2_code_16 *rUtf16;
|
||||
#endif
|
||||
|
||||
int n_groups;
|
||||
pcre2_match_data_8* match_data8;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
pcre2_match_data_16* match_data16;
|
||||
#endif
|
||||
|
||||
unsigned int flags;
|
||||
String string;
|
||||
String expr;
|
||||
|
||||
void create8(pcre2_code_8 *inR, String inExpr, int inFlags)
|
||||
{
|
||||
rUtf8 = inR;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
rUtf16 = 0;
|
||||
#endif
|
||||
expr = inExpr;
|
||||
HX_OBJ_WB_GET(this, expr.raw_ref());
|
||||
flags = inFlags;
|
||||
|
||||
n_groups = 0;
|
||||
pcre2_pattern_info_8(rUtf8,PCRE2_INFO_CAPTURECOUNT,&n_groups);
|
||||
n_groups++;
|
||||
match_data8 = pcre2_match_data_create_from_pattern_8(rUtf8, NULL);
|
||||
#ifdef HX_SMART_STRINGS
|
||||
match_data16 = 0;
|
||||
#endif
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
void create16(pcre2_code_16 *inR, String inExpr, int inFlags)
|
||||
{
|
||||
rUtf8 = 0;
|
||||
rUtf16 = inR;
|
||||
expr = inExpr;
|
||||
HX_OBJ_WB_GET(this, expr.raw_ref());
|
||||
flags = inFlags;
|
||||
|
||||
n_groups = 0;
|
||||
pcre2_pattern_info_16(rUtf16,PCRE2_INFO_CAPTURECOUNT,&n_groups);
|
||||
n_groups++;
|
||||
match_data8 = 0;
|
||||
match_data16 = pcre2_match_data_create_from_pattern_16(rUtf16, NULL);
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool run(String string,int pos,int len)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (string.isUTF16Encoded())
|
||||
{
|
||||
if (!rUtf16)
|
||||
{
|
||||
int error_code;
|
||||
size_t error_offset;
|
||||
hx::strbuf buf;
|
||||
int utf16Length = 0;
|
||||
PCRE2_SPTR16 utf16 = (PCRE2_SPTR16)expr.wc_str(&buf, &utf16Length);
|
||||
rUtf16 = pcre2_compile_16((PCRE2_SPTR16)expr.wc_str(&buf),utf16Length,flags,&error_code,&error_offset,NULL);
|
||||
if (!rUtf16) {
|
||||
regexp_compilation_error(expr,error_code,error_offset);
|
||||
}
|
||||
match_data16 = pcre2_match_data_create_from_pattern_16(rUtf16, NULL);
|
||||
}
|
||||
|
||||
int n = pcre2_match_16(rUtf16,(PCRE2_SPTR16)string.raw_wptr(),pos+len,pos,PCRE2_NO_UTF_CHECK,match_data16,NULL);
|
||||
return n>=0;
|
||||
}
|
||||
|
||||
if (!rUtf8)
|
||||
{
|
||||
int error_code;
|
||||
size_t error_offset;
|
||||
int utf8Length = 0;
|
||||
PCRE2_SPTR8 utf8 = (PCRE2_SPTR8)expr.utf8_str(NULL, true, &utf8Length);
|
||||
rUtf8 = pcre2_compile_8(utf8, utf8Length, flags, &error_code, &error_offset, NULL);
|
||||
if (!rUtf8) {
|
||||
regexp_compilation_error(expr,error_code,error_offset);
|
||||
}
|
||||
match_data8 = pcre2_match_data_create_from_pattern_8(rUtf8, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
return pcre2_match_8(rUtf8,(PCRE2_SPTR8)string.utf8_str(),pos+len,pos,PCRE2_NO_UTF_CHECK,match_data8,NULL) >= 0;
|
||||
}
|
||||
|
||||
size_t* get_matches() {
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (string.isUTF16Encoded()) {
|
||||
return pcre2_get_ovector_pointer_16(match_data16);
|
||||
}
|
||||
#endif
|
||||
return pcre2_get_ovector_pointer_8(match_data8);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
pcre2_code_free_8( rUtf8 );
|
||||
pcre2_match_data_free_8( match_data8 );
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
pcre2_code_free_16( rUtf16 );
|
||||
pcre2_match_data_free_16( match_data16 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(string); HX_MARK_MEMBER(expr); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(string); HX_VISIT_MEMBER(expr); }
|
||||
#endif
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((pcredata *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return expr; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
regexp_new_options : reg:string -> options:string -> 'regexp
|
||||
<doc>Build a new regexpr with the following options :
|
||||
<ul>
|
||||
<li>i : case insensitive matching</li>
|
||||
<li>s : . match anything including newlines</li>
|
||||
<li>m : treat the input as a multiline string</li>
|
||||
<li>u : run in utf8 mode</li>
|
||||
<li>g : turn off greedy behavior</li>
|
||||
</ul>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
Dynamic _hx_regexp_new_options(String s, String opt)
|
||||
{
|
||||
hx::strbuf buf;
|
||||
const char *o = opt.utf8_str(&buf);
|
||||
int options = PCRE2_UCP | PCRE2_UTF;
|
||||
while( *o )
|
||||
{
|
||||
switch( *o++ )
|
||||
{
|
||||
case 'i':
|
||||
options |= PCRE2_CASELESS;
|
||||
break;
|
||||
case 's':
|
||||
options |= PCRE2_DOTALL;
|
||||
break;
|
||||
case 'm':
|
||||
options |= PCRE2_MULTILINE;
|
||||
break;
|
||||
case 'g':
|
||||
options |= PCRE2_UNGREEDY;
|
||||
break;
|
||||
case 'u':
|
||||
break;
|
||||
default:
|
||||
hx::Throw( HX_CSTRING("Regexp unknown modifier : ") + String::fromCharCode(o[-1]) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (s.isUTF16Encoded())
|
||||
{
|
||||
int error_code;
|
||||
size_t error_offset;
|
||||
pcre2_code_16 *p = pcre2_compile_16((PCRE2_SPTR16)s.raw_wptr(),s.length,options,&error_code,&error_offset,NULL);
|
||||
if( !p ) {
|
||||
regexp_compilation_error(s,error_code,error_offset);
|
||||
}
|
||||
|
||||
pcredata *pdata = new pcredata;
|
||||
pdata->create16(p,s,options);
|
||||
return pdata;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int error_code = 0;
|
||||
size_t error_offset;
|
||||
pcre2_code_8 *p = pcre2_compile_8((PCRE2_SPTR8)s.utf8_str(),s.length,options,&error_code,&error_offset,NULL);
|
||||
if( !p ) {
|
||||
regexp_compilation_error(s,error_code,error_offset);
|
||||
}
|
||||
|
||||
pcredata *pdata = new pcredata;
|
||||
pdata->create8(p,s,options);
|
||||
return pdata;
|
||||
}
|
||||
}
|
||||
|
||||
bool _hx_regexp_match(Dynamic handle, String string, int pos, int len)
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos > string.length || pos + len > string.length )
|
||||
return false;
|
||||
|
||||
pcredata *d = PCRE(handle);
|
||||
|
||||
if( d->run(string,pos,len) )
|
||||
{
|
||||
d->string = string;
|
||||
HX_OBJ_WB_GET(d, d->string.raw_ref());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->string = String();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String _hx_regexp_matched(Dynamic handle, int m)
|
||||
{
|
||||
pcredata *d = PCRE(handle);
|
||||
|
||||
if( m < 0 || m >= d->n_groups || !d->string.raw_ptr() )
|
||||
return null();
|
||||
//hx::Throw( HX_CSTRING("regexp_matched - no valid match"));
|
||||
|
||||
size_t* matches = d->get_matches();
|
||||
int start = matches[m*2];
|
||||
int len = matches[m*2+1] - start;
|
||||
if( start == -1 )
|
||||
return String();
|
||||
return d->string.substr(start, len);
|
||||
}
|
||||
|
||||
/**
|
||||
regexp_matched_pos : 'regexp -> n:int -> { pos => int, len => int }
|
||||
<doc>Return the [n]th matched block position by the regexp. If [n] is 0 then
|
||||
return the whole matched substring position</doc>
|
||||
**/
|
||||
Dynamic _hx_regexp_matched_pos(Dynamic handle, int m)
|
||||
{
|
||||
pcredata *d = PCRE(handle);
|
||||
if (m < 0 || m >= d->n_groups || !d->string.raw_ptr())
|
||||
return null();
|
||||
|
||||
size_t* matches = d->get_matches();
|
||||
int start = matches[m*2];
|
||||
int len = matches[m*2+1] - start;
|
||||
|
||||
return hx::Anon_obj::Create(2)
|
||||
->setFixed(0,HX_("len",d5,4b,52,00),len)
|
||||
->setFixed(1,HX_("pos",94,5d,55,00),start);
|
||||
}
|
||||
|
||||
/**
|
||||
regexp_matched_num : 'regexp -> int
|
||||
<doc>Return the total number of matched groups, or -1 if the regexp has not
|
||||
been matched yet</doc>
|
||||
**/
|
||||
int _hx_regexp_matched_num(Dynamic handle)
|
||||
{
|
||||
pcredata *d = PCRE(handle);
|
||||
|
||||
if( !d->string.raw_ptr() )
|
||||
return -1;
|
||||
else
|
||||
return d->n_groups;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
<xml>
|
||||
<compilerflag value="-DHAVE_CONFIG_H" />
|
||||
<compilerflag value="-DPCRE2_STATIC" />
|
||||
<compilerflag value="-DSUPPORT_UNICODE" />
|
||||
<compilerflag value="-I${PCRE_DIR}" />
|
||||
<compilerflag value="-std=c99" unless="MSVC_VER" />
|
||||
|
||||
<file name="${PCRE_DIR}/pcre2_auto_possess.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_chartables.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_compile.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_config.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_context.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_convert.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_dfa_match.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_error.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_extuni.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_find_bracket.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_jit_compile.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_maketables.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_match.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_match_data.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_newline.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_ord2utf.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_pattern_info.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_script_run.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_serialize.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_string_utils.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_study.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_substitute.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_substring.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_tables.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_ucd.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_valid_utf.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_xclass.c" />
|
||||
</xml>
|
25
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/sqlite/Build.xml
Normal file
25
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/sqlite/Build.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="SQLITE_DIR" value="${HXCPP}/project/thirdparty/sqlite-3.40.1"/>
|
||||
|
||||
<files id="hxcpp_sqlite" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-I${SQLITE_DIR}"/>
|
||||
|
||||
<file name="Sqlite.cpp"/>
|
||||
|
||||
<depend name="${SQLITE_DIR}/sqlite3.h" />
|
||||
<file name="${SQLITE_DIR}/sqlite3.c"/>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_sqlite"/>
|
||||
<lib name="-lpthread" if="linux" unless="static_link" />
|
||||
</target>
|
||||
|
||||
</xml>
|
404
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/sqlite/Sqlite.cpp
Normal file
404
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/sqlite/Sqlite.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 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 <hxcpp.h>
|
||||
#include "sqlite3.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
// Put in anon-namespace to avoid conflicts if static-linked
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
struct result : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSqlite };
|
||||
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *r;
|
||||
int ncols;
|
||||
int count;
|
||||
String *names;
|
||||
int *bools;
|
||||
int done;
|
||||
int first;
|
||||
|
||||
void create(sqlite3 *inDb, sqlite3_stmt *inR, String sql)
|
||||
{
|
||||
_hx_set_finalizer(this, finalize);
|
||||
|
||||
db = inDb;
|
||||
r = inR;
|
||||
|
||||
ncols = sqlite3_column_count(r);
|
||||
names = (String *)malloc(sizeof(String)*ncols);
|
||||
bools = (int*)malloc(sizeof(int)*ncols);
|
||||
first = 1;
|
||||
done = 0;
|
||||
for(int i=0;i<ncols;i++)
|
||||
{
|
||||
names[i] = String::createPermanent(sqlite3_column_name(r,i),-1);
|
||||
for(int j=0;j<i;j++)
|
||||
if( names[j] == names[i] )
|
||||
hx::Throw(HX_CSTRING("Error, same field is two times in the request ") + sql);
|
||||
|
||||
const char *dtype = sqlite3_column_decltype(r,i);
|
||||
bools[i] = dtype?(strcmp(dtype,"BOOL") == 0):0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj) { ((result *)(obj.mPtr))->destroy(false); }
|
||||
void destroy(bool inThrowError)
|
||||
{
|
||||
if (bools)
|
||||
{
|
||||
free(bools);
|
||||
bools = 0;
|
||||
}
|
||||
if (names)
|
||||
{
|
||||
free(names);
|
||||
names = 0;
|
||||
}
|
||||
if (r)
|
||||
{
|
||||
first = 0;
|
||||
done = 1;
|
||||
if( ncols == 0 )
|
||||
count = sqlite3_changes(db);
|
||||
|
||||
bool err = sqlite3_finalize(r) != SQLITE_OK;
|
||||
db = 0;
|
||||
r = 0;
|
||||
|
||||
if( err && inThrowError)
|
||||
hx::Throw(HX_CSTRING("Could not finalize request"));
|
||||
}
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("Sqlite Result"); }
|
||||
|
||||
//static void finalize_result( result *r, int exc, bool throwError = true )
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>SQLite</h1>
|
||||
<p>
|
||||
Sqlite is a small embeddable SQL database that store all its data into
|
||||
a single file. See http://sqlite.org for more details.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
struct database : public hx::Object
|
||||
{
|
||||
sqlite3 *db;
|
||||
hx::ObjectPtr<result> last;
|
||||
|
||||
void create(sqlite3 *inDb)
|
||||
{
|
||||
db = inDb;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
static void finalize(Dynamic obj) { ((database *)(obj.mPtr))->destroy(false); }
|
||||
void destroy(bool inThrowError)
|
||||
{
|
||||
if (db)
|
||||
{
|
||||
if (last.mPtr)
|
||||
{
|
||||
last->destroy(inThrowError);
|
||||
last = null();
|
||||
}
|
||||
|
||||
if( sqlite3_close(db) != SQLITE_OK )
|
||||
{
|
||||
if (inThrowError)
|
||||
hx::Throw(HX_CSTRING("Sqlite: could not close"));
|
||||
}
|
||||
db = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setResult(result *inResult)
|
||||
{
|
||||
if (last.mPtr)
|
||||
last->destroy(true);
|
||||
|
||||
last = inResult;
|
||||
HX_OBJ_WB_GET(this, last.mPtr);
|
||||
}
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(last); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(last); }
|
||||
#endif
|
||||
|
||||
String toString() { return HX_CSTRING("Sqlite Databse"); }
|
||||
};
|
||||
|
||||
static void sqlite_error( sqlite3 *db ) {
|
||||
hx::Throw( HX_CSTRING("Sqlite error : ") + String(sqlite3_errmsg(db)) );
|
||||
}
|
||||
|
||||
database *getDatabase(Dynamic handle)
|
||||
{
|
||||
database *db = dynamic_cast<database *>(handle.mPtr);
|
||||
if (!db || !db->db)
|
||||
hx::Throw( HX_CSTRING("Invalid sqlite database") );
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
result *getResult(Dynamic handle, bool inRequireStatement)
|
||||
{
|
||||
result *r = dynamic_cast<result *>(handle.mPtr);
|
||||
if (!r || (inRequireStatement && !r->r))
|
||||
hx::Throw( HX_CSTRING("Invalid sqlite result") );
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
} // End anon-namespace
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
connect : filename:string -> 'db
|
||||
<doc>Open or create the database stored in the specified file.</doc>
|
||||
**/
|
||||
Dynamic _hx_sqlite_connect(String filename)
|
||||
{
|
||||
int err;
|
||||
sqlite3 *sqlDb = 0;
|
||||
if( (err = sqlite3_open(filename.utf8_str(),&sqlDb)) != SQLITE_OK )
|
||||
sqlite_error(sqlDb);
|
||||
|
||||
database *db = new database();
|
||||
db->create(sqlDb);
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
close : 'db -> void
|
||||
<doc>Closes the database.</doc>
|
||||
**/
|
||||
void _hx_sqlite_close(Dynamic handle)
|
||||
{
|
||||
database *db = getDatabase(handle);
|
||||
db->destroy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
last_insert_id : 'db -> int
|
||||
<doc>Returns the last inserted auto_increment id.</doc>
|
||||
**/
|
||||
int _hx_sqlite_last_insert_id(Dynamic handle)
|
||||
{
|
||||
database *db = getDatabase(handle);
|
||||
return sqlite3_last_insert_rowid(db->db);
|
||||
}
|
||||
|
||||
/**
|
||||
request : 'db -> sql:string -> 'result
|
||||
<doc>Executes the SQL request and returns its result</doc>
|
||||
**/
|
||||
Dynamic _hx_sqlite_request(Dynamic handle,String sql)
|
||||
{
|
||||
database *db = getDatabase(handle);
|
||||
|
||||
int byteLength = 0;
|
||||
const char * sqlStr = sql.utf8_str(0, true, &byteLength);
|
||||
sqlite3_stmt *statement = 0;
|
||||
const char *tl = 0;
|
||||
if( sqlite3_prepare(db->db,sqlStr,byteLength,&statement,&tl) != SQLITE_OK )
|
||||
{
|
||||
hx::Throw( HX_CSTRING("Sqlite error in ") + sql + HX_CSTRING(" : ") +
|
||||
String(sqlite3_errmsg(db->db) ) );
|
||||
}
|
||||
if( *tl )
|
||||
{
|
||||
sqlite3_finalize(statement);
|
||||
hx::Throw(HX_CSTRING("Cannot execute several SQL requests at the same time"));
|
||||
}
|
||||
|
||||
int i,j;
|
||||
|
||||
result *r = new result();
|
||||
r->create(db->db, statement,sql);
|
||||
|
||||
db->setResult(r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
result_get_length : 'result -> int
|
||||
<doc>Returns the number of rows in the result or the number of rows changed by the request.</doc>
|
||||
**/
|
||||
int _hx_sqlite_result_get_length(Dynamic handle)
|
||||
{
|
||||
result *r = getResult(handle,false);
|
||||
if( r->ncols != 0 )
|
||||
hx::Throw(HX_CSTRING("Getting change count from non-change request")); // ???
|
||||
return r->count;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_nfields : 'result -> int
|
||||
<doc>Returns the number of fields in the result.</doc>
|
||||
**/
|
||||
int _hx_sqlite_result_get_nfields(Dynamic handle)
|
||||
{
|
||||
return getResult(handle,false)->ncols;
|
||||
}
|
||||
|
||||
/**
|
||||
result_next : 'result -> object?
|
||||
<doc>Returns the next row in the result or [null] if no more result.</doc>
|
||||
**/
|
||||
|
||||
Dynamic _hx_sqlite_result_next(Dynamic handle)
|
||||
{
|
||||
result *r = getResult(handle,false);
|
||||
if( r->done )
|
||||
return null();
|
||||
|
||||
switch( sqlite3_step(r->r) )
|
||||
{
|
||||
case SQLITE_ROW:
|
||||
{
|
||||
hx::Anon v = hx::Anon_obj::Create();
|
||||
r->first = 0;
|
||||
for(int i=0;i<r->ncols;i++)
|
||||
{
|
||||
Dynamic f;
|
||||
switch( sqlite3_column_type(r->r,i) )
|
||||
{
|
||||
case SQLITE_NULL:
|
||||
break;
|
||||
case SQLITE_INTEGER:
|
||||
if( r->bools[i] )
|
||||
f = bool(sqlite3_column_int(r->r,i));
|
||||
else
|
||||
f = int(sqlite3_column_int(r->r,i));
|
||||
break;
|
||||
case SQLITE_FLOAT:
|
||||
f = Float(sqlite3_column_double(r->r,i));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
f = String((char*)sqlite3_column_text(r->r,i));
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
{
|
||||
int size = sqlite3_column_bytes(r->r,i);
|
||||
f = Array_obj<unsigned char>::fromData((const unsigned char *)sqlite3_column_blob(r->r,i),size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
hx::Throw( HX_CSTRING("Unknown Sqlite type #") +
|
||||
String((int)sqlite3_column_type(r->r,i)));
|
||||
}
|
||||
}
|
||||
v->__SetField(r->names[i],f,hx::paccDynamic);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
case SQLITE_DONE:
|
||||
r->destroy(true);
|
||||
return null();
|
||||
case SQLITE_BUSY:
|
||||
hx::Throw(HX_CSTRING("Database is busy"));
|
||||
case SQLITE_ERROR:
|
||||
sqlite_error(r->db);
|
||||
default:
|
||||
hx::Throw(HX_CSTRING("Unkown sqlite result"));
|
||||
}
|
||||
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
static sqlite3_stmt *prepStatement(Dynamic handle,int n)
|
||||
{
|
||||
result *r = getResult(handle,true);
|
||||
if( n < 0 || n >= r->ncols )
|
||||
hx::Throw( HX_CSTRING("Sqlite: Invalid index") );
|
||||
|
||||
if( r->first )
|
||||
_hx_sqlite_result_next(handle);
|
||||
|
||||
if( r->done )
|
||||
hx::Throw( HX_CSTRING("Sqlite: no more results") );
|
||||
|
||||
return r->r;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get : 'result -> n:int -> string
|
||||
<doc>Return the [n]th field of the current result row.</doc>
|
||||
**/
|
||||
|
||||
|
||||
String _hx_sqlite_result_get(Dynamic handle,int n)
|
||||
{
|
||||
sqlite3_stmt *r = prepStatement(handle,n);
|
||||
return String((char*)sqlite3_column_text(r,n));
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_int : 'result -> n:int -> int
|
||||
<doc>Return the [n]th field of the current result row as an integer.</doc>
|
||||
**/
|
||||
int _hx_sqlite_result_get_int(Dynamic handle,int n)
|
||||
{
|
||||
sqlite3_stmt *r = prepStatement(handle,n);
|
||||
return sqlite3_column_int(r,n);
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_float : 'result -> n:int -> float
|
||||
<doc>Return the [n]th field of the current result row as a float.</doc>
|
||||
**/
|
||||
Float _hx_sqlite_result_get_float(Dynamic handle,int n)
|
||||
{
|
||||
sqlite3_stmt *r = prepStatement(handle,n);
|
||||
return sqlite3_column_double(r,n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
129
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/ssl/Build.xml
Normal file
129
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/ssl/Build.xml
Normal file
@ -0,0 +1,129 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="MBEDTLS_DIR" value="${HXCPP}/project/thirdparty/mbedtls-2.28.2" />
|
||||
|
||||
<files id="hxcpp_ssl" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
<compilerflag value="-I${MBEDTLS_DIR}/include"/>
|
||||
<compilerflag value="-I${this_dir}"/>
|
||||
|
||||
<file name="${this_dir}/SSL.cpp"/>
|
||||
|
||||
<compilerflag value="-DMBEDTLS_USER_CONFIG_FILE=<mbedtls_config.h>"/>
|
||||
|
||||
<file name="${MBEDTLS_DIR}/library/aes.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/aesni.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/arc4.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/aria.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/asn1parse.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/asn1write.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/base64.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/bignum.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/blowfish.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/camellia.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ccm.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/chacha20.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/chachapoly.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/cipher.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/cipher_wrap.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/constant_time.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/cmac.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ctr_drbg.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/des.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/dhm.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecdh.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecdsa.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecjpake.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecp.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecp_curves.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/entropy.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/entropy_poll.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/error.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/gcm.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/havege.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/hkdf.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/hmac_drbg.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md2.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md4.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md5.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/memory_buffer_alloc.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/mps_reader.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/mps_trace.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/nist_kw.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/oid.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/padlock.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pem.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pk.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pk_wrap.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkcs12.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkcs5.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkparse.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkwrite.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/platform.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/platform_util.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/poly1305.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_aead.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_cipher.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_client.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_driver_wrappers.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_ecp.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_hash.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_mac.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_rsa.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_se.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_slot_management.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_storage.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_its_file.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ripemd160.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/rsa.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/rsa_internal.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/sha1.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/sha256.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/sha512.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/threading.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/timing.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/version.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/version_features.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/xtea.c"/>
|
||||
|
||||
<file name="${MBEDTLS_DIR}/library/certs.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkcs11.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_create.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_crl.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_crt.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_csr.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509write_crt.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509write_csr.c"/>
|
||||
|
||||
<file name="${MBEDTLS_DIR}/library/debug.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/net_sockets.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_cache.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_ciphersuites.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_cli.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_cookie.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_msg.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_srv.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_ticket.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_tls.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_tls13_keys.c"/>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_ssl" />
|
||||
|
||||
<lib name="advapi32.lib" if="windows" unless="static_link" />
|
||||
<lib name="crypt32.lib" if="windows" unless="static_link" />
|
||||
<lib name="ws2_32.lib" if="windows" unless="static_link" />
|
||||
|
||||
<flag value="-framework" if="macos"/>
|
||||
<flag value="Security" if="macos"/>
|
||||
</target>
|
||||
|
||||
</xml>
|
861
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/ssl/SSL.cpp
Normal file
861
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/ssl/SSL.cpp
Normal file
@ -0,0 +1,861 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifndef KORE_CONSOLE
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wparentheses"
|
||||
#endif
|
||||
|
||||
#ifdef HX_WINDOWS
|
||||
# include <winsock2.h>
|
||||
# include <wincrypt.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <strings.h>
|
||||
# include <errno.h>
|
||||
typedef int SOCKET;
|
||||
#endif
|
||||
|
||||
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
#if defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV)
|
||||
#include <Security/Security.h>
|
||||
#endif
|
||||
|
||||
typedef size_t socket_int;
|
||||
|
||||
#define SOCKET_ERROR (-1)
|
||||
#define NRETRYS 20
|
||||
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/oid.h"
|
||||
#include "mbedtls/x509_crt.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/debug.h"
|
||||
|
||||
#define val_ssl(o) ((sslctx*)o.mPtr)
|
||||
#define val_conf(o) ((sslconf*)o.mPtr)
|
||||
#define val_cert(o) ((sslcert*)o.mPtr)
|
||||
#define val_pkey(o) ((sslpkey*)o.mPtr)
|
||||
|
||||
struct SocketWrapper : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSocket };
|
||||
SOCKET socket;
|
||||
};
|
||||
|
||||
struct sslctx : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSsl };
|
||||
|
||||
mbedtls_ssl_context *s;
|
||||
|
||||
void create()
|
||||
{
|
||||
s = (mbedtls_ssl_context *)malloc(sizeof(mbedtls_ssl_context));
|
||||
mbedtls_ssl_init(s);
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( s )
|
||||
{
|
||||
mbedtls_ssl_free( s );
|
||||
free(s);
|
||||
s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslctx *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslctx"); }
|
||||
};
|
||||
|
||||
struct sslconf : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslConf };
|
||||
|
||||
mbedtls_ssl_config *c;
|
||||
|
||||
void create()
|
||||
{
|
||||
c = (mbedtls_ssl_config *)malloc(sizeof(mbedtls_ssl_config));
|
||||
mbedtls_ssl_config_init(c);
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( c )
|
||||
{
|
||||
mbedtls_ssl_config_free( c );
|
||||
free(c);
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslconf *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslconfig"); }
|
||||
};
|
||||
|
||||
struct sslcert : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslCert };
|
||||
|
||||
mbedtls_x509_crt *c;
|
||||
bool head;
|
||||
|
||||
void create(const mbedtls_x509_crt *inC)
|
||||
{
|
||||
|
||||
if( inC ){
|
||||
c = (mbedtls_x509_crt *)inC;
|
||||
head = false;
|
||||
}else{
|
||||
c = (mbedtls_x509_crt *)malloc(sizeof(mbedtls_x509_crt));
|
||||
mbedtls_x509_crt_init(c);
|
||||
head = true;
|
||||
}
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( c && head )
|
||||
{
|
||||
mbedtls_x509_crt_free( c );
|
||||
free(c);
|
||||
head = 0;
|
||||
}
|
||||
c = 0;
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslcert *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslcert"); }
|
||||
};
|
||||
|
||||
struct sslpkey : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslKey };
|
||||
|
||||
mbedtls_pk_context *k;
|
||||
|
||||
void create()
|
||||
{
|
||||
k = (mbedtls_pk_context *)malloc(sizeof(mbedtls_pk_context));
|
||||
mbedtls_pk_init(k);
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( k )
|
||||
{
|
||||
mbedtls_pk_free(k);
|
||||
free(k);
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslpkey *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslpkey"); }
|
||||
};
|
||||
|
||||
static mbedtls_entropy_context entropy;
|
||||
static mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
static bool is_ssl_blocking( int r ) {
|
||||
return r == MBEDTLS_ERR_SSL_WANT_READ || r == MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
}
|
||||
|
||||
static bool is_block_error() {
|
||||
#ifdef NEKO_WINDOWS
|
||||
int err = WSAGetLastError();
|
||||
if( err == WSAEWOULDBLOCK || err == WSAEALREADY || err == WSAETIMEDOUT )
|
||||
#else
|
||||
if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
|
||||
#endif
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ssl_error( int ret ){
|
||||
char buf[256];
|
||||
mbedtls_strerror(ret, buf, sizeof(buf));
|
||||
hx::Throw( String(buf) );
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_new( Dynamic hconf ) {
|
||||
int ret;
|
||||
sslctx *ssl = new sslctx();
|
||||
ssl->create();
|
||||
sslconf *conf = val_conf(hconf);
|
||||
if( ret = mbedtls_ssl_setup(ssl->s, conf->c) != 0 ){
|
||||
ssl->destroy();
|
||||
ssl_error(ret);
|
||||
}
|
||||
return ssl;
|
||||
}
|
||||
|
||||
void _hx_ssl_close( Dynamic hssl ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
ssl->destroy();
|
||||
}
|
||||
|
||||
void _hx_ssl_debug_set (int i) {
|
||||
mbedtls_debug_set_threshold(i);
|
||||
}
|
||||
|
||||
void _hx_ssl_handshake( Dynamic hssl ) {
|
||||
int r;
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
POSIX_LABEL(handshake_again);
|
||||
r = mbedtls_ssl_handshake( ssl->s );
|
||||
if ( is_ssl_blocking(r) ) {
|
||||
HANDLE_EINTR(handshake_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( r == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(handshake_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}else if( r != 0 )
|
||||
ssl_error(r);
|
||||
}
|
||||
|
||||
int net_read( void *fd, unsigned char *buf, size_t len ){
|
||||
hx::EnterGCFreeZone();
|
||||
int r = recv((SOCKET)(socket_int)fd, (char *)buf, len, 0);
|
||||
if( r == SOCKET_ERROR && is_block_error() )
|
||||
r = MBEDTLS_ERR_SSL_WANT_READ;
|
||||
hx::ExitGCFreeZone();
|
||||
return r;
|
||||
}
|
||||
|
||||
int net_write( void *fd, const unsigned char *buf, size_t len ){
|
||||
hx::EnterGCFreeZone();
|
||||
int r = send((SOCKET)(socket_int)fd, (char *)buf, len, 0);
|
||||
if( r == SOCKET_ERROR && is_block_error() )
|
||||
r = MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
hx::ExitGCFreeZone();
|
||||
return r;
|
||||
}
|
||||
|
||||
void _hx_ssl_set_socket( Dynamic hssl, Dynamic hsocket ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
SocketWrapper *socket = (SocketWrapper *)hsocket.mPtr;
|
||||
mbedtls_ssl_set_bio( ssl->s, (void *)(socket_int)socket->socket, net_write, net_read, NULL );
|
||||
}
|
||||
|
||||
void _hx_ssl_set_hostname( Dynamic hssl, String hostname ){
|
||||
int ret;
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
hx::strbuf buf;
|
||||
if( ret = mbedtls_ssl_set_hostname(ssl->s, hostname.utf8_str(&buf)) != 0 )
|
||||
ssl_error(ret);
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_get_peer_certificate( Dynamic hssl ){
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(ssl->s);
|
||||
if( crt == NULL )
|
||||
return null();
|
||||
sslcert *cert = new sslcert();
|
||||
cert->create( crt );
|
||||
return cert;
|
||||
}
|
||||
|
||||
bool _hx_ssl_get_verify_result( Dynamic hssl ){
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int r = mbedtls_ssl_get_verify_result( ssl->s );
|
||||
if( r == 0 )
|
||||
return true;
|
||||
else if( r != -1 )
|
||||
return false;
|
||||
hx::Throw( HX_CSTRING("not available") );
|
||||
return false;
|
||||
}
|
||||
|
||||
void _hx_ssl_send_char( Dynamic hssl, int c ) {
|
||||
if( c < 0 || c > 255 )
|
||||
hx::Throw( HX_CSTRING("invalid char") );
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
const unsigned char cc = c;
|
||||
mbedtls_ssl_write( ssl->s, &cc, 1 );
|
||||
}
|
||||
|
||||
int _hx_ssl_send( Dynamic hssl, Array<unsigned char> buf, int p, int l ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int dlen = buf->length;
|
||||
if( p < 0 || l < 0 || p > dlen || p + l > dlen )
|
||||
hx::Throw( HX_CSTRING("ssl_send") );
|
||||
POSIX_LABEL(send_again);
|
||||
const unsigned char *base = (const unsigned char *)&buf[0];
|
||||
dlen = mbedtls_ssl_write( ssl->s, base + p, l );
|
||||
if ( is_ssl_blocking(dlen) ) {
|
||||
HANDLE_EINTR(send_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( dlen == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(send_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
return dlen;
|
||||
}
|
||||
|
||||
void _hx_ssl_write( Dynamic hssl, Array<unsigned char> buf ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int len = buf->length;
|
||||
unsigned char *cdata = &buf[0];
|
||||
while( len > 0 ) {
|
||||
POSIX_LABEL( write_again );
|
||||
int slen = mbedtls_ssl_write( ssl->s, cdata, len );
|
||||
if ( is_ssl_blocking(slen) ) {
|
||||
HANDLE_EINTR( write_again );
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( slen == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR( write_again );
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
cdata += slen;
|
||||
len -= slen;
|
||||
}
|
||||
}
|
||||
|
||||
int _hx_ssl_recv_char( Dynamic hssl ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
unsigned char cc;
|
||||
int r = mbedtls_ssl_read( ssl->s, &cc, 1 );
|
||||
if( r <= 0 )
|
||||
hx::Throw( HX_CSTRING("ssl_recv_char") );
|
||||
return (int)cc;
|
||||
}
|
||||
|
||||
int _hx_ssl_recv( Dynamic hssl, Array<unsigned char> buf, int p, int l ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int dlen = buf->length;
|
||||
if( p < 0 || l < 0 || p > dlen || p + l > dlen )
|
||||
hx::Throw( HX_CSTRING("ssl_recv") );
|
||||
|
||||
unsigned char *base = &buf[0];
|
||||
POSIX_LABEL(recv_again);
|
||||
dlen = mbedtls_ssl_read( ssl->s, base + p, l );
|
||||
if ( is_ssl_blocking(dlen) ) {
|
||||
HANDLE_EINTR(recv_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( dlen == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(recv_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
if( dlen < 0 ) {
|
||||
if( dlen == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) {
|
||||
mbedtls_ssl_close_notify( ssl->s );
|
||||
return 0;
|
||||
}
|
||||
hx::Throw( HX_CSTRING("ssl_recv") );
|
||||
}
|
||||
return dlen;
|
||||
}
|
||||
|
||||
Array<unsigned char> _hx_ssl_read( Dynamic hssl ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
Array<unsigned char> result = Array_obj<unsigned char>::__new();
|
||||
unsigned char buf[256];
|
||||
|
||||
while( true ) {
|
||||
POSIX_LABEL(read_again);
|
||||
int len = mbedtls_ssl_read( ssl->s, buf, 256 );
|
||||
if ( is_ssl_blocking(len) ) {
|
||||
HANDLE_EINTR(read_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( len == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(read_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
if( len == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) {
|
||||
mbedtls_ssl_close_notify( ssl->s );
|
||||
len = 0;
|
||||
}
|
||||
if( len == 0 )
|
||||
break;
|
||||
result->memcpy(result->length, buf, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_conf_new( bool server ) {
|
||||
int ret;
|
||||
sslconf *conf = new sslconf();
|
||||
conf->create();
|
||||
if( ret = mbedtls_ssl_config_defaults( conf->c,
|
||||
server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM, 0 ) != 0 ){
|
||||
conf->destroy();
|
||||
ssl_error( ret );
|
||||
}
|
||||
mbedtls_ssl_conf_rng( conf->c, mbedtls_ctr_drbg_random, &ctr_drbg );
|
||||
return conf;
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_close( Dynamic hconf ) {
|
||||
sslconf *conf = val_conf(hconf);
|
||||
conf->destroy();
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_ca( Dynamic hconf, Dynamic hcert ) {
|
||||
sslconf *conf = val_conf(hconf);
|
||||
if( hconf.mPtr ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
mbedtls_ssl_conf_ca_chain( conf->c, cert->c, NULL );
|
||||
}else{
|
||||
mbedtls_ssl_conf_ca_chain( conf->c, NULL, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_verify( Dynamic hconf, int mode ) {
|
||||
sslconf *conf = val_conf(hconf);
|
||||
if( mode == 2 )
|
||||
mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
else if( mode == 1 )
|
||||
mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
else
|
||||
mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_cert( Dynamic hconf, Dynamic hcert, Dynamic hpkey ) {
|
||||
int r;
|
||||
sslconf *conf = val_conf(hconf);
|
||||
sslcert *cert = val_cert(hcert);
|
||||
sslpkey *pkey = val_pkey(hpkey);
|
||||
|
||||
if( r = mbedtls_ssl_conf_own_cert(conf->c, cert->c, pkey->k) != 0 )
|
||||
ssl_error(r);
|
||||
}
|
||||
|
||||
static int sni_callback( void *arg, mbedtls_ssl_context *ctx, const unsigned char *name, size_t len ){
|
||||
if( name && arg ){
|
||||
Dynamic cb = new Dynamic();
|
||||
cb.mPtr = (hx::Object*)arg;
|
||||
const char *n = (const char *)name;
|
||||
Dynamic ret = cb->__run( String(n,strlen(n)) );
|
||||
if( ret != null() ){
|
||||
// TODO authmode and ca
|
||||
Dynamic hcert = ret->__Field(HX_CSTRING("cert"), hx::paccDynamic);
|
||||
Dynamic hpkey = ret->__Field(HX_CSTRING("key"), hx::paccDynamic);
|
||||
sslcert *cert = val_cert(hcert);
|
||||
sslpkey *pk = val_pkey(hpkey);
|
||||
|
||||
return mbedtls_ssl_set_hs_own_cert( ctx, cert->c, pk->k );
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_servername_callback( Dynamic hconf, Dynamic cb ){
|
||||
sslconf *conf = val_conf(hconf);
|
||||
mbedtls_ssl_conf_sni( conf->c, sni_callback, (void *)cb.mPtr );
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_load_defaults(){
|
||||
#if defined(NEKO_WINDOWS) && !defined(KORE_WINDOWSAPP)
|
||||
HCERTSTORE store;
|
||||
PCCERT_CONTEXT cert;
|
||||
sslcert *chain = NULL;
|
||||
if( store = CertOpenSystemStoreA(0, (LPCSTR)"Root") ){
|
||||
cert = NULL;
|
||||
while( cert = CertEnumCertificatesInStore(store, cert) ){
|
||||
if( chain == NULL ){
|
||||
chain = new sslcert();
|
||||
chain->create( NULL );
|
||||
}
|
||||
mbedtls_x509_crt_parse_der( chain->c, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded );
|
||||
}
|
||||
CertCloseStore(store, 0);
|
||||
}
|
||||
if( chain != NULL )
|
||||
return chain;
|
||||
#elif defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV)
|
||||
CFMutableDictionaryRef search;
|
||||
CFArrayRef result;
|
||||
SecKeychainRef keychain;
|
||||
SecCertificateRef item;
|
||||
CFDataRef dat;
|
||||
sslcert *chain = NULL;
|
||||
|
||||
// Load keychain
|
||||
if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",&keychain) != errSecSuccess )
|
||||
return null();
|
||||
|
||||
// Search for certificates
|
||||
search = CFDictionaryCreateMutable( NULL, 0, NULL, NULL );
|
||||
CFDictionarySetValue( search, kSecClass, kSecClassCertificate );
|
||||
CFDictionarySetValue( search, kSecMatchLimit, kSecMatchLimitAll );
|
||||
CFDictionarySetValue( search, kSecReturnRef, kCFBooleanTrue );
|
||||
CFDictionarySetValue( search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL) );
|
||||
if( SecItemCopyMatching( search, (CFTypeRef *)&result ) == errSecSuccess ){
|
||||
CFIndex n = CFArrayGetCount( result );
|
||||
for( CFIndex i = 0; i < n; i++ ){
|
||||
item = (SecCertificateRef)CFArrayGetValueAtIndex( result, i );
|
||||
|
||||
// Get certificate in DER format
|
||||
dat = SecCertificateCopyData( item );
|
||||
if( dat ){
|
||||
if( chain == NULL ){
|
||||
chain = new sslcert();
|
||||
chain->create( NULL );
|
||||
}
|
||||
mbedtls_x509_crt_parse_der( chain->c, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat) );
|
||||
CFRelease( dat );
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(keychain);
|
||||
if( chain != NULL )
|
||||
return chain;
|
||||
#endif
|
||||
return null();
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_load_file( String file ){
|
||||
int r;
|
||||
sslcert *cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
hx::strbuf buf;
|
||||
if( r = mbedtls_x509_crt_parse_file(cert->c, file.utf8_str(&buf)) != 0 ){
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_load_path( String path ){
|
||||
int r;
|
||||
sslcert *cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
hx::strbuf buf;
|
||||
if( r = mbedtls_x509_crt_parse_path(cert->c, path.utf8_str(&buf)) != 0 ){
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
static String asn1_buf_to_string( mbedtls_asn1_buf *dat ){
|
||||
unsigned int i, c;
|
||||
HX_CHAR *result = hx::NewString( dat->len );
|
||||
for( i = 0; i < dat->len; i++ ) {
|
||||
c = dat->p[i];
|
||||
if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
|
||||
result[i] = '?';
|
||||
else
|
||||
result[i] = c;
|
||||
}
|
||||
result[i] = '\0';
|
||||
return String(result,dat->len);
|
||||
}
|
||||
|
||||
String _hx_ssl_cert_get_subject( Dynamic hcert, String objname ){
|
||||
mbedtls_x509_name *obj;
|
||||
int r;
|
||||
const char *oname;
|
||||
sslcert *cert = val_cert(hcert);
|
||||
obj = &cert->c->subject;
|
||||
if( obj == NULL )
|
||||
hx::Throw( HX_CSTRING("cert_get_subject") );
|
||||
hx::strbuf buf;
|
||||
while( obj != NULL ){
|
||||
r = mbedtls_oid_get_attr_short_name( &obj->oid, &oname );
|
||||
if( r == 0 && strcmp( oname, objname.utf8_str(&buf) ) == 0 )
|
||||
return asn1_buf_to_string( &obj->val );
|
||||
obj = obj->next;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
String _hx_ssl_cert_get_issuer( Dynamic hcert, String objname ){
|
||||
mbedtls_x509_name *obj;
|
||||
int r;
|
||||
const char *oname;
|
||||
sslcert *cert = val_cert(hcert);
|
||||
obj = &cert->c->issuer;
|
||||
if( obj == NULL )
|
||||
hx::Throw( HX_CSTRING("cert_get_issuer") );
|
||||
hx::strbuf buf;
|
||||
while( obj != NULL ){
|
||||
r = mbedtls_oid_get_attr_short_name( &obj->oid, &oname );
|
||||
if( r == 0 && strcmp( oname, objname.utf8_str(&buf) ) == 0 )
|
||||
return asn1_buf_to_string( &obj->val );
|
||||
obj = obj->next;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
Array<String> _hx_ssl_cert_get_altnames( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
mbedtls_asn1_sequence *cur;
|
||||
Array<String> result(0,1);
|
||||
if( cert->c->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ){
|
||||
cur = &cert->c->subject_alt_names;
|
||||
|
||||
while( cur != NULL ){
|
||||
result.Add( asn1_buf_to_string(&cur->buf) );
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Array<int> x509_time_to_array( mbedtls_x509_time *t ){
|
||||
if( !t )
|
||||
hx::Throw( HX_CSTRING("x509_time_to_array") );
|
||||
Array<int> result(6,6);
|
||||
result[0] = t->year;
|
||||
result[1] = t->mon;
|
||||
result[2] = t->day;
|
||||
result[3] = t->hour;
|
||||
result[4] = t->min;
|
||||
result[5] = t->sec;
|
||||
return result;
|
||||
}
|
||||
|
||||
Array<int> _hx_ssl_cert_get_notbefore( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
if( !cert->c )
|
||||
hx::Throw( HX_CSTRING("cert_get_notbefore") );
|
||||
return x509_time_to_array( &cert->c->valid_from );
|
||||
}
|
||||
|
||||
Array<int> _hx_ssl_cert_get_notafter( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
if( !cert->c )
|
||||
hx::Throw( HX_CSTRING("cert_get_notafter") );
|
||||
return x509_time_to_array( &cert->c->valid_to );
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_get_next( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
mbedtls_x509_crt *crt = cert->c->next;
|
||||
if( crt == NULL )
|
||||
return null();
|
||||
cert = new sslcert();
|
||||
cert->create(crt);
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_add_pem( Dynamic hcert, String data ){
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (data.isUTF16Encoded())
|
||||
hx::Throw( HX_CSTRING("Invalid data encoding") );
|
||||
#endif
|
||||
sslcert *cert = val_cert(hcert);
|
||||
int r;
|
||||
bool isnew = 0;
|
||||
if( !cert ){
|
||||
cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
isnew = 1;
|
||||
}
|
||||
unsigned char *b = (unsigned char *)malloc((data.length+1) * sizeof(unsigned char));
|
||||
memcpy(b,data.raw_ptr(),data.length);
|
||||
b[data.length] = '\0';
|
||||
r = mbedtls_x509_crt_parse( cert->c, b, data.length+1 );
|
||||
free(b);
|
||||
if( r < 0 ){
|
||||
if( isnew )
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_add_der( Dynamic hcert, Array<unsigned char> buf ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
int r;
|
||||
bool isnew = 0;
|
||||
if( !cert ){
|
||||
cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
isnew = 1;
|
||||
}
|
||||
if( (r = mbedtls_x509_crt_parse_der( cert->c, &buf[0], buf->length)) < 0 ){
|
||||
if( isnew )
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_key_from_der( Array<unsigned char> buf, bool pub ){
|
||||
sslpkey *pk = new sslpkey();
|
||||
pk->create();
|
||||
int r;
|
||||
if( pub )
|
||||
r = mbedtls_pk_parse_public_key( pk->k, &buf[0], buf->length );
|
||||
else
|
||||
r = mbedtls_pk_parse_key( pk->k, &buf[0], buf->length, NULL, 0 );
|
||||
if( r != 0 ){
|
||||
pk->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_key_from_pem( String data, bool pub, String pass ){
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (data.isUTF16Encoded())
|
||||
hx::Throw( HX_CSTRING("Invalid data encoding") );
|
||||
#endif
|
||||
sslpkey *pk = new sslpkey();
|
||||
pk->create();
|
||||
int r;
|
||||
unsigned char *b = (unsigned char *)malloc((data.length+1) * sizeof(unsigned char));
|
||||
memcpy(b,data.raw_ptr(),data.length);
|
||||
b[data.length] = '\0';
|
||||
if( pub ){
|
||||
r = mbedtls_pk_parse_public_key( pk->k, b, data.length+1 );
|
||||
}else if( pass == null() ){
|
||||
r = mbedtls_pk_parse_key( pk->k, b, data.length+1, NULL, 0 );
|
||||
}else{
|
||||
Array<unsigned char> pbytes(0,0);
|
||||
__hxcpp_bytes_of_string(pbytes,pass);
|
||||
r = mbedtls_pk_parse_key( pk->k, b, data.length+1, (const unsigned char *)pbytes->GetBase(), pbytes->length );
|
||||
}
|
||||
free(b);
|
||||
if( r != 0 ){
|
||||
pk->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
Array<unsigned char> _hx_ssl_dgst_make( Array<unsigned char> buf, String alg ){
|
||||
hx::strbuf ubuf;
|
||||
const mbedtls_md_info_t *md = mbedtls_md_info_from_string(alg.utf8_str(&ubuf));
|
||||
if( md == NULL )
|
||||
hx::Throw( HX_CSTRING("Invalid hash algorithm") );
|
||||
|
||||
int size = mbedtls_md_get_size(md);
|
||||
Array<unsigned char> out = Array_obj<int>::__new(size,size);
|
||||
int r = -1;
|
||||
if( r = mbedtls_md( md, &buf[0], buf->length, &out[0] ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Array<unsigned char> _hx_ssl_dgst_sign( Array<unsigned char> buf, Dynamic hpkey, String alg ){
|
||||
int r = -1;
|
||||
size_t olen = 0;
|
||||
unsigned char hash[32];
|
||||
sslpkey *pk = val_pkey(hpkey);
|
||||
|
||||
hx::strbuf ubuf;
|
||||
const mbedtls_md_info_t *md = mbedtls_md_info_from_string( alg.utf8_str(&ubuf) );
|
||||
if( md == NULL )
|
||||
hx::Throw( HX_CSTRING("Invalid hash algorithm") );
|
||||
|
||||
if( r = mbedtls_md( md, &buf[0], buf->length, hash ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
Array<unsigned char> result = Array_obj<unsigned char>::__new(MBEDTLS_MPI_MAX_SIZE,MBEDTLS_MPI_MAX_SIZE);
|
||||
if( r = mbedtls_pk_sign( pk->k, mbedtls_md_get_type(md), hash, 0, &result[0], &olen, mbedtls_ctr_drbg_random, &ctr_drbg ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
result[olen] = 0;
|
||||
result->__SetSize(olen);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool _hx_ssl_dgst_verify( Array<unsigned char> buf, Array<unsigned char> sign, Dynamic hpkey, String alg ){
|
||||
const mbedtls_md_info_t *md;
|
||||
int r = -1;
|
||||
unsigned char hash[32];
|
||||
sslpkey *pk = val_pkey(hpkey);
|
||||
|
||||
hx::strbuf ubuf;
|
||||
md = mbedtls_md_info_from_string( alg.utf8_str(&ubuf) );
|
||||
if( md == NULL )
|
||||
hx::Throw( HX_CSTRING("Invalid hash algorithm") );
|
||||
|
||||
if( r = mbedtls_md( md, &buf[0], buf->length, hash ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
if( r = mbedtls_pk_verify( pk->k, mbedtls_md_get_type(md), hash, 0, &sign[0], sign->length ) != 0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if (_MSC_VER || defined(WIN32))
|
||||
|
||||
static void threading_mutex_init_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL )
|
||||
return;
|
||||
InitializeCriticalSection( &mutex->cs );
|
||||
mutex->is_valid = 1;
|
||||
}
|
||||
|
||||
static void threading_mutex_free_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL || !mutex->is_valid )
|
||||
return;
|
||||
DeleteCriticalSection( &mutex->cs );
|
||||
mutex->is_valid = 0;
|
||||
}
|
||||
|
||||
static int threading_mutex_lock_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL || !mutex->is_valid )
|
||||
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
|
||||
|
||||
EnterCriticalSection( &mutex->cs );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int threading_mutex_unlock_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL || !mutex->is_valid )
|
||||
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
|
||||
|
||||
LeaveCriticalSection( &mutex->cs );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool _hx_ssl_inited = false;
|
||||
void _hx_ssl_init() {
|
||||
if (_hx_ssl_inited) return;
|
||||
_hx_ssl_inited = true;
|
||||
|
||||
#if (_MSC_VER || defined(WIN32))
|
||||
mbedtls_threading_set_alt( threading_mutex_init_alt, threading_mutex_free_alt,
|
||||
threading_mutex_lock_alt, threading_mutex_unlock_alt );
|
||||
#endif
|
||||
|
||||
// Init RNG
|
||||
mbedtls_entropy_init( &entropy );
|
||||
mbedtls_ctr_drbg_init( &ctr_drbg );
|
||||
mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
@ -0,0 +1,10 @@
|
||||
#ifdef HX_WINDOWS
|
||||
#define MBEDTLS_THREADING_ALT
|
||||
#endif
|
||||
#ifndef HX_WINDOWS
|
||||
#define MBEDTLS_THREADING_PTHREAD
|
||||
#endif
|
||||
|
||||
#undef MBEDTLS_NET_C
|
||||
|
||||
#define MBEDTLS_THREADING_C
|
@ -0,0 +1,6 @@
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
CRITICAL_SECTION cs;
|
||||
char is_valid;
|
||||
} mbedtls_threading_mutex_t;
|
26
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Build.xml
Normal file
26
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Build.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<files id="hxcpp_std" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="1" asLibrary="true" />
|
||||
|
||||
<file name="File.cpp"/>
|
||||
<file name="Sys.cpp"/>
|
||||
<file name="Process.cpp"/>
|
||||
<file name="Random.cpp"/>
|
||||
<file name="Socket.cpp" />
|
||||
|
||||
</files>
|
||||
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_std"/>
|
||||
<lib name="ws2_32.lib" if="windows" unless="static_link" />
|
||||
<lib name="-lsocket" if="blackberry" unless="static_link" />
|
||||
</target>
|
||||
|
||||
|
||||
</xml>
|
404
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/File.cpp
Normal file
404
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/File.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
#include <hxcpp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include <hx/OS.h>
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>File</h1>
|
||||
<p>
|
||||
The file api can be used for different kind of file I/O.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct fio : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdFio };
|
||||
|
||||
String name;
|
||||
FILE *io;
|
||||
bool closeIo;
|
||||
|
||||
void create(FILE *inFile, String inName, bool inClose)
|
||||
{
|
||||
name = inName;
|
||||
HX_OBJ_WB_GET(this,name.raw_ref());
|
||||
io = inFile;
|
||||
closeIo = inClose;
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy(bool inForceClose = false)
|
||||
{
|
||||
if (io && (inForceClose || closeIo))
|
||||
fclose(io);
|
||||
io = 0;
|
||||
name = String();
|
||||
}
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(name); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(name); }
|
||||
#endif
|
||||
|
||||
static void finalize(Dynamic inObj)
|
||||
{
|
||||
((fio *)(inObj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("fio:") + name; }
|
||||
|
||||
};
|
||||
|
||||
fio *getFio(Dynamic handle, bool inRequireFile=true)
|
||||
{
|
||||
fio *result = dynamic_cast<fio *>(handle.mPtr);
|
||||
if (!result || (!result->io && inRequireFile))
|
||||
hx::Throw( HX_CSTRING("Bad file handle") );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void file_error(const char *msg, String inName)
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
Array<String> err = Array_obj<String>::__new(2,2);
|
||||
err[0] = String(msg);
|
||||
err[1] = inName;
|
||||
hx::Throw(err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
file_open : f:string -> r:string -> 'file
|
||||
<doc>
|
||||
Call the C function [fopen] with the file path and access rights.
|
||||
Return the opened file or throw an exception if the file couldn't be open.
|
||||
</doc>
|
||||
**/
|
||||
Dynamic _hx_std_file_open( String fname, String r )
|
||||
{
|
||||
FILE *file = 0;
|
||||
|
||||
hx::strbuf buf0;
|
||||
hx::strbuf buf1;
|
||||
#ifdef NEKO_WINDOWS
|
||||
hx::EnterGCFreeZone();
|
||||
file = _wfopen(fname.wchar_str(&buf0),r.wchar_str(&buf1));
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
file = fopen(fname.utf8_str(&buf0),r.utf8_str(&buf1));
|
||||
#endif
|
||||
if (!file)
|
||||
file_error("file_open",fname);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
fio *f = new fio;
|
||||
f->create(file,fname,true);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
file_close : 'file -> void
|
||||
<doc>Close an file. Any other operations on this file will fail</doc>
|
||||
**/
|
||||
void _hx_std_file_close( Dynamic handle )
|
||||
{
|
||||
fio *fio = getFio(handle);
|
||||
fio->destroy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
file_name : 'file -> string
|
||||
<doc>Return the name of the file which was opened</doc>
|
||||
**/
|
||||
String hx_std_file_name( Dynamic handle )
|
||||
{
|
||||
fio *fio = getFio(handle);
|
||||
return fio->name;
|
||||
}
|
||||
|
||||
/**
|
||||
file_write : 'file -> s:string -> p:int -> l:int -> int
|
||||
<doc>
|
||||
Write up to [l] chars of string [s] starting at position [p].
|
||||
Returns the number of chars written which is >= 0.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_file_write( Dynamic handle, Array<unsigned char> s, int p, int n )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
|
||||
int buflen = s->length;
|
||||
int len = n;
|
||||
if( p < 0 || len < 0 || p > buflen || p + len > buflen )
|
||||
return 0;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
while( len > 0 )
|
||||
{
|
||||
POSIX_LABEL(file_write_again);
|
||||
int d = (int)fwrite(&s[p],1,len,f->io);
|
||||
if( d <= 0 )
|
||||
{
|
||||
HANDLE_FINTR(f->io,file_write_again);
|
||||
file_error("file_write",f->name);
|
||||
}
|
||||
p += d;
|
||||
len -= d;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
file_read : 'file -> s:string -> p:int -> l:int -> int
|
||||
<doc>
|
||||
Read up to [l] chars into the string [s] starting at position [p].
|
||||
Returns the number of chars readed which is > 0 (or 0 if l == 0).
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_file_read( Dynamic handle, Array<unsigned char> buf, int p, int n )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
|
||||
int buf_len = buf->length;
|
||||
int len = n;
|
||||
if( p < 0 || len < 0 || p > buf_len || p + len > buf_len )
|
||||
return 0;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
// Attempt to increase the chances of pinning on the stack...
|
||||
unsigned char *bufPtr = &buf[0];
|
||||
while( len > 0 )
|
||||
{
|
||||
POSIX_LABEL(file_read_again);
|
||||
int d = (int)fread(bufPtr + p,1,len,f->io);
|
||||
if( d <= 0 )
|
||||
{
|
||||
int size = n - len;
|
||||
HANDLE_FINTR(f->io,file_read_again);
|
||||
if( size == 0 )
|
||||
file_error("file_read",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
return size;
|
||||
}
|
||||
p += d;
|
||||
len -= d;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
file_write_char : 'file -> c:int -> void
|
||||
<doc>Write the char [c]. Error if [c] outside of the range 0..255</doc>
|
||||
**/
|
||||
void _hx_std_file_write_char( Dynamic handle, int c )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
if( c < 0 || c > 255 )
|
||||
return;
|
||||
char cc = (char)c;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
POSIX_LABEL(write_char_again);
|
||||
if( fwrite(&cc,1,1,f->io) != 1 )
|
||||
{
|
||||
HANDLE_FINTR(f->io,write_char_again);
|
||||
file_error("file_write_char",f->name);
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
file_read_char : 'file -> int
|
||||
<doc>Read a char from the file. Exception on error</doc>
|
||||
**/
|
||||
int _hx_std_file_read_char( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
|
||||
unsigned char cc = 0;
|
||||
hx::EnterGCFreeZone();
|
||||
POSIX_LABEL(read_char_again);
|
||||
if( fread(&cc,1,1,f->io) != 1 )
|
||||
{
|
||||
HANDLE_FINTR(f->io,read_char_again);
|
||||
file_error("file_read_char",f->name);
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
return cc;
|
||||
}
|
||||
|
||||
/**
|
||||
file_seek : 'file -> pos:int -> mode:int -> void
|
||||
<doc>Use [fseek] to move the file pointer.</doc>
|
||||
**/
|
||||
void _hx_std_file_seek( Dynamic handle, int pos, int kind )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
hx::EnterGCFreeZone();
|
||||
if( fseek(f->io,pos,kind) != 0 )
|
||||
file_error("file_seek",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
file_tell : 'file -> int
|
||||
<doc>Return the current position in the file</doc>
|
||||
**/
|
||||
int _hx_std_file_tell( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
hx::EnterGCFreeZone();
|
||||
int p = ftell(f->io);
|
||||
if( p == -1 )
|
||||
file_error("file_tell",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
file_eof : 'file -> bool
|
||||
<doc>Tell if we have reached the end of the file</doc>
|
||||
**/
|
||||
bool _hx_std_file_eof( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
return feof(f->io);
|
||||
}
|
||||
|
||||
/**
|
||||
file_flush : 'file -> void
|
||||
<doc>Flush the file buffer</doc>
|
||||
**/
|
||||
void _hx_std_file_flush( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
hx::EnterGCFreeZone();
|
||||
if( fflush( f->io ) != 0 )
|
||||
file_error("file_flush",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
file_contents : f:string -> string
|
||||
<doc>Read the content of the file [f] and return it.</doc>
|
||||
**/
|
||||
String _hx_std_file_contents_string( String name )
|
||||
{
|
||||
std::vector<char> buffer;
|
||||
|
||||
hx::strbuf buf;
|
||||
#ifdef NEKO_WINDOWS
|
||||
hx::EnterGCFreeZone();
|
||||
FILE *file = _wfopen(name.wchar_str(&buf), L"rb");
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
FILE *file = fopen(name.utf8_str(&buf), "rb");
|
||||
#endif
|
||||
if(!file)
|
||||
file_error("file_contents",name);
|
||||
|
||||
fseek(file,0,SEEK_END);
|
||||
int len = ftell(file);
|
||||
if (len<0)
|
||||
file_error("file_ftell",name);
|
||||
if (len==0)
|
||||
{
|
||||
fclose(file);
|
||||
hx::ExitGCFreeZone();
|
||||
return String::emptyString;
|
||||
}
|
||||
|
||||
fseek(file,0,SEEK_SET);
|
||||
buffer.resize(len);
|
||||
int p = 0;
|
||||
while( len > 0 )
|
||||
{
|
||||
POSIX_LABEL(file_contents);
|
||||
int d = (int)fread(&buffer[p],1,len,file);
|
||||
if( d <= 0 )
|
||||
{
|
||||
HANDLE_FINTR(file,file_contents);
|
||||
fclose(file);
|
||||
file_error("file_contents",name);
|
||||
}
|
||||
p += d;
|
||||
len -= d;
|
||||
}
|
||||
fclose(file);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return String::create(&buffer[0], buffer.size());
|
||||
}
|
||||
|
||||
#include <kinc/io/filereader.h>
|
||||
|
||||
|
||||
/**
|
||||
file_contents : f:string -> string
|
||||
<doc>Read the content of the file [f] and return it.</doc>
|
||||
**/
|
||||
Array<unsigned char> _hx_std_file_contents_bytes( String name )
|
||||
{
|
||||
hx::strbuf buf;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
kinc_file_reader_t file;
|
||||
|
||||
if(!kinc_file_reader_open(&file, name.utf8_str(&buf), KINC_FILE_TYPE_ASSET))
|
||||
file_error("file_contents",name);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
Array<unsigned char> buffer = Array_obj<unsigned char>::__new(kinc_file_reader_size(&file),kinc_file_reader_size(&file));
|
||||
hx::EnterGCFreeZone();
|
||||
if (kinc_file_reader_size(&file))
|
||||
{
|
||||
char *dest = (char *)&buffer[0];
|
||||
|
||||
kinc_file_reader_read(&file, dest, kinc_file_reader_size(&file));
|
||||
}
|
||||
kinc_file_reader_close(&file);
|
||||
hx::ExitGCFreeZone();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dynamic _hx_std_file_stdin()
|
||||
{
|
||||
fio *f = new fio();
|
||||
f->create(stdin, HX_CSTRING("stdin"), false);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
Dynamic _hx_std_file_stdout()
|
||||
{
|
||||
fio *f = new fio();
|
||||
f->create(stdout, HX_CSTRING("stdout"), false);
|
||||
return f;
|
||||
}
|
||||
|
||||
Dynamic _hx_std_file_stderr()
|
||||
{
|
||||
fio *f = new fio();
|
||||
f->create(stderr, HX_CSTRING("stderr"), false);
|
||||
return f;
|
||||
}
|
||||
|
621
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Process.cpp
Normal file
621
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Process.cpp
Normal file
@ -0,0 +1,621 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
#if !defined(HX_WINRT) && !defined(EPPC)
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <memory.h>
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# if (defined(ANDROID) || defined(BLACKBERRY) || defined(EMSCRIPTEN) || defined(__FreeBSD__)) && !defined(KORE_CONSOLE)
|
||||
# include <sys/wait.h>
|
||||
# elif !defined(NEKO_MAC) && !defined(KORE_CONSOLE)
|
||||
# include <wait.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
#ifndef NEKO_WINDOWS
|
||||
static int do_close( int fd )
|
||||
{
|
||||
#ifndef KORE_CONSOLE
|
||||
POSIX_LABEL(close_again);
|
||||
if( close(fd) != 0 ) {
|
||||
HANDLE_EINTR(close_again);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
struct vprocess : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdProcess };
|
||||
|
||||
bool open;
|
||||
#ifdef NEKO_WINDOWS
|
||||
HANDLE oread;
|
||||
HANDLE eread;
|
||||
HANDLE iwrite;
|
||||
PROCESS_INFORMATION pinf;
|
||||
#define HANDLE_INIT 0
|
||||
#else
|
||||
int oread;
|
||||
int eread;
|
||||
int iwrite;
|
||||
int pid;
|
||||
#define HANDLE_INIT -1
|
||||
#endif
|
||||
|
||||
void create()
|
||||
{
|
||||
open = true;
|
||||
oread = HANDLE_INIT;
|
||||
eread = HANDLE_INIT;
|
||||
iwrite = HANDLE_INIT;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (open)
|
||||
{
|
||||
#ifdef NEKO_WINDOWS
|
||||
if (eread)
|
||||
CloseHandle(eread);
|
||||
if (oread)
|
||||
CloseHandle(oread);
|
||||
if (iwrite)
|
||||
CloseHandle(iwrite);
|
||||
CloseHandle(pinf.hProcess);
|
||||
CloseHandle(pinf.hThread);
|
||||
#else
|
||||
if (eread!=-1)
|
||||
do_close(eread);
|
||||
if (oread!=-1)
|
||||
do_close(oread);
|
||||
if (iwrite!=-1)
|
||||
do_close(iwrite);
|
||||
#endif
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((vprocess *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("vprocess"); }
|
||||
};
|
||||
|
||||
vprocess *getProcess(Dynamic handle)
|
||||
{
|
||||
vprocess *p = dynamic_cast<vprocess *>(handle.mPtr);
|
||||
if (!p)
|
||||
hx::Throw(HX_CSTRING("Invalid process"));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>Process</h1>
|
||||
<p>
|
||||
An API for starting and communication with sub processes.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
static String TQuoted(const T *ptr, int len)
|
||||
{
|
||||
std::vector<T> quoted;
|
||||
quoted.reserve(len*2);
|
||||
|
||||
unsigned int bs_count = 0;
|
||||
for(int j=0;j<len;j++)
|
||||
{
|
||||
T c = ptr[j];
|
||||
switch( c )
|
||||
{
|
||||
case '"':
|
||||
// Double backslashes.
|
||||
for (int k=0;k<bs_count*2;k++)
|
||||
quoted.push_back('\\');
|
||||
bs_count = 0;
|
||||
quoted.push_back('\\');
|
||||
quoted.push_back('"');
|
||||
break;
|
||||
case '\\':
|
||||
// Don't know if we need to double yet.
|
||||
bs_count++;
|
||||
break;
|
||||
default:
|
||||
// Normal char
|
||||
for (int k=0;k<bs_count;k++)
|
||||
quoted.push_back('\\');
|
||||
bs_count = 0;
|
||||
quoted.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add remaining backslashes, if any.
|
||||
for (int k=0;k<bs_count*2;k++)
|
||||
quoted.push_back('\\');
|
||||
int qlen = (int)quoted.size();
|
||||
quoted.push_back('\0');
|
||||
|
||||
return String::create( "ed[0], qlen );
|
||||
}
|
||||
|
||||
#if defined(NEKO_WINDOWS)
|
||||
static String quoteString(String v)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (v.isUTF16Encoded())
|
||||
return TQuoted(v.raw_wptr(),v.length);
|
||||
#endif
|
||||
return TQuoted(v.raw_ptr(),v.length);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
process_run : cmd:string -> args:string array -> 'process
|
||||
<doc>
|
||||
Start a process using a command.
|
||||
When args is not null, cmd and args will be auto-quoted/escaped.
|
||||
If no auto-quoting/escaping is desired, you should append necessary
|
||||
arguments to cmd as if it is inputted to the shell directly, and pass
|
||||
null to args.
|
||||
|
||||
inShowParam = only for windows, SHOW_* from "ShowWindow" function
|
||||
default = 1 = SHOW_WINDOW
|
||||
</doc>
|
||||
**/
|
||||
Dynamic _hx_std_process_run( String cmd, Array<String> vargs, int inShowParam )
|
||||
{
|
||||
#if defined(APPLETV) || defined(HX_APPLEWATCH) || defined(KORE_CONSOLE)
|
||||
return null();
|
||||
|
||||
#else
|
||||
vprocess *p = 0;
|
||||
bool isRaw = !vargs.mPtr;
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
SECURITY_ATTRIBUTES sattr;
|
||||
STARTUPINFOW sinf;
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
HANDLE oread,eread,iwrite;
|
||||
// creates commandline
|
||||
String b;
|
||||
if (isRaw)
|
||||
{
|
||||
b = HX_CSTRING("\"");
|
||||
const char* cmdexe = getenv("COMSPEC");
|
||||
if (!cmdexe) cmdexe = "cmd.exe";
|
||||
b += String(cmdexe) + HX_CSTRING("\" /C \"") + cmd + HX_CSTRING("\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
b = HX_CSTRING("\"") + cmd + HX_CSTRING("\"");
|
||||
|
||||
for(int i=0;i<vargs->length;i++)
|
||||
{
|
||||
b += HX_CSTRING(" \"");
|
||||
if (vargs[i].length)
|
||||
b += quoteString(vargs[i]);
|
||||
b += HX_CSTRING("\"");
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t *name = b.__WCStr();
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
// startup process
|
||||
sattr.nLength = sizeof(sattr);
|
||||
sattr.bInheritHandle = TRUE;
|
||||
sattr.lpSecurityDescriptor = NULL;
|
||||
memset(&sinf,0,sizeof(sinf));
|
||||
sinf.cb = sizeof(sinf);
|
||||
sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
sinf.wShowWindow = inShowParam;
|
||||
CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
|
||||
CreatePipe(&eread,&sinf.hStdError,&sattr,0);
|
||||
CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
|
||||
|
||||
HANDLE procOread,procEread,procIwrite;
|
||||
|
||||
DuplicateHandle(proc,oread,proc,&procOread,0,FALSE,DUPLICATE_SAME_ACCESS);
|
||||
DuplicateHandle(proc,eread,proc,&procEread,0,FALSE,DUPLICATE_SAME_ACCESS);
|
||||
DuplicateHandle(proc,iwrite,proc,&procIwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
|
||||
CloseHandle(oread);
|
||||
CloseHandle(eread);
|
||||
CloseHandle(iwrite);
|
||||
//printf("Cmd %s\n",val_string(cmd));
|
||||
PROCESS_INFORMATION pinf;
|
||||
memset(&pinf,0,sizeof(pinf));
|
||||
if( !CreateProcessW(NULL,(wchar_t *)name,NULL,NULL,TRUE,CREATE_NO_WINDOW,NULL,NULL,&sinf,&pinf) )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
hx::Throw(HX_CSTRING("Could not start process"));
|
||||
}
|
||||
// close unused pipes
|
||||
CloseHandle(sinf.hStdOutput);
|
||||
CloseHandle(sinf.hStdError);
|
||||
CloseHandle(sinf.hStdInput);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
p = new vprocess;
|
||||
p->create();
|
||||
p->oread = procOread;
|
||||
p->eread = procEread;
|
||||
p->iwrite = procIwrite;
|
||||
p->pinf = pinf;
|
||||
}
|
||||
#else // not windows ...
|
||||
{
|
||||
int input[2], output[2], error[2];
|
||||
if( pipe(input) || pipe(output) || pipe(error) )
|
||||
return null();
|
||||
|
||||
hx::strbuf buf;
|
||||
std::vector< std::string > values;
|
||||
if (isRaw)
|
||||
{
|
||||
values.resize(3);
|
||||
values[0] = "/bin/sh";
|
||||
values[1] = "-c";
|
||||
values[2] = cmd.utf8_str(&buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
values.resize(vargs->length+1);
|
||||
|
||||
values[0] = cmd.utf8_str(&buf);
|
||||
for(int i=0;i<vargs->length;i++)
|
||||
values[i+1] = vargs[i].utf8_str(&buf);
|
||||
}
|
||||
|
||||
std::vector<const char *> argv(values.size()+1);
|
||||
for(int i=0;i<values.size();i++)
|
||||
argv[i] = values[i].c_str();
|
||||
|
||||
int pid = fork();
|
||||
if( pid == -1 )
|
||||
return null();
|
||||
|
||||
// child
|
||||
if( pid == 0 )
|
||||
{
|
||||
close(input[1]);
|
||||
close(output[0]);
|
||||
close(error[0]);
|
||||
dup2(input[0],0);
|
||||
dup2(output[1],1);
|
||||
dup2(error[1],2);
|
||||
execvp(argv[0],(char* const*)&argv[0]);
|
||||
fprintf(stderr,"Command not found : %S\n",cmd.wchar_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// parent
|
||||
do_close(input[0]);
|
||||
do_close(output[1]);
|
||||
do_close(error[1]);
|
||||
|
||||
p = new vprocess;
|
||||
p->create();
|
||||
p->iwrite = input[1];
|
||||
p->oread = output[0];
|
||||
p->eread = error[0];
|
||||
p->pid = pid;
|
||||
}
|
||||
#endif
|
||||
|
||||
return p;
|
||||
|
||||
#endif // not APPLETV/HX_APPLEWATCH
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
process_stdout_read : 'process -> buf:string -> pos:int -> len:int -> int
|
||||
<doc>
|
||||
Read up to [len] bytes in [buf] starting at [pos] from the process stdout.
|
||||
Returns the number of bytes readed this way. Raise an exception if this
|
||||
process stdout is closed and no more data is available for reading.
|
||||
|
||||
For hxcpp, the input buffer is in bytes, not characters
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_stdout_read( Dynamic handle, Array<unsigned char> buf, int pos, int len )
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos + len > buf->length )
|
||||
return 0;
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
unsigned char *dest = &buf[0];
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
DWORD nbytes = 0;
|
||||
if( !ReadFile(p->oread,dest+pos,len,&nbytes,0) )
|
||||
nbytes = 0;
|
||||
#elif !defined(KORE_CONSOLE)
|
||||
int nbytes = read(p->oread,dest + pos,len);
|
||||
if( nbytes <= 0 )
|
||||
nbytes = 0;
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#ifdef KORE_CONSOLE
|
||||
return 0;
|
||||
#else
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
process_stderr_read : 'process -> buf:string -> pos:int -> len:int -> int
|
||||
<doc>
|
||||
Read up to [len] bytes in [buf] starting at [pos] from the process stderr.
|
||||
Returns the number of bytes readed this way. Raise an exception if this
|
||||
process stderr is closed and no more data is available for reading.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_stderr_read( Dynamic handle, Array<unsigned char> buf, int pos, int len )
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos + len > buf->length )
|
||||
return 0;
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
unsigned char *dest = &buf[0];
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
DWORD nbytes = 0;
|
||||
if( !ReadFile(p->eread,dest+pos,len,&nbytes,0) )
|
||||
nbytes = 0;
|
||||
#elif !defined(KORE_CONSOLE)
|
||||
int nbytes = read(p->eread,dest + pos,len);
|
||||
if( nbytes <= 0 )
|
||||
nbytes = 0;
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#ifdef KORE_CONSOLE
|
||||
return 0;
|
||||
#else
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
process_stdin_write : 'process -> buf:string -> pos:int -> len:int -> int
|
||||
<doc>
|
||||
Write up to [len] bytes from [buf] starting at [pos] to the process stdin.
|
||||
Returns the number of bytes writen this way. Raise an exception if this
|
||||
process stdin is closed.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_stdin_write( Dynamic handle, Array<unsigned char> buf, int pos, int len )
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos + len > buf->length )
|
||||
return 0;
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
unsigned char *src = &buf[0];
|
||||
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
DWORD nbytes =0;
|
||||
if( !WriteFile(p->iwrite,src+pos,len,&nbytes,0) )
|
||||
nbytes = 0;
|
||||
#elif !defined(KORE_CONSOLE)
|
||||
int nbytes = write(p->iwrite,src+pos,len);
|
||||
if( nbytes == -1 )
|
||||
nbytes = 0;
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#ifdef KORE_CONSOLE
|
||||
return 0;
|
||||
#else
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
process_stdin_close : 'process -> void
|
||||
<doc>
|
||||
Close the process standard input.
|
||||
</doc>
|
||||
**/
|
||||
void _hx_std_process_stdin_close( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
if ( p->iwrite )
|
||||
CloseHandle(p->iwrite);
|
||||
#else
|
||||
if( p->iwrite!=-1 )
|
||||
do_close(p->iwrite);
|
||||
#endif
|
||||
p->iwrite = HANDLE_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
process_exit : 'process -> int
|
||||
<doc>
|
||||
Wait until the process terminate, then returns its exit code.
|
||||
</doc>
|
||||
**/
|
||||
#if (HXCPP_API_LEVEL > 420)
|
||||
Dynamic _hx_std_process_exit( Dynamic handle, bool block )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
DWORD rval;
|
||||
DWORD wait = INFINITE;
|
||||
if (!block)
|
||||
wait = 0;
|
||||
|
||||
WaitForSingleObject(p->pinf.hProcess,wait);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) && block)
|
||||
return 0;
|
||||
else if (!block && rval == STILL_ACTIVE)
|
||||
return null();
|
||||
else
|
||||
return rval;
|
||||
}
|
||||
#else
|
||||
int options=0;
|
||||
if (!block)
|
||||
options = WNOHANG;
|
||||
|
||||
int rval=0;
|
||||
pid_t ret=-1;
|
||||
while( (ret = waitpid(p->pid,&rval,options)) != p->pid )
|
||||
{
|
||||
if( errno == EINTR )
|
||||
continue;
|
||||
|
||||
if (!block && ret == 0)
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return null();
|
||||
}
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
return 0;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
if( !WIFEXITED(rval) )
|
||||
return 0;
|
||||
|
||||
return WEXITSTATUS(rval);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
int _hx_std_process_exit( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
DWORD rval;
|
||||
WaitForSingleObject(p->pinf.hProcess,INFINITE);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
|
||||
return 0;
|
||||
return rval;
|
||||
}
|
||||
#elif !defined(KORE_CONSOLE)
|
||||
int rval=0;
|
||||
while( waitpid(p->pid,&rval,0) != p->pid )
|
||||
{
|
||||
if( errno == EINTR )
|
||||
continue;
|
||||
hx::ExitGCFreeZone();
|
||||
return 0;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
if( !WIFEXITED(rval) )
|
||||
return 0;
|
||||
|
||||
return WEXITSTATUS(rval);
|
||||
#else
|
||||
hx::ExitGCFreeZone();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
process_pid : 'process -> int
|
||||
<doc>
|
||||
Returns the process id.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_pid( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
return p->pinf.dwProcessId;
|
||||
#else
|
||||
return p->pid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _hx_std_process_kill( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
TerminateProcess(p->pinf.hProcess, -1);
|
||||
#else
|
||||
kill(p->pid, SIGTERM);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
process_close : 'process -> void
|
||||
<doc>
|
||||
Close the process I/O.
|
||||
</doc>
|
||||
**/
|
||||
void _hx_std_process_close( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
p->destroy();
|
||||
}
|
||||
|
||||
#else // !HX_WINRT
|
||||
|
||||
Dynamic _hx_std_process_run( String cmd, Array<String> vargs, int inShowParam ){ return null(); }
|
||||
int _hx_std_process_stdout_read( Dynamic handle, Array<unsigned char> buf, int pos, int len ) { return 0; }
|
||||
int _hx_std_process_stderr_read( Dynamic handle, Array<unsigned char> buf, int pos, int len ) { return 0; }
|
||||
int _hx_std_process_stdin_write( Dynamic handle, Array<unsigned char> buf, int pos, int len ) { return 0; }
|
||||
void _hx_std_process_stdin_close( Dynamic handle ) { }
|
||||
#if (HXCPP_API_LEVEL > 420)
|
||||
Dynamic _hx_std_process_exit( Dynamic handle, bool block ) { return 0; }
|
||||
#else
|
||||
int _hx_std_process_exit( Dynamic handle ) { return 0; }
|
||||
#endif
|
||||
int _hx_std_process_pid( Dynamic handle ) { return 0; }
|
||||
void _hx_std_process_close( Dynamic handle ) { }
|
||||
void _hx_std_process_kill( Dynamic handle ) { }
|
||||
|
||||
#endif // HX_WINRT
|
||||
|
181
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Random.cpp
Normal file
181
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Random.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#ifdef HX_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <process.h>
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
# include <time.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>Random</h1>
|
||||
<p>A seeded pseudo-random generator</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
|
||||
|
||||
#define NSEEDS 25
|
||||
#ifdef MAX
|
||||
#undef MAX
|
||||
#endif
|
||||
#define MAX 7
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct rnd : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdRandom };
|
||||
|
||||
unsigned long seeds[NSEEDS];
|
||||
unsigned long cur;
|
||||
|
||||
String toString() { return HX_CSTRING("rand"); }
|
||||
};
|
||||
|
||||
static unsigned long mag01[2]={
|
||||
0x0, 0x8ebfd028 // magic, don't change
|
||||
};
|
||||
|
||||
static const unsigned long init_seeds[] = {
|
||||
0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23,
|
||||
0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825,
|
||||
0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f,
|
||||
0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9,
|
||||
0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void rnd_set_seed( rnd *r, int s )
|
||||
{
|
||||
int i;
|
||||
r->cur = 0;
|
||||
memcpy(r->seeds,init_seeds,sizeof(init_seeds));
|
||||
for(i=0;i<NSEEDS;i++)
|
||||
r->seeds[i] ^= s;
|
||||
}
|
||||
|
||||
rnd *getRnd(Dynamic handle)
|
||||
{
|
||||
rnd *r = dynamic_cast<rnd *>(handle.mPtr);
|
||||
if (!r)
|
||||
hx::Throw(HX_CSTRING("Invalid random handle"));
|
||||
return r;
|
||||
}
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
Dynamic _hx_std_random_new()
|
||||
{
|
||||
rnd *r = new rnd();
|
||||
|
||||
#if defined(NEKO_WINDOWS) && !defined(KORE_CONSOLE)
|
||||
#if defined(HX_WINRT) && defined(__cplusplus_winrt)
|
||||
int pid = Windows::Security::Cryptography::CryptographicBuffer::GenerateRandomNumber();
|
||||
#else
|
||||
int pid = GetCurrentProcessId();
|
||||
#endif
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
int pid = 1;
|
||||
#else
|
||||
int pid = getpid();
|
||||
#endif
|
||||
|
||||
unsigned int t;
|
||||
#ifdef HX_WINRT
|
||||
t = (unsigned int)GetTickCount64();
|
||||
#elif defined(NEKO_WINDOWS) && !defined(KORE_CONSOLE)
|
||||
t = GetTickCount();
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
time_t tod;
|
||||
time(&tod);
|
||||
t = (double)tod;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
t = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
#endif
|
||||
|
||||
|
||||
rnd_set_seed(r,t ^ (pid | (pid << 16)));
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned int rnd_int( rnd *r )
|
||||
{
|
||||
unsigned int y;
|
||||
int pos = r->cur++;
|
||||
if( pos >= NSEEDS ) {
|
||||
int kk;
|
||||
for(kk=0;kk<NSEEDS-MAX;kk++)
|
||||
r->seeds[kk] = r->seeds[kk+MAX] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
|
||||
for(;kk<NSEEDS;kk++)
|
||||
r->seeds[kk] = r->seeds[kk+(MAX-NSEEDS)] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
|
||||
r->cur = 1;
|
||||
pos = 0;
|
||||
}
|
||||
y = r->seeds[pos];
|
||||
y ^= (y << 7) & 0x2b5b2500;
|
||||
y ^= (y << 15) & 0xdb8b0000;
|
||||
y ^= (y >> 16);
|
||||
return y;
|
||||
}
|
||||
|
||||
static double rnd_float( rnd *r )
|
||||
{
|
||||
double big = 4294967296.0;
|
||||
return ((rnd_int(r) / big + rnd_int(r)) / big + rnd_int(r)) / big;
|
||||
}
|
||||
|
||||
/**
|
||||
random_new : void -> 'random
|
||||
<doc>Create a new random with random seed</doc>
|
||||
**/
|
||||
|
||||
|
||||
#include<stdlib.h>
|
||||
|
||||
|
||||
/**
|
||||
random_set_seed : 'random -> int -> void
|
||||
<doc>Set the generator seed</doc>
|
||||
**/
|
||||
void _hx_std_random_set_seed( Dynamic handle, int v )
|
||||
{
|
||||
rnd_set_seed( getRnd(handle) ,v);
|
||||
}
|
||||
|
||||
/**
|
||||
random_int : 'random -> max:int -> int
|
||||
<doc>Return a random integer modulo [max]</doc>
|
||||
**/
|
||||
int _hx_std_random_int( Dynamic handle, int max )
|
||||
{
|
||||
if( max <= 0 )
|
||||
return 0;
|
||||
return (rnd_int( getRnd(handle)) & 0x3FFFFFFF) % max;
|
||||
}
|
||||
|
||||
/**
|
||||
random_float : 'random -> float
|
||||
<doc>Return a random float</doc>
|
||||
**/
|
||||
double _hx_std_random_float( Dynamic handle )
|
||||
{
|
||||
return rnd_float(getRnd(handle));
|
||||
}
|
||||
|
||||
|
1374
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Socket.cpp
Normal file
1374
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Socket.cpp
Normal file
File diff suppressed because it is too large
Load Diff
915
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Sys.cpp
Normal file
915
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/std/Sys.cpp
Normal file
@ -0,0 +1,915 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef EPPC
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifndef __clang__
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <conio.h>
|
||||
#include <locale.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#if !defined(EPPC) && !defined(KORE_CONSOLE)
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <termios.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#ifndef ANDROID
|
||||
#include <locale.h>
|
||||
#if !defined(BLACKBERRY) && !defined(EPPC) && !defined(GCW0) && !defined(__GLIBC__) && !defined(KORE_CONSOLE)
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
#ifdef NEKO_MAC
|
||||
#include <sys/syslimits.h>
|
||||
#include <limits.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifndef CLK_TCK
|
||||
#define CLK_TCK 100
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>System</h1>
|
||||
<p>
|
||||
Interactions with the operating system.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
/**
|
||||
get_env : string -> string?
|
||||
<doc>Get some environment variable if exists</doc>
|
||||
**/
|
||||
|
||||
String _hx_std_get_env( String v )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(KORE_CONSOLE)
|
||||
return String();
|
||||
#else
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
hx::strbuf wbuf;
|
||||
return String::create( _wgetenv( v.wchar_str(&wbuf) ) );
|
||||
#else
|
||||
hx::strbuf buf;
|
||||
return String::create( getenv(v.utf8_str(&buf)) );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
put_env : var:string -> val:string -> void
|
||||
<doc>Set some environment variable value</doc>
|
||||
**/
|
||||
void _hx_std_put_env( String e, String v )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(KORE_CONSOLE)
|
||||
// Do nothing
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
String set = e + HX_CSTRING("=") + (v != null()?v:"");
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (set.isUTF16Encoded())
|
||||
_wputenv(set.wchar_str());
|
||||
else
|
||||
#endif
|
||||
putenv(set.utf8_str());
|
||||
#else
|
||||
if (v == null())
|
||||
unsetenv(e.utf8_str());
|
||||
else
|
||||
setenv(e.utf8_str(),v.utf8_str(),1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_sleep : number -> void
|
||||
<doc>Sleep a given number of seconds</doc>
|
||||
**/
|
||||
|
||||
void _hx_std_sys_sleep( double f )
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
#if defined(NEKO_WINDOWS)
|
||||
Sleep((DWORD)(f * 1000));
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
//TODO: Implement sys_sleep for EPPC
|
||||
#else
|
||||
{
|
||||
struct timespec t;
|
||||
struct timespec tmp;
|
||||
t.tv_sec = (int)(f);
|
||||
t.tv_nsec = (int)(((f) - t.tv_sec) * 1e9);
|
||||
while( nanosleep(&t,&tmp) == -1 )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return;
|
||||
}
|
||||
t = tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
set_time_locale : string -> bool
|
||||
<doc>Set the locale for LC_TIME, returns true on success</doc>
|
||||
**/
|
||||
bool _hx_std_set_time_locale( String l )
|
||||
{
|
||||
#if defined(ANDROID) || defined(GCW0) || defined(KORE_CONSOLE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
#if defined(NEKO_POSIX)
|
||||
locale_t lc, old;
|
||||
lc = newlocale(LC_TIME_MASK,l.utf8_str(),NULL);
|
||||
if( !lc )
|
||||
return false;
|
||||
old = uselocale(lc);
|
||||
if( !old )
|
||||
{
|
||||
freelocale(lc);
|
||||
return false;
|
||||
}
|
||||
if( old != LC_GLOBAL_LOCALE )
|
||||
freelocale(old);
|
||||
return true;
|
||||
#else
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
if (l.isUTF16Encoded())
|
||||
return _wsetlocale(LC_TIME,l.wchar_str());
|
||||
#endif
|
||||
return setlocale(LC_TIME,l.utf8_str());
|
||||
#endif
|
||||
|
||||
#endif // !Android
|
||||
}
|
||||
|
||||
/**
|
||||
get_cwd : void -> string
|
||||
<doc>Return current working directory</doc>
|
||||
**/
|
||||
String _hx_std_get_cwd()
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(KORE_CONSOLE)
|
||||
return HX_CSTRING("ms-appdata:///local/");
|
||||
#elif defined(EPPC)
|
||||
return String();
|
||||
#else
|
||||
#ifdef NEKO_WINDOWS
|
||||
wchar_t buf[261];
|
||||
int l;
|
||||
if( !GetCurrentDirectoryW(260,buf) )
|
||||
return String();
|
||||
l = (int)wcslen(buf);
|
||||
if( buf[l-1] != '/' && buf[l-1] != '\\' ) {
|
||||
buf[l] = '/';
|
||||
buf[l+1] = 0;
|
||||
}
|
||||
#else
|
||||
char buf[1025];
|
||||
int l;
|
||||
if( getcwd(buf,1024) == NULL )
|
||||
return String();
|
||||
l = (int)strlen(buf);
|
||||
if( buf[l-1] != '/' && buf[l-1] != '\\' ) {
|
||||
buf[l] = '/';
|
||||
buf[l+1] = 0;
|
||||
}
|
||||
#endif
|
||||
return String::create(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
set_cwd : string -> void
|
||||
<doc>Set current working directory</doc>
|
||||
**/
|
||||
bool _hx_std_set_cwd( String d )
|
||||
{
|
||||
#if !defined(HX_WINRT) && !defined(EPPC) && !defined(KORE_CONSOLE)
|
||||
#ifdef NEKO_WINDOWS
|
||||
return SetCurrentDirectoryW(d.wchar_str()) == 0;
|
||||
#else
|
||||
return chdir(d.utf8_str()) == 0;
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
sys_string : void -> string
|
||||
<doc>
|
||||
Return the local system string. The current value are possible :
|
||||
<ul>
|
||||
<li>[Windows]</li>
|
||||
<li>[Linux]</li>
|
||||
<li>[BSD]</li>
|
||||
<li>[Mac]</li>
|
||||
</ul>
|
||||
</doc>
|
||||
**/
|
||||
String _hx_std_sys_string()
|
||||
{
|
||||
#if defined(KORE_CONSOLE)
|
||||
return HX_CSTRING("Kore Console");
|
||||
#elif defined(HX_WINRT)
|
||||
return HX_CSTRING("WinRT");
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
return HX_CSTRING("Windows");
|
||||
#elif defined(NEKO_GNUKBSD)
|
||||
return HX_CSTRING("GNU/kFreeBSD");
|
||||
#elif defined(NEKO_LINUX)
|
||||
return HX_CSTRING("Linux");
|
||||
#elif defined(NEKO_BSD)
|
||||
return HX_CSTRING("BSD");
|
||||
#elif defined(NEKO_MAC)
|
||||
return HX_CSTRING("Mac");
|
||||
#elif defined(ANDROID)
|
||||
return HX_CSTRING("Android");
|
||||
#elif defined(BLACKBERRY)
|
||||
return HX_CSTRING("BlackBerry");
|
||||
#elif defined(EMSCRIPTEN)
|
||||
return HX_CSTRING("Emscripten");
|
||||
#elif defined(EPPC)
|
||||
return HX_CSTRING("EPPC");
|
||||
#else
|
||||
#error Unknow system string
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_is64 : void -> bool
|
||||
<doc>
|
||||
Returns true if we are on a 64-bit system
|
||||
</doc>
|
||||
**/
|
||||
bool _hx_std_sys_is64()
|
||||
{
|
||||
#ifdef NEKO_64BITS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_command : string -> int
|
||||
<doc>Run the shell command and return exit code</doc>
|
||||
**/
|
||||
int _hx_std_sys_command( String cmd )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(EMSCRIPTEN) || defined(EPPC) || defined(IPHONE) || defined(APPLETV) || defined(HX_APPLEWATCH) || defined(KORE_CONSOLE)
|
||||
return -1;
|
||||
#else
|
||||
if( !cmd.raw_ptr() || !cmd.length )
|
||||
return -1;
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
int result = 0;
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (!cmd.isUTF16Encoded())
|
||||
result = system(cmd.raw_ptr());
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf wbuf;
|
||||
result = _wsystem(cmd.wchar_str(&wbuf));
|
||||
}
|
||||
#else
|
||||
hx::strbuf buf;
|
||||
hx::EnterGCFreeZone();
|
||||
int result = system(cmd.utf8_str(&buf));
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
#if !defined(NEKO_WINDOWS) && !defined(__FreeBSD__)
|
||||
result = WEXITSTATUS(result) | (WTERMSIG(result) << 8);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
sys_exit : int -> void
|
||||
<doc>Exit with the given errorcode. Never returns.</doc>
|
||||
**/
|
||||
void _hx_std_sys_exit( int code )
|
||||
{
|
||||
exit(code);
|
||||
}
|
||||
|
||||
/**
|
||||
sys_exists : string -> bool
|
||||
<doc>Returns true if the file or directory exists.</doc>
|
||||
**/
|
||||
bool _hx_std_sys_exists( String path )
|
||||
{
|
||||
#if defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return true;
|
||||
#else
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
const wchar_t * wpath = path.wchar_str();
|
||||
hx::EnterGCFreeZone();
|
||||
bool result = GetFileAttributesW(wpath) != INVALID_FILE_ATTRIBUTES;
|
||||
#else
|
||||
struct stat st;
|
||||
hx::EnterGCFreeZone();
|
||||
hx::strbuf buf;
|
||||
bool result = stat(path.utf8_str(&buf),&st) == 0;
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
file_delete : string -> void
|
||||
<doc>Delete the file. Exception on error.</doc>
|
||||
**/
|
||||
void _hx_std_file_delete( String path )
|
||||
{
|
||||
#if !defined(EPPC) && !defined(KORE_CONSOLE)
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
bool err = false;
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
err = _wunlink(path.wchar_str());
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = unlink(path.utf8_str(&buf));
|
||||
}
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
if (err)
|
||||
hx::Throw( HX_CSTRING("Could not delete ") + path );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_rename : from:string -> to:string -> void
|
||||
<doc>Rename the file or directory. Exception on error.</doc>
|
||||
**/
|
||||
void _hx_std_sys_rename( String path, String newname )
|
||||
{
|
||||
#ifdef KORE_CONSOLE
|
||||
bool err = true;
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
hx::strbuf buf0;
|
||||
hx::strbuf buf1;
|
||||
#ifdef NEKO_WINDOWS
|
||||
bool err = _wrename(path.wchar_str(&buf0),newname.wchar_str(&buf1));
|
||||
#else
|
||||
bool err = rename(path.utf8_str(&buf0),newname.utf8_str(&buf1));
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#endif
|
||||
if (err)
|
||||
hx::Throw(HX_CSTRING("Could not rename"));
|
||||
}
|
||||
|
||||
#define STATF(f) o->Add(HX_CSTRING(#f),(int)(s.st_##f))
|
||||
|
||||
/**
|
||||
sys_stat : string -> {
|
||||
gid => int,
|
||||
uid => int,
|
||||
atime => 'int,
|
||||
mtime => 'int,
|
||||
ctime => 'int,
|
||||
dev => int,
|
||||
ino => int,
|
||||
nlink => int,
|
||||
rdev => int,
|
||||
mode => int,
|
||||
size => int
|
||||
}
|
||||
<doc>Run the [stat] command on the given file or directory.</doc>
|
||||
**/
|
||||
Dynamic _hx_std_sys_stat( String path )
|
||||
{
|
||||
#if defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return null();
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
bool err = false;
|
||||
#if defined(NEKO_WINDOWS)
|
||||
struct _stat s;
|
||||
#if defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _wstat(path.wchar_str(&buf),&s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _stat(path.utf8_str(&buf),&s);
|
||||
}
|
||||
#else
|
||||
struct stat s;
|
||||
hx::strbuf buf;
|
||||
err = stat(path.utf8_str(&buf),&s);
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
if (err)
|
||||
return null();
|
||||
hx::Anon o = hx::Anon_obj::Create();
|
||||
|
||||
STATF(gid);
|
||||
STATF(uid);
|
||||
STATF(atime);
|
||||
STATF(mtime);
|
||||
STATF(ctime);
|
||||
STATF(dev);
|
||||
STATF(ino);
|
||||
STATF(mode);
|
||||
STATF(nlink);
|
||||
STATF(rdev);
|
||||
STATF(size);
|
||||
STATF(mode);
|
||||
|
||||
return o;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_file_type : string -> string
|
||||
<doc>
|
||||
Return the type of the file. The current values are possible :
|
||||
<ul>
|
||||
<li>[file]</li>
|
||||
<li>[dir]</li>
|
||||
<li>[symlink]</li>
|
||||
<li>[sock]</li>
|
||||
<li>[char]</li>
|
||||
<li>[block]</li>
|
||||
<li>[fifo]</li>
|
||||
</ul>
|
||||
</doc>
|
||||
**/
|
||||
String _hx_std_sys_file_type( String path )
|
||||
{
|
||||
if (path==null())
|
||||
return String();
|
||||
#if defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return String();
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
bool err = false;
|
||||
#if defined(NEKO_WINDOWS)
|
||||
struct _stat s;
|
||||
#if defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _wstat(path.wchar_str(&buf),&s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _stat(path.utf8_str(&buf),&s);
|
||||
}
|
||||
#else
|
||||
struct stat s;
|
||||
hx::strbuf buf;
|
||||
err = stat(path.utf8_str(&buf),&s);
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
if (err)
|
||||
return String();
|
||||
|
||||
if( s.st_mode & S_IFREG )
|
||||
return HX_CSTRING("file");
|
||||
if( s.st_mode & S_IFDIR )
|
||||
return HX_CSTRING("dir");
|
||||
if( s.st_mode & S_IFCHR )
|
||||
return HX_CSTRING("char");
|
||||
#ifndef NEKO_WINDOWS
|
||||
if( s.st_mode & S_IFLNK )
|
||||
return HX_CSTRING("symlink");
|
||||
if( s.st_mode & S_IFBLK )
|
||||
return HX_CSTRING("block");
|
||||
if( s.st_mode & S_IFIFO )
|
||||
return HX_CSTRING("fifo");
|
||||
if( s.st_mode & S_IFSOCK )
|
||||
return HX_CSTRING("sock");
|
||||
#endif
|
||||
return String();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_create_dir : string -> mode:int -> void
|
||||
<doc>Create a directory with the specified rights</doc>
|
||||
**/
|
||||
bool _hx_std_sys_create_dir( String path, int mode )
|
||||
{
|
||||
#if defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return true;
|
||||
#else
|
||||
#ifdef NEKO_WINDOWS
|
||||
const wchar_t * wpath = path.wchar_str();
|
||||
hx::EnterGCFreeZone();
|
||||
bool err = _wmkdir(wpath);
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
hx::strbuf buf;
|
||||
bool err = mkdir(path.utf8_str(&buf), mode);
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
return !err;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_remove_dir : string -> void
|
||||
<doc>Remove a directory. Exception on error</doc>
|
||||
**/
|
||||
void _hx_std_sys_remove_dir( String path )
|
||||
{
|
||||
#if defined(EPPC) || defined(KORE_CONSOLE)
|
||||
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
bool ok = false;
|
||||
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
{
|
||||
ok = _wrmdir(path.wchar_str()) == 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
ok = rmdir(path.utf8_str(&buf)) == 0;
|
||||
}
|
||||
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
if (!ok)
|
||||
hx::Throw(HX_CSTRING("Could not remove directory"));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_time : void -> float
|
||||
<doc>Return an accurate local time stamp in seconds since Jan 1 1970</doc>
|
||||
**/
|
||||
double _hx_std_sys_time()
|
||||
{
|
||||
#ifdef NEKO_WINDOWS
|
||||
#define EPOCH_DIFF (134774*24*60*60.0)
|
||||
SYSTEMTIME t;
|
||||
FILETIME ft;
|
||||
ULARGE_INTEGER ui;
|
||||
GetSystemTime(&t);
|
||||
if( !SystemTimeToFileTime(&t,&ft) )
|
||||
return 0;
|
||||
ui.LowPart = ft.dwLowDateTime;
|
||||
ui.HighPart = ft.dwHighDateTime;
|
||||
return ( ((double)ui.QuadPart) / 10000000.0 - EPOCH_DIFF );
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
time_t tod;
|
||||
time(&tod);
|
||||
return ((double)tod);
|
||||
#else
|
||||
struct timeval tv;
|
||||
if( gettimeofday(&tv,NULL) != 0 )
|
||||
return 0;
|
||||
return ( tv.tv_sec + ((double)tv.tv_usec) / 1000000.0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_cpu_time : void -> float
|
||||
<doc>Return the most accurate CPU time spent since the process started (in seconds)</doc>
|
||||
**/
|
||||
double _hx_std_sys_cpu_time()
|
||||
{
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
return ((double)GetTickCount64()/1000.0);
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
FILETIME unused;
|
||||
FILETIME stime;
|
||||
FILETIME utime;
|
||||
if( !GetProcessTimes(GetCurrentProcess(),&unused,&unused,&stime,&utime) )
|
||||
return 0;
|
||||
return ( ((double)(utime.dwHighDateTime+stime.dwHighDateTime)) * 65.536 * 6.5536 + (((double)utime.dwLowDateTime + (double)stime.dwLowDateTime) / 10000000) );
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return ((double)clock()/(double)CLOCKS_PER_SEC);
|
||||
#else
|
||||
struct tms t;
|
||||
times(&t);
|
||||
return ( ((double)(t.tms_utime + t.tms_stime)) / CLK_TCK );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_read_dir : string -> string list
|
||||
<doc>Return the content of a directory</doc>
|
||||
**/
|
||||
Array<String> _hx_std_sys_read_dir( String p )
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
|
||||
#if defined(NEKO_WINDOWS)
|
||||
const wchar_t *path = p.wchar_str();
|
||||
size_t len = wcslen(path);
|
||||
if (len>MAX_PATH)
|
||||
return null();
|
||||
|
||||
WIN32_FIND_DATAW d;
|
||||
HANDLE handle;
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
std::wstring tempWStr(path);
|
||||
std::string searchPath(tempWStr.begin(), tempWStr.end());
|
||||
#else
|
||||
wchar_t searchPath[ MAX_PATH + 4 ];
|
||||
memcpy(searchPath,path, len*sizeof(wchar_t));
|
||||
#endif
|
||||
|
||||
|
||||
if( len && path[len-1] != '/' && path[len-1] != '\\' )
|
||||
searchPath[len++] = '/';
|
||||
searchPath[len++] = '*';
|
||||
searchPath[len++] = '.';
|
||||
searchPath[len++] = '*';
|
||||
searchPath[len] = '\0';
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
handle = FindFirstFileExA(searchPath.c_str(), FindExInfoStandard, &d, FindExSearchNameMatch, NULL, 0);
|
||||
#else
|
||||
handle = FindFirstFileW(searchPath,&d);
|
||||
#endif
|
||||
if( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return null();
|
||||
}
|
||||
while( true )
|
||||
{
|
||||
// skip magic dirs
|
||||
if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
result->push(String::create(d.cFileName));
|
||||
hx::EnterGCFreeZone();
|
||||
}
|
||||
if( !FindNextFileW(handle,&d) )
|
||||
break;
|
||||
}
|
||||
FindClose(handle);
|
||||
#elif !defined(EPPC) && !defined(KORE_CONSOLE)
|
||||
const char *name = p.utf8_str();
|
||||
hx::EnterGCFreeZone();
|
||||
DIR *d = opendir(name);
|
||||
if( d == NULL )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
hx::Throw(HX_CSTRING("Invalid directory"));
|
||||
}
|
||||
while( true )
|
||||
{
|
||||
struct dirent *e = readdir(d);
|
||||
if( e == NULL )
|
||||
break;
|
||||
// skip magic dirs
|
||||
if( e->d_name[0] == '.' && (e->d_name[1] == 0 || (e->d_name[1] == '.' && e->d_name[2] == 0)) )
|
||||
continue;
|
||||
hx::ExitGCFreeZone();
|
||||
result->push( String::create(e->d_name) );
|
||||
hx::EnterGCFreeZone();
|
||||
}
|
||||
closedir(d);
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
file_full_path : string -> string
|
||||
<doc>Return an absolute path from a relative one. The file or directory must exists</doc>
|
||||
**/
|
||||
String _hx_std_file_full_path( String path )
|
||||
{
|
||||
#if defined(HX_WINRT)
|
||||
return path;
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
wchar_t buf[MAX_PATH+1];
|
||||
hx::strbuf wbuf;
|
||||
if( GetFullPathNameW(path.wchar_str(&wbuf),MAX_PATH+1,buf,NULL) == 0 )
|
||||
return null();
|
||||
return String::create(buf);
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return path;
|
||||
#else
|
||||
char buf[PATH_MAX];
|
||||
hx::strbuf ubuf;
|
||||
if( realpath(path.utf8_str(&ubuf),buf) == NULL )
|
||||
return null();
|
||||
return String::create(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_exe_path : void -> string
|
||||
<doc>Return the path of the executable</doc>
|
||||
**/
|
||||
String _hx_std_sys_exe_path()
|
||||
{
|
||||
#if defined(HX_WINRT) && defined(__cplusplus_winrt)
|
||||
Windows::ApplicationModel::Package^ package = Windows::ApplicationModel::Package::Current;
|
||||
Windows::Storage::StorageFolder^ installedLocation = package->InstalledLocation;
|
||||
return(String::create(installedLocation->Path->Data()));
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
wchar_t path[MAX_PATH];
|
||||
if( GetModuleFileNameW(NULL,path,MAX_PATH) == 0 )
|
||||
return null();
|
||||
return String::create(path);
|
||||
#elif defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
char path[PATH_MAX+1];
|
||||
uint32_t path_len = PATH_MAX;
|
||||
if( _NSGetExecutablePath(path, &path_len) )
|
||||
return null();
|
||||
return String::create(path);
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return HX_CSTRING("");
|
||||
#else
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int length = readlink("/proc/self/exe", path, sizeof(path));
|
||||
if( length < 0 )
|
||||
{
|
||||
const char *p = getenv("_");
|
||||
if (p)
|
||||
return String::create(p);
|
||||
return null();
|
||||
}
|
||||
path[length] = '\0';
|
||||
return String::create(path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
#ifdef NEKO_MAC
|
||||
#include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NEKO_WINDOWS
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
/**
|
||||
sys_env : void -> #list
|
||||
<doc>Return all the (key,value) pairs in the environment as a chained list</doc>
|
||||
**/
|
||||
Array<String> _hx_std_sys_env()
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
#if !defined(HX_WINRT) && !defined(KORE_CONSOLE)
|
||||
char **e = environ;
|
||||
while( *e )
|
||||
{
|
||||
char *x = strchr(*e,'=');
|
||||
if( x == NULL )
|
||||
{
|
||||
e++;
|
||||
continue;
|
||||
}
|
||||
result->push(String::create(*e,(int)(x-*e)));
|
||||
result->push(String::create(x+1));
|
||||
e++;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#define tcsetattr(fd,opt,s) ioctl(fd,opt,s)
|
||||
#define tcgetattr(fd,s) ioctl(fd,TCGETS,s)
|
||||
|
||||
static __inline__ void inline_cfmakeraw(struct termios *s)
|
||||
{
|
||||
s->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
||||
s->c_oflag &= ~OPOST;
|
||||
s->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
s->c_cflag &= ~(CSIZE|PARENB);
|
||||
s->c_cflag |= CS8;
|
||||
}
|
||||
|
||||
#define cfmakeraw inline_cfmakeraw
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
sys_getch : bool -> int
|
||||
<doc>Read a character from stdin with or without echo</doc>
|
||||
**/
|
||||
int _hx_std_sys_getch( bool b )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(EMSCRIPTEN) || defined(EPPC) || defined(KORE_CONSOLE) || defined(__FreeBSD__)
|
||||
return 0;
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
hx::EnterGCFreeZone();
|
||||
int result = b?getche():getch();
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return result;
|
||||
#else
|
||||
// took some time to figure out how to do that
|
||||
// without relying on ncurses, which clear the
|
||||
// terminal on initscr()
|
||||
int c;
|
||||
struct termios term, old;
|
||||
hx::EnterGCFreeZone();
|
||||
tcgetattr(fileno(stdin), &old);
|
||||
term = old;
|
||||
cfmakeraw(&term);
|
||||
tcsetattr(fileno(stdin), 0, &term);
|
||||
c = getchar();
|
||||
tcsetattr(fileno(stdin), 0, &old);
|
||||
if( b ) fputc(c,stdout);
|
||||
hx::ExitGCFreeZone();
|
||||
return c;
|
||||
# endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_get_pid : void -> int
|
||||
<doc>Returns the current process identifier</doc>
|
||||
**/
|
||||
int _hx_std_sys_get_pid()
|
||||
{
|
||||
# ifdef NEKO_WINDOWS
|
||||
return (int)(GetCurrentProcessId());
|
||||
#elif defined(EPPC) || defined(KORE_CONSOLE)
|
||||
return (1);
|
||||
# else
|
||||
return (getpid());
|
||||
# endif
|
||||
}
|
42
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/zlib/Build.xml
Normal file
42
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/zlib/Build.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="ZLIB_DIR" value="${HXCPP}/project/thirdparty/zlib-1.2.13"/>
|
||||
|
||||
<files id="hxcpp_zlib" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="1" />
|
||||
|
||||
<compilerflag value="-I${ZLIB_DIR}"/>
|
||||
<compilerflag value="-DSTDC" unless="windows" />
|
||||
<compilerflag value="-DHAVE_UNISTD_H" unless="windows" />
|
||||
|
||||
<file name="ZLib.cpp"/>
|
||||
|
||||
<!-- HXCPP_LINK_NO_ZLIB may be set too late, so use filterout as well. -->
|
||||
<section unless="HXCPP_LINK_NO_ZLIB" >
|
||||
<file name="${ZLIB_DIR}/adler32.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/compress.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/crc32.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/deflate.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzclose.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzlib.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzread.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzwrite.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/infback.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/inffast.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/inflate.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/inftrees.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/trees.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/uncompr.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/zutil.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
</section>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_zlib" />
|
||||
</target>
|
||||
|
||||
</xml>
|
284
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/zlib/ZLib.cpp
Normal file
284
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/libs/zlib/ZLib.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
#include <hxcpp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>ZLib</h1>
|
||||
<p>
|
||||
Give access to the popular ZLib compression library, used in several file
|
||||
formats such as ZIP and PNG.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
namespace {
|
||||
|
||||
struct ZipResult
|
||||
{
|
||||
inline ZipResult(bool inOk, bool inDone, int inRead, int inWrite)
|
||||
: ok(inOk)
|
||||
, done(inDone)
|
||||
, read(inRead)
|
||||
, write(inWrite) { }
|
||||
bool ok;
|
||||
bool done;
|
||||
int read;
|
||||
int write;
|
||||
};
|
||||
|
||||
struct ZStream : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdZLib };
|
||||
|
||||
z_stream *z;
|
||||
bool isInflate;
|
||||
int flush;
|
||||
|
||||
void create(bool inIsInflate, int inParam)
|
||||
{
|
||||
isInflate = inIsInflate;
|
||||
flush = Z_NO_FLUSH;
|
||||
z = (z_stream*)malloc(sizeof(z_stream));
|
||||
memset(z,0,sizeof(z_stream));
|
||||
int err = 0;
|
||||
if (!isInflate)
|
||||
{
|
||||
if( (err = deflateInit(z,inParam)) != Z_OK )
|
||||
{
|
||||
free(z);
|
||||
z = 0;
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (err = inflateInit2(z,inParam)) != Z_OK )
|
||||
{
|
||||
free(z);
|
||||
z = 0;
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((ZStream *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (z)
|
||||
{
|
||||
if (isInflate)
|
||||
inflateEnd(z);
|
||||
else
|
||||
deflateEnd(z);
|
||||
free(z);
|
||||
z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ZipResult deflate(Array<unsigned char> src, int srcpos, Array<unsigned char> dest, int dstpos)
|
||||
{
|
||||
if( srcpos < 0 || dstpos < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
|
||||
int slen = src->length - srcpos;
|
||||
int dlen = dest->length - dstpos;
|
||||
if( slen < 0 || dlen < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
|
||||
z->next_in = (Bytef*)(&src[srcpos]);
|
||||
z->next_out = (Bytef*)(&dest[dstpos]);
|
||||
z->avail_in = slen;
|
||||
z->avail_out = dlen;
|
||||
int err = 0;
|
||||
if( (err = ::deflate(z,flush)) < 0 )
|
||||
onError(err);
|
||||
|
||||
z->next_in = 0;
|
||||
z->next_out = 0;
|
||||
return ZipResult( true, err == Z_STREAM_END, (int)(slen - z->avail_in), (int)(dlen - z->avail_out) );
|
||||
}
|
||||
|
||||
ZipResult inflate(Array<unsigned char> src, int srcpos, Array<unsigned char> dest, int dstpos)
|
||||
{
|
||||
int slen = src->length;
|
||||
int dlen = dest->length;
|
||||
|
||||
if( srcpos < 0 || dstpos < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
slen -= srcpos;
|
||||
dlen -= dstpos;
|
||||
if( slen < 0 || dlen < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
|
||||
z->next_in = (Bytef*)&src[srcpos];
|
||||
z->next_out = (Bytef*)&dest[dstpos];
|
||||
z->avail_in = slen;
|
||||
z->avail_out = dlen;
|
||||
int err = 0;
|
||||
if( (err = ::inflate(z,flush)) < 0 )
|
||||
onError(err);
|
||||
z->next_in = 0;
|
||||
z->next_out = 0;
|
||||
return ZipResult( true, err == Z_STREAM_END, (int)(slen - z->avail_in), (int)(dlen - z->avail_out) );
|
||||
}
|
||||
|
||||
int getDeflateBound(int inLength)
|
||||
{
|
||||
return deflateBound(z,inLength);
|
||||
}
|
||||
|
||||
void setFlushMode(String inMode)
|
||||
{
|
||||
if( inMode == HX_CSTRING("NO") )
|
||||
flush = Z_NO_FLUSH;
|
||||
else if( inMode==HX_CSTRING("SYNC"))
|
||||
flush = Z_SYNC_FLUSH;
|
||||
else if( inMode==HX_CSTRING("FULL"))
|
||||
flush = Z_FULL_FLUSH;
|
||||
else if( inMode==HX_CSTRING("FINISH"))
|
||||
flush = Z_FINISH;
|
||||
else if( inMode==HX_CSTRING("BLOCK"))
|
||||
flush = Z_BLOCK;
|
||||
}
|
||||
|
||||
|
||||
void onError(int inCode)
|
||||
{
|
||||
String message = HX_CSTRING("ZLib Error : ");
|
||||
if( z && z->msg )
|
||||
message += String(z->msg) + HX_CSTRING("(") + String(inCode) + HX_CSTRING(")");
|
||||
else
|
||||
message += String(inCode);
|
||||
hx::Throw(message);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
ZStream *GetDeflateStream(Dynamic inHandle)
|
||||
{
|
||||
ZStream *z = dynamic_cast<ZStream *>(inHandle.mPtr);
|
||||
if (!z || !z->z || z->isInflate)
|
||||
hx::Throw( HX_CSTRING("ZLib: Not a valid deflate stream"));
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
ZStream *GetInflateStream(Dynamic inHandle)
|
||||
{
|
||||
ZStream *z = dynamic_cast<ZStream *>(inHandle.mPtr);
|
||||
if (!z || !z->z || !z->isInflate)
|
||||
hx::Throw( HX_CSTRING("ZLib: Not a valid inflate stream"));
|
||||
return z;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
deflate_init : level:int -> 'dstream
|
||||
<doc>Open a compression stream with the given level of compression</doc>
|
||||
**/
|
||||
Dynamic _hx_deflate_init(int level)
|
||||
{
|
||||
ZStream *zStream = new ZStream;
|
||||
zStream->create(false, level);
|
||||
return zStream;
|
||||
}
|
||||
|
||||
/**
|
||||
deflate_buffer : 'dstream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int }
|
||||
**/
|
||||
Dynamic _hx_deflate_buffer(Dynamic handle, Array<unsigned char> src, int srcPos, Array<unsigned char> dest, int destPos)
|
||||
{
|
||||
ZipResult result = GetDeflateStream(handle)->deflate(src,srcPos,dest,destPos);
|
||||
if (!result.ok)
|
||||
return null();
|
||||
|
||||
return hx::Anon_obj::Create(3)
|
||||
->setFixed(0,HX_("write",df,6c,59,d0),result.write)
|
||||
->setFixed(1,HX_("done",82,f0,6d,42),result.done)
|
||||
->setFixed(2,HX_("read",56,4b,a7,4b),result.read);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
deflate_bound : 'dstream -> n:int -> int
|
||||
<doc>Return the maximum buffer size needed to write [n] bytes</doc>
|
||||
**/
|
||||
int _hx_deflate_bound(Dynamic handle,int length)
|
||||
{
|
||||
return GetDeflateStream(handle)->getDeflateBound(length);
|
||||
}
|
||||
|
||||
void _hx_deflate_end(Dynamic handle)
|
||||
{
|
||||
GetDeflateStream(handle)->destroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
set_flush_mode : 'stream -> string -> void
|
||||
<doc>Change the flush mode ("NO","SYNC","FULL","FINISH","BLOCK")</doc>
|
||||
**/
|
||||
void _hx_zip_set_flush_mode(Dynamic handle, String flushMode)
|
||||
{
|
||||
ZStream *zstream = dynamic_cast<ZStream *>(handle.mPtr);
|
||||
if (!zstream || !zstream->z)
|
||||
hx::Throw( HX_CSTRING("ZLib flush: not a valid stream") );
|
||||
|
||||
zstream->setFlushMode(flushMode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
inflate_init : window_size:int? -> 'istream
|
||||
<doc>Open a decompression stream</doc>
|
||||
**/
|
||||
Dynamic _hx_inflate_init(Dynamic windowBits)
|
||||
{
|
||||
int bits = windowBits==null() ? MAX_WBITS : (int)windowBits;
|
||||
|
||||
ZStream *zStream = new ZStream();
|
||||
zStream->create(true, bits);
|
||||
return zStream;
|
||||
}
|
||||
|
||||
/**
|
||||
inflate_buffer : 'istream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int }
|
||||
**/
|
||||
Dynamic _hx_inflate_buffer(Dynamic handle, Array<unsigned char> src, int srcPos, Array<unsigned char> dest, int destPos)
|
||||
{
|
||||
ZipResult result = GetInflateStream(handle)->inflate(src,srcPos,dest,destPos);
|
||||
if (!result.ok)
|
||||
return null();
|
||||
|
||||
return hx::Anon_obj::Create(3)
|
||||
->setFixed(0,HX_("write",df,6c,59,d0),result.write)
|
||||
->setFixed(1,HX_("done",82,f0,6d,42),result.done)
|
||||
->setFixed(2,HX_("read",56,4b,a7,4b),result.read);
|
||||
}
|
||||
|
||||
/**
|
||||
inflate_end : 'istream -> void
|
||||
<doc>Close a decompression stream</doc>
|
||||
**/
|
||||
void _hx_inflate_end(Dynamic handle)
|
||||
{
|
||||
GetInflateStream(handle)->destroy();
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user