예제 #1
0
 static function iconv_fallback_utf8_utf16be($string, $bom = false)
 {
     $newcharstring = '';
     if ($bom) {
         $newcharstring .= "þÿ";
     }
     $offset = 0;
     $stringlength = strlen($string);
     while ($offset < $stringlength) {
         if ((ord($string[$offset]) | 0x7) == 0xf7) {
             // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
             $charval = (ord($string[$offset + 0]) & 0x7) << 18 & (ord($string[$offset + 1]) & 0x3f) << 12 & (ord($string[$offset + 2]) & 0x3f) << 6 & (ord($string[$offset + 3]) & 0x3f);
             $offset += 4;
         } elseif ((ord($string[$offset]) | 0xf) == 0xef) {
             // 1110bbbb 10bbbbbb 10bbbbbb
             $charval = (ord($string[$offset + 0]) & 0xf) << 12 & (ord($string[$offset + 1]) & 0x3f) << 6 & (ord($string[$offset + 2]) & 0x3f);
             $offset += 3;
         } elseif ((ord($string[$offset]) | 0x1f) == 0xdf) {
             // 110bbbbb 10bbbbbb
             $charval = (ord($string[$offset + 0]) & 0x1f) << 6 & (ord($string[$offset + 1]) & 0x3f);
             $offset += 2;
         } elseif ((ord($string[$offset]) | 0x7f) == 0x7f) {
             // 0bbbbbbb
             $charval = ord($string[$offset]);
             $offset += 1;
         } else {
             // error? throw some kind of warning here?
             $charval = false;
             $offset += 1;
         }
         if ($charval !== false) {
             $newcharstring .= $charval < 65536 ? getid3_lib::BigEndian2String($charval, 2) : "" . '?';
         }
     }
     return $newcharstring;
 }
예제 #2
0
파일: write.real.php 프로젝트: aptitune/app
 public function GenerateCONTchunk()
 {
     foreach ($this->tag_data as $key => $value) {
         // limit each value to 0xFFFF bytes
         $this->tag_data[$key] = substr($value, 0, 65535);
     }
     $CONTchunk = "";
     // object version
     $CONTchunk .= getid3_lib::BigEndian2String(!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : 0, 2);
     $CONTchunk .= !empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : '';
     $CONTchunk .= getid3_lib::BigEndian2String(!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : 0, 2);
     $CONTchunk .= !empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : '';
     $CONTchunk .= getid3_lib::BigEndian2String(!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : 0, 2);
     $CONTchunk .= !empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : '';
     $CONTchunk .= getid3_lib::BigEndian2String(!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : 0, 2);
     $CONTchunk .= !empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : '';
     if ($this->paddedlength > strlen($CONTchunk) + 8) {
         $CONTchunk .= str_repeat("", $this->paddedlength - strlen($CONTchunk) - 8);
     }
     $CONTchunk = 'CONT' . getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4) . $CONTchunk;
     // CONT chunk identifier + chunk length
     return $CONTchunk;
 }
 function Float2String($floatvalue, $bits)
 {
     // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
     switch ($bits) {
         case 32:
             $exponentbits = 8;
             $fractionbits = 23;
             break;
         case 64:
             $exponentbits = 11;
             $fractionbits = 52;
             break;
         default:
             return false;
             break;
     }
     if ($floatvalue >= 0) {
         $signbit = '0';
     } else {
         $signbit = '1';
     }
     $normalizedbinary = getid3_lib::NormalizeBinaryPoint(getid3_lib::Float2BinaryDecimal($floatvalue), $fractionbits);
     $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent'];
     // (127 or 1023) +/- exponent
     $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
     $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
     return getid3_lib::BigEndian2String(getid3_lib::Bin2Dec($signbit . $exponentbitstring . $fractionbitstring), $bits % 8, false);
 }
예제 #4
0
	function iconv_fallback_utf8_utf16be($string, $bom=false) {
		$newcharstring = '';
		if ($bom) {
			$newcharstring .= "\xFE\xFF";
		}
		$offset = 0;
		$stringlength = strlen($string);
		while ($offset < $stringlength) {
			if ((ord($string{$offset}) | 0x07) == 0xF7) {
				// 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
				$charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
				           ((ord($string{($offset + 1)}) & 0x3F) << 12) &
				           ((ord($string{($offset + 2)}) & 0x3F) <<  6) &
				            (ord($string{($offset + 3)}) & 0x3F);
				$offset += 4;
			} elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
				// 1110bbbb 10bbbbbb 10bbbbbb
				$charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
				           ((ord($string{($offset + 1)}) & 0x3F) <<  6) &
				            (ord($string{($offset + 2)}) & 0x3F);
				$offset += 3;
			} elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
				// 110bbbbb 10bbbbbb
				$charval = ((ord($string{($offset + 0)}) & 0x1F) <<  6) &
				            (ord($string{($offset + 1)}) & 0x3F);
				$offset += 2;
			} elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
				// 0bbbbbbb
				$charval = ord($string{$offset});
				$offset += 1;
			} else {
				// error? throw some kind of warning here?
				$charval = false;
				$offset += 1;
			}
			if ($charval !== false) {
				$newcharstring .= (($charval < 65536) ? getid3_lib::BigEndian2String($charval, 2) : "\x00".'?');
			}
		}
		return $newcharstring;
	}
예제 #5
0
 function GenerateID3v2Tag($noerrorsonly = true)
 {
     $this->ID3v2FrameIsAllowed(null, '');
     // clear static array in case this isn't the first call to $this->GenerateID3v2Tag()
     $tagstring = '';
     if (is_array($this->tag_data)) {
         foreach ($this->tag_data as $frame_name => $frame_rawinputdata) {
             foreach ($frame_rawinputdata as $irrelevantindex => $source_data_array) {
                 if (getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) {
                     unset($frame_length);
                     unset($frame_flags);
                     $frame_data = false;
                     if ($this->ID3v2FrameIsAllowed($frame_name, $source_data_array)) {
                         if ($frame_data = $this->GenerateID3v2FrameData($frame_name, $source_data_array)) {
                             $FrameUnsynchronisation = false;
                             if ($this->majorversion >= 4) {
                                 // frame-level unsynchronisation
                                 $unsynchdata = $frame_data;
                                 if ($this->id3v2_use_unsynchronisation) {
                                     $unsynchdata = $this->Unsynchronise($frame_data);
                                 }
                                 if (strlen($unsynchdata) != strlen($frame_data)) {
                                     // unsynchronisation needed
                                     $FrameUnsynchronisation = true;
                                     $frame_data = $unsynchdata;
                                     if (isset($TagUnsynchronisation) && $TagUnsynchronisation === false) {
                                         // only set to true if ALL frames are unsynchronised
                                     } else {
                                         $TagUnsynchronisation = true;
                                     }
                                 } else {
                                     if (isset($TagUnsynchronisation)) {
                                         $TagUnsynchronisation = false;
                                     }
                                 }
                                 unset($unsynchdata);
                                 $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, true);
                             } else {
                                 $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, false);
                             }
                             $frame_flags = $this->GenerateID3v2FrameFlags($this->ID3v2FrameFlagsLookupTagAlter($frame_name), $this->ID3v2FrameFlagsLookupFileAlter($frame_name), false, false, false, false, $FrameUnsynchronisation, false);
                         }
                     } else {
                         $this->errors[] = 'Frame "' . $frame_name . '" is NOT allowed';
                     }
                     if ($frame_data === false) {
                         $this->errors[] = '$this->GenerateID3v2FrameData() failed for "' . $frame_name . '"';
                         if ($noerrorsonly) {
                             return false;
                         } else {
                             unset($frame_name);
                         }
                     }
                 } else {
                     // ignore any invalid frame names, including 'title', 'header', etc
                     $this->warnings[] = 'Ignoring invalid ID3v2 frame type: "' . $frame_name . '"';
                     unset($frame_name);
                     unset($frame_length);
                     unset($frame_flags);
                     unset($frame_data);
                 }
                 if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) {
                     $tagstring .= $frame_name . $frame_length . $frame_flags . $frame_data;
                 }
             }
         }
         if (!isset($TagUnsynchronisation)) {
             $TagUnsynchronisation = false;
         }
         if ($this->majorversion <= 3 && $this->id3v2_use_unsynchronisation) {
             // tag-level unsynchronisation
             $unsynchdata = $this->Unsynchronise($tagstring);
             if (strlen($unsynchdata) != strlen($tagstring)) {
                 // unsynchronisation needed
                 $TagUnsynchronisation = true;
                 $tagstring = $unsynchdata;
             }
         }
         while ($this->paddedlength < strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)) {
             $this->paddedlength += 1024;
         }
         $footer = false;
         // ID3v2 footers not yet supported in getID3()
         if (!$footer && $this->paddedlength > strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)) {
             // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength
             // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag."
             $tagstring .= @str_repeat("", $this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion));
         }
         if ($this->id3v2_use_unsynchronisation && substr($tagstring, strlen($tagstring) - 1, 1) == "ÿ") {
             // special unsynchronisation case:
             // if last byte == $FF then appended a $00
             $TagUnsynchronisation = true;
             $tagstring .= "";
         }
         $tagheader = 'ID3';
         $tagheader .= chr($this->majorversion);
         $tagheader .= chr($this->minorversion);
         $tagheader .= $this->GenerateID3v2TagFlags(array('unsynchronisation' => $TagUnsynchronisation));
         $tagheader .= getid3_lib::BigEndian2String(strlen($tagstring), 4, true);
         return $tagheader . $tagstring;
     }
     $this->errors[] = 'tag_data is not an array in GenerateID3v2Tag()';
     return false;
 }
예제 #6
0
 protected function generate_frame_data($frame_name, $source_data_array)
 {
     $frame_data = '';
     switch ($frame_name) {
         case 'UFID':
             // 4.1   UFID Unique file identifier
             // Owner identifier        <text string> $00
             // Identifier              <up to 64 bytes binary data>
             if (strlen($source_data_array['data']) > 64) {
                 throw new getid3_exception('Identifier not allowed to be longer than 64 bytes in ' . $frame_name . ' (supplied data was ' . strlen($source_data_array['data']) . ' bytes long)');
             }
             $frame_data .= str_replace("", '', $source_data_array['ownerid']) . "";
             $frame_data .= substr($source_data_array['data'], 0, 64);
             // max 64 bytes - truncate anything longer
             break;
         case 'TXXX':
             // 4.2.2 TXXX User defined text information frame
             // Text encoding     $xx
             // Description       <text string according to encoding> $00 (00)
             // Value             <text string according to encoding>
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= $source_data_array['description'] . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'WXXX':
             // 4.3.2 WXXX User defined URL link frame
             // Text encoding     $xx
             // Description       <text string according to encoding> $00 (00)
             // URL               <text string>
             if (!isset($source_data_array['data']) || !$this->valid_url($source_data_array['data'], false, false)) {
                 throw new getid3_exception('Invalid URL in ' . $frame_name . ' (' . $source_data_array['data'] . ')');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= $source_data_array['description'] . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'IPLS':
             // 4.4  IPLS Involved people list (ID3v2.3 only)
             // Text encoding     $xx
             // People list strings    <textstrings>
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= $source_data_array['data'];
             break;
         case 'MCDI':
             // 4.4   MCDI Music CD identifier
             // CD TOC                <binary data>
             $frame_data .= $source_data_array['data'];
             break;
         case 'ETCO':
             // 4.5   ETCO Event timing codes
             // Time stamp format    $xx
             //   Where time stamp format is:
             // $01  (32-bit value) MPEG frames from beginning of file
             // $02  (32-bit value) milliseconds from beginning of file
             //   Followed by a list of key events in the following format:
             // Type of event   $xx
             // Time stamp      $xx (xx ...)
             //   The 'Time stamp' is set to zero if directly at the beginning of the sound
             //   or after the previous event. All events MUST be sorted in chronological order.
             if ($source_data_array['timestampformat'] > 2 || $source_data_array['timestampformat'] < 1) {
                 throw new getid3_exception('Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ')');
             }
             $frame_data .= chr($source_data_array['timestampformat']);
             foreach ($source_data_array as $key => $val) {
                 if (!$this->ID3v2IsValidETCOevent($val['typeid'])) {
                     throw new getid3_exception('Invalid Event Type byte in ' . $frame_name . ' (' . $val['typeid'] . ')');
                 }
                 if ($key != 'timestampformat' && $key != 'flags') {
                     if ($val['timestamp'] > 0 && $previousETCOtimestamp >= $val['timestamp']) {
                         //   The 'Time stamp' is set to zero if directly at the beginning of the sound
                         //   or after the previous event. All events MUST be sorted in chronological order.
                         throw new getid3_exception('Out-of-order timestamp in ' . $frame_name . ' (' . $val['timestamp'] . ') for Event Type (' . $val['typeid'] . ')');
                     }
                     $frame_data .= chr($val['typeid']);
                     $frame_data .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
                 }
             }
             break;
         case 'MLLT':
             // 4.6   MLLT MPEG location lookup table
             // MPEG frames between reference  $xx xx
             // Bytes between reference        $xx xx xx
             // Milliseconds between reference $xx xx xx
             // Bits for bytes deviation       $xx
             // Bits for milliseconds dev.     $xx
             //   Then for every reference the following data is included;
             // Deviation in bytes         %xxx....
             // Deviation in milliseconds  %xxx....
             if ($source_data_array['framesbetweenreferences'] > 0 && $source_data_array['framesbetweenreferences'] <= 65535) {
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['framesbetweenreferences'], 2, false);
             } else {
                 throw new getid3_exception('Invalid MPEG Frames Between References in ' . $frame_name . ' (' . $source_data_array['framesbetweenreferences'] . ')');
             }
             if ($source_data_array['bytesbetweenreferences'] > 0 && $source_data_array['bytesbetweenreferences'] <= 16777215) {
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false);
             } else {
                 throw new getid3_exception('Invalid bytes Between References in ' . $frame_name . ' (' . $source_data_array['bytesbetweenreferences'] . ')');
             }
             if ($source_data_array['msbetweenreferences'] > 0 && $source_data_array['msbetweenreferences'] <= 16777215) {
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['msbetweenreferences'], 3, false);
             } else {
                 throw new getid3_exception('Invalid Milliseconds Between References in ' . $frame_name . ' (' . $source_data_array['msbetweenreferences'] . ')');
             }
             if (!$this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false)) {
                 if ($source_data_array['bitsforbytesdeviation'] % 4 == 0) {
                     $frame_data .= chr($source_data_array['bitsforbytesdeviation']);
                 } else {
                     throw new getid3_exception('Bits For Bytes Deviation in ' . $frame_name . ' (' . $source_data_array['bitsforbytesdeviation'] . ') must be a multiple of 4.');
                 }
             } else {
                 throw new getid3_exception('Invalid Bits For Bytes Deviation in ' . $frame_name . ' (' . $source_data_array['bitsforbytesdeviation'] . ')');
             }
             if (!$this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false)) {
                 if ($source_data_array['bitsformsdeviation'] % 4 == 0) {
                     $frame_data .= chr($source_data_array['bitsformsdeviation']);
                 } else {
                     throw new getid3_exception('Bits For Milliseconds Deviation in ' . $frame_name . ' (' . $source_data_array['bitsforbytesdeviation'] . ') must be a multiple of 4.');
                 }
             } else {
                 throw new getid3_exception('Invalid Bits For Milliseconds Deviation in ' . $frame_name . ' (' . $source_data_array['bitsformsdeviation'] . ')');
             }
             foreach ($source_data_array as $key => $val) {
                 if ($key != 'framesbetweenreferences' && $key != 'bytesbetweenreferences' && $key != 'msbetweenreferences' && $key != 'bitsforbytesdeviation' && $key != 'bitsformsdeviation' && $key != 'flags') {
                     $unwritten_bit_stream .= str_pad(getid3_lib::Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT);
                     $unwritten_bit_stream .= str_pad(getid3_lib::Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT);
                 }
             }
             for ($i = 0; $i < strlen($unwritten_bit_stream); $i += 8) {
                 $high_nibble = bindec(substr($unwritten_bit_stream, $i, 4)) << 4;
                 $low_nibble = bindec(substr($unwritten_bit_stream, $i + 4, 4));
                 $frame_data .= chr($high_nibble & $low_nibble);
             }
             break;
         case 'SYTC':
             // 4.7   SYTC Synchronised tempo codes
             // Time stamp format   $xx
             // Tempo data          <binary data>
             //   Where time stamp format is:
             // $01  (32-bit value) MPEG frames from beginning of file
             // $02  (32-bit value) milliseconds from beginning of file
             if ($source_data_array['timestampformat'] > 2 || $source_data_array['timestampformat'] < 1) {
                 throw new getid3_exception('Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ')');
             }
             $frame_data .= chr($source_data_array['timestampformat']);
             foreach ($source_data_array as $key => $val) {
                 if (!$this->ID3v2IsValidETCOevent($val['typeid'])) {
                     throw new getid3_exception('Invalid Event Type byte in ' . $frame_name . ' (' . $val['typeid'] . ')');
                 }
                 if ($key != 'timestampformat' && $key != 'flags') {
                     if ($val['tempo'] < 0 || $val['tempo'] > 510) {
                         throw new getid3_exception('Invalid Tempo (max = 510) in ' . $frame_name . ' (' . $val['tempo'] . ') at timestamp (' . $val['timestamp'] . ')');
                     }
                     if ($val['tempo'] > 255) {
                         $frame_data .= chr(255);
                         $val['tempo'] -= 255;
                     }
                     $frame_data .= chr($val['tempo']);
                     $frame_data .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
                 }
             }
             break;
         case 'USLT':
             // 4.8   USLT Unsynchronised lyric/text transcription
             // Text encoding        $xx
             // Language             $xx xx xx
             // Content descriptor   <text string according to encoding> $00 (00)
             // Lyrics/text          <full text string according to encoding>
             if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
                 throw new getid3_exception('Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= strtolower($source_data_array['language']);
             $frame_data .= $source_data_array['description'] . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'SYLT':
             // 4.9   SYLT Synchronised lyric/text
             // Text encoding        $xx
             // Language             $xx xx xx
             // Time stamp format    $xx
             //   $01  (32-bit value) MPEG frames from beginning of file
             //   $02  (32-bit value) milliseconds from beginning of file
             // Content type         $xx
             // Content descriptor   <text string according to encoding> $00 (00)
             //   Terminated text to be synced (typically a syllable)
             //   Sync identifier (terminator to above string)   $00 (00)
             //   Time stamp                                     $xx (xx ...)
             if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
                 throw new getid3_exception('Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')');
             }
             if ($source_data_array['timestampformat'] > 2 || $source_data_array['timestampformat'] < 1) {
                 throw new getid3_exception('Invalid Time Stamp Format byte in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ')');
             }
             if (!$this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid'])) {
                 throw new getid3_exception('Invalid Content Type byte in ' . $frame_name . ' (' . $source_data_array['contenttypeid'] . ')');
             }
             if (!is_array($source_data_array['data'])) {
                 throw new getid3_exception('Invalid Lyric/Timestamp data in ' . $frame_name . ' (must be an array)');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= strtolower($source_data_array['language']);
             $frame_data .= chr($source_data_array['timestampformat']);
             $frame_data .= chr($source_data_array['contenttypeid']);
             $frame_data .= $source_data_array['description'] . "";
             ksort($source_data_array['data']);
             foreach ($source_data_array['data'] as $key => $val) {
                 $frame_data .= $val['data'] . "";
                 $frame_data .= getid3_lib::BigEndian2String($val['timestamp'], 4, false);
             }
             break;
         case 'COMM':
             // 4.10  COMM Comments
             // Text encoding          $xx
             // Language               $xx xx xx
             // Short content descrip. <text string according to encoding> $00 (00)
             // The actual text        <full text string according to encoding>
             if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
                 throw new getid3_exception('Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= strtolower($source_data_array['language']);
             $frame_data .= $source_data_array['description'] . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'RVA2':
             // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
             // Identification          <text string> $00
             //   The 'identification' string is used to identify the situation and/or
             //   device where this adjustment should apply. The following is then
             //   repeated for every channel:
             // Type of channel         $xx
             // Volume adjustment       $xx xx
             // Bits representing peak  $xx
             // Peak volume             $xx (xx ...)
             $frame_data .= str_replace("", '', $source_data_array['description']) . "";
             foreach ($source_data_array as $key => $val) {
                 if ($key != 'description') {
                     $frame_data .= chr($val['channeltypeid']);
                     $frame_data .= getid3_lib::BigEndian2String($val['volumeadjust'], 2, false, true);
                     // signed 16-bit
                     if (!$this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false)) {
                         $frame_data .= chr($val['bitspeakvolume']);
                         if ($val['bitspeakvolume'] > 0) {
                             $frame_data .= getid3_lib::BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false);
                         }
                     } else {
                         throw new getid3_exception('Invalid Bits Representing Peak Volume in ' . $frame_name . ' (' . $val['bitspeakvolume'] . ') (range = 0 to 255)');
                     }
                 }
             }
             break;
         case 'RVAD':
             // 4.12  RVAD Relative volume adjustment (ID3v2.3 only)
             // Increment/decrement     %00fedcba
             // Bits used for volume descr.        $xx
             // Relative volume change, right      $xx xx (xx ...) // a
             // Relative volume change, left       $xx xx (xx ...) // b
             // Peak volume right                  $xx xx (xx ...)
             // Peak volume left                   $xx xx (xx ...)
             // Relative volume change, right back $xx xx (xx ...) // c
             // Relative volume change, left back  $xx xx (xx ...) // d
             // Peak volume right back             $xx xx (xx ...)
             // Peak volume left back              $xx xx (xx ...)
             // Relative volume change, center     $xx xx (xx ...) // e
             // Peak volume center                 $xx xx (xx ...)
             // Relative volume change, bass       $xx xx (xx ...) // f
             // Peak volume bass                   $xx xx (xx ...)
             if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) {
                 throw new getid3_exception('Invalid Bits For Volume Description byte in ' . $frame_name . ' (' . $source_data_array['bitsvolume'] . ') (range = 1 to 255)');
             } else {
                 $inc_dec_flag .= '00';
                 $inc_dec_flag .= $source_data_array['incdec']['right'] ? '1' : '0';
                 // a - Relative volume change, right
                 $inc_dec_flag .= $source_data_array['incdec']['left'] ? '1' : '0';
                 // b - Relative volume change, left
                 $inc_dec_flag .= $source_data_array['incdec']['rightrear'] ? '1' : '0';
                 // c - Relative volume change, right back
                 $inc_dec_flag .= $source_data_array['incdec']['leftrear'] ? '1' : '0';
                 // d - Relative volume change, left back
                 $inc_dec_flag .= $source_data_array['incdec']['center'] ? '1' : '0';
                 // e - Relative volume change, center
                 $inc_dec_flag .= $source_data_array['incdec']['bass'] ? '1' : '0';
                 // f - Relative volume change, bass
                 $frame_data .= chr(bindec($inc_dec_flag));
                 $frame_data .= chr($source_data_array['bitsvolume']);
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false);
                 $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false);
                 if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] || $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] || $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume'] / 8), false);
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume'] / 8), false);
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume'] / 8), false);
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume'] / 8), false);
                 }
                 if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume'] / 8), false);
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume'] / 8), false);
                 }
                 if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) {
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume'] / 8), false);
                     $frame_data .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume'] / 8), false);
                 }
             }
             break;
         case 'EQU2':
             // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
             // Interpolation method  $xx
             //   $00  Band
             //   $01  Linear
             // Identification        <text string> $00
             //   The following is then repeated for every adjustment point
             // Frequency          $xx xx
             // Volume adjustment  $xx xx
             if ($source_data_array['interpolationmethod'] < 0 || $source_data_array['interpolationmethod'] > 1) {
                 throw new getid3_exception('Invalid Interpolation Method byte in ' . $frame_name . ' (' . $source_data_array['interpolationmethod'] . ') (valid = 0 or 1)');
             }
             $frame_data .= chr($source_data_array['interpolationmethod']);
             $frame_data .= str_replace("", '', $source_data_array['description']) . "";
             foreach ($source_data_array['data'] as $key => $val) {
                 $frame_data .= getid3_lib::BigEndian2String(intval(round($key * 2)), 2, false);
                 $frame_data .= getid3_lib::BigEndian2String($val, 2, false, true);
                 // signed 16-bit
             }
             break;
         case 'EQUA':
             // 4.12  EQUA Equalisation (ID3v2.3 only)
             // Adjustment bits    $xx
             //   This is followed by 2 bytes + ('adjustment bits' rounded up to the
             //   nearest byte) for every equalisation band in the following format,
             //   giving a frequency range of 0 - 32767Hz:
             // Increment/decrement   %x (MSB of the Frequency)
             // Frequency             (lower 15 bits)
             // Adjustment            $xx (xx ...)
             if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) {
                 throw new getid3_exception('Invalid Adjustment Bits byte in ' . $frame_name . ' (' . $source_data_array['bitsvolume'] . ') (range = 1 to 255)');
             }
             $frame_data .= chr($source_data_array['adjustmentbits']);
             foreach ($source_data_array as $key => $val) {
                 if ($key != 'bitsvolume') {
                     if ($key > 32767 || $key < 0) {
                         throw new getid3_exception('Invalid Frequency in ' . $frame_name . ' (' . $key . ') (range = 0 to 32767)');
                     } else {
                         if ($val >= 0) {
                             // put MSB of frequency to 1 if increment, 0 if decrement
                             $key |= 0x8000;
                         }
                         $frame_data .= getid3_lib::BigEndian2String($key, 2, false);
                         $frame_data .= getid3_lib::BigEndian2String($val, ceil($source_data_array['adjustmentbits'] / 8), false);
                     }
                 }
             }
             break;
         case 'RVRB':
             // 4.13  RVRB Reverb
             // Reverb left (ms)                 $xx xx
             // Reverb right (ms)                $xx xx
             // Reverb bounces, left             $xx
             // Reverb bounces, right            $xx
             // Reverb feedback, left to left    $xx
             // Reverb feedback, left to right   $xx
             // Reverb feedback, right to right  $xx
             // Reverb feedback, right to left   $xx
             // Premix left to right             $xx
             // Premix right to left             $xx
             if (!$this->IsWithinBitRange($source_data_array['left'], 16, false)) {
                 throw new getid3_exception('Invalid Reverb Left in ' . $frame_name . ' (' . $source_data_array['left'] . ') (range = 0 to 65535)');
             }
             if (!$this->IsWithinBitRange($source_data_array['right'], 16, false)) {
                 throw new getid3_exception('Invalid Reverb Left in ' . $frame_name . ' (' . $source_data_array['right'] . ') (range = 0 to 65535)');
             }
             if (!$this->IsWithinBitRange($source_data_array['bouncesL'], 8, false)) {
                 throw new getid3_exception('Invalid Reverb Bounces, Left in ' . $frame_name . ' (' . $source_data_array['bouncesL'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['bouncesR'], 8, false)) {
                 throw new getid3_exception('Invalid Reverb Bounces, Right in ' . $frame_name . ' (' . $source_data_array['bouncesR'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['feedbackLL'], 8, false)) {
                 throw new getid3_exception('Invalid Reverb Feedback, Left-To-Left in ' . $frame_name . ' (' . $source_data_array['feedbackLL'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['feedbackLR'], 8, false)) {
                 throw new getid3_exception('Invalid Reverb Feedback, Left-To-Right in ' . $frame_name . ' (' . $source_data_array['feedbackLR'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['feedbackRR'], 8, false)) {
                 throw new getid3_exception('Invalid Reverb Feedback, Right-To-Right in ' . $frame_name . ' (' . $source_data_array['feedbackRR'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['feedbackRL'], 8, false)) {
                 throw new getid3_exception('Invalid Reverb Feedback, Right-To-Left in ' . $frame_name . ' (' . $source_data_array['feedbackRL'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['premixLR'], 8, false)) {
                 throw new getid3_exception('Invalid Premix, Left-To-Right in ' . $frame_name . ' (' . $source_data_array['premixLR'] . ') (range = 0 to 255)');
             }
             if (!$this->IsWithinBitRange($source_data_array['premixRL'], 8, false)) {
                 throw new getid3_exception('Invalid Premix, Right-To-Left in ' . $frame_name . ' (' . $source_data_array['premixRL'] . ') (range = 0 to 255)');
             }
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['left'], 2, false);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['right'], 2, false);
             $frame_data .= chr($source_data_array['bouncesL']);
             $frame_data .= chr($source_data_array['bouncesR']);
             $frame_data .= chr($source_data_array['feedbackLL']);
             $frame_data .= chr($source_data_array['feedbackLR']);
             $frame_data .= chr($source_data_array['feedbackRR']);
             $frame_data .= chr($source_data_array['feedbackRL']);
             $frame_data .= chr($source_data_array['premixLR']);
             $frame_data .= chr($source_data_array['premixRL']);
             break;
         case 'APIC':
             // 4.14  APIC Attached picture
             // Text encoding      $xx
             // MIME type          <text string> $00
             // Picture type       $xx
             // Description        <text string according to encoding> $00 (00)
             // Picture data       <binary data>
             if (!$this->ID3v2IsValidAPICpicturetype($source_data_array['picturetypeid'])) {
                 throw new getid3_exception('Invalid Picture Type byte in ' . $frame_name . ' (' . $source_data_array['picturetypeid'] . ') for ID3v2.' . getid3_id3v2_write::major_version);
             }
             if (getid3_id3v2_write::major_version >= 3 && !$this->ID3v2IsValidAPICimageformat($source_data_array['mime'])) {
                 throw new getid3_exception('Invalid MIME Type in ' . $frame_name . ' (' . $source_data_array['mime'] . ') for ID3v2.' . getid3_id3v2_write::major_version);
             }
             if ($source_data_array['mime'] == '-->' && !$this->valid_url($source_data_array['data'], false, false)) {
                 throw new getid3_exception('Invalid URL in ' . $frame_name . ' (' . $source_data_array['data'] . ')');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= str_replace("", '', $source_data_array['mime']) . "";
             $frame_data .= chr($source_data_array['picturetypeid']);
             $frame_data .= @$source_data_array['description'] . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'GEOB':
             // 4.15  GEOB General encapsulated object
             // Text encoding          $xx
             // MIME type              <text string> $00
             // Filename               <text string according to encoding> $00 (00)
             // Content description    <text string according to encoding> $00 (00)
             // Encapsulated object    <binary data>
             if (!$this->IsValidMIMEstring($source_data_array['mime'])) {
                 throw new getid3_exception('Invalid MIME Type in ' . $frame_name . ' (' . $source_data_array['mime'] . ')');
             }
             if (!$source_data_array['description']) {
                 throw new getid3_exception('Missing Description in ' . $frame_name);
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= str_replace("", '', $source_data_array['mime']) . "";
             $frame_data .= $source_data_array['filename'] . "";
             $frame_data .= $source_data_array['description'] . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'PCNT':
             // 4.16  PCNT Play counter
             //   When the counter reaches all one's, one byte is inserted in
             //   front of the counter thus making the counter eight bits bigger
             // Counter        $xx xx xx xx (xx ...)
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false);
             break;
         case 'POPM':
             // 4.17  POPM Popularimeter
             //   When the counter reaches all one's, one byte is inserted in
             //   front of the counter thus making the counter eight bits bigger
             // Email to user   <text string> $00
             // Rating          $xx
             // Counter         $xx xx xx xx (xx ...)
             if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) {
                 throw new getid3_exception('Invalid Rating byte in ' . $frame_name . ' (' . $source_data_array['rating'] . ') (range = 0 to 255)');
             }
             if (!IsValidEmail($source_data_array['email'])) {
                 throw new getid3_exception('Invalid Email in ' . $frame_name . ' (' . $source_data_array['email'] . ')');
             }
             $frame_data .= str_replace("", '', $source_data_array['email']) . "";
             $frame_data .= chr($source_data_array['rating']);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false);
             break;
         case 'RBUF':
             // 4.18  RBUF Recommended buffer size
             // Buffer size               $xx xx xx
             // Embedded info flag        %0000000x
             // Offset to next tag        $xx xx xx xx
             if (!$this->IsWithinBitRange($source_data_array['buffersize'], 24, false)) {
                 throw new getid3_exception('Invalid Buffer Size in ' . $frame_name);
             }
             if (!$this->IsWithinBitRange($source_data_array['nexttagoffset'], 32, false)) {
                 throw new getid3_exception('Invalid Offset To Next Tag in ' . $frame_name);
             }
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['buffersize'], 3, false);
             $flag .= '0000000';
             $flag .= $source_data_array['flags']['embededinfo'] ? '1' : '0';
             $frame_data .= chr(bindec($flag));
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['nexttagoffset'], 4, false);
             break;
         case 'AENC':
             // 4.19  AENC Audio encryption
             // Owner identifier   <text string> $00
             // Preview start      $xx xx
             // Preview length     $xx xx
             // Encryption info    <binary data>
             if (!$this->IsWithinBitRange($source_data_array['previewstart'], 16, false)) {
                 throw new getid3_exception('Invalid Preview Start in ' . $frame_name . ' (' . $source_data_array['previewstart'] . ')');
             }
             if (!$this->IsWithinBitRange($source_data_array['previewlength'], 16, false)) {
                 throw new getid3_exception('Invalid Preview Length in ' . $frame_name . ' (' . $source_data_array['previewlength'] . ')');
             }
             $frame_data .= str_replace("", '', $source_data_array['ownerid']) . "";
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['previewstart'], 2, false);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['previewlength'], 2, false);
             $frame_data .= $source_data_array['encryptioninfo'];
             break;
         case 'LINK':
             // 4.20  LINK Linked information
             // Frame identifier               $xx xx xx xx
             // URL                            <text string> $00
             // ID and additional data         <text string(s)>
             if (!getid3_id3v2::valid_frame_name($source_data_array['frameid'], getid3_id3v2_write::major_version)) {
                 throw new getid3_exception('Invalid Frame Identifier in ' . $frame_name . ' (' . $source_data_array['frameid'] . ')');
             }
             if (!$this->valid_url($source_data_array['data'], true, false)) {
                 throw new getid3_exception('Invalid URL in ' . $frame_name . ' (' . $source_data_array['data'] . ')');
             }
             if (($source_data_array['frameid'] == 'AENC' || $source_data_array['frameid'] == 'APIC' || $source_data_array['frameid'] == 'GEOB' || $source_data_array['frameid'] == 'TXXX') && $source_data_array['additionaldata'] == '') {
                 throw new getid3_exception('Content Descriptor must be specified as additional data for Frame Identifier of ' . $source_data_array['frameid'] . ' in ' . $frame_name);
             }
             if ($source_data_array['frameid'] == 'USER' && getid3_id3v2::LanguageLookup($source_data_array['additionaldata'], true) == '') {
                 throw new getid3_exception('Language must be specified as additional data for Frame Identifier of ' . $source_data_array['frameid'] . ' in ' . $frame_name);
             }
             if ($source_data_array['frameid'] == 'PRIV' && $source_data_array['additionaldata'] == '') {
                 throw new getid3_exception('Owner Identifier must be specified as additional data for Frame Identifier of ' . $source_data_array['frameid'] . ' in ' . $frame_name);
             }
             if (($source_data_array['frameid'] == 'COMM' || $source_data_array['frameid'] == 'SYLT' || $source_data_array['frameid'] == 'USLT') && (getid3_id3v2::LanguageLookup(substr($source_data_array['additionaldata'], 0, 3), true) == '' || substr($source_data_array['additionaldata'], 3) == '')) {
                 throw new getid3_exception('Language followed by Content Descriptor must be specified as additional data for Frame Identifier of ' . $source_data_array['frameid'] . ' in ' . $frame_name);
             }
             $frame_data .= $source_data_array['frameid'];
             $frame_data .= str_replace("", '', $source_data_array['data']) . "";
             switch ($source_data_array['frameid']) {
                 case 'COMM':
                 case 'SYLT':
                 case 'USLT':
                 case 'PRIV':
                 case 'USER':
                 case 'AENC':
                 case 'APIC':
                 case 'GEOB':
                 case 'TXXX':
                     $frame_data .= $source_data_array['additionaldata'];
                     break;
                 case 'ASPI':
                 case 'ETCO':
                 case 'EQU2':
                 case 'MCID':
                 case 'MLLT':
                 case 'OWNE':
                 case 'RVA2':
                 case 'RVRB':
                 case 'SYTC':
                 case 'IPLS':
                 case 'RVAD':
                 case 'EQUA':
                     // no additional data required
                     break;
                 case 'RBUF':
                     if (getid3_id3v2_write::major_version == 3) {
                         // no additional data required
                     } else {
                         throw new getid3_exception($source_data_array['frameid'] . ' is not a valid Frame Identifier in ' . $frame_name . ' (in ID3v2.' . getid3_id3v2_write::major_version . ')');
                     }
                 default:
                     if (substr($source_data_array['frameid'], 0, 1) == 'T' || substr($source_data_array['frameid'], 0, 1) == 'W') {
                         // no additional data required
                     } else {
                         throw new getid3_exception($source_data_array['frameid'] . ' is not a valid Frame Identifier in ' . $frame_name . ' (in ID3v2.' . getid3_id3v2_write::major_version . ')');
                     }
             }
             break;
         case 'POSS':
             // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
             // Time stamp format         $xx
             // Position                  $xx (xx ...)
             if ($source_data_array['timestampformat'] < 1 || $source_data_array['timestampformat'] > 2) {
                 throw new getid3_exception('Invalid Time Stamp Format in ' . $frame_name . ' (' . $source_data_array['timestampformat'] . ') (valid = 1 or 2)');
             }
             if (!$this->IsWithinBitRange($source_data_array['position'], 32, false)) {
                 throw new getid3_exception('Invalid Position in ' . $frame_name . ' (' . $source_data_array['position'] . ') (range = 0 to 4294967295)');
             }
             $frame_data .= chr($source_data_array['timestampformat']);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['position'], 4, false);
             break;
         case 'USER':
             // 4.22  USER Terms of use (ID3v2.3+ only)
             // Text encoding        $xx
             // Language             $xx xx xx
             // The actual text      <text string according to encoding>
             if (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') {
                 throw new getid3_exception('Invalid Language in ' . $frame_name . ' (' . $source_data_array['language'] . ')');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= strtolower($source_data_array['language']);
             $frame_data .= $source_data_array['data'];
             break;
         case 'OWNE':
             // 4.23  OWNE Ownership frame (ID3v2.3+ only)
             // Text encoding     $xx
             // Price paid        <text string> $00
             // Date of purch.    <text string>
             // Seller            <text string according to encoding>
             if (!$this->IsANumber($source_data_array['pricepaid']['value'], false)) {
                 throw new getid3_exception('Invalid Price Paid in ' . $frame_name . ' (' . $source_data_array['pricepaid']['value'] . ')');
             }
             if (!$this->IsValidDateStampString($source_data_array['purchasedate'])) {
                 throw new getid3_exception('Invalid Date Of Purchase in ' . $frame_name . ' (' . $source_data_array['purchasedate'] . ') (format = YYYYMMDD)');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             $frame_data .= str_replace("", '', $source_data_array['pricepaid']['value']) . "";
             $frame_data .= $source_data_array['purchasedate'];
             $frame_data .= $source_data_array['seller'];
             break;
         case 'COMR':
             // 4.24  COMR Commercial frame (ID3v2.3+ only)
             // Text encoding      $xx
             // Price string       <text string> $00
             // Valid until        <text string>
             // Contact URL        <text string> $00
             // Received as        $xx
             // Name of seller     <text string according to encoding> $00 (00)
             // Description        <text string according to encoding> $00 (00)
             // Picture MIME type  <string> $00
             // Seller logo        <binary data>
             if (!$this->IsValidDateStampString($source_data_array['pricevaliduntil'])) {
                 throw new getid3_exception('Invalid Valid Until date in ' . $frame_name . ' (' . $source_data_array['pricevaliduntil'] . ') (format = YYYYMMDD)');
             }
             if (!$this->valid_url($source_data_array['contacturl'], false, true)) {
                 throw new getid3_exception('Invalid Contact URL in ' . $frame_name . ' (' . $source_data_array['contacturl'] . ') (allowed schemes: http, https, ftp, mailto)');
             }
             if (!$this->ID3v2IsValidCOMRreceivedAs($source_data_array['receivedasid'])) {
                 throw new getid3_exception('Invalid Received As byte in ' . $frame_name . ' (' . $source_data_array['contacturl'] . ') (range = 0 to 8)');
             }
             if (!$this->IsValidMIMEstring($source_data_array['mime'])) {
                 throw new getid3_exception('Invalid MIME Type in ' . $frame_name . ' (' . $source_data_array['mime'] . ')');
             }
             $frame_data .= chr(3);
             // UTF-8 encoding
             unset($price_string);
             foreach ($source_data_array['price'] as $key => $val) {
                 if ($this->ID3v2IsValidPriceString($key . $val['value'])) {
                     $price_strings[] = $key . $val['value'];
                 } else {
                     throw new getid3_exception('Invalid Price String in ' . $frame_name . ' (' . $key . $val['value'] . ')');
                 }
             }
             $frame_data .= implode('/', $price_strings);
             $frame_data .= $source_data_array['pricevaliduntil'];
             $frame_data .= str_replace("", '', $source_data_array['contacturl']) . "";
             $frame_data .= chr($source_data_array['receivedasid']);
             $frame_data .= $source_data_array['sellername'] . "";
             $frame_data .= $source_data_array['description'] . "";
             $frame_data .= $source_data_array['mime'] . "";
             $frame_data .= $source_data_array['logo'];
             break;
         case 'ENCR':
             // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
             // Owner identifier    <text string> $00
             // Method symbol       $xx
             // Encryption data     <binary data>
             if (!$this->IsWithinBitRange($source_data_array['methodsymbol'], 8, false)) {
                 throw new getid3_exception('Invalid Group Symbol in ' . $frame_name . ' (' . $source_data_array['methodsymbol'] . ') (range = 0 to 255)');
             }
             $frame_data .= str_replace("", '', $source_data_array['ownerid']) . "";
             $frame_data .= ord($source_data_array['methodsymbol']);
             $frame_data .= $source_data_array['data'];
             break;
         case 'GRID':
             // 4.26  GRID Group identification registration (ID3v2.3+ only)
             // Owner identifier      <text string> $00
             // Group symbol          $xx
             // Group dependent data  <binary data>
             if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) {
                 throw new getid3_exception('Invalid Group Symbol in ' . $frame_name . ' (' . $source_data_array['groupsymbol'] . ') (range = 0 to 255)');
             }
             $frame_data .= str_replace("", '', $source_data_array['ownerid']) . "";
             $frame_data .= ord($source_data_array['groupsymbol']);
             $frame_data .= $source_data_array['data'];
             break;
         case 'PRIV':
             // 4.27  PRIV Private frame (ID3v2.3+ only)
             // Owner identifier      <text string> $00
             // The private data      <binary data>
             $frame_data .= str_replace("", '', $source_data_array['ownerid']) . "";
             $frame_data .= $source_data_array['data'];
             break;
         case 'SIGN':
             // 4.28  SIGN Signature frame (ID3v2.4+ only)
             // Group symbol      $xx
             // Signature         <binary data>
             if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) {
                 throw new getid3_exception('Invalid Group Symbol in ' . $frame_name . ' (' . $source_data_array['groupsymbol'] . ') (range = 0 to 255)');
             }
             $frame_data .= ord($source_data_array['groupsymbol']);
             $frame_data .= $source_data_array['data'];
             break;
         case 'SEEK':
             // 4.29  SEEK Seek frame (ID3v2.4+ only)
             // Minimum offset to next tag       $xx xx xx xx
             if (!$this->IsWithinBitRange($source_data_array['data'], 32, false)) {
                 throw new getid3_exception('Invalid Minimum Offset in ' . $frame_name . ' (' . $source_data_array['data'] . ') (range = 0 to 4294967295)');
             }
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false);
             break;
         case 'ASPI':
             // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
             // Indexed data start (S)         $xx xx xx xx
             // Indexed data length (L)        $xx xx xx xx
             // Number of index points (N)     $xx xx
             // Bits per index point (b)       $xx
             //   Then for every index point the following data is included:
             // Fraction at index (Fi)          $xx (xx)
             if (!$this->IsWithinBitRange($source_data_array['datastart'], 32, false)) {
                 throw new getid3_exception('Invalid Indexed Data Start in ' . $frame_name . ' (' . $source_data_array['datastart'] . ') (range = 0 to 4294967295)');
             }
             if (!$this->IsWithinBitRange($source_data_array['datalength'], 32, false)) {
                 throw new getid3_exception('Invalid Indexed Data Length in ' . $frame_name . ' (' . $source_data_array['datalength'] . ') (range = 0 to 4294967295)');
             }
             if (!$this->IsWithinBitRange($source_data_array['indexpoints'], 16, false)) {
                 throw new getid3_exception('Invalid Number Of Index Points in ' . $frame_name . ' (' . $source_data_array['indexpoints'] . ') (range = 0 to 65535)');
             }
             if (!$this->IsWithinBitRange($source_data_array['bitsperpoint'], 8, false)) {
                 throw new getid3_exception('Invalid Bits Per Index Point in ' . $frame_name . ' (' . $source_data_array['bitsperpoint'] . ') (range = 0 to 255)');
             }
             if ($source_data_array['indexpoints'] != count($source_data_array['indexes'])) {
                 throw new getid3_exception('Number Of Index Points does not match actual supplied data in ' . $frame_name);
             }
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['datastart'], 4, false);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['datalength'], 4, false);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['indexpoints'], 2, false);
             $frame_data .= getid3_lib::BigEndian2String($source_data_array['bitsperpoint'], 1, false);
             foreach ($source_data_array['indexes'] as $key => $val) {
                 $frame_data .= getid3_lib::BigEndian2String($val, ceil($source_data_array['bitsperpoint'] / 8), false);
             }
             break;
         case 'RGAD':
             //   RGAD Replay Gain Adjustment
             //   http://privatewww.essex.ac.uk/~djmrob/replaygain/
             // Peak Amplitude                     $xx $xx $xx $xx
             // Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
             // Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
             //   a - name code
             //   b - originator code
             //   c - sign bit
             //   d - replay gain adjustment
             if ($source_data_array['track_adjustment'] > 51 || $source_data_array['track_adjustment'] < -51) {
                 throw new getid3_exception('Invalid Track Adjustment in ' . $frame_name . ' (' . $source_data_array['track_adjustment'] . ') (range = -51.0 to +51.0)');
             }
             if ($source_data_array['album_adjustment'] > 51 || $source_data_array['album_adjustment'] < -51) {
                 throw new getid3_exception('Invalid Album Adjustment in ' . $frame_name . ' (' . $source_data_array['album_adjustment'] . ') (range = -51.0 to +51.0)');
             }
             if (!$this->ID3v2IsValidRGADname($source_data_array['raw']['track_name'])) {
                 throw new getid3_exception('Invalid Track Name Code in ' . $frame_name . ' (' . $source_data_array['raw']['track_name'] . ') (range = 0 to 2)');
             }
             if (!$this->ID3v2IsValidRGADname($source_data_array['raw']['album_name'])) {
                 throw new getid3_exception('Invalid Album Name Code in ' . $frame_name . ' (' . $source_data_array['raw']['album_name'] . ') (range = 0 to 2)');
             }
             if (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['track_originator'])) {
                 throw new getid3_exception('Invalid Track Originator Code in ' . $frame_name . ' (' . $source_data_array['raw']['track_originator'] . ') (range = 0 to 3)');
             }
             if (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['album_originator'])) {
                 throw new getid3_exception('Invalid Album Originator Code in ' . $frame_name . ' (' . $source_data_array['raw']['album_originator'] . ') (range = 0 to 3)');
             }
             $frame_data .= getid3_lib::Float2String($source_data_array['peakamplitude'], 32);
             $frame_data .= getid3_lib::RGADgainString($source_data_array['raw']['track_name'], $source_data_array['raw']['track_originator'], $source_data_array['track_adjustment']);
             $frame_data .= getid3_lib::RGADgainString($source_data_array['raw']['album_name'], $source_data_array['raw']['album_originator'], $source_data_array['album_adjustment']);
             break;
         default:
             if ($frame_name[0] == 'T') {
                 // 4.2. T???  Text information frames
                 // Text encoding                $xx
                 // Information                  <text string(s) according to encoding>
                 $frame_data .= chr(3);
                 // UTF-8 encoding
                 $frame_data .= $source_data_array['data'];
             } elseif ($frame_name[0] == 'W') {
                 // 4.3. W???  URL link frames
                 // URL              <text string>
                 if (!$this->valid_url($source_data_array['data'], false, false)) {
                     throw new getid3_exception('Invalid URL in ' . $frame_name . ' (' . $source_data_array['data'] . ')');
                 } else {
                     $frame_data .= $source_data_array['data'];
                 }
             } else {
                 throw new getid3_exception($frame_name . ' not supported by generate_frame_data()');
             }
             break;
     }
     return $frame_data;
 }