Skip to content

Commit

Permalink
Merge tag 'v1.9.23' into 2.0-with-1.9.23-202310190849
Browse files Browse the repository at this point in the history
# Conflicts:
#	README.md
#	getid3/module.audio-video.matroska.php
#	license.txt
#	phpstan.neon
#	src/GetID3.php
#	src/Module/Audio/Shorten.php
#	src/Module/Audio/module.archive.7zip.php
#	src/Module/AudioVideo/QuickTime.php
#	src/Module/Graphic/Bmp.php
#	src/Write/ID3v2.php
  • Loading branch information
StudioMaX committed Nov 2, 2023
2 parents 4e7aca9 + 06c7482 commit 5a3f29c
Show file tree
Hide file tree
Showing 44 changed files with 718 additions and 544 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ jobs:
- "8.0"
- "8.1"
- "8.2"
- "8.3"
steps:
- uses: "actions/checkout@v2"
- uses: "actions/checkout@v3"
- uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
Expand All @@ -36,11 +37,11 @@ jobs:
name: "Static Analysis"
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- uses: "actions/checkout@v3"
- uses: "shivammathur/setup-php@v2"
with:
php-version: "7.4"
tools: "phpstan:0.12.99"
tools: "phpstan:1.8.11"
coverage: "none"
- uses: "ramsey/composer-install@v2"
- name: "Run PHPStan"
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ Mozilla MPL

getID3 Commercial License
-------------------------
* [gCL](http://getid3.org/#gCL) (payment required)
* [gCL](http://getid3.org/#gCL) (no longer available, existing licenses remain valid)
13 changes: 13 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@
Version History
===============

1.9.23: [2023-10-19] James Heinrich :: 1.9.23-202310190849
» add detection support for 7-zip archives
* #424 RIFF Undefined index "data"
* #421 tag.xmp remove GLOBALS
* #419 Quicktime Undefined index "time_scale"
* #418 tag.xmp zero-length fread
* #414 Quicktime bitrate for mp4 audio
* #413 Quicktime audio metadata
* #410 MPEG-1 pixel aspect ratio
* #407 PHP 8.1 compatibility
* #404 guard against division by zero
* #402 remove utf8_encode/utf8_decode

1.9.22: [2022-09-29] James Heinrich :: 1.9.22-202207161647
* bugfix #387 fails to detect h265 video codec (QuickTime)
* bugfix #385 Quicktime extended atom size
Expand Down
2 changes: 1 addition & 1 deletion demos/demo.browse.php
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ function table_var_dump($variable, $wrap_in_td=false, $encoding='') {
global $FileSystemEncoding;
$encoding = ($encoding ? $encoding : $FileSystemEncoding);
$returnstring = '';
switch (gettype($variable)) {
switch (strtolower(gettype($variable))) {
case 'array':
$returnstring .= ($wrap_in_td ? '<td>' : '');
$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
Expand Down
61 changes: 29 additions & 32 deletions demos/demo.mp3header.php
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ function RoughTranslateUnicodeToASCII($rawdata, $frame_textencoding) {
break;

case 3: // UTF-8 encoded Unicode. Terminated with $00.
$asciidata = utf8_decode($rawdata);
$asciidata = utf8_to_iso8859_1($rawdata);
break;

case 255: // Unicode, Big-Endian. Terminated with $00 00.
Expand Down Expand Up @@ -929,43 +929,40 @@ function image_type_to_mime_type($imagetypeid) {
}
}

if (!function_exists('utf8_decode')) {
// PHP has this function built-in if it's configured with the --with-xml option
// This version of the function is only provided in case XML isn't installed
function utf8_decode($utf8text) {
// http://www.php.net/manual/en/function.utf8-encode.php
// bytes bits representation
// 1 7 0bbbbbbb
// 2 11 110bbbbb 10bbbbbb
// 3 16 1110bbbb 10bbbbbb 10bbbbbb
// 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb

$utf8length = strlen($utf8text);
$decodedtext = '';
for ($i = 0; $i < $utf8length; $i++) {
if ((ord($utf8text[$i]) & 0x80) == 0) {
$decodedtext .= $utf8text[$i];
} elseif ((ord($utf8text[$i]) & 0xF0) == 0xF0) {
$decodedtext .= '?';
$i += 3;
} elseif ((ord($utf8text[$i]) & 0xE0) == 0xE0) {
function utf8_to_iso8859_1($utf8text) {
// http://www.php.net/manual/en/function.utf8-encode.php
// bytes bits representation
// 1 7 0bbbbbbb
// 2 11 110bbbbb 10bbbbbb
// 3 16 1110bbbb 10bbbbbb 10bbbbbb
// 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb

$utf8length = strlen($utf8text);
$decodedtext = '';
for ($i = 0; $i < $utf8length; $i++) {
if ((ord($utf8text[$i]) & 0x80) == 0) {
$decodedtext .= $utf8text[$i];
} elseif ((ord($utf8text[$i]) & 0xF0) == 0xF0) {
$decodedtext .= '?';
$i += 3;
} elseif ((ord($utf8text[$i]) & 0xE0) == 0xE0) {
$decodedtext .= '?';
$i += 2;
} elseif ((ord($utf8text[$i]) & 0xC0) == 0xC0) {
// 2 11 110bbbbb 10bbbbbb
$decodedchar = Bin2Dec(substr(Dec2Bin(ord($utf8text[$i])), 3, 5).substr(Dec2Bin(ord($utf8text[($i + 1)])), 2, 6));
if ($decodedchar <= 255) {
$decodedtext .= chr($decodedchar);
} else {
$decodedtext .= '?';
$i += 2;
} elseif ((ord($utf8text[$i]) & 0xC0) == 0xC0) {
// 2 11 110bbbbb 10bbbbbb
$decodedchar = Bin2Dec(substr(Dec2Bin(ord($utf8text[$i])), 3, 5).substr(Dec2Bin(ord($utf8text[($i + 1)])), 2, 6));
if ($decodedchar <= 255) {
$decodedtext .= chr($decodedchar);
} else {
$decodedtext .= '?';
}
$i += 1;
}
$i += 1;
}
return $decodedtext;
}
return $decodedtext;
}


if (!function_exists('DateMac2Unix')) {
function DateMac2Unix($macdate) {
// Macintosh timestamp: seconds since 00:00h January 1, 1904
Expand Down
3 changes: 2 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ GNU LGPL: https://gnu.org/licenses/lgpl.html (v3)

Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2)

getID3 Commercial License: https://www.getid3.org/#gCL (payment required)
getID3 Commercial License: https://www.getid3.org/#gCL
(no longer available, existing licenses remain valid)

*****************************************************************
*****************************************************************
Expand Down
13 changes: 11 additions & 2 deletions src/GetID3.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ class GetID3
*/
protected $startup_warning = '';

const VERSION = '2.0.x-202207161647';
const VERSION = '2.0.x-202310190849';
const FREAD_BUFFER_SIZE = 32768;

const ATTACHMENTS_NONE = false;
Expand Down Expand Up @@ -1253,6 +1253,15 @@ public function GetFileFormatArray() {
'fail_ape' => 'ERROR',
),

// XZ - data - XZ compressed data
'7zip' => array(
'pattern' => '^7z\\xBC\\xAF\\x27\\x1C',
'module' => 'Archive\\SevenZip',
'mime_type' => 'application/x-7z-compressed',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
),


// Misc other formats

Expand Down Expand Up @@ -1750,7 +1759,7 @@ public function CalculateCompressionRatioVideo() {
}
$BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;

$this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
$this->info['video']['compression_ratio'] = Utils::SafeDiv($BitrateCompressed, $BitrateUncompressed, 1);
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Module/Archive/Hpk.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function Analyze() {
$info['hpk']['header']['fragmented_filesystem_offset'] = Utils::LittleEndian2Int(substr($HPKheader, 28, 4));
$info['hpk']['header']['fragmented_filesystem_length'] = Utils::LittleEndian2Int(substr($HPKheader, 32, 4));

$info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8);
$info['hpk']['header']['filesystem_entries'] = Utils::SafeDiv($info['hpk']['header']['fragmented_filesystem_length'], $info['hpk']['header']['fragments_per_file'] * 8);
$this->fseek($info['hpk']['header']['fragmented_filesystem_offset']);
for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) {
$offset = Utils::LittleEndian2Int($this->fread(4));
Expand Down
52 changes: 52 additions & 0 deletions src/Module/Archive/SevenZip.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace JamesHeinrich\GetID3\Module\Archive;

use JamesHeinrich\GetID3\Module\Handler;
use JamesHeinrich\GetID3\Utils;

/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <[email protected]> //
// available at https://github.com/JamesHeinrich/getID3 //
// or https://www.getid3.org //
// or http://getid3.sourceforge.net //
// see readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.7zip.php //
// module for analyzing 7zip files //
// ///
/////////////////////////////////////////////////////////////////

class SevenZip extends Handler
{
/**
* @return bool
*/
public function Analyze() {
$info = &$this->getid3->info;

$this->fseek($info['avdataoffset']);
$z7header = $this->fread(32);

// https://py7zr.readthedocs.io/en/latest/archive_format.html
$info['7zip']['header']['magic'] = substr($z7header, 0, 6);
if ($info['7zip']['header']['magic'] != '7z'."\xBC\xAF\x27\x1C") {
$this->error('Invalid 7zip stream header magic (expecting 37 7A BC AF 27 1C, found '.Utils::PrintHexBytes($info['7zip']['header']['magic']).') at offset '.$info['avdataoffset']);
return false;
}
$info['fileformat'] = '7zip';

$info['7zip']['header']['version_major'] = Utils::LittleEndian2Int(substr($z7header, 6, 1)); // always 0x00 (?)
$info['7zip']['header']['version_minor'] = Utils::LittleEndian2Int(substr($z7header, 7, 1)); // always 0x04 (?)
$info['7zip']['header']['start_header_crc'] = Utils::LittleEndian2Int(substr($z7header, 8, 4));
$info['7zip']['header']['next_header_offset'] = Utils::LittleEndian2Int(substr($z7header, 12, 8));
$info['7zip']['header']['next_header_size'] = Utils::LittleEndian2Int(substr($z7header, 20, 8));
$info['7zip']['header']['next_header_crc'] = Utils::LittleEndian2Int(substr($z7header, 28, 4));

$this->error('7zip parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
return false;

}

}
2 changes: 1 addition & 1 deletion src/Module/Audio/Amr.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public function Analyze() {
} while (strlen($buffer) > 0);

$info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long
$info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding
$info['audio']['bitrate'] = Utils::SafeDiv(8 * ($info['avdataend'] - $info['avdataoffset']), $info['playtime_seconds']); // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding
$info['bitrate'] = $info['audio']['bitrate'];

return true;
Expand Down
4 changes: 2 additions & 2 deletions src/Module/Audio/Au.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public function Analyze() {
$this->warning('Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
}

$info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
$info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds'];
$info['audio']['bitrate'] = $thisfile_au['sample_rate'] * $thisfile_au['channels'] * $thisfile_au['used_bits_per_sample'];
$info['playtime_seconds'] = Utils::SafeDiv($thisfile_au['data_size'], $info['audio']['bitrate'] / 8);

return true;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Module/Audio/Avr.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ public function Analyze() {
$info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample'];
$info['audio']['sample_rate'] = $info['avr']['sample_rate'];
$info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1);
$info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate'];
$info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds'];

$bits_per_sample = ($info['avr']['bits_per_sample'] == 8) ? 8 : 16;
$info['audio']['bitrate'] = $bits_per_sample * $info['audio']['channels'] * $info['avr']['sample_rate'];
$info['playtime_seconds'] = Utils::SafeDiv($info['avr']['sample_length'] * $bits_per_sample, $info['audio']['bitrate']);

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Module/Audio/Bonk.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public function HandleBonkTags($BonkTagName) {
$info['audio']['lossless'] = $thisfile_bonk_BONK['lossless'];
$info['audio']['codec'] = 'bonk';

$info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
$info['playtime_seconds'] = Utils::SafeDiv($thisfile_bonk_BONK['number_samples'], $thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
if ($info['playtime_seconds'] > 0) {
$info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds'];
}
Expand Down
10 changes: 7 additions & 3 deletions src/Module/Audio/Dsdiff.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,13 @@ public function Analyze() {
$this->fseek(1, SEEK_CUR);
}

if ($commentkey = (($thisChunk['name'] == 'DIAR') ? 'artist' : (($thisChunk['name'] == 'DITI') ? 'title' : ''))) {
@$info['dsdiff']['comments'][$commentkey][] = $thisChunk['description'];
}
$commentKeys = array(
'DIAR' => 'artist',
'DITI' => 'title'
);
$commentkey = $commentKeys[$thisChunk['name']];

$info['dsdiff']['comments'][$commentkey][] = $thisChunk['description'];
break;
case 'EMID': // Edited Master ID chunk
if ($thisChunk['size']) {
Expand Down
2 changes: 1 addition & 1 deletion src/Module/Audio/Dsf.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public function Analyze() {
$info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate'];
$info['audio']['channels'] = $info['dsf']['fmt']['channels'];
$info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
$info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
$info['playtime_seconds'] = Utils::SafeDiv($info['dsf']['data']['data_chunk_size'] * 8, $info['audio']['bitrate']);

return true;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Module/Audio/Lpac.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ public function Analyze() {
}
}

$info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate'];
$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
$info['playtime_seconds'] = Utils::SafeDiv($info['lpac']['total_samples'], $info['audio']['sample_rate']);
$info['audio']['bitrate'] = Utils::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']);

return true;
}
Expand Down
2 changes: 0 additions & 2 deletions src/Module/Audio/Midi.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ public function Analyze() {
$thisfile_midi['totalticks'] = 0;
$info['playtime_seconds'] = 0;
$CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
$CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
$MicroSecondsPerQuarterNoteAfter = array ();
$MIDIevents = array();

Expand Down Expand Up @@ -251,7 +250,6 @@ public function Analyze() {
return false;
}
$thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
$CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60;
$MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
$TicksAtCurrentBPM = 0;
break;
Expand Down
Loading

0 comments on commit 5a3f29c

Please sign in to comment.