From: Brian Candler Date: 2005-06-05T17:50:57+09:00 Subject: Re: Converting variable-length binary value > how about: > > [int.to_s(16)].pack('H*') That doesn't work if the number of hex digits is odd: irb(main):006:0> 1234.to_s(16) => "4d2" irb(main):007:0> [1234.to_s(16)].pack("H*") => "M " # that's \x4d \x20 irb(main):008:0> ["04d2"].pack("H*") => "\004\322" # that's \x04 \xd2 irb(main):009:0> > Also, if you aren't tied to this exact format, there's the > BER-compressed integer option in #pack/#unpack, which handles > variable-length integers in a nice way As it happens, I'm unpacking BER. The length field in a BER-encoded element is encoded as a straightforward N octets. See [**] below: def ber_read(io) blk = io.read(2) # minimum: short tag, short length tag = blk[0] & 0x1f len = blk[1] if tag == 0x1f # long form tag = 0 while true ch = io.getc blk << ch tag = (tag << 7) | (ch & 0x7f) break if (ch & 0x80) == 0 end len = io.getc blk << len end if (len & 0x80) != 0 # long form len = len & 0x7f raise "Indefinite length encoding not supported" if len == 0 offset = blk.length blk << io.read(len) # is there a more efficient way of doing this? [**] len = 0 blk[offset..-1].each_byte { |b| len = (len << 8) | b } end offset = blk.length blk << io.read(len) return blk, [blk[0] >> 5, tag], offset end The reason for this is so that I can read a DER element from a stream (OpenSSL::ASL1::decode requires the data to be in memory first) You'll notice that the long-form *tag* is encoded in the format you mention; however I can't use unpack for that since the length isn't known up-front. Regards, Brian.