/** * Read v1 tag * * @param file * @param newFile * @param loadOptions * @throws IOException */ private void readV1Tag(File file, RandomAccessFile newFile, int loadOptions) throws IOException { if ((loadOptions & LOAD_IDV1TAG) != 0) { logger.finer("Attempting to read id3v1tags"); try { id3v1tag = new ID3v11Tag(newFile, file.getName()); } catch (TagNotFoundException ex) { logger.config("No ids3v11 tag found"); } try { if (id3v1tag == null) { id3v1tag = new ID3v1Tag(newFile, file.getName()); } } catch (TagNotFoundException ex) { logger.config("No id3v1 tag found"); } } }
/** * Calculates hash with algorithm "MD5", "SHA-1" or SHA-256". Hash is calculated EXCLUDING * meta-data, like id3v1 or id3v2 * * @return byte[] hash value in byte * @param String algorithm * @param int buffersize * @throws IOException * @throws InvalidAudioFrameException * @throws NoSuchAlgorithmException */ public byte[] getHash(String algorithm, int bufferSize) throws InvalidAudioFrameException, IOException, NoSuchAlgorithmException { File mp3File = getFile(); long startByte = getMP3StartByte(mp3File); int id3v1TagSize = 0; if (hasID3v1Tag()) { ID3v1Tag id1tag = getID3v1Tag(); id3v1TagSize = id1tag.getSize(); } InputStream inStream = Files.newInputStream(Paths.get(mp3File.getAbsolutePath())); byte[] buffer = new byte[bufferSize]; MessageDigest digest = MessageDigest.getInstance(algorithm); inStream.skip(startByte); int read; long totalSize = mp3File.length() - startByte - id3v1TagSize; int pointer = buffer.length; while (pointer <= totalSize) { read = inStream.read(buffer); digest.update(buffer, 0, read); pointer += buffer.length; } read = inStream.read(buffer, 0, (int) totalSize - pointer + buffer.length); digest.update(buffer, 0, read); byte[] hash = digest.digest(); return hash; }
/** * Check can write to file * * @param file * @throws IOException */ public void precheck(File file) throws IOException { if (!file.exists()) { logger.severe( ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName())); throw new IOException( ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName())); } if (!file.canWrite()) { logger.severe(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(file.getName())); throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(file.getName())); } if (file.length() <= MINIMUM_FILESIZE) { logger.severe( ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getName())); throw new IOException( ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getName())); } }
/** * Saves the tags in this dataType to the file argument. It will be saved as * TagConstants.MP3_FILE_SAVE_WRITE * * @param fileToSave file to save the this dataTypes tags to * @throws FileNotFoundException if unable to find file * @throws IOException on any I/O error */ public void save(File fileToSave) throws IOException { // Ensure we are dealing with absolute filepaths not relative ones File file = fileToSave.getAbsoluteFile(); logger.config("Saving : " + file.getPath()); // Checks before starting write precheck(file); RandomAccessFile rfile = null; try { // ID3v2 Tag if (TagOptionSingleton.getInstance().isId3v2Save()) { if (id3v2tag == null) { rfile = new RandomAccessFile(file, "rw"); (new ID3v24Tag()).delete(rfile); (new ID3v23Tag()).delete(rfile); (new ID3v22Tag()).delete(rfile); logger.config("Deleting ID3v2 tag:" + file.getName()); rfile.close(); } else { logger.config("Writing ID3v2 tag:" + file.getName()); final MP3AudioHeader mp3AudioHeader = (MP3AudioHeader) this.getAudioHeader(); final long mp3StartByte = mp3AudioHeader.getMp3StartByte(); final long newMp3StartByte = id3v2tag.write(file, mp3StartByte); if (mp3StartByte != newMp3StartByte) { logger.config("New mp3 start byte: " + newMp3StartByte); mp3AudioHeader.setMp3StartByte(newMp3StartByte); } } } rfile = new RandomAccessFile(file, "rw"); // Lyrics 3 Tag if (TagOptionSingleton.getInstance().isLyrics3Save()) { if (lyrics3tag != null) { lyrics3tag.write(rfile); } } // ID3v1 tag if (TagOptionSingleton.getInstance().isId3v1Save()) { logger.config("Processing ID3v1"); if (id3v1tag == null) { logger.config("Deleting ID3v1"); (new ID3v1Tag()).delete(rfile); } else { logger.config("Saving ID3v1"); id3v1tag.write(rfile); } } } catch (FileNotFoundException ex) { logger.log( Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName()), ex); throw ex; } catch (IOException iex) { logger.log( Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(file.getName(), iex.getMessage()), iex); throw iex; } catch (RuntimeException re) { logger.log( Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(file.getName(), re.getMessage()), re); throw re; } finally { if (rfile != null) { rfile.close(); } } }
/** * Read V2tag if exists * * <p>TODO:shouldn't we be handing TagExceptions:when will they be thrown * * @param file * @param loadOptions * @throws IOException * @throws TagException */ private void readV2Tag(File file, int loadOptions, int startByte) throws IOException, TagException { // We know where the actual Audio starts so load all the file from start to that point into // a buffer then we can read the IDv2 information without needing any more File I/O if (startByte >= AbstractID3v2Tag.TAG_HEADER_LENGTH) { logger.finer("Attempting to read id3v2tags"); FileInputStream fis = null; FileChannel fc = null; ByteBuffer bb; try { fis = new FileInputStream(file); fc = fis.getChannel(); bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, startByte); } // #JAUDIOTAGGER-419:If reading networked file map can fail so just copy bytes instead catch (IOException ioe) { bb = ByteBuffer.allocate(startByte); fc.read(bb, 0); } finally { if (fc != null) { fc.close(); } if (fis != null) { fis.close(); } } try { bb.rewind(); if ((loadOptions & LOAD_IDV2TAG) != 0) { logger.config("Attempting to read id3v2tags"); try { this.setID3v2Tag(new ID3v24Tag(bb, file.getName())); } catch (TagNotFoundException ex) { logger.config("No id3v24 tag found"); } try { if (id3v2tag == null) { this.setID3v2Tag(new ID3v23Tag(bb, file.getName())); } } catch (TagNotFoundException ex) { logger.config("No id3v23 tag found"); } try { if (id3v2tag == null) { this.setID3v2Tag(new ID3v22Tag(bb, file.getName())); } } catch (TagNotFoundException ex) { logger.config("No id3v22 tag found"); } } } finally { // Workaround for 4724038 on Windows bb.clear(); if (bb.isDirect() && !TagOptionSingleton.getInstance().isAndroid()) { // Reflection substitute for following code: // ((sun.nio.ch.DirectBuffer) bb).cleaner().clean(); // which causes exception on Android - Sun NIO classes are not available try { Class<?> clazz = Class.forName("sun.nio.ch.DirectBuffer"); Method cleanerMethod = clazz.getMethod("cleaner"); Object cleaner = cleanerMethod.invoke(bb); // cleaner = bb.cleaner() if (cleaner != null) { Method cleanMethod = cleaner.getClass().getMethod("clean"); cleanMethod.invoke(cleaner); // cleaner.clean() } } catch (ClassNotFoundException e) { logger.severe("Could not load sun.nio.ch.DirectBuffer."); } catch (NoSuchMethodException e) { logger.severe("Could not invoke DirectBuffer method - " + e.getMessage()); } catch (InvocationTargetException e) { logger.severe("Could not invoke DirectBuffer method - target exception"); } catch (IllegalAccessException e) { logger.severe("Could not invoke DirectBuffer method - illegal access"); } } } } else { logger.config("Not enough room for valid id3v2 tag:" + startByte); } }