|
@@ -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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|