Giter Club home page Giter Club logo

bit-struct's Introduction

I'm @[email protected].

I mostly use a private network of gitolite instances instead of github, so these are old projects. Just to mention one, which might be useful someday: RedShift is a modeling and simulation framework for dynamic networks of hybrid automata (AKA Cyber-Physical Systems), based on (obsolete) SHIFT. Nothing else does quite what these two languages do. Check out the examples. You'll need ruby and a working C compiler.

bit-struct's People

Contributors

abarisani avatar busterb avatar egypt avatar komep avatar vjoel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bit-struct's Issues

Variable list field parsed by block

Hi, first off I just want to say this library has been fantastic. It has handled almost all of my uses cases. However, I am dealing with an issue where the last bits of data contain an list of structures of unknown length. Ideally I would like to be able to define my own block for parsing them automagically.

I tried using vectors but I had to declare length and was limited parsing a single class of static size.

Is there an elegant way to do this already? If can you give me some pointers on how to get started so I can contribute something?

If you want any reference the file with issue is here : https://github.com/Sovietaced/OpenFlow/blob/master/lib/openflow/v10/stats/flow_stats_reply.rb

The last line rest :actions is defined in the protocol spec as

< struct ofp_action_header actions[0]; /* Actions. */ >
or a list of actions.

These actions are defined here : https://github.com/Sovietaced/OpenFlow/tree/master/lib/openflow/v10/action

Most of them are subclasses of action.rb and tend to have variable lengths.

I want to create a nice case statement to handle those and return them to a list.

bit-struct struggle conversion issues in Rubinus

I have some code written originally for Ruby 1.8 that works in Ruby 1.9, but fails in Rubinus 2.3.0 with the following exception:

undefined conversion for '#<Example::Header foo_component="\xfeXYZ", command=0, beer_buffer="\u0000\u0000\u0000\u0000", flags=24, flags2=0, pid_high=0, signature="\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", vid=0, xid=0, zid=0, yid=0>' from UTF-8 to ASCII-8BIT (Encoding::CompatibilityError)

I don't know if it's an issue with the Rubinus or bit-struct, but Ruby 2.1 doesn't have this problem (FOO_CONTAINER constant may require enforce_encoding to make it work, but others remain). This is definitely a problem of using String as container for binary data.

The example code below (sorry, but it's long):

# This is an standalone example causing encoding issue in Rubinus

require 'rubygems'
require 'bit-struct'

require 'stringio'

class Enum
  include Comparable

  class << self

    # Return true if the classes are close enough
    def checkclass(k1, k2)
      if k1.kind_of?(Integer) && k2.kind_of?(Integer)
        return true
      end
      return k1.class == k2.class
    end

    def initialize_enum(hash)
      self.to_s.match(/(.*)::[^:]*/)
      module0 = $1.nil?() ? "Kernel" : $1
      @typical = hash.first[1]
      @value_to_name = Hash.new()
      hash.each { |name, value|
        if !checkclass(value, @typical)
          raise "Error mixed type Enum.  Enum previously initialized with #{@typical}:#{@typical.class} initialized with #{name} => #{value}:#{value.class}"
        end
        hashed_value = value.hash
        if @value_to_name[hashed_value].nil?()
          @value_to_name[hashed_value] = Array.new
        end
        @value_to_name[hashed_value].push(name)
        eval(module0).const_set(name.intern(), self.new(value))
      }
    end

    def value_to_name(value)
      names = @value_to_name[value.hash]
      return "<unknown>" if names.nil? || names.empty?

      result = ""
      names.each() { |name|
        if !result.empty?()
          result += " or "
        end
        result += name
      }
      return result
    end

    def value_is_valid(value)
      names = @value_to_name[value.hash]
      return !names.nil? && !names.empty?
    end

    def create_value(value)
      if @typical.kind_of?(Integer)
        value
      else
        @typical.class.new(value)
      end
    end
  end

  def initialize(value)
    @value = self.class.create_value(value.to_i)
  end

  attr :value

  def <=>(rhs)
    if rhs.kind_of?(self.class)
      return @value <=> rhs.value
    else
      return @value <=> rhs
    end
  end

  def to_i()
    return @value.to_i
  end

  def to_int()
    return @value.to_int
  end

  def to_s()
    os = StringIO.new()
    os << self.class.value_to_name(@value)
    if @value.kind_of?(Numeric)
      os << " (0x" << @value.to_s(16) << ")"
    else
      os << " " << @value.to_s
    end
    return os.string()
  end

  def <<(rhs)
    return @value << rhs
  end

  def &(rhs)
    return self.class.new(@value & rhs)
  end

  def |(rhs)
    return self.class.new(@value | rhs)
  end

  def ~
    return self.class.new(~@value)
  end
end

class TestStatus < Enum
  initialize_enum({
    # Success
    "STATUS_SUCCESS" => 0x00000000
  })
end

class ExampleStatus < Enum 
    initialize_enum({
      "EXAMPLE_STATUS" => 0x0100b70f
    })
end

class FlagsField
  include Comparable

  class << self
    def initialize_flags(hash)
      self.to_s.match(/(.*)::[^:]*/)
      module0 = $1.nil?() ? "Kernel" : $1
      @value_to_name = Hash.new()
      hash.each { |name, value|
        if @value_to_name[value].nil?
          @value_to_name[value] = Array.new
        end
        @value_to_name[value].push(name)
        eval(module0).const_set(name.intern(), self.new(value))
      }
    end

    def value_to_name(value)
      names = @value_to_name[value]
      if names.nil?() || names.empty?()
        return [nil, "<unknown> (0x#{value.to_s(16)})"]
      end
      result = ""
      names.each() { |name|
        if !result.empty?()
          result += " or "
        end
        result += name
      }
      return [value, result]
    end
  end

  def initialize(value)
    @value = value.to_i
  end

  attr :value

  def <=>(rhs)
    return @value <=> get_value_from(rhs)
  end

  def &(rhs)
    return self.class.new(@value & get_value_from(rhs))
  end

  def ^(rhs)
    return self.class.new(@value ^ get_value_from(rhs))
  end

  def |(rhs)
    return self.class.new(@value | get_value_from(rhs))
  end

  def ~
    return self.class.new(~@value)
  end

  def <<(rhs)
    return self.class.new(@value << rhs)
  end

  def to_i()
    return @value
  end

  def to_int()
    return @value
  end

  def to_s()
    os = StringIO.new()
    os << "0x" << @value.to_s(16)
    prefix = " ("
    if @value != 0
      it = 1
      while @value >= it
        if (@value & it) != 0
          os << prefix << self.class.value_to_name(it)[1]
          prefix = ", "
        end
        it <<= 1
      end
      os << ")"
    else
      result, name = self.class.value_to_name(0)
      os << prefix << name << ")" if result
    end
    return os.string()

  end

  def inspect
    return to_s
  end

  def hash
    @value.hash
  end
private

  def get_value_from(rhs)
    return rhs.kind_of?(self.class) ? rhs.value : rhs
  end
end

class Flags < FlagsField
  initialize_flags(
    "FLAGS_EXAMPLE1" => 0x80,
    "FLAGS_EXAMPLE2" => 0x40,
    "FLAGS_EXAMPLE4" => 0x10,
    "FLAGS_EXAMPLE5" => 0x08,
  )
end

class Flags2 < FlagsField
  initialize_flags(
    "FLAGS_EXAMPLE11" => 0x8000,
    "FLAGS_EXAMPLE12" => 0x4000,
    "FLAGS_EXAMPLE15" => 0x0800,
    "FLAGS_EXAMPLE16" => 0x0040,
    "FLAGS_EXAMPLE19" => 0x0001
  )
end

FOO_COMPONENT = "\xfeXYZ"

module Example 

class Header < BitStruct 
  char :foo_component, 32, "Foo Component" 
  unsigned :command, 8, "Command", :endian => :little 
  char :beer_buffer, 32, "Status" 
  unsigned :flags, 8, "Flags", :endian => :little 
  unsigned :flags2, 16, "Flags2", :endian => :little 
  unsigned :pid_high, 16, "PID High", :endian => :little
  char :signature, 64, "Signature"
  pad :reserved, 16
  unsigned :vid, 16, "VID", :endian => :little
  unsigned :xid, 16, "XID", :endian => :little
  unsigned :zid, 16, "ZID", :endian => :little
  unsigned :yid, 16, "YID", :endian => :little

  def dos_status # SRCDOC_PROTEST_GETTER_SETTER
    if (self.flags2 & FLAGS_EXAMPLE12) != 0
      raise "Error: ..."
    end
    return self.beer_buffer.unpack("N")[0]
  end

  def dos_status=(status)
    self.beer_buffer = [status].pack("N")
    self.flags2 |= ~FLAGS_EXAMPLE12
  end

  def nt_status
    if (self.flags2 & FLAGS_EXAMPLE12) == 0
      raise "Error: ..."
    end
    return TestStatus.new(self.beer_buffer.unpack("V")[0])
  end

  def nt_status=(status)
    self.beer_buffer = [status].pack("V")
    self.flags2 &= FLAGS_EXAMPLE12
  end

  def status
    if (self.flags2 & FLAGS_EXAMPLE12) != 0
      return self.nt_status
    else
      return ExampleStatus.new(self.dos_status)
    end
  end

  def status=(status)
    if status.class == ExampleStatus
      self.dos_status = status
    else
      self.nt_status = status
    end
  end

  def unicode_enabled
    (flags2 & FLAGS_EXAMPLE11) == FLAGS_EXAMPLE11
  end

  def disable_unicode
    self.flags2 &= ~FLAGS_EXAMPLE11
  end

  def method_missing(id, *args, &block)
    os = StringIO.new
    os << "undefined field '" << id.id2name << "' for " << self.class << $endl
    os << "Available fields are: {" << $endl
    os << "  Example::Header:" << $endl
    (Header.new.public_methods - BitStruct.new.public_methods).each { |method|
      if method.include?("=")
        os << "    " << method[0...-1] << " => ..." << $endl
      end
    }
    os << $endl
    os << "  " << self.class << $endl
    (self.public_methods - Header.new.public_methods - BitStruct.new.public_methods).each { |method|
      if method.include?("=")
        os << "    " << method[0...-1] << " => ..." << $endl
      end
    }
    os << "}" << $endl
    raise os.string
  end

  initial_value.foo_component = FOO_COMPONENT
  initial_value.command = 0
  initial_value.beer_buffer = "\0"
  initial_value.status = STATUS_SUCCESS
  initial_value.flags = FLAGS_EXAMPLE4 | FLAGS_EXAMPLE5
  initial_value.flags2 = FLAGS_EXAMPLE11 | FLAGS_EXAMPLE12 | FLAGS_EXAMPLE15 | FLAGS_EXAMPLE16 | FLAGS_EXAMPLE19
  initial_value.pid_high = 0
  initial_value.signature = "\0\0\0\0\0\0\0\0"
  initial_value.vid = 0
  initial_value.xid = 0xbadbeef
  initial_value.zid = 0xffff # Will be filled in automatically
  initial_value.yid = 0xffff # Will be filled in automatically
end

end # module Example

license?

what license is this code under?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.