[Tutor] Extracting a PNG Image File from a Binary File..

Aaron Elbaz flamesrock at gmail.com
Mon Jan 3 11:33:30 CET 2005


Hi,

My question is sort of on the difficult side, but I promise I'm a newb
;) So maybe it isn't..


Frederick Lundh himself gave me this chunk of code..and I can't get it
to work. I was hoping someone could spot the error.

The goal is to extract a png image file from a binary simcity 4 file.
#import struct
#
#def pngcopy(infile, outfile):
#
#   # copy header
#   header = infile.read(8)
#   if header != "\211PNG\r\n\032\n":
#       raise IOError("not a valid PNG file")
#   outfile.write(header)
#
#   # copy chunks, until IEND
#   while 1:
#       chunk = infile.read(8)
#       size, cid = struct.unpack("!l4s", chunk)
#       outfile.write(chunk)
#       outfile.write(infile.read(size))
#       outfile.write(infile.read(4)) # checksum
#       if cid == "IEND":
#           break
#
#infile = open("/home/flamesrock/Desktop/peachville.sc4", "rb")
#infile.seek(0x50)
#outfile = open("myimage.png", "wb")
#pngcopy(infile, outfile)
#outfile.close()
#infile.close()

It returns the IO error when I try it on this and other files:
http://simcitysphere.com/peachville.sc4

I've confirmed the position using a hex editor (its the first 'P' or
0x50 in the file)
http://simcitysphere.com/peachville.png

The idea comes from this php code which works -if only I could
understand how to translate it. The code may or may not also extract
data which denotes a relative position on an image map:
also available at http://simcitysphere.com/regionFileDecode_inc.php.txt
<?php
	function fileDecode($inbuf, $Cname)
	{
		  /* length of data */
		  $inlen=strlen($inbuf);

		  $outlen	=	unpack1($inbuf[6],'C') << 16;
		  $outlen	+=	unpack1($inbuf[7],'C') << 8;
		  $outlen	+=	unpack1($inbuf[8],'C');

		  /* position in file */
		  $inpos=9;
		  $outpos=0;

		  $outbuf =array();

		  while (($inpos<$inlen)&&(unpack1($inbuf[$inpos],'C')<0xFC))
			{


				 $packcode=$inbuf[$inpos];
				 $packcode=unpack1($packcode,'C');
				 $a=unpack1($inbuf[$inpos+1],'C');
				 $b=unpack1($inbuf[$inpos+2],'C');
				 //decho("inlen: {$inlen} | outlen: {$outlen} | inpos: {$inpos} |
outpos: {$outpos} | packcode: $packcode");
				 
				 if (!($packcode&0x80)) {
					//decho('match 0x80');
					$lena=$packcode&3;
					mmemcpy($outbuf,$outpos,$inbuf,$inpos+2,$lena);
					$inpos+=$lena+2;
					$outpos+=$lena;
					$lenb=(($packcode&0x1c)>>2)+3;
					$offset=(($packcode>>5)<<8)+$a+1;
					mmemcpy($outbuf,$outpos,$outbuf,$outpos-$offset,$lenb);
					$outpos+=$lenb;
					//decho ("Code $packcode len plain: $lena len: $lenb offset:
$offset outpos: $outpos");
				 }
				 else if (!($packcode&0x40)) {
					//decho('match 0x40');
					$lena=($a>>6)&3; 
					mmemcpy($outbuf,$outpos,$inbuf,$inpos+3,$lena);
					$inpos+=$lena+3;
					$outpos+=$lena;
					$lenb=($packcode&0x3f)+4;
					$offset=($a&0x3f)*256+$b+1;
					mmemcpy($outbuf,$outpos,$outbuf,$outpos-$offset,$lenb);
					$outpos+=$lenb;
					//decho ("Code $packcode len plain: $lena len: $lenb offset:
$offset outpos: $outpos");
				 }  
				 else if (!($packcode&0x20)) {
					//decho('match 0x20');
					$c=unpack1($inbuf[$inpos+3],'C');
					$lena=$packcode&3; 
					mmemcpy($outbuf,$outpos,$inbuf,$inpos+4,$lena);
					$inpos+=$lena+4;
					$outpos+=$lena;
					$lenb=(($packcode>>2)&3)*256+$c+5;
					$offset=(($packcode&0x10)<<12)+256*$a+$b+1;
					mmemcpy($outbuf,$outpos,$outbuf,$outpos-$offset,$lenb);
					$outpos+=$lenb;
					//decho ("Code $packcode len plain: $lena len: $lenb offset:
$offset outpos: $outpos");
				 }  
				 else {
					//decho('match 0x1f');
					$len=($packcode&0x1f)*4+4;
					mmemcpy($outbuf,$outpos,$inbuf,$inpos+1,$len);
					$inpos+=$len+1;
					$outpos+=$len;
					//decho ("Code $packcode Plain Chars: $len outpos: $outpos");
//Code 224 Plain Chars: 4 outpos: 0
				 }
			}

		  /* trailing bytes 
		  if (($inpos<$inlen)&&($outpos<$outlen)) {
			 mmemcpy($outbuf,$outpos,$inbuf,$inpos+1,unpack1($inbuf[$inpos],'C')&3);
			 $outpos+=unpack1($inbuf[$inpos],'C')&3;
		  }
		  */
		  
		  /*
		  if ($outpos!=$outlen) 
			  decho("Warning: bad length ? {$outpos} instead of {$outlen} with
{$Cname}");
		  */
		  $buflen=$outlen;
		  return $outbuf;
	}



	function mmemcpy(&$dest, $destpos, &$src, $srcpos, $len)
		{
		  while ($len--)
			{
				//decho ("destpos: $destpos | srcpos: {$src[$srcpos]}");
				$dest[$destpos] = $src[$srcpos];

				$destpos++;
				$srcpos++;
			}
		}


	function unpack1($bytes, $type=false)
	{
		if($type)
		{
			$dat = unpack("{$type}int",$bytes);
			return $dat['int'];
		} else {
			$dat = unpack('Vint',$bytes);
			return $dat['int'];
		}
	}
?>

ANY replies are welcome. Even if you don't know the answer, something
to point me in the right direction would be greatly appreciated. I'm
completely stuck.

-thanks


More information about the Tutor mailing list