JunkGuy has asked for the wisdom of the Perl Monks concerning the following question:

I'm successfully retrieving values from a file (thanks for the help from yesterday), but I'm having a problem. One of the fields I'm retrieving is a binary field. I think I'm retrieving it okay, but when I try to convert it using unpack to a string or number, I end up with 0's. I should be getting a number greater than zero.

I've tested this by grabbing other binary fields from the same file, and when I unpack them (using 'N' or 'I') I end up with zeros, as well.

Any ideas?

Here's some of my code:

sysread(INPUT,$outp\0\,12,1);
print "length: ".$outp\0\."\n";
print "length: ".unpack("I", $outp\0\)."\n";

where 1 through 12 are binary fields.

Thanks for your time.

Replies are listed 'Best First'.
Re: Binary data
by pfaut (Priest) on Feb 06, 2003 at 17:59 UTC

    You asked sysread to read 12 bytes, not 12 fields. unpack("I") will only decode one 32-bit value from the beginning of the buffer passed to it.

    Do you have a C type structure definition or some other description for the data you are trying to parse?

    My Pack/Unpack Tutorial might be helpful to you.

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
Re: Binary data
by jasonk (Parson) on Feb 06, 2003 at 17:52 UTC

    Are you sure you understand the format of the binary data that is included in the file? Your comments make it appear that there is more than on piece of binary data included, but you try and read in 12 bytes and then unpack it as an "I" (do your system and the data you are reading both consider integers to be 12 bytes long?)

    You also indicate that you tried both "N" (big-endian unsigned long), and "I" (unsigned integer) which are really not compatible data types, if you don't know the format of the data being unpacked, you will have a difficult time finding the right template to unpack it.

Re: Binary data
by steves (Curate) on Feb 06, 2003 at 17:56 UTC

    It sounds like you're thinking these are single bit binary fields when you say "1 through 12 are binary." Your sysread is reading 12 bytes, starting one byte into the data (index 1). You're then trying to unpack the 12 bytes read as an integer value.

Re: Binary data
by JunkGuy (Initiate) on Feb 06, 2003 at 19:45 UTC
    I'm not quite as dumb as you might want to believe. I was trying to make the problem more general.

    Maybe this rework will help you out:
    sysseek(INPUT,8,0);
    sysread(INPUT,@outp\0\,4,9);
    
    print "length: ".$outp\0\."\n";
    print "length: ".unpack("B32", $outp\0\)."\n";
    print "length: ".unpack("b32", $outp\0\)."\n";
    
    In the sysread each digit is a byte of binary data.

    The first output gives me junk characters, the next two give me 32 0s, as shown below: length: ?| length: 00000000000000000000000000000000 length: 00000000000000000000000000000000

      No one said you were dumb. It just seemed like your explaination for what you were trying to do didn't match the code you provided. Also, you might try using <code> and </code> around your code instead of <pre>. That way, your brackets will show up as brackets. Backslashes don't escape things in HTML like they do in source.

      The second argument to sysread should be a scalar, not an array. I'm not sure exactly what sysread does when passed an array there. Also, sysread only takes three arguments (at least in 5.6.1).

      Your first output looks like junk because you read binary data from a file and printed it. You should expect it to look like junk. Both of the next two prints looked at the same data and interpret it as a bitstring. If the value happens to be zero, both would return a string of 32 '0's.

      Could you please provide a C struct definition or other description of what you are trying to parse? It would make it a lot easier for us to help you out.

      --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';