]> git.donarmstrong.com Git - bamtools.git/commitdiff
Fixed variable length tag data retrieval in BamAlignment::GetTag(). To do this, remov...
authorDerek <derekwbarnett@gmail.com>
Thu, 22 Jul 2010 16:18:16 +0000 (12:18 -0400)
committerDerek <derekwbarnett@gmail.com>
Thu, 22 Jul 2010 16:18:16 +0000 (12:18 -0400)
BamAux.h

index 2578bf87ab6c4f6c2f057ec9d826b400d8532459..6387dd33a54e3a879c43362ab7108e1fe259d156 100644 (file)
--- a/BamAux.h
+++ b/BamAux.h
@@ -24,6 +24,9 @@
 #include <utility>\r
 #include <vector>\r
 \r
+#include <iostream>\r
+#include <typeinfo>\r
+\r
 // Platform-specific type definitions\r
 #ifndef BAMTOOLS_TYPES\r
 #define BAMTOOLS_TYPES\r
@@ -103,11 +106,16 @@ struct BamAlignment {
 \r
     // Tag data access methods\r
     public:\r
-        bool GetEditDistance(uint8_t& editDistance) const;     // get "NM" tag data - contributed by Aaron Quinlan\r
-        bool GetReadGroup(std::string& readGroup) const;       // get "RG" tag data\r
+        // generic tag data access methods \r
+        bool GetTag(const std::string& tag, std::string& destination) const;    // access variable-length char or hex strings \r
+        bool GetTag(const std::string& tag, uint32_t& destination) const;       // access unsigned integer data\r
+        bool GetTag(const std::string& tag, int32_t& destination) const;        // access signed integer data\r
+        bool GetTag(const std::string& tag, float& destination) const;          // access floating point data\r
         \r
-        bool GetTag(const std::string& tag, std::string& destination);\r
-        template<typename T> bool GetTag(const std::string& tag, T& destination);\r
+        // specific tag data access methods - only remain here for legacy support\r
+        bool GetEditDistance(uint8_t& editDistance) const;      // get "NM" tag data - contributed by Aaron Quinlan\r
+        bool GetReadGroup(std::string& readGroup) const;        // get "RG" tag data\r
+\r
 \r
     // Additional data access methods\r
     public:\r
@@ -115,7 +123,7 @@ struct BamAlignment {
 \r
     // 'internal' utility methods \r
     private:\r
-        static void SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed);\r
+        static bool SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed);\r
 \r
     // Data members\r
     public:\r
@@ -313,7 +321,8 @@ int BamAlignment::GetEndPosition(bool usePadded) const {
 inline \r
 bool BamAlignment::GetEditDistance(uint8_t& editDistance) const {\r
 \r
-    if ( TagData.empty() ) { return false; }\r
+    // make sure tag data exists\r
+    if ( TagData.empty() ) return false;\r
 \r
     // localize the tag data\r
     char* pTagData = (char*)TagData.data();\r
@@ -321,7 +330,7 @@ bool BamAlignment::GetEditDistance(uint8_t& editDistance) const {
     unsigned int numBytesParsed = 0;\r
 \r
     bool foundEditDistanceTag = false;\r
-    while( numBytesParsed < tagDataLen ) {\r
+    while ( numBytesParsed < tagDataLen ) {\r
 \r
         const char* pTagType = pTagData;\r
         const char* pTagStorageType = pTagData + 2;\r
@@ -335,12 +344,12 @@ bool BamAlignment::GetEditDistance(uint8_t& editDistance) const {
         }\r
 \r
         // get the storage class and find the next tag\r
-        if (*pTagStorageType == '\0') { return false; }\r
-        SkipToNextTag( *pTagStorageType, pTagData, numBytesParsed );\r
-        if (*pTagData == '\0') { return false; }\r
+        if ( *pTagStorageType == '\0' ) return false;\r
+        if ( !SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) ) return false;\r
+        if ( *pTagData == '\0' ) return false;\r
     }\r
     // return if the edit distance tag was not present\r
-    if ( !foundEditDistanceTag ) { return false; }\r
+    if ( !foundEditDistanceTag ) return false;\r
 \r
     // assign the editDistance value\r
     std::memcpy(&editDistance, pTagData, 1);\r
@@ -352,7 +361,8 @@ bool BamAlignment::GetEditDistance(uint8_t& editDistance) const {
 inline \r
 bool BamAlignment::GetReadGroup(std::string& readGroup) const {\r
 \r
-    if ( TagData.empty() ) { return false; }\r
+    // make sure tag data exists\r
+    if ( TagData.empty() ) return false;\r
 \r
     // localize the tag data\r
     char* pTagData = (char*)TagData.data();\r
@@ -374,13 +384,13 @@ bool BamAlignment::GetReadGroup(std::string& readGroup) const {
         }\r
 \r
         // get the storage class and find the next tag\r
-        if (*pTagStorageType == '\0') { return false; }\r
-        SkipToNextTag( *pTagStorageType, pTagData, numBytesParsed );\r
-        if (*pTagData == '\0') { return false; }\r
+        if ( *pTagStorageType == '\0' ) return false;\r
+        if ( !SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) ) return false;\r
+        if ( *pTagData == '\0' ) return false;\r
     }\r
 \r
     // return if the read group tag was not present\r
-    if ( !foundReadGroupTag ) { return false; }\r
+    if ( !foundReadGroupTag ) return false;\r
 \r
     // assign the read group\r
     const unsigned int readGroupLen = std::strlen(pTagData);\r
@@ -390,9 +400,10 @@ bool BamAlignment::GetReadGroup(std::string& readGroup) const {
 }\r
 \r
 inline\r
-bool BamAlignment::GetTag(const std::string& tag, std::string& destination) {\r
+bool BamAlignment::GetTag(const std::string& tag, std::string& destination) const {\r
   \r
-    if ( TagData.empty() ) { return false; }\r
+    // make sure tag data exists\r
+    if ( TagData.empty() ) return false;\r
 \r
     // localize the tag data\r
     char* pTagData = (char*)TagData.data();\r
@@ -400,7 +411,7 @@ bool BamAlignment::GetTag(const std::string& tag, std::string& destination) {
     unsigned int numBytesParsed = 0;\r
 \r
     bool foundReadGroupTag = false;\r
-    while( numBytesParsed < tagDataLen ) {\r
+    while ( numBytesParsed < tagDataLen ) {\r
 \r
         const char* pTagType = pTagData;\r
         const char* pTagStorageType = pTagData + 2;\r
@@ -414,13 +425,13 @@ bool BamAlignment::GetTag(const std::string& tag, std::string& destination) {
         }\r
 \r
         // get the storage class and find the next tag\r
-        if (*pTagStorageType == '\0') { return false; }\r
-        SkipToNextTag( *pTagStorageType, pTagData, numBytesParsed );\r
-        if (*pTagData == '\0') { return false; }\r
+        if ( *pTagStorageType == '\0' ) return false; \r
+        if ( !SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) ) return false;\r
+        if ( *pTagData == '\0' ) return false;\r
     }\r
 \r
     // return if the read group tag was not present\r
-    if ( !foundReadGroupTag ) { return false; }\r
+    if ( !foundReadGroupTag ) return false;\r
 \r
     // assign the read group\r
     const unsigned int dataLen = std::strlen(pTagData);\r
@@ -429,16 +440,106 @@ bool BamAlignment::GetTag(const std::string& tag, std::string& destination) {
     return true;\r
 }\r
 \r
-template<typename T> \r
-bool BamAlignment::GetTag(const std::string& tag, T& destination) {\r
+inline\r
+bool BamAlignment::GetTag(const std::string& tag, uint32_t& destination) const {\r
   \r
-    if ( TagData.empty() ) { return false; }\r
+    // make sure data exists\r
+    if ( TagData.empty() ) return false;\r
+\r
+    // clear out destination\r
+    destination = 0;\r
 \r
     // localize the tag data\r
     char* pTagData = (char*)TagData.data();\r
     const unsigned int tagDataLen = TagData.size();\r
     unsigned int numBytesParsed = 0;\r
 \r
+    int destinationLength = 0;    \r
+    bool foundDesiredTag = false;\r
+    while ( numBytesParsed < tagDataLen ) {\r
+\r
+        const char* pTagType = pTagData;\r
+        const char* pTagStorageType = pTagData + 2;\r
+        pTagData       += 3;\r
+        numBytesParsed += 3;\r
+\r
+        // check the current tag\r
+        if ( strncmp(pTagType, tag.c_str(), 2) == 0 ) {\r
+            \r
+            // determine actual length of data depending on tag type\r
+            // this is necessary because some tags may be of variable byte-lengths (i.e. char or short)\r
+            const char type = *pTagStorageType;\r
+            switch(type) {\r
+\r
+                // 1 byte data\r
+                case 'A':\r
+                case 'c':\r
+                case 'C':\r
+                    destinationLength = 1;\r
+                    break;\r
+\r
+                // 2 byte data\r
+                case 's':\r
+                case 'S':\r
+                    destinationLength = 2;\r
+                    break;\r
+\r
+                // 4 byte data\r
+                case 'i':\r
+                case 'I':\r
+                    destinationLength = 4;\r
+                    break;\r
+\r
+                // unsupported type for integer destination (float & var-length strings)\r
+                case 'f':\r
+                case 'Z':\r
+                case 'H':\r
+                    printf("ERROR: Cannot store tag of type %c in integer destination\n", type);\r
+                    return false;\r
+\r
+                // unknown tag type\r
+                default:\r
+                    printf("ERROR: Unknown tag storage class encountered: [%c]\n", *pTagData);\r
+                    return false;\r
+            }\r
+            \r
+            foundDesiredTag = true;\r
+            break;\r
+        }\r
+\r
+        // get the storage class and find the next tag\r
+        if ( *pTagStorageType == '\0' ) return false;\r
+        if ( !SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) ) return false;\r
+        if ( *pTagData == '\0' ) return false;\r
+    }\r
+    // return if the edit distance tag was not present\r
+    if ( !foundDesiredTag ) return false; \r
+\r
+    // assign the editDistance value\r
+    std::memcpy(&destination, pTagData, destinationLength);\r
+    return true;\r
+}\r
+\r
+inline\r
+bool BamAlignment::GetTag(const std::string& tag, int32_t& destination) const {\r
+    return GetTag(tag, (uint32_t&)destination);\r
+}\r
+\r
+inline\r
+bool BamAlignment::GetTag(const std::string& tag, float& destination) const {\r
+  \r
+    // make sure data exists\r
+    if ( TagData.empty() ) return false;\r
+\r
+    // clear out destination\r
+    destination = 0.0;\r
+\r
+    // localize the tag data\r
+    char* pTagData = (char*)TagData.data();\r
+    const unsigned int tagDataLen = TagData.size();\r
+    unsigned int numBytesParsed = 0;\r
+\r
+    int destinationLength = 0;\r
     bool foundDesiredTag = false;\r
     while( numBytesParsed < tagDataLen ) {\r
 \r
@@ -449,25 +550,63 @@ bool BamAlignment::GetTag(const std::string& tag, T& destination) {
 \r
         // check the current tag\r
         if ( strncmp(pTagType, tag.c_str(), 2) == 0 ) {\r
+          \r
+            // determine actual length of data depending on tag type\r
+            // this is necessary because some tags may be of variable byte-lengths (i.e. char or short)\r
+            const char type = *pTagStorageType;\r
+            switch(type) {\r
+\r
+                // 1 byte data\r
+                case 'A':\r
+                case 'c':\r
+                case 'C':\r
+                    destinationLength = 1;\r
+                    break;\r
+\r
+                // 2 byte data\r
+                case 's':\r
+                case 'S':\r
+                    destinationLength = 2;\r
+                    break;\r
+\r
+                // 4 byte data\r
+                case 'f':\r
+                case 'i':\r
+                case 'I':\r
+                    destinationLength = 4;\r
+                    break;\r
+                \r
+                // unsupported type (var-length strings)\r
+                case 'Z':\r
+                case 'H':\r
+                    printf("ERROR: Cannot store tag of type %c in integer destination\n", type);\r
+                    return false;\r
+\r
+                // unknown tag type\r
+                default:\r
+                    printf("ERROR: Unknown tag storage class encountered: [%c]\n", *pTagData);\r
+                    return false;\r
+            }\r
+            \r
             foundDesiredTag = true;\r
             break;\r
         }\r
 \r
         // get the storage class and find the next tag\r
-        if (*pTagStorageType == '\0') { return false; }\r
-        SkipToNextTag( *pTagStorageType, pTagData, numBytesParsed );\r
-        if (*pTagData == '\0') { return false; }\r
+        if ( *pTagStorageType == '\0' ) return false;\r
+        if ( !SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) ) return false;\r
+        if ( *pTagData == '\0' ) return false;\r
     }\r
     // return if the edit distance tag was not present\r
-    if ( !foundDesiredTag ) { return false; }\r
+    if ( !foundDesiredTag ) return false; \r
 \r
     // assign the editDistance value\r
-    std::memcpy(&destination, pTagData, sizeof(T));\r
+    std::memcpy(&destination, pTagData, destinationLength);\r
     return true;\r
 }\r
 \r
 inline\r
-void BamAlignment::SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed) {\r
+bool BamAlignment::SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed) {\r
     \r
     switch(storageType) {\r
 \r
@@ -505,10 +644,14 @@ void BamAlignment::SkipToNextTag(const char storageType, char* &pTagData, unsign
         // ---------------------------\r
             break;\r
 \r
-        default:\r
+        default: \r
+            // error case\r
             printf("ERROR: Unknown tag storage class encountered: [%c]\n", *pTagData);\r
-            exit(1);\r
+            return false;\r
     }\r
+    \r
+    // return success\r
+    return true;\r
 }\r
 \r
 // ----------------------------------------------------------------\r