# Bitstuct and binary files

**URL:** <https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461>\
**Category:** Ruby\
**Created:** [October 24, 2006, 8:05pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461 "2006-10-24T20:05:53Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 8:05pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/1 "2006-10-24T20:05:53Z")

</div>

Hi,

I’ve been working with modifying a binary file to replace some meta-data  
included within. I’ve had some discussions previously  
([Binary file modification - Ruby - Ruby-Forum](http://www.ruby-forum.com/topic/85591)) about this but couldn’t get to a  
satisfactory conclusion. Basically I need to encode an integer value  
into 3 bytes as part of a binary file - Bitstruct was suggested as one  
of the solutions, however I haven’t been able to get it to work for  
values larger than 1024 :

require ‘bit-struct’

class Audio \< BitStruct  
signed :aheader, 8, :endian =\> :little  
unsigned :alength, 3\*8, :endian =\> :little  
signed :afooter, 8, :endian =\> :little  
end

audio = Audio.new  
audio.aheader = 1  
audio.alength = 3027  
audio.afooter = 1  
f = open(“testfile”,“wb”)  
f.write(audio)  
f.close  
f = open(“testfile”,“rb”)  
f.pos=0  
puts f.read(1).unpack(“c”).first.to\_s  
puts f.read(3).unpack(‘H6’).first.to\_i(16)  
puts f.read(1).unpack(“c”).first.to\_s  
f.close

In the application above, if the value of audio.alength is set to equal  
or below 1024 then the output for f.read(3).unpack(‘H6’).first.to\_i(16)  
matches, however if set above this then the value printed doesn’t match.

Can anybody tell me why setting an audio.alength\>=1024 breaks the output  
and provide a way to fix it …

Thanks

---

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 8:23pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/2 "2006-10-24T20:23:03Z")

</div>

Rob L. wrote:

> puts f.read(3).unpack(‘H6’).first.to\_i(16)

I think you want ‘h’ instead of ‘H’, and you need to reverse the  
nibbles:

puts f.read(3).unpack(‘h6’).first.reverse.to\_i(16)

---

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 8:41pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/3 "2006-10-24T20:41:04Z")

</div>

> -----Original Message-----  
> […]  
> Can anybody tell me why setting an audio.alength\>=1024 breaks  
> the output  
> and provide a way to fix it …

## —borked— num=359447 f.write(num.to\_s(16)[0…2].instance\_eval {(self.reverse + ‘0’ \* (6 - self.length)).reverse}.scan(/…/).inject(’’) {|s,byte| s \<\< byte.to\_i(16)})

My code is broken. Where I said [0…2] I meant [0…5], I added it in at  
the  
last minute as an overflow check without testing - I was thinking 3 raw  
hex  
bytes but the string after the conversion is a 6 byte ‘friendly’ hex  
string.

Sorry. ☹

ben

---

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 8:43pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/4 "2006-10-24T20:43:32Z")

</div>

Joel VanderWerf wrote:

> Rob L. wrote:
> 
> > puts f.read(3).unpack(‘H6’).first.to\_i(16)
> 
> I think you want ‘h’ instead of ‘H’, and you need to reverse the  
> nibbles:
> 
> puts f.read(3).unpack(‘h6’).first.reverse.to\_i(16)

Ah, OK that works with my example script - thanks. However, that means  
the Bitstruct definition I gave is incorrect. The binary file I’m  
trying to modify correctly unpacks the integer using :

f.read(3).unpack(‘H6’).first.to\_i(16)

However, I’m really confused over what the Bitstruct definition should  
be to support this - do you have any suggestions ?

Thanks

---

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 8:50pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/5 "2006-10-24T20:50:26Z")

</div>

> My code is broken. Where I said [0…2] I meant [0…5], I added it in at  
> the  
> last minute as an overflow check without testing - I was thinking 3 raw  
> hex  
> bytes but the string after the conversion is a 6 byte ‘friendly’ hex  
> string.
> 
> Sorry. ☹
> 
> ben

No problem ! I’ve just modified the code and it works great - thanks 🙂  
I’m investigating bitstruct as well but it’s always nice to have  
alternatives …

---

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 8:55pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/6 "2006-10-24T20:55:21Z")

</div>

Rob L. wrote:

> trying to modify correctly unpacks the integer using :
> 
> f.read(3).unpack(‘H6’).first.to\_i(16)
> 
> However, I’m really confused over what the Bitstruct definition should  
> be to support this - do you have any suggestions ?
> 
> Thanks

Then probably your data is in big endian order–I should have grokked  
that from your code. Try this:

class Audio \< BitStruct  
signed :aheader, 8  
unsigned :alength, 3\*8  
signed :afooter, 8  
end

---

<div class="post-metadata">

**Author:** ![rob](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/838e76/32.png) [@rob](https://www.ruby-forum.com/u/rob)\
**Post date:** [October 24, 2006, 9:01pm UTC](https://www.ruby-forum.com/t/bitstuct-and-binary-files/73461/7 "2006-10-24T21:01:34Z")

</div>

> Then probably your data is in big endian order–I should have grokked  
> that from your code. Try this:
> 
> class Audio \< BitStruct  
> signed :aheader, 8  
> unsigned :alength, 3\*8  
> signed :afooter, 8  
> end

Excellent - thank you. It all works - if you’re interested I’m working  
on a Ruby proxy for the Nabaztag (wifi bunny rabbit) and I’m trying to  
extend some of it’s audio capabilities 🙂
