Kryo的变长序列化底层在AS3的实现
当前是个人把java的Output和Input的翻译成了AS3版本,虽然没什么技术含量,但是还是很有帮助,经过长时间使用,基本确保和java之间的通信没有任何问题。
package yxcq.kryo { import flash.utils.ByteArray; import yxcq.utils.math.Long; public class Input { protected var buffer:ByteArray; public function Input(bytes:ByteArray) { if(bytes != null){ this.buffer = bytes; this.buffer.position = 0; } } public function get bytesAvailable():int { return buffer.bytesAvailable; } public function setBytes(bytes:ByteArray):void { this.buffer = bytes; this.buffer.position = 0; } protected function require(required:int):int { if(buffer.bytesAvailable>=required) return buffer.bytesAvailable; else throw new Error(); } public function read():int { if(buffer.bytesAvailable<1) return -1; return buffer.readUnsignedByte()&0xFF; } public function skip(count:int):void { this.buffer.position = this.buffer.position+count; } public function readByte():int { require(1); return buffer.readByte(); } public function readByteUnsigned():int { require(1); return buffer.readUnsignedByte(); } public function readBytes(length:int):ByteArray { var bytes:ByteArray = new ByteArray; _readBytes(bytes,0,length); return bytes; } protected function _readBytes(bytes:ByteArray,offset:int,length:int):void { buffer.readBytes(bytes,offset,length); } public function readInt():int{ require(4); return (buffer.readUnsignedByte() & 0xFF) << 24 // | (buffer.readUnsignedByte() & 0xFF) << 16 // | (buffer.readUnsignedByte() & 0xFF) << 8 // | buffer.readUnsignedByte() & 0xFF; } /** Reads a 1-5 byte int. It is guaranteed that a varible length encoding will be used. */ public function readVarInt (optimizePositive:Boolean):int { if (require(1) < 5) return readInt_slow(optimizePositive); var b:int = buffer.readUnsignedByte(); var result:int = b & 0x7F; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 7; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 14; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 21; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 28; } } } } return optimizePositive ? result : ((result >>> 1) ^ -(result & 1)); } private function readInt_slow (optimizePositive:Boolean):int { // The buffer is guaranteed to have at least 1 byte. var b:int = buffer.readUnsignedByte(); var result:int = b & 0x7F; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 7; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 14; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 21; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 28; } } } } return optimizePositive ? result : ((result >>> 1) ^ -(result & 1)); } protected var chars:ByteArray = new ByteArray; public function readString():String { var available:int = require(1); var b:int = buffer.readUnsignedByte(); if((b&0x80) == 0)return readAscii(); var charCount:int = available>=5?readUtf8Length(b) : readUtf8Length_slow(b); switch (charCount) { case 0: return null; case 1: return ""; } charCount--; chars.clear(); readUtf8(charCount); var len:int = chars.position; chars.position = 0; return chars.readUTFBytes(len); } private function readUtf8Length (b:int):int { var result:int = b & 0x3F; // Mask all but first 6 bits. if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8. b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 6; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 13; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 20; if ((b & 0x80) != 0) { b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 27; } } } } return result; } private function readUtf8Length_slow (b:int):int { var result:int = b & 0x3F; // Mask all but first 6 bits. if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8. require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 6; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 13; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 20; if ((b & 0x80) != 0) { require(1); b = buffer.readUnsignedByte(); result |= (b & 0x7F) << 27; } } } } return result; } private function readUtf8 (charCount:int):void { // Try to read 7 bit ASCII chars. var charIndex:int = 0; var count:int = Math.min(require(1), charCount); var b:int; while (charIndex < count) { b = buffer.readByte(); if (b < 0) { this.buffer.position--; break; } charIndex++; chars.writeByte(b); } // If buffer didn't hold all chars or any were not ASCII, use slow path for remainder. if (charIndex < charCount){ readUtf8_slow(charCount, charIndex); } } private function readUtf8_slow (charCount:int, charIndex:int):void { var utfstrlen:int = 0; var position:int = buffer.position; while (charIndex < charCount) { var b:int = buffer.readByte() & 0x000000FF; switch (b >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: chars.writeByte(b); break; case 12: case 13: chars.writeByte(b); chars.writeByte(buffer.readByte()); break; case 14: chars.writeByte(b); chars.writeByte(buffer.readByte()); chars.writeByte(buffer.readByte()); break; } charIndex++; } } private function readAscii ():String { var position:int = buffer.position; var end:int = buffer.position; var start:int = end -1; var limit:int = buffer.length; var b:int; do { if(end == limit){ buffer.position = position-1; return readAscii_slow(); } b = buffer.readUnsignedByte(); end++; } while ((b & 0x00000080) == 0); buffer[end - 1] &=0x0000007F; // Mask end of ascii bit. buffer.position = position-1; var value:String = (buffer as ByteArray).readMultiByte(end-start,'iso-8859-1'); buffer[end - 1] |= 0x00000080; return value; } private function readAscii_slow ():String { throw new Error("数据流中有不支持的字符串解析"); } public function readFloat():Number { return buffer.readFloat(); } public function readFloat2(precision:Number,optimizePositive:Boolean):Number { return Number(readInt_slow(optimizePositive))/precision; } public function readShort():int { return buffer.readShort(); } public function readShortUnsigned():int { return buffer.readUnsignedShort(); } public function readLong():Long { var h:int = buffer.readUnsignedByte()<<22; h |= buffer.readUnsignedByte()<<16; h |= buffer.readUnsignedByte()<<8; h |= buffer.readUnsignedByte(); var l:int = buffer.readUnsignedByte()<<22; l |= buffer.readUnsignedByte()<<16; l |= buffer.readUnsignedByte()<<8; l |= buffer.readUnsignedByte(); return new Long(h,l); } public function readVarLong (optimizePositive:Boolean):Long{ var b:int = buffer.readByte(); var low:int = b & 0x7F; var high:int = 0; if ((b & 0x80) != 0) { b = buffer.readByte(); low |= (b & 0x7F) << 7; if ((b & 0x80) != 0) { b = buffer.readByte(); low |= (b & 0x7F) << 14; if ((b & 0x80) != 0) { b = buffer.readByte(); low |= (b & 0x7F) << 21; if ((b & 0x80) != 0) { b = buffer.readByte(); var temp:int = b&0x7F; high = ((0 << temp) | (temp >>> 4) )|high; low |= (temp << 28); if ((b & 0x80) != 0) { b = buffer.readByte(); high |= (b & 0x7F)<<3; if ((b & 0x80) != 0) { b = buffer.readByte(); high |= (b & 0x7F) << 10; if ((b & 0x80) != 0) { b = buffer.readByte(); high |= (b & 0x7F) << 17; if ((b & 0x80) != 0) { b = buffer.readByte(); high |= (b & 0x7F) << 24; } } } } } } } } var result:Long = new Long(high,low); if (!optimizePositive) result = result.rightShift(1,true).xor(result.and(1)); return result; } public function readBoolean():Boolean { return buffer.readUnsignedByte()==1; } public function readChar():int { return buffer.readUnsignedShort(); } public function readDouble():Number { return buffer.readDouble(); } /** Bulk input of an int array. */ public function readVarInts (length:int, optimizePositive:Boolean):Vector.<int>{ var array:Vector.<int> = new Vector.<int>; for (var i:int = 0; i < length; i++) array[i] = readVarInt(optimizePositive); return array; } public function readVarLongs (length:int, optimizePositive:Boolean):Vector.<Long>{ var array:Vector.<Long> = new Vector.<Long>; for (var i:int = 0; i < length; i++) array[i] = readVarLong(optimizePositive); return array; } /** Bulk input of an int array. */ public function readInts (length:int) :Vector.<int> { var array:Vector.<int> = new Vector.<int>; for (var i:int = 0; i < length; i++) array[i] = readInt(); return array; } /** Bulk input of a long array. */ public function readLongs (length:int):Vector.<Long> { var array:Vector.<Long> = new Vector.<Long>; for (var i:int = 0; i < length; i++) array[i] = readLong(); return array; } /** Bulk input of a float array. */ public function readFloats (length:int) :Vector.<Number> { var array:Vector.<Number> = new Vector.<Number>; for (var i:int = 0; i < length; i++) array[i] = readFloat(); return array; } /** Bulk input of a short array. */ public function readShorts (length:int):Vector.<int> { var array:Vector.<int> = new Vector.<int>; for (var i:int = 0; i < length; i++) array[i] = readShort(); return array; } /** Bulk input of a char array. */ public function readChars (length:int):Vector.<int> { var array:Vector.<int> = new Vector.<int>; for (var i:int = 0; i < length; i++) array[i] = readChar(); return array; } /** Bulk input of a double array. */ public function readDoubles (length:int):Vector.<Number> { var array:Vector.<Number> = new Vector.<Number>; for (var i:int = 0; i < length; i++) array[i] = readDouble(); return array; } } }
package yxcq.kryo { import yxcq.utils.math.Long; import flash.utils.ByteArray; public class Output { protected var buffer:ByteArray = new ByteArray; public function Output() { } public function getBuffer():ByteArray { return buffer; } public function write(value:int):void { buffer.writeByte(value); } public function writeBytes(bytes:ByteArray,offset:int,length:int):void { buffer.writeBytes(bytes,offset,length); } public function writeByte(b:int):void { buffer.writeByte(b); } public function writeInt(value:int):void { buffer.writeInt(value); } public function writeVarInt(value:int,optimizePositive:Boolean):int { if(!optimizePositive) value = (value<<1)^(value>>31); if(value>>>7 == 0){ buffer.writeByte(value&0xFF); return 1; } if(value>>>14 == 0){ buffer.writeByte((value&0x7F | 0x80)&0xFF); buffer.writeByte((value>>>7)&0xFF); return 2; } if (value >>> 21 == 0) { buffer.writeByte((value&0x7F | 0x80)&0xFF); buffer.writeByte((value>>>7|0x80)&0xFF); buffer.writeByte((value>>>14)&0xFF); return 3; } if (value >>> 28 == 0) { buffer.writeByte((value&0x7F | 0x80)&0xFF); buffer.writeByte((value>>>7|0x80)&0xFF); buffer.writeByte((value>>>14|0x80)&0xFF); buffer.writeByte((value>>>21)&0xFF); return 4; } buffer.writeByte((value&0x7F | 0x80)&0xFF); buffer.writeByte((value>>>7|0x80)&0xFF); buffer.writeByte((value>>>14|0x80)&0xFF); buffer.writeByte((value>>>21|0x80)&0xFF); buffer.writeByte((value>>>28)&0xFF); return 5; } public function writeVarLong (value:Long, optimizePositive:Boolean):int{ if (!optimizePositive) value = value.leftShift(1).xor(value.rightShift(63)); if (value.rightShift(7,true).isZero()) { buffer.writeByte(value.getLow()); return 1; } if (value.rightShift(14,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).getLow()); return 2; } if (value.rightShift(21,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).getLow()); return 3; } if (value.rightShift(28,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(21,true).getLow()); return 4; } if (value.rightShift(35,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(21,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(28,true).getLow()); return 5; } if (value.rightShift(42,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(21,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(28,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(35,true).getLow()); return 6; } if (value.rightShift(49,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(21,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(28,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(35,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(42,true).getLow()); return 7; } if (value.rightShift(56,true).isZero()) { buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(21,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(28,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(35,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(42,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(49,true).getLow()); return 8; } buffer.writeByte(value.and(0x7F).or(0x80).getLow()); buffer.writeByte(value.rightShift(7,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(14,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(21,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(28,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(35,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(42,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(49,true).or(0x80).getLow()); buffer.writeByte(value.rightShift(56,true).getLow()); return 9; } public function writeString (value:String):void { if (value == null) { writeByte(0x80); // 0 means null, bit 8 means UTF8. return; } var charCount:int = value.length; if (charCount == 0) { writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8. return; } // Detect ASCII. 检查是否ASCII var ascii:Boolean = false; if (charCount > 1 && charCount < 64) { ascii = true; for (var i:int = 0; i < charCount; i++) { var c:int = value.charCodeAt(i); if (c > 127) { ascii = false; break; } } } if (ascii) { buffer.writeUTFBytes(value); buffer[buffer.position - 1] |= 0x80; } else { writeUtf8Length(charCount + 1); var charIndex:int = 0; var position:int = buffer.position; // Try to write 8 bit chars. for (; charIndex < charCount; charIndex++) { var c:int = value.charCodeAt(charIndex); if (c > 127) break; buffer.writeByte(c&0xFF); position++; } buffer.position = position; if (charIndex < charCount) writeString_slow(value, charCount, charIndex); } } /** Writes a string that is known to contain only ASCII characters. Non-ASCII strings passed to this method will be corrupted. * Each byte is a 7 bit character with the remaining byte denoting if another character is available. This is slightly more * efficient than {@link #writeString(String)}. The string can be read using {@link Input#readString()} or * {@link Input#readStringBuilder()}. * @param value May be null. */ public function writeAscii (value:String):void{ if (value == null) { writeByte(0x80); // 0 means null, bit 8 means UTF8. return; } var charCount:int = value.length; switch (charCount) { case 0: writeByte(1 | 0x80); // 1 is string length + 1, bit 8 means UTF8. return; case 1: writeByte(2 | 0x80); // 2 is string length + 1, bit 8 means UTF8. writeByte(value.charCodeAt(0)); return; } buffer.writeUTF(value); buffer[buffer.position - 1] |= 0x80; // Bit 8 means end of ASCII. } /** Writes the length of a string, which is a variable length encoded int except the first byte uses bit 8 to denote UTF8 and * bit 7 to denote if another byte is present. */ private function writeUtf8Length (value:int):void { if (value >>> 6 == 0) { buffer.writeByte((value | 0x80)&0xFF); // Set bit 8. } else if (value >>> 13 == 0) { buffer.writeByte((value | 0x40 | 0x80)&0xFF); // Set bit 7 and 8. buffer.writeByte((value >>> 6)&0xFF); } else if (value >>> 20 == 0) { buffer.writeByte((value | 0x40 | 0x80)&0xFF); // Set bit 7 and 8. buffer.writeByte(((value >>> 6) | 0x80)&0xFF); // Set bit 8. buffer.writeByte((value >>> 13)&0xFF); } else if (value >>> 27 == 0) { buffer.writeByte((value | 0x40 | 0x80)&0xFF); // Set bit 7 and 8. buffer.writeByte(((value >>> 6) | 0x80)&0xFF); // Set bit 8. buffer.writeByte(((value >>> 13) | 0x80)&0xFF); // Set bit 8. buffer.writeByte((value >>> 20)&0xFF); } else { buffer.writeByte((value | 0x40 | 0x80)&0xFF); // Set bit 7 and 8. buffer.writeByte(((value >>> 6) | 0x80)&0xFF); // Set bit 8. buffer.writeByte(((value >>> 13) | 0x80)&0xFF); // Set bit 8. buffer.writeByte(((value >>> 20) | 0x80)&0xFF); // Set bit 8. buffer.writeByte((value >>> 27)&0xFF); } } private function writeString_slow (value:String, charCount:int, charIndex:int):void { for (; charIndex < charCount; charIndex++) { var c:int = value.charCodeAt(charIndex); if (c <= 0x007F) { buffer.writeByte(c&0xFF); } else if (c > 0x07FF) { buffer.writeByte((0xE0 | c >> 12 & 0x0F)&0xFF); buffer.writeByte((0x80 | c >> 6 & 0x3F)&0xFF); buffer.writeByte((0x80 | c & 0x3F)&0xFF); } else { buffer.writeByte((0xC0 | c >> 6 & 0x1F)&0xFF); buffer.writeByte((0x80 | c & 0x3F)&0xFF); } } } public function writeFloat(value:Number):void { this.buffer.writeFloat(value); } public function writeFloat2(value:Number,precision:Number,optimizePositive:Boolean):void { this.writeVarInt(value*precision,optimizePositive); } public function writeShort(value:int):void { this.buffer.writeShort(value); } public function writeLong(value:Long):void { this.buffer.writeByte(value.getHigh()>>>24); this.buffer.writeByte(value.getHigh()>>>16); this.buffer.writeByte(value.getHigh()>>>8); this.buffer.writeByte(value.getHigh()); this.buffer.writeByte(value.getLow()>>>24); this.buffer.writeByte(value.getLow()>>>16); this.buffer.writeByte(value.getLow()>>>8); this.buffer.writeByte(value.getLow()); } public function writeBoolean(value:Boolean):void { this.buffer.writeBoolean(value); } public function writeChar(value:int):void { this.buffer.writeShort(value); } public function writeDouble(value:Number):void { this.buffer.writeDouble(value); } /** Bulk output of an int array. */ public function writeVarInts (object:Vector.<int>, optimizePositive:Boolean) :void { for (var i:int = 0, n:int = object.length; i < n; i++) writeVarInt(object[i], optimizePositive); } /** Bulk output of an int array. */ public function writeInts (object:Vector.<int>) :void { for (var i:int = 0, n:int = object.length; i < n; i++) this.buffer.writeInt(object[i]); } public function writeVarLongs (object:Vector.<Long>, optimizePositive:Boolean):void{ for (var i:int = 0, n:int = object.length; i < n; i++) writeVarLong(object[i], optimizePositive); } /** Bulk output of an long array. */ public function writeLongs (object:Vector.<Long>) :void { for (var i:int = 0, n:int = object.length; i < n; i++) writeLong(object[i]); } /** Bulk output of a float array. */ public function writeFloats (object:Vector.<Number>) :void { for (var i:int = 0, n:int = object.length; i < n; i++) writeFloat(object[i]); } /** Bulk output of a short array. */ public function writeShorts (object:Vector.<int>) :void { for (var i:int = 0, n:int = object.length; i < n; i++) writeShort(object[i]); } /** Bulk output of a char array. */ public function writeChars (object:Vector.<int>) :void { for (var i:int = 0, n:int = object.length; i < n; i++) writeChar(object[i]); } /** Bulk output of a double array. */ public function writeDoubles (object:Vector.<int>) :void { for (var i:int = 0, n:int = object.length; i < n; i++) writeDouble(object[i]); } } }