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

Popular posts from this blog

facebook - android ACTION_SEND to share with specific application only -

python - Creating a new virtualenv gives a permissions error -

javascript - cocos2d-js draw circle not instantly -