Module: Net::BER::BERParser

Included in:
IO, StringIO
Defined in:
lib/net/ber.rb

Overview

This module is for mixing into IO and IO-like objects.

Constant Summary collapse

TagClasses =

The order of these follows the class-codes in BER. Maybe this should have been a hash.

[:universal, :application, :context_specific, :private]
BuiltinSyntax =
{
  :universal => {
    :primitive => {
      1 => :boolean,
      2 => :integer,
      4 => :string,
      10 => :integer,
    },
    :constructed => {
      16 => :array,
      17 => :array
    }
  }
}

Instance Method Summary collapse

Instance Method Details

#read_ber(syntax = nil) ⇒ Object

read_ber 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.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/net/ber.rb', line 70

def read_ber syntax=nil
  return nil if eof?

  id = getc  # don't trash this value, we'll use it later
  tag = id & 31
  tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" )
  tagclass = TagClasses[ id >> 6 ]
  encoding = (id & 0x20 != 0) ? :constructed : :primitive

  n = getc
  lengthlength,contentlength = if n <= 127
    [1,n]
  else
    j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc}
    [1 + (n & 127), j]
  end

  newobj = read contentlength

  objtype = nil
  [syntax, BuiltinSyntax].each {|syn|
    if syn && (ot = syn[tagclass]) && (ot = ot[encoding]) && ot[tag]
      objtype = ot[tag]
      break
    end
  }
  
  obj = case objtype
  when :boolean
    newobj != "\000"
  when :string
    (newobj || "").dup
  when :integer
    j = 0
    newobj.each_byte {|b| j = (j << 8) + b}
    j
  when :array
    seq = []
    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
  else
    raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" )
  end

  # Add the identifier bits into the object if it's a String or an Array.
  # We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway.
  obj and ([String,Array].include? obj.class) and obj.instance_eval "def ber_identifier; #{id}; end"
  obj

end