// -*- mode: c++; indent-tabs-mode: nil; -*- // // Copyright 2009 Illumina, Inc. // // This software is covered by the "Illumina Genome Analyzer Software // License Agreement" and the "Illumina Source Code License Agreement", // and certain third party copyright/licenses, and any user of this // source file is bound by the terms therein (see accompanying files // Illumina_Genome_Analyzer_Software_License_Agreement.pdf and // Illumina_Source_Code_License_Agreement.pdf and third party // copyright/license notices). // // /// \file /// \author Chris Saunders /// #ifndef __BAM_RECORD_HH #define __BAM_RECORD_HH #include "blt_util/bam_util.hh" #include "blt_util/bam_seq.hh" //#include "blt_util/read_record.hh" struct bam_record { bam_record() : _bp(bam_init1()) {} ~bam_record() { if (NULL != _bp) { if(NULL != _bp->data) free(_bp->data); free(_bp); } } bam_record(const bam_record& br) : _bp(bam_dup1(br._bp)) {} void copy(const bam_record& br) { bam_copy1(_bp,br._bp); } private: const bam_record& operator==(const bam_record& rhs); public: const char* qname() const { return reinterpret_cast(_bp->data); } void set_qname(const char* name) { edit_bam_qname(name,*_bp); } bool is_paired() const { return (_bp->core.flag & BAM_FLAG::PAIRED); } bool is_proper_pair() const { return (_bp->core.flag & BAM_FLAG::PROPER_PAIR); } bool is_unmapped() const { return (_bp->core.flag & BAM_FLAG::UNMAPPED); } bool is_mate_unmapped() const { return (_bp->core.flag & BAM_FLAG::MATE_UNMAPPED); } bool is_fwd_strand() const { return (not (_bp->core.flag & BAM_FLAG::STRAND)); } bool is_mate_fwd_strand() const { return (not (_bp->core.flag & BAM_FLAG::MATE_STRAND)); } bool is_dup() const { return (_bp->core.flag & BAM_FLAG::DUPLICATE); } bool is_filter() const { return (_bp->core.flag & BAM_FLAG::FILTER); } bool is_first() const { return (_bp->core.flag & BAM_FLAG::FIRST_READ); } bool is_second() const { return (_bp->core.flag & BAM_FLAG::SECOND_READ); } bool is_secondary() const { return (_bp->core.flag & BAM_FLAG::SECONDARY); } void toggle_is_paired() { _bp->core.flag ^= BAM_FLAG::PAIRED; } void toggle_is_unmapped() { _bp->core.flag ^= BAM_FLAG::UNMAPPED; } void toggle_is_fwd_strand() { _bp->core.flag ^= BAM_FLAG::STRAND; } void toggle_is_mate_fwd_strand() { _bp->core.flag ^= BAM_FLAG::MATE_STRAND; } void toggle_is_first() { _bp->core.flag ^= BAM_FLAG::FIRST_READ; } void toggle_is_second() { _bp->core.flag ^= BAM_FLAG::SECOND_READ; } int read_no() const { return ( (is_second() and (not is_first())) ? 2 : 1 ); } int target_id() const { return _bp->core.tid; } int mate_target_id() const { return _bp->core.mtid; } int pos() const { return (_bp->core.pos+1); } int mate_pos() const { return (_bp->core.mpos+1); } uint8_t map_qual() const { return _bp->core.qual; } // attempt to recover the single read mapping score if it exists, // else return MAPQ: unsigned se_map_qual() const { static const char smtag[] = {'S','M'}; return alt_map_qual(smtag); } // attempt to recover the ELAND paired-end mapping score if it // exists, else return MAPQ: unsigned pe_map_qual() const { static const char astag[] = {'A','S'}; return alt_map_qual(astag); } // Test if SM and AM fields both exist and are equal to zero. Any // other result returns false: // bool is_unanchored() const { if(not is_paired()) return false; static const char amtag[] = {'A','M'}; uint8_t* am_ptr(bam_aux_get(_bp,amtag)); if(NULL == am_ptr) return false; static const char smtag[] = {'S','M'}; uint8_t* sm_ptr(bam_aux_get(_bp,smtag)); if(NULL == sm_ptr) return false; return (is_int_code(am_ptr[0]) and is_int_code(sm_ptr[0]) and (0 == bam_aux2i(am_ptr)) and (0 == bam_aux2i(sm_ptr))); } const uint32_t* raw_cigar() const { return bam1_cigar(_bp); } unsigned n_cigar() const { return _bp->core.n_cigar; } unsigned read_size() const { return _bp->core.l_qseq; } bam_seq get_bam_read() const { return bam_seq(bam1_seq(_bp),read_size()); } const char* get_string_tag(const char* tag) const; bool get_num_tag(const char* tag, int32_t& num) const; const uint8_t* qual() const { return bam1_qual(_bp); } void set_target_id(int32_t tid) { if(tid<-1) tid=-1; _bp->core.tid=tid; } // read should be null terminated, qual should already have offset removed: // void set_readqual(const char* read, const uint8_t* qual) { edit_bam_read_and_quality(read,qual,*_bp); } bam1_t* get_data() { return _bp; } const bam1_t* get_data() const { return _bp; } private: friend struct bam_streamer; friend struct starling_read; unsigned alt_map_qual(const char* tag) const; static bool is_int_code(char c) { switch(c) { case 'c' : case 's' : case 'i' : case 'C' : case 'S' : case 'I' : return true; default : return false; } } bam1_t* _bp; }; #endif