# File lib/net/ber/ber_parser.rb, line 35
      def read_ber syntax=nil
        # TODO: clean this up so it works properly with partial
        # packets coming from streams that don't block when
        # we ask for more data (like StringIOs). At it is,
        # this can throw TypeErrors and other nasties.
                
        id = getbyte or return nil  # don't trash this value, we'll use it later

        n = getbyte
        lengthlength,contentlength = if n <= 127
          [1,n]
        else
          # Replaced the inject because it profiles hot.
          #   j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc}
          j = 0
          read( n & 127 ).each_byte {|n1| j = (j << 8) + n1}
          [1 + (n & 127), j]
        end

        newobj = read contentlength

        # This exceptionally clever and clear bit of code is verrrry slow.
        objtype = (syntax && syntax[id]) || BuiltinSyntax[id]

        # == is expensive so sort this if/else so the common cases are at the top.
        obj = if objtype == :string
          #(newobj || "").dup
          s = BerIdentifiedString.new( newobj || "" )
          s.ber_identifier = id
          s
        elsif objtype == :integer
          j = 0
          newobj.each_byte {|b| j = (j << 8) + b}
          j
        elsif objtype == :oid
          # cf X.690 pgh 8.19 for an explanation of this algorithm.
          # Potentially not good enough. We may need a BerIdentifiedOid
          # as a subclass of BerIdentifiedArray, to get the ber identifier
          # and also a to_s method that produces the familiar dotted notation.
          oid = newobj.unpack("w*")
          f = oid.shift
          g = if f < 40
            [0, f]
          elsif f < 80
            [1, f-40]
          else
            [2, f-80] # f-80 can easily be > 80. What a weird optimization.
          end
          oid.unshift g.last
          oid.unshift g.first
          oid
        elsif objtype == :array
          #seq = []
          seq = BerIdentifiedArray.new
          seq.ber_identifier = id
          sio = StringIO.new( newobj || "" )
          # Interpret the subobject, but note how the loop
          # is built: nil ends the loop, but false (a valid
          # BER value) does not!
          while (e = sio.read_ber(syntax)) != nil
            seq << e
          end
          seq
        elsif objtype == :boolean
          newobj != "\000"
        elsif objtype == :null
          n = BerIdentifiedNull.new
          n.ber_identifier = id
          n
        else
          raise BerError.new( "unsupported object type: id=#{id}" )
        end

        obj
      end