📄 id3v2tag.java
字号:
/** * Copyright (C) 2001 Jonathan Hilliker * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Description: * This class reads and writes id3v2 tags from a file. * * @author: Jonathan Hilliker * @version: $Id: ID3v2Tag.java,v 1.5 2001/11/29 03:57:15 helliker Exp $ * Revsisions: * $Log: ID3v2Tag.java,v $ * Revision 1.5 2001/11/29 03:57:15 helliker * Fixed file handle leaks * * Revision 1.4 2001/11/10 07:20:12 helliker * Removed the getPaddingBytes method because it was not needed. * * Revision 1.3 2001/10/24 20:50:27 helliker * The padding size is updated before writing a tag, not during. * Created a method to update the padding size. * * Revision 1.2 2001/10/19 03:57:53 helliker * All set for release. * * */package helliker.id3;import java.io.File;import java.io.FileNotFoundException;import java.io.RandomAccessFile;import java.io.IOException;import java.io.UnsupportedEncodingException;public class ID3v2Tag { private final String ENC_TYPE = "ISO-8859-1"; private File mp3 = null; private ID3v2Header head = null; private ID3v2ExtendedHeader ext_head = null; private ID3v2Frames frames = null; private ID3v2Footer foot = null; private int padding; private int origSize; private int origPadding; private boolean exists; /** * Create an id3v2 tag bound to the file provided as a parameter. If * a tag exists in the file already, then all the information in the tag * will be extracted. If a tag doesn't exist, then this is the file that * will be written to when the writeTag method is called. * * @param mp3 the file to write/read the the tag information to/from * @exception FileNotFoundException if an error occurs * @exception IOException if an error occurs * @exception ID3v2FormatException if an exisiting id3v2 tag isn't correct */ public ID3v2Tag( File mp3 ) throws FileNotFoundException, IOException, ID3v2FormatException { this.mp3 = mp3; frames = new ID3v2Frames(); head = new ID3v2Header( mp3 ); padding = 0; exists = head.headerExists(); if( exists ) { if( head.getExtendedHeader() ) { ext_head = new ID3v2ExtendedHeader( mp3 ); } if( head.getFooter() ) { foot = new ID3v2Footer( mp3, head.getTagSize() + head.getHeaderSize() ); } RandomAccessFile in = null; try { in = new RandomAccessFile( mp3, "r" ); // For now only support id3v2.3.0 or greater if( head.getMajorVersion() >= 3 ) { parseFrames( in ); } } finally { if( in != null ) { in.close(); } } origSize = getSize(); origPadding = getPadding(); } } /** * Read the frames from the file and create ID3v2Frame objects from the * data found. * * @param raf the open file to read from * @exception FileNotFoundException if an error occurs * @exception IOException if an error occurs * @exception ID3v2FormatException if an error occurs */ private void parseFrames( RandomAccessFile raf ) throws FileNotFoundException, IOException, ID3v2FormatException { int offset = head.getHeaderSize(); int framesLength = head.getTagSize(); int bytesRead = 0; int curLength = 0; ID3v2Frame frame = null; String id = null; byte[] buf; byte[] flags; boolean done = false; if( head.getExtendedHeader() ) { framesLength -= ext_head.getSize(); offset += ext_head.getSize(); } raf.seek( offset ); while( (bytesRead < framesLength) && !done ) { buf = new byte[4]; bytesRead += raf.read( buf ); if( buf[0] != '\0' ) { id = new String( buf ); buf = new byte[4]; bytesRead += raf.read( buf ); curLength = BinaryParser.convertToInt( buf ); flags = new byte[2]; bytesRead += raf.read( flags ); buf = new byte[curLength]; bytesRead += raf.read( buf ); frame = new ID3v2Frame( id, flags, buf ); frames.put( id, frame ); } else { done = true; padding = framesLength - bytesRead - buf.length; } } } /** * Saves all the information in the tag to the file passed to the * constructor. If a tag doesn't exist, a tag is prepended to the file. * If the padding has not changed since the creation of this object and * the size is less than the original size + the original padding, then * the previous tag and part of the previous padding will be overwritten. * Otherwise, a new tag will be prepended to the file. * * @return true if the tag was successfully written * @exception FileNotFoundException if an error occurs * @exception IOException if an error occurs */ public void writeTag() throws FileNotFoundException, IOException { RandomAccessFile raf = null; int curSize = getSize(); origPadding = padding; padding = getUpdatedPadding(); try { raf = new RandomAccessFile( mp3, "rw" ); // This means that the file does not need to change size if( (padding > origPadding) || ((padding == origPadding) && (curSize == origSize)) ) { byte[] out = getBytes(); raf.seek(0); raf.write( out ); } else { Long bufSize = new Long( mp3.length() + curSize ); byte[] out = new byte[bufSize.intValue()]; System.arraycopy( getBytes(), 0, out, 0, curSize ); bufSize = new Long( mp3.length() - origSize ); byte[] in = new byte[bufSize.intValue()]; raf.seek( origSize ); if( raf.read( in ) != in.length ) { throw new IOException( "Error reading mp3 file before writing"); } System.arraycopy( in, 0, out, curSize, in.length ); raf.setLength( bufSize.longValue() ); raf.seek(0); raf.write( out ); } } finally { if( raf != null ) { raf.close(); } } origSize = curSize; exists = true; } /** * Remove an existing id3v2 tag from the file passed to the constructor. * * @return true if the removal was a success * @exception FileNotFoundException if an error occurs * @exception IOException if an error occurs */ public void removeTag() throws FileNotFoundException, IOException { if( exists ) { RandomAccessFile raf = null; try { Long bufSize = new Long( mp3.length() - origSize ); byte[] buf = new byte[bufSize.intValue()]; raf = new RandomAccessFile( mp3, "rw" ); raf.seek( origSize ); if( raf.read( buf ) != buf.length ) { throw new IOException("Error encountered while removing " + "id3v2 tag."); } raf.setLength( bufSize.longValue() ); raf.seek(0); raf.write( buf ); raf.close(); } finally { if( raf != null ) { raf.close(); } } exists = false; } } /** * Return a binary representation of this object to be written to a file. * This is in the format of the id3v2 specifications. This includes the * header, extended header (if it exists), the frames, padding (if it * exists), and a footer (if it exists). * * @return a binary representation of this id3v2 tag */ public byte[] getBytes() { byte[] b = new byte[getSize() + padding]; int bytesCopied = 0; int length = 0; length = head.getHeaderSize(); System.arraycopy( head.getBytes(), 0, b, bytesCopied, length ); bytesCopied += length; if( head.getExtendedHeader() ) { length = ext_head.getSize(); System.arraycopy( ext_head.getBytes(), 0, b, bytesCopied, length ); bytesCopied += length; } length = frames.getLength(); System.arraycopy( frames.getBytes(), 0, b, bytesCopied, length); bytesCopied += length; // Bytes should all be zero's by default System.arraycopy( new byte[padding], 0, b, bytesCopied, padding ); bytesCopied += padding; if( head.getFooter() ) { length = foot.getFooterSize(); System.arraycopy( foot.getBytes(), 0, b, bytesCopied, length ); bytesCopied += length; } return b; } /** * Determines the new amount of padding to use. If the user has not * changed the amount of padding then existing padding will be overwritten
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -