1require 'dl' 2 3module DL 4 module PackInfo 5 ALIGN_MAP = { 6 TYPE_VOIDP => ALIGN_VOIDP, 7 TYPE_CHAR => ALIGN_CHAR, 8 TYPE_SHORT => ALIGN_SHORT, 9 TYPE_INT => ALIGN_INT, 10 TYPE_LONG => ALIGN_LONG, 11 TYPE_FLOAT => ALIGN_FLOAT, 12 TYPE_DOUBLE => ALIGN_DOUBLE, 13 -TYPE_CHAR => ALIGN_CHAR, 14 -TYPE_SHORT => ALIGN_SHORT, 15 -TYPE_INT => ALIGN_INT, 16 -TYPE_LONG => ALIGN_LONG, 17 } 18 19 PACK_MAP = { 20 TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"), 21 TYPE_CHAR => "c", 22 TYPE_SHORT => "s!", 23 TYPE_INT => "i!", 24 TYPE_LONG => "l!", 25 TYPE_FLOAT => "f", 26 TYPE_DOUBLE => "d", 27 -TYPE_CHAR => "c", 28 -TYPE_SHORT => "s!", 29 -TYPE_INT => "i!", 30 -TYPE_LONG => "l!", 31 } 32 33 SIZE_MAP = { 34 TYPE_VOIDP => SIZEOF_VOIDP, 35 TYPE_CHAR => SIZEOF_CHAR, 36 TYPE_SHORT => SIZEOF_SHORT, 37 TYPE_INT => SIZEOF_INT, 38 TYPE_LONG => SIZEOF_LONG, 39 TYPE_FLOAT => SIZEOF_FLOAT, 40 TYPE_DOUBLE => SIZEOF_DOUBLE, 41 -TYPE_CHAR => SIZEOF_CHAR, 42 -TYPE_SHORT => SIZEOF_SHORT, 43 -TYPE_INT => SIZEOF_INT, 44 -TYPE_LONG => SIZEOF_LONG, 45 } 46 if defined?(TYPE_LONG_LONG) 47 ALIGN_MAP[TYPE_LONG_LONG] = ALIGN_MAP[-TYPE_LONG_LONG] = ALIGN_LONG_LONG 48 PACK_MAP[TYPE_LONG_LONG] = PACK_MAP[-TYPE_LONG_LONG] = "q" 49 SIZE_MAP[TYPE_LONG_LONG] = SIZE_MAP[-TYPE_LONG_LONG] = SIZEOF_LONG_LONG 50 end 51 52 def align(addr, align) 53 d = addr % align 54 if( d == 0 ) 55 addr 56 else 57 addr + (align - d) 58 end 59 end 60 module_function :align 61 end 62 63 class Packer 64 include PackInfo 65 66 def self.[](*types) 67 new(types) 68 end 69 70 def initialize(types) 71 parse_types(types) 72 end 73 74 def size() 75 @size 76 end 77 78 def pack(ary) 79 case SIZEOF_VOIDP 80 when SIZEOF_LONG 81 ary.pack(@template) 82 when SIZEOF_LONG_LONG 83 ary.pack(@template) 84 else 85 raise(RuntimeError, "sizeof(void*)?") 86 end 87 end 88 89 def unpack(ary) 90 case SIZEOF_VOIDP 91 when SIZEOF_LONG 92 ary.join().unpack(@template) 93 when SIZEOF_LONG_LONG 94 ary.join().unpack(@template) 95 else 96 raise(RuntimeError, "sizeof(void*)?") 97 end 98 end 99 100 private 101 102 def parse_types(types) 103 @template = "" 104 addr = 0 105 types.each{|t| 106 orig_addr = addr 107 if( t.is_a?(Array) ) 108 addr = align(orig_addr, ALIGN_MAP[TYPE_VOIDP]) 109 else 110 addr = align(orig_addr, ALIGN_MAP[t]) 111 end 112 d = addr - orig_addr 113 if( d > 0 ) 114 @template << "x#{d}" 115 end 116 if( t.is_a?(Array) ) 117 @template << (PACK_MAP[t[0]] * t[1]) 118 addr += (SIZE_MAP[t[0]] * t[1]) 119 else 120 @template << PACK_MAP[t] 121 addr += SIZE_MAP[t] 122 end 123 } 124 addr = align(addr, ALIGN_MAP[TYPE_VOIDP]) 125 @size = addr 126 end 127 end 128end 129