diff options
| author | Kip Cole | 2012-10-04 07:34:41 +0800 | 
|---|---|---|
| committer | Kip Cole | 2012-10-04 07:34:41 +0800 | 
| commit | 4525becf2fd07058de87ed3c9e8aabe93bd7107d (patch) | |
| tree | ea2685dab5bbce06206640229af39690395818c6 /vendor/thrift/protocol/compact_protocol.rb | |
| parent | d075e04fc0a5aec62ecba37581833f494affd6cd (diff) | |
| download | evernote-4525becf2fd07058de87ed3c9e8aabe93bd7107d.tar.bz2 | |
Notestore wrapper updated for oauth, add transforms from ruby method names to camel-case names in the thrift interface
Diffstat (limited to 'vendor/thrift/protocol/compact_protocol.rb')
| -rw-r--r-- | vendor/thrift/protocol/compact_protocol.rb | 426 | 
1 files changed, 426 insertions, 0 deletions
| diff --git a/vendor/thrift/protocol/compact_protocol.rb b/vendor/thrift/protocol/compact_protocol.rb new file mode 100644 index 0000000..ede82f2 --- /dev/null +++ b/vendor/thrift/protocol/compact_protocol.rb @@ -0,0 +1,426 @@ +#  +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +#  + +module Thrift +  class CompactProtocol < BaseProtocol + +    PROTOCOL_ID = [0x82].pack('c').unpack('c').first +    VERSION = 1 +    VERSION_MASK = 0x1f +    TYPE_MASK = 0xE0 +    TYPE_SHIFT_AMOUNT = 5 + +    TSTOP = ["", Types::STOP, 0] + +    #  +    # All of the on-wire type codes. +    #  +    class CompactTypes +      BOOLEAN_TRUE   = 0x01 +      BOOLEAN_FALSE  = 0x02 +      BYTE           = 0x03 +      I16            = 0x04 +      I32            = 0x05 +      I64            = 0x06 +      DOUBLE         = 0x07 +      BINARY         = 0x08 +      LIST           = 0x09 +      SET            = 0x0A +      MAP            = 0x0B +      STRUCT         = 0x0C +       +      def self.is_bool_type?(b) +        (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE +      end +       +      COMPACT_TO_TTYPE = { +        Types::STOP   => Types::STOP, +        BOOLEAN_FALSE => Types::BOOL, +        BOOLEAN_TRUE  => Types::BOOL, +        BYTE          => Types::BYTE, +        I16           => Types::I16, +        I32           => Types::I32, +        I64           => Types::I64, +        DOUBLE        => Types::DOUBLE, +        BINARY        => Types::STRING, +        LIST          => Types::LIST, +        SET           => Types::SET, +        MAP           => Types::MAP, +        STRUCT        => Types::STRUCT +      } + +      TTYPE_TO_COMPACT = { +        Types::STOP           => Types::STOP, +        Types::BOOL           => BOOLEAN_TRUE, +        Types::BYTE           => BYTE, +        Types::I16            => I16, +        Types::I32            => I32, +        Types::I64            => I64, +        Types::DOUBLE         => DOUBLE, +        Types::STRING         => BINARY, +        Types::LIST           => LIST, +        Types::SET            => SET, +        Types::MAP            => MAP, +        Types::STRUCT         => STRUCT +      } +       +      def self.get_ttype(compact_type) +        val = COMPACT_TO_TTYPE[compact_type & 0x0f] +        raise "don't know what type: #{compact_type & 0x0f}" unless val +        val +      end +       +      def self.get_compact_type(ttype) +        val = TTYPE_TO_COMPACT[ttype] +        raise "don't know what type: #{ttype & 0x0f}" unless val +        val +      end +    end + +    def initialize(transport) +      super(transport) + +      @last_field = [0] +      @boolean_value = nil + +      # Pre-allocated read buffer for read_double(). +      @rbuf = "\0" * 8 +      @rbuf.force_encoding("BINARY") if @rbuf.respond_to?(:force_encoding) +    end + +    def write_message_begin(name, type, seqid) +      write_byte(PROTOCOL_ID) +      write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK)) +      write_varint32(seqid) +      write_string(name) +      nil +    end + +    def write_struct_begin(name) +      @last_field.push(0) +      nil +    end + +    def write_struct_end +      @last_field.pop +      nil +    end + +    def write_field_begin(name, type, id) +      if type == Types::BOOL +        # we want to possibly include the value, so we'll wait. +        @boolean_field = [type, id] +      else +        write_field_begin_internal(type, id) +      end +      nil +    end + +    #  +    # The workhorse of writeFieldBegin. It has the option of doing a  +    # 'type override' of the type header. This is used specifically in the  +    # boolean field case. +    #  +    def write_field_begin_internal(type, id, type_override=nil) +      last_id = @last_field.pop +       +      # if there's a type override, use that. +      typeToWrite = type_override || CompactTypes.get_compact_type(type) + +      # check if we can use delta encoding for the field id +      if id > last_id && id - last_id <= 15 +        # write them together +        write_byte((id - last_id) << 4 | typeToWrite) +      else +        # write them separate +        write_byte(typeToWrite) +        write_i16(id) +      end + +      @last_field.push(id) +      nil +    end + +    def write_field_stop +      write_byte(Types::STOP) +    end + +    def write_map_begin(ktype, vtype, size) +      if (size == 0) +        write_byte(0) +      else +        write_varint32(size) +        write_byte(CompactTypes.get_compact_type(ktype) << 4 | CompactTypes.get_compact_type(vtype)) +      end +    end + +    def write_list_begin(etype, size) +      write_collection_begin(etype, size) +    end + +    def write_set_begin(etype, size) +      write_collection_begin(etype, size); +    end + +    def write_bool(bool) +      type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE +      unless @boolean_field.nil? +        # we haven't written the field header yet +        write_field_begin_internal(@boolean_field.first, @boolean_field.last, type) +        @boolean_field = nil +      else +        # we're not part of a field, so just write the value. +        write_byte(type) +      end +    end + +    def write_byte(byte) +      @trans.write([byte].pack('c')) +    end + +    def write_i16(i16) +      write_varint32(int_to_zig_zag(i16)) +    end + +    def write_i32(i32) +      write_varint32(int_to_zig_zag(i32)) +    end + +    def write_i64(i64) +      write_varint64(long_to_zig_zag(i64)) +    end + +    def write_double(dub) +      @trans.write([dub].pack("G").reverse) +    end + +    def write_string(str) +      write_varint32(str.length) +      @trans.write(str) +    end + +    def read_message_begin +      protocol_id = read_byte() +      if protocol_id != PROTOCOL_ID +        raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}") +      end +       +      version_and_type = read_byte() +      version = version_and_type & VERSION_MASK +      if (version != VERSION) +        raise ProtocolException.new("Expected version #{VERSION} but got #{version}"); +      end +       +      type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03 +      seqid = read_varint32() +      messageName = read_string() +      [messageName, type, seqid] +    end + +    def read_struct_begin +      @last_field.push(0) +      "" +    end + +    def read_struct_end +      @last_field.pop() +      nil +    end + +    def read_field_begin +      type = read_byte() + +      # if it's a stop, then we can return immediately, as the struct is over. +      if (type & 0x0f) == Types::STOP +        TSTOP +      else +        field_id = nil + +        # mask off the 4 MSB of the type header. it could contain a field id delta. +        modifier = (type & 0xf0) >> 4 +        if modifier == 0 +          # not a delta. look ahead for the zigzag varint field id. +          @last_field.pop +          field_id = read_i16() +        else +          # has a delta. add the delta to the last read field id. +          field_id = @last_field.pop + modifier +        end + +        # if this happens to be a boolean field, the value is encoded in the type +        if CompactTypes.is_bool_type?(type) +          # save the boolean value in a special instance variable. +          @bool_value = (type & 0x0f) == CompactTypes::BOOLEAN_TRUE +        end + +        # push the new field onto the field stack so we can keep the deltas going. +        @last_field.push(field_id) +        ["", CompactTypes.get_ttype(type & 0x0f), field_id] +      end +    end + +    def read_map_begin +      size = read_varint32() +      key_and_value_type = size == 0 ? 0 : read_byte() +      [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size] +    end + +    def read_list_begin +      size_and_type = read_byte() +      size = (size_and_type >> 4) & 0x0f +      if size == 15 +        size = read_varint32() +      end +      type = CompactTypes.get_ttype(size_and_type) +      [type, size] +    end + +    def read_set_begin +      read_list_begin +    end + +    def read_bool +      unless @bool_value.nil? +        bv = @bool_value +        @bool_value = nil +        bv +      else +        read_byte() == CompactTypes::BOOLEAN_TRUE +      end +    end + +    def read_byte +      val = trans.read_byte +      if (val > 0x7f) +        val = 0 - ((val - 1) ^ 0xff) +      end +      val +    end + +    def read_i16 +      zig_zag_to_int(read_varint32()) +    end + +    def read_i32 +      zig_zag_to_int(read_varint32()) +    end + +    def read_i64 +      zig_zag_to_long(read_varint64()) +    end + +    def read_double +      trans.read_into_buffer(@rbuf, 8) +      val = @rbuf.reverse.unpack('G').first +      val +    end + +    def read_string +      size = read_varint32() +      trans.read_all(size) +    end +     +     +    private +     +    #  +    # Abstract method for writing the start of lists and sets. List and sets on  +    # the wire differ only by the type indicator. +    #  +    def write_collection_begin(elem_type, size) +      if size <= 14 +        write_byte(size << 4 | CompactTypes.get_compact_type(elem_type)) +      else +        write_byte(0xf0 | CompactTypes.get_compact_type(elem_type)) +        write_varint32(size) +      end +    end + +    def write_varint32(n) +      # int idx = 0; +      while true +        if (n & ~0x7F) == 0 +          # i32buf[idx++] = (byte)n; +          write_byte(n) +          break +          # return; +        else +          # i32buf[idx++] = (byte)((n & 0x7F) | 0x80); +          write_byte((n & 0x7F) | 0x80) +          n = n >> 7 +        end +      end +      # trans_.write(i32buf, 0, idx); +    end + +    SEVEN_BIT_MASK = 0x7F +    EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK + +    def write_varint64(n) +      while true +        if (n & EVERYTHING_ELSE_MASK) == 0 #TODO need to find a way to make this into a long... +          write_byte(n) +          break +        else +          write_byte((n & SEVEN_BIT_MASK) | 0x80) +          n >>= 7 +        end +      end +    end +     +    def read_varint32() +      read_varint64() +    end +     +    def read_varint64() +      shift = 0 +      result = 0 +      while true +        b = read_byte() +        result |= (b & 0x7f) << shift +        break if (b & 0x80) != 0x80 +        shift += 7 +      end +      result +    end +     +    def int_to_zig_zag(n) +      (n << 1) ^ (n >> 31) +    end +     +    def long_to_zig_zag(l) +      # puts "zz encoded #{l} to #{(l << 1) ^ (l >> 63)}" +      (l << 1) ^ (l >> 63) +    end +     +    def zig_zag_to_int(n) +      (n >> 1) ^ -(n & 1) +    end +     +    def zig_zag_to_long(n) +      (n >> 1) ^ -(n & 1) +    end +  end + +  class CompactProtocolFactory < BaseProtocolFactory +    def get_protocol(trans) +      CompactProtocol.new(trans) +    end +  end +end | 
