r9p

git clone git://oldgit.suckless.org/r9p/
Log | Files | Refs

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