wp/wp-includes/ID3/getid3.lib.php
changeset 16 a86126ab1dd4
parent 7 cf61fcea0001
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     1 <?php
     1 <?php
       
     2 
     2 /////////////////////////////////////////////////////////////////
     3 /////////////////////////////////////////////////////////////////
     3 /// getID3() by James Heinrich <info@getid3.org>               //
     4 /// getID3() by James Heinrich <info@getid3.org>               //
     4 //  available at http://getid3.sourceforge.net                 //
     5 //  available at https://github.com/JamesHeinrich/getID3       //
     5 //            or http://www.getid3.org                         //
     6 //            or https://www.getid3.org                        //
     6 //          also https://github.com/JamesHeinrich/getID3       //
     7 //            or http://getid3.sourceforge.net                 //
     7 /////////////////////////////////////////////////////////////////
       
     8 //                                                             //
     8 //                                                             //
     9 // getid3.lib.php - part of getID3()                           //
     9 // getid3.lib.php - part of getID3()                           //
    10 // See readme.txt for more details                             //
    10 //  see readme.txt for more details                            //
    11 //                                                            ///
    11 //                                                            ///
    12 /////////////////////////////////////////////////////////////////
    12 /////////////////////////////////////////////////////////////////
    13 
    13 
    14 
    14 
    15 class getid3_lib
    15 class getid3_lib
    16 {
    16 {
    17 
    17 	/**
       
    18 	 * @param string      $string
       
    19 	 * @param bool        $hex
       
    20 	 * @param bool        $spaces
       
    21 	 * @param string|bool $htmlencoding
       
    22 	 *
       
    23 	 * @return string
       
    24 	 */
    18 	public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
    25 	public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
    19 		$returnstring = '';
    26 		$returnstring = '';
    20 		for ($i = 0; $i < strlen($string); $i++) {
    27 		for ($i = 0; $i < strlen($string); $i++) {
    21 			if ($hex) {
    28 			if ($hex) {
    22 				$returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
    29 				$returnstring .= str_pad(dechex(ord($string[$i])), 2, '0', STR_PAD_LEFT);
    23 			} else {
    30 			} else {
    24 				$returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤');
    31 				$returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string[$i]) ? $string[$i] : '¤');
    25 			}
    32 			}
    26 			if ($spaces) {
    33 			if ($spaces) {
    27 				$returnstring .= ' ';
    34 				$returnstring .= ' ';
    28 			}
    35 			}
    29 		}
    36 		}
    34 			$returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
    41 			$returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
    35 		}
    42 		}
    36 		return $returnstring;
    43 		return $returnstring;
    37 	}
    44 	}
    38 
    45 
       
    46 	/**
       
    47 	 * Truncates a floating-point number at the decimal point.
       
    48 	 *
       
    49 	 * @param float $floatnumber
       
    50 	 *
       
    51 	 * @return float|int returns int (if possible, otherwise float)
       
    52 	 */
    39 	public static function trunc($floatnumber) {
    53 	public static function trunc($floatnumber) {
    40 		// truncates a floating-point number at the decimal point
       
    41 		// returns int (if possible, otherwise float)
       
    42 		if ($floatnumber >= 1) {
    54 		if ($floatnumber >= 1) {
    43 			$truncatednumber = floor($floatnumber);
    55 			$truncatednumber = floor($floatnumber);
    44 		} elseif ($floatnumber <= -1) {
    56 		} elseif ($floatnumber <= -1) {
    45 			$truncatednumber = ceil($floatnumber);
    57 			$truncatednumber = ceil($floatnumber);
    46 		} else {
    58 		} else {
    50 			$truncatednumber = (int) $truncatednumber;
    62 			$truncatednumber = (int) $truncatednumber;
    51 		}
    63 		}
    52 		return $truncatednumber;
    64 		return $truncatednumber;
    53 	}
    65 	}
    54 
    66 
    55 
    67 	/**
       
    68 	 * @param int|null $variable
       
    69 	 * @param int      $increment
       
    70 	 *
       
    71 	 * @return bool
       
    72 	 */
    56 	public static function safe_inc(&$variable, $increment=1) {
    73 	public static function safe_inc(&$variable, $increment=1) {
    57 		if (isset($variable)) {
    74 		if (isset($variable)) {
    58 			$variable += $increment;
    75 			$variable += $increment;
    59 		} else {
    76 		} else {
    60 			$variable = $increment;
    77 			$variable = $increment;
    61 		}
    78 		}
    62 		return true;
    79 		return true;
    63 	}
    80 	}
    64 
    81 
       
    82 	/**
       
    83 	 * @param int|float $floatnum
       
    84 	 *
       
    85 	 * @return int|float
       
    86 	 */
    65 	public static function CastAsInt($floatnum) {
    87 	public static function CastAsInt($floatnum) {
    66 		// convert to float if not already
    88 		// convert to float if not already
    67 		$floatnum = (float) $floatnum;
    89 		$floatnum = (float) $floatnum;
    68 
    90 
    69 		// convert a float to type int, only if possible
    91 		// convert a float to type int, only if possible
    75 			}
    97 			}
    76 		}
    98 		}
    77 		return $floatnum;
    99 		return $floatnum;
    78 	}
   100 	}
    79 
   101 
       
   102 	/**
       
   103 	 * @param int $num
       
   104 	 *
       
   105 	 * @return bool
       
   106 	 */
    80 	public static function intValueSupported($num) {
   107 	public static function intValueSupported($num) {
    81 		// check if integers are 64-bit
   108 		// check if integers are 64-bit
    82 		static $hasINT64 = null;
   109 		static $hasINT64 = null;
    83 		if ($hasINT64 === null) { // 10x faster than is_null()
   110 		if ($hasINT64 === null) { // 10x faster than is_null()
    84 			$hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
   111 			$hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
    85 			if (!$hasINT64 && !defined('PHP_INT_MIN')) {
   112 			if (!$hasINT64 && !defined('PHP_INT_MIN')) {
    86 				define('PHP_INT_MIN', ~PHP_INT_MAX);
   113 				define('PHP_INT_MIN', ~PHP_INT_MAX);
    87 			}
   114 			}
    88 		}
   115 		}
    89 		// if integers are 64-bit - no other check required
   116 		// if integers are 64-bit - no other check required
    90 		if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
   117 		if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { // phpcs:ignore PHPCompatibility.Constants.NewConstants.php_int_minFound
    91 			return true;
   118 			return true;
    92 		}
   119 		}
    93 		return false;
   120 		return false;
    94 	}
   121 	}
    95 
   122 
       
   123 	/**
       
   124 	 * @param string $fraction
       
   125 	 *
       
   126 	 * @return float
       
   127 	 */
    96 	public static function DecimalizeFraction($fraction) {
   128 	public static function DecimalizeFraction($fraction) {
    97 		list($numerator, $denominator) = explode('/', $fraction);
   129 		list($numerator, $denominator) = explode('/', $fraction);
    98 		return $numerator / ($denominator ? $denominator : 1);
   130 		return $numerator / ($denominator ? $denominator : 1);
    99 	}
   131 	}
   100 
   132 
   101 
   133 	/**
       
   134 	 * @param string $binarynumerator
       
   135 	 *
       
   136 	 * @return float
       
   137 	 */
   102 	public static function DecimalBinary2Float($binarynumerator) {
   138 	public static function DecimalBinary2Float($binarynumerator) {
   103 		$numerator   = self::Bin2Dec($binarynumerator);
   139 		$numerator   = self::Bin2Dec($binarynumerator);
   104 		$denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
   140 		$denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
   105 		return ($numerator / $denominator);
   141 		return ($numerator / $denominator);
   106 	}
   142 	}
   107 
   143 
   108 
   144 	/**
       
   145 	 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
       
   146 	 *
       
   147 	 * @param string $binarypointnumber
       
   148 	 * @param int    $maxbits
       
   149 	 *
       
   150 	 * @return array
       
   151 	 */
   109 	public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
   152 	public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
   110 		// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
       
   111 		if (strpos($binarypointnumber, '.') === false) {
   153 		if (strpos($binarypointnumber, '.') === false) {
   112 			$binarypointnumber = '0.'.$binarypointnumber;
   154 			$binarypointnumber = '0.'.$binarypointnumber;
   113 		} elseif ($binarypointnumber{0} == '.') {
   155 		} elseif ($binarypointnumber[0] == '.') {
   114 			$binarypointnumber = '0'.$binarypointnumber;
   156 			$binarypointnumber = '0'.$binarypointnumber;
   115 		}
   157 		}
   116 		$exponent = 0;
   158 		$exponent = 0;
   117 		while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
   159 		while (($binarypointnumber[0] != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
   118 			if (substr($binarypointnumber, 1, 1) == '.') {
   160 			if (substr($binarypointnumber, 1, 1) == '.') {
   119 				$exponent--;
   161 				$exponent--;
   120 				$binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
   162 				$binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
   121 			} else {
   163 			} else {
   122 				$pointpos = strpos($binarypointnumber, '.');
   164 				$pointpos = strpos($binarypointnumber, '.');
   123 				$exponent += ($pointpos - 1);
   165 				$exponent += ($pointpos - 1);
   124 				$binarypointnumber = str_replace('.', '', $binarypointnumber);
   166 				$binarypointnumber = str_replace('.', '', $binarypointnumber);
   125 				$binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
   167 				$binarypointnumber = $binarypointnumber[0].'.'.substr($binarypointnumber, 1);
   126 			}
   168 			}
   127 		}
   169 		}
   128 		$binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
   170 		$binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
   129 		return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
   171 		return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
   130 	}
   172 	}
   131 
   173 
   132 
   174 	/**
       
   175 	 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
       
   176 	 *
       
   177 	 * @param float $floatvalue
       
   178 	 *
       
   179 	 * @return string
       
   180 	 */
   133 	public static function Float2BinaryDecimal($floatvalue) {
   181 	public static function Float2BinaryDecimal($floatvalue) {
   134 		// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
       
   135 		$maxbits = 128; // to how many bits of precision should the calculations be taken?
   182 		$maxbits = 128; // to how many bits of precision should the calculations be taken?
   136 		$intpart   = self::trunc($floatvalue);
   183 		$intpart   = self::trunc($floatvalue);
   137 		$floatpart = abs($floatvalue - $intpart);
   184 		$floatpart = abs($floatvalue - $intpart);
   138 		$pointbitstring = '';
   185 		$pointbitstring = '';
   139 		while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
   186 		while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
   143 		}
   190 		}
   144 		$binarypointnumber = decbin($intpart).'.'.$pointbitstring;
   191 		$binarypointnumber = decbin($intpart).'.'.$pointbitstring;
   145 		return $binarypointnumber;
   192 		return $binarypointnumber;
   146 	}
   193 	}
   147 
   194 
   148 
   195 	/**
       
   196 	 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
       
   197 	 *
       
   198 	 * @param float $floatvalue
       
   199 	 * @param int $bits
       
   200 	 *
       
   201 	 * @return string|false
       
   202 	 */
   149 	public static function Float2String($floatvalue, $bits) {
   203 	public static function Float2String($floatvalue, $bits) {
   150 		// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
   204 		$exponentbits = 0;
       
   205 		$fractionbits = 0;
   151 		switch ($bits) {
   206 		switch ($bits) {
   152 			case 32:
   207 			case 32:
   153 				$exponentbits = 8;
   208 				$exponentbits = 8;
   154 				$fractionbits = 23;
   209 				$fractionbits = 23;
   155 				break;
   210 				break;
   159 				$fractionbits = 52;
   214 				$fractionbits = 52;
   160 				break;
   215 				break;
   161 
   216 
   162 			default:
   217 			default:
   163 				return false;
   218 				return false;
   164 				break;
       
   165 		}
   219 		}
   166 		if ($floatvalue >= 0) {
   220 		if ($floatvalue >= 0) {
   167 			$signbit = '0';
   221 			$signbit = '0';
   168 		} else {
   222 		} else {
   169 			$signbit = '1';
   223 			$signbit = '1';
   174 		$fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
   228 		$fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
   175 
   229 
   176 		return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
   230 		return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
   177 	}
   231 	}
   178 
   232 
   179 
   233 	/**
       
   234 	 * @param string $byteword
       
   235 	 *
       
   236 	 * @return float|false
       
   237 	 */
   180 	public static function LittleEndian2Float($byteword) {
   238 	public static function LittleEndian2Float($byteword) {
   181 		return self::BigEndian2Float(strrev($byteword));
   239 		return self::BigEndian2Float(strrev($byteword));
   182 	}
   240 	}
   183 
   241 
   184 
   242 	/**
       
   243 	 * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
       
   244 	 *
       
   245 	 * @link http://www.psc.edu/general/software/packages/ieee/ieee.html
       
   246 	 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
       
   247 	 *
       
   248 	 * @param string $byteword
       
   249 	 *
       
   250 	 * @return float|false
       
   251 	 */
   185 	public static function BigEndian2Float($byteword) {
   252 	public static function BigEndian2Float($byteword) {
   186 		// ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
       
   187 		// http://www.psc.edu/general/software/packages/ieee/ieee.html
       
   188 		// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
       
   189 
       
   190 		$bitword = self::BigEndian2Bin($byteword);
   253 		$bitword = self::BigEndian2Bin($byteword);
   191 		if (!$bitword) {
   254 		if (!$bitword) {
   192 			return 0;
   255 			return 0;
   193 		}
   256 		}
   194 		$signbit = $bitword{0};
   257 		$signbit = $bitword[0];
       
   258 		$floatvalue = 0;
       
   259 		$exponentbits = 0;
       
   260 		$fractionbits = 0;
   195 
   261 
   196 		switch (strlen($byteword) * 8) {
   262 		switch (strlen($byteword) * 8) {
   197 			case 32:
   263 			case 32:
   198 				$exponentbits = 8;
   264 				$exponentbits = 8;
   199 				$fractionbits = 23;
   265 				$fractionbits = 23;
   206 
   272 
   207 			case 80:
   273 			case 80:
   208 				// 80-bit Apple SANE format
   274 				// 80-bit Apple SANE format
   209 				// http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
   275 				// http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
   210 				$exponentstring = substr($bitword, 1, 15);
   276 				$exponentstring = substr($bitword, 1, 15);
   211 				$isnormalized = intval($bitword{16});
   277 				$isnormalized = intval($bitword[16]);
   212 				$fractionstring = substr($bitword, 17, 63);
   278 				$fractionstring = substr($bitword, 17, 63);
   213 				$exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
   279 				$exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
   214 				$fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
   280 				$fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
   215 				$floatvalue = $exponent * $fraction;
   281 				$floatvalue = $exponent * $fraction;
   216 				if ($signbit == '1') {
   282 				if ($signbit == '1') {
   217 					$floatvalue *= -1;
   283 					$floatvalue *= -1;
   218 				}
   284 				}
   219 				return $floatvalue;
   285 				return $floatvalue;
   220 				break;
       
   221 
   286 
   222 			default:
   287 			default:
   223 				return false;
   288 				return false;
   224 				break;
       
   225 		}
   289 		}
   226 		$exponentstring = substr($bitword, 1, $exponentbits);
   290 		$exponentstring = substr($bitword, 1, $exponentbits);
   227 		$fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
   291 		$fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
   228 		$exponent = self::Bin2Dec($exponentstring);
   292 		$exponent = self::Bin2Dec($exponentstring);
   229 		$fraction = self::Bin2Dec($fractionstring);
   293 		$fraction = self::Bin2Dec($fractionstring);
   257 			}
   321 			}
   258 		}
   322 		}
   259 		return (float) $floatvalue;
   323 		return (float) $floatvalue;
   260 	}
   324 	}
   261 
   325 
   262 
   326 	/**
       
   327 	 * @param string $byteword
       
   328 	 * @param bool   $synchsafe
       
   329 	 * @param bool   $signed
       
   330 	 *
       
   331 	 * @return int|float|false
       
   332 	 * @throws Exception
       
   333 	 */
   263 	public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
   334 	public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
   264 		$intvalue = 0;
   335 		$intvalue = 0;
   265 		$bytewordlen = strlen($byteword);
   336 		$bytewordlen = strlen($byteword);
   266 		if ($bytewordlen == 0) {
   337 		if ($bytewordlen == 0) {
   267 			return false;
   338 			return false;
   268 		}
   339 		}
   269 		for ($i = 0; $i < $bytewordlen; $i++) {
   340 		for ($i = 0; $i < $bytewordlen; $i++) {
   270 			if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
   341 			if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
   271 				//$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
   342 				//$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
   272 				$intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
   343 				$intvalue += (ord($byteword[$i]) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
   273 			} else {
   344 			} else {
   274 				$intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
   345 				$intvalue += ord($byteword[$i]) * pow(256, ($bytewordlen - 1 - $i));
   275 			}
   346 			}
   276 		}
   347 		}
   277 		if ($signed && !$synchsafe) {
   348 		if ($signed && !$synchsafe) {
   278 			// synchsafe ints are not allowed to be signed
   349 			// synchsafe ints are not allowed to be signed
   279 			if ($bytewordlen <= PHP_INT_SIZE) {
   350 			if ($bytewordlen <= PHP_INT_SIZE) {
   286 			}
   357 			}
   287 		}
   358 		}
   288 		return self::CastAsInt($intvalue);
   359 		return self::CastAsInt($intvalue);
   289 	}
   360 	}
   290 
   361 
   291 
   362 	/**
       
   363 	 * @param string $byteword
       
   364 	 * @param bool   $signed
       
   365 	 *
       
   366 	 * @return int|float|false
       
   367 	 */
   292 	public static function LittleEndian2Int($byteword, $signed=false) {
   368 	public static function LittleEndian2Int($byteword, $signed=false) {
   293 		return self::BigEndian2Int(strrev($byteword), false, $signed);
   369 		return self::BigEndian2Int(strrev($byteword), false, $signed);
   294 	}
   370 	}
   295 
   371 
       
   372 	/**
       
   373 	 * @param string $byteword
       
   374 	 *
       
   375 	 * @return string
       
   376 	 */
   296 	public static function LittleEndian2Bin($byteword) {
   377 	public static function LittleEndian2Bin($byteword) {
   297 		return self::BigEndian2Bin(strrev($byteword));
   378 		return self::BigEndian2Bin(strrev($byteword));
   298 	}
   379 	}
   299 
   380 
       
   381 	/**
       
   382 	 * @param string $byteword
       
   383 	 *
       
   384 	 * @return string
       
   385 	 */
   300 	public static function BigEndian2Bin($byteword) {
   386 	public static function BigEndian2Bin($byteword) {
   301 		$binvalue = '';
   387 		$binvalue = '';
   302 		$bytewordlen = strlen($byteword);
   388 		$bytewordlen = strlen($byteword);
   303 		for ($i = 0; $i < $bytewordlen; $i++) {
   389 		for ($i = 0; $i < $bytewordlen; $i++) {
   304 			$binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
   390 			$binvalue .= str_pad(decbin(ord($byteword[$i])), 8, '0', STR_PAD_LEFT);
   305 		}
   391 		}
   306 		return $binvalue;
   392 		return $binvalue;
   307 	}
   393 	}
   308 
   394 
   309 
   395 	/**
       
   396 	 * @param int  $number
       
   397 	 * @param int  $minbytes
       
   398 	 * @param bool $synchsafe
       
   399 	 * @param bool $signed
       
   400 	 *
       
   401 	 * @return string
       
   402 	 * @throws Exception
       
   403 	 */
   310 	public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
   404 	public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
   311 		if ($number < 0) {
   405 		if ($number < 0) {
   312 			throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
   406 			throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
   313 		}
   407 		}
   314 		$maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
   408 		$maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
   325 			$number = floor($quotient);
   419 			$number = floor($quotient);
   326 		}
   420 		}
   327 		return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
   421 		return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
   328 	}
   422 	}
   329 
   423 
   330 
   424 	/**
       
   425 	 * @param int $number
       
   426 	 *
       
   427 	 * @return string
       
   428 	 */
   331 	public static function Dec2Bin($number) {
   429 	public static function Dec2Bin($number) {
   332 		while ($number >= 256) {
   430 		while ($number >= 256) {
   333 			$bytes[] = (($number / 256) - (floor($number / 256))) * 256;
   431 			$bytes[] = (($number / 256) - (floor($number / 256))) * 256;
   334 			$number = floor($number / 256);
   432 			$number = floor($number / 256);
   335 		}
   433 		}
   339 			$binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
   437 			$binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
   340 		}
   438 		}
   341 		return $binstring;
   439 		return $binstring;
   342 	}
   440 	}
   343 
   441 
   344 
   442 	/**
       
   443 	 * @param string $binstring
       
   444 	 * @param bool   $signed
       
   445 	 *
       
   446 	 * @return int|float
       
   447 	 */
   345 	public static function Bin2Dec($binstring, $signed=false) {
   448 	public static function Bin2Dec($binstring, $signed=false) {
   346 		$signmult = 1;
   449 		$signmult = 1;
   347 		if ($signed) {
   450 		if ($signed) {
   348 			if ($binstring{0} == '1') {
   451 			if ($binstring[0] == '1') {
   349 				$signmult = -1;
   452 				$signmult = -1;
   350 			}
   453 			}
   351 			$binstring = substr($binstring, 1);
   454 			$binstring = substr($binstring, 1);
   352 		}
   455 		}
   353 		$decvalue = 0;
   456 		$decvalue = 0;
   355 			$decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
   458 			$decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
   356 		}
   459 		}
   357 		return self::CastAsInt($decvalue * $signmult);
   460 		return self::CastAsInt($decvalue * $signmult);
   358 	}
   461 	}
   359 
   462 
   360 
   463 	/**
       
   464 	 * @param string $binstring
       
   465 	 *
       
   466 	 * @return string
       
   467 	 */
   361 	public static function Bin2String($binstring) {
   468 	public static function Bin2String($binstring) {
   362 		// return 'hi' for input of '0110100001101001'
   469 		// return 'hi' for input of '0110100001101001'
   363 		$string = '';
   470 		$string = '';
   364 		$binstringreversed = strrev($binstring);
   471 		$binstringreversed = strrev($binstring);
   365 		for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
   472 		for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
   366 			$string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
   473 			$string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
   367 		}
   474 		}
   368 		return $string;
   475 		return $string;
   369 	}
   476 	}
   370 
   477 
   371 
   478 	/**
       
   479 	 * @param int  $number
       
   480 	 * @param int  $minbytes
       
   481 	 * @param bool $synchsafe
       
   482 	 *
       
   483 	 * @return string
       
   484 	 */
   372 	public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
   485 	public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
   373 		$intstring = '';
   486 		$intstring = '';
   374 		while ($number > 0) {
   487 		while ($number > 0) {
   375 			if ($synchsafe) {
   488 			if ($synchsafe) {
   376 				$intstring = $intstring.chr($number & 127);
   489 				$intstring = $intstring.chr($number & 127);
   381 			}
   494 			}
   382 		}
   495 		}
   383 		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
   496 		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
   384 	}
   497 	}
   385 
   498 
   386 
   499 	/**
       
   500 	 * @param mixed $array1
       
   501 	 * @param mixed $array2
       
   502 	 *
       
   503 	 * @return array|false
       
   504 	 */
   387 	public static function array_merge_clobber($array1, $array2) {
   505 	public static function array_merge_clobber($array1, $array2) {
   388 		// written by kcØhireability*com
   506 		// written by kcØhireability*com
   389 		// taken from http://www.php.net/manual/en/function.array-merge-recursive.php
   507 		// taken from http://www.php.net/manual/en/function.array-merge-recursive.php
   390 		if (!is_array($array1) || !is_array($array2)) {
   508 		if (!is_array($array1) || !is_array($array2)) {
   391 			return false;
   509 			return false;
   399 			}
   517 			}
   400 		}
   518 		}
   401 		return $newarray;
   519 		return $newarray;
   402 	}
   520 	}
   403 
   521 
   404 
   522 	/**
       
   523 	 * @param mixed $array1
       
   524 	 * @param mixed $array2
       
   525 	 *
       
   526 	 * @return array|false
       
   527 	 */
   405 	public static function array_merge_noclobber($array1, $array2) {
   528 	public static function array_merge_noclobber($array1, $array2) {
   406 		if (!is_array($array1) || !is_array($array2)) {
   529 		if (!is_array($array1) || !is_array($array2)) {
   407 			return false;
   530 			return false;
   408 		}
   531 		}
   409 		$newarray = $array1;
   532 		$newarray = $array1;
   415 			}
   538 			}
   416 		}
   539 		}
   417 		return $newarray;
   540 		return $newarray;
   418 	}
   541 	}
   419 
   542 
       
   543 	/**
       
   544 	 * @param mixed $array1
       
   545 	 * @param mixed $array2
       
   546 	 *
       
   547 	 * @return array|false|null
       
   548 	 */
   420 	public static function flipped_array_merge_noclobber($array1, $array2) {
   549 	public static function flipped_array_merge_noclobber($array1, $array2) {
   421 		if (!is_array($array1) || !is_array($array2)) {
   550 		if (!is_array($array1) || !is_array($array2)) {
   422 			return false;
   551 			return false;
   423 		}
   552 		}
   424 		# naturally, this only works non-recursively
   553 		# naturally, this only works non-recursively
   429 			}
   558 			}
   430 		}
   559 		}
   431 		return array_flip($newarray);
   560 		return array_flip($newarray);
   432 	}
   561 	}
   433 
   562 
   434 
   563 	/**
       
   564 	 * @param array $theArray
       
   565 	 *
       
   566 	 * @return bool
       
   567 	 */
   435 	public static function ksort_recursive(&$theArray) {
   568 	public static function ksort_recursive(&$theArray) {
   436 		ksort($theArray);
   569 		ksort($theArray);
   437 		foreach ($theArray as $key => $value) {
   570 		foreach ($theArray as $key => $value) {
   438 			if (is_array($value)) {
   571 			if (is_array($value)) {
   439 				self::ksort_recursive($theArray[$key]);
   572 				self::ksort_recursive($theArray[$key]);
   440 			}
   573 			}
   441 		}
   574 		}
   442 		return true;
   575 		return true;
   443 	}
   576 	}
   444 
   577 
       
   578 	/**
       
   579 	 * @param string $filename
       
   580 	 * @param int    $numextensions
       
   581 	 *
       
   582 	 * @return string
       
   583 	 */
   445 	public static function fileextension($filename, $numextensions=1) {
   584 	public static function fileextension($filename, $numextensions=1) {
   446 		if (strstr($filename, '.')) {
   585 		if (strstr($filename, '.')) {
   447 			$reversedfilename = strrev($filename);
   586 			$reversedfilename = strrev($filename);
   448 			$offset = 0;
   587 			$offset = 0;
   449 			for ($i = 0; $i < $numextensions; $i++) {
   588 			for ($i = 0; $i < $numextensions; $i++) {
   455 			return strrev(substr($reversedfilename, 0, $offset));
   594 			return strrev(substr($reversedfilename, 0, $offset));
   456 		}
   595 		}
   457 		return '';
   596 		return '';
   458 	}
   597 	}
   459 
   598 
   460 
   599 	/**
       
   600 	 * @param int $seconds
       
   601 	 *
       
   602 	 * @return string
       
   603 	 */
   461 	public static function PlaytimeString($seconds) {
   604 	public static function PlaytimeString($seconds) {
   462 		$sign = (($seconds < 0) ? '-' : '');
   605 		$sign = (($seconds < 0) ? '-' : '');
   463 		$seconds = round(abs($seconds));
   606 		$seconds = round(abs($seconds));
   464 		$H = (int) floor( $seconds                            / 3600);
   607 		$H = (int) floor( $seconds                            / 3600);
   465 		$M = (int) floor(($seconds - (3600 * $H)            ) /   60);
   608 		$M = (int) floor(($seconds - (3600 * $H)            ) /   60);
   466 		$S = (int) round( $seconds - (3600 * $H) - (60 * $M)        );
   609 		$S = (int) round( $seconds - (3600 * $H) - (60 * $M)        );
   467 		return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
   610 		return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
   468 	}
   611 	}
   469 
   612 
   470 
   613 	/**
       
   614 	 * @param int $macdate
       
   615 	 *
       
   616 	 * @return int|float
       
   617 	 */
   471 	public static function DateMac2Unix($macdate) {
   618 	public static function DateMac2Unix($macdate) {
   472 		// Macintosh timestamp: seconds since 00:00h January 1, 1904
   619 		// Macintosh timestamp: seconds since 00:00h January 1, 1904
   473 		// UNIX timestamp:      seconds since 00:00h January 1, 1970
   620 		// UNIX timestamp:      seconds since 00:00h January 1, 1970
   474 		return self::CastAsInt($macdate - 2082844800);
   621 		return self::CastAsInt($macdate - 2082844800);
   475 	}
   622 	}
   476 
   623 
   477 
   624 	/**
       
   625 	 * @param string $rawdata
       
   626 	 *
       
   627 	 * @return float
       
   628 	 */
   478 	public static function FixedPoint8_8($rawdata) {
   629 	public static function FixedPoint8_8($rawdata) {
   479 		return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
   630 		return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
   480 	}
   631 	}
   481 
   632 
   482 
   633 	/**
       
   634 	 * @param string $rawdata
       
   635 	 *
       
   636 	 * @return float
       
   637 	 */
   483 	public static function FixedPoint16_16($rawdata) {
   638 	public static function FixedPoint16_16($rawdata) {
   484 		return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
   639 		return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
   485 	}
   640 	}
   486 
   641 
   487 
   642 	/**
       
   643 	 * @param string $rawdata
       
   644 	 *
       
   645 	 * @return float
       
   646 	 */
   488 	public static function FixedPoint2_30($rawdata) {
   647 	public static function FixedPoint2_30($rawdata) {
   489 		$binarystring = self::BigEndian2Bin($rawdata);
   648 		$binarystring = self::BigEndian2Bin($rawdata);
   490 		return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
   649 		return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
   491 	}
   650 	}
   492 
   651 
   493 
   652 
       
   653 	/**
       
   654 	 * @param string $ArrayPath
       
   655 	 * @param string $Separator
       
   656 	 * @param mixed $Value
       
   657 	 *
       
   658 	 * @return array
       
   659 	 */
   494 	public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
   660 	public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
   495 		// assigns $Value to a nested array path:
   661 		// assigns $Value to a nested array path:
   496 		//   $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
   662 		//   $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
   497 		// is the same as:
   663 		// is the same as:
   498 		//   $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
   664 		//   $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
   505 			$ReturnedArray[$ArrayPath] = $Value;
   671 			$ReturnedArray[$ArrayPath] = $Value;
   506 		}
   672 		}
   507 		return $ReturnedArray;
   673 		return $ReturnedArray;
   508 	}
   674 	}
   509 
   675 
       
   676 	/**
       
   677 	 * @param array $arraydata
       
   678 	 * @param bool  $returnkey
       
   679 	 *
       
   680 	 * @return int|false
       
   681 	 */
   510 	public static function array_max($arraydata, $returnkey=false) {
   682 	public static function array_max($arraydata, $returnkey=false) {
   511 		$maxvalue = false;
   683 		$maxvalue = false;
   512 		$maxkey = false;
   684 		$maxkey   = false;
   513 		foreach ($arraydata as $key => $value) {
   685 		foreach ($arraydata as $key => $value) {
   514 			if (!is_array($value)) {
   686 			if (!is_array($value)) {
   515 				if ($value > $maxvalue) {
   687 				if (($maxvalue === false) || ($value > $maxvalue)) {
   516 					$maxvalue = $value;
   688 					$maxvalue = $value;
   517 					$maxkey = $key;
   689 					$maxkey = $key;
   518 				}
   690 				}
   519 			}
   691 			}
   520 		}
   692 		}
   521 		return ($returnkey ? $maxkey : $maxvalue);
   693 		return ($returnkey ? $maxkey : $maxvalue);
   522 	}
   694 	}
   523 
   695 
       
   696 	/**
       
   697 	 * @param array $arraydata
       
   698 	 * @param bool  $returnkey
       
   699 	 *
       
   700 	 * @return int|false
       
   701 	 */
   524 	public static function array_min($arraydata, $returnkey=false) {
   702 	public static function array_min($arraydata, $returnkey=false) {
   525 		$minvalue = false;
   703 		$minvalue = false;
   526 		$minkey = false;
   704 		$minkey   = false;
   527 		foreach ($arraydata as $key => $value) {
   705 		foreach ($arraydata as $key => $value) {
   528 			if (!is_array($value)) {
   706 			if (!is_array($value)) {
   529 				if ($value > $minvalue) {
   707 				if (($minvalue === false) || ($value < $minvalue)) {
   530 					$minvalue = $value;
   708 					$minvalue = $value;
   531 					$minkey = $key;
   709 					$minkey = $key;
   532 				}
   710 				}
   533 			}
   711 			}
   534 		}
   712 		}
   535 		return ($returnkey ? $minkey : $minvalue);
   713 		return ($returnkey ? $minkey : $minvalue);
   536 	}
   714 	}
   537 
   715 
       
   716 	/**
       
   717 	 * @param string $XMLstring
       
   718 	 *
       
   719 	 * @return array|false
       
   720 	 */
   538 	public static function XML2array($XMLstring) {
   721 	public static function XML2array($XMLstring) {
   539 		if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
   722 		if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
   540 			// http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
   723 			// http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
   541 			// https://core.trac.wordpress.org/changeset/29378
   724 			// https://core.trac.wordpress.org/changeset/29378
   542 			$loader = libxml_disable_entity_loader(true);
   725 			$loader = libxml_disable_entity_loader(true);
   546 			return $return;
   729 			return $return;
   547 		}
   730 		}
   548 		return false;
   731 		return false;
   549 	}
   732 	}
   550 
   733 
       
   734 	/**
       
   735 	* @param SimpleXMLElement|array|mixed $XMLobject
       
   736 	*
       
   737 	* @return mixed
       
   738 	*/
   551 	public static function SimpleXMLelement2array($XMLobject) {
   739 	public static function SimpleXMLelement2array($XMLobject) {
   552 		if (!is_object($XMLobject) && !is_array($XMLobject)) {
   740 		if (!is_object($XMLobject) && !is_array($XMLobject)) {
   553 			return $XMLobject;
   741 			return $XMLobject;
   554 		}
   742 		}
   555 		$XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
   743 		$XMLarray = $XMLobject instanceof SimpleXMLElement ? get_object_vars($XMLobject) : $XMLobject;
   556 		foreach ($XMLarray as $key => $value) {
   744 		foreach ($XMLarray as $key => $value) {
   557 			$XMLarray[$key] = self::SimpleXMLelement2array($value);
   745 			$XMLarray[$key] = self::SimpleXMLelement2array($value);
   558 		}
   746 		}
   559 		return $XMLarray;
   747 		return $XMLarray;
   560 	}
   748 	}
   561 
   749 
   562 
   750 	/**
   563 	// Allan Hansen <ahØartemis*dk>
   751 	 * Returns checksum for a file from starting position to absolute end position.
   564 	// self::md5_data() - returns md5sum for a file from startuing position to absolute end position
   752 	 *
       
   753 	 * @param string $file
       
   754 	 * @param int    $offset
       
   755 	 * @param int    $end
       
   756 	 * @param string $algorithm
       
   757 	 *
       
   758 	 * @return string|false
       
   759 	 * @throws getid3_exception
       
   760 	 */
   565 	public static function hash_data($file, $offset, $end, $algorithm) {
   761 	public static function hash_data($file, $offset, $end, $algorithm) {
   566 		static $tempdir = '';
       
   567 		if (!self::intValueSupported($end)) {
   762 		if (!self::intValueSupported($end)) {
   568 			return false;
   763 			return false;
   569 		}
   764 		}
   570 		switch ($algorithm) {
   765 		if (!in_array($algorithm, array('md5', 'sha1'))) {
   571 			case 'md5':
   766 			throw new getid3_exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
   572 				$hash_function = 'md5_file';
   767 		}
   573 				$unix_call     = 'md5sum';
   768 
   574 				$windows_call  = 'md5sum.exe';
       
   575 				$hash_length   = 32;
       
   576 				break;
       
   577 
       
   578 			case 'sha1':
       
   579 				$hash_function = 'sha1_file';
       
   580 				$unix_call     = 'sha1sum';
       
   581 				$windows_call  = 'sha1sum.exe';
       
   582 				$hash_length   = 40;
       
   583 				break;
       
   584 
       
   585 			default:
       
   586 				throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
       
   587 				break;
       
   588 		}
       
   589 		$size = $end - $offset;
   769 		$size = $end - $offset;
   590 		while (true) {
   770 
   591 			if (GETID3_OS_ISWINDOWS) {
   771 		$fp = fopen($file, 'rb');
   592 
   772 		fseek($fp, $offset);
   593 				// It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
   773 		$ctx = hash_init($algorithm);
   594 				// Fall back to create-temp-file method:
   774 		while ($size > 0) {
   595 				if ($algorithm == 'sha1') {
   775 			$buffer = fread($fp, min($size, getID3::FREAD_BUFFER_SIZE));
   596 					break;
   776 			hash_update($ctx, $buffer);
   597 				}
   777 			$size -= getID3::FREAD_BUFFER_SIZE;
   598 
   778 		}
   599 				$RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
   779 		$hash = hash_final($ctx);
   600 				foreach ($RequiredFiles as $required_file) {
   780 		fclose($fp);
   601 					if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
   781 
   602 						// helper apps not available - fall back to old method
   782 		return $hash;
   603 						break 2;
   783 	}
   604 					}
   784 
   605 				}
   785 	/**
   606 				$commandline  = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
   786 	 * @param string $filename_source
   607 				$commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
   787 	 * @param string $filename_dest
   608 				$commandline .= GETID3_HELPERAPPSDIR.$windows_call;
   788 	 * @param int    $offset
   609 
   789 	 * @param int    $length
   610 			} else {
   790 	 *
   611 
   791 	 * @return bool
   612 				$commandline  = 'head -c'.$end.' '.escapeshellarg($file).' | ';
   792 	 * @throws Exception
   613 				$commandline .= 'tail -c'.$size.' | ';
   793 	 *
   614 				$commandline .= $unix_call;
   794 	 * @deprecated Unused, may be removed in future versions of getID3
   615 
   795 	 */
   616 			}
       
   617 			if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
       
   618 				//throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
       
   619 				break;
       
   620 			}
       
   621 			return substr(`$commandline`, 0, $hash_length);
       
   622 		}
       
   623 
       
   624 		if (empty($tempdir)) {
       
   625 			// yes this is ugly, feel free to suggest a better way
       
   626 			require_once(dirname(__FILE__).'/getid3.php');
       
   627 			$getid3_temp = new getID3();
       
   628 			$tempdir = $getid3_temp->tempdir;
       
   629 			unset($getid3_temp);
       
   630 		}
       
   631 		// try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
       
   632 		if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
       
   633 			// can't find anywhere to create a temp file, just fail
       
   634 			return false;
       
   635 		}
       
   636 
       
   637 		// Init
       
   638 		$result = false;
       
   639 
       
   640 		// copy parts of file
       
   641 		try {
       
   642 			self::CopyFileParts($file, $data_filename, $offset, $end - $offset);
       
   643 			$result = $hash_function($data_filename);
       
   644 		} catch (Exception $e) {
       
   645 			throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
       
   646 		}
       
   647 		unlink($data_filename);
       
   648 		return $result;
       
   649 	}
       
   650 
       
   651 	public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
   796 	public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
   652 		if (!self::intValueSupported($offset + $length)) {
   797 		if (!self::intValueSupported($offset + $length)) {
   653 			throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
   798 			throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
   654 		}
   799 		}
   655 		if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
   800 		if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
   658 					$byteslefttowrite = $length;
   803 					$byteslefttowrite = $length;
   659 					while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
   804 					while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
   660 						$byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
   805 						$byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
   661 						$byteslefttowrite -= $byteswritten;
   806 						$byteslefttowrite -= $byteswritten;
   662 					}
   807 					}
       
   808 					fclose($fp_dest);
   663 					return true;
   809 					return true;
   664 				} else {
   810 				} else {
       
   811 					fclose($fp_src);
   665 					throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
   812 					throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
   666 				}
   813 				}
   667 				fclose($fp_dest);
       
   668 			} else {
   814 			} else {
   669 				throw new Exception('failed to create file for writing '.$filename_dest);
   815 				throw new Exception('failed to create file for writing '.$filename_dest);
   670 			}
   816 			}
   671 			fclose($fp_src);
       
   672 		} else {
   817 		} else {
   673 			throw new Exception('failed to open file for reading '.$filename_source);
   818 			throw new Exception('failed to open file for reading '.$filename_source);
   674 		}
   819 		}
   675 		return false;
   820 	}
   676 	}
   821 
   677 
   822 	/**
       
   823 	 * @param int $charval
       
   824 	 *
       
   825 	 * @return string
       
   826 	 */
   678 	public static function iconv_fallback_int_utf8($charval) {
   827 	public static function iconv_fallback_int_utf8($charval) {
   679 		if ($charval < 128) {
   828 		if ($charval < 128) {
   680 			// 0bbbbbbb
   829 			// 0bbbbbbb
   681 			$newcharstring = chr($charval);
   830 			$newcharstring = chr($charval);
   682 		} elseif ($charval < 2048) {
   831 		} elseif ($charval < 2048) {
   696 			$newcharstring .= chr(($charval & 0x3F) | 0x80);
   845 			$newcharstring .= chr(($charval & 0x3F) | 0x80);
   697 		}
   846 		}
   698 		return $newcharstring;
   847 		return $newcharstring;
   699 	}
   848 	}
   700 
   849 
   701 	// ISO-8859-1 => UTF-8
   850 	/**
       
   851 	 * ISO-8859-1 => UTF-8
       
   852 	 *
       
   853 	 * @param string $string
       
   854 	 * @param bool   $bom
       
   855 	 *
       
   856 	 * @return string
       
   857 	 */
   702 	public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
   858 	public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
   703 		if (function_exists('utf8_encode')) {
   859 		if (function_exists('utf8_encode')) {
   704 			return utf8_encode($string);
   860 			return utf8_encode($string);
   705 		}
   861 		}
   706 		// utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
   862 		// utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
   707 		$newcharstring = '';
   863 		$newcharstring = '';
   708 		if ($bom) {
   864 		if ($bom) {
   709 			$newcharstring .= "\xEF\xBB\xBF";
   865 			$newcharstring .= "\xEF\xBB\xBF";
   710 		}
   866 		}
   711 		for ($i = 0; $i < strlen($string); $i++) {
   867 		for ($i = 0; $i < strlen($string); $i++) {
   712 			$charval = ord($string{$i});
   868 			$charval = ord($string[$i]);
   713 			$newcharstring .= self::iconv_fallback_int_utf8($charval);
   869 			$newcharstring .= self::iconv_fallback_int_utf8($charval);
   714 		}
   870 		}
   715 		return $newcharstring;
   871 		return $newcharstring;
   716 	}
   872 	}
   717 
   873 
   718 	// ISO-8859-1 => UTF-16BE
   874 	/**
       
   875 	 * ISO-8859-1 => UTF-16BE
       
   876 	 *
       
   877 	 * @param string $string
       
   878 	 * @param bool   $bom
       
   879 	 *
       
   880 	 * @return string
       
   881 	 */
   719 	public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
   882 	public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
   720 		$newcharstring = '';
   883 		$newcharstring = '';
   721 		if ($bom) {
   884 		if ($bom) {
   722 			$newcharstring .= "\xFE\xFF";
   885 			$newcharstring .= "\xFE\xFF";
   723 		}
   886 		}
   724 		for ($i = 0; $i < strlen($string); $i++) {
   887 		for ($i = 0; $i < strlen($string); $i++) {
   725 			$newcharstring .= "\x00".$string{$i};
   888 			$newcharstring .= "\x00".$string[$i];
   726 		}
   889 		}
   727 		return $newcharstring;
   890 		return $newcharstring;
   728 	}
   891 	}
   729 
   892 
   730 	// ISO-8859-1 => UTF-16LE
   893 	/**
       
   894 	 * ISO-8859-1 => UTF-16LE
       
   895 	 *
       
   896 	 * @param string $string
       
   897 	 * @param bool   $bom
       
   898 	 *
       
   899 	 * @return string
       
   900 	 */
   731 	public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
   901 	public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
   732 		$newcharstring = '';
   902 		$newcharstring = '';
   733 		if ($bom) {
   903 		if ($bom) {
   734 			$newcharstring .= "\xFF\xFE";
   904 			$newcharstring .= "\xFF\xFE";
   735 		}
   905 		}
   736 		for ($i = 0; $i < strlen($string); $i++) {
   906 		for ($i = 0; $i < strlen($string); $i++) {
   737 			$newcharstring .= $string{$i}."\x00";
   907 			$newcharstring .= $string[$i]."\x00";
   738 		}
   908 		}
   739 		return $newcharstring;
   909 		return $newcharstring;
   740 	}
   910 	}
   741 
   911 
   742 	// ISO-8859-1 => UTF-16LE (BOM)
   912 	/**
       
   913 	 * ISO-8859-1 => UTF-16LE (BOM)
       
   914 	 *
       
   915 	 * @param string $string
       
   916 	 *
       
   917 	 * @return string
       
   918 	 */
   743 	public static function iconv_fallback_iso88591_utf16($string) {
   919 	public static function iconv_fallback_iso88591_utf16($string) {
   744 		return self::iconv_fallback_iso88591_utf16le($string, true);
   920 		return self::iconv_fallback_iso88591_utf16le($string, true);
   745 	}
   921 	}
   746 
   922 
   747 	// UTF-8 => ISO-8859-1
   923 	/**
       
   924 	 * UTF-8 => ISO-8859-1
       
   925 	 *
       
   926 	 * @param string $string
       
   927 	 *
       
   928 	 * @return string
       
   929 	 */
   748 	public static function iconv_fallback_utf8_iso88591($string) {
   930 	public static function iconv_fallback_utf8_iso88591($string) {
   749 		if (function_exists('utf8_decode')) {
   931 		if (function_exists('utf8_decode')) {
   750 			return utf8_decode($string);
   932 			return utf8_decode($string);
   751 		}
   933 		}
   752 		// utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
   934 		// utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
   753 		$newcharstring = '';
   935 		$newcharstring = '';
   754 		$offset = 0;
   936 		$offset = 0;
   755 		$stringlength = strlen($string);
   937 		$stringlength = strlen($string);
   756 		while ($offset < $stringlength) {
   938 		while ($offset < $stringlength) {
   757 			if ((ord($string{$offset}) | 0x07) == 0xF7) {
   939 			if ((ord($string[$offset]) | 0x07) == 0xF7) {
   758 				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
   940 				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
   759 				$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
   941 				$charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
   760 						   ((ord($string{($offset + 1)}) & 0x3F) << 12) &
   942 						   ((ord($string[($offset + 1)]) & 0x3F) << 12) &
   761 						   ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
   943 						   ((ord($string[($offset + 2)]) & 0x3F) <<  6) &
   762 							(ord($string{($offset + 3)}) & 0x3F);
   944 							(ord($string[($offset + 3)]) & 0x3F);
   763 				$offset += 4;
   945 				$offset += 4;
   764 			} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
   946 			} elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
   765 				// 1110bbbb 10bbbbbb 10bbbbbb
   947 				// 1110bbbb 10bbbbbb 10bbbbbb
   766 				$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
   948 				$charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
   767 						   ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
   949 						   ((ord($string[($offset + 1)]) & 0x3F) <<  6) &
   768 							(ord($string{($offset + 2)}) & 0x3F);
   950 							(ord($string[($offset + 2)]) & 0x3F);
   769 				$offset += 3;
   951 				$offset += 3;
   770 			} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
   952 			} elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
   771 				// 110bbbbb 10bbbbbb
   953 				// 110bbbbb 10bbbbbb
   772 				$charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
   954 				$charval = ((ord($string[($offset + 0)]) & 0x1F) <<  6) &
   773 							(ord($string{($offset + 1)}) & 0x3F);
   955 							(ord($string[($offset + 1)]) & 0x3F);
   774 				$offset += 2;
   956 				$offset += 2;
   775 			} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
   957 			} elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
   776 				// 0bbbbbbb
   958 				// 0bbbbbbb
   777 				$charval = ord($string{$offset});
   959 				$charval = ord($string[$offset]);
   778 				$offset += 1;
   960 				$offset += 1;
   779 			} else {
   961 			} else {
   780 				// error? throw some kind of warning here?
   962 				// error? throw some kind of warning here?
   781 				$charval = false;
   963 				$charval = false;
   782 				$offset += 1;
   964 				$offset += 1;
   786 			}
   968 			}
   787 		}
   969 		}
   788 		return $newcharstring;
   970 		return $newcharstring;
   789 	}
   971 	}
   790 
   972 
   791 	// UTF-8 => UTF-16BE
   973 	/**
       
   974 	 * UTF-8 => UTF-16BE
       
   975 	 *
       
   976 	 * @param string $string
       
   977 	 * @param bool   $bom
       
   978 	 *
       
   979 	 * @return string
       
   980 	 */
   792 	public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
   981 	public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
   793 		$newcharstring = '';
   982 		$newcharstring = '';
   794 		if ($bom) {
   983 		if ($bom) {
   795 			$newcharstring .= "\xFE\xFF";
   984 			$newcharstring .= "\xFE\xFF";
   796 		}
   985 		}
   797 		$offset = 0;
   986 		$offset = 0;
   798 		$stringlength = strlen($string);
   987 		$stringlength = strlen($string);
   799 		while ($offset < $stringlength) {
   988 		while ($offset < $stringlength) {
   800 			if ((ord($string{$offset}) | 0x07) == 0xF7) {
   989 			if ((ord($string[$offset]) | 0x07) == 0xF7) {
   801 				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
   990 				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
   802 				$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
   991 				$charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
   803 						   ((ord($string{($offset + 1)}) & 0x3F) << 12) &
   992 						   ((ord($string[($offset + 1)]) & 0x3F) << 12) &
   804 						   ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
   993 						   ((ord($string[($offset + 2)]) & 0x3F) <<  6) &
   805 							(ord($string{($offset + 3)}) & 0x3F);
   994 							(ord($string[($offset + 3)]) & 0x3F);
   806 				$offset += 4;
   995 				$offset += 4;
   807 			} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
   996 			} elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
   808 				// 1110bbbb 10bbbbbb 10bbbbbb
   997 				// 1110bbbb 10bbbbbb 10bbbbbb
   809 				$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
   998 				$charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
   810 						   ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
   999 						   ((ord($string[($offset + 1)]) & 0x3F) <<  6) &
   811 							(ord($string{($offset + 2)}) & 0x3F);
  1000 							(ord($string[($offset + 2)]) & 0x3F);
   812 				$offset += 3;
  1001 				$offset += 3;
   813 			} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
  1002 			} elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
   814 				// 110bbbbb 10bbbbbb
  1003 				// 110bbbbb 10bbbbbb
   815 				$charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
  1004 				$charval = ((ord($string[($offset + 0)]) & 0x1F) <<  6) &
   816 							(ord($string{($offset + 1)}) & 0x3F);
  1005 							(ord($string[($offset + 1)]) & 0x3F);
   817 				$offset += 2;
  1006 				$offset += 2;
   818 			} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
  1007 			} elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
   819 				// 0bbbbbbb
  1008 				// 0bbbbbbb
   820 				$charval = ord($string{$offset});
  1009 				$charval = ord($string[$offset]);
   821 				$offset += 1;
  1010 				$offset += 1;
   822 			} else {
  1011 			} else {
   823 				// error? throw some kind of warning here?
  1012 				// error? throw some kind of warning here?
   824 				$charval = false;
  1013 				$charval = false;
   825 				$offset += 1;
  1014 				$offset += 1;
   829 			}
  1018 			}
   830 		}
  1019 		}
   831 		return $newcharstring;
  1020 		return $newcharstring;
   832 	}
  1021 	}
   833 
  1022 
   834 	// UTF-8 => UTF-16LE
  1023 	/**
       
  1024 	 * UTF-8 => UTF-16LE
       
  1025 	 *
       
  1026 	 * @param string $string
       
  1027 	 * @param bool   $bom
       
  1028 	 *
       
  1029 	 * @return string
       
  1030 	 */
   835 	public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
  1031 	public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
   836 		$newcharstring = '';
  1032 		$newcharstring = '';
   837 		if ($bom) {
  1033 		if ($bom) {
   838 			$newcharstring .= "\xFF\xFE";
  1034 			$newcharstring .= "\xFF\xFE";
   839 		}
  1035 		}
   840 		$offset = 0;
  1036 		$offset = 0;
   841 		$stringlength = strlen($string);
  1037 		$stringlength = strlen($string);
   842 		while ($offset < $stringlength) {
  1038 		while ($offset < $stringlength) {
   843 			if ((ord($string{$offset}) | 0x07) == 0xF7) {
  1039 			if ((ord($string[$offset]) | 0x07) == 0xF7) {
   844 				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
  1040 				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
   845 				$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
  1041 				$charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
   846 						   ((ord($string{($offset + 1)}) & 0x3F) << 12) &
  1042 						   ((ord($string[($offset + 1)]) & 0x3F) << 12) &
   847 						   ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
  1043 						   ((ord($string[($offset + 2)]) & 0x3F) <<  6) &
   848 							(ord($string{($offset + 3)}) & 0x3F);
  1044 							(ord($string[($offset + 3)]) & 0x3F);
   849 				$offset += 4;
  1045 				$offset += 4;
   850 			} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
  1046 			} elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
   851 				// 1110bbbb 10bbbbbb 10bbbbbb
  1047 				// 1110bbbb 10bbbbbb 10bbbbbb
   852 				$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
  1048 				$charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
   853 						   ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
  1049 						   ((ord($string[($offset + 1)]) & 0x3F) <<  6) &
   854 							(ord($string{($offset + 2)}) & 0x3F);
  1050 							(ord($string[($offset + 2)]) & 0x3F);
   855 				$offset += 3;
  1051 				$offset += 3;
   856 			} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
  1052 			} elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
   857 				// 110bbbbb 10bbbbbb
  1053 				// 110bbbbb 10bbbbbb
   858 				$charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
  1054 				$charval = ((ord($string[($offset + 0)]) & 0x1F) <<  6) &
   859 							(ord($string{($offset + 1)}) & 0x3F);
  1055 							(ord($string[($offset + 1)]) & 0x3F);
   860 				$offset += 2;
  1056 				$offset += 2;
   861 			} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
  1057 			} elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
   862 				// 0bbbbbbb
  1058 				// 0bbbbbbb
   863 				$charval = ord($string{$offset});
  1059 				$charval = ord($string[$offset]);
   864 				$offset += 1;
  1060 				$offset += 1;
   865 			} else {
  1061 			} else {
   866 				// error? maybe throw some warning here?
  1062 				// error? maybe throw some warning here?
   867 				$charval = false;
  1063 				$charval = false;
   868 				$offset += 1;
  1064 				$offset += 1;
   872 			}
  1068 			}
   873 		}
  1069 		}
   874 		return $newcharstring;
  1070 		return $newcharstring;
   875 	}
  1071 	}
   876 
  1072 
   877 	// UTF-8 => UTF-16LE (BOM)
  1073 	/**
       
  1074 	 * UTF-8 => UTF-16LE (BOM)
       
  1075 	 *
       
  1076 	 * @param string $string
       
  1077 	 *
       
  1078 	 * @return string
       
  1079 	 */
   878 	public static function iconv_fallback_utf8_utf16($string) {
  1080 	public static function iconv_fallback_utf8_utf16($string) {
   879 		return self::iconv_fallback_utf8_utf16le($string, true);
  1081 		return self::iconv_fallback_utf8_utf16le($string, true);
   880 	}
  1082 	}
   881 
  1083 
   882 	// UTF-16BE => UTF-8
  1084 	/**
       
  1085 	 * UTF-16BE => UTF-8
       
  1086 	 *
       
  1087 	 * @param string $string
       
  1088 	 *
       
  1089 	 * @return string
       
  1090 	 */
   883 	public static function iconv_fallback_utf16be_utf8($string) {
  1091 	public static function iconv_fallback_utf16be_utf8($string) {
   884 		if (substr($string, 0, 2) == "\xFE\xFF") {
  1092 		if (substr($string, 0, 2) == "\xFE\xFF") {
   885 			// strip BOM
  1093 			// strip BOM
   886 			$string = substr($string, 2);
  1094 			$string = substr($string, 2);
   887 		}
  1095 		}
   891 			$newcharstring .= self::iconv_fallback_int_utf8($charval);
  1099 			$newcharstring .= self::iconv_fallback_int_utf8($charval);
   892 		}
  1100 		}
   893 		return $newcharstring;
  1101 		return $newcharstring;
   894 	}
  1102 	}
   895 
  1103 
   896 	// UTF-16LE => UTF-8
  1104 	/**
       
  1105 	 * UTF-16LE => UTF-8
       
  1106 	 *
       
  1107 	 * @param string $string
       
  1108 	 *
       
  1109 	 * @return string
       
  1110 	 */
   897 	public static function iconv_fallback_utf16le_utf8($string) {
  1111 	public static function iconv_fallback_utf16le_utf8($string) {
   898 		if (substr($string, 0, 2) == "\xFF\xFE") {
  1112 		if (substr($string, 0, 2) == "\xFF\xFE") {
   899 			// strip BOM
  1113 			// strip BOM
   900 			$string = substr($string, 2);
  1114 			$string = substr($string, 2);
   901 		}
  1115 		}
   905 			$newcharstring .= self::iconv_fallback_int_utf8($charval);
  1119 			$newcharstring .= self::iconv_fallback_int_utf8($charval);
   906 		}
  1120 		}
   907 		return $newcharstring;
  1121 		return $newcharstring;
   908 	}
  1122 	}
   909 
  1123 
   910 	// UTF-16BE => ISO-8859-1
  1124 	/**
       
  1125 	 * UTF-16BE => ISO-8859-1
       
  1126 	 *
       
  1127 	 * @param string $string
       
  1128 	 *
       
  1129 	 * @return string
       
  1130 	 */
   911 	public static function iconv_fallback_utf16be_iso88591($string) {
  1131 	public static function iconv_fallback_utf16be_iso88591($string) {
   912 		if (substr($string, 0, 2) == "\xFE\xFF") {
  1132 		if (substr($string, 0, 2) == "\xFE\xFF") {
   913 			// strip BOM
  1133 			// strip BOM
   914 			$string = substr($string, 2);
  1134 			$string = substr($string, 2);
   915 		}
  1135 		}
   919 			$newcharstring .= (($charval < 256) ? chr($charval) : '?');
  1139 			$newcharstring .= (($charval < 256) ? chr($charval) : '?');
   920 		}
  1140 		}
   921 		return $newcharstring;
  1141 		return $newcharstring;
   922 	}
  1142 	}
   923 
  1143 
   924 	// UTF-16LE => ISO-8859-1
  1144 	/**
       
  1145 	 * UTF-16LE => ISO-8859-1
       
  1146 	 *
       
  1147 	 * @param string $string
       
  1148 	 *
       
  1149 	 * @return string
       
  1150 	 */
   925 	public static function iconv_fallback_utf16le_iso88591($string) {
  1151 	public static function iconv_fallback_utf16le_iso88591($string) {
   926 		if (substr($string, 0, 2) == "\xFF\xFE") {
  1152 		if (substr($string, 0, 2) == "\xFF\xFE") {
   927 			// strip BOM
  1153 			// strip BOM
   928 			$string = substr($string, 2);
  1154 			$string = substr($string, 2);
   929 		}
  1155 		}
   933 			$newcharstring .= (($charval < 256) ? chr($charval) : '?');
  1159 			$newcharstring .= (($charval < 256) ? chr($charval) : '?');
   934 		}
  1160 		}
   935 		return $newcharstring;
  1161 		return $newcharstring;
   936 	}
  1162 	}
   937 
  1163 
   938 	// UTF-16 (BOM) => ISO-8859-1
  1164 	/**
       
  1165 	 * UTF-16 (BOM) => ISO-8859-1
       
  1166 	 *
       
  1167 	 * @param string $string
       
  1168 	 *
       
  1169 	 * @return string
       
  1170 	 */
   939 	public static function iconv_fallback_utf16_iso88591($string) {
  1171 	public static function iconv_fallback_utf16_iso88591($string) {
   940 		$bom = substr($string, 0, 2);
  1172 		$bom = substr($string, 0, 2);
   941 		if ($bom == "\xFE\xFF") {
  1173 		if ($bom == "\xFE\xFF") {
   942 			return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
  1174 			return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
   943 		} elseif ($bom == "\xFF\xFE") {
  1175 		} elseif ($bom == "\xFF\xFE") {
   944 			return self::iconv_fallback_utf16le_iso88591(substr($string, 2));
  1176 			return self::iconv_fallback_utf16le_iso88591(substr($string, 2));
   945 		}
  1177 		}
   946 		return $string;
  1178 		return $string;
   947 	}
  1179 	}
   948 
  1180 
   949 	// UTF-16 (BOM) => UTF-8
  1181 	/**
       
  1182 	 * UTF-16 (BOM) => UTF-8
       
  1183 	 *
       
  1184 	 * @param string $string
       
  1185 	 *
       
  1186 	 * @return string
       
  1187 	 */
   950 	public static function iconv_fallback_utf16_utf8($string) {
  1188 	public static function iconv_fallback_utf16_utf8($string) {
   951 		$bom = substr($string, 0, 2);
  1189 		$bom = substr($string, 0, 2);
   952 		if ($bom == "\xFE\xFF") {
  1190 		if ($bom == "\xFE\xFF") {
   953 			return self::iconv_fallback_utf16be_utf8(substr($string, 2));
  1191 			return self::iconv_fallback_utf16be_utf8(substr($string, 2));
   954 		} elseif ($bom == "\xFF\xFE") {
  1192 		} elseif ($bom == "\xFF\xFE") {
   955 			return self::iconv_fallback_utf16le_utf8(substr($string, 2));
  1193 			return self::iconv_fallback_utf16le_utf8(substr($string, 2));
   956 		}
  1194 		}
   957 		return $string;
  1195 		return $string;
   958 	}
  1196 	}
   959 
  1197 
       
  1198 	/**
       
  1199 	 * @param string $in_charset
       
  1200 	 * @param string $out_charset
       
  1201 	 * @param string $string
       
  1202 	 *
       
  1203 	 * @return string
       
  1204 	 * @throws Exception
       
  1205 	 */
   960 	public static function iconv_fallback($in_charset, $out_charset, $string) {
  1206 	public static function iconv_fallback($in_charset, $out_charset, $string) {
   961 
  1207 
   962 		if ($in_charset == $out_charset) {
  1208 		if ($in_charset == $out_charset) {
   963 			return $string;
  1209 			return $string;
   964 		}
  1210 		}
   965 
  1211 
   966 		// mb_convert_encoding() availble
  1212 		// mb_convert_encoding() available
   967 		if (function_exists('mb_convert_encoding')) {
  1213 		if (function_exists('mb_convert_encoding')) {
       
  1214 			if ((strtoupper($in_charset) == 'UTF-16') && (substr($string, 0, 2) != "\xFE\xFF") && (substr($string, 0, 2) != "\xFF\xFE")) {
       
  1215 				// if BOM missing, mb_convert_encoding will mishandle the conversion, assume UTF-16BE and prepend appropriate BOM
       
  1216 				$string = "\xFF\xFE".$string;
       
  1217 			}
       
  1218 			if ((strtoupper($in_charset) == 'UTF-16') && (strtoupper($out_charset) == 'UTF-8')) {
       
  1219 				if (($string == "\xFF\xFE") || ($string == "\xFE\xFF")) {
       
  1220 					// if string consists of only BOM, mb_convert_encoding will return the BOM unmodified
       
  1221 					return '';
       
  1222 				}
       
  1223 			}
   968 			if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) {
  1224 			if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) {
   969 				switch ($out_charset) {
  1225 				switch ($out_charset) {
   970 					case 'ISO-8859-1':
  1226 					case 'ISO-8859-1':
   971 						$converted_string = rtrim($converted_string, "\x00");
  1227 						$converted_string = rtrim($converted_string, "\x00");
   972 						break;
  1228 						break;
   973 				}
  1229 				}
   974 				return $converted_string;
  1230 				return $converted_string;
   975 			}
  1231 			}
   976 			return $string;
  1232 			return $string;
   977 		}
  1233 
   978 		// iconv() availble
  1234 		// iconv() available
   979 		else if (function_exists('iconv')) {
  1235 		} elseif (function_exists('iconv')) {
   980 			if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
  1236 			if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
   981 				switch ($out_charset) {
  1237 				switch ($out_charset) {
   982 					case 'ISO-8859-1':
  1238 					case 'ISO-8859-1':
   983 						$converted_string = rtrim($converted_string, "\x00");
  1239 						$converted_string = rtrim($converted_string, "\x00");
   984 						break;
  1240 						break;
  1015 			return self::$ConversionFunction($string);
  1271 			return self::$ConversionFunction($string);
  1016 		}
  1272 		}
  1017 		throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
  1273 		throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
  1018 	}
  1274 	}
  1019 
  1275 
       
  1276 	/**
       
  1277 	 * @param mixed  $data
       
  1278 	 * @param string $charset
       
  1279 	 *
       
  1280 	 * @return mixed
       
  1281 	 */
  1020 	public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
  1282 	public static function recursiveMultiByteCharString2HTML($data, $charset='ISO-8859-1') {
  1021 		if (is_string($data)) {
  1283 		if (is_string($data)) {
  1022 			return self::MultiByteCharString2HTML($data, $charset);
  1284 			return self::MultiByteCharString2HTML($data, $charset);
  1023 		} elseif (is_array($data)) {
  1285 		} elseif (is_array($data)) {
  1024 			$return_data = array();
  1286 			$return_data = array();
  1029 		}
  1291 		}
  1030 		// integer, float, objects, resources, etc
  1292 		// integer, float, objects, resources, etc
  1031 		return $data;
  1293 		return $data;
  1032 	}
  1294 	}
  1033 
  1295 
       
  1296 	/**
       
  1297 	 * @param string|int|float $string
       
  1298 	 * @param string           $charset
       
  1299 	 *
       
  1300 	 * @return string
       
  1301 	 */
  1034 	public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
  1302 	public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
  1035 		$string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
  1303 		$string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
  1036 		$HTMLstring = '';
  1304 		$HTMLstring = '';
  1037 
  1305 
  1038 		switch (strtolower($charset)) {
  1306 		switch (strtolower($charset)) {
  1067 				break;
  1335 				break;
  1068 
  1336 
  1069 			case 'utf-8':
  1337 			case 'utf-8':
  1070 				$strlen = strlen($string);
  1338 				$strlen = strlen($string);
  1071 				for ($i = 0; $i < $strlen; $i++) {
  1339 				for ($i = 0; $i < $strlen; $i++) {
  1072 					$char_ord_val = ord($string{$i});
  1340 					$char_ord_val = ord($string[$i]);
  1073 					$charval = 0;
  1341 					$charval = 0;
  1074 					if ($char_ord_val < 0x80) {
  1342 					if ($char_ord_val < 0x80) {
  1075 						$charval = $char_ord_val;
  1343 						$charval = $char_ord_val;
  1076 					} elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F  &&  $i+3 < $strlen) {
  1344 					} elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F  &&  $i+3 < $strlen) {
  1077 						$charval  = (($char_ord_val & 0x07) << 18);
  1345 						$charval  = (($char_ord_val & 0x07) << 18);
  1078 						$charval += ((ord($string{++$i}) & 0x3F) << 12);
  1346 						$charval += ((ord($string[++$i]) & 0x3F) << 12);
  1079 						$charval += ((ord($string{++$i}) & 0x3F) << 6);
  1347 						$charval += ((ord($string[++$i]) & 0x3F) << 6);
  1080 						$charval +=  (ord($string{++$i}) & 0x3F);
  1348 						$charval +=  (ord($string[++$i]) & 0x3F);
  1081 					} elseif ((($char_ord_val & 0xE0) >> 5) == 0x07  &&  $i+2 < $strlen) {
  1349 					} elseif ((($char_ord_val & 0xE0) >> 5) == 0x07  &&  $i+2 < $strlen) {
  1082 						$charval  = (($char_ord_val & 0x0F) << 12);
  1350 						$charval  = (($char_ord_val & 0x0F) << 12);
  1083 						$charval += ((ord($string{++$i}) & 0x3F) << 6);
  1351 						$charval += ((ord($string[++$i]) & 0x3F) << 6);
  1084 						$charval +=  (ord($string{++$i}) & 0x3F);
  1352 						$charval +=  (ord($string[++$i]) & 0x3F);
  1085 					} elseif ((($char_ord_val & 0xC0) >> 6) == 0x03  &&  $i+1 < $strlen) {
  1353 					} elseif ((($char_ord_val & 0xC0) >> 6) == 0x03  &&  $i+1 < $strlen) {
  1086 						$charval  = (($char_ord_val & 0x1F) << 6);
  1354 						$charval  = (($char_ord_val & 0x1F) << 6);
  1087 						$charval += (ord($string{++$i}) & 0x3F);
  1355 						$charval += (ord($string[++$i]) & 0x3F);
  1088 					}
  1356 					}
  1089 					if (($charval >= 32) && ($charval <= 127)) {
  1357 					if (($charval >= 32) && ($charval <= 127)) {
  1090 						$HTMLstring .= htmlentities(chr($charval));
  1358 						$HTMLstring .= htmlentities(chr($charval));
  1091 					} else {
  1359 					} else {
  1092 						$HTMLstring .= '&#'.$charval.';';
  1360 						$HTMLstring .= '&#'.$charval.';';
  1121 				break;
  1389 				break;
  1122 		}
  1390 		}
  1123 		return $HTMLstring;
  1391 		return $HTMLstring;
  1124 	}
  1392 	}
  1125 
  1393 
  1126 
  1394 	/**
  1127 
  1395 	 * @param int $namecode
       
  1396 	 *
       
  1397 	 * @return string
       
  1398 	 */
  1128 	public static function RGADnameLookup($namecode) {
  1399 	public static function RGADnameLookup($namecode) {
  1129 		static $RGADname = array();
  1400 		static $RGADname = array();
  1130 		if (empty($RGADname)) {
  1401 		if (empty($RGADname)) {
  1131 			$RGADname[0] = 'not set';
  1402 			$RGADname[0] = 'not set';
  1132 			$RGADname[1] = 'Track Gain Adjustment';
  1403 			$RGADname[1] = 'Track Gain Adjustment';
  1134 		}
  1405 		}
  1135 
  1406 
  1136 		return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
  1407 		return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
  1137 	}
  1408 	}
  1138 
  1409 
  1139 
  1410 	/**
       
  1411 	 * @param int $originatorcode
       
  1412 	 *
       
  1413 	 * @return string
       
  1414 	 */
  1140 	public static function RGADoriginatorLookup($originatorcode) {
  1415 	public static function RGADoriginatorLookup($originatorcode) {
  1141 		static $RGADoriginator = array();
  1416 		static $RGADoriginator = array();
  1142 		if (empty($RGADoriginator)) {
  1417 		if (empty($RGADoriginator)) {
  1143 			$RGADoriginator[0] = 'unspecified';
  1418 			$RGADoriginator[0] = 'unspecified';
  1144 			$RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
  1419 			$RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
  1147 		}
  1422 		}
  1148 
  1423 
  1149 		return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
  1424 		return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
  1150 	}
  1425 	}
  1151 
  1426 
  1152 
  1427 	/**
       
  1428 	 * @param int $rawadjustment
       
  1429 	 * @param int $signbit
       
  1430 	 *
       
  1431 	 * @return float
       
  1432 	 */
  1153 	public static function RGADadjustmentLookup($rawadjustment, $signbit) {
  1433 	public static function RGADadjustmentLookup($rawadjustment, $signbit) {
  1154 		$adjustment = $rawadjustment / 10;
  1434 		$adjustment = (float) $rawadjustment / 10;
  1155 		if ($signbit == 1) {
  1435 		if ($signbit == 1) {
  1156 			$adjustment *= -1;
  1436 			$adjustment *= -1;
  1157 		}
  1437 		}
  1158 		return (float) $adjustment;
  1438 		return $adjustment;
  1159 	}
  1439 	}
  1160 
  1440 
  1161 
  1441 	/**
       
  1442 	 * @param int $namecode
       
  1443 	 * @param int $originatorcode
       
  1444 	 * @param int $replaygain
       
  1445 	 *
       
  1446 	 * @return string
       
  1447 	 */
  1162 	public static function RGADgainString($namecode, $originatorcode, $replaygain) {
  1448 	public static function RGADgainString($namecode, $originatorcode, $replaygain) {
  1163 		if ($replaygain < 0) {
  1449 		if ($replaygain < 0) {
  1164 			$signbit = '1';
  1450 			$signbit = '1';
  1165 		} else {
  1451 		} else {
  1166 			$signbit = '0';
  1452 			$signbit = '0';
  1172 		$gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT);
  1458 		$gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT);
  1173 
  1459 
  1174 		return $gainstring;
  1460 		return $gainstring;
  1175 	}
  1461 	}
  1176 
  1462 
       
  1463 	/**
       
  1464 	 * @param float $amplitude
       
  1465 	 *
       
  1466 	 * @return float
       
  1467 	 */
  1177 	public static function RGADamplitude2dB($amplitude) {
  1468 	public static function RGADamplitude2dB($amplitude) {
  1178 		return 20 * log10($amplitude);
  1469 		return 20 * log10($amplitude);
  1179 	}
  1470 	}
  1180 
  1471 
  1181 
  1472 	/**
       
  1473 	 * @param string $imgData
       
  1474 	 * @param array  $imageinfo
       
  1475 	 *
       
  1476 	 * @return array|false
       
  1477 	 */
  1182 	public static function GetDataImageSize($imgData, &$imageinfo=array()) {
  1478 	public static function GetDataImageSize($imgData, &$imageinfo=array()) {
       
  1479 		if (PHP_VERSION_ID >= 50400) {
       
  1480 			$GetDataImageSize = @getimagesizefromstring($imgData, $imageinfo);
       
  1481 			if ($GetDataImageSize === false || !isset($GetDataImageSize[0], $GetDataImageSize[1])) {
       
  1482 				return false;
       
  1483 			}
       
  1484 			$GetDataImageSize['height'] = $GetDataImageSize[0];
       
  1485 			$GetDataImageSize['width'] = $GetDataImageSize[1];
       
  1486 			return $GetDataImageSize;
       
  1487 		}
  1183 		static $tempdir = '';
  1488 		static $tempdir = '';
  1184 		if (empty($tempdir)) {
  1489 		if (empty($tempdir)) {
  1185 			if (function_exists('sys_get_temp_dir')) {
  1490 			if (function_exists('sys_get_temp_dir')) {
  1186 				$tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52
  1491 				$tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52
  1187 			}
  1492 			}
  1188 
  1493 
  1189 			// yes this is ugly, feel free to suggest a better way
  1494 			// yes this is ugly, feel free to suggest a better way
  1190 			if (include_once(dirname(__FILE__).'/getid3.php')) {
  1495 			if (include_once(dirname(__FILE__).'/getid3.php')) {
  1191 				if ($getid3_temp = new getID3()) {
  1496 				$getid3_temp = new getID3();
  1192 					if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
  1497 				if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
  1193 						$tempdir = $getid3_temp_tempdir;
  1498 					$tempdir = $getid3_temp_tempdir;
  1194 					}
       
  1195 					unset($getid3_temp, $getid3_temp_tempdir);
       
  1196 				}
  1499 				}
       
  1500 				unset($getid3_temp, $getid3_temp_tempdir);
  1197 			}
  1501 			}
  1198 		}
  1502 		}
  1199 		$GetDataImageSize = false;
  1503 		$GetDataImageSize = false;
  1200 		if ($tempfilename = tempnam($tempdir, 'gI3')) {
  1504 		if ($tempfilename = tempnam($tempdir, 'gI3')) {
  1201 			if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
  1505 			if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
  1211 			unlink($tempfilename);
  1515 			unlink($tempfilename);
  1212 		}
  1516 		}
  1213 		return $GetDataImageSize;
  1517 		return $GetDataImageSize;
  1214 	}
  1518 	}
  1215 
  1519 
       
  1520 	/**
       
  1521 	 * @param string $mime_type
       
  1522 	 *
       
  1523 	 * @return string
       
  1524 	 */
  1216 	public static function ImageExtFromMime($mime_type) {
  1525 	public static function ImageExtFromMime($mime_type) {
  1217 		// temporary way, works OK for now, but should be reworked in the future
  1526 		// temporary way, works OK for now, but should be reworked in the future
  1218 		return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
  1527 		return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
  1219 	}
  1528 	}
  1220 
  1529 
  1221 	public static function ImageTypesLookup($imagetypeid) {
  1530 	/**
  1222 		static $ImageTypesLookup = array();
  1531 	 * @param array $ThisFileInfo
  1223 		if (empty($ImageTypesLookup)) {
  1532 	 * @param bool  $option_tags_html default true (just as in the main getID3 class)
  1224 			$ImageTypesLookup[1]  = 'gif';
  1533 	 *
  1225 			$ImageTypesLookup[2]  = 'jpeg';
  1534 	 * @return bool
  1226 			$ImageTypesLookup[3]  = 'png';
  1535 	 */
  1227 			$ImageTypesLookup[4]  = 'swf';
  1536 	public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) {
  1228 			$ImageTypesLookup[5]  = 'psd';
       
  1229 			$ImageTypesLookup[6]  = 'bmp';
       
  1230 			$ImageTypesLookup[7]  = 'tiff (little-endian)';
       
  1231 			$ImageTypesLookup[8]  = 'tiff (big-endian)';
       
  1232 			$ImageTypesLookup[9]  = 'jpc';
       
  1233 			$ImageTypesLookup[10] = 'jp2';
       
  1234 			$ImageTypesLookup[11] = 'jpx';
       
  1235 			$ImageTypesLookup[12] = 'jb2';
       
  1236 			$ImageTypesLookup[13] = 'swc';
       
  1237 			$ImageTypesLookup[14] = 'iff';
       
  1238 		}
       
  1239 		return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : '');
       
  1240 	}
       
  1241 
       
  1242 	public static function CopyTagsToComments(&$ThisFileInfo) {
       
  1243 
       
  1244 		// Copy all entries from ['tags'] into common ['comments']
  1537 		// Copy all entries from ['tags'] into common ['comments']
  1245 		if (!empty($ThisFileInfo['tags'])) {
  1538 		if (!empty($ThisFileInfo['tags'])) {
       
  1539 			if (isset($ThisFileInfo['tags']['id3v1'])) {
       
  1540 				// bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings
       
  1541 				$ID3v1 = $ThisFileInfo['tags']['id3v1'];
       
  1542 				unset($ThisFileInfo['tags']['id3v1']);
       
  1543 				$ThisFileInfo['tags']['id3v1'] = $ID3v1;
       
  1544 				unset($ID3v1);
       
  1545 			}
  1246 			foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
  1546 			foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
  1247 				foreach ($tagarray as $tagname => $tagdata) {
  1547 				foreach ($tagarray as $tagname => $tagdata) {
  1248 					foreach ($tagdata as $key => $value) {
  1548 					foreach ($tagdata as $key => $value) {
  1249 						if (!empty($value)) {
  1549 						if (!empty($value)) {
  1250 							if (empty($ThisFileInfo['comments'][$tagname])) {
  1550 							if (empty($ThisFileInfo['comments'][$tagname])) {
  1259 									if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) {
  1559 									if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) {
  1260 										// new value is identical but shorter-than (or equal-length to) one already in comments - skip
  1560 										// new value is identical but shorter-than (or equal-length to) one already in comments - skip
  1261 										break 2;
  1561 										break 2;
  1262 									}
  1562 									}
  1263 								}
  1563 								}
       
  1564 								if (function_exists('mb_convert_encoding')) {
       
  1565 									if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) {
       
  1566 										// value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1.
       
  1567 										// As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character
       
  1568 										break 2;
       
  1569 									}
       
  1570 								}
  1264 
  1571 
  1265 							} elseif (!is_array($value)) {
  1572 							} elseif (!is_array($value)) {
  1266 
  1573 
  1267 								$newvaluelength = strlen(trim($value));
  1574 								$newvaluelength = strlen(trim($value));
  1268 								foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
  1575 								foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
  1269 									$oldvaluelength = strlen(trim($existingvalue));
  1576 									$oldvaluelength = strlen(trim($existingvalue));
  1270 									if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
  1577 									if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
  1271 										$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
  1578 										$ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
  1272 										//break 2;
       
  1273 										break;
  1579 										break;
  1274 									}
  1580 									}
  1275 								}
  1581 								}
  1276 
  1582 
  1277 							}
  1583 							}
  1278 							if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
  1584 							if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
  1279 								$value = (is_string($value) ? trim($value) : $value);
  1585 								$value = (is_string($value) ? trim($value) : $value);
  1280 								if (!is_int($key) && !ctype_digit($key)) {
  1586 								if (!is_int($key) && !ctype_digit($key)) {
  1281 									$ThisFileInfo['comments'][$tagname][$key] = $value;
  1587 									$ThisFileInfo['comments'][$tagname][$key] = $value;
  1282 								} else {
  1588 								} else {
  1283 									if (isset($ThisFileInfo['comments'][$tagname])) {
  1589 									if (!isset($ThisFileInfo['comments'][$tagname])) {
  1284 										$ThisFileInfo['comments'][$tagname] = array($value);
  1590 										$ThisFileInfo['comments'][$tagname] = array($value);
  1285 									} else {
  1591 									} else {
  1286 										$ThisFileInfo['comments'][$tagname][] = $value;
  1592 										$ThisFileInfo['comments'][$tagname][] = $value;
  1287 									}
  1593 									}
  1288 								}
  1594 								}
  1302 					$ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
  1608 					$ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
  1303 					unset($ThisFileInfo['comments'][$badkey]);
  1609 					unset($ThisFileInfo['comments'][$badkey]);
  1304 				}
  1610 				}
  1305 			}
  1611 			}
  1306 
  1612 
  1307 			// Copy to ['comments_html']
  1613 			if ($option_tags_html) {
  1308 			if (!empty($ThisFileInfo['comments'])) {
  1614 				// Copy ['comments'] to ['comments_html']
  1309 				foreach ($ThisFileInfo['comments'] as $field => $values) {
  1615 				if (!empty($ThisFileInfo['comments'])) {
  1310 					if ($field == 'picture') {
  1616 					foreach ($ThisFileInfo['comments'] as $field => $values) {
  1311 						// pictures can take up a lot of space, and we don't need multiple copies of them
  1617 						if ($field == 'picture') {
  1312 						// let there be a single copy in [comments][picture], and not elsewhere
  1618 							// pictures can take up a lot of space, and we don't need multiple copies of them
  1313 						continue;
  1619 							// let there be a single copy in [comments][picture], and not elsewhere
  1314 					}
  1620 							continue;
  1315 					foreach ($values as $index => $value) {
  1621 						}
  1316 						if (is_array($value)) {
  1622 						foreach ($values as $index => $value) {
  1317 							$ThisFileInfo['comments_html'][$field][$index] = $value;
  1623 							if (is_array($value)) {
  1318 						} else {
  1624 								$ThisFileInfo['comments_html'][$field][$index] = $value;
  1319 							$ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
  1625 							} else {
       
  1626 								$ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
       
  1627 							}
  1320 						}
  1628 						}
  1321 					}
  1629 					}
  1322 				}
  1630 				}
  1323 			}
  1631 			}
  1324 
  1632 
  1325 		}
  1633 		}
  1326 		return true;
  1634 		return true;
  1327 	}
  1635 	}
  1328 
  1636 
  1329 
  1637 	/**
       
  1638 	 * @param string $key
       
  1639 	 * @param int    $begin
       
  1640 	 * @param int    $end
       
  1641 	 * @param string $file
       
  1642 	 * @param string $name
       
  1643 	 *
       
  1644 	 * @return string
       
  1645 	 */
  1330 	public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
  1646 	public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
  1331 
  1647 
  1332 		// Cached
  1648 		// Cached
  1333 		static $cache;
  1649 		static $cache;
  1334 		if (isset($cache[$file][$name])) {
  1650 		if (isset($cache[$file][$name])) {
  1371 		// Close and return
  1687 		// Close and return
  1372 		fclose($fp);
  1688 		fclose($fp);
  1373 		return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
  1689 		return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
  1374 	}
  1690 	}
  1375 
  1691 
       
  1692 	/**
       
  1693 	 * @param string $filename
       
  1694 	 * @param string $sourcefile
       
  1695 	 * @param bool   $DieOnFailure
       
  1696 	 *
       
  1697 	 * @return bool
       
  1698 	 * @throws Exception
       
  1699 	 */
  1376 	public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
  1700 	public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
  1377 		global $GETID3_ERRORARRAY;
  1701 		global $GETID3_ERRORARRAY;
  1378 
  1702 
  1379 		if (file_exists($filename)) {
  1703 		if (file_exists($filename)) {
  1380 			if (include_once($filename)) {
  1704 			if (include_once($filename)) {
  1391 			$GETID3_ERRORARRAY[] = $diemessage;
  1715 			$GETID3_ERRORARRAY[] = $diemessage;
  1392 		}
  1716 		}
  1393 		return false;
  1717 		return false;
  1394 	}
  1718 	}
  1395 
  1719 
       
  1720 	/**
       
  1721 	 * @param string $string
       
  1722 	 *
       
  1723 	 * @return string
       
  1724 	 */
  1396 	public static function trimNullByte($string) {
  1725 	public static function trimNullByte($string) {
  1397 		return trim($string, "\x00");
  1726 		return trim($string, "\x00");
  1398 	}
  1727 	}
  1399 
  1728 
       
  1729 	/**
       
  1730 	 * @param string $path
       
  1731 	 *
       
  1732 	 * @return float|bool
       
  1733 	 */
  1400 	public static function getFileSizeSyscall($path) {
  1734 	public static function getFileSizeSyscall($path) {
  1401 		$filesize = false;
  1735 		$filesize = false;
  1402 
  1736 
  1403 		if (GETID3_OS_ISWINDOWS) {
  1737 		if (GETID3_OS_ISWINDOWS) {
  1404 			if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini:
  1738 			if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini:
  1419 			}
  1753 			}
  1420 		}
  1754 		}
  1421 		return $filesize;
  1755 		return $filesize;
  1422 	}
  1756 	}
  1423 
  1757 
  1424 
  1758 	/**
  1425 	/**
  1759 	 * @param string $filename
  1426 	* Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
  1760 	 *
  1427 	* @param string $path A path.
  1761 	 * @return string|false
  1428 	* @param string $suffix If the name component ends in suffix this will also be cut off.
  1762 	 */
  1429 	* @return string
  1763 	public static function truepath($filename) {
  1430 	*/
  1764 		// 2017-11-08: this could use some improvement, patches welcome
       
  1765 		if (preg_match('#^(\\\\\\\\|//)[a-z0-9]#i', $filename, $matches)) {
       
  1766 			// PHP's built-in realpath function does not work on UNC Windows shares
       
  1767 			$goodpath = array();
       
  1768 			foreach (explode('/', str_replace('\\', '/', $filename)) as $part) {
       
  1769 				if ($part == '.') {
       
  1770 					continue;
       
  1771 				}
       
  1772 				if ($part == '..') {
       
  1773 					if (count($goodpath)) {
       
  1774 						array_pop($goodpath);
       
  1775 					} else {
       
  1776 						// cannot step above this level, already at top level
       
  1777 						return false;
       
  1778 					}
       
  1779 				} else {
       
  1780 					$goodpath[] = $part;
       
  1781 				}
       
  1782 			}
       
  1783 			return implode(DIRECTORY_SEPARATOR, $goodpath);
       
  1784 		}
       
  1785 		return realpath($filename);
       
  1786 	}
       
  1787 
       
  1788 	/**
       
  1789 	 * Workaround for Bug #37268 (https://bugs.php.net/bug.php?id=37268)
       
  1790 	 *
       
  1791 	 * @param string $path A path.
       
  1792 	 * @param string $suffix If the name component ends in suffix this will also be cut off.
       
  1793 	 *
       
  1794 	 * @return string
       
  1795 	 */
  1431 	public static function mb_basename($path, $suffix = null) {
  1796 	public static function mb_basename($path, $suffix = null) {
  1432 		$splited = preg_split('#/#', rtrim($path, '/ '));
  1797 		$splited = preg_split('#/#', rtrim($path, '/ '));
  1433 		return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
  1798 		return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
  1434 	}
  1799 	}
  1435 
  1800