package htsjdk.samtools; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.BlockCompressedInputStream; import htsjdk.samtools.util.BlockCompressedStreamConstants; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.zip.GZIPInputStream; /** * Utilities related to processing of {@link java.io.InputStream}s encoding SAM data * * @author mccowan */ public class SamStreams { private static int readBytes(final InputStream stream, final byte[] buffer, final int offset, final int length) throws IOException { int bytesRead = 0; while (bytesRead < length) { final int count = stream.read(buffer, offset + bytesRead, length - bytesRead); if (count <= 0) { break; } bytesRead += count; } return bytesRead; } /** * @param stream stream.markSupported() must be true * @return true if this looks like a BAM file. */ public static boolean isBAMFile(final InputStream stream) throws IOException { if (!BlockCompressedInputStream.isValidFile(stream)) { return false; } final int buffSize = BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; stream.mark(buffSize); final byte[] buffer = new byte[buffSize]; readBytes(stream, buffer, 0, buffSize); stream.reset(); final byte[] magicBuf = new byte[4]; final int magicLength = readBytes(new BlockCompressedInputStream(new ByteArrayInputStream(buffer)), magicBuf, 0, 4); return magicLength == BAMFileConstants.BAM_MAGIC.length && Arrays.equals(BAMFileConstants.BAM_MAGIC, magicBuf); } // Its too expensive to examine the remote file to determine type. // Rely on file extension. public static boolean sourceLikeBam(final SeekableStream strm) { String source = strm.getSource(); if (source == null) return true; source = source.toLowerCase(); //Source will typically be a file path or URL //If it's a URL we require one of the query parameters to be bam file return source.endsWith(".bam") || source.contains(".bam?") || source.contains(".bam&") || source.contains(".bam%26"); } public static boolean isGzippedSAMFile(final InputStream stream) { if (!stream.markSupported()) { throw new IllegalArgumentException("Cannot test a stream that doesn't support marking."); } stream.mark(8000); try { final GZIPInputStream gunzip = new GZIPInputStream(stream); final int ch = gunzip.read(); return true; } catch (final IOException ioe) { return false; } finally { try { stream.reset(); } catch (final IOException ioe) { throw new IllegalStateException("Could not reset stream."); } } } }