/**
   * if the ID3v2.4 tag header's values have been modified, then resize the raw binary buffer and
   * store the new values there. When finished, reset the dirty flag to indicate that the buffer is
   * up to date, and the tag header is now ready to be saved to the .mp3 file.
   */
  public void setBuffer() {
    System.arraycopy(version.getIdBytes(), 0, header, 0, ID3TagVersion.NUM_ID_BYTES);
    header[5] =
        (byte)
            (unsynchronization
                ? header[5] | TAG_HEADER_UNSYNCHRONIZATION_MASK
                : header[5] & ~TAG_HEADER_UNSYNCHRONIZATION_MASK);
    header[5] =
        (byte)
            (extendedHeaderPresent
                ? header[5] | TAG_HEADER_EXTENDED_HEADER_PRESENT_MASK
                : header[5] & ~TAG_HEADER_EXTENDED_HEADER_PRESENT_MASK);
    header[5] =
        (byte)
            (experimentalIndicator
                ? header[5] | TAG_HEADER_EXPERIMENTAL_INDICATOR_MASK
                : header[5] & ~TAG_HEADER_EXPERIMENTAL_INDICATOR_MASK);
    header[5] =
        (byte)
            (footerPresent
                ? header[5] | TAG_HEADER_FOOTER_PRESENT_MASK
                : header[5] & ~TAG_HEADER_FOOTER_PRESENT_MASK);
    System.arraycopy(ID3v24FrameBodyUtility.synchsafeIntToBytes(tagSize), 0, header, 6, 4);

    dirty = false;
  }
  /**
   * gets a string representation of the ID3v2.4 tag header showing the values of the standard
   * ID3v2.4 tag header's fields.
   *
   * @return a string representation of the ID3v2.4 tag header.
   */
  @Override
  public String toString() {
    StringBuffer buffer = new StringBuffer();

    buffer.append("ID3v2.4 tag header\n");
    buffer.append("   bytes..................: " + header.length + " bytes\n");
    buffer.append("                            " + ID3v24FrameBodyUtility.hex(header, 27) + "\n");
    buffer.append("   version................: " + version + "\n");
    buffer.append("   tag size...............: " + tagSize + " bytes\n");
    buffer.append("   unsynchronization......: " + unsynchronization + "\n");
    buffer.append("   extended header present: " + extendedHeaderPresent + "\n");
    buffer.append("   experimental indicator.: " + experimentalIndicator + "\n");
    buffer.append("   footer present.........: " + footerPresent);

    return buffer.toString();
  }
  /**
   * This constructor is called when reading in an existing ID3v2.4 tag header from an .mp3 file.
   *
   * @param inputStream input stream pointing to the end of the standard ID3v2.4 tag header in the
   *     .mp3 file.
   * @throws IOException if the tag header can not be loaded from the .mp3 file.
   */
  public ID3v24TagHeader(InputStream inputStream) throws IOException {
    this();

    // read in the rest of the ID3v2.4 tag header (the bytes after the ID3v2.4 id)
    byte[] buffer = new byte[TAG_HEADER_SIZE - ID3TagVersion.NUM_ID_BYTES];
    if (inputStream.read(buffer) != buffer.length)
      throw new IOException("Unable to read in the ID3v2.4 tag header from the .mp3 file.");
    System.arraycopy(buffer, 0, header, ID3TagVersion.NUM_ID_BYTES, buffer.length);

    // parse the flags
    unsynchronization = (buffer[0] & TAG_HEADER_UNSYNCHRONIZATION_MASK) != 0;
    extendedHeaderPresent = (buffer[0] & TAG_HEADER_EXTENDED_HEADER_PRESENT_MASK) != 0;
    experimentalIndicator = (buffer[0] & TAG_HEADER_EXPERIMENTAL_INDICATOR_MASK) != 0;
    footerPresent = (buffer[0] & TAG_HEADER_FOOTER_PRESENT_MASK) != 0;

    // get the size of the tag (not counting this header)
    tagSize = ID3v24FrameBodyUtility.bytesToSynchsafeInt(buffer, 1);

    dirty = false;
  }