const std::string bamtoolsIndexFilename = bamFilename + ".bti";
const bool bamtoolsIndexExists = BamTools::FileExists(bamtoolsIndexFilename);
if ( (type == BamIndex::BAMTOOLS) && bamtoolsIndexExists )
- return new BamToolsIndex(bgzf, reader);
+ return new BamToolsIndex(bgzf, reader);
const std::string standardIndexFilename = bamFilename + ".bai";
const bool standardIndexExists = BamTools::FileExists(standardIndexFilename);
if ( (type == BamIndex::STANDARD) && standardIndexExists )
- return new BamStandardIndex(bgzf, reader);
+ return new BamStandardIndex(bgzf, reader);
// ----------------------------------------------------
// preferred type could not be found, try other (non-preferred) types
if ( bamtoolsIndexExists ) return new BamToolsIndex(bgzf, reader);
if ( standardIndexExists ) return new BamStandardIndex(bgzf, reader);
- return 0;
+ return 0;
}
// returns index based on explicitly named index file (or 0 if not found)
// if has bamtoolsIndexExtension
if ( indexFilename.find(bamtoolsIndexExtension) == (indexFilename.length() - bamtoolsIndexExtension.length()) )
- return new BamToolsIndex(bgzf, reader);
+ return new BamToolsIndex(bgzf, reader);
// if has standardIndexExtension
if ( indexFilename.find(standardIndexExtension) == (indexFilename.length() - standardIndexExtension.length()) )
- return new BamStandardIndex(bgzf, reader);
+ return new BamStandardIndex(bgzf, reader);
// otherwise, unsupported file type
return 0;
virtual bool Jump(const BamTools::BamRegion& region, bool* hasAlignmentsInRegion) =0;
// loads existing data from file into memory
virtual bool Load(const std::string& filename);
- // change the index caching behavior
+ // change the index caching behavior
virtual void SetCacheMode(const BamIndexCacheMode mode);
// writes in-memory index data out to file
// N.B. - (this is the original BAM filename, method will modify it to use applicable extension)
FILE* m_indexStream;
+ // friends
friend class Internal::BamStandardIndex;
friend class Internal::BamToolsIndex;
};
bool BamReader::IsOpen(void) const { return d->mBGZF.IsOpen; }
bool BamReader::Jump(int refID, int position) { return d->SetRegion( BamRegion(refID, position) ); }
bool BamReader::Open(const std::string& filename,
- const std::string& indexFilename,
- const bool lookForIndex,
- const bool preferStandardIndex)
+ const std::string& indexFilename,
+ const bool lookForIndex,
+ const bool preferStandardIndex)
{
return d->Open(filename, indexFilename, lookForIndex, preferStandardIndex);
}
bool Jump(int refID, int position = 0);\r
// opens BAM file (and optional BAM index file, if provided)\r
// @lookForIndex - if no indexFilename provided, look in BAM file's directory for an existing index file\r
- // default behavior is to skip index file search if no index filename given\r
+ // default behavior is to skip index file search if no index filename given\r
// @preferStandardIndex - if true, give priority in index file searching to standard BAM index (*.bai)\r
- // default behavior is to prefer the BamToolsIndex (*.bti) if both are available\r
+ // default behavior is to prefer the BamToolsIndex (*.bti) if both are available\r
bool Open(const std::string& filename, \r
const std::string& indexFilename = "", \r
const bool lookForIndex = false, \r
// retrieves next available alignment core data (returns success/fail)\r
// ** DOES NOT parse any character data (read name, bases, qualities, tag data) **\r
// useful for operations requiring ONLY aligner-related information \r
- // (refId/position, alignment flags, CIGAR, mapQuality, etc)\r
+ // (refId/position, alignment flags, CIGAR, mapQuality, etc)\r
bool GetNextAlignmentCore(BamAlignment& bAlignment);\r
\r
// ----------------------\r
// default behavior is to create the BAM standard index (".bai")\r
// set flag to false to create the BamTools-specific index (".bti")\r
bool CreateIndex(bool useStandardIndex = true);\r
- // returns whether index data is available for reading \r
- // (e.g. if true, BamReader should be able to seek to a region)\r
- bool HasIndex(void) const;\r
- // change the index caching behavior\r
- // default BamReader/Index mode is LimitedIndexCaching\r
- // @mode - can be either FullIndexCaching, LimitedIndexCaching, \r
- // or NoIndexCaching. See BamIndex.h for more details\r
+ // returns whether index data is available for reading\r
+ // (e.g. if true, BamReader should be able to seek to a region)\r
+ bool HasIndex(void) const;\r
+ // change the index caching behavior\r
+ // default BamReader/Index mode is LimitedIndexCaching\r
+ // @mode - can be either FullIndexCaching, LimitedIndexCaching,\r
+ // or NoIndexCaching. See BamIndex.h for more details\r
void SetIndexCacheMode(const BamIndex::BamIndexCacheMode mode);\r
\r
// deprecated methods\r
public:\r
\r
- // deprecated (but still available): prefer HasIndex() instead\r
- //\r
- // Deprecated purely for API semantic clarity - HasIndex() should be clearer \r
- // than IsIndexLoaded() in light of the new caching modes that may clear the \r
- // index data from memory, but leave the index file open for later random access \r
- // seeks.\r
- //\r
- // For example, what would (IsIndexLoaded() == true) mean when cacheMode has been \r
- // explicitly set to NoIndexCaching? This is confusing at best, misleading about \r
- // current memory behavior at worst.\r
- //\r
- // returns whether index data is available \r
- // (e.g. if true, BamReader should be able to seek to a region)\r
+ // deprecated (but still available): prefer HasIndex() instead\r
+ //\r
+ // Deprecated purely for API semantic clarity - HasIndex() should be clearer\r
+ // than IsIndexLoaded() in light of the new caching modes that may clear the\r
+ // index data from memory, but leave the index file open for later random access\r
+ // seeks.\r
+ //\r
+ // For example, what would (IsIndexLoaded() == true) mean when cacheMode has been\r
+ // explicitly set to NoIndexCaching? This is confusing at best, misleading about\r
+ // current memory behavior at worst.\r
+ //\r
+ // returns whether index data is available\r
+ // (e.g. if true, BamReader should be able to seek to a region)\r
bool IsIndexLoaded(void) const;\r
\r
// private implementation\r
private:\r
- Internal::BamReaderPrivate* d;\r
+ Internal::BamReaderPrivate* d;\r
};\r
\r
} // namespace BamTools\r
\r
// closes the alignment archive\r
void BamWriter::Close(void) {\r
- d->Close();\r
+ d->Close();\r
}\r
\r
// opens the alignment archive\r
bool BamWriter::Open(const string& filename,\r
- const string& samHeader,\r
- const RefVector& referenceSequences,\r
- bool isWriteUncompressed)\r
+ const string& samHeader,\r
+ const RefVector& referenceSequences,\r
+ bool isWriteUncompressed)\r
{\r
return d->Open(filename, samHeader, referenceSequences, isWriteUncompressed);\r
}\r
\r
// private implementation\r
private:\r
- Internal::BamWriterPrivate* d;\r
+ Internal::BamWriterPrivate* d;\r
};\r
\r
} // namespace BamTools\r
switch (type) {
- case('A') :
- case('C') :
- ++i;
- break;
-
- case('S') :
- SwapEndian_16p(&tagData[i]);
- i += sizeof(uint16_t);
- break;
-
- case('F') :
- case('I') :
- SwapEndian_32p(&tagData[i]);
- i += sizeof(uint32_t);
- break;
-
- case('D') :
- SwapEndian_64p(&tagData[i]);
- i += sizeof(uint64_t);
- break;
-
- case('H') :
- case('Z') :
- while (tagData[i]) { ++i; }
- ++i; // increment one more for null terminator
- break;
-
- default :
- fprintf(stderr, "ERROR: Invalid tag value type\n"); // shouldn't get here
- exit(1);
+ case('A') :
+ case('C') :
+ ++i;
+ break;
+
+ case('S') :
+ SwapEndian_16p(&tagData[i]);
+ i += sizeof(uint16_t);
+ break;
+
+ case('F') :
+ case('I') :
+ SwapEndian_32p(&tagData[i]);
+ i += sizeof(uint32_t);
+ break;
+
+ case('D') :
+ SwapEndian_64p(&tagData[i]);
+ i += sizeof(uint64_t);
+ break;
+
+ case('H') :
+ case('Z') :
+ while (tagData[i]) { ++i; }
+ ++i; // increment one more for null terminator
+ break;
+
+ default :
+ fprintf(stderr, "ERROR: Invalid tag value type\n"); // shouldn't get here
+ exit(1);
}
}
}
// Marth Lab, Department of Biology, Boston College
// All rights reserved.
// ---------------------------------------------------------------------------
-// Last modified: 5 December 2010
+// Last modified: 13 December 2010
// ---------------------------------------------------------------------------
// Integrates a number of BamTools functionalities into a single executable.
// ***************************************************************************
-// stringify version information
-#define BAMTOOLS_VER1_(x) #x
-#define BAMTOOLS_VER_(x) BAMTOOLS_VER1_(x)
-#define BAMTOOLS_VERSION BAMTOOLS_VER_(BT_VERSION)
-
// includes
-#include <cstdio>
-#include <iostream>
-#include <sstream>
-#include <string>
#include "bamtools_convert.h"
#include "bamtools_count.h"
#include "bamtools_coverage.h"
#include "bamtools_split.h"
#include "bamtools_stats.h"
#include "bamtools_version.h"
-using namespace std;
+
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+#include <string>
+
using namespace BamTools;
+using namespace std;
// bamtools subtool names
static const string CONVERT = "convert";
cerr << "\tindex Generates index for BAM file" << endl;
cerr << "\tmerge Merge multiple BAM files into single file" << endl;
cerr << "\trandom Select random alignments from existing BAM file(s)" << endl;
+ cerr << "\trevert Removes duplicate marks and restores original base qualities" << endl;
cerr << "\tsort Sorts the BAM file according to some criteria" << endl;
cerr << "\tsplit Splits a BAM file on user-specified property, creating a new BAM output file for each value found" << endl;
cerr << "\tstats Prints some basic statistics from input BAM file(s)" << endl;
stringstream versionStream("");
versionStream << BAMTOOLS_VERSION_MAJOR << "."
- << BAMTOOLS_VERSION_MINOR << "."
- << BAMTOOLS_VERSION_BUILD;
+ << BAMTOOLS_VERSION_MINOR << "."
+ << BAMTOOLS_VERSION_BUILD;
cout << endl;
cout << "bamtools " << versionStream.str() << endl;
void PrintJson(const BamAlignment& a);
void PrintSam(const BamAlignment& a);
void PrintWiggle(const BamAlignment& a);
- void PrintYaml(const BamAlignment& a);
+ void PrintYaml(const BamAlignment& a);
// special case - uses the PileupEngine
bool RunPileupConversion(BamMultiReader* reader);
// iterate through file, doing conversion
BamAlignment a;
- while ( reader.GetNextAlignment(a) )
+ while ( reader.GetNextAlignment(a) )
(this->*pFunction)(a);
// set flag for successful conversion
// write Cigar data
const vector<CigarOp>& cigarData = a.CigarData;
if ( !cigarData.empty() ) {
- m_out << " " << "Cigar: ";
- vector<CigarOp>::const_iterator cigarBegin = cigarData.begin();
- vector<CigarOp>::const_iterator cigarIter = cigarBegin;
- vector<CigarOp>::const_iterator cigarEnd = cigarData.end();
- for ( ; cigarIter != cigarEnd; ++cigarIter ) {
- const CigarOp& op = (*cigarIter);
- m_out << op.Length << op.Type;
- }
- m_out << endl;
+ m_out << " " << "Cigar: ";
+ vector<CigarOp>::const_iterator cigarBegin = cigarData.begin();
+ vector<CigarOp>::const_iterator cigarIter = cigarBegin;
+ vector<CigarOp>::const_iterator cigarEnd = cigarData.end();
+ for ( ; cigarIter != cigarEnd; ++cigarIter ) {
+ const CigarOp& op = (*cigarIter);
+ m_out << op.Length << op.Type;
+ }
+ m_out << endl;
}
}
// if no region specified, count entire file
if ( !m_settings->HasRegion ) {
- while ( reader.GetNextAlignmentCore(al) )
+ while ( reader.GetNextAlignmentCore(al) )
++alignmentCount;
}
const PropertyFilterValue& valueFilter = (*propertyIter).second;
if ( propertyName == ALIGNMENTFLAG_PROPERTY ) keepAlignment &= valueFilter.check(al.AlignmentFlag);
- else if ( propertyName == CIGAR_PROPERTY ) {
+ else if ( propertyName == CIGAR_PROPERTY ) {
stringstream cigarSs;
const vector<CigarOp>& cigarData = al.CigarData;
if ( !cigarData.empty() ) {
bool checkAlignmentTag(const PropertyFilterValue& valueFilter, const BamAlignment& al) {
- // ensure filter contains string data
- Variant entireTagFilter = valueFilter.Value;
- if ( !entireTagFilter.is_type<string>() ) return false;
-
- // localize string from variant
- const string& entireTagFilterString = entireTagFilter.get<string>();
-
- // ensure we have at least "XX:x"
- if ( entireTagFilterString.length() < 4 ) return false;
-
- // get tagName & lookup in alignment
- // if found, set tagType to tag type character
- // if not found, return false
- const string& tagName = entireTagFilterString.substr(0,2);
- char tagType = '\0';
- if ( !al.GetTagType(tagName, tagType) ) return false;
-
- // remove tagName & ":" from beginning tagFilter
- string tagFilterString = entireTagFilterString.substr(3);
-
- // switch on tag type to set tag query value & parse filter token
- int32_t intFilterValue, intQueryValue;
- uint32_t uintFilterValue, uintQueryValue;
- float realFilterValue, realQueryValue;
- string stringFilterValue, stringQueryValue;
-
- PropertyFilterValue tagFilter;
- PropertyFilterValue::ValueCompareType compareType;
- bool keepAlignment = false;
- switch (tagType) {
-
- // signed int tag type
- case 'c' :
- case 's' :
+ // ensure filter contains string data
+ Variant entireTagFilter = valueFilter.Value;
+ if ( !entireTagFilter.is_type<string>() ) return false;
+
+ // localize string from variant
+ const string& entireTagFilterString = entireTagFilter.get<string>();
+
+ // ensure we have at least "XX:x"
+ if ( entireTagFilterString.length() < 4 ) return false;
+
+ // get tagName & lookup in alignment
+ // if found, set tagType to tag type character
+ // if not found, return false
+ const string& tagName = entireTagFilterString.substr(0,2);
+ char tagType = '\0';
+ if ( !al.GetTagType(tagName, tagType) ) return false;
+
+ // remove tagName & ":" from beginning tagFilter
+ string tagFilterString = entireTagFilterString.substr(3);
+
+ // switch on tag type to set tag query value & parse filter token
+ int32_t intFilterValue, intQueryValue;
+ uint32_t uintFilterValue, uintQueryValue;
+ float realFilterValue, realQueryValue;
+ string stringFilterValue, stringQueryValue;
+
+ PropertyFilterValue tagFilter;
+ PropertyFilterValue::ValueCompareType compareType;
+ bool keepAlignment = false;
+ switch (tagType) {
+
+ // signed int tag type
+ case 'c' :
+ case 's' :
case 'i' :
- if ( al.GetTag(tagName, intQueryValue) ) {
- if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, intFilterValue, compareType) ) {
- tagFilter.Value = intFilterValue;
- tagFilter.Type = compareType;
- keepAlignment = tagFilter.check(intQueryValue);
- }
- }
- break;
-
- // unsigned int tag type
+ if ( al.GetTag(tagName, intQueryValue) ) {
+ if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, intFilterValue, compareType) ) {
+ tagFilter.Value = intFilterValue;
+ tagFilter.Type = compareType;
+ keepAlignment = tagFilter.check(intQueryValue);
+ }
+ }
+ break;
+
+ // unsigned int tag type
case 'C' :
case 'S' :
- case 'I' :
- if ( al.GetTag(tagName, uintQueryValue) ) {
- if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, uintFilterValue, compareType) ) {
- tagFilter.Value = uintFilterValue;
- tagFilter.Type = compareType;
- keepAlignment = tagFilter.check(uintQueryValue);
- }
- }
- break;
-
- // 'real' tag type
+ case 'I' :
+ if ( al.GetTag(tagName, uintQueryValue) ) {
+ if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, uintFilterValue, compareType) ) {
+ tagFilter.Value = uintFilterValue;
+ tagFilter.Type = compareType;
+ keepAlignment = tagFilter.check(uintQueryValue);
+ }
+ }
+ break;
+
+ // 'real' tag type
case 'f' :
- if ( al.GetTag(tagName, realQueryValue) ) {
- if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, realFilterValue, compareType) ) {
- tagFilter.Value = realFilterValue;
- tagFilter.Type = compareType;
- keepAlignment = tagFilter.check(realQueryValue);
- }
- }
+ if ( al.GetTag(tagName, realQueryValue) ) {
+ if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, realFilterValue, compareType) ) {
+ tagFilter.Value = realFilterValue;
+ tagFilter.Type = compareType;
+ keepAlignment = tagFilter.check(realQueryValue);
+ }
+ }
break;
-
- // string tag type
+
+ // string tag type
case 'A':
case 'Z':
- case 'H':
+ case 'H':
if ( al.GetTag(tagName, stringQueryValue) ) {
- if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, stringFilterValue, compareType) ) {
- tagFilter.Value = stringFilterValue;
- tagFilter.Type = compareType;
- keepAlignment = tagFilter.check(stringQueryValue);
- }
- }
- break;
-
- // unknown tag type
- default :
- keepAlignment = false;
- }
-
- return keepAlignment;
+ if ( FilterEngine<BamAlignmentChecker>::parseToken(tagFilterString, stringFilterValue, compareType) ) {
+ tagFilter.Value = stringFilterValue;
+ tagFilter.Type = compareType;
+ keepAlignment = tagFilter.check(stringQueryValue);
+ }
+ }
+ break;
+
+ // unknown tag type
+ default :
+ keepAlignment = false;
+ }
+
+ return keepAlignment;
}
};
// attempt to re-open reader with index files
reader.Close();
- bool openedOK = reader.Open(m_settings->InputFiles, true, false );
+ bool openedOK = reader.Open(m_settings->InputFiles, true, false );
// if error
if ( !openedOK ) {
cerr << "ERROR: Could not open input BAM file(s)... Aborting." << endl;
- return false;
+ return false;
}
// if index data available, we can use SetRegion
if ( !reader.SetRegion(region.LeftRefID, region.LeftPosition, region.RightRefID, region.RightPosition) ) {
cerr << "ERROR: Region requested, but could not set BamReader region to REGION: " << m_settings->Region << " Aborting." << endl;
reader.Close();
- return false;
+ return false;
}
// everything checks out, just iterate through specified region, filtering alignments
- while ( reader.GetNextAlignment(al) )
+ while ( reader.GetNextAlignment(al) )
if ( CheckAlignment(al) )
writer.SaveAlignment(al);
- }
+ }
// no index data available, we have to iterate through until we
// find overlapping alignments
else {
- while ( reader.GetNextAlignment(al) ) {
+ while ( reader.GetNextAlignment(al) ) {
if ( (al.RefID >= region.LeftRefID) && ((al.Position + al.Length) >= region.LeftPosition) &&
(al.RefID <= region.RightRefID) && ( al.Position <= region.RightPosition) )
{
cerr << "ERROR: Could not parse REGION - " << m_settings->Region << endl;
cerr << "Be sure REGION is in valid format (see README) and that coordinates are valid for selected references" << endl;
reader.Close();
- return false;
+ return false;
}
}
// Marth Lab, Department of Biology, Boston College
// All rights reserved.
// ---------------------------------------------------------------------------
-// Last modified: 5 December 2010
+// Last modified: 13 December 2010
// ---------------------------------------------------------------------------
// Prints general alignment statistics for BAM file(s).
// ***************************************************************************
// constructor
RevertSettings(void)
: HasInput(false)
- , HasOutput(false)
- , IsForceCompression(false)
- , IsKeepDuplicateFlag(false)
- , IsKeepQualities(false)
- , InputFilename(Options::StandardIn())
- , OutputFilename(Options::StandardOut())
+ , HasOutput(false)
+ , IsForceCompression(false)
+ , IsKeepDuplicateFlag(false)
+ , IsKeepQualities(false)
+ , InputFilename(Options::StandardIn())
+ , OutputFilename(Options::StandardOut())
{ }
};
// internal methods
private:
- void RevertAlignment(BamAlignment& al);
+ void RevertAlignment(BamAlignment& al);
// data members
private:
RevertTool::RevertSettings* m_settings;
- string m_OQ;
+ string m_OQ;
};
RevertTool::RevertToolPrivate::RevertToolPrivate(RevertTool::RevertSettings* settings)
// replace Qualities with OQ, if requested
if ( !m_settings->IsKeepQualities ) {
- string originalQualities;
- if ( al.GetTag(m_OQ, originalQualities) ) {
- al.Qualities = originalQualities;
- al.RemoveTag(m_OQ);
- }
+ string originalQualities;
+ if ( al.GetTag(m_OQ, originalQualities) ) {
+ al.Qualities = originalQualities;
+ al.RemoveTag(m_OQ);
+ }
}
// clear duplicate flag, if requested
if ( !m_settings->IsKeepDuplicateFlag )
- al.SetIsDuplicate(false);
+ al.SetIsDuplicate(false);
}
bool RevertTool::RevertToolPrivate::Run(void) {
// opens the BAM file without checking for indexes
BamReader reader;
if ( !reader.Open(m_settings->InputFilename) ) {
- cerr << "Could not open input BAM file... quitting." << endl;
+ cerr << "Could not open input BAM file... quitting." << endl;
return false;
}
// plow through file, reverting alignments
BamAlignment al;
while ( reader.GetNextAlignment(al) ) {
- RevertAlignment(al);
+ RevertAlignment(al);
writer.SaveAlignment(al);
}
// while data available in temp files
BamAlignment al;
- while ( multiReader.GetNextAlignmentCore(al) ) {
+ while ( multiReader.GetNextAlignmentCore(al) )
mergedWriter.SaveAlignment(al);
- }
// close readers
multiReader.Close();
namespace BamTools {
- // string constants
- static const string SPLIT_MAPPED_TOKEN = ".MAPPED";
- static const string SPLIT_UNMAPPED_TOKEN = ".UNMAPPED";
- static const string SPLIT_PAIRED_TOKEN = ".PAIRED_END";
- static const string SPLIT_SINGLE_TOKEN = ".SINGLE_END";
- static const string SPLIT_REFERENCE_TOKEN = ".REF_";
+// string constants
+static const string SPLIT_MAPPED_TOKEN = ".MAPPED";
+static const string SPLIT_UNMAPPED_TOKEN = ".UNMAPPED";
+static const string SPLIT_PAIRED_TOKEN = ".PAIRED_END";
+static const string SPLIT_SINGLE_TOKEN = ".SINGLE_END";
+static const string SPLIT_REFERENCE_TOKEN = ".REF_";
- string GetTimestampString(void) {
-
- // get human readable timestamp
- time_t currentTime;
- time(¤tTime);
- stringstream timeStream("");
- timeStream << ctime(¤tTime);
-
- // convert whitespace to '_'
- string timeString = timeStream.str();
- size_t found = timeString.find(" ");
- while (found != string::npos) {
- timeString.replace(found, 1, "_");
- found = timeString.find(" ", found+1);
- }
- return timeString;
- }
-
- // remove copy of filename without extension
- // (so /path/to/file.txt becomes /path/to/file )
- string RemoveFilenameExtension(const string& filename) {
- size_t found = filename.rfind(".");
- return filename.substr(0, found);
+string GetTimestampString(void) {
+
+ // get human readable timestamp
+ time_t currentTime;
+ time(¤tTime);
+ stringstream timeStream("");
+ timeStream << ctime(¤tTime);
+
+ // convert whitespace to '_'
+ string timeString = timeStream.str();
+ size_t found = timeString.find(" ");
+ while (found != string::npos) {
+ timeString.replace(found, 1, "_");
+ found = timeString.find(" ", found+1);
}
+ return timeString;
+}
+
+// remove copy of filename without extension
+// (so /path/to/file.txt becomes /path/to/file )
+string RemoveFilenameExtension(const string& filename) {
+ size_t found = filename.rfind(".");
+ return filename.substr(0, found);
+}
} // namespace BamTools