Esempio n. 1
0
 function table_var_dump($variable)
 {
     $returnstring = '';
     switch (gettype($variable)) {
         case 'array':
             $returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">';
             foreach ($variable as $key => $value) {
                 $returnstring .= '<TR><TD VALIGN="TOP"><B>' . str_replace(chr(0), ' ', $key) . '</B></TD>';
                 $returnstring .= '<TD VALIGN="TOP">' . gettype($value);
                 if (is_array($value)) {
                     $returnstring .= '&nbsp;(' . count($value) . ')';
                 } elseif (is_string($value)) {
                     $returnstring .= '&nbsp;(' . strlen($value) . ')';
                 }
                 if ($key == 'data' && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
                     require_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
                     $imageinfo = array();
                     $imagechunkcheck = GetDataImageSize($value, $imageinfo);
                     $DumpedImageSRC = (!empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3') . '.' . $variable['dataoffset'] . '.' . ImageTypesLookup($imagechunkcheck[2]);
                     if ($tempimagefile = fopen($DumpedImageSRC, 'wb')) {
                         fwrite($tempimagefile, $value);
                         fclose($tempimagefile);
                     }
                     $returnstring .= '</TD><TD><IMG SRC="' . $DumpedImageSRC . '" WIDTH="' . $imagechunkcheck[0] . '" HEIGHT="' . $imagechunkcheck[1] . '"></TD></TR>';
                 } else {
                     $returnstring .= '</TD><TD>' . table_var_dump($value) . '</TD></TR>';
                 }
             }
             $returnstring .= '</TABLE>';
             break;
         case 'boolean':
             $returnstring .= $variable ? 'TRUE' : 'FALSE';
             break;
         case 'integer':
         case 'double':
         case 'float':
             $returnstring .= $variable;
             break;
         case 'object':
         case 'null':
             $returnstring .= string_var_dump($variable);
             break;
         case 'string':
             $variable = str_replace(chr(0), ' ', $variable);
             $varlen = strlen($variable);
             for ($i = 0; $i < $varlen; $i++) {
                 if (ereg('[' . chr(0xa) . chr(0xd) . ' -;0-9A-Za-z]', $variable[$i])) {
                     $returnstring .= $variable[$i];
                 } else {
                     $returnstring .= '&#' . str_pad(ord($variable[$i]), 3, '0', STR_PAD_LEFT) . ';';
                 }
             }
             $returnstring = nl2br($returnstring);
             break;
         default:
             require_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
             $imageinfo = array();
             $imagechunkcheck = GetDataImageSize(substr($variable, 0, FREAD_BUFFER_SIZE), $imageinfo);
             if ($imagechunkcheck[2] >= 1 && $imagechunkcheck[2] <= 3) {
                 $returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">';
                 $returnstring .= '<TR><TD><B>type</B></TD><TD>' . ImageTypesLookup($imagechunkcheck[2]) . '</TD></TR>';
                 $returnstring .= '<TR><TD><B>width</B></TD><TD>' . number_format($imagechunkcheck[0]) . ' px</TD></TR>';
                 $returnstring .= '<TR><TD><B>height</B></TD><TD>' . number_format($imagechunkcheck[1]) . ' px</TD></TR>';
                 $returnstring .= '<TR><TD><B>size</B></TD><TD>' . number_format(strlen($variable)) . ' bytes</TD></TR></TABLE>';
             } else {
                 $returnstring .= nl2br(htmlspecialchars(str_replace(chr(0), ' ', $variable)));
             }
             break;
     }
     return $returnstring;
 }
function ID3v2FrameProcessing($frame_name, $frame_flags, &$ThisFileInfo)
{
    // define $frame_arrayindex once here (used for many frames), override or ignore as neccesary
    $frame_arrayindex = count($ThisFileInfo['id3v2']["{$frame_name}"]);
    // 'data', 'datalength'
    if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['data'])) {
        $frame_arrayindex--;
    }
    if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength'])) {
        $frame_arrayindex--;
    }
    if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'])) {
        $frame_arrayindex--;
    }
    if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['flags'])) {
        $frame_arrayindex--;
    }
    if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['timestampformat'])) {
        $frame_arrayindex--;
    }
    if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
        // frame flags are not part of the ID3v2.2 standard
        if ($ThisFileInfo['id3v2']['majorversion'] == 3) {
            //    Frame Header Flags
            //    %abc00000 %ijk00000
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 0, 1);
            // a - Tag alter preservation
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 1, 1);
            // b - File alter preservation
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 2, 1);
            // c - Read only
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['compression'] = (bool) substr($frame_flags, 8, 1);
            // i - Compression
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['Encryption'] = (bool) substr($frame_flags, 9, 1);
            // j - Encryption
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 10, 1);
            // k - Grouping identity
        } elseif ($ThisFileInfo['id3v2']['majorversion'] == 4) {
            //    Frame Header Flags
            //    %0abc0000 %0h00kmnp
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['TagAlterPreservation'] = (bool) substr($frame_flags, 1, 1);
            // a - Tag alter preservation
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['FileAlterPreservation'] = (bool) substr($frame_flags, 2, 1);
            // b - File alter preservation
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['ReadOnly'] = (bool) substr($frame_flags, 3, 1);
            // c - Read only
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['GroupingIdentity'] = (bool) substr($frame_flags, 9, 1);
            // h - Grouping identity
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['compression'] = (bool) substr($frame_flags, 12, 1);
            // k - Compression
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['Encryption'] = (bool) substr($frame_flags, 13, 1);
            // m - Encryption
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['Unsynchronisation'] = (bool) substr($frame_flags, 14, 1);
            // n - Unsynchronisation
            $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['DataLengthIndicator'] = (bool) substr($frame_flags, 15, 1);
            // p - Data length indicator
        }
        //    Frame-level de-unsynchronization - ID3v2.4
        if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']['Unsynchronisation'])) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = DeUnSynchronise($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        }
        //    Frame-level de-compression
        if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']['compression'])) {
            // it's on the wishlist :)
        }
    }
    if ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'UFID' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'UFI') {
        // 4.1   UFI  Unique file identifier
        //   There may be more than one 'UFID' frame in a tag,
        //   but only one with the same 'Owner identifier'.
        // <Header for 'Unique file identifier', ID: 'UFID'>
        // Owner identifier        <text string> $00
        // Identifier              <up to 64 bytes binary data>
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0));
        $frame_idstring = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['ownerid'] = $frame_idstring;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'TXXX' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'TXX') {
        // 4.2.2 TXX  User defined text information frame
        //   There may be more than one 'TXXX' frame in each tag,
        //   but only one with the same description.
        // <Header for 'User defined text information frame', ID: 'TXXX'>
        // Text encoding     $xx
        // Description       <text string according to encoding> $00 (00)
        // Value             <text string according to encoding>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'], $frame_textencoding);
        }
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata'];
        }
    } elseif ($frame_name[0] == 'T') {
        // 4.2. T??[?] Text information frame
        //   There may only be one text information frame of its kind in an tag.
        // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
        // excluding 'TXXX' described in 4.2.6.>
        // Text encoding                $xx
        // Information                  <text string(s) according to encoding>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        // $ThisFileInfo['id3v2']["$frame_name"]['data'] = substr($ThisFileInfo['id3v2']["$frame_name"]['data'], $frame_offset);
        // this one-line method should work, but as a safeguard against null-padded data, do it the safe way
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        if ($frame_terminatorpos) {
            // there are null bytes after the data - this is not according to spec
            // only use data up to first null byte
            $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        } else {
            // no null bytes following data, just use all data
            $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        }
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']['compression']) || !$ThisFileInfo['id3v2']["{$frame_name}"]['flags']['compression']) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"]['asciidata']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"]['asciidata'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'WXXX' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'WXX') {
        // 4.3.2 WXX  User defined URL link frame
        //   There may be more than one 'WXXX' frame in each tag,
        //   but only one with the same description
        // <Header for 'User defined URL link frame', ID: 'WXXX'>
        // Text encoding     $xx
        // Description       <text string according to encoding> $00 (00)
        // URL               <text string>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding));
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        if ($frame_terminatorpos) {
            // there are null bytes after the data - this is not according to spec
            // only use data up to first null byte
            $frame_urldata = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
        } else {
            // no null bytes following data, just use all data
            $frame_urldata = $ThisFileInfo['id3v2']["{$frame_name}"]['data'];
        }
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url'] = $frame_urldata;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url'];
        }
    } elseif ($frame_name[0] == 'W') {
        // 4.3. W??? URL link frames
        //   There may only be one URL link frame of its kind in a tag,
        //   except when stated otherwise in the frame description
        // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
        // described in 4.3.2.>
        // URL              <text string>
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url'] = trim($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] == 3 && $frame_name == 'IPLS' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'IPL') {
        // 4.4  IPL  Involved people list (ID3v2.2 only)
        //   There may only be one 'IPL' frame in each tag
        // <Header for 'User defined URL link frame', ID: 'IPL'>
        // Text encoding     $xx
        // People list strings    <textstrings>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $ThisFileInfo['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $ThisFileInfo['id3v2']["{$frame_name}"]['encodingid']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"]['asciidata']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"]['asciidata'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'MCDI' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'MCI') {
        // 4.5   MCI  Music CD identifier
        //   There may only be one 'MCDI' frame in each tag
        // <Header for 'Music CD identifier', ID: 'MCDI'>
        // CD TOC                <binary data>
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"]['data']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"]['data'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'ETCO' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'ETC') {
        // 4.6   ETC  Event timing codes
        //   There may only be one 'ETCO' frame in each tag
        // <Header for 'Event timing codes', ID: 'ETCO'>
        // 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.
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        while ($frame_offset < strlen($ThisFileInfo['id3v2']["{$frame_name}"]['data'])) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['typeid'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1);
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['type'] = ETCOEventLookup($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['typeid']);
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
            $frame_offset += 4;
        }
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'MLLT' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'MLL') {
        // 4.7   MLL MPEG location lookup table
        //   There may only be one 'MLLT' frame in each tag
        // <Header for 'Location lookup table', ID: 'MLLT'>
        // 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....
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['framesbetweenreferences'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 0, 2));
        $ThisFileInfo['id3v2']["{$frame_name}"]['bytesbetweenreferences'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 2, 3));
        $ThisFileInfo['id3v2']["{$frame_name}"]['msbetweenreferences'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 5, 3));
        $ThisFileInfo['id3v2']["{$frame_name}"]['bitsforbytesdeviation'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 8, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['bitsformsdeviation'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 9, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 10);
        while ($frame_offset < strlen($ThisFileInfo['id3v2']["{$frame_name}"]['data'])) {
            $deviationbitstream .= BigEndian2Bin(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        }
        while (strlen($deviationbitstream)) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $ThisFileInfo['id3v2']["{$frame_name}"]['bitsforbytesdeviation']));
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['msdeviation'] = bindec(substr($deviationbitstream, $ThisFileInfo['id3v2']["{$frame_name}"]['bitsforbytesdeviation'], $ThisFileInfo['id3v2']["{$frame_name}"]['bitsformsdeviation']));
            $deviationbitstream = substr($deviationbitstream, $ThisFileInfo['id3v2']["{$frame_name}"]['bitsforbytesdeviation'] + $ThisFileInfo['id3v2']["{$frame_name}"]['bitsformsdeviation']);
            $frame_arrayindex++;
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'SYTC' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'STC') {
        // 4.8   STC  Synchronised tempo codes
        //   There may only be one 'SYTC' frame in each tag
        // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
        // 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
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        while ($frame_offset < strlen($ThisFileInfo['id3v2']["{$frame_name}"]['data'])) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['tempo'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
            if ($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['tempo'] == 255) {
                $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['tempo'] += ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
            }
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
            $frame_offset += 4;
            $frame_arrayindex++;
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'USLT' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'ULT') {
        // 4.9   ULT  Unsynchronised lyric/text transcription
        //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
        //   in each tag, but only one with the same language and content descriptor.
        // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
        // Text encoding        $xx
        // Language             $xx xx xx
        // Content descriptor   <text string according to encoding> $00 (00)
        // Lyrics/text          <full text string according to encoding>
        require_once GETID3_INCLUDEPATH . 'getid3.frames.php';
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_language = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
        $frame_offset += 3;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = $ThisFileInfo['id3v2']["{$frame_name}"]['data'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['language'] = $frame_language;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['languagename'] = LanguageLookup($frame_language, false);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'], $frame_textencoding);
        }
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'], $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'SYLT' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'SLT') {
        // 4.10  SLT  Synchronised lyric/text
        //   There may be more than one 'SYLT' frame in each tag,
        //   but only one with the same language and content descriptor.
        // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
        // 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 ...)
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_language = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
        $frame_offset += 3;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['contenttypeid'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['contenttype'] = SYTLContentTypeLookup($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['contenttypeid']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['language'] = $frame_language;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['languagename'] = LanguageLookup($frame_language, false);
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $timestampindex = 0;
        $frame_remainingdata = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        while (strlen($frame_remainingdata)) {
            $frame_offset = 0;
            $frame_terminatorpos = strpos($frame_remainingdata, TextEncodingLookup('terminator', $frame_textencoding));
            if ($frame_terminatorpos === false) {
                $frame_remainingdata = '';
            } else {
                if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
                    $frame_terminatorpos++;
                    // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                }
                $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
                if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
                    $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'][$timestampindex]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'][$timestampindex]['data'], $frame_textencoding);
                }
                $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
                if ($timestampindex == 0 && ord($frame_remainingdata[0]) != 0) {
                    // timestamp probably omitted for first data item
                } else {
                    $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'][$timestampindex]['timestamp'] = BigEndian2Int(substr($frame_remainingdata, 0, 4));
                    $frame_remainingdata = substr($frame_remainingdata, 4);
                }
                $timestampindex++;
            }
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'COMM' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'COM') {
        // 4.11  COM  Comments
        //   There may be more than one comment frame in each tag,
        //   but only one with the same language and content descriptor.
        // <Header for 'Comment', ID: 'COMM'>
        // 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>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_language = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
        $frame_offset += 3;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $frame_text = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['language'] = $frame_language;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['languagename'] = LanguageLookup($frame_language, false);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = $frame_text;
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
        }
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata'] = RoughTranslateUnicodeToASCII($frame_text, $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidata'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 4 && $frame_name == 'RVA2') {
        // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
        //   There may be more than one 'RVA2' frame in each tag,
        //   but only one with the same identification string
        // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
        // 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_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0));
        $frame_idstring = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], 0, $frame_terminatorpos);
        if (ord($frame_idstring) === 0) {
            $frame_idstring = '';
        }
        $frame_remainingdata = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_idstring;
        while (strlen($frame_remainingdata)) {
            $frame_offset = 0;
            $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex][$frame_channeltypeid]['channeltypeid'] = $frame_channeltypeid;
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex][$frame_channeltypeid]['channeltype'] = RVA2ChannelTypeLookup($frame_channeltypeid);
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex][$frame_channeltypeid]['volumeadjust'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true);
            // 16-bit signed
            $frame_offset += 2;
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex][$frame_channeltypeid]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
            $frame_bytespeakvolume = ceil($ThisFileInfo['id3v2']["{$frame_name}"][$frame_channeltypeid]['bitspeakvolume'] / 8);
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex][$frame_channeltypeid]['peakvolume'] = BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
            $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex][$frame_channeltypeid]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] == 3 && $frame_name == 'RVAD' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'RVA') {
        // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
        //   There may only be one 'RVA' frame in each tag
        // <Header for 'Relative volume adjustment', ID: 'RVA'>
        // ID3v2.2 => Increment/decrement     %000000ba
        // ID3v2.3 => 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 ...)
        //   ID3v2.3 only, optional (not present in ID3v2.2):
        // 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 ...)
        //   ID3v2.3 only, optional (not present in ID3v2.2):
        // Relative volume change, center     $xx xx (xx ...) // e
        // Peak volume center                 $xx xx (xx ...)
        //   ID3v2.3 only, optional (not present in ID3v2.2):
        // Relative volume change, bass       $xx xx (xx ...) // f
        // Peak volume bass                   $xx xx (xx ...)
        $frame_offset = 0;
        $frame_incrdecrflags = BigEndian2Bin(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
        $ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
        $ThisFileInfo['id3v2']["{$frame_name}"]['bitsvolume'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $frame_bytesvolume = ceil($ThisFileInfo['id3v2']["{$frame_name}"]['bitsvolume'] / 8);
        $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['right'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
        if ($ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['right'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['right'] *= -1;
        }
        $frame_offset += $frame_bytesvolume;
        $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['left'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
        if ($ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['left'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['left'] *= -1;
        }
        $frame_offset += $frame_bytesvolume;
        $ThisFileInfo['id3v2']["{$frame_name}"]['peakvolume']['right'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
        $frame_offset += $frame_bytesvolume;
        $ThisFileInfo['id3v2']["{$frame_name}"]['peakvolume']['left'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
        $frame_offset += $frame_bytesvolume;
        if ($ThisFileInfo['id3v2']['majorversion'] == 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
            if (strlen($ThisFileInfo['id3v2']["{$frame_name}"]['data']) > 0) {
                $ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
                $ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
                $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['rightrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                if ($ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['rightrear'] === false) {
                    $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['rightrear'] *= -1;
                }
                $frame_offset += $frame_bytesvolume;
                $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['leftrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                if ($ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['leftrear'] === false) {
                    $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['leftrear'] *= -1;
                }
                $frame_offset += $frame_bytesvolume;
                $ThisFileInfo['id3v2']["{$frame_name}"]['peakvolume']['rightrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                $frame_offset += $frame_bytesvolume;
                $ThisFileInfo['id3v2']["{$frame_name}"]['peakvolume']['leftrear'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                $frame_offset += $frame_bytesvolume;
            }
            $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
            if (strlen($ThisFileInfo['id3v2']["{$frame_name}"]['data']) > 0) {
                $ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
                $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['center'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                if ($ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['center'] === false) {
                    $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['center'] *= -1;
                }
                $frame_offset += $frame_bytesvolume;
                $ThisFileInfo['id3v2']["{$frame_name}"]['peakvolume']['center'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                $frame_offset += $frame_bytesvolume;
            }
            $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
            if (strlen($ThisFileInfo['id3v2']["{$frame_name}"]['data']) > 0) {
                $ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
                $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['bass'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                if ($ThisFileInfo['id3v2']["{$frame_name}"]['incdec']['bass'] === false) {
                    $ThisFileInfo['id3v2']["{$frame_name}"]['volumechange']['bass'] *= -1;
                }
                $frame_offset += $frame_bytesvolume;
                $ThisFileInfo['id3v2']["{$frame_name}"]['peakvolume']['bass'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesvolume));
                $frame_offset += $frame_bytesvolume;
            }
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 4 && $frame_name == 'EQU2') {
        // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
        //   There may be more than one 'EQU2' frame in each tag,
        //   but only one with the same identification string
        // <Header of 'Equalisation (2)', ID: 'EQU2'>
        // 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
        $frame_offset = 0;
        $frame_interpolationmethod = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_idstring = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_idstring) === 0) {
            $frame_idstring = '';
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_idstring;
        $frame_remainingdata = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(chr(0)));
        while (strlen($frame_remainingdata)) {
            $frame_frequency = BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'][$frame_frequency] = BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
            $frame_remainingdata = substr($frame_remainingdata, 4);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['interpolationmethod'] = $frame_interpolationmethod;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] == 3 && $frame_name == 'EQUA' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'EQU') {
        // 4.13  EQU  Equalisation (ID3v2.2 only)
        //   There may only be one 'EQUA' frame in each tag
        // <Header for 'Relative volume adjustment', ID: 'EQU'>
        // 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 ...)
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['adjustmentbits'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1);
        $frame_adjustmentbytes = ceil($ThisFileInfo['id3v2']["{$frame_name}"]['adjustmentbits'] / 8);
        $frame_remainingdata = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        while (strlen($frame_remainingdata)) {
            $frame_frequencystr = BigEndian2Bin(substr($frame_remainingdata, 0, 2));
            $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
            $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_frequency]['incdec'] = $frame_incdec;
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_frequency]['adjustment'] = BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
            if ($ThisFileInfo['id3v2']["{$frame_name}"][$frame_frequency]['incdec'] === false) {
                $ThisFileInfo['id3v2']["{$frame_name}"][$frame_frequency]['adjustment'] *= -1;
            }
            $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'RVRB' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'REV') {
        // 4.14  REV  Reverb
        //   There may only be one 'RVRB' frame in each tag.
        // <Header for 'Reverb', ID: 'RVRB'>
        // 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
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['left'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $ThisFileInfo['id3v2']["{$frame_name}"]['right'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $ThisFileInfo['id3v2']["{$frame_name}"]['bouncesL'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['bouncesR'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['feedbackLL'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['feedbackLR'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['feedbackRR'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['feedbackRL'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['premixLR'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['premixRL'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'APIC' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'PIC') {
        // 4.15  PIC  Attached picture
        //   There may be several pictures attached to one file,
        //   each in their individual 'APIC' frame, but only one
        //   with the same content descriptor
        // <Header for 'Attached picture', ID: 'APIC'>
        // Text encoding      $xx
        // ID3v2.3+ => MIME type          <text string> $00
        // ID3v2.2  => Image format       $xx xx xx
        // Picture type       $xx
        // Description        <text string according to encoding> $00 (00)
        // Picture data       <binary data>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        if ($ThisFileInfo['id3v2']['majorversion'] == 2) {
            $frame_imagetype = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
            if (strtolower($frame_imagetype) == 'ima') {
                // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
                // MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoff@pacbell.net)
                $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
                $frame_mimetype = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
                if (ord($frame_mimetype) === 0) {
                    $frame_mimetype = '';
                }
                $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
                if ($frame_imagetype == 'JPEG') {
                    $frame_imagetype = 'JPG';
                }
                $frame_offset = $frame_terminatorpos + strlen(chr(0));
            } else {
                $frame_offset += 3;
            }
        }
        if ($ThisFileInfo['id3v2']['majorversion'] > 2) {
            $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
            $frame_mimetype = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
            if (ord($frame_mimetype) === 0) {
                $frame_mimetype = '';
            }
            $frame_offset = $frame_terminatorpos + strlen(chr(0));
        }
        $frame_picturetype = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        if ($ThisFileInfo['id3v2']['majorversion'] == 2) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['imagetype'] = $frame_imagetype;
        } else {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['mime'] = $frame_mimetype;
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['picturetypeid'] = $frame_picturetype;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['picturetype'] = APICPictureTypeLookup($frame_picturetype);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)));
        require_once GETID3_INCLUDEPATH . 'getid3.getimagesize.php';
        $imagechunkcheck = GetDataImageSize($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data']);
        if ($imagechunkcheck[2] >= 1 && $imagechunkcheck[2] <= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['image_mime'] = ImageTypesLookup($imagechunkcheck[2]);
            if ($imagechunkcheck[0]) {
                $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['image_width'] = $imagechunkcheck[0];
            }
            if ($imagechunkcheck[1]) {
                $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['image_height'] = $imagechunkcheck[1];
            }
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['image_bytes'] = strlen($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength'])) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        }
        if (isset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'])) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'GEOB' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'GEO') {
        // 4.16  GEO  General encapsulated object
        //   There may be more than one 'GEOB' frame in each tag,
        //   but only one with the same content descriptor
        // <Header for 'General encapsulated object', ID: 'GEOB'>
        // 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>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_mimetype = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_mimetype) === 0) {
            $frame_mimetype = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_filename = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_filename) === 0) {
            $frame_filename = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['objectdata'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['mime'] = $frame_mimetype;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['filename'] = $frame_filename;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            if (!isset($ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression']) || $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags']['compression'] === false) {
                $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
            }
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'PCNT' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'CNT') {
        // 4.17  CNT  Play counter
        //   There may only be one 'PCNT' frame in each tag.
        //   When the counter reaches all one's, one byte is inserted in
        //   front of the counter thus making the counter eight bits bigger
        // <Header for 'Play counter', ID: 'PCNT'>
        // Counter        $xx xx xx xx (xx ...)
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = BigEndian2Int($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'POPM' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'POP') {
        // 4.18  POP  Popularimeter
        //   There may be more than one 'POPM' frame in each tag,
        //   but only one with the same email address
        // <Header for 'Popularimeter', ID: 'POPM'>
        // Email to user   <text string> $00
        // Rating          $xx
        // Counter         $xx xx xx xx (xx ...)
        $frame_offset = 0;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_emailaddress = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_emailaddress) === 0) {
            $frame_emailaddress = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $frame_rating = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['email'] = $frame_emailaddress;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['rating'] = $frame_rating;
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'RBUF' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'BUF') {
        // 4.19  BUF  Recommended buffer size
        //   There may only be one 'RBUF' frame in each tag
        // <Header for 'Recommended buffer size', ID: 'RBUF'>
        // Buffer size               $xx xx xx
        // Embedded info flag        %0000000x
        // Offset to next tag        $xx xx xx xx
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['buffersize'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3));
        $frame_offset += 3;
        $frame_embeddedinfoflags = BigEndian2Bin(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
        $ThisFileInfo['id3v2']["{$frame_name}"]['nexttagoffset'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'CRM') {
        // 4.20  Encrypted meta frame (ID3v2.2 only)
        //   There may be more than one 'CRM' frame in a tag,
        //   but only one with the same 'owner identifier'
        // <Header for 'Encrypted meta frame', ID: 'CRM'>
        // Owner identifier      <textstring> $00 (00)
        // Content/explanation   <textstring> $00 (00)
        // Encrypted datablock   <binary data>
        $frame_offset = 0;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_ownerid = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_ownerid) === 0) {
            $frame_ownerid = count($ThisFileInfo['id3v2']["{$frame_name}"]) - 1;
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['ownerid'] = $frame_ownerid;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'AENC' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'CRA') {
        // 4.21  CRA  Audio encryption
        //   There may be more than one 'AENC' frames in a tag,
        //   but only one with the same 'Owner identifier'
        // <Header for 'Audio encryption', ID: 'AENC'>
        // Owner identifier   <text string> $00
        // Preview start      $xx xx
        // Preview length     $xx xx
        // Encryption info    <binary data>
        $frame_offset = 0;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_ownerid = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_ownerid) === 0) {
            $frame_ownerid == '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['ownerid'] = $frame_ownerid;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['previewstart'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['previewlength'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encryptioninfo'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_ownerid}"]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'LINK' || $ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == 'LNK') {
        // 4.22  LNK  Linked information
        //   There may be more than one 'LINK' frame in a tag,
        //   but only one with the same contents
        // <Header for 'Linked information', ID: 'LINK'>
        // ID3v2.3+ => Frame identifier   $xx xx xx xx
        // ID3v2.2  => Frame identifier   $xx xx xx
        // URL                            <text string> $00
        // ID and additional data         <text string(s)>
        $frame_offset = 0;
        if ($ThisFileInfo['id3v2']['majorversion'] == 2) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['frameid'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
            $frame_offset += 3;
        } else {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['frameid'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4);
            $frame_offset += 4;
        }
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_url = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_url) === 0) {
            $frame_url = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url'] = $frame_url;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['additionaldata'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        if ($ThisFileInfo['id3v2']['majorversion'] >= 3) {
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
            unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['url'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'POSS') {
        // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
        //   There may only be one 'POSS' frame in each tag
        // <Head for 'Position synchronisation', ID: 'POSS'>
        // Time stamp format         $xx
        // Position                  $xx (xx ...)
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['timestampformat'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['position'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset));
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'USER') {
        // 4.22  USER Terms of use (ID3v2.3+ only)
        //   There may be more than one 'Terms of use' frame in a tag,
        //   but only one with the same 'Language'
        // <Header for 'Terms of use frame', ID: 'USER'>
        // Text encoding        $xx
        // Language             $xx xx xx
        // The actual text      <text string according to encoding>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_language = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 3);
        $frame_offset += 3;
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['language'] = $frame_language;
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['languagename'] = LanguageLookup($frame_language, false);
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        if (!$ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['flags']['compression']) {
            $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['asciidata'] = RoughTranslateUnicodeToASCII($ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['data'], $frame_textencoding);
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
        if (FrameNameShortLookup($frame_name) && $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['asciidata']) {
            $ThisFileInfo['id3v2']['comments'][FrameNameShortLookup($frame_name)][] = $ThisFileInfo['id3v2']["{$frame_name}"]["{$frame_language}"]['asciidata'];
        }
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'OWNE') {
        // 4.23  OWNE Ownership frame (ID3v2.3+ only)
        //   There may only be one 'OWNE' frame in a tag
        // <Header for 'Ownership frame', ID: 'OWNE'>
        // Text encoding     $xx
        // Price paid        <text string> $00
        // Date of purch.    <text string>
        // Seller            <text string according to encoding>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $ThisFileInfo['id3v2']["{$frame_name}"]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_pricepaid = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"]['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
        $ThisFileInfo['id3v2']["{$frame_name}"]['pricepaid']['currency'] = LookupCurrency($ThisFileInfo['id3v2']["{$frame_name}"]['pricepaid']['currencyid'], 'units');
        $ThisFileInfo['id3v2']["{$frame_name}"]['pricepaid']['value'] = substr($frame_pricepaid, 3);
        $ThisFileInfo['id3v2']["{$frame_name}"]['purchasedate'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 8);
        if (!IsValidDateStampString($ThisFileInfo['id3v2']["{$frame_name}"]['purchasedate'])) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['purchasedateunix'] = mktime(0, 0, 0, substr($ThisFileInfo['id3v2']["{$frame_name}"]['purchasedate'], 4, 2), substr($ThisFileInfo['id3v2']["{$frame_name}"]['purchasedate'], 6, 2), substr($ThisFileInfo['id3v2']["{$frame_name}"]['purchasedate'], 0, 4));
        }
        $frame_offset += 8;
        $ThisFileInfo['id3v2']["{$frame_name}"]['seller'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'COMR') {
        // 4.24  COMR Commercial frame (ID3v2.3+ only)
        //   There may be more than one 'commercial frame' in a tag,
        //   but no two may be identical
        // <Header for 'Commercial frame', ID: 'COMR'>
        // 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>
        $frame_offset = 0;
        $frame_textencoding = TextEncodingVerified(ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1)), $ThisFileInfo, $frame_name);
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_pricestring = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $frame_rawpricearray = explode('/', $frame_pricestring);
        foreach ($frame_rawpricearray as $key => $val) {
            $frame_currencyid = substr($val, 0, 3);
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['price']["{$frame_currencyid}"]['currency'] = LookupCurrency($frame_currencyid, 'units');
            $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['price']["{$frame_currencyid}"]['value'] = substr($val, 3);
        }
        $frame_datestring = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 8);
        $frame_offset += 8;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_contacturl = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $frame_receivedasid = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_sellername = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_sellername) === 0) {
            $frame_sellername = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], TextEncodingLookup('terminator', $frame_textencoding), $frame_offset);
        if (ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding)), 1)) === 0) {
            $frame_terminatorpos++;
            // strpos() fooled because 2nd byte of Unicode chars are often 0x00
        }
        $frame_description = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_description) === 0) {
            $frame_description = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(TextEncodingLookup('terminator', $frame_textencoding));
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_mimetype = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $frame_sellerlogo = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encodingid'] = $frame_textencoding;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['encoding'] = TextEncodingLookup('encoding', $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['pricevaliduntil'] = $frame_datestring;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['contacturl'] = $frame_contacturl;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['receivedasid'] = $frame_receivedasid;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['receivedas'] = COMRReceivedAsLookup($frame_receivedasid);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['sellername'] = $frame_sellername;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciisellername'] = RoughTranslateUnicodeToASCII($frame_sellername, $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['description'] = $frame_description;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['asciidescription'] = RoughTranslateUnicodeToASCII($frame_description, $frame_textencoding);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['mime'] = $frame_mimetype;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['logo'] = $frame_sellerlogo;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'ENCR') {
        // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
        //   There may be several 'ENCR' frames in a tag,
        //   but only one containing the same symbol
        //   and only one containing the same owner identifier
        // <Header for 'Encryption method registration', ID: 'ENCR'>
        // Owner identifier    <text string> $00
        // Method symbol       $xx
        // Encryption data     <binary data>
        $frame_offset = 0;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_ownerid = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_ownerid) === 0) {
            $frame_ownerid = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['ownerid'] = $frame_ownerid;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['methodsymbol'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'GRID') {
        // 4.26  GRID Group identification registration (ID3v2.3+ only)
        //   There may be several 'GRID' frames in a tag,
        //   but only one containing the same symbol
        //   and only one containing the same owner identifier
        // <Header for 'Group ID registration', ID: 'GRID'>
        // Owner identifier      <text string> $00
        // Group symbol          $xx
        // Group dependent data  <binary data>
        $frame_offset = 0;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_ownerid = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_ownerid) === 0) {
            $frame_ownerid = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['ownerid'] = $frame_ownerid;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['groupsymbol'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'PRIV') {
        // 4.27  PRIV Private frame (ID3v2.3+ only)
        //   The tag may contain more than one 'PRIV' frame
        //   but only with different contents
        // <Header for 'Private frame', ID: 'PRIV'>
        // Owner identifier      <text string> $00
        // The private data      <binary data>
        $frame_offset = 0;
        $frame_terminatorpos = strpos($ThisFileInfo['id3v2']["{$frame_name}"]['data'], chr(0), $frame_offset);
        $frame_ownerid = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
        if (ord($frame_ownerid) === 0) {
            $frame_ownerid = '';
        }
        $frame_offset = $frame_terminatorpos + strlen(chr(0));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['ownerid'] = $frame_ownerid;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 4 && $frame_name == 'SIGN') {
        // 4.28  SIGN Signature frame (ID3v2.4+ only)
        //   There may be more than one 'signature frame' in a tag,
        //   but no two may be identical
        // <Header for 'Signature frame', ID: 'SIGN'>
        // Group symbol      $xx
        // Signature         <binary data>
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['groupsymbol'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['data'] = substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['flags'] = $ThisFileInfo['id3v2']["{$frame_name}"]['flags'];
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['flags']);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['datalength'] = $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['datalength']);
        $ThisFileInfo['id3v2']["{$frame_name}"][$frame_arrayindex]['dataoffset'] = $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'];
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 4 && $frame_name == 'SEEK') {
        // 4.29  SEEK Seek frame (ID3v2.4+ only)
        //   There may only be one 'seek frame' in a tag
        // <Header for 'Seek frame', ID: 'SEEK'>
        // Minimum offset to next tag       $xx xx xx xx
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 4 && $frame_name == 'ASPI') {
        // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
        //   There may only be one 'audio seek point index' frame in a tag
        // <Header for 'Seek Point Index', ID: 'ASPI'>
        // 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)
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['datastart'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
        $frame_offset += 4;
        $ThisFileInfo['id3v2']["{$frame_name}"]['indexeddatalength'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
        $frame_offset += 4;
        $ThisFileInfo['id3v2']["{$frame_name}"]['indexpoints'] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $ThisFileInfo['id3v2']["{$frame_name}"]['bitsperpoint'] = ord(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset++, 1));
        $frame_bytesperpoint = ceil($ThisFileInfo['id3v2']["{$frame_name}"]['bitsperpoint'] / 8);
        for ($i = 0; $i < $frame_indexpoints; $i++) {
            $ThisFileInfo['id3v2']["{$frame_name}"]['indexes'][$i] = BigEndian2Int(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, $frame_bytesperpoint));
            $frame_offset += $frame_bytesperpoint;
        }
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    } elseif ($ThisFileInfo['id3v2']['majorversion'] >= 3 && $frame_name == 'RGAD') {
        // Replay Gain Adjustment
        // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
        //   There may only be one 'RGAD' frame in a tag
        // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
        // 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
        require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
        $frame_offset = 0;
        $ThisFileInfo['id3v2']["{$frame_name}"]['peakamplitude'] = BigEndian2Float(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 4));
        $frame_offset += 4;
        $radioadjustment = Dec2Bin(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $audiophileadjustment = Dec2Bin(substr($ThisFileInfo['id3v2']["{$frame_name}"]['data'], $frame_offset, 2));
        $frame_offset += 2;
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['name'] = Bin2Dec(substr($radioadjustment, 0, 3));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['originator'] = Bin2Dec(substr($radioadjustment, 3, 3));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['signbit'] = Bin2Dec(substr($radioadjustment, 6, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['adjustment'] = Bin2Dec(substr($radioadjustment, 7, 9));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['name'] = Bin2Dec(substr($audiophileadjustment, 0, 3));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['originator'] = Bin2Dec(substr($audiophileadjustment, 3, 3));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['signbit'] = Bin2Dec(substr($audiophileadjustment, 6, 1));
        $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['adjustment'] = Bin2Dec(substr($audiophileadjustment, 7, 9));
        $ThisFileInfo['id3v2']["{$frame_name}"]['radio']['name'] = RGADnameLookup($ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['name']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['originator']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['adjustment'], $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['radio']['signbit']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['audiophile']['name'] = RGADnameLookup($ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['name']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['originator']);
        $ThisFileInfo['id3v2']["{$frame_name}"]['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['adjustment'], $ThisFileInfo['id3v2']["{$frame_name}"]['raw']['audiophile']['signbit']);
        $ThisFileInfo['replay_gain']['radio']['peak'] = $ThisFileInfo['id3v2']["{$frame_name}"]['peakamplitude'];
        $ThisFileInfo['replay_gain']['radio']['originator'] = $ThisFileInfo['id3v2']["{$frame_name}"]['radio']['originator'];
        $ThisFileInfo['replay_gain']['radio']['adjustment'] = $ThisFileInfo['id3v2']["{$frame_name}"]['radio']['adjustment'];
        $ThisFileInfo['replay_gain']['audiophile']['originator'] = $ThisFileInfo['id3v2']["{$frame_name}"]['audiophile']['originator'];
        $ThisFileInfo['replay_gain']['audiophile']['adjustment'] = $ThisFileInfo['id3v2']["{$frame_name}"]['audiophile']['adjustment'];
        $ThisFileInfo['id3v2']["{$frame_name}"]['framenamelong'] = FrameNameLongLookup($frame_name);
        unset($ThisFileInfo['id3v2']["{$frame_name}"]['data']);
    }
    return true;
}