Example #1
0
  /**
   * @param startByte
   * @param endByte
   * @return
   * @throws Exception
   * @return true if all the bytes between in the file between startByte and endByte are null, false
   *     otherwise
   */
  private boolean isFilePortionNull(int startByte, int endByte) throws IOException {
    logger.config("Checking file portion:" + Hex.asHex(startByte) + ":" + Hex.asHex(endByte));
    FileInputStream fis = null;
    FileChannel fc = null;
    try {
      fis = new FileInputStream(file);
      fc = fis.getChannel();
      fc.position(startByte);
      ByteBuffer bb = ByteBuffer.allocateDirect(endByte - startByte);
      fc.read(bb);
      while (bb.hasRemaining()) {
        if (bb.get() != 0) {
          return false;
        }
      }
    } finally {
      if (fc != null) {
        fc.close();
      }

      if (fis != null) {
        fis.close();
      }
    }
    return true;
  }
Example #2
0
  /**
   * Creates a new MP3File dataType and parse the tag from the given file Object, files can be
   * opened read only if required.
   *
   * @param file MP3 file
   * @param loadOptions decide what tags to load
   * @param readOnly causes the files to be opened readonly
   * @throws IOException on any I/O error
   * @throws TagException on any exception generated by this library.
   * @throws org.jaudiotagger.audio.exceptions.ReadOnlyFileException
   * @throws org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
   */
  public MP3File(File file, int loadOptions, boolean readOnly)
      throws IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException {
    RandomAccessFile newFile = null;
    try {
      this.file = file;

      // Check File accessibility
      newFile = checkFilePermissions(file, readOnly);

      // Read ID3v2 tag size (if tag exists) to allow audioHeader parsing to skip over tag
      long tagSizeReportedByHeader = AbstractID3v2Tag.getV2TagSizeIfExists(file);
      logger.config("TagHeaderSize:" + Hex.asHex(tagSizeReportedByHeader));
      audioHeader = new MP3AudioHeader(file, tagSizeReportedByHeader);

      // If the audio header is not straight after the end of the tag then search from start of file
      if (tagSizeReportedByHeader != ((MP3AudioHeader) audioHeader).getMp3StartByte()) {
        logger.config("First header found after tag:" + audioHeader);
        audioHeader = checkAudioStart(tagSizeReportedByHeader, (MP3AudioHeader) audioHeader);
      }

      // Read v1 tags (if any)
      readV1Tag(file, newFile, loadOptions);

      // Read v2 tags (if any)
      readV2Tag(file, loadOptions, (int) ((MP3AudioHeader) audioHeader).getMp3StartByte());

      // If we have a v2 tag use that, if we do not but have v1 tag use that
      // otherwise use nothing
      // TODO:if have both should we merge
      // rather than just returning specific ID3v22 tag, would it be better to return v24 version ?
      if (this.getID3v2Tag() != null) {
        tag = this.getID3v2Tag();
      } else if (id3v1tag != null) {
        tag = id3v1tag;
      }
    } finally {
      if (newFile != null) {
        newFile.close();
      }
    }
  }
Example #3
0
  /**
   * Regets the audio header starting from start of file, and write appropriate logging to indicate
   * potential problem to user.
   *
   * @param startByte
   * @param firstHeaderAfterTag
   * @return
   * @throws IOException
   * @throws InvalidAudioFrameException
   */
  private MP3AudioHeader checkAudioStart(long startByte, MP3AudioHeader firstHeaderAfterTag)
      throws IOException, InvalidAudioFrameException {
    MP3AudioHeader headerOne;
    MP3AudioHeader headerTwo;

    logger.warning(
        ErrorMessage.MP3_ID3TAG_LENGTH_INCORRECT.getMsg(
            file.getPath(),
            Hex.asHex(startByte),
            Hex.asHex(firstHeaderAfterTag.getMp3StartByte())));

    // because we cant agree on start location we reread the audioheader from the start of the file,
    // at least
    // this way we cant overwrite the audio although we might overwrite part of the tag if we write
    // this file
    // back later
    headerOne = new MP3AudioHeader(file, 0);
    logger.config("Checking from start:" + headerOne);

    // Although the id3 tag size appears to be incorrect at least we have found the same location
    // for the start
    // of audio whether we start searching from start of file or at the end of the alleged of file
    // so no real
    // problem
    if (firstHeaderAfterTag.getMp3StartByte() == headerOne.getMp3StartByte()) {
      logger.config(
          ErrorMessage.MP3_START_OF_AUDIO_CONFIRMED.getMsg(
              file.getPath(), Hex.asHex(headerOne.getMp3StartByte())));
      return firstHeaderAfterTag;
    } else {

      // We get a different value if read from start, can't guarantee 100% correct lets do some more
      // checks
      logger.config(
          (ErrorMessage.MP3_RECALCULATED_POSSIBLE_START_OF_MP3_AUDIO.getMsg(
              file.getPath(), Hex.asHex(headerOne.getMp3StartByte()))));

      // Same frame count so probably both audio headers with newAudioHeader being the first one
      if (firstHeaderAfterTag.getNumberOfFrames() == headerOne.getNumberOfFrames()) {
        logger.warning(
            (ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(
                file.getPath(), Hex.asHex(headerOne.getMp3StartByte()))));
        return headerOne;
      }

      // If the size reported by the tag header is a little short and there is only nulls between
      // the recorded value
      // and the start of the first audio found then we stick with the original header as more
      // likely that currentHeader
      // DataInputStream not really a header
      if (isFilePortionNull((int) startByte, (int) firstHeaderAfterTag.getMp3StartByte())) {
        return firstHeaderAfterTag;
      }

      // Skip to the next header (header 2, counting from start of file)
      headerTwo =
          new MP3AudioHeader(
              file, headerOne.getMp3StartByte() + headerOne.mp3FrameHeader.getFrameLength());

      // It matches the header we found when doing the original search from after the ID3Tag
      // therefore it
      // seems that newAudioHeader was a false match and the original header was correct
      if (headerTwo.getMp3StartByte() == firstHeaderAfterTag.getMp3StartByte()) {
        logger.warning(
            (ErrorMessage.MP3_START_OF_AUDIO_CONFIRMED.getMsg(
                file.getPath(), Hex.asHex(firstHeaderAfterTag.getMp3StartByte()))));
        return firstHeaderAfterTag;
      }

      // It matches the frameCount the header we just found so lends weight to the fact that the
      // audio does indeed start at new header
      // however it maybe that neither are really headers and just contain the same data being
      // misrepresented as headers.
      if (headerTwo.getNumberOfFrames() == headerOne.getNumberOfFrames()) {
        logger.warning(
            (ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(
                file.getPath(), Hex.asHex(headerOne.getMp3StartByte()))));
        return headerOne;
      }
      /// Doesnt match the frameCount lets go back to the original header
      else {
        logger.warning(
            (ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(
                file.getPath(), Hex.asHex(firstHeaderAfterTag.getMp3StartByte()))));
        return firstHeaderAfterTag;
      }
    }
  }