function read_gzip($fd, &$ThisFileInfo) { $start_length = 10; $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os'; //+---+---+---+---+---+---+---+---+---+---+ //|ID1|ID2|CM |FLG| MTIME |XFL|OS | //+---+---+---+---+---+---+---+---+---+---+ @fseek($fd, 0); $buffer = @fread($fd, $ThisFileInfo['filesize']); $arr_members = explode("‹", $buffer); while (true) { $is_wrong_members = false; $num_members = intval(count($arr_members)); for ($i = 0; $i < $num_members; $i++) { if (strlen($arr_members[$i]) == 0) { continue; } $buf = "‹" . $arr_members[$i]; $attr = unpack($unpack_header, substr($buf, 0, $start_length)); if (!$this->get_os_type(ord($attr['os']))) { // Merge member with previous if wrong OS type $arr_members[$i - 1] .= $buf; $arr_members[$i] = ''; $is_wrong_members = true; continue; } } if (!$is_wrong_members) { break; } } $ThisFileInfo['gzip']['files'] = array(); $fpointer = 0; $idx = 0; for ($i = 0; $i < $num_members; $i++) { if (strlen($arr_members[$i]) == 0) { continue; } $thisThisFileInfo =& $ThisFileInfo['gzip']['member_header'][++$idx]; $buff = "‹" . $arr_members[$i]; $attr = unpack($unpack_header, substr($buff, 0, $start_length)); $thisThisFileInfo['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']); $thisThisFileInfo['raw']['id1'] = ord($attr['cmethod']); $thisThisFileInfo['raw']['id2'] = ord($attr['cmethod']); $thisThisFileInfo['raw']['cmethod'] = ord($attr['cmethod']); $thisThisFileInfo['raw']['os'] = ord($attr['os']); $thisThisFileInfo['raw']['xflags'] = ord($attr['xflags']); $thisThisFileInfo['raw']['flags'] = ord($attr['flags']); $thisThisFileInfo['flags']['crc16'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x2); $thisThisFileInfo['flags']['extra'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x4); $thisThisFileInfo['flags']['filename'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x8); $thisThisFileInfo['flags']['comment'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x10); $thisThisFileInfo['compression'] = $this->get_xflag_type($thisThisFileInfo['raw']['xflags']); $thisThisFileInfo['os'] = $this->get_os_type($thisThisFileInfo['raw']['os']); if (!$thisThisFileInfo['os']) { $ThisFileInfo['error'][] = 'Read error on gzip file'; return false; } $fpointer = 10; $arr_xsubfield = array(); // bit 2 - FLG.FEXTRA //+---+---+=================================+ //| XLEN |...XLEN bytes of "extra field"...| //+---+---+=================================+ if ($thisThisFileInfo['flags']['extra']) { $w_xlen = substr($buff, $fpointer, 2); $xlen = getid3_lib::LittleEndian2Int($w_xlen); $fpointer += 2; $thisThisFileInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen); // Extra SubFields //+---+---+---+---+==================================+ //|SI1|SI2| LEN |... LEN bytes of subfield data ...| //+---+---+---+---+==================================+ $idx = 0; while (true) { if ($idx >= $xlen) { break; } $si1 = ord(substr($buff, $fpointer + $idx++, 1)); $si2 = ord(substr($buff, $fpointer + $idx++, 1)); if ($si1 == 0x41 && $si2 == 0x70) { $w_xsublen = substr($buff, $fpointer + $idx, 2); $xsublen = getid3_lib::LittleEndian2Int($w_xsublen); $idx += 2; $arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen); $idx += $xsublen; } else { break; } } $fpointer += $xlen; } // bit 3 - FLG.FNAME //+=========================================+ //|...original file name, zero-terminated...| //+=========================================+ // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz $thisThisFileInfo['filename'] = preg_replace('{.gz$}i', '', $ThisFileInfo['filename']); if ($thisThisFileInfo['flags']['filename']) { while (true) { if (ord($buff[$fpointer]) == 0) { $fpointer++; break; } $thisThisFileInfo['filename'] .= $buff[$fpointer]; $fpointer++; } } // bit 4 - FLG.FCOMMENT //+===================================+ //|...file comment, zero-terminated...| //+===================================+ if ($thisThisFileInfo['flags']['comment']) { while (true) { if (ord($buff[$fpointer]) == 0) { $fpointer++; break; } $thisThisFileInfo['comment'] .= $buff[$fpointer]; $fpointer++; } } // bit 1 - FLG.FHCRC //+---+---+ //| CRC16 | //+---+---+ if ($thisThisFileInfo['flags']['crc16']) { $w_crc = substr($buff, $fpointer, 2); $thisThisFileInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc); $fpointer += 2; } // bit 0 - FLG.FTEXT //if ($thisThisFileInfo['raw']['flags'] & 0x01) { // Ignored... //} // bits 5, 6, 7 - reserved $thisThisFileInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4)); $thisThisFileInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4)); $ThisFileInfo['gzip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['gzip']['files'], getid3_lib::CreateDeepArray($thisThisFileInfo['filename'], '/', $thisThisFileInfo['filesize'])); if ($this->option_gzip_parse_contents) { // Try to inflate GZip $csize = 0; $inflated = ''; $chkcrc32 = ''; if (function_exists('gzinflate')) { $cdata = substr($buff, $fpointer); $cdata = substr($cdata, 0, strlen($cdata) - 8); $csize = strlen($cdata); $inflated = gzinflate($cdata); // Calculate CRC32 for inflated content $thisThisFileInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisThisFileInfo['crc32']); // determine format $formattest = substr($inflated, 0, 32774); $newgetID3 = new getID3(); $determined_format = $newgetID3->GetFileFormat($formattest); unset($newgetID3); // file format is determined switch (@$determined_format['module']) { case 'tar': // view TAR-file info if (file_exists(GETID3_INCLUDEPATH . $determined_format['include']) && @(include_once GETID3_INCLUDEPATH . $determined_format['include'])) { getid3_tar::read_tar($inflated, $ThisFileInfo['gzip']['member_header'][$idx]); } break; case '': default: // unknown or unhandled format break; } } } } return true; }
function getid3_tar(&$fd, &$ThisFileInfo) { $ThisFileInfo['fileformat'] = 'tar'; $ThisFileInfo['tar']['files'] = array(); $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155/prefix'; $null_512k = str_repeat("", 512); // end-of-file marker @fseek($fd, 0); while (!feof($fd)) { $buffer = fread($fd, 512); // check the block $checksum = 0; for ($i = 0; $i < 148; $i++) { $checksum += ord($buffer[$i]); } for ($i = 148; $i < 156; $i++) { $checksum += ord(' '); } for ($i = 156; $i < 512; $i++) { $checksum += ord($buffer[$i]); } $attr = unpack($unpack_header, $buffer); $name = trim(@$attr['fname']); $mode = octdec(trim(@$attr['mode'])); $uid = octdec(trim(@$attr['uid'])); $gid = octdec(trim(@$attr['gid'])); $size = octdec(trim(@$attr['size'])); $mtime = octdec(trim(@$attr['mtime'])); $chksum = octdec(trim(@$attr['chksum'])); $typflag = trim(@$attr['typflag']); $lnkname = trim(@$attr['lnkname']); $magic = trim(@$attr['magic']); $ver = trim(@$attr['ver']); $uname = trim(@$attr['uname']); $gname = trim(@$attr['gname']); $devmaj = octdec(trim(@$attr['devmaj'])); $devmin = octdec(trim(@$attr['devmin'])); $prefix = trim(@$attr['prefix']); if ($checksum == 256 && $chksum == 0) { // EOF Found break; } if ($prefix) { $name = $prefix . '/' . $name; } if (preg_match('#/$#', $name) && !$name) { $typeflag = 5; } if ($buffer == $null_512k) { // it's the end of the tar-file... break; } // Read to the next chunk fseek($fd, $size, SEEK_CUR); $diff = $size % 512; if ($diff != 0) { // Padding, throw away fseek($fd, 512 - $diff, SEEK_CUR); } // Protect against tar-files with garbage at the end if ($name == '') { break; } $ThisFileInfo['tar']['file_details'][$name] = array('name' => $name, 'mode_raw' => $mode, 'mode' => getid3_tar::display_perms($mode), 'uid' => $uid, 'gid' => $gid, 'size' => $size, 'mtime' => $mtime, 'chksum' => $chksum, 'typeflag' => getid3_tar::get_flag_type($typflag), 'linkname' => $lnkname, 'magic' => $magic, 'version' => $ver, 'uname' => $uname, 'gname' => $gname, 'devmajor' => $devmaj, 'devminor' => $devmin); $ThisFileInfo['tar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['tar']['files'], getid3_lib::CreateDeepArray($ThisFileInfo['tar']['file_details'][$name]['name'], '/', $size)); } return true; }
function Analyze() { $info =& $this->getid3->info; $info['fileformat'] = 'tar'; $fp = $this->getid3->fp; fseek($fp, 0); $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155/prefix'; $null_512k = str_repeat("", 512); // end-of-file marker $already_warned = false; while (!feof($fp)) { $buffer = fread($fp, 512); // check the block $checksum = 0; for ($i = 0; $i < 148; $i++) { $checksum += ord(substr($buffer, $i, 1)); } for ($i = 148; $i < 156; $i++) { $checksum += ord(' '); } for ($i = 156; $i < 512; $i++) { $checksum += ord(substr($buffer, $i, 1)); } $attr = unpack($unpack_header, $buffer); $name = trim(@$attr['fname']); $mode = octdec(trim(@$attr['mode'])); $uid = octdec(trim(@$attr['uid'])); $gid = octdec(trim(@$attr['gid'])); $size = octdec(trim(@$attr['size'])); $mtime = octdec(trim(@$attr['mtime'])); $chksum = octdec(trim(@$attr['chksum'])); $typflag = trim(@$attr['typflag']); $lnkname = trim(@$attr['lnkname']); $magic = trim(@$attr['magic']); $ver = trim(@$attr['ver']); $uname = trim(@$attr['uname']); $gname = trim(@$attr['gname']); $devmaj = octdec(trim(@$attr['devmaj'])); $devmin = octdec(trim(@$attr['devmin'])); $prefix = trim(@$attr['prefix']); // EOF Found if ($checksum == 256 && $chksum == 0) { break; } // Check if filename if 7bit as spec requires if (!$already_warned) { for ($i = 0; $i < strlen($name); $i++) { if ($name[$i] < chr(32) || $name[$i] > chr(127)) { $this->getid3->warning('Some filenames contains extended characters, which breaks the tar specifation. This is not uncommon, but you will have to handle the character encoding for filenames yourself.'); $already_warned = true; break; } } } if ($prefix) { $name = $prefix . '/' . $name; } if (preg_match('#/$#', $name) && !$name) { $typeflag = 5; } // If it's the end of the tar-file... if ($buffer == $null_512k) { break; } // Protect against tar-files with garbage at the end if ($name == '') { break; } $info['tar']['file_details'][$name] = array('name' => $name, 'mode_raw' => $mode, 'mode' => getid3_tar::display_perms($mode), 'uid' => $uid, 'gid' => $gid, 'size' => $size, 'mtime' => $mtime, 'chksum' => $chksum, 'typeflag' => getid3_tar::get_flag_type($typflag), 'linkname' => $lnkname, 'magic' => $magic, 'version' => $ver, 'uname' => $uname, 'gname' => $gname, 'devmajor' => $devmaj, 'devminor' => $devmin); // Skip the next chunk fseek($fp, $size, SEEK_CUR); // Throw away padding if ($size % 512) { fseek($fp, 512 - $diff, SEEK_CUR); } } return true; }