// Read returns the next sam.Record in the BAM stream. func (br *Reader) Read() (*sam.Record, error) { if br.c != nil && vOffset(br.r.LastChunk().End) >= vOffset(br.c.End) { return nil, io.EOF } r := errReader{r: br.r} bin := binaryReader{r: &r} // Read record header data. blockSize := int(bin.readInt32()) r.n = 0 // The blocksize field is not included in the blocksize. // br.r.Chunk() is only valid after the call the Read(), so this // must come after the first read in the record. tx := br.r.Begin() defer func() { br.lastChunk = tx.End() }() var rec sam.Record refID := bin.readInt32() rec.Pos = int(bin.readInt32()) nLen := bin.readUint8() rec.MapQ = bin.readUint8() _ = bin.readUint16() nCigar := bin.readUint16() rec.Flags = sam.Flags(bin.readUint16()) lSeq := bin.readInt32() nextRefID := bin.readInt32() rec.MatePos = int(bin.readInt32()) rec.TempLen = int(bin.readInt32()) if r.err != nil { return nil, r.err } // Read variable length data. name := make([]byte, nLen) if nf, _ := r.Read(name); nf != int(nLen) { return nil, errors.New("bam: truncated record name") } rec.Name = string(name[:len(name)-1]) // The BAM spec indicates name is null terminated. rec.Cigar = readCigarOps(&bin, nCigar) if r.err != nil { return nil, r.err } seq := make(doublets, (lSeq+1)>>1) if nf, _ := r.Read(seq.Bytes()); nf != int((lSeq+1)>>1) { return nil, errors.New("bam: truncated sequence") } rec.Seq = sam.Seq{Length: int(lSeq), Seq: seq} rec.Qual = make([]byte, lSeq) if nf, _ := r.Read(rec.Qual); nf != int(lSeq) { return nil, errors.New("bam: truncated quality") } auxTags := make([]byte, blockSize-r.n) r.Read(auxTags) if r.n != blockSize { return nil, errors.New("bam: truncated auxilliary data") } rec.AuxFields = parseAux(auxTags) if r.err != nil { return nil, r.err } refs := int32(len(br.h.Refs())) if refID != -1 { if refID < -1 || refID >= refs { return nil, errors.New("bam: reference id out of range") } rec.Ref = br.h.Refs()[refID] } if nextRefID != -1 { if nextRefID < -1 || nextRefID >= refs { return nil, errors.New("bam: mate reference id out of range") } rec.MateRef = br.h.Refs()[nextRefID] } return &rec, nil }