1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
require 'bindata/base_primitive'
require 'bindata/dsl'
require 'bindata/struct'
module BinData
# A Primitive is a declarative way to define a new BinData data type.
# The data type must contain a primitive value only, i.e numbers or strings.
# For new data types that contain multiple values see BinData::Record.
#
# To define a new data type, set fields as if for Record and add a
# #get and #set method to extract / convert the data between the fields
# and the #value of the object.
#
# require 'bindata'
#
# class PascalString < BinData::Primitive
# uint8 :len, value: -> { data.length }
# string :data, read_length: :len
#
# def get
# self.data
# end
#
# def set(v)
# self.data = v
# end
# end
#
# ps = PascalString.new(initial_value: "hello")
# ps.to_binary_s #=> "\005hello"
# ps.read("\003abcde")
# ps #=> "abc"
#
# # Unsigned 24 bit big endian integer
# class Uint24be < BinData::Primitive
# uint8 :byte1
# uint8 :byte2
# uint8 :byte3
#
# def get
# (self.byte1 << 16) | (self.byte2 << 8) | self.byte3
# end
#
# def set(v)
# v = 0 if v < 0
# v = 0xffffff if v > 0xffffff
#
# self.byte1 = (v >> 16) & 0xff
# self.byte2 = (v >> 8) & 0xff
# self.byte3 = v & 0xff
# end
# end
#
# u24 = Uint24be.new
# u24.read("\x12\x34\x56")
# "0x%x" % u24 #=> 0x123456
#
# == Parameters
#
# Primitive objects accept all the parameters that BinData::BasePrimitive do.
#
class Primitive < BasePrimitive
extend DSLMixin
unregister_self
dsl_parser :primitive
arg_processor :primitive
mandatory_parameter :struct_params
def initialize_instance
super
@struct = BinData::Struct.new(get_parameter(:struct_params), self)
end
def respond_to?(symbol, include_private = false) #:nodoc:
@struct.respond_to?(symbol, include_private) || super
end
def method_missing(symbol, *args, &block) #:nodoc:
if @struct.respond_to?(symbol)
@struct.__send__(symbol, *args, &block)
else
super
end
end
def assign(val)
super(val)
set(_value)
@value = get
end
def debug_name_of(child) #:nodoc:
debug_name + "-internal-"
end
def do_write(io)
set(_value)
@struct.do_write(io)
end
def do_num_bytes
set(_value)
@struct.do_num_bytes
end
#---------------
private
def sensible_default
get
end
def read_and_return_value(io)
@struct.do_read(io)
get
end
###########################################################################
# To be implemented by subclasses
# Extracts the value for this data object from the fields of the
# internal struct.
def get
raise NotImplementedError
end
# Sets the fields of the internal struct to represent +v+.
def set(v)
raise NotImplementedError
end
# To be implemented by subclasses
###########################################################################
end
class PrimitiveArgProcessor < BaseArgProcessor
def sanitize_parameters!(obj_class, params)
params[:struct_params] = params.create_sanitized_params(obj_class.dsl_params, BinData::Struct)
end
end
end
|