Best way to create a string with gap (0x00's) in the middle?

I’m trying to build a packet to send to UDPSocket::send. Send requires
a string, but I’m not sure of the best way to build this string. The
packet’s structure requires two strings: one beginning at byte 0 and the
other at byte 64. The packet is 128 bytes long and must contain 0’s in
the bytes that the strings don’t use. Here is an example packet:

54 68 69 73 20 69 73 20 73 74 72 69 6E 67 20 41 This is string A
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
4E 6F 77 20 77 65 20 68 61 76 65 20 73 74 72 69 Now we have stri
6E 67 20 42 00 00 00 00 00 00 00 00 00 00 00 00 ng B…
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …

I have a solution, but it’s not very elegant and I’m looking for a
better way of doing this. Here’s what I have so far:

I tried this first, but ended up with a bunch of 0x30’s where the 0x00’s
should be:

dgram = Array.new(128, 0)
dgram[0] = “This is string A”.to_a
dgram[64] = “Now we have string B”.to_a
UDPSocket.open.send(dgram.to_s, 0, host, port)

dgram.to_s converts all of the 0x00’s in the array to 0x30’s in the
string, which is not acceptable.

This is what I have right now:

dgram = “”
94.times {dgram << 0}
dgram[0] = “This is string A”
dgram[64] = “Now we have string B”
UDPSocket.open.send(dgram, 0, host, port)

Like I said: it works, but I don’t really like it. Any ideas for a
better implementation?

Thanks,
Earle

Earle C. wrote:

4E 6F 77 20 77 65 20 68 61 76 65 20 73 74 72 69 Now we have stri
dgram = Array.new(128, 0)
dgram = “”

BLANK_DGRAM = “\0”*128
dgram = BLANK_DGRAM.dup

s1 = “This is string A”
s2 = “Now we have string B”

dgram[0…s1.length] = s1
dgram[64…64+s2.length] = s2

If you think you might need to fill in other kinds of fields besides
fixed-length strings, you could use a BitStruct:

require ‘bit-struct’ # BitStruct

class Dgram < BitStruct
char :s1, 648
char :s2, 64
8
end

dgram = Dgram.new
dgram.s1 = “This is string A”
dgram.s2 = “Now we have string B”

On 24.04.2007 17:47, Earle C. wrote:

4E 6F 77 20 77 65 20 68 61 76 65 20 73 74 72 69 Now we have stri
dgram = Array.new(128, 0)
dgram = “”
94.times {dgram << 0}
dgram[0] = “This is string A”
dgram[64] = “Now we have string B”
UDPSocket.open.send(dgram, 0, host, port)

Like I said: it works, but I don’t really like it. Any ideas for a
better implementation?

%w{foo bar}
=> [“foo”, “bar”]

%w{foo bar}.pack(“a64a64”)
=>
“foo\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000bar\000\000\000\000\000\000\0
00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0
00\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000”

Or, printed more nicely:

%w{foo bar}.pack(“a64a64”).to_enum(:each_byte).each_slice(16) {|s|
puts s.map {|x| “%02x” % x}.join(" ")}
66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62 61 72 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=> nil

Kind regards

robert