/**
  * parses the raw bytes of the frame body and stores the parsed values in the frame's fields.
  *
  * @throws IllegalArgumentException if an invalid value is detected while parsing the frame body's
  *     raw bytes.
  */
 @Override
 public void parse() throws IllegalArgumentException {
   try {
     setEncoding(Encoding.valueOf(buffer[0]));
   } catch (
       IllegalArgumentException
           ex) { // ignore the bad value and set it to ISO-8859-1 so we can continue parsing the
     // tag
     setEncoding(Encoding.ISO_8859_1);
   }
   try {
     setLanguage(
         Language.getLanguage(new String(buffer, 1, 3, Encoding.ISO_8859_1.getCharacterSet())));
   } catch (
       IllegalArgumentException
           ex) { // ignore the bad value and set it to english so we can continue parsing the tag
     setLanguage(Language.ENG);
   }
   text = new String(buffer, 4, buffer.length - 4, encoding.getCharacterSet()).trim();
   dirty =
       false; // we just read in the frame info, so the frame body's internal byte buffer is up to
   // date
 }
 /**
  * parses the raw bytes of the frame body and stores the parsed values in the frame's fields.
  *
  * @throws IllegalArgumentException if an invalid value is detected while parsing the frame body's
  *     raw bytes.
  */
 @Override
 public void parse() throws IllegalArgumentException {
   try {
     setEncoding(Encoding.valueOf(buffer[0]));
   } catch (
       IllegalArgumentException
           ex) { // ignore the bad value and set it to ISO-8859-1 so we can continue parsing the
                 // tag
     setEncoding(Encoding.ISO_8859_1);
   }
   try {
     setLanguage(
         Language.getLanguage(new String(buffer, 1, 3, Encoding.ISO_8859_1.getCharacterSet())));
   } catch (
       IllegalArgumentException
           ex) { // ignore the bad value and set it to english so we can continue parsing the tag
     setLanguage(Language.ENG);
   }
   try {
     setTimeStampFormat(TimeStampFormat.valueOf(buffer[4]));
   } catch (
       IllegalArgumentException
           ex) { // ignore the bad value and set it to milliseconds so we can continue parsing the
                 // tag
     setTimeStampFormat(TimeStampFormat.MS);
   }
   try {
     setContentType(ContentType.getContentType(buffer[5]));
   } catch (
       IllegalArgumentException
           ex) { // ignore the bad value and set it to other so we can continue parsing the tag
     setContentType(ContentType.OTHER);
   }
   nullTerminatorIndex = getNextNullTerminator(6, encoding);
   description = new String(buffer, 6, nullTerminatorIndex - 6, encoding.getCharacterSet()).trim();
   nullTerminatorIndex += encoding.getNumBytesInNullTerminator();
   Vector<SynchronizedLyric> lyrics = new Vector<SynchronizedLyric>();
   String text;
   int timeStamp;
   while (nullTerminatorIndex < buffer.length) {
     nextNullTerminatorIndex = getNextNullTerminator(nullTerminatorIndex, encoding);
     text =
         new String(
                 buffer,
                 nullTerminatorIndex,
                 nextNullTerminatorIndex - nullTerminatorIndex,
                 encoding.getCharacterSet())
             .trim();
     nullTerminatorIndex = nextNullTerminatorIndex + encoding.getNumBytesInNullTerminator();
     timeStamp =
         ((buffer[nullTerminatorIndex] & 0xFF) << 24)
             + ((buffer[nullTerminatorIndex + 1] & 0xFF) << 16)
             + ((buffer[nullTerminatorIndex + 2] & 0xFF) << 8)
             + (buffer[nullTerminatorIndex + 3] & 0xFF);
     nullTerminatorIndex += 4;
     lyrics.add(new SynchronizedLyric(text, timeStamp));
   }
   setSynchronizedLyrics(lyrics);
   dirty =
       false; // we just read in the frame info, so the frame body's internal byte buffer is up to
              // date
 }