lib/bindata/primitive.rb
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