File indexing completed on 2024-12-22 05:33:13

0001 <?php
0002 /////////////////////////////////////////////////////////////////
0003 /// getID3() by James Heinrich <info@getid3.org>               //
0004 //  available at http://getid3.sourceforge.net                 //
0005 //            or http://www.getid3.org                         //
0006 //          also https://github.com/JamesHeinrich/getID3       //
0007 /////////////////////////////////////////////////////////////////
0008 // See readme.txt for more details                             //
0009 /////////////////////////////////////////////////////////////////
0010 //                                                             //
0011 // module.audio.shorten.php                                    //
0012 // module for analyzing Shorten Audio files                    //
0013 // dependencies: NONE                                          //
0014 //                                                            ///
0015 /////////////////////////////////////////////////////////////////
0016 
0017 
0018 class getid3_shorten extends getid3_handler
0019 {
0020 
0021   public function Analyze() {
0022     $info = &$this->getid3->info;
0023 
0024     $this->fseek($info['avdataoffset']);
0025 
0026     $ShortenHeader = $this->fread(8);
0027     $magic = 'ajkg';
0028     if (substr($ShortenHeader, 0, 4) != $magic) {
0029       $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"';
0030       return false;
0031     }
0032     $info['fileformat']            = 'shn';
0033     $info['audio']['dataformat']   = 'shn';
0034     $info['audio']['lossless']     = true;
0035     $info['audio']['bitrate_mode'] = 'vbr';
0036 
0037     $info['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1));
0038 
0039     $this->fseek($info['avdataend'] - 12);
0040     $SeekTableSignatureTest = $this->fread(12);
0041     $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK');
0042     if ($info['shn']['seektable']['present']) {
0043       $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
0044       $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length'];
0045       $this->fseek($info['shn']['seektable']['offset']);
0046       $SeekTableMagic = $this->fread(4);
0047       $magic = 'SEEK';
0048       if ($SeekTableMagic != $magic) {
0049 
0050         $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"';
0051         return false;
0052 
0053       } else {
0054 
0055         // typedef struct tag_TSeekEntry
0056         // {
0057         //   unsigned long SampleNumber;
0058         //   unsigned long SHNFileByteOffset;
0059         //   unsigned long SHNLastBufferReadPosition;
0060         //   unsigned short SHNByteGet;
0061         //   unsigned short SHNBufferOffset;
0062         //   unsigned short SHNFileBitOffset;
0063         //   unsigned long SHNGBuffer;
0064         //   unsigned short SHNBitShift;
0065         //   long CBuf0[3];
0066         //   long CBuf1[3];
0067         //   long Offset0[4];
0068         //   long Offset1[4];
0069         // }TSeekEntry;
0070 
0071         $SeekTableData = $this->fread($info['shn']['seektable']['length'] - 16);
0072         $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80);
0073         //$info['shn']['seektable']['entries'] = array();
0074         //$SeekTableOffset = 0;
0075         //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) {
0076         //  $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0077         //  $SeekTableOffset += 4;
0078         //  $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0079         //  $SeekTableOffset += 4;
0080         //  $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0081         //  $SeekTableOffset += 4;
0082         //  $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
0083         //  $SeekTableOffset += 2;
0084         //  $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
0085         //  $SeekTableOffset += 2;
0086         //  $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
0087         //  $SeekTableOffset += 2;
0088         //  $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0089         //  $SeekTableOffset += 4;
0090         //  $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
0091         //  $SeekTableOffset += 2;
0092         //  for ($j = 0; $j < 3; $j++) {
0093         //    $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0094         //    $SeekTableOffset += 4;
0095         //  }
0096         //  for ($j = 0; $j < 3; $j++) {
0097         //    $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0098         //    $SeekTableOffset += 4;
0099         //  }
0100         //  for ($j = 0; $j < 4; $j++) {
0101         //    $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0102         //    $SeekTableOffset += 4;
0103         //  }
0104         //  for ($j = 0; $j < 4; $j++) {
0105         //    $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
0106         //    $SeekTableOffset += 4;
0107         //  }
0108         //
0109         //  $info['shn']['seektable']['entries'][] = $SeekTableEntry;
0110         //}
0111 
0112       }
0113 
0114     }
0115 
0116     if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
0117       $info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files';
0118       return false;
0119     }
0120 
0121     if (GETID3_OS_ISWINDOWS) {
0122 
0123       $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
0124       foreach ($RequiredFiles as $required_file) {
0125         if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
0126           $info['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist';
0127           return false;
0128         }
0129       }
0130       $commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$info['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64';
0131       $commandline = str_replace('/', '\\', $commandline);
0132 
0133     } else {
0134 
0135       static $shorten_present;
0136       if (!isset($shorten_present)) {
0137         $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
0138       }
0139       if (!$shorten_present) {
0140         $info['error'][] = 'shorten binary was not found in path or /usr/local/bin';
0141         return false;
0142       }
0143       $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64';
0144 
0145     }
0146 
0147     $output = `$commandline`;
0148 
0149     if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) {
0150 
0151       getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
0152 
0153       $fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4));
0154       $DecodedWAVFORMATEX = getid3_riff::parseWAVEFORMATex(substr($output, 20, $fmt_size));
0155       $info['audio']['channels']        = $DecodedWAVFORMATEX['channels'];
0156       $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample'];
0157       $info['audio']['sample_rate']     = $DecodedWAVFORMATEX['sample_rate'];
0158 
0159       if (substr($output, 20 + $fmt_size, 4) == 'data') {
0160 
0161         $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec'];
0162 
0163       } else {
0164 
0165         $info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime';
0166         return false;
0167 
0168       }
0169 
0170       $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8;
0171 
0172     } else {
0173 
0174       $info['error'][] = 'shorten failed to decode file to WAV for parsing';
0175       return false;
0176 
0177     }
0178 
0179     return true;
0180   }
0181 
0182 }