浏览代码

added hbson format for binary json and string table

Nicolas Cannasse 3 年之前
父节点
当前提交
8f957d3cdf
共有 3 个文件被更改,包括 200 次插入1 次删除
  1. 78 0
      hxd/fmt/hbson/Reader.hx
  2. 104 0
      hxd/fmt/hbson/Writer.hx
  3. 18 1
      hxd/fs/Convert.hx

+ 78 - 0
hxd/fmt/hbson/Reader.hx

@@ -0,0 +1,78 @@
+package hxd.fmt.hbson;
+
+class Reader {
+
+	static var GLOBAL_STR_MAP : Map<String,String> = [];
+
+	var input : haxe.io.BytesInput;
+	var stringTbl : Array<String>;
+	var globalStrings : Bool;
+
+	public function new( data : haxe.io.Bytes, globalStrings ) {
+		stringTbl = [];
+		input = new haxe.io.BytesInput(data,6);
+		this.globalStrings = globalStrings;
+	}
+
+	function readString() : String {
+		var index = input.readInt32();
+		if( index & 0xC0000000 != 0 ) {
+			var str = input.readString(index & 0x3FFFFFFF);
+			if( index & 0x40000000 != 0 ) {
+				if( globalStrings ) {
+					var str2 = GLOBAL_STR_MAP.get(str);
+					if( str2 != null )
+						str = str2;
+					else
+						GLOBAL_STR_MAP.set(str, str);
+				}
+				stringTbl.push(str);
+			}
+			return str;
+		}
+		var str = stringTbl[index];
+		if( str == null ) throw "assert";
+		return str;
+	}
+
+	public function read() : Dynamic {
+		var code = input.readByte();
+		switch( code ) {
+		case 0:
+			return 0;
+		case 1:
+			return input.readByte();
+		case 2:
+			return input.readInt32();
+		case 3:
+			return input.readDouble();
+		case 4:
+			return true;
+		case 5:
+			return false;
+		case 6:
+			return null;
+		case 7:
+			return {};
+		case 8, 9:
+			var obj = {};
+			for( i in 0...(code == 8 ? input.readByte() : input.readInt32()) )
+				Reflect.setField(obj, readString(), read());
+			return obj;
+		case 10:
+			return readString();
+		case 11:
+			return [];
+		case 12, 13:
+			var arr : Array<Dynamic> = [];
+			var len = code == 12 ? input.readByte() : input.readInt32();
+			arr[len-1] = null;
+			for( i in 0...len )
+				arr[i] = read();
+			return arr;
+		default:
+			throw "assert";
+		}
+	}
+
+}

+ 104 - 0
hxd/fmt/hbson/Writer.hx

@@ -0,0 +1,104 @@
+package hxd.fmt.hbson;
+
+class Writer {
+
+	var out : haxe.io.Output;
+	var stringCount : Int;
+	var stringMap : Map<String,Int>;
+
+	public function new( out : haxe.io.Output ) {
+		this.out = out;
+		stringCount = 0;
+		stringMap = [];
+		out.writeString("HBSON");
+		out.writeByte(0);
+	}
+
+	public function write( json : Dynamic ) {
+		writeRec(json);
+	}
+
+	function isAscii(str:String) {
+		for( i in 0...str.length )
+			if( str.charCodeAt(i) > 127 )
+				return false;
+		return true;
+	}
+
+	function writeString( str : String ) {
+		if( str.length <= 16 && isAscii(str) ) {
+			var index = stringMap.get(str);
+			if( index == null ) {
+				index = stringCount++;
+				stringMap.set(str,index);
+				out.writeInt32(str.length | 0x40000000);
+				out.writeString(str);
+			} else
+				out.writeInt32(index);
+		} else {
+			var bytes = haxe.io.Bytes.ofString(str);
+			out.writeInt32(bytes.length | 0x80000000);
+			out.write(bytes);
+		}
+	}
+
+	function writeRec(value:Dynamic) {
+		switch( Type.typeof(value) ) {
+		case TInt:
+			var value : Int = value;
+			if( value == 0 )
+				out.writeByte(0);
+			else if( value >= 0 && value <= 255 ) {
+				out.writeByte(1);
+				out.writeByte(value);
+			} else {
+				out.writeByte(2);
+				out.writeInt32(value);
+			}
+		case TFloat:
+			out.writeByte(3);
+			out.writeDouble(value);
+		case TBool:
+			out.writeByte((value:Bool) ? 4 : 5);
+		case TNull:
+			out.writeByte(6);
+		case TObject:
+			var fields = Reflect.fields(value);
+			if( fields.length == 0 ) {
+				out.writeByte(7);
+			} else if( fields.length < 256 ) {
+				out.writeByte(8);
+				out.writeByte(fields.length);
+			} else {
+				out.writeByte(9);
+				out.writeInt32(fields.length);
+			}
+			for( f in fields ) {
+				writeString(f);
+				writeRec(Reflect.field(value,f));
+			}
+		case TClass(c):
+			if( c == String ) {
+				out.writeByte(10);
+				writeString(value);
+			} else if( c == Array ) {
+				var value : Array<Dynamic> = value;
+				if( value.length == 0 ) {
+					out.writeByte(11);
+				} else if( value.length < 256 ) {
+					out.writeByte(12);
+					out.writeByte(value.length);
+				} else {
+					out.writeByte(13);
+					out.writeInt32(value.length);
+				}
+				for( v in value )
+					writeRec(v);
+			} else
+				throw "Unsupported "+value;
+		default:
+			throw "Unsupported "+value;
+		}
+	}
+
+}

+ 18 - 1
hxd/fs/Convert.hx

@@ -292,4 +292,21 @@ class DummyConvert extends Convert {
 		Convert.register(new DummyConvert(null,"remove"))
 	];
 
-}
+}
+
+class ConvertBinJSON extends Convert {
+
+	override function convert() {
+		var json = haxe.Json.parse(srcBytes.toString());
+		var out = new haxe.io.BytesOutput();
+		new hxd.fmt.hbson.Writer(out).write(json);
+		save(out.getBytes());
+	}
+
+	static var _ = [
+		Convert.register(new ConvertBinJSON("json,prefab,l3d","hbson"))
+	];
+
+}
+
+