6

I have a packed string of 3 strings that is composed in a way so that I have an integer, specifying the byte length of the next item and then that item's bytes and then the next item's bytesize, etc. as if somebody did:

[a.bytesize, a, b.bytesize, b, c.bytesize, c].pack("na*na*na*")

How can I properly unpack that in a simple manner? The Perl solution to this problem was:

my($a, $b, $c) = unpack("(n/a*)3", $data)

For ruby, which apparently doesn't support '/' and parentheses in unpack, I'm using something like:

vals = []
3.times do
  size = data.unpack("n").first
  data.slice!(0, 2)
  vals << data.unpack("a#{size}").first
  data.slice!(0, size)
end

Is there an easier way to this?

dbenhur
  • 20,008
  • 4
  • 48
  • 45
Speed
  • 1,424
  • 1
  • 16
  • 24
  • 1
    Unless somebody finds a simple solution to this, I'll consider making a feature request to expand unpack on ruby's issue tracker, seems like it may be useful if the implementation gets some Perl features – Speed Feb 16 '13 at 14:40

3 Answers3

1

IMHO it is not as easy as in PERL, but this is some solution I can suggest.

unpacked = []
a, b, c = *unpacked << data.slice!(0, data.slice!(0, 2).unpack('S>').first) \
           until data.empty? 
egghese
  • 2,193
  • 16
  • 26
0

I don't see a way to do this as easily as the Perl solution (and agree it would be good to file a feature request to get that added in Ruby's pack/unpack implementation), but I could at least provide the solution in fewer lines if that helps:

vals = []
until data.empty?
  vals << data.slice!(0, data.slice!(0,2).unpack('n').first.to_i).unpack("a*").first
end
Stuart M
  • 11,458
  • 6
  • 45
  • 59
0

If you need any serious binary data processing, there's a gem for it: http://bindata.rubyforge.org/ I think you should use it, instead of forging unpacks un running loops.

You can of course file a feature request and wait for it to be implemented, but I suggest you use bindata gem instead, which is a much more robust solution IMO.

Michael Kruglos
  • 1,205
  • 14
  • 26