| /*
|
| * Copyright 1999-2011 Alibaba Group.
|
| *
|
| * Licensed under the Apache License, Version 2.0 (the "License");
|
| * you may not use this file except in compliance with the License.
|
| * You may obtain a copy of the License at
|
| *
|
| * http://www.apache.org/licenses/LICENSE-2.0
|
| *
|
| * Unless required by applicable law or agreed to in writing, software
|
| * distributed under the License is distributed on an "AS IS" BASIS,
|
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| * See the License for the specific language governing permissions and
|
| * limitations under the License.
|
| */
|
| package com.alibaba.dubbo.common.serialize.support.dubbo; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| import com.alibaba.dubbo.common.serialize.DataOutput; |
| |
| /** |
| * Default data output impl. |
| * Not thread-safe. |
| * |
| * @author qian.lei |
| */ |
| |
| public class GenericDataOutput implements DataOutput, GenericDataFlags |
| { |
| private static final int CHAR_BUF_SIZE = 256; |
| |
| private final byte[] mBuffer, mTemp = new byte[9]; |
| |
| private final char[] mCharBuf = new char[CHAR_BUF_SIZE]; |
| |
| private final OutputStream mOutput; |
| |
| private final int mLimit; |
| |
| private int mPosition = 0; |
| |
| public GenericDataOutput(OutputStream out) |
| { |
| this(out, 1024); |
| } |
| |
| public GenericDataOutput(OutputStream out, int buffSize) |
| { |
| mOutput = out; |
| mLimit = buffSize; |
| mBuffer = new byte[buffSize]; |
| } |
| |
| public void writeBool(boolean v) throws IOException |
| { |
| write0( v ? VARINT_1 : VARINT_0 ); |
| } |
| |
| public void writeByte(byte v) throws IOException |
| { |
| switch( v ) |
| { |
| case 0: write0(VARINT_0); break; case 1: write0(VARINT_1); break; case 2: write0(VARINT_2); break; case 3: write0(VARINT_3); break; |
| case 4: write0(VARINT_4); break; case 5: write0(VARINT_5); break; case 6: write0(VARINT_6); break; case 7: write0(VARINT_7); break; |
| case 8: write0(VARINT_8); break; case 9: write0(VARINT_9); break; case 10: write0(VARINT_A); break; case 11: write0(VARINT_B); break; |
| case 12: write0(VARINT_C); break; case 13: write0(VARINT_D); break; case 14: write0(VARINT_E); break; case 15: write0(VARINT_F); break; |
| case 16: write0(VARINT_10); break; case 17: write0(VARINT_11); break; case 18: write0(VARINT_12); break; case 19: write0(VARINT_13); break; |
| case 20: write0(VARINT_14); break; case 21: write0(VARINT_15); break; case 22: write0(VARINT_16); break; case 23: write0(VARINT_17); break; |
| case 24: write0(VARINT_18); break; case 25: write0(VARINT_19); break; case 26: write0(VARINT_1A); break; case 27: write0(VARINT_1B); break; |
| case 28: write0(VARINT_1C); break; case 29: write0(VARINT_1D); break; case 30: write0(VARINT_1E); break; case 31: write0(VARINT_1F); break; |
| default: |
| write0(VARINT8); |
| write0(v); |
| } |
| } |
| |
| public void writeShort(short v) throws IOException |
| { |
| writeVarint32(v); |
| } |
| |
| public void writeInt(int v) throws IOException |
| { |
| writeVarint32(v); |
| } |
| |
| public void writeLong(long v) throws IOException |
| { |
| writeVarint64(v); |
| } |
| |
| public void writeFloat(float v) throws IOException |
| { |
| writeVarint32(Float.floatToRawIntBits(v)); |
| } |
| |
| public void writeDouble(double v) throws IOException |
| { |
| writeVarint64(Double.doubleToRawLongBits(v)); |
| } |
| |
| public void writeUTF(String v) throws IOException |
| { |
| if( v == null ) |
| { |
| write0(OBJECT_NULL); |
| } |
| else |
| { |
| int len = v.length(); |
| if( len == 0 ) |
| { |
| write0(OBJECT_DUMMY); |
| } |
| else |
| { |
| write0(OBJECT_BYTES); |
| writeUInt(len); |
| |
| int off = 0, limit = mLimit - 3, size; |
| char[] buf = mCharBuf; |
| do |
| { |
| size = Math.min(len-off, CHAR_BUF_SIZE); |
| v.getChars(off, off+size, buf, 0); |
| |
| for(int i=0;i<size;i++) |
| { |
| char c = buf[i]; |
| if( mPosition > limit ) |
| { |
| if( c < 0x80 ) |
| { |
| write0((byte)c); |
| } |
| else if( c < 0x800 ) |
| { |
| write0((byte)(0xC0 | ((c >> 6) & 0x1F))); |
| write0((byte)(0x80 | (c & 0x3F))); |
| } |
| else |
| { |
| write0((byte)(0xE0 | ((c >> 12) & 0x0F))); |
| write0((byte)(0x80 | ((c >> 6) & 0x3F))); |
| write0((byte)(0x80 | (c & 0x3F))); |
| } |
| } |
| else |
| { |
| if( c < 0x80 ) |
| { |
| mBuffer[mPosition++] = (byte)c; |
| } |
| else if( c < 0x800 ) |
| { |
| mBuffer[mPosition++] = (byte)(0xC0 | ((c >> 6) & 0x1F)); |
| mBuffer[mPosition++] = (byte)(0x80 | (c & 0x3F)); |
| } |
| else |
| { |
| mBuffer[mPosition++] = (byte)(0xE0 | ((c >> 12) & 0x0F)); |
| mBuffer[mPosition++] = (byte)(0x80 | ((c >> 6) & 0x3F)); |
| mBuffer[mPosition++] = (byte)(0x80 | (c & 0x3F)); |
| } |
| } |
| } |
| off += size; |
| } |
| while( off < len ); |
| } |
| } |
| } |
| |
| public void writeBytes(byte[] b) throws IOException |
| { |
| if( b == null ) |
| write0(OBJECT_NULL); |
| else |
| writeBytes(b, 0, b.length); |
| } |
| |
| public void writeBytes(byte[] b, int off, int len) throws IOException |
| { |
| if( len == 0 ) |
| { |
| write0(OBJECT_DUMMY); |
| } |
| else |
| { |
| write0(OBJECT_BYTES); |
| writeUInt(len); |
| write0(b, off, len); |
| } |
| } |
| |
| public void flushBuffer() throws IOException |
| { |
| if( mPosition > 0 ) |
| { |
| mOutput.write(mBuffer, 0, mPosition); |
| mPosition = 0; |
| } |
| } |
| |
| public void writeUInt(int v) throws IOException |
| { |
| byte tmp; |
| while( true ) |
| { |
| tmp = (byte)( v & 0x7f ); |
| if( ( v >>>= 7 ) == 0 ) |
| { |
| write0( (byte)( tmp | 0x80 ) ); |
| return; |
| } |
| else |
| { |
| write0(tmp); |
| } |
| } |
| } |
| |
| protected void write0(byte b) throws IOException |
| { |
| if( mPosition == mLimit ) |
| flushBuffer(); |
| |
| mBuffer[mPosition++] = b; |
| } |
| |
| protected void write0(byte[] b, int off, int len) throws IOException |
| { |
| int rem = mLimit - mPosition; |
| if( rem > len ) |
| { |
| System.arraycopy(b, off, mBuffer, mPosition, len); |
| mPosition += len; |
| } |
| else |
| { |
| System.arraycopy(b, off, mBuffer, mPosition, rem); |
| mPosition = mLimit; |
| flushBuffer(); |
| |
| off += rem; |
| len -= rem; |
| |
| if( mLimit > len ) |
| { |
| System.arraycopy(b, off, mBuffer, 0, len); |
| mPosition = len; |
| } |
| else |
| { |
| mOutput.write(b, off, len); |
| } |
| } |
| } |
| |
| private void writeVarint32(int v) throws IOException |
| { |
| switch( v ) |
| { |
| case -15: write0(VARINT_NF); break; case -14: write0(VARINT_NE); break; case -13: write0(VARINT_ND); break; |
| case -12: write0(VARINT_NC); break; case -11: write0(VARINT_NB); break; case -10: write0(VARINT_NA); break; case -9: write0(VARINT_N9); break; |
| case -8: write0(VARINT_N8); break; case -7: write0(VARINT_N7); break; case -6: write0(VARINT_N6); break; case -5: write0(VARINT_N5); break; |
| case -4: write0(VARINT_N4); break; case -3: write0(VARINT_N3); break; case -2: write0(VARINT_N2); break; case -1: write0(VARINT_N1); break; |
| case 0: write0(VARINT_0); break; case 1: write0(VARINT_1); break; case 2: write0(VARINT_2); break; case 3: write0(VARINT_3); break; |
| case 4: write0(VARINT_4); break; case 5: write0(VARINT_5); break; case 6: write0(VARINT_6); break; case 7: write0(VARINT_7); break; |
| case 8: write0(VARINT_8); break; case 9: write0(VARINT_9); break; case 10: write0(VARINT_A); break; case 11: write0(VARINT_B); break; |
| case 12: write0(VARINT_C); break; case 13: write0(VARINT_D); break; case 14: write0(VARINT_E); break; case 15: write0(VARINT_F); break; |
| case 16: write0(VARINT_10); break; case 17: write0(VARINT_11); break; case 18: write0(VARINT_12); break; case 19: write0(VARINT_13); break; |
| case 20: write0(VARINT_14); break; case 21: write0(VARINT_15); break; case 22: write0(VARINT_16); break; case 23: write0(VARINT_17); break; |
| case 24: write0(VARINT_18); break; case 25: write0(VARINT_19); break; case 26: write0(VARINT_1A); break; case 27: write0(VARINT_1B); break; |
| case 28: write0(VARINT_1C); break; case 29: write0(VARINT_1D); break; case 30: write0(VARINT_1E); break; case 31: write0(VARINT_1F); break; |
| default: |
| int t = v, ix = 0; |
| byte[] b = mTemp; |
| |
| while( true ) |
| { |
| b[++ix] = (byte)( v & 0xff ); |
| if( ( v >>>= 8 ) == 0 ) |
| break; |
| } |
| |
| if( t > 0 ) |
| { |
| // [ 0a e2 => 0a e2 00 ] [ 92 => 92 00 ] |
| if( b[ix] < 0 ) |
| b[++ix] = 0; |
| } |
| else |
| { |
| // [ 01 ff ff ff => 01 ff ] [ e0 ff ff ff => e0 ] |
| while( b[ix] == (byte)0xff && b[ix-1] < 0 ) |
| ix--; |
| } |
| |
| b[0] = (byte)( VARINT + ix - 1 ); |
| write0(b, 0, ix+1); |
| } |
| } |
| |
| private void writeVarint64(long v) throws IOException |
| { |
| int i = (int)v; |
| if( v == i ) |
| { |
| writeVarint32(i); |
| } |
| else |
| { |
| long t = v; |
| int ix = 0; |
| byte[] b = mTemp; |
| |
| while( true ) |
| { |
| b[++ix] = (byte)( v & 0xff ); |
| if( ( v >>>= 8 ) == 0 ) |
| break; |
| } |
| |
| if( t > 0 ) |
| { |
| // [ 0a e2 => 0a e2 00 ] [ 92 => 92 00 ] |
| if( b[ix] < 0 ) |
| b[++ix] = 0; |
| } |
| else |
| { |
| // [ 01 ff ff ff => 01 ff ] [ e0 ff ff ff => e0 ] |
| while( b[ix] == (byte)0xff && b[ix-1] < 0 ) |
| ix--; |
| } |
| |
| b[0] = (byte)( VARINT + ix - 1 ); |
| write0(b, 0, ix+1); |
| } |
| } |
| } |