serial.rb (3702B)
1 # Copyright (C) 2007 Kris Maglione 2 # See PERMISSIONS 3 4 module R9P 5 class Serial 6 Conv = { 7 :byte => [ 1, 'C' ], 8 :word => [ 2, 'v' ], 9 :dword => [ 4, 'V' ], 10 } 11 12 attr_reader :fields, :serial, :opstack 13 14 def initialize(data) 15 @fields ||= {} 16 @serial ||= '' 17 @opstack = [] 18 print "#{self.class.inspect}.new(#{data.inspect})\n" if $debug > 5 19 case data 20 when String 21 deserialize data 22 when Hash 23 fields.merge! data 24 end 25 print "\tFields: #{fields.inspect}\n\n" if $debug > 5 26 end 27 28 def deserialize(data = @serial) 29 @opstack = [] 30 @serial = data 31 unstack self.class.field_stack 32 self 33 end 34 def serialize 35 print "serialize #{self.inspect}\n" if $debug > 4 36 @opstack = [] 37 @serial = stack self.class.field_stack 38 end 39 40 def fields 41 @fields ||= {} 42 end 43 def opstack 44 @opstack 45 end 46 def serial 47 @serial ||= "" 48 end 49 50 def slice 51 if @offset > 0 52 @serial.slice!(0..@offset-1) 53 @offset = 0 54 end 55 end 56 def unstack(stack) 57 print "\nunstack(stack): #{self.class.inspect}\n" if $debug > 4 58 @offset = 0 59 stack.each { |op| 60 print "\top: #{op.inspect} top: #{@opstack[-1].inspect}\n" if $debug > 4 61 print "\tserial: #{@serial.inspect}\n" if $debug > 6 62 case op 63 when Field 64 fields[op.name] = pop 65 when Array 66 list = (1..pop).to_a.collect! { 67 unstack op 68 pop 69 } 70 push list 71 when :string 72 num = pop 73 str, = unpack num, "a#{num}" 74 push str 75 when :qword 76 low, high = unpack 8, "VV" 77 push high<<32|low 78 when :size 79 when Symbol 80 push unpack(*Conv[op])[0] 81 when Module 82 if op <= Serial 83 slice 84 push op.new(@serial) 85 end 86 end 87 } 88 print "\n/unstack(stack): #{self.class.inspect}\n" if $debug > 4 89 slice 90 self 91 end 92 def stack(stack) 93 print "\nstack(stack): #{self.class.inspect}\n" if $debug > 4 94 stack.reverse.each { |op| 95 print "\top: #{op.inspect} top: #{@opstack[-1].inspect}\n" if $debug > 4 96 print "\tstack: #{@opstack.inspect}\n" if $debug > 5 97 print "\tserial: #{@serial.inspect}\n" if $debug > 5 98 case op 99 when Field 100 push @fields[op.name] 101 when Array 102 list = pop 103 list.reverse.each { |i| 104 push i 105 stack op 106 } 107 push list.length 108 when :string 109 str = pop 110 push str 111 push str.length 112 when :qword 113 num = pop 114 push [num, num >> 32].pack("VV") 115 when :size 116 add = pop 117 push @opstack.inject(add) { |l, o| l + o.length } 118 when Symbol 119 push [pop].pack(Conv[op][1]) 120 when Module 121 if op <= Serial 122 push op.new(@serial).serialize 123 end 124 else 125 pop 126 push op 127 end 128 } 129 print "\n/stack(stack): #{self.class.inspect}\n" if $debug > 4 130 @opstack.reverse.join '' 131 end 132 133 def push(arg) 134 @opstack.push arg 135 end 136 def pop 137 @opstack.pop 138 end 139 def unpack(length, fmt) 140 print "unpack(#{length}, #{fmt}) @offset: #{@offset}\n" if $debug > 5 141 @offset += length 142 @serial.unpack("@#{@offset-length}#{fmt}") 143 end 144 145 def to_s 146 "fields: #{@fields.inspect}, serial: #{@serial.inspect}, stack: #{@opstack.inspect}" 147 end 148 def inspect 149 "#<#{self.class.inspect} #{to_s}>" 150 end 151 152 class Field 153 attr_reader :name 154 def initialize(name) 155 @name = name 156 end 157 end 158 159 class <<self 160 def field_stack 161 @field_stack ||=if self.superclass <= Serial 162 self.superclass.field_stack.clone 163 else 164 [] 165 end 166 end 167 def field(name, *rest) 168 module_eval <<-"end_eval" 169 def #{name.id2name} 170 @fields[#{name.inspect}] 171 end 172 def #{name.id2name}=(val) 173 @fields[#{name.inspect}] = val 174 end 175 end_eval 176 self.field_stack.concat(rest) << Field.new(name) 177 end 178 end 179 end 180 end