Skip to content

Instantly share code, notes, and snippets.

@efuquen
Created May 16, 2012 01:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save efuquen/2706661 to your computer and use it in GitHub Desktop.
Save efuquen/2706661 to your computer and use it in GitHub Desktop.
import java.io.*;
//Custom java md5 implementaiton, use whatever you have available, as long as you stream bytes
//into it.
import com.twmacinta.util.MD5;
public class FileHash
{
/*
* Computes the start of mp3 audio data, skipping over any ID3v2 tag, if it exists.
* The original implementation has bug in it where its reading 10 more bytes into the audio
* then it actually should be if there is an ID3v2 tag (see if you can see the bug).
* Unfortunately this needs to stay in as all our MD5Hashes are computed this way.
*/
private static long mp3StartByte( InputStream mp3Stream ) throws IOException
{
byte[] id3header = new byte[4];
int size = -10;
mp3Stream.read( id3header, 0, 3 );
// Look for ID3v2
if( ( id3header[0] == 'I' ) && ( id3header[1] == 'D' ) && ( id3header[2] == '3' ) )
{
mp3Stream.read( id3header, 0, 3 );
mp3Stream.read( id3header, 0, 4 );
size = ( id3header[0] << 21 ) + ( id3header[1] << 14 ) + ( id3header[2] << 7 )
+ ( id3header[3] );
}
return size + 10;
}
public static String mp3Hash(File mp3File) {
return MD5.asHex(FileHash.mp3ByteHash(mp3File));
}
public static byte[] mp3ByteHash( File mp3File )
{
int buf = 8192;
//This is the size of a ID3v1 tag, which would be at the end of the mp3.
int id3 = 128;
FileInputStream mp3Stream = null;
MD5 md5 = new MD5();
try
{
//Open file and create necessary buffers
mp3Stream = new FileInputStream( mp3File );
long fileLength = mp3File.length();
byte[] buffer = new byte[buf];
long curByte;
//Initializes the md5 object
md5.Init();
//compute start byte offset of mp3 audio
long startByte = mp3StartByte( mp3Stream );
//closes the stream again so we can compute the md5 from the beginning
mp3Stream.close();
//open it back up and skip to the audio start position
mp3Stream = new FileInputStream( mp3File );
mp3Stream.skip( startByte );
//start reading the audio and pipe it to the md5 object. We stop reading right
//when we reach the last 128 bytes of the file, to check if its an ID3v1 tag.
int read = 0;
for( curByte = startByte; curByte + buf < fileLength - id3; curByte += read )
{
read = mp3Stream.read( buffer );
md5.Update( buffer, read );
}
//Read in the last 128 Bytes of the file
Long tempLong = new Long( fileLength - curByte - id3 );
buffer = new byte[tempLong.intValue()];
read = mp3Stream.read( buffer );
md5.Update( buffer, read );
buffer = new byte[3];
read = mp3Stream.read( buffer );
//Read the first 3 bytes of that last 128 and see if its a TAG string.
//If it is, its a ID3v1 tag and we should use it to compute the md5, if its
//not then its not an ID3 tag and we should use it in the md5 computation.
String tag = new String( buffer );
if( !tag.equals( "TAG" ) )
{
md5.Update( buffer, read );
buffer = new byte[id3 - read];
while( read != -1 )
{
read = mp3Stream.read( buffer );
if( read != -1 )
md5.Update( buffer, read );
}
}
//compute the md5 and return it.
return md5.Final();
}
catch( Exception e )
{
e.printStackTrace();
return null;
}
finally
{
if( mp3Stream != null )
{
try
{
mp3Stream.close();
}
catch( IOException e )
{
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment