241 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
// Msgpack parser with typed arrays
 | 
						|
// Based on https://github.com/aaulia/msgpack-haxe
 | 
						|
//
 | 
						|
// 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 iron.system;
 | 
						|
 | 
						|
import haxe.io.Bytes;
 | 
						|
import haxe.io.BytesInput;
 | 
						|
import haxe.io.BytesOutput;
 | 
						|
import haxe.io.Eof;
 | 
						|
import iron.data.SceneFormat;
 | 
						|
#if (!macro)
 | 
						|
import kha.arrays.Float32Array;
 | 
						|
import kha.arrays.Uint32Array;
 | 
						|
import kha.arrays.Int16Array;
 | 
						|
#end
 | 
						|
 | 
						|
class LnxPack {
 | 
						|
 | 
						|
	public static inline function decode<T>(b: Bytes): T {
 | 
						|
		var i = new BytesInput(b);
 | 
						|
		i.bigEndian = false;
 | 
						|
		return read(i);
 | 
						|
	}
 | 
						|
 | 
						|
	static function read(i: BytesInput, key = "", parentKey = ""): Any {
 | 
						|
		try {
 | 
						|
			var b = i.readByte();
 | 
						|
			switch (b) {
 | 
						|
				case 0xc0: return null;
 | 
						|
				case 0xc2: return false;
 | 
						|
				case 0xc3: return true;
 | 
						|
				case 0xc4: return i.read(i.readByte());
 | 
						|
				case 0xc5: return i.read(i.readUInt16());
 | 
						|
				case 0xc6: return i.read(i.readInt32());
 | 
						|
				case 0xca: return i.readFloat();
 | 
						|
				case 0xcc: return i.readByte();
 | 
						|
				case 0xcd: return i.readUInt16();
 | 
						|
				case 0xce: return i.readInt32();
 | 
						|
				case 0xd0: return i.readInt8();
 | 
						|
				case 0xd1: return i.readInt16();
 | 
						|
				case 0xd2: return i.readInt32();
 | 
						|
				// case 0xd3: return Int64.make(i.readInt32(), i.readInt32());
 | 
						|
				case 0xd9: return i.readString(i.readByte());
 | 
						|
				case 0xda: return i.readString(i.readUInt16());
 | 
						|
				case 0xdb: return i.readString(i.readInt32());
 | 
						|
				case 0xdc: return readArray(i, i.readUInt16(), key, parentKey);
 | 
						|
				case 0xdd: return readArray(i, i.readInt32(), key, parentKey);
 | 
						|
				case 0xde: return readMap(i, i.readUInt16(), key, parentKey);
 | 
						|
				case 0xdf: return readMap(i, i.readInt32(), key, parentKey);
 | 
						|
 | 
						|
				default: {
 | 
						|
					if (b < 0x80) return b; // positive fix num
 | 
						|
					else if (b < 0x90) return readMap(i, (0xf & b), key, parentKey); // fix map
 | 
						|
					else if (b < 0xa0) return readArray(i, (0xf & b), key, parentKey); // fix array
 | 
						|
					else if (b < 0xc0) return i.readString(0x1f & b); // fix string
 | 
						|
					else if (b > 0xdf) return 0xffffff00 | b; // negative fix num
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		catch (e: Eof) {}
 | 
						|
		return null;
 | 
						|
	}
 | 
						|
 | 
						|
	static function readArray(i: BytesInput, length: Int, key = "", parentKey = ""): Any {
 | 
						|
		var b = i.readByte();
 | 
						|
		i.position--;
 | 
						|
 | 
						|
		if (b == 0xca) { // Typed float32
 | 
						|
			i.position++;
 | 
						|
			var a = new Float32Array(length);
 | 
						|
			for (x in 0...length) a[x] = i.readFloat();
 | 
						|
			return a;
 | 
						|
		}
 | 
						|
		else if (b == 0xd2) { // Typed int32
 | 
						|
			i.position++;
 | 
						|
			var a = new Uint32Array(length);
 | 
						|
			for (x in 0...length) a[x] = i.readInt32();
 | 
						|
			return a;
 | 
						|
		}
 | 
						|
		else if (b == 0xd1) { // Typed int16
 | 
						|
			i.position++;
 | 
						|
			var a = new Int16Array(length);
 | 
						|
			for (x in 0...length) a[x] = i.readInt16();
 | 
						|
			return a;
 | 
						|
		}
 | 
						|
		else { // Dynamic type-value
 | 
						|
			var a: Array<Dynamic> = [];
 | 
						|
			for (x in 0...length) a.push(read(i, key, parentKey));
 | 
						|
			return a;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	static function readMap(i: BytesInput, length: Int, key = "", parentKey = ""): Any {
 | 
						|
		#if js
 | 
						|
		var out = {};
 | 
						|
		#else
 | 
						|
		var out = Type.createEmptyInstance(getClass(key, parentKey));
 | 
						|
		#end
 | 
						|
		for (n in 0...length) {
 | 
						|
			var k = Std.string(read(i));
 | 
						|
			var v = read(i, k, key);
 | 
						|
			Reflect.setField(out, k, v);
 | 
						|
		}
 | 
						|
		return out;
 | 
						|
	}
 | 
						|
 | 
						|
	#if (!js)
 | 
						|
	static function getClass(key: String, parentKey: String): Class<Dynamic> {
 | 
						|
		return switch (key) {
 | 
						|
			case "": TSceneFormat;
 | 
						|
			case "mesh_datas": TMeshData;
 | 
						|
			case "light_datas": TLightData;
 | 
						|
			case "probe_datas": TProbeData;
 | 
						|
			case "probe": TProbeData;
 | 
						|
			case "camera_datas": TCameraData;
 | 
						|
			case "material_datas": TMaterialData;
 | 
						|
			case "particle_datas": TParticleData;
 | 
						|
			case "shader_datas": TShaderData;
 | 
						|
			case "speaker_datas": TSpeakerData;
 | 
						|
			case "world_datas": TWorldData;
 | 
						|
			case "terrain_datas": TTerrainData;
 | 
						|
			case "tilesheet_datas": TTilesheetData;
 | 
						|
			case "objects": TObj;
 | 
						|
			case "children": TObj;
 | 
						|
			case "groups": TGroup;
 | 
						|
			case "traits": TTrait;
 | 
						|
			case "properties": TProperty;
 | 
						|
			case "vertex_arrays": TVertexArray;
 | 
						|
			case "index_arrays": TIndexArray;
 | 
						|
			case "skin": TSkin;
 | 
						|
			case "transform": TTransform;
 | 
						|
			case "constraints": TConstraint;
 | 
						|
			case "contexts": parentKey == "material_datas" ? TMaterialContext : TShaderContext;
 | 
						|
			case "override_context": TShaderOverride;
 | 
						|
			case "bind_constants": TBindConstant;
 | 
						|
			case "bind_textures": TBindTexture;
 | 
						|
			case "vertex_elements": TVertexElement;
 | 
						|
			case "constants": TShaderConstant;
 | 
						|
			case "texture_units": TTextureUnit;
 | 
						|
			case "actions": TTilesheetAction;
 | 
						|
			case "particle_refs": TParticleReference;
 | 
						|
			case "lods": TLod;
 | 
						|
			case "anim": TAnimation;
 | 
						|
			case "tracks": TTrack;
 | 
						|
			case "morph_target": TMorphTarget;
 | 
						|
			case "vertex_groups": TVertex_groups;
 | 
						|
			case _: TSceneFormat;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	#end
 | 
						|
 | 
						|
	#if (!macro && armorcore)
 | 
						|
 | 
						|
	public static inline function encode(d: Dynamic): Bytes {
 | 
						|
		var o = new BytesOutput();
 | 
						|
		o.bigEndian = false;
 | 
						|
		write(o, d);
 | 
						|
		return o.getBytes();
 | 
						|
	}
 | 
						|
 | 
						|
	static function write(o: BytesOutput, d: Dynamic) {
 | 
						|
		switch (Type.typeof(d)) {
 | 
						|
			case TNull: o.writeByte(0xc0);
 | 
						|
			case TBool: o.writeByte(d ? 0xc3 : 0xc2);
 | 
						|
			case TInt: { o.writeByte(0xd2); o.writeInt32(d); }
 | 
						|
			case TFloat: { o.writeByte(0xca); o.writeFloat(d); }
 | 
						|
			case TClass(c): {
 | 
						|
				switch (Type.getClassName(c)) {
 | 
						|
					case "String": {
 | 
						|
						o.writeByte(0xdb);
 | 
						|
						var b = Bytes.ofString(d);
 | 
						|
						o.writeInt32(b.length);
 | 
						|
						o.writeFullBytes(b, 0, b.length);
 | 
						|
					}
 | 
						|
					case "Array", null: { // kha.arrays give null
 | 
						|
						o.writeByte(0xdd);
 | 
						|
						o.writeInt32(d.length);
 | 
						|
						var isInt16 = Std.isOfType(d, #if js js.lib.Int16Array #else Int16ArrayPrivate #end);
 | 
						|
						var isInt = Std.isOfType(d[0], Int) && !Std.isOfType(d, #if js js.lib.Float32Array #else Float32ArrayPrivate #end);
 | 
						|
						var isFloat = Std.isOfType(d[0], Float);
 | 
						|
 | 
						|
						if (isInt16) { // Int16Array
 | 
						|
							o.writeByte(0xd1);
 | 
						|
							for (i in 0...d.length) o.writeInt16(d[i]);
 | 
						|
						}
 | 
						|
						else if (isFloat && !isInt) { // Float32Array
 | 
						|
							o.writeByte(0xca);
 | 
						|
							for (i in 0...d.length) o.writeFloat(d[i]);
 | 
						|
						}
 | 
						|
						else if (isInt) { // Uint32Array
 | 
						|
							o.writeByte(0xd2);
 | 
						|
							for (i in 0...d.length) o.writeInt32(d[i]);
 | 
						|
						}
 | 
						|
						else for (i in 0...d.length) write(o, d[i]); // Array
 | 
						|
					}
 | 
						|
					case "haxe.io.Bytes": {
 | 
						|
						o.writeByte(0xc6);
 | 
						|
						o.writeInt32(d.length);
 | 
						|
						o.writeFullBytes(d, 0, d.length);
 | 
						|
					}
 | 
						|
					default: writeObject(o, d);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			case TObject: writeObject(o, d);
 | 
						|
			default: {}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	static function writeObject(o: BytesOutput, d: Dynamic) {
 | 
						|
		var f = Reflect.fields(d);
 | 
						|
		o.writeByte(0xdf);
 | 
						|
		o.writeInt32(f.length);
 | 
						|
		for (k in f) {
 | 
						|
			o.writeByte(0xdb);
 | 
						|
			var b = Bytes.ofString(k);
 | 
						|
			o.writeInt32(b.length);
 | 
						|
			o.writeFullBytes(b, 0, b.length);
 | 
						|
			write(o, Reflect.field(d, k));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	#end
 | 
						|
}
 |