Binary data

Hello!

I’m new to ruby. I’m learning it and it seems to be a very nice
language.

However, I do have a question about binary handling. I’d like to write
binary data directly to a file.
I found that I can use myfile.write([“1001010100”].pack(“B10”)), but
i’d like to be able to write, for example 0b1001010100 directly to a
file. How do I do that, or else, are ther other useful ways to write
binary data to a file

Thanks in advance

Alwin

Is my question to hard or to easy to answer? Can someone please
comment? I’m playing with ruby + fbdev on my laptop so I can make
mandelbrots everywhere I go!

Thanks,
Alwin

···

On 23-dec-03, at 22:36, Alwin Blok wrote:

Hello!

I’m new to ruby. I’m learning it and it seems to be a very nice
language.

However, I do have a question about binary handling. I’d like to write
binary data directly to a file.
I found that I can use myfile.write([“1001010100”].pack(“B10”)), but
i’d like to be able to write, for example 0b1001010100 directly to a
file. How do I do that, or else, are ther other useful ways to write
binary data to a file?

Thanks in advance

Alwin

Alwin Blok wrote:

Hello!

I’m new to ruby. I’m learning it and it seems to be a very nice language.

However, I do have a question about binary handling. I’d like to write
binary data directly to a file.
I found that I can use myfile.write([“1001010100”].pack(“B10”)), but i’d
like to be able to write, for example 0b1001010100 directly to a file.
How do I do that, or else, are ther other useful ways to write binary
data to a file

Thanks in advance

Alwin

very old coding style, may be of interest

 begin
    out_file = your data
    f = File.new("file name", "w")
  end

  begin
    out_file.each{ |ch|
      f.binmode.putc(ch)
    }
  ensure
    f.close
  end

neil

Alwin Blok wrote:

However, I do have a question about binary handling. I’d like to
write binary data directly to a file.
I found that I can use myfile.write([“1001010100”].pack(“B10”)), but
i’d like to be able to write, for example 0b1001010100 directly to a
file. How do I do that, or else, are ther other useful ways to write
binary data to a file?

I’d be interested in an answer to this one, too, from someone who is “in
the know.” Whenever I’ve needed to write binary data in the past I’ve
had to pack it into a string first… shouldn’t there be a routine
somewhere that will write a value directly without first converting it
to a string?

Yes, I know it isn’t hard to create a method that will take a value and
convert it to a binary string representation, but I’m wondering if there
is already a solution to this in the existing Ruby libraries.

  • Jamis
···


Jamis Buck
jgb3@email.byu.edu

ruby -h | ruby -e ‘a=;readlines.join.scan(/-(.)[e|Kk(\S*)|le.l(…)e|#!(\S*)/) {|r| a << r.compact.first };puts “\n>#{a.join(%q/ /)}<\n\n”’

Alwin Blok wrote:

However, I do have a question about binary handling. I’d like to write
binary data directly to a file.
I found that I can use myfile.write([“1001010100”].pack(“B10”)), but
i’d like to be able to write, for example 0b1001010100 directly to a
file. How do I do that, or else, are ther other useful ways to write
binary data to a file?

I don’t know of a more appropriate method, but what about

class IO
def raw_write bits
bits = [bits.to_s].pack(‘B*’) if bits.is_a? Fixnum
write bits
end
end

myfile.raw_write 0b1001010100

Dave

“quillion” wrote:

Alwin Blok wrote:

Hello!

I’m new to ruby. I’m learning it and it seems to be a very nice language.

However, I do have a question about binary handling. I’d like to write
binary data directly to a file.
I found that I can use myfile.write([“1001010100”].pack(“B10”)), but i’d
like to be able to write, for example 0b1001010100 directly to a file.
How do I do that, or else, are ther other useful ways to write binary
data to a file

Thanks in advance

Alwin

very old coding style, may be of interest

 begin
    out_file = your data
    f = File.new("file name", "w")
  end

  begin
    out_file.each{ |ch|
      f.binmode.putc(ch)
    }
  ensure
    f.close
  end

neil

Like Neil said …

File.open(‘tbinary.dat’, ‘wb’) do |fb|
fb.putc 0b11011011
fb.putc 255
fb.putc 0xAB
fb.putc 0x42
end

See what happened …

File.open(‘tbinary.dat’, ‘rb’) do |fb|
bd = fb.read
puts bd.unpack(‘H*’)
end

#-> dbffab42

daz

I was playing wih the framebuffer device, using pack, I was able to get
the bits where I wanted, but It’s not handy when you want gradients and
other fancy stuff

When I use

File.open(‘/dev/fb0’,‘w’) do |fb|
(800*600).times do
fb.putc 0b0111110000000000
end
end

I get half my screen filled, Which is obvious since putc is short for
putchar (i assume), hence 8bits
(the screen is 16 bits color)

So my real question is:
What command do I use to put an arbitrary amount of bits?
I can think of some ways, but I hate it when it feels like a workaround.

Thanks
-Alwin

···

On 2-mrt-04, at 5:49, daz wrote:

Like Neil said …

File.open(‘tbinary.dat’, ‘wb’) do |fb|
fb.putc 0b11011011
fb.putc 255
fb.putc 0xAB
fb.putc 0x42
end

See what happened …

File.open(‘tbinary.dat’, ‘rb’) do |fb|
bd = fb.read
puts bd.unpack(‘H*’)
end

#-> dbffab42

daz

Alwin Blok wrote:

I was playing wih the framebuffer device, using pack, I was able to get
the bits where I wanted, but It’s not handy when you want gradients and
other fancy stuff

When I use

File.open(‘/dev/fb0’,‘w’) do |fb|
(800*600).times do
fb.putc 0b0111110000000000
end
end

I get half my screen filled, Which is obvious since putc is short for
putchar (i assume), hence 8bits
(the screen is 16 bits color)

For that specific case, 2 x putc

File.open(‘/dev/fb0’,‘w’) do |fb|
(800*600).times do
fb.putc 0b011111000
fb.putc 0
end
end

… but, I know, you want something more flexible.
It intrigues me that you’d want to write, say, 10 bits when you
haven’t specified left, right or no padding.

Here are all the screen size options on my display adapter.

Test width / height exactly divisible by 8

ss = lambda {|w, h| p [w % 8 == 0, w/8, h % 8 == 0, h/8]}

ss[ 640, 480]
ss[ 800, 600]
ss[1024, 768]
ss[1152, 864]
ss[1280, 1024]
ss[1600, 1200]

#-> [true, 80, true, 60]
#-> [true, 100, true, 75]
#-> [true, 128, true, 96]
#-> [true, 144, true, 108]
#-> [true, 160, true, 128]
#-> [true, 200, true, 150]

Anyway, see if any of this helps …

Constraint:

···

#------------

If the bit pattern is to be given as an integer,

the pattern length also needs to given because

leading zeros have no significance.

puts
puts 0b0110.to_s(2)
puts 0b00110.to_s(2)
puts 0b00000000000000110.to_s(2)
puts

Strings have a slight advantage in this respect.

puts ‘0110’.length
puts ‘00110’.length
puts ‘00000000000000110’.length

OTOH, with known length, leading zeros

need not be given.

fmt = “%010b\n”

(e.g. these examples are equivalent):

puts format(fmt, 0b110)
puts format(fmt, 0b0110)
puts format(fmt, 0b00000000000000110)
puts format(fmt, 6)

#-> 110
#-> 110
#-> 110
#->
#-> 4
#-> 5
#-> 17
#-> 0000000110
#-> 0000000110
#-> 0000000110
#-> 0000000110

Here’s a buffered write to play with:
(messed up by comments & display stuff)

#-----------------------------------------------------------------
$watch = true

n = 0b1001_11101101_00010000
nbits = 20 # n represents 20 bits

Normally start with:

##> buff = bufn = 0
buff = 0b10 # example remainder from “previous use”
bufn = 3 # buff represents 3 bits == 010

Prepend bits (less than a full byte) to new bits

n |= (buff << nbits)

Temporarily adjust the number of bits to write this time round

nb = nbits + bufn
if $watch
printf(“START (%2d) x[%08x] b[%0#{nb}b]\n\n”, nb, n, n)
end
while nb >= 8
nb -=8
mask = 0xff << nb ## find the first full byte
n8 = (n & mask) ## temporarily ignore the rest
if $watch
printf(“mask x[%08x] b[%0#{nb+8}b]\n”, mask, mask)
printf(“tmp x[%08x] b[%0#{nb+8}b]\n”, n8, n8)
end
n ^= n8 ## remove these 8 bits from the bits to be written
n8 >>= nb ## move these 8 bits down to bits 7…0
if $watch
printf(“putc x[%08x] b[%08b]\n\n”, n8, n8)
printf(“NEXTn (%2d) x[%08x] b[%0#{nb}b]\n”, nb, n, n)
puts ‘-’*10
end
end

buff = n ## save partial last byte for next time round
bufn = nb ## AND the exact number of bits with significance
if $watch
printf(“-> buff %0#{bufn}b\n”, buff)
end

#-----------------------------------------------------------------

And here’s how it might look in the real world:

class Screen
def initialize(w, h, nbits = 16)
@width = w
@height = h
@nbits = nbits
@screen = File.open(‘tbinary.dat’, ‘wb’)
@screen.sync = true
@buff = 0
@bufn = 0 # Number of unwritten bits in buffer
end

def close
##
@buff <<= 8-@bufn # align left in byte
@screen.putc(@buff) # write to screen
@screen.close
end

def write(patt, nbits = @nbits)

patt |= (@buff << nbits)
nb = nbits + @bufn

while nb >= 8
  nb -=8
  mask = 0xff << nb  ## find the first full byte
  n8 = (patt & mask) ## temporarily ignore the rest
  patt ^= n8         ## remove these 8 bits from the bits to be written
  n8 >>= nb          ## move these 8 bits down to bits 7......0
  @screen.putc(n8)  # write to screen
end

@buff = patt   ## save partial last byte for next time round
@bufn = nb     ## AND the exact number of bits with significance

end
end

fb = Screen.new(800, 600, 10)
5.times {fb.write(0b11111010, 16)}
fb.write 0b1101101101 # length 10 from Screen.new
fb.write 0b1010111010
fb.write(0b0011001100, 40)
fb.close

See what happened …

File.open(‘tbinary.dat’, ‘rb’) do |fb|
bd = fb.read
puts bd.unpack(‘H*’)
end

#-> 00fa00fa00fa00fa00fadb6ba00000000cc0

#-----------------------------------------------------------------

So my real question is:
What command do I use to put an arbitrary amount of bits?

putc

I can think of some ways, but I hate it when it feels like a workaround.

I know what you mean.
It’s not a workaround, it’s a tricky problem. Once you have a
method which does what you want, you can forget about the complexity
and advance to the next stage like adding Screen#fill(pattern).

Thanks
-Alwin

OK,

daz