Correct way to unpack a 32 bit vector in Perl to read a uint32 written in C -
i parsing photoshop raw, 16 bit/channel, rgb file in c , trying keep log of exceptional data points. need fast c analysis of 36 mpix images 16 bit quanta or 216 mb photoshop .raw files.
<1% of points have weird skin tones , want graph them perlmagick or perl gd see coming from.
the first 4 bytes of c data file contain unsigned image width uint32_t. in perl, read whole file in binary mode , extract first 32 bits:
xres=1779105792l = 0x6a0b0000
it looks lot c log file:
da: color anomalies=14177=0.229%: da: ii=1) raw pidx=0x10000b25, xcols=[0]=0x00000b6a
dec(0x00000b6a) = 2922, exact x_columns_width of small test file.
clearly case of intel's 1972 8008 nuxi architecture. how hard possibly translate 0x6a0b0000 0x6a0b0000; swap 2 bytes , 2 nibbles , you're done. slicing 8 characters , rearranging them done kind of ugly hack trying avoid.
grab same 32 bit vector file offset 0 , unpack "vax" unsigned long.
$xres = vec($bdat, 0, 32); # vec expr,offset,bits $vul = unpack("v", vec($bdat, 0, 32)); printf("length (\$bdat)=%d, xres=0x%08x, vax ulong=%ul=0x%08x\n", length($bdat), $xres, $vul, $vul); length ($bdat) = 56712, xres=0x6a0b0000, vax ulong=959919921l=0x39373731
every single hex character mangled. wrong endian, not vax. "other" 1 network big-endian
http://perldoc.perl.org/functions/pack.html n unsigned long (32-bit) in "network" (big-endian) order. v unsigned long (32-bit) in "vax" (little-endian) order. $nul = unpack("n", vec($bdat, 0, 32)); # network unsigned long 32b printf("xres=0x%08x, net ulong=%ul=0x%08x\n", $xres, $nul, $nul); xres=0x6a0b0000, net ulong=825702201l=0x31373739
the $xres still shows right hex in wrong order. "network" long 32 bit uint extracted same bits unrecognizable. try binary
$bits = unpack("b*", vec($bdat, 0, 32)); printf("bits=$bits, len=%d\n", length $bits); bits=10001100111011001110110010011100100011000000110010101100111011001001110001001100, len=80
i asked 32 bits , got 80 bits. gives?
try 4, unsigned, 8bit bytes can not swapped:
for($ii = 0; $ii < 4; $ii++) { $bit_off=$ii*8; # bit offset $uc = unpack("c", vec($bdat, $bit_off, 8)); # c unsigned char printf("ii $ii, bo $bit_off, d=%d, u=%u, x=0x%x\n", $uc,$uc, $uc); } ii 0, bo 0, d=49, u=49, x=0x31 ii 1, bo 8, d=51, u=51, x=0x33 ii 2, bo 16, d=49, u=49, x=0x31 ii 3, bo 24, d=49, u=49, x=0x31
i looking hex 0, 6, or b. there no "3"s or "1"s in right answer. try pirating c file:
http://cpansearch.perl.org/src/mhx/convert-binary-c-0.76/tests/include/include/bits/byteswap.h $x = $xres; $x= (((($x) & 0xff000000) >> 24) | ((($x) & 0x00ff0000) >> 8) | ((($x) & 0x0000ff00) << 8) | ((($x) & 0x000000ff) << 24)); printf("\$xres=0x%08x -> \$x=0x%08x = %u\n", $xres, $x, $x); $xres=0x6a0b0000 -> $x=0x00000b6a = 2922
it works! but, uglier converting original, wrong order hex number string untangle it:
$stupid_str = sprintf("%08x", $xres); $stupid_num = join('', reverse ($stupid_str =~ m/../g)); printf("stupid_num '%s'->0x%08x=%d\n", $stupid_num, $dec=hex $stupid_num, $dec); stupid_num '00000b6a'->0x00000b6a=2922
it's judging ugliest dog contest, still rather have maintain text version more abominable c version.
i know there ways in java/python/go/ruby/.....
i know there command line utilities this.
i must figure out how misusing either vec or unpack, both of have used zillion times. brain teasing aspect driving me nuts! endianness == endianmess!!!
tyvm!
=================================================
borodin,
thanks lookin' @ this.
my intel processor little-endian. when read back, trans-mutilated vec "correct" big-endian, network format.
i tried reading verbatim binary file read , works fine:
($b4 = $bdat) =~ s/^(....).*$/$1/msg; # give me 4 bytes without mutilation! printf("b4='%s'=>0x%08x=<0x%08x\n", $b4, unpack("l>", $b4), unpack("l<", $b4)); b4='j...' = >0x6a0b0000 = <0x00000b6a <<< right answer!!!
if try unpack 'v', $bdat find works
that first attempt: $vul = unpack("v", vec($bdat, 0, 32)); # unpack v!
printf("length (\$bdat)=%d, xres=0x%08x, vax ulong=%ul=0x%08x\n", length($bdat), $xres, $vul, $vul); length ($bdat) = 56712, xres=0x6a0b0000, vax ulong=959919921l=0x39373731 <<<< totally wrong!
i had verified $bdat info right data in wrong format. needed rearrangement.
i used vec() generate 1 bit , 4 bit graphics files , worked faithfully, returning exact bits wrote. must have mistaken intel i7 ibm system/370. i7/37??? easy mistake make. :)
i read [confusing] part "converted number pack ...". that's why number backward. >>unpack("v", vec($bdat"<< ... ill-fated attempt byte-swap backward number in $bdat wrong vec()-preferred format native format supported architecture.
now understand why saw many examples of people extracting byte, avoid big brother's helping hand!
data::bitstream::vec "uses perl vec store data. vector accessed in 1-bit units"
thanks 1e6,
b
you confusing things combining vec
unpack
the correct way simply
unpack 'v', $bdat
which returns value of 0x00000b6a
expect
vec($bdat, 0, 32)
equivalent unpack 'n', $bdat
can see value of $xres
in first code block, , documentation vec
confirms with
if bits 16 or more, bytes of input string grouped chunks of size bits/8, , each group converted number pack()/unpack() big-endian formats n/n
the line
$vul = unpack("v", vec($bdat, 0, 32))
is wrong, because decimal value of vec($bdat, 0, 32)
1779105792, calling unpack
on string "1779105792"
doesn't useful @ all
Comments
Post a Comment