]> git.donarmstrong.com Git - bamtools.git/blobdiff - src/api/BamAlignment.cpp
Version 2.2.2
[bamtools.git] / src / api / BamAlignment.cpp
index 0eff5c72e46fba52c137c063989a66dd90e1d52c..620ba2ee72db0127db733808708318ddf05ec240 100644 (file)
@@ -2,13 +2,13 @@
 // BamAlignment.cpp (c) 2009 Derek Barnett
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
 // BamAlignment.cpp (c) 2009 Derek Barnett
 // Marth Lab, Department of Biology, Boston College
 // ---------------------------------------------------------------------------
-// Last modified: 7 October 2011 (DB)
+// Last modified: 4 December 2012 (DB)
 // ---------------------------------------------------------------------------
 // Provides the BamAlignment data structure
 // ***************************************************************************
 
 // ---------------------------------------------------------------------------
 // Provides the BamAlignment data structure
 // ***************************************************************************
 
-#include <api/BamAlignment.h>
-#include <api/BamConstants.h>
+#include "api/BamAlignment.h"
+#include "api/BamConstants.h"
 using namespace BamTools;
 using namespace std;
 
 using namespace BamTools;
 using namespace std;
 
@@ -25,12 +25,22 @@ using namespace std;
 */
 /*! \var BamAlignment::QueryBases
     \brief 'original' sequence (as reported from sequencing machine)
 */
 /*! \var BamAlignment::QueryBases
     \brief 'original' sequence (as reported from sequencing machine)
+
+    \note Setting this field to "*" indicates that the sequence is not to be stored on output.
+    In this case, the contents of the Qualities field should be invalidated as well (cleared or marked as "*").
 */
 /*! \var BamAlignment::AlignedBases
     \brief 'aligned' sequence (includes any indels, padding, clipping)
 */
 /*! \var BamAlignment::AlignedBases
     \brief 'aligned' sequence (includes any indels, padding, clipping)
+
+    This field will be completely empty after reading from BamReader/BamMultiReader when
+    QueryBases is empty.
 */
 /*! \var BamAlignment::Qualities
     \brief FASTQ qualities (ASCII characters, not numeric values)
 */
 /*! \var BamAlignment::Qualities
     \brief FASTQ qualities (ASCII characters, not numeric values)
+
+    \note Setting this field to "*" indicates to BamWriter that the quality scores are not to be stored,
+    but instead will be output as a sequence of '0xFF'. Otherwise, QueryBases must not be a "*" and
+    the length of this field should equal the length of QueryBases.
 */
 /*! \var BamAlignment::TagData
     \brief tag data (use the provided methods to query/modify)
 */
 /*! \var BamAlignment::TagData
     \brief tag data (use the provided methods to query/modify)
@@ -70,8 +80,12 @@ using namespace std;
     \brief constructor
 */
 BamAlignment::BamAlignment(void)
     \brief constructor
 */
 BamAlignment::BamAlignment(void)
-    : RefID(-1)
+    : Length(0)
+    , RefID(-1)
     , Position(-1)
     , Position(-1)
+    , Bin(0)
+    , MapQuality(0)
+    , AlignmentFlag(0)
     , MateRefID(-1)
     , MatePosition(-1)
     , InsertSize(0)
     , MateRefID(-1)
     , MatePosition(-1)
     , InsertSize(0)
@@ -105,31 +119,6 @@ BamAlignment::BamAlignment(const BamAlignment& other)
 */
 BamAlignment::~BamAlignment(void) { }
 
 */
 BamAlignment::~BamAlignment(void) { }
 
-///*! \fn bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const std::string& value)
-//    \brief Adds a field with string data to the BAM tags.
-
-//    Does NOT modify an existing tag - use \link BamAlignment::EditTag() \endlink instead.
-
-//    \param[in] tag   2-character tag name
-//    \param[in] type  1-character tag type (must be "Z" or "H")
-//    \param[in] value string data to store
-//    \return \c true if the \b new tag was added successfully
-//    \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
-//*/
-
-
-///*! \fn bool AddTag(const std::string& tag, const std::vector<uint8_t>& values);
-//    \brief Adds a numeric array field to the BAM tags.
-
-//    Does NOT modify an existing tag - use \link BamAlignment::EditTag() \endlink instead.
-
-//    \param tag    2-character tag name
-//    \param values vector of uint8_t values to store
-
-//    \return \c true if the \b new tag was added successfully
-//    \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
-//*/
-
 /*! \fn bool BamAlignment::BuildCharData(void)
     \brief Populates alignment string fields (read name, bases, qualities, tag data).
 
 /*! \fn bool BamAlignment::BuildCharData(void)
     \brief Populates alignment string fields (read name, bases, qualities, tag data).
 
@@ -159,22 +148,17 @@ bool BamAlignment::BuildCharData(void) {
     const unsigned int tagDataLength  = dataLength - tagDataOffset;
 
     // check offsets to see what char data exists
     const unsigned int tagDataLength  = dataLength - tagDataOffset;
 
     // check offsets to see what char data exists
-    const bool hasSeqData  = ( seqDataOffset  < dataLength );
-    const bool hasQualData = ( qualDataOffset < dataLength );
+    const bool hasSeqData  = ( seqDataOffset  < qualDataOffset );
+    const bool hasQualData = ( qualDataOffset < tagDataOffset );
     const bool hasTagData  = ( tagDataOffset  < dataLength );
 
     const bool hasTagData  = ( tagDataOffset  < dataLength );
 
-    // set up char buffers
-    const char* allCharData = SupportData.AllCharData.data();
-    const char* seqData     = ( hasSeqData  ? (((const char*)allCharData) + seqDataOffset)  : (const char*)0 );
-    const char* qualData    = ( hasQualData ? (((const char*)allCharData) + qualDataOffset) : (const char*)0 );
-          char* tagData     = ( hasTagData  ? (((char*)allCharData) + tagDataOffset)        : (char*)0 );
-
     // store alignment name (relies on null char in name as terminator)
     // store alignment name (relies on null char in name as terminator)
-    Name.assign((const char*)(allCharData));
+    Name.assign(SupportData.AllCharData.data());
 
     // save query sequence
     QueryBases.clear();
     if ( hasSeqData ) {
 
     // save query sequence
     QueryBases.clear();
     if ( hasSeqData ) {
+        const char* seqData = SupportData.AllCharData.data() + seqDataOffset;
         QueryBases.reserve(SupportData.QuerySequenceLength);
         for ( size_t i = 0; i < SupportData.QuerySequenceLength; ++i ) {
             const char singleBase = Constants::BAM_DNA_LOOKUP[ ( (seqData[(i/2)] >> (4*(1-(i%2)))) & 0xf ) ];
         QueryBases.reserve(SupportData.QuerySequenceLength);
         for ( size_t i = 0; i < SupportData.QuerySequenceLength; ++i ) {
             const char singleBase = Constants::BAM_DNA_LOOKUP[ ( (seqData[(i/2)] >> (4*(1-(i%2)))) & 0xf ) ];
@@ -182,13 +166,21 @@ bool BamAlignment::BuildCharData(void) {
         }
     }
 
         }
     }
 
-    // save qualities, converting from numeric QV to 'FASTQ-style' ASCII character
+    // save qualities
+
     Qualities.clear();
     if ( hasQualData ) {
     Qualities.clear();
     if ( hasQualData ) {
-        Qualities.reserve(SupportData.QuerySequenceLength);
-        for ( size_t i = 0; i < SupportData.QuerySequenceLength; ++i ) {
-            const char singleQuality = static_cast<const char>(qualData[i]+33);
-            Qualities.append(1, singleQuality);
+        const char* qualData = SupportData.AllCharData.data() + qualDataOffset;
+
+        // if marked as unstored (sequence of 0xFF) - don't do conversion, just fill with 0xFFs
+        if ( qualData[0] == (char)0xFF )
+            Qualities.resize(SupportData.QuerySequenceLength, (char)0xFF);
+
+        // otherwise convert from numeric QV to 'FASTQ-style' ASCII character
+        else {
+            Qualities.reserve(SupportData.QuerySequenceLength);
+            for ( size_t i = 0; i < SupportData.QuerySequenceLength; ++i )
+                Qualities.append(1, qualData[i]+33);
         }
     }
 
         }
     }
 
@@ -197,7 +189,7 @@ bool BamAlignment::BuildCharData(void) {
 
     // if QueryBases has data, build AlignedBases using CIGAR data
     // otherwise, AlignedBases will remain empty (this case IS allowed)
 
     // if QueryBases has data, build AlignedBases using CIGAR data
     // otherwise, AlignedBases will remain empty (this case IS allowed)
-    if ( !QueryBases.empty() ) {
+    if ( !QueryBases.empty() && QueryBases != "*" ) {
 
         // resize AlignedBases
         AlignedBases.reserve(SupportData.QuerySequenceLength);
 
         // resize AlignedBases
         AlignedBases.reserve(SupportData.QuerySequenceLength);
@@ -256,6 +248,9 @@ bool BamAlignment::BuildCharData(void) {
     // save tag data
     TagData.clear();
     if ( hasTagData ) {
     // save tag data
     TagData.clear();
     if ( hasTagData ) {
+
+        char* tagData = (((char*)SupportData.AllCharData.data()) + tagDataOffset);
+
         if ( IsBigEndian ) {
             size_t i = 0;
             while ( i < tagDataLength ) {
         if ( IsBigEndian ) {
             size_t i = 0;
             while ( i < tagDataLength ) {
@@ -351,49 +346,20 @@ bool BamAlignment::BuildCharData(void) {
         memcpy((char*)(TagData.data()), tagData, tagDataLength);
     }
 
         memcpy((char*)(TagData.data()), tagData, tagDataLength);
     }
 
-    // clear the core-only flag
+    // clear core-only flag & return success
     SupportData.HasCoreOnly = false;
     SupportData.HasCoreOnly = false;
-
-    // return success
     return true;
 }
 
     return true;
 }
 
-///*! \fn bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const std::string& value)
-//    \brief Edits a BAM tag field containing string data.
-
-//    If \a tag does not exist, a new entry is created.
-
-//    \param tag   2-character tag name
-//    \param type  1-character tag type (must be "Z" or "H")
-//    \param value string data to store
-
-//    \return \c true if the tag was modified/created successfully
-
-//    \sa BamAlignment::RemoveTag()
-//    \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
-//*/
-
-///*! \fn bool EditTag(const std::string& tag, const std::vector<uint8_t>& values);
-//    \brief Edits a BAM tag field containing a numeric array.
-
-//    If \a tag does not exist, a new entry is created.
-
-//    \param tag   2-character tag name
-//    \param value vector of uint8_t values to store
-
-//    \return \c true if the tag was modified/created successfully
-//    \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
-//*/
-
-/*! \fn bool BamAlignment::FindTag(const std::string& tag, char*& pTagData, const unsigned int& tagDataLength, unsigned int& numBytesParsed)
+/*! \fn bool BamAlignment::FindTag(const std::string& tag, char*& pTagData, const unsigned int& tagDataLength, unsigned int& numBytesParsed) const
     \internal
 
     Searches for requested tag in BAM tag data.
 
     \internal
 
     Searches for requested tag in BAM tag data.
 
-    \param tag            requested 2-character tag name
-    \param pTagData       pointer to current position in BamAlignment::TagData
-    \param tagDataLength  length of BamAlignment::TagData
-    \param numBytesParsed number of bytes parsed so far
+    \param[in]     tag            requested 2-character tag name
+    \param[in,out] pTagData       pointer to current position in BamAlignment::TagData
+    \param[in]     tagDataLength  length of BamAlignment::TagData
+    \param[in,out] numBytesParsed number of bytes parsed so far
 
     \return \c true if found
 
 
     \return \c true if found
 
@@ -428,37 +394,88 @@ bool BamAlignment::FindTag(const std::string& tag,
     return false;
 }
 
     return false;
 }
 
-/*! \fn bool BamAlignment::GetEditDistance(uint32_t& editDistance) const
-    \brief Retrieves value of edit distance tag ("NM").
-
-    \deprecated Instead use BamAlignment::GetTag()
-        \code
-            BamAlignment::GetTag("NM", editDistance);
-        \endcode
+/*! \fn bool BamAlignment::GetArrayTagType(const std::string& tag, char& type) const
+    \brief Retrieves the BAM tag type-code for the array elements associated with requested tag name.
 
 
-    \param editDistance destination for retrieved value
+    \param[in]  tag  2-character tag name
+    \param[out] type retrieved (1-character) type-code
 
 
-    \return \c true if found
+    \return \c true if found. False if not found, or if tag is not an array type.
+    \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
 */
 */
+bool BamAlignment::GetArrayTagType(const std::string& tag, char& type) const {
+
+    // skip if alignment is core-only
+    if ( SupportData.HasCoreOnly ) {
+        // TODO: set error string?
+        return false;
+    }
+
+    // skip if no tags present
+    if ( TagData.empty() ) {
+        // TODO: set error string?
+        return false;
+    }
+
+    // localize the tag data
+    char* pTagData = (char*)TagData.data();
+    const unsigned int tagDataLength = TagData.size();
+    unsigned int numBytesParsed = 0;
+
+    // if tag not found, return failure
+    if ( !FindTag(tag, pTagData, tagDataLength, numBytesParsed) ){
+        // TODO: set error string?
+        return false;
+    }
+
+    // check that tag type code is array
+    type = *(pTagData - 1);
+    if ( type != Constants::BAM_TAG_TYPE_ARRAY ) {
+        // TODO: set error string
+        return false;
+    }
 
 
-// TODO : REMOVE THIS METHOD
-bool BamAlignment::GetEditDistance(uint32_t& editDistance) const {
-    return GetTag("NM", (uint32_t&)editDistance);
+    // fetch element type
+    const char elementType = *pTagData;
+    switch ( elementType ) {
+
+        // allowable types
+        case (Constants::BAM_TAG_TYPE_INT8)   :
+        case (Constants::BAM_TAG_TYPE_UINT8)  :
+        case (Constants::BAM_TAG_TYPE_INT16)  :
+        case (Constants::BAM_TAG_TYPE_UINT16) :
+        case (Constants::BAM_TAG_TYPE_INT32)  :
+        case (Constants::BAM_TAG_TYPE_UINT32) :
+        case (Constants::BAM_TAG_TYPE_FLOAT)  :
+            type = elementType;
+            break;
+
+        default:
+            //TODO: set error string
+            return false;
+    }
+
+    // if we get here, return success
+    return true;
 }
 
 }
 
-/*! \fn int BamAlignment::GetEndPosition(bool usePadded = false, bool zeroBased = true) const
-    \brief Calculates alignment end position, based on starting position and CIGAR data.
 
 
-    \param usePadded Inserted bases affect reported position. Default is false, so that reported
-                     position stays 'sync-ed' with reference coordinates.
-    \param zeroBased Return (BAM standard) 0-based coordinate. Setting this to false can be useful
-                     when using BAM data with half-open formats (e.g. BED).
+/*! \fn int BamAlignment::GetEndPosition(bool usePadded = false, bool closedInterval = false) const
+    \brief Calculates alignment end position, based on its starting position and CIGAR data.
+
+    \warning The position returned now represents a zero-based, HALF-OPEN interval.
+    In previous versions of BamTools (0.x & 1.x) all intervals were treated
+    as zero-based, CLOSED.
+
+    \param[in] usePadded      Allow inserted bases to affect the reported position. Default is
+                              false, so that reported position stays synced with reference
+                              coordinates.
+    \param[in] closedInterval Setting this to true will return a 0-based end coordinate. Default is
+                              false, so that his value represents a standard, half-open interval.
 
     \return alignment end position
 */
 
     \return alignment end position
 */
-int BamAlignment::GetEndPosition(bool usePadded, bool zeroBased) const {
-
-    // TODO: Come back to this for coordinate issues !!!
+int BamAlignment::GetEndPosition(bool usePadded, bool closedInterval) const {
 
     // initialize alignment end to starting position
     int alignEnd = Position;
 
     // initialize alignment end to starting position
     int alignEnd = Position;
@@ -467,77 +484,183 @@ int BamAlignment::GetEndPosition(bool usePadded, bool zeroBased) const {
     vector<CigarOp>::const_iterator cigarIter = CigarData.begin();
     vector<CigarOp>::const_iterator cigarEnd  = CigarData.end();
     for ( ; cigarIter != cigarEnd; ++cigarIter) {
     vector<CigarOp>::const_iterator cigarIter = CigarData.begin();
     vector<CigarOp>::const_iterator cigarEnd  = CigarData.end();
     for ( ; cigarIter != cigarEnd; ++cigarIter) {
-        const char cigarType = (*cigarIter).Type;
-        const uint32_t& cigarLength = (*cigarIter).Length;
-
-        if ( cigarType == Constants::BAM_CIGAR_MATCH_CHAR ||
-             cigarType == Constants::BAM_CIGAR_DEL_CHAR ||
-             cigarType == Constants::BAM_CIGAR_REFSKIP_CHAR )
-            alignEnd += cigarLength;
-        else if ( usePadded && cigarType == Constants::BAM_CIGAR_INS_CHAR )
-            alignEnd += cigarLength;
+        const CigarOp& op = (*cigarIter);
+
+        switch ( op.Type ) {
+
+            // increase end position on CIGAR chars [DMXN=]
+            case Constants::BAM_CIGAR_DEL_CHAR      :
+            case Constants::BAM_CIGAR_MATCH_CHAR    :
+            case Constants::BAM_CIGAR_MISMATCH_CHAR :
+            case Constants::BAM_CIGAR_REFSKIP_CHAR  :
+            case Constants::BAM_CIGAR_SEQMATCH_CHAR :
+                alignEnd += op.Length;
+                break;
+
+            // increase end position on insertion, only if @usePadded is true
+            case Constants::BAM_CIGAR_INS_CHAR :
+                if ( usePadded )
+                    alignEnd += op.Length;
+                break;
+
+            // all other CIGAR chars do not affect end position
+            default :
+                break;
+        }
     }
 
     }
 
-    // adjust for zero-based coordinates, if requested
-    if ( zeroBased ) alignEnd -= 1;
+    // adjust for closedInterval, if requested
+    if ( closedInterval )
+        alignEnd -= 1;
 
     // return result
     return alignEnd;
 }
 
 /*! \fn std::string BamAlignment::GetErrorString(void) const
 
     // return result
     return alignEnd;
 }
 
 /*! \fn std::string BamAlignment::GetErrorString(void) const
-    \brief Returns a description of the last error that occurred
+    \brief Returns a human-readable description of the last error that occurred
 
 
-    This method allows elimnation of STDERR pollution. Developers of client code
+    This method allows elimination of STDERR pollution. Developers of client code
     may choose how the messages are displayed to the user, if at all.
 
     may choose how the messages are displayed to the user, if at all.
 
-    \return description of last error that occurred
+    \return error description
 */
 std::string BamAlignment::GetErrorString(void) const {
     return ErrorString;
 }
 
 */
 std::string BamAlignment::GetErrorString(void) const {
     return ErrorString;
 }
 
-/*! \fn bool BamAlignment::GetReadGroup(std::string& readGroup) const
-    \brief Retrieves value of read group tag ("RG").
+/*! \fn bool BamAlignment::GetSoftClips(std::vector<int>& clipSizes, std::vector<int>& readPositions, std::vector<int>& genomePositions, bool usePadded = false) const
+    \brief Identifies if an alignment has a soft clip. If so, identifies the
+           sizes of the soft clips, as well as their positions in the read and reference.
 
 
-    \deprecated Instead use BamAlignment::GetTag()
-        \code
-            BamAlignment::GetTag("RG", readGroup);
-        \endcode
+    \param[out] clipSizes       vector of the sizes of each soft clip in the alignment
+    \param[out] readPositions   vector of the 0-based read locations of each soft clip in the alignment.
+                                These positions are basically indexes within the read, not genomic positions.
+    \param[out] genomePositions vector of the 0-based genome locations of each soft clip in the alignment
+    \param[in]  usePadded       inserted bases affect reported position. Default is false, so that
+                                reported position stays 'sync-ed' with reference coordinates.
 
 
-    \param readGroup destination for retrieved value
-
-    \return \c true if found
+    \return \c true if any soft clips were found in the alignment
 */
 */
+bool BamAlignment::GetSoftClips(vector<int>& clipSizes,
+                                vector<int>& readPositions,
+                                vector<int>& genomePositions,
+                                bool usePadded) const
+{
+    // initialize positions & flags
+    int refPosition  = Position;
+    int readPosition = 0;
+    bool softClipFound = false;
+    bool firstCigarOp  = true;
 
 
-// TODO : REMOVE THIS METHOD
-bool BamAlignment::GetReadGroup(std::string& readGroup) const {
-    return GetTag("RG", readGroup);
+    // iterate over cigar operations
+    vector<CigarOp>::const_iterator cigarIter = CigarData.begin();
+    vector<CigarOp>::const_iterator cigarEnd  = CigarData.end();
+    for ( ; cigarIter != cigarEnd; ++cigarIter) {
+        const CigarOp& op = (*cigarIter);
+
+        switch ( op.Type ) {
+
+            // increase both read & genome positions on CIGAR chars [DMXN=]
+            case Constants::BAM_CIGAR_DEL_CHAR      :
+            case Constants::BAM_CIGAR_MATCH_CHAR    :
+            case Constants::BAM_CIGAR_MISMATCH_CHAR :
+            case Constants::BAM_CIGAR_REFSKIP_CHAR  :
+            case Constants::BAM_CIGAR_SEQMATCH_CHAR :
+                refPosition  += op.Length;
+                readPosition += op.Length;
+                break;
+
+            // increase read position on insertion, genome position only if @usePadded is true
+            case Constants::BAM_CIGAR_INS_CHAR :
+                readPosition += op.Length;
+                if ( usePadded )
+                    refPosition += op.Length;
+                break;
+
+            case Constants::BAM_CIGAR_SOFTCLIP_CHAR :
+
+                softClipFound = true;
+
+                //////////////////////////////////////////////////////////////////////////////
+                // if we are dealing with the *first* CIGAR operation
+                // for this alignment, we increment the read position so that
+                // the read and genome position of the clip are referring to the same base.
+                // For example, in the alignment below, the ref position would be 4, yet
+                //              the read position would be 0. Thus, to "sync" the two,
+                //              we need to increment the read position by the length of the
+                //              soft clip.
+                // Read:  ATCGTTTCGTCCCTGC
+                // Ref:   GGGATTTCGTCCCTGC
+                // Cigar: SSSSMMMMMMMMMMMM
+                //
+                // NOTE: This only needs to be done if the soft clip is the _first_ CIGAR op.
+                //////////////////////////////////////////////////////////////////////////////
+                if ( firstCigarOp )
+                    readPosition += op.Length;
+
+                // track the soft clip's size, read position, and genome position
+                clipSizes.push_back(op.Length);
+                readPositions.push_back(readPosition);
+                genomePositions.push_back(refPosition);
+
+            // any other CIGAR operations have no effect
+            default :
+                break;
+        }
+
+        // clear our "first pass" flag
+        firstCigarOp = false;
+    }
+
+    // return whether any soft clips found
+    return softClipFound;
 }
 
 }
 
-///*! \fn bool BamAlignment::GetTag(const std::string& tag, std::string& destination) const
-//    \brief Retrieves the string value associated with a BAM tag.
+/*! \fn std::vector<std::string> BamAlignment::GetTagNames(void) const
+    \brief Retrieves the BAM tag names.
+
+    When paired with GetTagType() and GetTag(), this method allows you
+    to iterate over an alignment's tag data without knowing the names (or types)
+    beforehand.
+
+    \return \c vector containing all tag names found (empty if none available)
+    \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
+*/
+std::vector<std::string> BamAlignment::GetTagNames(void) const {
+
+    std::vector<std::string> result;
+    if ( SupportData.HasCoreOnly || TagData.empty() )
+        return result;
 
 
-//    \param tag         2-character tag name
-//    \param destination destination for retrieved value
+    char* pTagData = (char*)TagData.data();
+    const unsigned int tagDataLength = TagData.size();
+    unsigned int numBytesParsed = 0;
+    while ( numBytesParsed < tagDataLength ) {
 
 
-//    \return \c true if found
-//*/
+        // get current tag name & type
+        const char* pTagName = pTagData;
+        const char* pTagType = pTagData + 2;
+        pTagData       += 3;
+        numBytesParsed +=3;
 
 
-///*! \fn bool BamAlignment::GetTag(const std::string& tag, std::vector<uint32_t>& destination) const
-//    \brief Retrieves the numeric array data associated with a BAM tag
+        // store tag name
+        result.push_back( std::string(pTagName, 2)  );
 
 
-//    \param tag         2-character tag name
-//    \param destination destination for retrieved data
+        // find the next tag
+        if ( *pTagType == '\0' ) break;
+        if ( !SkipToNextTag(*pTagType, pTagData, numBytesParsed) ) break;
+        if ( *pTagData == '\0' ) break;
+    }
 
 
-//    \return \c true if found
-//*/
+    return result;
+}
 
 /*! \fn bool BamAlignment::GetTagType(const std::string& tag, char& type) const
     \brief Retrieves the BAM tag type-code associated with requested tag name.
 
 
 /*! \fn bool BamAlignment::GetTagType(const std::string& tag, char& type) const
     \brief Retrieves the BAM tag type-code associated with requested tag name.
 
-    \param tag  2-character tag name
-    \param type destination for the retrieved (1-character) tag type
+    \param[in]  tag  2-character tag name
+    \param[out] type retrieved (1-character) type-code
 
     \return \c true if found
     \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
 
     \return \c true if found
     \sa \samSpecURL for more details on reserved tag names, supported tag types, etc.
@@ -593,7 +716,8 @@ bool BamAlignment::GetTagType(const std::string& tag, char& type) const {
 
 /*! \fn bool BamAlignment::HasTag(const std::string& tag) const
     \brief Returns true if alignment has a record for requested tag.
 
 /*! \fn bool BamAlignment::HasTag(const std::string& tag) const
     \brief Returns true if alignment has a record for requested tag.
-    \param tag 2-character tag name
+
+    \param[in] tag 2-character tag name
     \return \c true if alignment has a record for tag
 */
 bool BamAlignment::HasTag(const std::string& tag) const {
     \return \c true if alignment has a record for tag
 */
 bool BamAlignment::HasTag(const std::string& tag) const {
@@ -688,17 +812,14 @@ bool BamAlignment::IsSecondMate(void) const {
     return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_READ_2) != 0 );
 }
 
     return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_READ_2) != 0 );
 }
 
-/*! \fn bool BamAlignment::IsValidSize(const string& tag, const string& type) const
+/*! \fn bool BamAlignment::IsValidSize(const std::string& tag, const std::string& type) const
     \internal
 
     Checks that tag name & type strings are expected sizes.
     \internal
 
     Checks that tag name & type strings are expected sizes.
-    \a tag  should have length
-    \a type should have length 1
-
-    \param tag  BAM tag name
-    \param type BAM tag type-code
 
 
-    \return \c true if both \a tag and \a type are correct sizes
+    \param tag[in]  BAM tag name
+    \param type[in] BAM tag type-code
+    \return \c true if both input strings are valid sizes
 */
 bool BamAlignment::IsValidSize(const std::string& tag, const std::string& type) const {
     return (tag.size()  == Constants::BAM_TAG_TAGSIZE) &&
 */
 bool BamAlignment::IsValidSize(const std::string& tag, const std::string& type) const {
     return (tag.size()  == Constants::BAM_TAG_TAGSIZE) &&
@@ -707,6 +828,8 @@ bool BamAlignment::IsValidSize(const std::string& tag, const std::string& type)
 
 /*! \fn void BamAlignment::RemoveTag(const std::string& tag)
     \brief Removes field from BAM tags.
 
 /*! \fn void BamAlignment::RemoveTag(const std::string& tag)
     \brief Removes field from BAM tags.
+
+    \param[in] tag 2-character name of field to remove
 */
 void BamAlignment::RemoveTag(const std::string& tag) {
   
 */
 void BamAlignment::RemoveTag(const std::string& tag) {
   
@@ -759,6 +882,9 @@ void BamAlignment::RemoveTag(const std::string& tag) {
     \internal
 
     Sets a formatted error string for this alignment.
     \internal
 
     Sets a formatted error string for this alignment.
+
+    \param[in] where class/method where error occurred
+    \param[in] what  description of error
 */
 void BamAlignment::SetErrorString(const std::string& where, const std::string& what) const {
     static const string SEPARATOR = ": ";
 */
 void BamAlignment::SetErrorString(const std::string& where, const std::string& what) const {
     static const string SEPARATOR = ": ";
@@ -805,15 +931,6 @@ void BamAlignment::SetIsMateMapped(bool ok) {
     else    AlignmentFlag |=  Constants::BAM_ALIGNMENT_MATE_UNMAPPED;
 }
 
     else    AlignmentFlag |=  Constants::BAM_ALIGNMENT_MATE_UNMAPPED;
 }
 
-/*! \fn void BamAlignment::SetIsMateUnmapped(bool ok)
-    \brief Complement of using SetIsMateMapped().
-    \deprecated For sake of symmetry with the query methods
-    \sa IsMateMapped(), SetIsMateMapped()
-*/
-void BamAlignment::SetIsMateUnmapped(bool ok) {
-    SetIsMateMapped(!ok);
-}
-
 /*! \fn void BamAlignment::SetIsMateReverseStrand(bool ok)
     \brief Sets "alignment's mate mapped to reverse strand" flag to \a ok.
 */
 /*! \fn void BamAlignment::SetIsMateReverseStrand(bool ok)
     \brief Sets "alignment's mate mapped to reverse strand" flag to \a ok.
 */
@@ -854,15 +971,6 @@ void BamAlignment::SetIsReverseStrand(bool ok) {
     else    AlignmentFlag &= ~Constants::BAM_ALIGNMENT_REVERSE_STRAND;
 }
 
     else    AlignmentFlag &= ~Constants::BAM_ALIGNMENT_REVERSE_STRAND;
 }
 
-/*! \fn void BamAlignment::SetIsSecondaryAlignment(bool ok)
-    \brief Complement of using SetIsPrimaryAlignment().
-    \deprecated For sake of symmetry with the query methods
-    \sa IsPrimaryAlignment(), SetIsPrimaryAlignment()
-*/
-void BamAlignment::SetIsSecondaryAlignment(bool ok) {
-    SetIsPrimaryAlignment(!ok);
-}
-
 /*! \fn void BamAlignment::SetIsSecondMate(bool ok)
     \brief Sets "alignment is second mate on read" flag to \a ok.
 */
 /*! \fn void BamAlignment::SetIsSecondMate(bool ok)
     \brief Sets "alignment is second mate on read" flag to \a ok.
 */
@@ -871,26 +979,18 @@ void BamAlignment::SetIsSecondMate(bool ok) {
     else    AlignmentFlag &= ~Constants::BAM_ALIGNMENT_READ_2;
 }
 
     else    AlignmentFlag &= ~Constants::BAM_ALIGNMENT_READ_2;
 }
 
-/*! \fn void BamAlignment::SetIsUnmapped(bool ok)
-    \brief Complement of using SetIsMapped().
-    \deprecated For sake of symmetry with the query methods
-    \sa IsMapped(), SetIsMapped()
-*/
-void BamAlignment::SetIsUnmapped(bool ok) {
-    SetIsMapped(!ok);
-}
-
-/*! \fn bool BamAlignment::SkipToNextTag(const char storageType, char*& pTagData, unsigned int& numBytesParsed)
+/*! \fn bool BamAlignment::SkipToNextTag(const char storageType, char*& pTagData, unsigned int& numBytesParsed) const
     \internal
 
     Moves to next available tag in tag data string
 
     \internal
 
     Moves to next available tag in tag data string
 
-    \param storageType    BAM tag type-code that determines how far to move cursor
-    \param pTagData       pointer to current position (cursor) in tag string
-    \param numBytesParsed report of how many bytes were parsed (cumulatively)
+    \param[in]     storageType    BAM tag type-code that determines how far to move cursor
+    \param[in,out] pTagData       pointer to current position (cursor) in tag string
+    \param[in,out] numBytesParsed report of how many bytes were parsed (cumulatively)
 
     \return \c if storageType was a recognized BAM tag type
 
     \return \c if storageType was a recognized BAM tag type
-    \post \a pTagData will point to the byte where the next tag data begins.
+
+    \post \a pTagData       will point to the byte where the next tag data begins.
           \a numBytesParsed will correspond to the cursor's position in the full TagData string.
 */
 bool BamAlignment::SkipToNextTag(const char storageType,
           \a numBytesParsed will correspond to the cursor's position in the full TagData string.
 */
 bool BamAlignment::SkipToNextTag(const char storageType,