Created
May 16, 2012 01:48
-
-
Save efuquen/2706664 to your computer and use it in GitHub Desktop.
Grooveshark MD5 Calculations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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