[SPIP] v3.2.12 -> v3.2.12 - Reinstallation avec le spip_loader
[lhc/web/www.git] / www / plugins-dist / medias / lib / getid3 / module.audio.bonk.php
1 <?php
2
3 /////////////////////////////////////////////////////////////////
4 /// getID3() by James Heinrich <info@getid3.org> //
5 // available at https://github.com/JamesHeinrich/getID3 //
6 // or https://www.getid3.org //
7 // or http://getid3.sourceforge.net //
8 // see readme.txt for more details //
9 /////////////////////////////////////////////////////////////////
10 // //
11 // module.audio.la.php //
12 // module for analyzing BONK audio files //
13 // dependencies: module.tag.id3v2.php (optional) //
14 // ///
15 /////////////////////////////////////////////////////////////////
16
17 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
18 exit;
19 }
20
21 class getid3_bonk extends getid3_handler
22 {
23 /**
24 * @return bool
25 */
26 public function Analyze() {
27 $info = &$this->getid3->info;
28
29 // shortcut
30 $info['bonk'] = array();
31 $thisfile_bonk = &$info['bonk'];
32
33 $thisfile_bonk['dataoffset'] = $info['avdataoffset'];
34 $thisfile_bonk['dataend'] = $info['avdataend'];
35
36 if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) {
37
38 $this->warning('Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to '.round(PHP_INT_MAX / 1073741824).'GB');
39
40 } else {
41
42 // scan-from-end method, for v0.6 and higher
43 $this->fseek($thisfile_bonk['dataend'] - 8);
44 $PossibleBonkTag = $this->fread(8);
45 while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) {
46 $BonkTagSize = getid3_lib::LittleEndian2Int(substr($PossibleBonkTag, 0, 4));
47 $this->fseek(0 - $BonkTagSize, SEEK_CUR);
48 $BonkTagOffset = $this->ftell();
49 $TagHeaderTest = $this->fread(5);
50 if (($TagHeaderTest[0] != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
51 $this->error('Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"');
52 return false;
53 }
54 $BonkTagName = substr($TagHeaderTest, 1, 4);
55
56 $thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize;
57 $thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset;
58 $this->HandleBonkTags($BonkTagName);
59 $NextTagEndOffset = $BonkTagOffset - 8;
60 if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) {
61 if (empty($info['audio']['encoder'])) {
62 $info['audio']['encoder'] = 'Extended BONK v0.9+';
63 }
64 return true;
65 }
66 $this->fseek($NextTagEndOffset);
67 $PossibleBonkTag = $this->fread(8);
68 }
69
70 }
71
72 // seek-from-beginning method for v0.4 and v0.5
73 if (empty($thisfile_bonk['BONK'])) {
74 $this->fseek($thisfile_bonk['dataoffset']);
75 do {
76 $TagHeaderTest = $this->fread(5);
77 switch ($TagHeaderTest) {
78 case "\x00".'BONK':
79 if (empty($info['audio']['encoder'])) {
80 $info['audio']['encoder'] = 'BONK v0.4';
81 }
82 break;
83
84 case "\x00".'INFO':
85 $info['audio']['encoder'] = 'Extended BONK v0.5';
86 break;
87
88 default:
89 break 2;
90 }
91 $BonkTagName = substr($TagHeaderTest, 1, 4);
92 $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
93 $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
94 $this->HandleBonkTags($BonkTagName);
95
96 } while (true);
97 }
98
99 // parse META block for v0.6 - v0.8
100 if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) {
101 $this->fseek($thisfile_bonk['META']['tags']['info']);
102 $TagHeaderTest = $this->fread(5);
103 if ($TagHeaderTest == "\x00".'INFO') {
104 $info['audio']['encoder'] = 'Extended BONK v0.6 - v0.8';
105
106 $BonkTagName = substr($TagHeaderTest, 1, 4);
107 $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
108 $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
109 $this->HandleBonkTags($BonkTagName);
110 }
111 }
112
113 if (empty($info['audio']['encoder'])) {
114 $info['audio']['encoder'] = 'Extended BONK v0.9+';
115 }
116 if (empty($thisfile_bonk['BONK'])) {
117 unset($info['bonk']);
118 }
119 return true;
120
121 }
122
123 /**
124 * @param string $BonkTagName
125 */
126 public function HandleBonkTags($BonkTagName) {
127 $info = &$this->getid3->info;
128 switch ($BonkTagName) {
129 case 'BONK':
130 // shortcut
131 $thisfile_bonk_BONK = &$info['bonk']['BONK'];
132
133 $BonkData = "\x00".'BONK'.$this->fread(17);
134 $thisfile_bonk_BONK['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1));
135 $thisfile_bonk_BONK['number_samples'] = getid3_lib::LittleEndian2Int(substr($BonkData, 6, 4));
136 $thisfile_bonk_BONK['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BonkData, 10, 4));
137
138 $thisfile_bonk_BONK['channels'] = getid3_lib::LittleEndian2Int(substr($BonkData, 14, 1));
139 $thisfile_bonk_BONK['lossless'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 15, 1));
140 $thisfile_bonk_BONK['joint_stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 16, 1));
141 $thisfile_bonk_BONK['number_taps'] = getid3_lib::LittleEndian2Int(substr($BonkData, 17, 2));
142 $thisfile_bonk_BONK['downsampling_ratio'] = getid3_lib::LittleEndian2Int(substr($BonkData, 19, 1));
143 $thisfile_bonk_BONK['samples_per_packet'] = getid3_lib::LittleEndian2Int(substr($BonkData, 20, 2));
144
145 $info['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17;
146 $info['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size'];
147
148 $info['fileformat'] = 'bonk';
149 $info['audio']['dataformat'] = 'bonk';
150 $info['audio']['bitrate_mode'] = 'vbr'; // assumed
151 $info['audio']['channels'] = $thisfile_bonk_BONK['channels'];
152 $info['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate'];
153 $info['audio']['channelmode'] = ($thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo');
154 $info['audio']['lossless'] = $thisfile_bonk_BONK['lossless'];
155 $info['audio']['codec'] = 'bonk';
156
157 $info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
158 if ($info['playtime_seconds'] > 0) {
159 $info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds'];
160 }
161 break;
162
163 case 'INFO':
164 // shortcut
165 $thisfile_bonk_INFO = &$info['bonk']['INFO'];
166
167 $thisfile_bonk_INFO['version'] = getid3_lib::LittleEndian2Int($this->fread(1));
168 $thisfile_bonk_INFO['entries_count'] = 0;
169 $NextInfoDataPair = $this->fread(5);
170 if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
171 while (!feof($this->getid3->fp)) {
172 //$CurrentSeekInfo['offset'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4));
173 //$CurrentSeekInfo['nextbit'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1));
174 //$thisfile_bonk_INFO[] = $CurrentSeekInfo;
175
176 $NextInfoDataPair = $this->fread(5);
177 if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
178 $this->fseek(-5, SEEK_CUR);
179 break;
180 }
181 $thisfile_bonk_INFO['entries_count']++;
182 }
183 }
184 break;
185
186 case 'META':
187 $BonkData = "\x00".'META'.$this->fread($info['bonk']['META']['size'] - 5);
188 $info['bonk']['META']['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1));
189
190 $MetaTagEntries = floor(((strlen($BonkData) - 8) - 6) / 8); // BonkData - xxxxmeta - ØMETA
191 $offset = 6;
192 for ($i = 0; $i < $MetaTagEntries; $i++) {
193 $MetaEntryTagName = substr($BonkData, $offset, 4);
194 $offset += 4;
195 $MetaEntryTagOffset = getid3_lib::LittleEndian2Int(substr($BonkData, $offset, 4));
196 $offset += 4;
197 $info['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset;
198 }
199 break;
200
201 case ' ID3':
202 $info['audio']['encoder'] = 'Extended BONK v0.9+';
203
204 // ID3v2 checking is optional
205 if (class_exists('getid3_id3v2')) {
206 $getid3_temp = new getID3();
207 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
208 $getid3_id3v2 = new getid3_id3v2($getid3_temp);
209 $getid3_id3v2->StartingOffset = $info['bonk'][' ID3']['offset'] + 2;
210 $info['bonk'][' ID3']['valid'] = $getid3_id3v2->Analyze();
211 if ($info['bonk'][' ID3']['valid']) {
212 $info['id3v2'] = $getid3_temp->info['id3v2'];
213 }
214 unset($getid3_temp, $getid3_id3v2);
215 }
216 break;
217
218 default:
219 $this->warning('Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset']);
220 break;
221
222 }
223 }
224
225 /**
226 * @param string $PossibleBonkTag
227 * @param bool $ignorecase
228 *
229 * @return bool
230 */
231 public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) {
232 static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META');
233 foreach ($BonkIsValidTagName as $validtagname) {
234 if ($validtagname == $PossibleBonkTag) {
235 return true;
236 } elseif ($ignorecase && (strtolower($validtagname) == strtolower($PossibleBonkTag))) {
237 return true;
238 }
239 }
240 return false;
241 }
242
243 }