PDA

View Full Version : It's been a while.


daeken_bb
03-14-2004, 03:40 AM
Well, it's been a while since I've coded anything related to EQ, so I decided that since I started playing eqlive again, an S3D extractor would be a perfect test for my new unpack_struct() function (hopefully in core php soon).


<?php
define('NL', chr(10));
$struct_s3d_header = array('offset' => 'long',
'magicCookie' => 'char[4]',
'unknown' => 'long'); // 12 bytes

$struct_s3d_directory_header = array('count' => 'long'); // 4 bytes

$struct_s3d_directory = array('crc' => 'long',
'offset' => 'long',
'size' => 'long'); // 12 bytes

$struct_s3d_footer = array('steveCookie' => 'char[5]',
'crc' => 'long'); // 9 bytes

$struct_data_block = array('defLen' => 'long',
'infLen' => 'long'); // 8 bytes

$struct_fn_header = array('fncount' => 'long'); // 4 bytes

$struct_fn_entry = array('fnlen' => 'long'); // 4 bytes;

if($_SERVER['argc'] > 1) {
$s3d = &$_SERVER['argv'][1];
}
else {
echo 'Usage: ', $_SERVER['argv'][0], ' [s3d filename]', NL;
exit;
}
if(!file_exists($s3d)) {
echo 'File does not exist.', NL;
exit;
}
@mkdir($s3d . '_cont');
$file = file_get_contents($s3d);
$header = unpack_struct($struct_s3d_header, $file);
if($header->magicCookie != 'PFS ') {
echo 'Magic Cookie != `PFS \', dieing.', NL;
exit;
}
$dhead = unpack_struct($struct_s3d_directory_header, substr($file, $header->offset, 4));
$pos = $header->offset + 4;
$filenames = array();
$files = array();
for($i = 0; $i < $dhead->count; ++$i) {
$ent = unpack_struct($struct_s3d_directory, substr($file, $pos, 12));
if($ent->crc == 0x61580AC9) {
$fnames = substr($file, $ent->offset);
$fpos = 0;
$inf = (string) null;
while(strlen($inf) < $ent->size) {
$block = unpack_struct($struct_data_block, substr($fnames, $fpos, 8));
$inf .= gzuncompress(substr($fnames, $fpos + 8, $block->defLen));
$fpos += 8 + $block->defLen;
}
$fnhead = unpack_struct($struct_fn_header, $inf);
$fpos = 4;
for($j = 0; $j < $fnhead->fncount; ++$j) {
$fnent = unpack_struct($struct_fn_entry, substr($inf, $fpos, 4));
$filenames[] = substr($inf, $fpos + 4, $fnent->fnlen - 1);
$fpos += 4 + $fnent->fnlen;
}
$pos += 12;
continue;
}
$fblock = substr($file, $ent->offset);
$fpos = 0;
$inf = (string) null;
while(strlen($inf) < $ent->size) {
$block = unpack_struct($struct_data_block, substr($fblock, $fpos, 8));
$inf .= gzuncompress(substr($fblock, $fpos + 8, $block->defLen));
$fpos += 8 + $block->defLen;
}
$files[$ent->offset] = $inf;
$pos += 12;
}
if(count($files) != count($filenames)) {
echo 'Dieing: The count of files and the count of filenames don\'t match.', NL;
exit;
}
ksort($files);
$i = 0;
foreach($files as $data) {
$fp = fopen($s3d . '_cont/' . $filenames[$i++], 'wb');
fwrite($fp, $data);
fclose($fp);
}
?>


To run the script, use the PHP CLI (NOT CGI!) as follows 'php s3dread.php foobar.s3d' and you'll get a directory called foobar.s3d_cont/ with the content in it.

There's the source for the script itself, and the source for the patched php is available at http://archshadow.com/standard.tar.bz2

Note, I have only tested both of these pieces of code (the new functions and the script itself) on Linux with PHP 4.3.4-dev, with snapshot php4-STABLE-200409101930.

Happy Hacking,
Lord Daeken M. BlackBlade
(Cody Brocious)

khuong
03-14-2004, 03:48 AM
sorry php is so hawt :P but wra!

Shawn319
03-14-2004, 06:45 AM
so wtf does this do????

daeken_bb
03-14-2004, 07:41 AM
Guess I should've mentioned that...


Takes all the content from an S3D and puts it in a directory so that it can be manipulated and such.