#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
\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
\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
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
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
}\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
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
}\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
}\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
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
}\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
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
\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
// ---------------------------\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