Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,300 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.*;
import php.ArrayIterator as NativeArrayIterator;
import haxe.iterators.ArrayKeyValueIterator;
using php.Global;
@:coreApi
final class Array<T> implements ArrayAccess<Int, T> implements IteratorAggregate<T> implements Countable implements JsonSerializable<NativeIndexedArray<T>> {
public var length(default, null):Int;
var arr:NativeIndexedArray<T>;
public function new() {
arr = new NativeIndexedArray<T>();
length = 0;
}
public function concat(a:Array<T>):Array<T> {
return wrap(Global.array_merge(arr, a.arr));
}
public inline function copy():Array<T> {
return Syntax.clone(this);
}
public inline function filter(f:T->Bool):Array<T> {
var result = Syntax.arrayDecl();
for(item in arr) {
if (f(item)) {
result.push(item);
}
}
return wrap(result);
}
public inline function contains(x:T):Bool {
return indexOf(x) != -1;
}
public function indexOf(x:T, ?fromIndex:Int):Int {
if (fromIndex == null && !Boot.isHxClosure(x) && !Boot.isNumber(x)) {
var index = Global.array_search(x, arr, true);
if (index == false) {
return -1;
} else {
return index;
}
}
if (fromIndex == null) {
fromIndex = 0;
} else {
if (fromIndex < 0)
fromIndex += length;
if (fromIndex < 0)
fromIndex = 0;
}
while (fromIndex < length) {
if (arr[fromIndex] == x)
return fromIndex;
fromIndex++;
}
return -1;
}
public function insert(pos:Int, x:T):Void {
length++;
Global.array_splice(arr, pos, 0, Syntax.arrayDecl(x));
}
@:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "anon_read.iterator")
public inline function iterator():haxe.iterators.ArrayIterator<T> {
return new haxe.iterators.ArrayIterator(this);
}
@:keep
public inline function keyValueIterator():ArrayKeyValueIterator<T> {
return new ArrayKeyValueIterator(this);
}
public function join(sep:String):String {
return Global.implode(sep, Global.array_map(Syntax.nativeClassName(Boot) + '::stringify', arr));
}
public function lastIndexOf(x:T, ?fromIndex:Int):Int {
if (fromIndex == null || fromIndex >= length)
fromIndex = length - 1;
if (fromIndex < 0)
fromIndex += length;
while (fromIndex >= 0) {
if (arr[fromIndex] == x)
return fromIndex;
fromIndex--;
}
return -1;
}
public inline function map<S>(f:T->S):Array<S> {
var result = Syntax.arrayDecl();
for(item in arr) {
result.push(f(item));
}
return wrap(result);
}
public inline function pop():Null<T> {
if (length > 0)
length--;
return Global.array_pop(arr);
}
public inline function push(x:T):Int {
arr[length++] = x;
return length;
}
public function remove(x:T):Bool {
var result = false;
for(index in 0...length) {
if (arr[index] == x) {
Global.array_splice(arr, index, 1);
length--;
result = true;
break;
}
}
return result;
}
public inline function reverse():Void {
arr = Global.array_reverse(arr);
}
public inline function shift():Null<T> {
if (length > 0)
length--;
return Global.array_shift(arr);
}
public function slice(pos:Int, ?end:Int):Array<T> {
if (pos < 0)
pos += length;
if (pos < 0)
pos = 0;
if (end == null) {
return wrap(Global.array_slice(arr, pos));
} else {
if (end < 0)
end += length;
if (end <= pos) {
return [];
} else {
return wrap(Global.array_slice(arr, pos, end - pos));
}
}
}
public inline function sort(f:T->T->Int):Void {
arr.usort(f);
}
public function splice(pos:Int, len:Int):Array<T> {
if (len < 0)
return [];
var result = wrap(Global.array_splice(arr, pos, len));
length -= result.length;
return result;
}
public inline function unshift(x:T):Void {
length = Global.array_unshift(arr, x);
}
public function toString():String {
return inline Boot.stringifyNativeIndexedArray(arr);
}
public function resize(len:Int):Void {
if (length < len) {
arr = Global.array_pad(arr, len, null);
} else if (length > len) {
Global.array_splice(arr, len, length - len);
}
length = len;
}
@:noCompletion @:keep
@:php.attribute('\\ReturnTypeWillChange')
function offsetExists(offset:Int):Bool {
return offset < length;
}
@:noCompletion @:keep
@:php.attribute('\\ReturnTypeWillChange')
function offsetGet(offset:Int):Ref<T> {
try {
return arr[offset];
} catch (e:Dynamic) {
return null;
}
}
@:noCompletion @:keep
@:php.attribute('\\ReturnTypeWillChange')
function offsetSet(offset:Int, value:T):Void {
if (length <= offset) {
for(i in length...offset + 1) {
arr[i] = null;
}
length = offset + 1;
}
arr[offset] = value;
Syntax.code("return {0}", value);
}
@:noCompletion @:keep
@:php.attribute('\\ReturnTypeWillChange')
function offsetUnset(offset:Int):Void {
if (offset >= 0 && offset < length) {
Global.array_splice(arr, offset, 1);
--length;
}
}
@:noCompletion @:keep
@:php.attribute('\\ReturnTypeWillChange')
private function getIterator():Traversable {
return new NativeArrayIterator(arr);
}
@:noCompletion @:keep
@:native('count') //to not interfere with `Lambda.count`
@:php.attribute('\\ReturnTypeWillChange')
private function _hx_count():Int {
return length;
}
@:noCompletion @:keep
@:php.attribute('\\ReturnTypeWillChange')
function jsonSerialize():NativeIndexedArray<T> {
return arr;
}
static function wrap<T>(arr:NativeIndexedArray<T>):Array<T> {
var a = new Array();
a.arr = arr;
a.length = Global.count(arr);
return a;
}
}
/**
Following interfaces are required to make `Array` mimic native arrays for usage
from a 3rd party PHP code.
**/
@:native('ArrayAccess')
private extern interface ArrayAccess<K, V> {
private function offsetExists(offset:K):Bool;
private function offsetGet(offset:K):V;
private function offsetSet(offset:K, value:V):Void;
private function offsetUnset(offset:K):Void;
}
@:native('JsonSerializable')
private extern interface JsonSerializable<T> {
private function jsonSerialize():T;
}
@:native('IteratorAggregate')
private extern interface IteratorAggregate<T> extends Traversable {
private function getIterator():Traversable;
}
@:native('Countable')
private extern interface Countable {
@:native('count') //to not interfere with `Lambda.count`
private function _hx_count():Int;
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.Global.*;
import php.Syntax.*;
@:coreApi final class Date {
private var __t:Float;
public function new(year:Int, month:Int, day:Int, hour:Int, min:Int, sec:Int):Void {
__t = mktime(hour, min, sec, month + 1, day, year);
}
public function getTime():Float {
return __t * 1000.0;
}
private function getPhpTime():Float {
return __t;
}
public function getFullYear():Int {
return int(date("Y", int(__t)));
}
public function getMonth():Int {
var m:Int = int(date("n", int(__t)));
return -1 + m;
}
public function getDate():Int {
return int(date("j", int(__t)));
}
public function getHours():Int {
return int(date("G", int(__t)));
}
public function getMinutes():Int {
return int(date("i", int(__t)));
}
public function getSeconds():Int {
return int(date("s", int(__t)));
}
public function getDay():Int {
return int(date("w", int(__t)));
}
public function getUTCFullYear():Int {
return int(gmdate("Y", int(__t)));
}
public function getUTCMonth():Int {
var m:Int = int(gmdate("n", int(__t)));
return -1 + m;
}
public function getUTCDate():Int {
return int(gmdate("j", int(__t)));
}
public function getUTCHours():Int {
return int(gmdate("G", int(__t)));
}
public function getUTCMinutes():Int {
return int(gmdate("i", int(__t)));
}
public function getUTCSeconds():Int {
return int(gmdate("s", int(__t)));
}
public function getUTCDay():Int {
return int(gmdate("w", int(__t)));
}
public function getTimezoneOffset():Int {
return -Std.int(int(date("Z", int(__t))) / 60);
}
public function toString():String {
return date("Y-m-d H:i:s", int(__t));
}
public static function now():Date {
return fromPhpTime(round(microtime(true), 3));
}
static function fromPhpTime(t:Float):Date {
var d = new Date(2000, 1, 1, 0, 0, 0);
d.__t = t;
return d;
}
public static function fromTime(t:Float):Date {
var d = new Date(2000, 1, 1, 0, 0, 0);
d.__t = t / 1000;
return d;
}
public static function fromString(s:String):Date {
switch (s.length) {
case 8: // hh:mm:ss
var k = s.split(":");
return Date.fromTime(Std.parseInt(k[0]) * 3600000. + Std.parseInt(k[1]) * 60000. + Std.parseInt(k[2]) * 1000.);
case 10: // YYYY-MM-DD
var k = s.split("-");
return new Date(Std.parseInt(k[0]), Std.parseInt(k[1]) - 1, Std.parseInt(k[2]), 0, 0, 0);
case 19: // YYYY-MM-DD hh:mm:ss
var k = s.split(" ");
var y = k[0].split("-");
var t = k[1].split(":");
return new Date(Std.parseInt(y[0]), Std.parseInt(y[1]) - 1, Std.parseInt(y[2]), Std.parseInt(t[0]), Std.parseInt(t[1]), Std.parseInt(t[2]));
default:
throw "Invalid date format : " + s;
}
}
}

View File

@ -0,0 +1,179 @@
/*
* Copyright (C)2005-2019 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.
*/
import haxe.extern.EitherType;
import php.*;
@:coreApi final class EReg {
var r:Dynamic;
var last:String;
var global:Bool;
var pattern:String;
var options:String;
var re:String;
var reUnicode(get, never):String;
var matches:NativeIndexedArray<NativeIndexedArray<EitherType<Int, String>>>;
public function new(r:String, opt:String):Void {
this.pattern = r;
options = Global.str_replace('g', '', opt);
global = options != opt;
options = Global.str_replace('u', '', options);
this.re = '"' + Global.str_replace('"', '\\"', r) + '"' + options;
}
public function match(s:String):Bool {
return matchFromByte(s, 0);
}
inline function matchFromByte(s:String, bytesOffset:Int):Bool {
var p = Global.preg_match(reUnicode, s, matches, Const.PREG_OFFSET_CAPTURE, bytesOffset);
if (p == false) {
handlePregError();
p = Global.preg_match(re, s, matches, Const.PREG_OFFSET_CAPTURE);
}
if ((p : Int) > 0) {
last = s;
} else {
last = null;
}
return (p : Int) > 0;
}
function handlePregError():Void {
var e = Global.preg_last_error();
if (e == Const.PREG_INTERNAL_ERROR) {
throw 'EReg: internal PCRE error';
} else if (e == Const.PREG_BACKTRACK_LIMIT_ERROR) {
throw 'EReg: backtrack limit';
} else if (e == Const.PREG_RECURSION_LIMIT_ERROR) {
throw 'EReg: recursion limit';
} else if (e == Const.PREG_JIT_STACKLIMIT_ERROR) {
throw 'failed due to limited JIT stack space';
}
// else if(e == Const.PREG_BAD_UTF8_ERROR) {
// throw 'EReg: malformed UTF8';
// } else if(e == Const.PREG_BAD_UTF8_OFFSET_ERROR) {
// throw 'EReg: the offset didn\'t correspond to the begin of a valid UTF-8 code point';
// }
}
public function matched(n:Int):String {
if (matches == null || n < 0)
throw "EReg::matched";
// we can't differentiate between optional groups at the end of a match
// that have not been matched and invalid groups
if (n >= Global.count(matches))
return null;
if ((matches[n][1] : Int) < 0)
return null;
return matches[n][0];
}
public function matchedLeft():String {
if (Global.count(matches) == 0)
throw "No string matched";
return Global.substr(last, 0, matches[0][1]);
}
public function matchedRight():String {
if (Global.count(matches) == 0)
throw "No string matched";
var x:Int = (matches[0][1] : Int) + Global.strlen(matches[0][0]);
return Global.substr(last, x);
}
public function matchedPos():{pos:Int, len:Int} {
return {
pos: Global.mb_strlen(Global.substr(last, 0, matches[0][1])),
len: Global.mb_strlen(matches[0][0])
};
}
public function matchSub(s:String, pos:Int, len:Int = -1):Bool {
var subject = len < 0 ? s : s.substr(0, pos + len);
var p = Global.preg_match(reUnicode, subject, matches, Const.PREG_OFFSET_CAPTURE, pos);
if (p == false) {
handlePregError();
p = Global.preg_match(re, subject, matches, Const.PREG_OFFSET_CAPTURE, pos);
}
if ((p : Int) > 0) {
last = s;
} else {
last = null;
}
return (p : Int) > 0;
}
public function split(s:String):Array<String> {
var parts:EitherType<Bool, NativeArray> = Global.preg_split(reUnicode, s, (global ? -1 : 2));
if (parts == false) {
handlePregError();
parts = Global.preg_split(re, s, (global ? -1 : 2));
}
return @:privateAccess Array.wrap(cast parts);
}
public function replace(s:String, by:String):String {
by = Global.str_replace("\\$", "\\\\$", by);
by = Global.str_replace("$$", "\\$", by);
if (!Global.preg_match('/\\\\([^?].*?\\\\)/', re)) {
by = Global.preg_replace('/\\$(\\d+)/', '\\$\\1', by);
}
var result = Global.preg_replace(reUnicode, by, s, global ? -1 : 1);
if (result == null) {
handlePregError();
result = Global.preg_replace(re, by, s, global ? -1 : 1);
}
return result;
}
public function map(s:String, f:EReg->String):String {
if(!matchFromByte(s, 0)) {
return s;
}
var result = '';
var bytesOffset = 0;
var bytesTotal = Global.strlen(s);
do {
result += Global.substr(s, bytesOffset, matches[0][1] - bytesOffset);
result += f(this);
bytesOffset = matches[0][1];
if(matches[0][0] == '') {
result += Global.mb_substr(Global.substr(s, bytesOffset), 0, 1);
bytesOffset++;
} else {
bytesOffset += Global.strlen(matches[0][0]);
}
} while(global && bytesOffset < bytesTotal && matchFromByte(s, bytesOffset));
result += Global.substr(s, bytesOffset);
return result;
}
public static inline function escape(s:String):String {
return Global.preg_quote(s);
}
inline function get_reUnicode():String {
return Syntax.concat(re, 'u');
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.Global;
import php.Const;
import php.Syntax;
@:coreApi class Math {
public static var PI(default, null):Float = Const.M_PI;
public static var NaN(default, null):Float = Const.NAN;
public static var POSITIVE_INFINITY(default, null):Float = Const.INF;
public static var NEGATIVE_INFINITY(default, null):Float = -Const.INF;
public static inline function abs(v:Float):Float
return Global.abs(v);
public static inline function min(a:Float, b:Float):Float
return isNaN(a) || isNaN(b) ? NaN : Global.min(a, b);
public static inline function max(a:Float, b:Float):Float
return isNaN(a) || isNaN(b) ? NaN : Global.max(a, b);
public static inline function sin(v:Float):Float
return Global.sin(v);
public static inline function cos(v:Float):Float
return Global.cos(v);
public static inline function atan2(y:Float, x:Float):Float
return Global.atan2(y, x);
public static inline function tan(v:Float):Float
return Global.tan(v);
public static inline function exp(v:Float):Float
return Global.exp(v);
public static inline function log(v:Float):Float
return Global.log(v);
public static inline function sqrt(v:Float):Float
return Global.sqrt(v);
public static inline function round(v:Float):Int
return Syntax.int(Global.floor(v + 0.5));
public static inline function floor(v:Float):Int
return Syntax.int(Global.floor(v));
public static inline function ceil(v:Float):Int
return Syntax.int(Global.ceil(v));
public static inline function atan(v:Float):Float
return Global.atan(v);
public static inline function asin(v:Float):Float
return Global.asin(v);
public static inline function acos(v:Float):Float
return Global.acos(v);
public static inline function pow(v:Float, exp:Float):Float
return Syntax.exp(v, exp);
public static inline function random():Float
return Global.mt_rand() / Global.mt_getrandmax();
public static inline function isNaN(f:Float):Bool
return Global.is_nan(f);
public static inline function isFinite(f:Float):Bool
return Global.is_finite(f);
public static inline function fround(v:Float):Float
return Global.floor(v + 0.5);
public static inline function ffloor(v:Float):Float
return Global.floor(v);
public static inline function fceil(v:Float):Float
return Global.ceil(v);
}

View File

@ -0,0 +1,180 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.Boot;
import php.Syntax;
import php.Closure;
import php.Const;
import php.NativeAssocArray;
import haxe.Constraints;
using php.Global;
@:coreApi class Reflect {
public static function hasField(o:Dynamic, field:String):Bool {
if (!o.is_object())
return false;
if (o.property_exists(field))
return true;
if (Boot.isClass(o)) {
var phpClassName = Boot.castClass(o).phpClassName;
return Global.property_exists(phpClassName, field)
|| Global.method_exists(phpClassName, field)
|| Global.defined('$phpClassName::$field');
}
return false;
}
public static function field(o:Dynamic, field:String):Dynamic {
if (o.is_string()) {
return Syntax.field(Boot.dynamicString(o), field);
}
if (!o.is_object())
return null;
if (field == '' && Const.PHP_VERSION_ID < 70100) {
return Syntax.coalesce(Syntax.array(o)[field], null);
}
if (o.property_exists(field)) {
return Syntax.field(o, field);
}
if (o.method_exists(field)) {
return Boot.getInstanceClosure(o, field);
}
if (Boot.isClass(o)) {
var phpClassName = Boot.castClass(o).phpClassName;
if (Global.defined('$phpClassName::$field')) {
return Global.constant('$phpClassName::$field');
}
if (Global.property_exists(phpClassName, field)) {
return Syntax.field(o, field);
}
if (Global.method_exists(phpClassName, field)) {
return Boot.getStaticClosure(phpClassName, field);
}
}
return null;
}
public static function setField(o:Dynamic, field:String, value:Dynamic):Void {
Syntax.setField(o, field, value);
}
public static function getProperty(o:Dynamic, field:String):Dynamic {
if (o.is_object()) {
if (Boot.isClass(o)) {
var phpClassName = Boot.castClass(o).phpClassName;
if (Boot.hasGetter(phpClassName, field)) {
return Syntax.staticCall(phpClassName, 'get_$field');
}
} else if (Boot.hasGetter(Global.get_class(o), field)) {
return Syntax.call(o, 'get_$field');
}
}
return Reflect.field(o, field);
}
public static function setProperty(o:Dynamic, field:String, value:Dynamic):Void {
if (o.is_object()) {
if (Boot.hasSetter(Global.get_class(o), field)) {
Syntax.call(o, 'set_$field', value);
} else {
Syntax.setField(o, field, value);
}
}
}
public static function callMethod(o:Dynamic, func:Function, args:Array<Dynamic>):Dynamic {
return Global.call_user_func_array(func, @:privateAccess args.arr);
}
public static function fields(o:Dynamic):Array<String> {
if (Global.is_object(o)) {
return @:privateAccess Array.wrap(Global.get_object_vars(o).array_keys());
}
return [];
}
public static inline function isFunction(f:Dynamic):Bool {
return Boot.isFunction(f);
}
public static function compare<T>(a:T, b:T):Int {
if (a == b)
return 0;
if (Global.is_string(a)) {
return Global.strcmp(cast a, cast b);
} else {
return ((cast a) > (cast b) ? 1 : -1);
}
}
public static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
if (Boot.isHxClosure(f1) && Boot.isHxClosure(f2)) {
return f1.equals(f2);
} else {
return f1 == f2;
}
}
public static function isObject(v:Dynamic):Bool {
if (Boot.isEnumValue(v)) {
return false;
} else {
return v.is_object() || v.is_string();
}
}
public static inline function isEnumValue(v:Dynamic):Bool {
return Boot.isEnumValue(v);
}
public static function deleteField(o:Dynamic, field:String):Bool {
if (hasField(o, field)) {
Global.unset(Syntax.field(o, field));
return true;
} else {
return false;
}
}
public static function copy<T>(o:Null<T>):Null<T> {
if (Boot.isAnon(o)) {
return Syntax.clone(o);
} else {
return null;
}
}
@:overload(function(f:Array<Dynamic>->Void):Dynamic {})
public static function makeVarArgs(f:Array<Dynamic>->Dynamic):Dynamic {
return function() {
return Global.call_user_func(f, @:privateAccess Array.wrap(Global.func_get_args()));
}
}
}

View File

@ -0,0 +1,100 @@
import php.Boot;
/*
* Copyright (C)2005-2019 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.
*/
import php.Global;
import php.Const;
import php.Syntax;
@:coreApi class Std {
@:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
public static inline function is(v:Dynamic, t:Dynamic):Bool {
return isOfType(v, t);
}
public static inline function isOfType(v:Dynamic, t:Dynamic):Bool {
return Boot.isOfType(v, t);
}
public static inline function downcast<T:{}, S:T>(value:T, c:Class<S>):S {
return Boot.isOfType(value, cast c) ? cast value : null;
}
@:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.')
public static inline function instance<T:{}, S:T>(value:T, c:Class<S>):S {
return Boot.isOfType(value, cast c) ? cast value : null;
}
public static function string(s:Dynamic):String {
return Boot.stringify(s);
}
public static inline function int(x:Float):Int {
return Syntax.int(x);
}
public static function parseInt(x:String):Null<Int> {
if (Global.is_numeric(x)) {
return Global.intval(x, 10);
} else {
x = Global.ltrim(x);
var firstCharIndex = (x.charAt(0) == '-' ? 1 : 0);
var firstCharCode = x.charCodeAt(firstCharIndex);
if (!isDigitCode(firstCharCode)) {
return null;
}
var secondChar = x.charAt(firstCharIndex + 1);
if (secondChar == 'x' || secondChar == 'X') {
return Global.intval(x, 0);
} else {
return Global.intval(x, 10);
}
}
}
public static function parseFloat(x:String):Float {
var result = Global.floatval(x);
if (result != 0)
return result;
x = Global.ltrim(x);
var firstCharIndex = (x.charAt(0) == '-' ? 1 : 0);
var charCode = x.charCodeAt(firstCharIndex);
if (charCode == '.'.code) {
charCode = x.charCodeAt(firstCharIndex + 1);
}
if (isDigitCode(charCode)) {
return 0.0;
} else {
return Const.NAN;
}
}
public static inline function random(x:Int):Int {
return x <= 1 ? 0 : Global.mt_rand(0, x - 1);
}
static inline function isDigitCode(charCode:Null<Int>):Bool {
return charCode != null && charCode >= '0'.code && charCode <= '9'.code;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.*;
@:coreApi extern class String {
var length(default, null):Int;
@:pure function new(string:String):Void;
@:pure @:runtime inline function toUpperCase():String {
return Global.mb_strtoupper(this);
}
@:pure @:runtime inline function toLowerCase():String {
return Global.mb_strtolower(this);
}
@:pure @:runtime inline function charAt(index:Int):String {
return index < 0 ? '' : Global.mb_substr(this, index, 1);
}
@:pure function charCodeAt(index:Int):Null<Int>;
@:pure function indexOf(str:String, ?startIndex:Int):Int;
@:pure function lastIndexOf(str:String, ?startIndex:Int):Int;
@:pure function split(delimiter:String):Array<String>;
@:pure @:runtime inline function substr(pos:Int, ?len:Int):String {
return Global.mb_substr(this, pos, len);
}
@:pure function substring(startIndex:Int, ?endIndex:Int):String;
@:pure @:runtime inline function toString():String {
return this;
}
@:pure @:runtime static inline function fromCharCode(code:Int):String {
return Global.mb_chr(code);
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.Global;
import php.Syntax;
@:coreApi class StringBuf {
private var b:String;
public var length(get, never):Int;
public function new():Void {
b = "";
}
inline function get_length():Int {
return b.length;
}
public function add<T>(x:T):Void {
if (x == null) {
b = Syntax.concat(b, 'null');
} else if (Global.is_bool(x)) {
b = Syntax.concat(b, ((x : Dynamic) ? 'true' : 'false'));
} else if (Global.is_string(x)) {
b = Syntax.concat(b, cast x);
} else {
b += x;
}
}
public inline function addSub(s:String, pos:Int, ?len:Int):Void {
b += s.substr(pos, len);
}
public inline function addChar(c:Int):Void {
b += String.fromCharCode(c);
}
public inline function toString():String {
return b;
}
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.*;
import haxe.iterators.StringIterator;
import haxe.iterators.StringKeyValueIterator;
@:coreApi class StringTools {
public inline static function urlEncode(s:String):String {
return Global.rawurlencode(s);
}
public inline static function urlDecode(s:String):String {
return Global.urldecode(s);
}
public inline static function htmlEscape(s:String, ?quotes:Bool):String {
return Global.htmlspecialchars(s, (quotes ? Const.ENT_QUOTES | Const.ENT_HTML401 : Const.ENT_NOQUOTES));
}
public inline static function htmlUnescape(s:String):String {
return Global.htmlspecialchars_decode(s, Const.ENT_QUOTES);
}
public inline static function contains(s:String, value:String):Bool {
return s.indexOf(value) != -1;
}
public static function startsWith(s:String, start:String):Bool {
return start == '' || Global.substr(s, 0, Global.strlen(start)) == start;
}
public static function endsWith(s:String, end:String):Bool {
return end == '' || Global.substr(s, -Global.strlen(end)) == end;
}
public static function isSpace(s:String, pos:Int):Bool {
var c = s.charCodeAt(pos);
return (c >= 9 && c <= 13) || c == 32;
}
public inline static function ltrim(s:String):String {
return Global.ltrim(s);
}
public inline static function rtrim(s:String):String {
return Global.rtrim(s);
}
public inline static function trim(s:String):String {
return Global.trim(s);
}
public static function rpad(s:String, c:String, l:Int):String {
var cLength = c.length;
var sLength = s.length;
if (cLength == 0 || sLength >= l)
return s;
var padLength = l - sLength;
var padCount = Syntax.int(padLength / cLength);
if (padCount > 0) {
var result = Global.str_pad(s, Global.strlen(s) + padCount * Global.strlen(c), c, Const.STR_PAD_RIGHT);
return (padCount * cLength >= padLength) ? result : Syntax.concat(result, c);
} else {
return Syntax.concat(s, c);
}
}
public static function lpad(s:String, c:String, l:Int):String {
var cLength = c.length;
var sLength = s.length;
if (cLength == 0 || sLength >= l)
return s;
var padLength = l - sLength;
var padCount = Syntax.int(padLength / cLength);
if (padCount > 0) {
var result = Global.str_pad(s, Global.strlen(s) + padCount * Global.strlen(c), c, Const.STR_PAD_LEFT);
return (padCount * cLength >= padLength) ? result : Syntax.concat(c, result);
} else {
return Syntax.concat(c, s);
}
}
public static function replace(s:String, sub:String, by:String):String {
if (sub == '') {
return Global.implode(by, Global.preg_split('//u', s, -1, Const.PREG_SPLIT_NO_EMPTY));
}
return Global.str_replace(sub, by, s);
}
public static function hex(n:Int, ?digits:Int):String {
var s = Global.dechex(n);
var len = 8;
if (Global.strlen(s) > (null == digits ? len : (len = digits > len ? digits : len)))
s = s.substr(-len);
else if (digits != null)
s = lpad(s, '0', digits);
return s.toUpperCase();
}
public static function fastCodeAt(s:String, index:Int):Int {
var char:NativeString = (index == 0 ? s : Global.mb_substr(s, index, 1));
if (char == '')
return 0;
return Boot.unsafeOrd(char);
}
public static function unsafeCodeAt(s:String, index:Int):Int {
var char:NativeString = (index == 0 ? s : Global.mb_substr(s, index, 1));
return Boot.unsafeOrd(char);
}
public static inline function iterator(s:String):StringIterator {
return new StringIterator(s);
}
public static inline function keyValueIterator(s:String):StringKeyValueIterator {
return new StringKeyValueIterator(s);
}
@:noUsing public static inline function isEof(c:Int):Bool {
return c == 0;
}
@:noCompletion
@:deprecated('StringTools.quoteUnixArg() is deprecated. Use haxe.SysTools.quoteUnixArg() instead.')
public static function quoteUnixArg(argument:String):String {
return inline haxe.SysTools.quoteUnixArg(argument);
}
@:noCompletion
@:deprecated('StringTools.winMetaCharacters is deprecated. Use haxe.SysTools.winMetaCharacters instead.')
public static var winMetaCharacters:Array<Int> = cast haxe.SysTools.winMetaCharacters;
@:noCompletion
@:deprecated('StringTools.quoteWinArg() is deprecated. Use haxe.SysTools.quoteWinArg() instead.')
public static function quoteWinArg(argument:String, escapeMetaCharacters:Bool):String {
return inline haxe.SysTools.quoteWinArg(argument, escapeMetaCharacters);
}
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.*;
import sys.io.FileOutput;
import sys.io.FileInput;
import haxe.SysTools;
@:coreApi class Sys {
/** Environment variables set by `Sys.putEnv()` */
static var customEnvVars = new NativeAssocArray<String>();
public static inline function print(v:Dynamic):Void {
Global.echo(Std.string(v));
}
public static inline function println(v:Dynamic):Void {
Global.echo(Std.string(v) + Const.PHP_EOL);
}
public static function args():Array<String> {
if (Global.array_key_exists('argv', SuperGlobal._SERVER)) {
return @:privateAccess Array.wrap(Global.array_slice(SuperGlobal._SERVER['argv'], 1));
} else {
return [];
}
}
public static function getEnv(s:String):String {
var value = Global.getenv(s);
return value == false ? null : value;
}
public static function putEnv(s:String, v:String):Void {
customEnvVars[s] = '$v'; // in case of `null` it should become `"null"`
Global.putenv('$s=$v');
}
public static inline function sleep(seconds:Float):Void {
return Global.usleep(Std.int(seconds * 1000000));
}
public static inline function setTimeLocale(loc:String):Bool {
return Global.setlocale(Const.LC_TIME, loc) != false;
}
public static function getCwd():String {
var cwd = Global.getcwd();
if (cwd == false)
return null;
var l = (cwd : String).substr(-1);
return (cwd : String) + (l == '/' || l == '\\' ? '' : '/');
}
public static inline function setCwd(s:String):Void {
Global.chdir(s);
}
public static function systemName():String {
var s = Global.php_uname('s');
var p = s.indexOf(" ");
return (p >= 0 ? s.substr(0, p) : s);
}
public static function command(cmd:String, ?args:Array<String>):Int {
if (args != null) {
switch (systemName()) {
case "Windows":
cmd = [
for (a in [StringTools.replace(cmd, "/", "\\")].concat(args))
SysTools.quoteWinArg(a, true)
].join(" ");
case _:
cmd = [cmd].concat(args).map(SysTools.quoteUnixArg).join(" ");
}
}
var result = Boot.deref(0);
Global.system(cmd, result);
return result;
}
public static inline function exit(code:Int):Void {
Global.exit(code);
}
public static inline function time():Float {
return Global.microtime(true);
}
public static function cpuTime():Float {
return time() - SuperGlobal._SERVER['REQUEST_TIME'];
}
@:deprecated("Use programPath instead") public static inline function executablePath():String {
return SuperGlobal._SERVER['SCRIPT_FILENAME'];
}
// It has to be initialized before any call to Sys.setCwd()...
static var _programPath = sys.FileSystem.fullPath(SuperGlobal._SERVER['SCRIPT_FILENAME']);
public static function programPath():String {
return _programPath;
}
public static function environment():Map<String, String> {
var env = SuperGlobal._SERVER;
Syntax.foreach(customEnvVars, function(name:String, value:String) {
env[name] = value;
});
return php.Lib.hashOfAssociativeArray(env);
}
public static function stdin():haxe.io.Input {
var p = Global.defined('STDIN') ? Const.STDIN : Global.fopen('php://stdin', 'r');
return @:privateAccess new FileInput(p);
}
public static function stdout():haxe.io.Output {
var p = Global.defined('STDOUT') ? Const.STDOUT : Global.fopen('php://stdout', 'w');
return @:privateAccess new FileOutput(p);
}
public static function stderr():haxe.io.Output {
var p = Global.defined('STDERR') ? Const.STDERR : Global.fopen('php://stderr', 'w');
return @:privateAccess new FileOutput(p);
}
public static function getChar(echo:Bool):Int {
var c = Global.fgetc(Const.STDIN);
if (c == false) {
return 0;
} else {
if (echo)
Global.echo(c);
return Global.ord(c);
}
}
}

View File

@ -0,0 +1,364 @@
/*
* Copyright (C)2005-2019 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.
*/
import php.*;
import php.reflection.*;
import haxe.extern.EitherType;
using php.Global;
enum ValueType {
TNull;
TInt;
TFloat;
TBool;
TObject;
TFunction;
TClass(c:Class<Dynamic>);
TEnum(e:Enum<Dynamic>);
TUnknown;
}
@:coreApi class Type {
public static function getClass<T>(o:T):Class<T> {
if (Global.is_object(o) && !Boot.isClass(o) && !Boot.isEnumValue(o)) {
var cls = Boot.getClass(Global.get_class(cast o));
return (Boot.isAnon(o) ? null : cast cls);
} else if (Global.is_string(o)) {
return cast String;
} else {
return null;
}
}
public static function getEnum(o:EnumValue):Enum<Dynamic> {
if (o == null)
return null;
return cast Boot.getClass(Global.get_class(cast o));
}
public static function getSuperClass(c:Class<Dynamic>):Class<Dynamic> {
if (c == null)
return null;
var parentClass = try {
Global.get_parent_class((cast c).phpClassName);
} catch(e) {
return null;
}
if (!parentClass)
return null;
return cast Boot.getClass(parentClass);
}
public static function getClassName(c:Class<Dynamic>):String {
if (c == null)
return null;
return Boot.getHaxeName(cast c);
}
public static function getEnumName(e:Enum<Dynamic>):String {
return getClassName(cast e);
}
public static function resolveClass(name:String):Class<Dynamic> {
if (name == null)
return null;
switch (name) {
case 'Dynamic':
return cast Dynamic;
case 'Int':
return cast Int;
case 'Float':
return cast Float;
case 'Bool':
return cast Bool;
case 'String':
return String;
case 'Class':
return cast Class;
case 'Enum':
return cast Enum;
}
var phpClass = Boot.getPhpName(name);
if (!Global.class_exists(phpClass) && !Global.interface_exists(phpClass))
return null;
var hxClass = Boot.getClass(phpClass);
return cast hxClass;
}
public static function resolveEnum(name:String):Enum<Dynamic> {
if (name == null)
return null;
if (name == 'Bool')
return cast Bool;
var phpClass = Boot.getPhpName(name);
if (!Global.class_exists(phpClass))
return null;
var hxClass = Boot.getClass(phpClass);
return cast hxClass;
}
public static function createInstance<T>(cl:Class<T>, args:Array<Dynamic>):T {
if (String == cast cl)
return args[0];
var nativeArgs:NativeArray = @:privateAccess args.arr;
return Syntax.construct(Syntax.nativeClassName(cl), Syntax.splat(nativeArgs));
}
public static function createEmptyInstance<T>(cl:Class<T>):T {
if (String == cast cl)
return cast '';
if (Array == cast cl)
return cast [];
var reflection = new ReflectionClass(Syntax.nativeClassName(cl));
return reflection.newInstanceWithoutConstructor();
}
public static function createEnum<T>(e:Enum<T>, constr:String, ?params:Array<Dynamic>):T {
if (e == null || constr == null)
return null;
var phpName = Syntax.nativeClassName(e);
if (!Global.in_array(constr, Syntax.staticCall(phpName, "__hx__list"))) {
throw 'No such constructor $constr';
}
var paramsCounts:NativeAssocArray<Int> = Syntax.staticCall(phpName, "__hx__paramsCount");
if ((params == null && paramsCounts[constr] != 0) || (params != null && params.length != paramsCounts[constr])) {
throw 'Provided parameters count does not match expected parameters count';
}
if (params == null) {
return Syntax.staticCall(phpName, constr);
} else {
var nativeArgs:NativeArray = @:privateAccess params.arr;
return Syntax.staticCall(phpName, constr, Syntax.splat(nativeArgs));
}
}
public static function createEnumIndex<T>(e:Enum<T>, index:Int, ?params:Array<Dynamic>):T {
if (e == null || index == null)
return null;
var phpName = Syntax.nativeClassName(e);
var constructors:NativeIndexedArray<String> = Syntax.staticCall(phpName, "__hx__list");
if (index < 0 || index >= Global.count(constructors)) {
throw '$index is not a valid enum constructor index';
}
var constr = constructors[index];
var paramsCounts:NativeAssocArray<Int> = Syntax.staticCall(phpName, "__hx__paramsCount");
if ((params == null && paramsCounts[constr] != 0) || (params != null && params.length != paramsCounts[constr])) {
throw 'Provided parameters count does not match expected parameters count';
}
if (params == null) {
return Syntax.staticCall(phpName, constr);
} else {
var nativeArgs:NativeArray = @:privateAccess params.arr;
return Syntax.staticCall(phpName, constr, Syntax.splat(nativeArgs));
}
}
public static function getInstanceFields(c:Class<Dynamic>):Array<String> {
if (c == null)
return null;
if (c == String) {
return [
'substr', 'charAt', 'charCodeAt', 'indexOf', 'lastIndexOf', 'split', 'toLowerCase', 'toUpperCase', 'toString', 'length'
];
}
var reflection = new ReflectionClass(Syntax.nativeClassName(c));
var methods = new NativeArray();
for (method in reflection.getMethods()) {
if (!method.isStatic()) {
var name = method.getName();
if (!isServiceFieldName(name)) {
methods.array_push(name);
}
}
}
var properties = new NativeArray();
for (property in reflection.getProperties()) {
if (!property.isStatic()) {
var name = property.getName();
if (!isServiceFieldName(name)) {
properties.array_push(name);
}
}
}
properties = Global.array_diff(properties, methods);
var fields = Global.array_merge(properties, methods);
return @:privateAccess Array.wrap(fields);
}
public static function getClassFields(c:Class<Dynamic>):Array<String> {
if (c == null)
return null;
if (c == String)
return ['fromCharCode'];
var phpName = Syntax.nativeClassName(c);
var reflection = new ReflectionClass(phpName);
var methods = new NativeArray();
for (m in reflection.getMethods(ReflectionMethod.IS_STATIC)) {
var name = m.getName();
if (!isServiceFieldName(name) && phpName == m.getDeclaringClass().getName()) {
methods.array_push(name);
}
}
var properties = new NativeArray();
for (p in reflection.getProperties(ReflectionProperty.IS_STATIC)) {
var name = p.getName();
if (!isServiceFieldName(name) && phpName == p.getDeclaringClass().getName()) {
properties.array_push(name);
}
}
properties = Global.array_diff(properties, methods);
var fields = Global.array_merge(properties, methods);
return @:privateAccess Array.wrap(fields);
}
public static function getEnumConstructs(e:Enum<Dynamic>):Array<String> {
if (e == null)
return null;
return @:privateAccess Array.wrap(Syntax.call(e, '__hx__list'));
}
public static function typeof(v:Dynamic):ValueType {
if (v == null)
return TNull;
if (v.is_object()) {
if (Reflect.isFunction(v))
return TFunction;
if (Std.isOfType(v, StdClass))
return TObject;
if (Boot.isClass(v))
return TObject;
var hxClass = Boot.getClass(Global.get_class(v));
if (Boot.isEnumValue(v))
return TEnum(cast hxClass);
return TClass(cast hxClass);
}
if (v.is_bool())
return TBool;
if (v.is_int())
return TInt;
if (v.is_float())
return TFloat;
if (v.is_string())
return TClass(String);
return TUnknown;
}
public static function enumEq<T:EnumValue>(a:T, b:T):Bool {
if (Syntax.strictEqual(a, b))
return true;
if (a == null || b == null)
return false;
try {
if (!Syntax.instanceof(a, (Global.get_class(cast b):String)))
return false;
if (enumIndex(a) != enumIndex(b))
return false;
var aParams:NativeIndexedArray<Dynamic> = Boot.castEnumValue(a).params;
var bParams:NativeIndexedArray<Dynamic> = Boot.castEnumValue(b).params;
for (i in 0...Global.count(aParams)) {
// enums
if (Boot.isEnumValue(aParams[i])) {
if (!enumEq(aParams[i], bParams[i])) {
return false;
}
// everything else
} else if (!inline Boot.equal(aParams[i], bParams[i])) {
return false;
}
}
return true;
} catch (e:Dynamic) {
return false;
}
}
public inline static function enumConstructor(e:EnumValue):String {
return Boot.castEnumValue(e).tag;
}
public inline static function enumParameters(e:EnumValue):Array<Dynamic> {
return @:privateAccess Array.wrap(Boot.castEnumValue(e).params);
}
public inline static function enumIndex(e:EnumValue):Int {
return Boot.castEnumValue(e).index;
}
public static function allEnums<T>(e:Enum<T>):Array<T> {
if (e == null)
return null;
var phpName = Syntax.nativeClassName(e);
var result = [];
for (name in getEnumConstructs(e)) {
var reflection = new ReflectionMethod(phpName, name);
if (reflection.getNumberOfParameters() == 0) {
result.push(reflection.invoke(null));
}
}
return result;
}
/**
check if specified `name` is a special field name generated by compiler.
**/
static inline function isServiceFieldName(name:String):Bool {
return (name == '__construct' || name.indexOf('__hx_') == 0);
}
}

View File

@ -0,0 +1,103 @@
package haxe;
import php.Throwable;
import php.NativeAssocArray;
import php.NativeIndexedArray;
@:coreApi
class Exception extends NativeException {
public var message(get,never):String;
public var stack(get,never):CallStack;
public var previous(get,never):Null<Exception>;
public var native(get,never):Any;
@:noCompletion var __exceptionStack:Null<CallStack>;
@:noCompletion var __nativeException:Throwable;
@:noCompletion var __skipStack:Int = 0;
@:noCompletion var __previousException:Null<Exception>;
static function caught(value:Any):Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else if(Std.isOfType(value, Throwable)) {
return new Exception((value:Throwable).getMessage(), null, value);
} else {
return new ValueException(value, null, value);
}
}
static function thrown(value:Any):Any {
if(Std.isOfType(value, Exception)) {
return (value:Exception).native;
} else if(Std.isOfType(value, Throwable)) {
return value;
} else {
var e = new ValueException(value);
e.__skipStack = 1;
return e;
}
}
public function new(message:String, ?previous:Exception, ?native:Any) {
super(message, 0, previous);
this.__previousException = previous;
if(native != null && Std.isOfType(native, Throwable)) {
__nativeException = native;
} else {
__nativeException = cast this;
}
}
function unwrap():Any {
return __nativeException;
}
public function toString():String {
return message;
}
public function details():String {
return inline CallStack.exceptionToString(this);
}
function get_message():String {
return this.getMessage();
}
function get_previous():Null<Exception> {
return __previousException;
}
final function get_native():Any {
return __nativeException;
}
function get_stack():CallStack {
return switch __exceptionStack {
case null:
var nativeTrace = NativeStackTrace.complementTrace(__nativeException.getTrace(), native);
__exceptionStack = NativeStackTrace.toHaxe(nativeTrace, __skipStack);
case s: s;
}
}
}
@:dox(hide)
@:noCompletion
@:native('Exception')
private extern class NativeException {
@:noCompletion private function new(?message:String, ?code:Int, ?previous:NativeException):Void;
@:noCompletion private var code:Int;
@:noCompletion private var file:String;
@:noCompletion private var line:Int;
@:noCompletion final private function getPrevious():Throwable;
@:noCompletion private function getMessage():String;
@:noCompletion private function getCode():Int;
@:noCompletion private function getFile():String;
@:noCompletion private function getLine():Int;
@:noCompletion private function getTrace():NativeIndexedArray<NativeAssocArray<Dynamic>>;
@:noCompletion private function getTraceAsString():String;
@:noCompletion @:phpMagic private function __toString():String;
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe;
import php.*;
import haxe.format.JsonPrinter;
@:coreApi
class Json {
public static inline function parse(text:String):Dynamic {
#if haxeJSON
return haxe.format.JsonParser.parse(text);
#else
return phpJsonDecode(text);
#end
}
public static inline function stringify(value:Dynamic, ?replacer:(key:Dynamic, value:Dynamic) -> Dynamic, ?space:String):String {
#if haxeJSON
return JsonPrinter.print(value, replacer, space);
#else
return phpJsonEncode(value, replacer, space);
#end
}
static function phpJsonDecode(json:String):Dynamic {
var value = Global.json_decode(json);
if (value == null && Global.json_last_error() != Const.JSON_ERROR_NONE) {
throw Global.json_last_error_msg();
}
return convertAfterDecode(value);
}
static function convertAfterDecode(value:Dynamic):Dynamic {
if (Global.is_object(value)) {
var result = new NativeAssocArray();
var data = Syntax.array(value);
Syntax.foreach(data, function(fieldName:String, fieldValue:Dynamic) {
result[fieldName] = convertAfterDecode(fieldValue);
});
return Boot.createAnon(result);
}
if (Global.is_array(value)) {
var result = new NativeIndexedArray();
Syntax.foreach(value, function(index:Int, item:Dynamic) {
result[index] = convertAfterDecode(item);
});
return @:privateAccess Array.wrap(result);
}
return value;
}
static function phpJsonEncode(value:Dynamic, ?replacer:(key:Dynamic, value:Dynamic) -> Dynamic, ?space:String):String {
if (null != replacer || null != space) {
return JsonPrinter.print(value, replacer, space);
}
var json = Global.json_encode(convertBeforeEncode(value));
if (Global.json_last_error() != Const.JSON_ERROR_NONE) {
return throw Global.json_last_error_msg();
}
return json;
}
static function convertBeforeEncode(value:Dynamic):Dynamic {
if (Std.isOfType(value, Array)) {
var result = new NativeIndexedArray();
Syntax.foreach(value.arr, function(index:Int, item:Dynamic) {
result[index] = convertBeforeEncode(item);
});
return result;
}
if (Global.is_object(value)) {
var result = {};
Syntax.foreach(value, function(fieldName:String, fieldValue:Dynamic) {
Syntax.setField(result, fieldName, convertBeforeEncode(fieldValue));
});
return result;
}
if (Global.is_float(value) && !Global.is_finite(value)) {
return null;
}
return value;
}
}

View File

@ -0,0 +1,115 @@
package haxe;
import php.*;
import haxe.CallStack.StackItem;
private typedef NativeTrace = NativeIndexedArray<NativeAssocArray<Dynamic>>;
/**
Do not use manually.
**/
@:dox(hide)
@:noCompletion
@:allow(haxe.Exception)
class NativeStackTrace {
/**
If defined this function will be used to transform call stack entries.
@param String - generated php file name.
@param Int - Line number in generated file.
**/
static public var mapPosition:String->Int->Null<{?source:String, ?originalLine:Int}>;
static var lastExceptionTrace:Null<NativeTrace>;
@:ifFeature('haxe.NativeStackTrace.exceptionStack')
static public function saveStack(e:Throwable) {
var nativeTrace = e.getTrace();
// Reduce exception stack to the place where exception was caught
var currentTrace = Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS);
var count = Global.count(currentTrace);
for (i in -(count - 1)...1) {
var exceptionEntry:NativeAssocArray<Dynamic> = Global.end(nativeTrace);
if (!Global.isset(exceptionEntry['file']) || !Global.isset(currentTrace[-i]['file'])) {
Global.array_pop(nativeTrace);
} else if (currentTrace[-i]['file'] == exceptionEntry['file'] && currentTrace[-i]['line'] == exceptionEntry['line']) {
Global.array_pop(nativeTrace);
} else {
break;
}
}
// Remove arguments from trace to avoid blocking some objects from GC
var count = Global.count(nativeTrace);
for (i in 0...count) {
nativeTrace[i]['args'] = new NativeArray();
}
lastExceptionTrace = complementTrace(nativeTrace, e);
}
static public inline function callStack():NativeTrace {
return Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS);
}
static public function exceptionStack():NativeTrace {
return lastExceptionTrace == null ? new NativeIndexedArray() : lastExceptionTrace;
}
static public function toHaxe(native:NativeTrace, skip:Int = 0):Array<StackItem> {
var result = [];
var count = Global.count(native);
for (i in 0...count) {
if(skip > i) {
continue;
}
var entry = native[i];
var item = null;
if (i + 1 < count) {
var next = native[i + 1];
if (!Global.isset(next['function']))
next['function'] = '';
if (!Global.isset(next['class']))
next['class'] = '';
if ((next['function'] : String).indexOf('{closure}') >= 0) {
item = LocalFunction();
} else if (Global.strlen(next['class']) > 0 && Global.strlen(next['function']) > 0) {
var cls = Boot.getClassName(next['class']);
item = Method(cls, next['function']);
}
}
if (Global.isset(entry['file'])) {
if (mapPosition != null) {
var pos = mapPosition(entry['file'], entry['line']);
if (pos != null && pos.source != null && pos.originalLine != null) {
entry['file'] = pos.source;
entry['line'] = pos.originalLine;
}
}
result.push(FilePos(item, entry['file'], entry['line']));
} else if (item != null) {
result.push(item);
}
}
return result;
}
static function complementTrace(nativeTrace:NativeTrace, e:Throwable):NativeTrace {
var thrownAt = new NativeAssocArray<Dynamic>();
thrownAt['function'] = '';
thrownAt['line'] = e.getLine();
thrownAt['file'] = e.getFile();
thrownAt['class'] = '';
thrownAt['args'] = new NativeArray();
Global.array_unshift(nativeTrace, thrownAt);
return nativeTrace;
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe;
import php.*;
import haxe.io.Bytes;
import haxe.crypto.Base64;
@:coreApi
class Resource {
static function cleanName(name:String):String {
return ~/[\\\/:?"*<>|]/.replace(name, '_');
}
static function getDir():String {
var pathToRoot = '/../..';
#if php_prefix
pathToRoot += '/..';
for (i in 0...Global.substr_count(Boot.getPrefix(), '\\')) {
pathToRoot += '/..';
}
#end
return Global.dirname(Const.__FILE__) + pathToRoot + "/res";
}
@:access(haxe.io.Path.escape)
static function getPath(name:String):String {
return getDir() + '/' + haxe.io.Path.escape(name);
}
@:access(haxe.io.Path.unescape)
public static function listNames():Array<String> {
var a = sys.FileSystem.readDirectory(getDir());
if (a[0] == '.')
a.shift();
if (a[0] == '..')
a.shift();
return a.map(function(s) return haxe.io.Path.unescape(s));
}
public static function getString(name:String):String {
var path = getPath(name);
return if (!sys.FileSystem.exists(path))
null;
else
sys.io.File.getContent(path);
}
public static function getBytes(name:String):haxe.io.Bytes {
var path = getPath(name);
return if (!sys.FileSystem.exists(path))
null;
else
sys.io.File.getBytes(path);
}
}

View File

@ -0,0 +1,50 @@
package haxe;
import php.*;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
private typedef NativeRest<T> = NativeIndexedArray<T>;
@:coreApi
@:semantics(value)
abstract Rest<T>(NativeRest<T>) {
public var length(get,never):Int;
inline function get_length():Int
return Global.count(this);
@:from
static public inline function of<T>(array:Array<T>):Rest<T>
return new Rest(@:privateAccess array.arr);
inline function new(a:NativeIndexedArray<T>):Void
this = a;
@:arrayAccess inline function get(index:Int):T
return this[index];
@:to public inline function toArray():Array<T>
return @:privateAccess Array.wrap(this);
public inline function iterator():RestIterator<T>
return new RestIterator<T>(this);
public inline function keyValueIterator():RestKeyValueIterator<T>
return new RestKeyValueIterator<T>(this);
public inline function append(item:T):Rest<T> {
var result = this;
result.push(item);
return new Rest(result);
}
public inline function prepend(item:T):Rest<T> {
var result = this;
Global.array_unshift(result, item);
return new Rest(result);
}
public function toString():String {
return inline Boot.stringifyNativeIndexedArray(this);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe;
import php.Global;
@:coreApi
@:deprecated('haxe.Utf8 is deprecated. Use UnicodeString instead.')
class Utf8 {
var __b:String;
public function new(?size:Int):Void {
__b = '';
}
public function addChar(c:Int):Void {
__b += uchr(c);
}
public function toString():String {
return __b;
}
public static function encode(s:String):String {
return Global.utf8_encode(s);
}
public static function decode(s:String):String {
return Global.utf8_decode(s);
}
public static function iter(s:String, chars:Int->Void):Void {
var len = length(s);
for (i in 0...len) {
chars(charCodeAt(s, i));
}
}
public static function charCodeAt(s:String, index:Int):Int {
return uord(sub(s, index, 1));
}
static function uchr(i:Int):String {
return Global.mb_convert_encoding(Global.pack('N', i), 'UTF-8', 'UCS-4BE');
}
static function uord(s:String):Int {
var c = Global.unpack('N', Global.mb_convert_encoding(s, 'UCS-4BE', 'UTF-8'));
return c[1];
}
public static function validate(s:String):Bool {
return Global.mb_check_encoding(s, enc);
}
public static function length(s:String):Int {
return Global.mb_strlen(s, enc);
}
public static function compare(a:String, b:String):Int {
return Global.strcmp(a, b);
}
public static function sub(s:String, pos:Int, len:Int):String {
return Global.mb_substr(s, pos, len, enc);
}
private static inline var enc = "UTF-8";
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.crypto;
import php.Global.*;
import php.Syntax;
import php.NativeArray;
import haxe.io.Bytes;
class Base64 {
public static var CHARS(default, null) = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
public static var BYTES(default, null) = haxe.io.Bytes.ofString(CHARS);
public static var URL_CHARS(default, null) = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
public static var URL_BYTES(default, null) = haxe.io.Bytes.ofString(URL_CHARS);
static final NORMAL_62_63:NativeArray = Syntax.arrayDecl('+', '/');
static final URL_62_63:NativeArray = Syntax.arrayDecl('-', '_');
public static inline function encode(bytes:Bytes, complement = true):String {
var result = base64_encode(bytes.toString());
return (complement ? result : rtrim(result, "="));
}
public static inline function decode(str:String, complement = true):Bytes {
if (!complement) {
switch (strlen(str) % 3) {
case 1:
str += "==";
case 2:
str += "=";
default:
}
}
return Bytes.ofString(base64_decode(str, true));
}
public static inline function urlEncode(bytes:Bytes, complement = false):String {
var result = str_replace(NORMAL_62_63, URL_62_63, base64_encode(bytes.toString()));
return (complement ? result : rtrim(result, "="));
}
public static inline function urlDecode(str:String, complement = false):Bytes {
if (complement) {
switch (strlen(str) % 3) {
case 1:
str += "==";
case 2:
str += "=";
default:
}
}
return Bytes.ofString(base64_decode(str_replace(URL_62_63, NORMAL_62_63, str), true));
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.crypto;
import php.Global;
import haxe.io.Bytes;
class Md5 {
public static inline function encode(s:String):String {
return Global.md5(s);
}
public static inline function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(Global.md5(b.getData(), true));
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.crypto;
import php.Global;
import haxe.io.Bytes;
class Sha1 {
public static inline function encode(s:String):String {
return Global.sha1(s);
}
public static inline function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(Global.sha1(b.getData(), true));
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.crypto;
import php.Global;
import haxe.io.Bytes;
class Sha224 {
public static inline function encode(s:String):String {
return Global.hash('sha224', s);
}
public static function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(Global.hash('sha224', b.getData(), true));
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.crypto;
import php.Global;
import haxe.io.Bytes;
class Sha256 {
public static inline function encode(s:String):String {
return Global.hash('sha256', s);
}
public static function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(Global.hash('sha256', b.getData(), true));
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.ds;
import php.Syntax;
import php.Global;
import php.NativeArray;
import php.NativeIndexedArray;
@:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
var data:NativeIndexedArray<T>;
public function new():Void {
data = new NativeIndexedArray();
}
public inline function set(key:Int, value:T):Void {
data[key] = value;
}
public inline function get(key:Int):Null<T> {
return Syntax.coalesce(data[key], null);
}
public inline function exists(key:Int):Bool {
return Global.array_key_exists(key, data);
}
public function remove(key:Int):Bool {
if (Global.array_key_exists(key, data)) {
Global.unset(data[key]);
return true;
}
return false;
}
public inline function keys():Iterator<Int> {
return Global.array_keys(data).iterator();
}
@:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "anon_read.iterator")
public inline function iterator():Iterator<T> {
return Global.array_values(data).iterator();
}
@:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "anon_read.keyValueIterator")
public inline function keyValueIterator():KeyValueIterator<Int, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public inline function copy():IntMap<T> {
return Syntax.clone(this);
}
public function toString():String {
var parts = new NativeArray();
Syntax.foreach(data, function(key:Int, value:T) {
Global.array_push(parts, '$key => ' + Std.string(value));
});
return '{' + Global.implode(', ', parts) + '}';
}
public inline function clear():Void {
data = new NativeIndexedArray();
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.ds;
import php.*;
@:coreApi
class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
var _keys:NativeAssocArray<K>;
var _values:NativeAssocArray<V>;
public function new():Void {
_keys = new NativeAssocArray();
_values = new NativeAssocArray();
}
public function set(key:K, value:V):Void {
var id = Global.spl_object_hash(key);
_keys[id] = key;
_values[id] = value;
}
public function get(key:K):Null<V> {
var id = Global.spl_object_hash(key);
return Global.isset(_values[id]) ? _values[id] : null;
}
public function exists(key:K):Bool {
return Global.array_key_exists(Global.spl_object_hash(key), _values);
}
public function remove(key:K):Bool {
var id = Global.spl_object_hash(key);
if (Global.array_key_exists(id, _values)) {
Global.unset(_keys[id], _values[id]);
return true;
} else {
return false;
}
}
public inline function keys():Iterator<K> {
return _keys.iterator();
}
@:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "anon_read.iterator")
public inline function iterator():Iterator<V> {
return _values.iterator();
}
@:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "anon_read.keyValueIterator")
public inline function keyValueIterator():KeyValueIterator<K, V> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public inline function copy():ObjectMap<K, V> {
return Syntax.clone(this);
}
public function toString():String {
var s = "{";
var it = keys();
for (i in it) {
s += Std.string(i);
s += " => ";
s += Std.string(get(i));
if (it.hasNext())
s += ", ";
}
return s + "}";
}
public inline function clear():Void {
_keys = new NativeAssocArray();
_values = new NativeAssocArray();
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.ds;
import php.Syntax;
import php.Global;
import php.NativeArray;
import php.NativeAssocArray;
import haxe.Constraints;
@:coreApi class StringMap<T> implements IMap<String, T> {
private var data:NativeAssocArray<T>;
public inline function new():Void {
data = new NativeAssocArray();
}
public inline function set(key:String, value:T):Void {
data[key] = value;
}
public inline function get(key:String):Null<T> {
return Syntax.coalesce(data[key], null);
}
public inline function exists(key:String):Bool {
return Global.array_key_exists(key, data);
}
public function remove(key:String):Bool {
if (Global.array_key_exists(key, data)) {
Global.unset(data[key]);
return true;
} else {
return false;
}
}
public inline function keys():Iterator<String> {
return Global.array_map('strval', Global.array_keys(data)).iterator();
}
@:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "anon_read.iterator")
public inline function iterator():Iterator<T> {
return data.iterator();
}
@:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "anon_read.keyValueIterator")
public inline function keyValueIterator():KeyValueIterator<String, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public inline function copy():StringMap<T> {
return Syntax.clone(this);
}
public function toString():String {
var parts = new NativeArray();
Syntax.foreach(data, function(key:String, value:T) {
Global.array_push(parts, '$key => ' + Std.string(value));
});
return '{' + Global.implode(', ', parts) + '}';
}
public inline function clear():Void {
data = new NativeAssocArray();
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.ds;
import php.*;
private class PhpVectorData<T> {
public var length:Int;
public var data:NativeIndexedArray<T>;
public inline function new(length:Int) {
this.length = length;
data = new NativeIndexedArray();
}
}
private typedef VectorData<T> = PhpVectorData<T>;
abstract Vector<T>(VectorData<T>) {
public var length(get, never):Int;
public inline function new(length:Int) {
this = new VectorData(length);
}
@:op([]) public inline function get(index:Int):T {
return Syntax.coalesce(this.data[index], null);
}
@:op([]) public inline function set(index:Int, val:T):T {
return this.data[index] = val;
}
inline function get_length():Int {
return this.length;
}
public static function blit<T>(src:Vector<T>, srcPos:Int, dest:Vector<T>, destPos:Int, len:Int):Void {
if (src == dest) {
if (srcPos < destPos) {
var i = srcPos + len;
var j = destPos + len;
for (k in 0...len) {
i--;
j--;
src[j] = src[i];
}
} else if (srcPos > destPos) {
var i = srcPos;
var j = destPos;
for (k in 0...len) {
src[j] = src[i];
i++;
j++;
}
}
} else {
for (i in 0...len) {
dest[destPos + i] = src[srcPos + i];
}
}
}
public function toArray():Array<T> {
var result = [];
@:privateAccess result.length = length;
for (i in 0...length) {
@:privateAccess result.arr.push(get(i));
}
return result;
}
public inline function toData():VectorData<T> {
return this;
}
static public inline function fromData<T>(data:VectorData<T>):Vector<T> {
return cast data;
}
static public inline function fromArrayCopy<T>(array:Array<T>):Vector<T> {
var vectorData = new VectorData(array.length);
vectorData.data = @:privateAccess array.arr;
return cast vectorData;
}
public inline function copy<T>():Vector<T> {
return cast Syntax.clone(this);
}
public function join<T>(sep:String):String {
if (this.length == 0) {
return '';
}
var result = Std.string(get(0));
for (i in 1...this.length) {
result = Syntax.concat(result, Syntax.concat(sep, Std.string(get(i))));
}
return result;
}
public inline function map<S>(f:T->S):Vector<S> {
var result = new Vector(this.length);
Syntax.foreach(this.data, function(key:Int, value:T) {
result[key] = f(value);
});
return result;
}
public inline function sort<T>(f:T->T->Int):Void {
Global.usort(this.data, f);
}
}

View File

@ -0,0 +1,273 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.format;
import php.Syntax;
import php.Global;
import php.NativeString;
using haxe.format.JsonParser;
class JsonParser {
static public inline function parse(str:String):Dynamic {
return new JsonParser(str).doParse();
}
var str:NativeString;
var pos:Int;
function new(str:String) {
this.str = str;
this.pos = 0;
}
function doParse():Dynamic {
var result = parseRec();
var c;
while (!StringTools.isEof(c = nextChar())) {
switch (c) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// allow trailing whitespace
default:
invalidChar();
}
}
return result;
}
function parseRec():Dynamic {
while (true) {
var c = nextChar();
switch (c) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// loop
case '{'.code:
var obj = {}, field = null, comma:Null<Bool> = null;
while (true) {
var c = nextChar();
switch (c) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// loop
case '}'.code:
if (field != null || comma == false)
invalidChar();
return obj;
case ':'.code:
if (field == null)
invalidChar();
Reflect.setField(obj, field, parseRec());
field = null;
comma = true;
case ','.code:
if (comma) comma = false else invalidChar();
case '"'.code:
if (field != null || comma) invalidChar();
field = parseString();
default:
invalidChar();
}
}
case '['.code:
var arr = [], comma:Null<Bool> = null;
while (true) {
var c = nextChar();
switch (c) {
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
// loop
case ']'.code:
if (comma == false) invalidChar();
return arr;
case ','.code:
if (comma) comma = false else invalidChar();
default:
if (comma) invalidChar();
pos--;
arr.push(parseRec());
comma = true;
}
}
case 't'.code:
var save = pos;
if (nextChar() != 'r'.code || nextChar() != 'u'.code || nextChar() != 'e'.code) {
pos = save;
invalidChar();
}
return true;
case 'f'.code:
var save = pos;
if (nextChar() != 'a'.code || nextChar() != 'l'.code || nextChar() != 's'.code || nextChar() != 'e'.code) {
pos = save;
invalidChar();
}
return false;
case 'n'.code:
var save = pos;
if (nextChar() != 'u'.code || nextChar() != 'l'.code || nextChar() != 'l'.code) {
pos = save;
invalidChar();
}
return null;
case '"'.code:
return parseString();
case '0'.code, '1'.code, '2'.code, '3'.code, '4'.code, '5'.code, '6'.code, '7'.code, '8'.code, '9'.code, '-'.code:
return parseNumber(c);
default:
invalidChar();
}
}
}
function parseString() {
var start = pos;
var buf:NativeString = null;
while (true) {
var c = nextChar();
if (c == '"'.code)
break;
if (c == '\\'.code) {
if (buf == null) {
buf = '';
}
buf = buf.addSub(str, start, pos - start - 1);
c = nextChar();
switch (c) {
case "r".code:
buf = Syntax.concat(buf, "\r");
case "n".code:
buf = Syntax.concat(buf, "\n");
case "t".code:
buf = Syntax.concat(buf, "\t");
case "b".code:
buf = Syntax.concat(buf, Global.chr(8));
case "f".code:
buf = Syntax.concat(buf, Global.chr(12));
case "/".code, '\\'.code, '"'.code:
buf = Syntax.concat(buf, Global.mb_chr(c));
case 'u'.code:
var uc = Std.parseInt("0x" + str.substr(pos, 4));
pos += 4;
buf = Syntax.concat(buf, Global.mb_chr(uc));
default:
throw "Invalid escape sequence \\" + String.fromCharCode(c) + " at position " + (pos - 1);
}
start = pos;
}
// ensure utf8 chars are not cut
else if (c >= 0x80) {
pos++;
if (c >= 0xFC)
pos += 4;
else if (c >= 0xF8)
pos += 3;
else if (c >= 0xF0)
pos += 2;
else if (c >= 0xE0)
pos++;
} else if (StringTools.isEof(c))
throw "Unclosed string";
}
if (buf == null) {
return str.substr(start, pos - start - 1);
} else {
return buf.addSub(str, start, pos - start - 1);
}
}
inline function parseNumber(c:Int):Dynamic {
var start = pos - 1;
var minus = c == '-'.code, digit = !minus, zero = c == '0'.code;
var point = false, e = false, pm = false, end = false;
while (true) {
c = nextChar();
switch (c) {
case '0'.code:
if (zero && !point)
invalidNumber(start);
if (minus) {
minus = false;
zero = true;
}
digit = true;
case '1'.code, '2'.code, '3'.code, '4'.code, '5'.code, '6'.code, '7'.code, '8'.code, '9'.code:
if (zero && !point)
invalidNumber(start);
if (minus)
minus = false;
digit = true;
zero = false;
case '.'.code:
if (minus || point || e)
invalidNumber(start);
digit = false;
point = true;
case 'e'.code, 'E'.code:
if (minus || zero || e)
invalidNumber(start);
digit = false;
e = true;
case '+'.code, '-'.code:
if (!e || pm)
invalidNumber(start);
digit = false;
pm = true;
default:
if (!digit)
invalidNumber(start);
pos--;
end = true;
}
if (end)
break;
}
var f = Std.parseFloat(str.substr(start, pos - start));
var i = Std.int(f);
return if (i == f) i else f;
}
inline function nextChar() {
return fastCodeAt(str, pos++);
}
function invalidChar() {
pos--; // rewind
throw "Invalid char " + fastCodeAt(str, pos) + " at position " + pos;
}
function invalidNumber(start:Int) {
throw "Invalid number at position " + start + ": " + str.substr(start, pos - start);
}
// TODO: rewrite the parser using a buffer instead of a string as the data source
static inline function fastCodeAt(s:NativeString, pos:Int):Int {
return pos >= Global.strlen(s) ? 0 : Global.ord(s[pos]);
}
static inline function substr(s:NativeString, pos:Int, ?length:Int):NativeString {
return Global.substr(s, pos, length);
}
static inline function addSub(buf:NativeString, s:NativeString, pos:Int, length:Int):NativeString {
return Syntax.concat(buf, Global.substr(s, pos, length));
}
}

View File

@ -0,0 +1,169 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.io;
import php.Global;
import php.Syntax;
class Bytes {
public var length(default, null):Int;
var b:BytesData;
function new(length:Int, b:BytesData):Void {
this.length = length;
this.b = b;
}
public inline function get(pos:Int):Int {
return b.get(pos);
}
public inline function set(pos:Int, v:Int):Void {
b.set(pos, v);
}
public inline function blit(pos:Int, src:Bytes, srcpos:Int, len:Int):Void {
if (pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length) {
throw Error.OutsideBounds;
} else {
b.blit(pos, src.b, srcpos, len);
}
}
public inline function fill(pos:Int, len:Int, value:Int):Void {
b.fill(pos, len, value);
}
public inline function sub(pos:Int, len:Int):Bytes {
if (pos < 0 || len < 0 || pos + len > length) {
throw Error.OutsideBounds;
} else {
return new Bytes(len, b.sub(pos, len));
}
}
public inline function compare(other:Bytes):Int {
return b.compare(other.b);
}
public function getDouble(pos:Int):Float {
return FPHelper.i64ToDouble(getInt32(pos), getInt32(pos + 4));
}
public function getFloat(pos:Int):Float {
var b = new haxe.io.BytesInput(this, pos, 4);
return b.readFloat();
}
public function setDouble(pos:Int, v:Float):Void {
var i = FPHelper.doubleToI64(v);
setInt32(pos, i.low);
setInt32(pos + 4, i.high);
}
public function setFloat(pos:Int, v:Float):Void {
setInt32(pos, FPHelper.floatToI32(v));
}
public inline function getUInt16(pos:Int):Int {
return get(pos) | (get(pos + 1) << 8);
}
public inline function setUInt16(pos:Int, v:Int):Void {
set(pos, v);
set(pos + 1, v >> 8);
}
public inline function getInt32(pos:Int):Int {
var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos + 3) << 24);
return if (v & 0x80000000 != 0) v | 0x80000000 else v;
}
public inline function getInt64(pos:Int):haxe.Int64 {
return haxe.Int64.make(getInt32(pos + 4), getInt32(pos));
}
public inline function setInt32(pos:Int, v:Int):Void {
set(pos, v);
set(pos + 1, v >> 8);
set(pos + 2, v >> 16);
set(pos + 3, v >>> 24);
}
public inline function setInt64(pos:Int, v:haxe.Int64):Void {
setInt32(pos, v.low);
setInt32(pos + 4, v.high);
}
public inline function getString(pos:Int, len:Int, ?encoding:Encoding):String {
if (pos < 0 || len < 0 || pos + len > length) {
throw Error.OutsideBounds;
} else {
// no need to handle encoding, because PHP strings are binary safe.
return b.getString(pos, len);
}
}
@:deprecated("readString is deprecated, use getString instead")
@:noCompletion
public inline function readString(pos:Int, len:Int):String {
return getString(pos, len);
}
public function toString():String {
return b;
}
public inline function toHex():String {
return php.Global.bin2hex(b.toString());
}
public inline function getData():BytesData {
return b;
}
public static function alloc(length:Int):Bytes {
return new Bytes(length, BytesData.alloc(length));
}
public static inline function ofString(s:String, ?encoding:Encoding):Bytes {
return new Bytes(php.Global.strlen(s), s);
}
public static inline function ofData(b:BytesData):Bytes {
return new Bytes(b.length, b);
}
public static function ofHex(s:String):Bytes {
var len = Global.strlen(s);
if ((len & 1) != 0)
throw "Not a hex string (odd number of digits)";
var b:String = php.Global.hex2bin(s);
return new Bytes(Global.strlen(b), b);
}
public inline static function fastGet(b:BytesData, pos:Int):Int {
return b.get(pos);
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.io;
import php.*;
import haxe.io.Error;
class BytesBuffer {
var b:NativeString;
public var length(get, never):Int;
public function new() {
b = "";
}
public inline function addByte(byte:Int) {
b = Syntax.concat(b, Global.chr(byte));
}
public inline function add(src:Bytes) {
b = Syntax.concat(b, src.getData().toNativeString());
}
public inline function addString(v:String, ?encoding:Encoding) {
b = Syntax.concat(b, v);
}
public function addInt32(v:Int) {
addByte(v & 0xFF);
addByte((v >> 8) & 0xFF);
addByte((v >> 16) & 0xFF);
addByte(v >>> 24);
}
public function addInt64(v:haxe.Int64) {
addInt32(v.low);
addInt32(v.high);
}
public inline function addFloat(v:Float) {
addInt32(FPHelper.floatToI32(v));
}
public inline function addDouble(v:Float) {
addInt64(FPHelper.doubleToI64(v));
}
public inline function addBytes(src:Bytes, pos:Int, len:Int) {
if (pos < 0 || len < 0 || pos + len > src.length) {
throw Error.OutsideBounds;
} else {
b = Syntax.concat(b, src.getData().sub(pos, len).toString());
}
}
public function getBytes():Bytes {
var bytes = @:privateAccess new Bytes(length, b);
b = null;
return bytes;
}
inline function get_length():Int {
return Global.strlen(b);
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.io;
import php.*;
using php.Syntax;
typedef BytesData = BytesDataAbstract;
private class Container {
public var s:NativeString;
public inline function new(s:NativeString)
this.s = s;
}
private abstract BytesDataAbstract(Container) from Container to Container {
public var length(get, never):Int;
public static inline function alloc(length:Int):BytesDataAbstract {
return Global.str_repeat(Global.chr(0), length);
}
@:arrayAccess
public inline function get(pos:Int):Int {
return Global.ord(this.s[pos]);
}
@:arrayAccess
public inline function set(index:Int, val:Int):Void {
this.s[index] = Global.chr(val);
}
public inline function compare(other:BytesDataAbstract):Int {
return Syntax.spaceship(this.s, (other : Container).s);
}
public inline function getString(pos:Int, len:Int):String {
return Global.substr(this.s, pos, len);
}
public inline function sub(pos:Int, len:Int):BytesDataAbstract {
return (Global.substr(this.s, pos, len) : String);
}
public inline function blit(pos:Int, src:BytesDataAbstract, srcpos:Int, len:Int):Void {
this.s = Global.substr(this.s, 0, pos).concat(Global.substr(src, srcpos, len)).concat(Global.substr(this.s, pos + len));
}
public inline function fill(pos:Int, len:Int, value:Int):Void {
this.s = Global.substr(this.s, 0, pos).concat(Global.str_repeat(Global.chr(value), len)).concat(Global.substr(this.s, pos + len));
}
inline function get_length():Int {
return Global.strlen(this.s);
}
@:from
static inline function fromNativeString(s:NativeString):BytesDataAbstract {
return new Container(s);
}
@:to
public inline function toNativeString():NativeString {
return this.s;
}
@:from
static inline function fromString(s:String):BytesDataAbstract {
return new Container(s);
}
@:to
public inline function toString():String {
return this.s;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.io;
class BytesInput extends Input {
var b:BytesData;
var pos:Int;
var len:Int;
var totlen:Int;
public var position(get, set):Int;
public var length(get, never):Int;
public function new(b:Bytes, ?pos:Int, ?len:Int) {
if (pos == null)
pos = 0;
if (len == null)
len = b.length - pos;
if (pos < 0 || len < 0 || pos + len > b.length)
throw Error.OutsideBounds;
this.b = b.getData();
this.pos = pos;
this.len = len;
this.totlen = len;
}
inline function get_position():Int {
return pos;
}
inline function get_length():Int {
return totlen;
}
function set_position(p:Int):Int {
if (p < 0)
p = 0;
else if (p > length)
p = length;
len = totlen - p;
return pos = p;
}
public override function readByte():Int {
if (len == 0)
throw new Eof();
--len;
return b[pos++];
}
public override function readBytes(buf:Bytes, pos, len):Int {
if (pos < 0 || len < 0 || pos + len > buf.length)
throw Error.OutsideBounds;
if (this.len == 0 && len > 0)
throw new Eof();
if (this.len < len)
len = this.len;
buf.getData().blit(pos, b, this.pos, len);
this.pos += len;
this.len -= len;
return len;
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.io;
class BytesOutput extends Output {
var b:BytesBuffer;
public var length(get, never):Int;
public function new() {
b = new BytesBuffer();
}
override function writeByte(c) {
b.addByte(c);
}
override function writeBytes(buf:Bytes, pos, len):Int {
b.addBytes(buf, pos, len);
return len;
}
public function getBytes():Bytes {
return b.getBytes();
}
inline function get_length():Int {
return b.length;
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.io;
import php.*;
class FPHelper {
static var isLittleEndian:Bool = Global.unpack('S', '\x01\x00')[1] == 1;
static var i64tmp = Int64.ofInt(0);
public static inline function i32ToFloat(i:Int):Float {
return Global.unpack('f', Global.pack('l', i))[1];
}
public static inline function floatToI32(f:Float):Int {
return Global.unpack('l', Global.pack('f', f))[1];
}
public static inline function i64ToDouble(low:Int, high:Int):Float {
return Global.unpack('d', Global.pack('ii', isLittleEndian ? low : high, isLittleEndian ? high : low))[1];
}
public static function doubleToI64(v:Float):Int64 {
var a = Global.unpack(isLittleEndian ? 'V2' : 'N2', Global.pack('d', v));
var i64 = i64tmp;
@:privateAccess i64.set_low(a[isLittleEndian ? 1 : 2]);
@:privateAccess i64.set_high(a[isLittleEndian ? 2 : 1]);
return i64;
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.iterators;
import php.Global.*;
import php.NativeString;
class StringIteratorUnicode {
var byteOffset:Int = 0;
var totalBytes:Int;
var s:NativeString;
public inline function new(s:String) {
this.s = s;
totalBytes = strlen(s);
}
public inline function hasNext() {
return byteOffset < totalBytes;
}
public inline function next() {
var code = ord(s[byteOffset]);
if (code < 0xC0) {
byteOffset++;
} else if (code < 0xE0) {
code = ((code - 0xC0) << 6) + ord(s[byteOffset + 1]) - 0x80;
byteOffset += 2;
} else if (code < 0xF0) {
code = ((code - 0xE0) << 12) + ((ord(s[byteOffset + 1]) - 0x80) << 6) + ord(s[byteOffset + 2]) - 0x80;
byteOffset += 3;
} else {
code = ((code - 0xF0) << 18)
+ ((ord(s[byteOffset + 1]) - 0x80) << 12)
+ ((ord(s[byteOffset + 2]) - 0x80) << 6)
+ ord(s[byteOffset + 3])
- 0x80;
byteOffset += 4;
}
return code;
}
static public inline function unicodeIterator(s:String) {
return new StringIteratorUnicode(s);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.iterators;
import php.Global.*;
import php.NativeString;
class StringKeyValueIteratorUnicode {
var charOffset:Int = 0;
var byteOffset:Int = 0;
var totalBytes:Int;
var s:NativeString;
public inline function new(s:String) {
this.s = s;
totalBytes = strlen(s);
}
public inline function hasNext() {
return byteOffset < totalBytes;
}
public inline function next() {
var code = ord(s[byteOffset]);
if (code < 0xC0) {
byteOffset++;
} else if (code < 0xE0) {
code = ((code - 0xC0) << 6) + ord(s[byteOffset + 1]) - 0x80;
byteOffset += 2;
} else if (code < 0xF0) {
code = ((code - 0xE0) << 12) + ((ord(s[byteOffset + 1]) - 0x80) << 6) + ord(s[byteOffset + 2]) - 0x80;
byteOffset += 3;
} else {
code = ((code - 0xF0) << 18)
+ ((ord(s[byteOffset + 1]) - 0x80) << 12)
+ ((ord(s[byteOffset + 2]) - 0x80) << 6)
+ ord(s[byteOffset + 3])
- 0x80;
byteOffset += 4;
}
return {key: charOffset++, value: code};
}
static public inline function unicodeKeyValueIterator(s:String) {
return new StringKeyValueIteratorUnicode(s);
}
}

View File

@ -0,0 +1,401 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.xml;
import php.Global;
import php.Syntax;
import php.NativeString;
using haxe.xml.Parser;
private enum abstract S(Int) {
var IGNORE_SPACES;
var BEGIN;
var BEGIN_NODE;
var TAG_NAME;
var BODY;
var ATTRIB_NAME;
var EQUALS;
var ATTVAL_BEGIN;
var ATTRIB_VAL;
var CHILDS;
var CLOSE;
var WAIT_END;
var WAIT_END_RET;
var PCDATA;
var HEADER;
var COMMENT;
var DOCTYPE;
var CDATA;
var ESCAPE;
}
class XmlParserException {
public var message:String;
public var lineNumber:Int;
public var positionAtLine:Int;
public var position:Int;
public var xml:String;
public function new(message:String, xml:String, position:Int) {
this.xml = xml;
this.message = message;
this.position = position;
lineNumber = 1;
positionAtLine = 0;
for (i in 0...position) {
var c = (xml : NativeString).fastCodeAt(i);
if (c == '\n'.code) {
lineNumber++;
positionAtLine = 0;
} else {
if (c != '\r'.code)
positionAtLine++;
}
}
}
public function toString():String {
return Type.getClassName(Type.getClass(this)) + ": " + message + " at line " + lineNumber + " char " + positionAtLine;
}
}
class Parser {
static var escapes = {
var h = new haxe.ds.StringMap();
h.set("lt", "<");
h.set("gt", ">");
h.set("amp", "&");
h.set("quot", '"');
h.set("apos", "'");
h;
}
static public function parse(str:String, strict = false) {
var doc = Xml.createDocument();
doParse(str, strict, 0, doc);
return doc;
}
static function doParse(str:NativeString, strict:Bool, p:Int = 0, ?parent:Xml):Int {
var xml:Xml = null;
var state = S.BEGIN;
var next = S.BEGIN;
var aname = null;
var start = 0;
var nsubs = 0;
var nbrackets = 0;
var c = str.fastCodeAt(p);
var buf:NativeString = '';
// need extra state because next is in use
var escapeNext = S.BEGIN;
var attrValQuote = -1;
inline function addChild(xml:Xml) {
parent.addChild(xml);
nsubs++;
}
while (!StringTools.isEof(c)) {
switch (state) {
case S.IGNORE_SPACES:
switch (c) {
case '\n'.code, '\r'.code, '\t'.code, ' '.code:
default:
state = next;
continue;
}
case S.BEGIN:
switch (c) {
case '<'.code:
state = S.IGNORE_SPACES;
next = S.BEGIN_NODE;
default:
start = p;
state = S.PCDATA;
continue;
}
case S.PCDATA:
if (c == '<'.code) {
buf = buf.addSub(str, start, p - start);
var child = Xml.createPCData(buf);
buf = '';
addChild(child);
state = S.IGNORE_SPACES;
next = S.BEGIN_NODE;
} else if (c == '&'.code) {
buf = buf.addSub(str, start, p - start);
state = S.ESCAPE;
escapeNext = S.PCDATA;
start = p + 1;
}
case S.CDATA:
if (c == ']'.code && str.fastCodeAt(p + 1) == ']'.code && str.fastCodeAt(p + 2) == '>'.code) {
var child = Xml.createCData(str.substr(start, p - start));
addChild(child);
p += 2;
state = S.BEGIN;
}
case S.BEGIN_NODE:
switch (c) {
case '!'.code:
if (str.fastCodeAt(p + 1) == '['.code) {
p += 2;
if (Global.strtoupper(str.substr(p, 6)) != "CDATA[")
throw new XmlParserException("Expected <![CDATA[", str, p);
p += 5;
state = S.CDATA;
start = p + 1;
} else if (str.fastCodeAt(p + 1) == 'D'.code || str.fastCodeAt(p + 1) == 'd'.code) {
if (Global.strtoupper(str.substr(p + 2, 6)) != "OCTYPE")
throw new XmlParserException("Expected <!DOCTYPE", str, p);
p += 8;
state = S.DOCTYPE;
start = p + 1;
} else if (str.fastCodeAt(p + 1) != '-'.code || str.fastCodeAt(p + 2) != '-'.code)
throw new XmlParserException("Expected <!--", str, p);
else {
p += 2;
state = S.COMMENT;
start = p + 1;
}
case '?'.code:
state = S.HEADER;
start = p;
case '/'.code:
if (parent == null)
throw new XmlParserException("Expected node name", str, p);
start = p + 1;
state = S.IGNORE_SPACES;
next = S.CLOSE;
default:
state = S.TAG_NAME;
start = p;
continue;
}
case S.TAG_NAME:
if (!isValidChar(c)) {
if (p == start)
throw new XmlParserException("Expected node name", str, p);
xml = Xml.createElement(str.substr(start, p - start));
addChild(xml);
state = S.IGNORE_SPACES;
next = S.BODY;
continue;
}
case S.BODY:
switch (c) {
case '/'.code:
state = S.WAIT_END;
case '>'.code:
state = S.CHILDS;
default:
state = S.ATTRIB_NAME;
start = p;
continue;
}
case S.ATTRIB_NAME:
if (!isValidChar(c)) {
var tmp;
if (start == p)
throw new XmlParserException("Expected attribute name", str, p);
tmp = str.substr(start, p - start);
aname = tmp;
if (xml.exists(aname))
throw new XmlParserException("Duplicate attribute [" + aname + "]", str, p);
state = S.IGNORE_SPACES;
next = S.EQUALS;
continue;
}
case S.EQUALS:
switch (c) {
case '='.code:
state = S.IGNORE_SPACES;
next = S.ATTVAL_BEGIN;
default:
throw new XmlParserException("Expected =", str, p);
}
case S.ATTVAL_BEGIN:
switch (c) {
case '"'.code | '\''.code:
buf = '';
state = S.ATTRIB_VAL;
start = p + 1;
attrValQuote = c;
default:
throw new XmlParserException("Expected \"", str, p);
}
case S.ATTRIB_VAL:
switch (c) {
case '&'.code:
buf = buf.addSub(str, start, p - start);
state = S.ESCAPE;
escapeNext = S.ATTRIB_VAL;
start = p + 1;
case '>'.code | '<'.code if (strict):
// HTML allows these in attributes values
throw new XmlParserException("Invalid unescaped " + String.fromCharCode(c) + " in attribute value", str, p);
case _ if (c == attrValQuote):
buf = buf.addSub(str, start, p - start);
var val = buf;
buf = '';
xml.set(aname, val);
state = S.IGNORE_SPACES;
next = S.BODY;
}
case S.CHILDS:
p = doParse(str, strict, p, xml);
start = p;
state = S.BEGIN;
case S.WAIT_END:
switch (c) {
case '>'.code:
state = S.BEGIN;
default:
throw new XmlParserException("Expected >", str, p);
}
case S.WAIT_END_RET:
switch (c) {
case '>'.code:
if (nsubs == 0)
parent.addChild(Xml.createPCData(""));
return p;
default:
throw new XmlParserException("Expected >", str, p);
}
case S.CLOSE:
if (!isValidChar(c)) {
if (start == p)
throw new XmlParserException("Expected node name", str, p);
var v = str.substr(start, p - start);
if (parent == null || parent.nodeType != Element) {
throw new XmlParserException('Unexpected </$v>, tag is not open', str, p);
}
if (v != parent.nodeName)
throw new XmlParserException("Expected </" + parent.nodeName + ">", str, p);
state = S.IGNORE_SPACES;
next = S.WAIT_END_RET;
continue;
}
case S.COMMENT:
if (c == '-'.code && str.fastCodeAt(p + 1) == '-'.code && str.fastCodeAt(p + 2) == '>'.code) {
addChild(Xml.createComment(str.substr(start, p - start)));
p += 2;
state = S.BEGIN;
}
case S.DOCTYPE:
if (c == '['.code)
nbrackets++;
else if (c == ']'.code)
nbrackets--;
else if (c == '>'.code && nbrackets == 0) {
addChild(Xml.createDocType(str.substr(start, p - start)));
state = S.BEGIN;
}
case S.HEADER:
if (c == '?'.code && str.fastCodeAt(p + 1) == '>'.code) {
p++;
var str = str.substr(start + 1, p - start - 2);
addChild(Xml.createProcessingInstruction(str));
state = S.BEGIN;
}
case S.ESCAPE:
if (c == ';'.code) {
var s = str.substr(start, p - start);
if (s.fastCodeAt(0) == '#'.code) {
var c = s.fastCodeAt(1) == 'x'.code ? Std.parseInt("0" + s.substr(1,
Global.strlen(s) - 1)) : Std.parseInt(s.substr(1, Global.strlen(s) - 1));
buf = Syntax.concat(buf, Global.mb_chr(c));
} else if (!escapes.exists(s)) {
if (strict)
throw new XmlParserException("Undefined entity: " + s, str, p);
buf = Syntax.concat(buf, '&$s;');
} else {
buf = Syntax.concat(buf, escapes.get(s));
}
start = p + 1;
state = escapeNext;
} else if (!isValidChar(c) && c != "#".code) {
if (strict)
throw new XmlParserException("Invalid character in entity: " + String.fromCharCode(c), str, p);
buf = Syntax.concat(buf, "&");
buf = buf.addSub(str, start, p - start);
p--;
start = p + 1;
state = escapeNext;
}
}
c = str.fastCodeAt(++p);
}
if (state == S.BEGIN) {
start = p;
state = S.PCDATA;
}
if (state == S.PCDATA) {
if (parent.nodeType == Element) {
throw new XmlParserException("Unclosed node <" + parent.nodeName + ">", str, p);
}
if (p != start || nsubs == 0) {
buf = buf.addSub(str, start, p - start);
addChild(Xml.createPCData(buf));
}
return p;
}
if (!strict && state == S.ESCAPE && escapeNext == S.PCDATA) {
buf = Syntax.concat(buf, "&");
buf = buf.addSub(str, start, p - start);
addChild(Xml.createPCData(buf));
return p;
}
throw new XmlParserException("Unexpected end", str, p);
}
static inline function isValidChar(c) {
return (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || (c >= '0'.code && c <= '9'.code) || c == ':'.code || c == '.'.code
|| c == '_'.code || c == '-'.code;
}
// TODO: rewrite the parser using a buffer instead of a string as the data source
@:allow(haxe.xml.XmlParserException)
static inline function fastCodeAt(s:NativeString, pos:Int):Int {
return pos >= Global.strlen(s) ? 0 : Global.ord(s[pos]);
}
static inline function substr(s:NativeString, pos:Int, ?length:Int):NativeString {
return Global.substr(s, pos, length);
}
static inline function addSub(buf:NativeString, s:NativeString, pos:Int, length:Int):NativeString {
return Syntax.concat(buf, Global.substr(s, pos, length));
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C)2005-2019 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.
*/
package haxe.zip;
@:coreApi
class Compress {
private var level:Int;
public function new(level:Int):Void {
this.level = level;
}
public function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, write:Int} {
var input = src.sub(srcPos, src.length - srcPos);
var data = run(input, level);
dst.blit(dstPos, data, 0, data.length);
return {
done: true,
read: input.length,
write: data.length
};
}
public function setFlushMode(f:FlushMode):Void {}
public function close():Void {}
public static function run(s:haxe.io.Bytes, level:Int):haxe.io.Bytes {
var c = php.Global.gzcompress(s.toString(), level);
return haxe.io.Bytes.ofString(c);
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.
*/
package haxe.zip;
class Uncompress {
public function new(?windowBits:Int) {}
public function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, write:Int} {
var input = src.sub(srcPos, src.length - srcPos);
var data = run(input);
dst.blit(dstPos, data, 0, data.length);
return {
done: true,
read: input.length,
write: data.length
};
}
public function setFlushMode(f:FlushMode) {}
public function close() {}
public static function run(src:haxe.io.Bytes, ?bufsize:Int):haxe.io.Bytes {
var c = php.Global.gzuncompress(src.toString());
return haxe.io.Bytes.ofString(c);
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys;
import php.*;
import haxe.io.Path;
private enum FileKind {
kdir;
kfile;
kother(k:String);
}
@:coreApi
class FileSystem {
public static inline function exists(path:String):Bool {
Global.clearstatcache(true, path);
return Global.file_exists(path);
}
public static inline function rename(path:String, newPath:String):Void {
Global.rename(path, newPath);
}
public static function stat(path:String):FileStat {
Global.clearstatcache(true, path);
var info = Global.stat(path);
if (info == false)
throw 'Unable to stat $path';
var info:NativeArray = info;
return {
gid: info['gid'],
uid: info['uid'],
atime: Date.fromTime(info['atime'] * 1000),
mtime: Date.fromTime(info['mtime'] * 1000),
ctime: Date.fromTime(info['ctime'] * 1000),
dev: info['dev'],
ino: info['ino'],
nlink: info['nlink'],
rdev: info['rdev'],
size: info['size'],
mode: info['mode']
};
}
public static inline function fullPath(relPath:String):String {
return Syntax.shortTernary(Global.realpath(relPath), null);
}
public static function absolutePath(relPath:String):String {
if (Path.isAbsolute(relPath))
return relPath;
return Path.join([Sys.getCwd(), relPath]);
}
static function kind(path:String):FileKind {
Global.clearstatcache(true, path);
var kind = Global.filetype(path);
if (kind == false)
throw 'Failed to check file type $path';
switch (kind) {
case "file":
return kfile;
case "dir":
return kdir;
default:
return kother(kind);
}
}
public static function isDirectory(path:String):Bool {
Global.clearstatcache(true, path);
return Global.is_dir(path);
}
public static function createDirectory(path:String):Void {
Global.clearstatcache(true, path);
if (!Global.is_dir(path))
Global.mkdir(path, 493, true);
}
public static inline function deleteFile(path:String):Void {
Global.unlink(path);
}
public static inline function deleteDirectory(path:String):Void {
Global.rmdir(path);
}
public static function readDirectory(path:String):Array<String> {
var list = [];
var dir = Global.opendir(path);
var file;
while ((file = Global.readdir(dir)) != false) {
if (file != '.' && file != '..') {
list.push(file);
}
}
Global.closedir(dir);
return list;
}
}

View File

@ -0,0 +1,268 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.db;
import php.*;
import sys.db.*;
import php.db.*;
import php.db.Mysqli_result;
@:coreApi class Mysql {
public static function connect(params:{
host:String,
?port:Int,
user:String,
pass:String,
?socket:String,
?database:String
}):Connection {
return new MysqlConnection(params);
}
}
private class MysqlConnection implements Connection {
var db:Mysqli;
public function new(params:{
host:String,
?port:Int,
user:String,
pass:String,
?socket:String,
?database:String
}):Void {
if (params.port == null)
params.port = Std.parseInt(Global.ini_get('mysqli.default_port'));
if (params.socket == null)
params.socket = Global.ini_get('mysqli.default_socket');
if (params.database == null)
params.database = "";
db = new Mysqli(params.host, params.user, params.pass, params.database, params.port, params.socket);
}
public function request(s:String):ResultSet {
var result = db.query(s);
if (result == false)
throw 'Failed to perform db query: ' + db.error;
if (result == true) {
return new WriteMysqlResultSet(db.affected_rows);
}
return new MysqlResultSet(result);
}
public function close():Void {
db.close();
}
public function escape(s:String):String {
return db.escape_string(s);
}
public function quote(s:String):String {
if (s.indexOf("\000") >= 0)
return "x'" + Global.bin2hex(s) + "'";
return "'" + db.escape_string(s) + "'";
}
public function addValue(s:StringBuf, v:Dynamic):Void {
if (Global.is_int(v) || Global.is_null(v)) {
s.add(v);
} else if (Global.is_bool(v)) {
s.add(v ? 1 : 0);
} else {
s.add(quote(Std.string(v)));
}
}
public function lastInsertId():Int {
return db.insert_id;
}
public function dbName():String {
return 'MySQL';
}
public function startTransaction():Void {
var success = db.begin_transaction();
if (!success)
throw 'Failed to start transaction: ' + db.error;
}
public function commit():Void {
var success = db.commit();
if (!success)
throw 'Failed to commit transaction: ' + db.error;
}
public function rollback():Void {
var success = db.rollback();
if (!success)
throw 'Failed to rollback transaction: ' + db.error;
}
}
private class MysqlResultSet implements ResultSet {
static var hxAnonClassName = Boot.getHxAnon().phpClassName;
public var length(get, null):Int;
public var nfields(get, null):Int;
var result:Mysqli_result;
var fetchedRow:NativeAssocArray<Scalar>;
var fieldsInfo:NativeAssocArray<MysqliFieldInfo>;
public function new(result:Mysqli_result) {
this.result = result;
}
public function hasNext():Bool {
if (fetchedRow == null)
fetchNext();
return fetchedRow != null;
}
public function next():Dynamic {
if (fetchedRow == null)
fetchNext();
return withdrawFetched();
}
public function results():List<Dynamic> {
var list = new List();
result.data_seek(0);
var row = result.fetch_object(hxAnonClassName);
while (row != null) {
row = correctObjectTypes(row);
list.add(row);
row = result.fetch_object(hxAnonClassName);
}
return list;
}
public function getResult(n:Int):String {
if (fetchedRow == null)
fetchNext();
return Global.array_values(fetchedRow)[n];
}
public function getIntResult(n:Int):Int {
return Syntax.int(getResult(n));
}
public function getFloatResult(n:Int):Float {
return Syntax.float(getResult(n));
}
public function getFieldsNames():Null<Array<String>> {
var fields = result.fetch_fields();
return [for (field in fields) field.name];
}
function fetchNext() {
var row = result.fetch_assoc();
if (row != null)
fetchedRow = correctArrayTypes(row);
}
function withdrawFetched():Dynamic {
if (fetchedRow == null)
return null;
var row = fetchedRow;
fetchedRow = null;
return Boot.createAnon(row);
}
function correctArrayTypes(row:NativeAssocArray<String>):NativeAssocArray<Scalar> {
var fieldsInfo = getFieldsInfo();
Syntax.foreach(row, function(field:String, value:String) {
row[field] = correctType(value, fieldsInfo[field].type);
});
return cast row;
}
function correctObjectTypes(row:{}):{} {
var fieldsInfo = getFieldsInfo();
Syntax.foreach(row, function(field:String, value:String) {
value = correctType(value, fieldsInfo[field].type);
Syntax.setField(row, field, value);
});
return row;
}
inline function getFieldsInfo():NativeAssocArray<MysqliFieldInfo> {
if (fieldsInfo == null) {
fieldsInfo = cast Syntax.arrayDecl();
Syntax.foreach(result.fetch_fields(), function(_, info) {
fieldsInfo[info.name] = info;
});
}
return fieldsInfo;
}
function correctType(value:String, type:Int):Scalar {
if (value == null)
return null;
if (type == Const.MYSQLI_TYPE_BIT || type == Const.MYSQLI_TYPE_TINY || type == Const.MYSQLI_TYPE_SHORT || type == Const.MYSQLI_TYPE_LONG
|| type == Const.MYSQLI_TYPE_INT24 || type == Const.MYSQLI_TYPE_CHAR) {
return Syntax.int(value);
}
if (type == Const.MYSQLI_TYPE_DECIMAL
|| type == Const.MYSQLI_TYPE_NEWDECIMAL
|| type == Const.MYSQLI_TYPE_FLOAT
|| type == Const.MYSQLI_TYPE_DOUBLE) {
return Syntax.float(value);
}
return value;
}
function get_length()
return result.num_rows;
function get_nfields()
return result.field_count;
}
private class WriteMysqlResultSet extends MysqlResultSet {
var affectedRows:Int = 0;
public function new(affectedRows:Int) {
super(null);
this.affectedRows = affectedRows;
}
override public function hasNext():Bool {
return false;
}
override function fetchNext() {}
override function get_length()
return affectedRows;
override function get_nfields()
return 0;
}

View File

@ -0,0 +1,218 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.db;
import php.*;
import php.Global.*;
import php.db.*;
import sys.db.*;
@:coreApi class Sqlite {
public static function open(file:String):Connection {
return new SQLiteConnection(file);
}
}
private class SQLiteConnection implements Connection {
var db:SQLite3;
public function new(file:String) {
db = new SQLite3(file);
db.enableExceptions(true);
}
public function request(s:String):ResultSet {
var result = db.query(s);
return new SQLiteResultSet(result);
}
public function close():Void {
db.close();
}
public function escape(s:String):String {
return SQLite3.escapeString(s);
}
public function quote(s:String):String {
if (s.indexOf("\000") >= 0)
return "x'" + Global.bin2hex(s) + "'";
return "'" + SQLite3.escapeString(s) + "'";
}
public function addValue(s:StringBuf, v:Dynamic):Void {
if (Global.is_int(v) || Global.is_null(v)) {
s.add(v);
} else if (Global.is_bool(v)) {
s.add(v ? 1 : 0);
} else {
s.add(quote(Std.string(v)));
}
}
public function lastInsertId():Int {
return Syntax.int(db.lastInsertRowID());
}
public function dbName():String {
return 'SQLite';
}
public function startTransaction():Void {
db.query('BEGIN TRANSACTION');
}
public function commit():Void {
db.query('COMMIT');
}
public function rollback():Void {
db.query('ROLLBACK');
}
}
private class SQLiteResultSet implements ResultSet {
public var length(get, null):Int;
public var nfields(get, null):Int;
var cache = new NativeIndexedArray<{}>();
var result:SQLite3Result;
var resultIsDepleted = false;
var fieldsInfo:NativeAssocArray<Int>;
public function new(result:SQLite3Result) {
this.result = result;
}
public function hasNext():Bool {
return switch next() {
case null: false;
case row:
array_unshift(cache, row);
row;
}
}
public function next():Dynamic {
return switch array_shift(cache) {
case null: fetchNext();
case row: row;
}
}
function fetchNext():Null<{}> {
return resultIsDepleted ? null : switch result.fetchArray(Const.SQLITE3_ASSOC) {
case false:
resultIsDepleted = true;
result.finalize();
null;
case row:
Boot.createAnon(correctArrayTypes(row));
}
}
public function cacheAll():NativeIndexedArray<{}> {
var row = fetchNext();
while(row != null) {
cache.push(row);
row = fetchNext();
}
return cache;
}
public function results():List<Dynamic> {
var list = new List();
for(row in cacheAll()) {
list.add(row);
}
return list;
}
function getColumn(n:Int):Any {
return array_values(Syntax.array(current()))[n];
}
public function getResult(n:Int):String {
return Syntax.string(getColumn(n));
}
public function getIntResult(n:Int):Int {
return Syntax.int(getColumn(n));
}
public function getFloatResult(n:Int):Float {
return Syntax.float(getColumn(n));
}
public function getFieldsNames():Null<Array<String>> {
var fieldsInfo = getFieldsInfo();
return Global.array_keys(fieldsInfo);
}
function current():Null<{}> {
return switch reset(cache) {
case false:
switch next() {
case null: null;
case row:
cache.push(row);
row;
}
case row: row;
}
}
function correctArrayTypes(row:NativeAssocArray<String>):NativeAssocArray<Scalar> {
var fieldsInfo = getFieldsInfo();
Syntax.foreach(row, function(field:String, value:String) {
row[field] = correctType(value, fieldsInfo[field]);
});
return cast row;
}
inline function getFieldsInfo():NativeAssocArray<Int> {
if (fieldsInfo == null) {
fieldsInfo = cast Syntax.arrayDecl();
for (i in 0...nfields) {
fieldsInfo[result.columnName(i)] = result.columnType(i);
}
}
return fieldsInfo;
}
function correctType(value:String, type:Int):Scalar {
if (value == null)
return null;
if (type == Const.SQLITE3_INTEGER)
return Syntax.int(value);
if (type == Const.SQLITE3_FLOAT)
return Syntax.float(value);
return value;
}
function get_length():Int
return count(cacheAll());
function get_nfields():Int
return result.numColumns();
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.io;
import php.Global.*;
import php.Global;
@:coreApi class File {
public static function getContent(path:String):String {
return file_get_contents(path);
}
public static function getBytes(path:String):haxe.io.Bytes {
return haxe.io.Bytes.ofString(file_get_contents(path));
}
public static function saveContent(path:String, content:String):Void {
file_put_contents(path, content);
}
public static function saveBytes(path:String, bytes:haxe.io.Bytes):Void {
var f = write(path);
f.write(bytes);
f.close();
}
public static function read(path:String, binary:Bool = true):FileInput {
return @:privateAccess new FileInput(fopen(path, binary ? "rb" : "r"));
}
public static function write(path:String, binary:Bool = true):FileOutput {
return untyped new FileOutput(fopen(path, binary ? "wb" : "w"));
}
public static function append(path:String, binary:Bool = true):FileOutput {
return untyped new FileOutput(fopen(path, binary ? "ab" : "a"));
}
public static function update(path:String, binary:Bool = true):FileOutput {
if (!FileSystem.exists(path)) {
write(path).close();
}
return untyped new FileOutput(fopen(path, binary ? "rb+" : "r+"));
}
public static function copy(srcPath:String, dstPath:String):Void {
Global.copy(srcPath, dstPath);
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.io;
import haxe.io.Eof;
import haxe.io.Error;
import haxe.io.Bytes;
import php.*;
import php.Global.*;
import php.Const.*;
@:coreApi
class FileInput extends haxe.io.Input {
private var __f:Resource;
function new(f:Resource):Void {
__f = f;
}
public override function readByte():Int {
var r = fread(__f, 1);
if (feof(__f))
throw new Eof();
if (r == false)
throw Custom('An error occurred');
return ord(r);
}
public override function readBytes(s:Bytes, p:Int, l:Int):Int {
if (feof(__f))
throw new Eof();
var r = fread(__f, l);
if (r == false)
throw Custom('An error occurred');
if (strlen(r) == 0)
throw new Eof();
var b = Bytes.ofString(r);
s.blit(p, b, 0, strlen(r));
return strlen(r);
}
public override function close():Void {
super.close();
if (__f != null)
fclose(__f);
}
public function seek(p:Int, pos:FileSeek):Void {
var w;
switch (pos) {
case SeekBegin:
w = SEEK_SET;
case SeekCur:
w = SEEK_CUR;
case SeekEnd:
w = SEEK_END;
}
var r = fseek(__f, p, w);
if (r == -1)
throw Custom('An error occurred');
}
public function tell():Int {
var r = ftell(__f);
if (r == false)
throw Custom('An error occurred');
return cast r;
}
public function eof():Bool {
return feof(__f);
}
override function readLine():String {
var r = fgets(__f);
if (false == r)
throw new Eof();
return rtrim(r, "\r\n");
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.io;
import php.*;
import php.Global.*;
import php.Const.*;
@:coreApi
class FileOutput extends haxe.io.Output {
private var __f:Resource;
function new(f:Resource):Void {
__f = f;
}
public override function writeByte(c:Int):Void {
var r = fwrite(__f, chr(c));
if (r == false)
throw haxe.io.Error.Custom('An error occurred');
}
public override function writeBytes(b:haxe.io.Bytes, p:Int, l:Int):Int {
var s = b.getString(p, l);
if (feof(__f))
throw new haxe.io.Eof();
var r = fwrite(__f, s, l);
if (r == false)
throw haxe.io.Error.Custom('An error occurred');
return r;
}
public override function flush():Void {
var r = fflush(__f);
if (r == false)
throw haxe.io.Error.Custom('An error occurred');
}
public override function close():Void {
super.close();
if (__f != null)
fclose(__f);
}
public function seek(p:Int, pos:FileSeek):Void {
var w;
switch (pos) {
case SeekBegin:
w = SEEK_SET;
case SeekCur:
w = SEEK_CUR;
case SeekEnd:
w = SEEK_END;
}
var r = fseek(__f, p, w);
if (r == -1)
throw haxe.io.Error.Custom('An error occurred');
}
public function tell():Int {
var r = ftell(__f);
if (r == false)
throw haxe.io.Error.Custom('An error occurred');
return r;
}
}

View File

@ -0,0 +1,200 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.io;
import php.*;
import haxe.io.*;
import haxe.SysTools;
using StringTools;
using php.Global;
@:forward(iterator)
private abstract ProcessPipes(NativeIndexedArray<Resource>) from NativeIndexedArray<Resource> to NativeIndexedArray<Resource> {
public var stdin(get, never):Resource;
public var stdout(get, never):Resource;
public var stderr(get, never):Resource;
inline function get_stdin()
return this[0];
inline function get_stdout()
return this[1];
inline function get_stderr()
return this[2];
}
private class ReadablePipe extends Input {
var pipe:Resource;
var tmpBytes:Bytes;
public function new(pipe:Resource) {
this.pipe = pipe;
tmpBytes = Bytes.alloc(1);
}
override public function close():Void {
pipe.fclose();
}
override public function readByte():Int {
if (readBytes(tmpBytes, 0, 1) == 0)
throw Error.Blocked;
return tmpBytes.get(0);
}
override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
if (pipe.feof())
throw new Eof();
var result = pipe.fread(len);
if (result == "")
throw new Eof();
if (result == false)
return throw Error.Custom('Failed to read process output');
var result:String = result;
var bytes = Bytes.ofString(result);
s.blit(pos, bytes, 0, result.strlen());
return result.strlen();
}
}
private class WritablePipe extends Output {
var pipe:Resource;
var tmpBytes:Bytes;
public function new(pipe:Resource) {
this.pipe = pipe;
tmpBytes = Bytes.alloc(1);
}
override public function close():Void {
pipe.fclose();
}
override public function writeByte(c:Int):Void {
tmpBytes.set(0, c);
writeBytes(tmpBytes, 0, 1);
}
override public function writeBytes(b:Bytes, pos:Int, l:Int):Int {
var s = b.getString(pos, l);
if (pipe.feof())
throw new Eof();
var result = Global.fwrite(pipe, s, l);
if (result == false)
throw Error.Custom('Failed to write to process input');
return result;
}
}
class Process {
public var stdout(default, null):Input;
public var stderr(default, null):Input;
public var stdin(default, null):Output;
var process:Resource;
var pipes:ProcessPipes;
var pid:Int = -1;
var running:Bool = true;
var _exitCode:Int = -1;
public function new(cmd:String, ?args:Array<String>, ?detached:Bool):Void {
if (detached)
throw "Detached process is not supported on this platform";
var descriptors = Syntax.arrayDecl(Syntax.arrayDecl('pipe', 'r'), Syntax.arrayDecl('pipe', 'w'), Syntax.arrayDecl('pipe', 'w'));
var result = buildCmd(cmd, args).proc_open(descriptors, pipes);
if (result == false)
throw Error.Custom('Failed to start process: $cmd');
process = result;
updateStatus();
stdin = new WritablePipe(pipes.stdin);
stdout = new ReadablePipe(pipes.stdout);
stderr = new ReadablePipe(pipes.stderr);
}
public function getPid():Int {
return pid;
}
public function exitCode(block:Bool = true):Null<Int> {
if (!block) {
updateStatus();
return (running ? null : _exitCode);
}
while (running) {
var arr = Syntax.arrayDecl(process);
try {
Syntax.suppress(Global.stream_select(arr, arr, arr, null));
} catch(_) {}
updateStatus();
}
return _exitCode;
}
public function close():Void {
if (!running)
return;
for (pipe in pipes)
Global.fclose(pipe);
process.proc_close();
}
public function kill():Void {
process.proc_terminate();
}
function buildCmd(cmd:String, ?args:Array<String>):String {
if (args == null)
return cmd;
return switch (Sys.systemName()) {
case "Windows":
[cmd.replace("/", "\\")].concat(args).map(SysTools.quoteWinArg.bind(_, true)).join(" ");
case _:
[cmd].concat(args).map(SysTools.quoteUnixArg).join(" ");
}
}
function updateStatus():Void {
if (!running)
return;
var status = process.proc_get_status();
if (status == false)
throw Error.Custom('Failed to obtain process status');
var status:NativeAssocArray<Scalar> = status;
pid = status['pid'];
running = status['running'];
_exitCode = status['exitcode'];
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.net;
import php.Global.*;
import php.SuperGlobal.*;
@:coreApi
class Host {
public var host(default, null):String;
private var _ip:String;
public var ip(default, null):Int;
public function new(name:String):Void {
host = name;
if (~/^(\d{1,3}\.){3}\d{1,3}$/.match(name)) {
_ip = name;
} else {
_ip = gethostbyname(name);
if (_ip == name) {
ip = 0;
return;
}
}
var p = _ip.split('.');
ip = intval(sprintf('%02X%02X%02X%02X', p[3], p[2], p[1], p[0]), 16);
}
public function toString():String {
return _ip;
}
public function reverse():String {
return gethostbyaddr(_ip);
}
public static function localhost():String {
return php.Syntax.coalesce(_SERVER['HTTP_HOST'], "localhost");
}
}

View File

@ -0,0 +1,200 @@
/*
* Copyright (C)2005-2019 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.
*/
package sys.net;
import php.*;
import php.Global.*;
import php.Const.*;
import sys.io.FileInput;
import sys.io.FileOutput;
@:coreApi
class Socket {
private var __s:Resource;
private var stream:Resource;
public var input(default, null):haxe.io.Input;
public var output(default, null):haxe.io.Output;
public var custom:Dynamic;
var protocol:String;
public function new():Void {
input = @:privateAccess new sys.io.FileInput(null);
output = @:privateAccess new sys.io.FileOutput(null);
initSocket();
protocol = "tcp";
}
private function initSocket():Void {
__s = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
}
private function assignHandler():Void {
stream = socket_export_stream(__s);
@:privateAccess (cast input : FileInput).__f = stream;
@:privateAccess (cast output : FileOutput).__f = stream;
}
public function close():Void {
socket_close(__s);
@:privateAccess (cast input : FileInput).__f = null;
@:privateAccess (cast output : FileOutput).__f = null;
input.close();
output.close();
}
public function read():String {
var b = '';
while (!feof(stream))
b += fgets(stream);
return b;
}
public function write(content:String):Void {
fwrite(stream, content);
}
public function connect(host:Host, port:Int):Void {
var r = socket_connect(__s, host.host, port);
checkError(r, 0, 'Unable to connect');
assignHandler();
}
public function listen(connections:Int):Void {
var r = socket_listen(__s, connections);
checkError(r, 0, 'Unable to listen on socket');
assignHandler();
}
public function shutdown(read:Bool, write:Bool):Void {
var rw = read && write ? 2 : (write ? 1 : (read ? 0 : 2));
var r = socket_shutdown(__s, rw);
checkError(r, 0, 'Unable to shutdown');
}
public function bind(host:Host, port:Int):Void {
var r = socket_bind(__s, host.host, port);
checkError(r, 0, "Unable to bind socket");
}
public function accept():Socket {
var r = socket_accept(__s);
checkError(r, 0, 'Unable to accept connections on socket');
var s = new Socket();
// FIXME: wasted resource here
s.__s = r;
s.assignHandler();
return s;
}
public function peer():{host:Host, port:Int} {
var host:String = "", port:Int = 0;
var r = socket_getpeername(__s, host, port);
checkError(r, 0, 'Unable to retrieve the peer name');
return {host: new Host(host), port: port};
}
public function host():{host:Host, port:Int} {
var host:String = "", port:Int = 0;
var r = socket_getsockname(__s, host, port);
checkError(r, 0, 'Unable to retrieve the host name');
return {host: new Host(host), port: port};
}
public function setTimeout(timeout:Float):Void {
var s = Std.int(timeout);
var ms = Std.int((timeout - s) * 1000000);
var timeOut:NativeStructArray<{sec:Int, usec:Int}> = {sec: s, usec: ms};
var r = socket_set_option(__s, SOL_SOCKET, SO_RCVTIMEO, timeOut);
checkError(r, 0, 'Unable to set receive timeout');
r = socket_set_option(__s, SOL_SOCKET, SO_SNDTIMEO, timeOut);
checkError(r, 0, 'Unable to set send timeout');
}
public function setBlocking(b:Bool):Void {
var r = b ? socket_set_block(__s) : socket_set_nonblock(__s);
checkError(r, 0, 'Unable to set blocking');
}
public function setFastSend(b:Bool):Void {
var r = socket_set_option(__s, SOL_TCP, TCP_NODELAY, true);
checkError(r, 0, "Unable to set TCP_NODELAY on socket");
}
public function waitForRead():Void {
select([this], null, null);
}
private static function checkError(r:Bool, code:Int, msg:String):Void {
if (r != false)
return;
throw haxe.io.Error.Custom('Error [$code]: $msg');
}
/**
Since PHP 8 sockets are represented as instances of class \Socket
TODO:
rewrite without `cast` after resolving https://github.com/HaxeFoundation/haxe/issues/9964
*/
static inline function getSocketId(s:Resource):Int {
return PHP_VERSION_ID < 80000 ? Syntax.int(s) : spl_object_id(cast s);
}
public static function select(read:Array<Socket>, write:Array<Socket>, others:Array<Socket>,
?timeout:Float):{read:Array<Socket>, write:Array<Socket>, others:Array<Socket>} {
var map:Map<Int, Socket> = new Map();
inline function addSockets(sockets:Array<Socket>) {
if (sockets != null)
for (s in sockets)
map[getSocketId(s.__s)] = s;
}
inline function getRaw(sockets:Array<Socket>):Array<Resource> {
return sockets == null ? [] : [for (s in sockets) s.__s];
}
inline function getOriginal(result:Array<Resource>) {
return [for (r in result) map[getSocketId(r)]];
}
addSockets(read);
addSockets(write);
addSockets(others);
// unwrap Sockets into Resources
var rawRead:NativeIndexedArray<Resource> = getRaw(read),
rawWrite:NativeIndexedArray<Resource> = getRaw(write),
rawOthers:NativeIndexedArray<Resource> = getRaw(others);
var sec = timeout == null ? null : Std.int(timeout);
var usec = timeout == null ? 0 : Std.int((timeout % 1) * 1000000);
var result = socket_select(rawRead, rawWrite, rawOthers, sec, usec);
checkError(result, 0, "Error during select call");
// convert raw resources back to Socket objects
return {
read: getOriginal(rawRead),
write: getOriginal(rawWrite),
others: getOriginal(rawOthers),
}
}
}