package htsjdk.samtools;
import htsjdk.samtools.cram.build.CramIO;
import htsjdk.samtools.cram.io.InputStreamUtils;
import htsjdk.samtools.cram.structure.CramHeader;
import htsjdk.samtools.util.BufferedLineReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.EnumSet;
public enum FileFormat {
UNKNOWN(new byte[0], "", false) {
},
SAM("@HD".getBytes(), ".sam", true) {
@Override
protected SAMFileHeader readHeader(InputStream is) {
SAMFileHeader samFileHeader = new SAMTextHeaderCodec().decode(new BufferedLineReader(is), null);
return samFileHeader;
}
},
BAM(new byte[] { 0x1f, (byte) 0x8b }, ".bam", true) {
@Override
protected SAMFileHeader readHeader(InputStream is) throws IOException {
try {
BAMFileReader reader = new BAMFileReader(is, null, false, false, ValidationStringency.SILENT, null);
return reader.getFileHeader();
} catch (IOException e) {
throw e;
} catch (Exception e) {
return null;
}
}
},
CRAM("CRAM".getBytes(), ".cram", true) {
@Override
protected CramHeader readHeader(InputStream is) throws IOException {
try {
return CramIO.readCramHeader(is);
} catch (IOException e) {
throw e;
} catch (Exception ee) {
return null;
}
}
};
private static EnumSet<FileFormat> knownFormats = EnumSet.complementOf(EnumSet.of(UNKNOWN));
private byte[] magic;
private String fileExtension;
private boolean doesFormatHasFileHeader;
private FileFormat(byte[] magic, String fileExtension, boolean doesFormatHasFileHeader) {
this.magic = magic;
this.fileExtension = fileExtension;
this.doesFormatHasFileHeader = doesFormatHasFileHeader;
}
private boolean checkMagic(InputStream bis) throws IOException {
if (magic.length == 0)
return true;
bis.mark(magic.length);
byte[] firstBytes = InputStreamUtils.readFully(bis, magic.length);
bis.reset();
return Arrays.equals(magic, firstBytes);
}
private boolean checkFileExtension(String source) {
if (source == null)
return false;
if (fileExtension.length() == 0)
return true;
return source.toLowerCase().endsWith(fileExtension.toLowerCase());
}
public boolean hasHeader() {
return doesFormatHasFileHeader;
}
protected Object readHeader(InputStream is) throws IOException {
return null;
};
public boolean testHeader(InputStream is) throws IOException {
if (!hasHeader())
throw new RuntimeException("Format has no concept of file header: " + name());
if (is != null && is.markSupported()) {
is.mark(100 * 1024);
Object header = readHeader(is);
is.reset();
return header != null;
}
return false;
}
public static FileFormat detect(InputStream bis, String source) throws IOException {
if (bis != null && bis.markSupported()) {
for (FileFormat format : knownFormats)
if (format.checkMagic(bis))
return format;
}
if (source != null) {
for (FileFormat format : knownFormats)
if (format.checkFileExtension(source))
return format;
}
return UNKNOWN;
}
}