I'm putting my solution just in case people want an alternative without java-servlet related code:
public enum MagicBytes {
PNG(0x89, 0x50), // Define just like previous answer
JPG(0xFF, 0xD8),
PDF(0x25, 0x50);
private final int[] magicBytes;
private MagicBytes(int...bytes) {
magicBytes = bytes;
}
// Checks if bytes match a specific magic bytes sequence
public boolean is(byte[] bytes) {
if (bytes.length != magicBytes.length)
throw new RuntimeException("I need the first "+magicBytes.length
+ " bytes of an input stream.");
for (int i=0; i<bytes.length; i++)
if (Byte.toUnsignedInt(bytes[i]) != magicBytes[i])
return false;
return true;
}
// Extracts head bytes from any stream
public static byte[] extract(InputStream is, int length) throws IOException {
try (is) { // automatically close stream on return
byte[] buffer = new byte[length];
is.read(buffer, 0, length);
return buffer;
}
}
/* Convenience methods */
public boolean is(File file) throws IOException {
return is(new FileInputStream(file));
}
public boolean is(InputStream is) throws IOException {
return is(extract(is, magicBytes.length));
}
}
Then just call like this depending on if you have a file or InputStream :
MagicBytes.PNG.is(new File("picture.png"))
MagicBytes.PNG.is(new FileInputStream("picture.png"))
Being an enum also allows us to loop over each format if we need to by using MagicBytes.values()
.
EDIT: The previous code i put is a simplified version of the actual enum i'm using for my own lib, but adapted using the previous answer to help people understand faster. However, some file formats might have different kinds of headers, so this class would be more appropriate if that is an issue for your specific use-case: gist