diff --git a/src/api/BamAlignment.h b/src/api/BamAlignment.h index a2349ea9..e3e21c11 100644 --- a/src/api/BamAlignment.h +++ b/src/api/BamAlignment.h @@ -127,7 +127,7 @@ struct API_EXPORT BamAlignment { //! \internal // internal utility methods - private: + //private: Still useful bool FindTag(const std::string& tag, char*& pTagData, const unsigned int& tagDataLength, @@ -150,6 +150,7 @@ struct API_EXPORT BamAlignment { uint32_t QueryNameLength; uint32_t QuerySequenceLength; bool HasCoreOnly; + int64_t FileOffset; // constructor BamAlignmentSupportData(void) @@ -160,7 +161,9 @@ struct API_EXPORT BamAlignment { , HasCoreOnly(false) { } }; + public: //Sometimes useful publicly BamAlignmentSupportData SupportData; + private: friend class Internal::BamReaderPrivate; friend class Internal::BamWriterPrivate; diff --git a/src/api/BamConstants.h b/src/api/BamConstants.h index 47f73a9b..18b9e38b 100644 --- a/src/api/BamConstants.h +++ b/src/api/BamConstants.h @@ -126,10 +126,10 @@ const char BAM_DNA_PAD = '*'; // zlib & BGZF constants const char GZIP_ID1 = 31; -const char GZIP_ID2 = 139; +const char GZIP_ID2 = 139u; const char CM_DEFLATE = 8; const char FLG_FEXTRA = 4; -const char OS_UNKNOWN = 255; +const char OS_UNKNOWN = 255u; const char BGZF_XLEN = 6; const char BGZF_ID1 = 66; const char BGZF_ID2 = 67; diff --git a/src/api/BamIndex.h b/src/api/BamIndex.h index fd41f691..32a046e7 100644 --- a/src/api/BamIndex.h +++ b/src/api/BamIndex.h @@ -12,6 +12,7 @@ #include "api/api_global.h" #include "api/BamAux.h" +#include "api/BamAlignment.h" #include namespace BamTools { @@ -20,6 +21,8 @@ namespace Internal { class BamReaderPrivate; } // namespace Internal +typedef bool (*CreateIndexProgressCallback)(const BamAlignment& alignment, void* cbData); + /*! \class BamTools::BamIndex \brief Provides methods for generating & loading BAM index files. @@ -49,7 +52,9 @@ class API_EXPORT BamIndex { // index interface public: // builds index from associated BAM file & writes out to index file - virtual bool Create(void) =0; + virtual bool Create(std::string* indexFileName=0, + CreateIndexProgressCallback cb=0, + void* cbData=0) =0; // creates index file from BAM file // returns a human-readable description of the last error encountered std::string GetErrorString(void) { return m_errorString; } diff --git a/src/api/BamReader.cpp b/src/api/BamReader.cpp index ae2adec9..027eb1cc 100644 --- a/src/api/BamReader.cpp +++ b/src/api/BamReader.cpp @@ -57,8 +57,11 @@ bool BamReader::Close(void) { \return \c true if index created OK \sa LocateIndex(), OpenIndex() */ -bool BamReader::CreateIndex(const BamIndex::IndexType& type) { - return d->CreateIndex(type); +bool BamReader::CreateIndex(const BamIndex::IndexType& type, + std::string* indexFileName, + CreateIndexProgressCallback cb, + void* cbData) { + return d->CreateIndex(type, indexFileName, cb, cbData); } /*! \fn std::string BamReader::GetErrorString(void) const diff --git a/src/api/BamReader.h b/src/api/BamReader.h index fb9064d9..1fa6558c 100644 --- a/src/api/BamReader.h +++ b/src/api/BamReader.h @@ -90,7 +90,10 @@ class API_EXPORT BamReader { // ---------------------- // creates an index file for current BAM file, using the requested index type - bool CreateIndex(const BamIndex::IndexType& type = BamIndex::STANDARD); + bool CreateIndex(const BamIndex::IndexType& type = BamIndex::STANDARD, + std::string* indexFileName=0, + CreateIndexProgressCallback cb=0, + void* cbData=0); // returns true if index data is available bool HasIndex(void) const; // looks in BAM file's directory for a matching index file diff --git a/src/api/IBamIODevice.h b/src/api/IBamIODevice.h index cf641298..8c8812d1 100644 --- a/src/api/IBamIODevice.h +++ b/src/api/IBamIODevice.h @@ -24,6 +24,9 @@ namespace BamTools { +class IBamIODevice; +typedef IBamIODevice* (*CreateBamIODeviceCallback)(const std::string& source); + class API_EXPORT IBamIODevice { // enums @@ -56,6 +59,8 @@ class API_EXPORT IBamIODevice { virtual bool IsOpen(void) const; virtual OpenMode Mode(void) const; + static void RegisterCreatorCallback(CreateBamIODeviceCallback cb); + // internal methods protected: IBamIODevice(void); // hidden ctor diff --git a/src/api/internal/bam/BamRandomAccessController_p.cpp b/src/api/internal/bam/BamRandomAccessController_p.cpp index 848fafd1..beaffb86 100644 --- a/src/api/internal/bam/BamRandomAccessController_p.cpp +++ b/src/api/internal/bam/BamRandomAccessController_p.cpp @@ -146,8 +146,11 @@ void BamRandomAccessController::ClearRegion(void) { } bool BamRandomAccessController::CreateIndex(BamReaderPrivate* reader, - const BamIndex::IndexType& type) -{ + const BamIndex::IndexType& type, + std::string* indexFileName, + CreateIndexProgressCallback cb, + void* cbData) { + // skip if reader is invalid assert(reader); if ( !reader->IsOpen() ) { @@ -166,7 +169,7 @@ bool BamRandomAccessController::CreateIndex(BamReaderPrivate* reader, } // attempt to build index from current BamReader file - if ( !newIndex->Create() ) { + if ( !newIndex->Create(indexFileName, cb, cbData) ) { const string indexError = newIndex->GetErrorString(); const string message = "could not create index: \n\t" + indexError; SetErrorString("BamRandomAccessController::CreateIndex", message); diff --git a/src/api/internal/bam/BamRandomAccessController_p.h b/src/api/internal/bam/BamRandomAccessController_p.h index 9262a612..df4b7f25 100644 --- a/src/api/internal/bam/BamRandomAccessController_p.h +++ b/src/api/internal/bam/BamRandomAccessController_p.h @@ -49,7 +49,10 @@ class BamRandomAccessController { // index methods void ClearIndex(void); - bool CreateIndex(BamReaderPrivate* reader, const BamIndex::IndexType& type); + bool CreateIndex(BamReaderPrivate* reader, const BamIndex::IndexType& type, + std::string* indexFileName, + CreateIndexProgressCallback cb, + void* cbData); bool HasIndex(void) const; bool IndexHasAlignmentsForReference(const int& refId); bool LocateIndex(BamReaderPrivate* reader, const BamIndex::IndexType& preferredType); diff --git a/src/api/internal/bam/BamReader_p.cpp b/src/api/internal/bam/BamReader_p.cpp index 24e54fd0..4c79450b 100644 --- a/src/api/internal/bam/BamReader_p.cpp +++ b/src/api/internal/bam/BamReader_p.cpp @@ -70,8 +70,10 @@ bool BamReaderPrivate::Close(void) { } // creates an index file of requested type on current BAM file -bool BamReaderPrivate::CreateIndex(const BamIndex::IndexType& type) { - +bool BamReaderPrivate::CreateIndex(const BamIndex::IndexType& type, + std::string* indexFileName, + CreateIndexProgressCallback cb, + void* cbData) { // skip if BAM file not open if ( !IsOpen() ) { SetErrorString("BamReader::CreateIndex", "cannot create index on unopened BAM file"); @@ -79,7 +81,7 @@ bool BamReaderPrivate::CreateIndex(const BamIndex::IndexType& type) { } // attempt to create index - if ( m_randomAccessController.CreateIndex(this, type) ) + if ( m_randomAccessController.CreateIndex(this, type, indexFileName, cb, cbData) ) return true; else { const string bracError = m_randomAccessController.GetErrorString(); @@ -230,10 +232,13 @@ void BamReaderPrivate::LoadHeaderData(void) { // populates BamAlignment with alignment data under file pointer, returns success/fail bool BamReaderPrivate::LoadNextAlignment(BamAlignment& alignment) { + alignment.SupportData.FileOffset = m_stream.Tell(); //Get the offset before we progress the stream + // read in the 'block length' value, make sure it's not zero char buffer[sizeof(uint32_t)]; fill_n(buffer, sizeof(uint32_t), 0); - m_stream.Read(buffer, sizeof(uint32_t)); + if(m_stream.Read(buffer, sizeof(uint32_t)) < sizeof(uint32_t)) + return false; alignment.SupportData.BlockLength = BamTools::UnpackUnsignedInt(buffer); if ( m_isBigEndian ) BamTools::SwapEndian_32(alignment.SupportData.BlockLength); if ( alignment.SupportData.BlockLength == 0 ) diff --git a/src/api/internal/bam/BamReader_p.h b/src/api/internal/bam/BamReader_p.h index e8db646e..f6df1261 100644 --- a/src/api/internal/bam/BamReader_p.h +++ b/src/api/internal/bam/BamReader_p.h @@ -62,7 +62,10 @@ class BamReaderPrivate { int GetReferenceID(const std::string& refName) const; // index operations - bool CreateIndex(const BamIndex::IndexType& type); + bool CreateIndex(const BamIndex::IndexType& type, + std::string* indexFileName, + CreateIndexProgressCallback cb, + void* cbData); bool HasIndex(void) const; bool LocateIndex(const BamIndex::IndexType& preferredType); bool OpenIndex(const std::string& indexFilename); diff --git a/src/api/internal/index/BamStandardIndex_p.cpp b/src/api/internal/index/BamStandardIndex_p.cpp index 2606a98d..0638557a 100644 --- a/src/api/internal/index/BamStandardIndex_p.cpp +++ b/src/api/internal/index/BamStandardIndex_p.cpp @@ -262,7 +262,9 @@ void BamStandardIndex::CloseFile(void) { } // builds index from associated BAM file & writes out to index file -bool BamStandardIndex::Create(void) { +bool BamStandardIndex::Create(std::string* indexFileNamePreferred, + CreateIndexProgressCallback progressCB, + void* progressCBData) { // skip if BamReader is invalid or not open if ( m_reader == 0 || !m_reader->IsOpen() ) { @@ -281,7 +283,11 @@ bool BamStandardIndex::Create(void) { try { // open new index file (read & write) - string indexFilename = m_reader->Filename() + Extension(); + string indexFilename; + if(indexFileNamePreferred != 0) + indexFilename = *indexFileNamePreferred; + else + indexFilename = m_reader->Filename() + Extension(); OpenFile(indexFilename, IBamIODevice::ReadWrite); // initialize BaiFileSummary with number of references @@ -306,6 +312,17 @@ bool BamStandardIndex::Create(void) { BaiReferenceEntry refEntry; while ( m_reader->LoadNextAlignment(al) ) { + if(progressCB){ + //Call progress CB for every read + if(!progressCB(al, progressCBData)){ + //progressCB can return false indicating user canceled the index operation + CloseFile(); + remove(indexFilename.c_str()); + m_reader->Rewind(); + return false; + } + } + // changed to new reference if ( lastRefID != al.RefID ) { diff --git a/src/api/internal/index/BamStandardIndex_p.h b/src/api/internal/index/BamStandardIndex_p.h index 273d56e7..4cc058b8 100644 --- a/src/api/internal/index/BamStandardIndex_p.h +++ b/src/api/internal/index/BamStandardIndex_p.h @@ -113,7 +113,9 @@ class BamStandardIndex : public BamIndex { // BamIndex implementation public: // builds index from associated BAM file & writes out to index file - bool Create(void); + bool Create(std::string* indexFileName=0, + CreateIndexProgressCallback cb=0, + void* cbData=0); // returns whether reference has alignments or no bool HasAlignments(const int& referenceID) const; // attempts to use index data to jump to @region, returns success/fail diff --git a/src/api/internal/index/BamToolsIndex_p.cpp b/src/api/internal/index/BamToolsIndex_p.cpp index bb09bc97..97cca1f1 100644 --- a/src/api/internal/index/BamToolsIndex_p.cpp +++ b/src/api/internal/index/BamToolsIndex_p.cpp @@ -131,7 +131,9 @@ void BamToolsIndex::CloseFile(void) { } // builds index from associated BAM file & writes out to index file -bool BamToolsIndex::Create(void) { +bool BamToolsIndex::Create(std::string* indexFileNamePreferred, + CreateIndexProgressCallback progressCB, + void* progressCBData) { // skip if BamReader is invalid or not open if ( m_reader == 0 || !m_reader->IsOpen() ) { @@ -149,7 +151,11 @@ bool BamToolsIndex::Create(void) { try { // open new index file (read & write) - const string indexFilename = m_reader->Filename() + Extension(); + string indexFilename; + if(indexFileNamePreferred != 0) + indexFilename = *indexFileNamePreferred; + else + indexFilename = m_reader->Filename() + Extension(); OpenFile(indexFilename, IBamIODevice::ReadWrite); // initialize BtiFileSummary with number of references @@ -172,6 +178,17 @@ bool BamToolsIndex::Create(void) { BtiReferenceEntry refEntry; while ( m_reader->LoadNextAlignment(al) ) { + if(progressCB){ + //Call progress CB every read + if(!progressCB(al, progressCBData)){ + //progressCB can return false indicating user canceled the index operation + CloseFile(); + remove(indexFilename.c_str()); + m_reader->Rewind(); + return false; + } + } + // if moved to new reference if ( al.RefID != blockRefId ) { diff --git a/src/api/internal/index/BamToolsIndex_p.h b/src/api/internal/index/BamToolsIndex_p.h index c1e1aa0d..bbca0be4 100644 --- a/src/api/internal/index/BamToolsIndex_p.h +++ b/src/api/internal/index/BamToolsIndex_p.h @@ -108,7 +108,9 @@ class BamToolsIndex : public BamIndex { // BamIndex implementation public: // builds index from associated BAM file & writes out to index file - bool Create(void); + bool Create(std::string* indexFileName=0, + CreateIndexProgressCallback cb=0, + void* cbData=0); // returns whether reference has alignments or no bool HasAlignments(const int& referenceID) const; // attempts to use index data to jump to @region, returns success/fail diff --git a/src/api/internal/io/BamDeviceFactory_p.cpp b/src/api/internal/io/BamDeviceFactory_p.cpp index f9c7694e..8e843481 100644 --- a/src/api/internal/io/BamDeviceFactory_p.cpp +++ b/src/api/internal/io/BamDeviceFactory_p.cpp @@ -9,29 +9,37 @@ #include "api/internal/io/BamDeviceFactory_p.h" #include "api/internal/io/BamFile_p.h" -#include "api/internal/io/BamFtp_p.h" -#include "api/internal/io/BamHttp_p.h" #include "api/internal/io/BamPipe_p.h" using namespace BamTools; using namespace BamTools::Internal; #include +#include using namespace std; +static std::vector m_callBacks; + IBamIODevice* BamDeviceFactory::CreateDevice(const string& source) { + for(int i=0; i using namespace std; +static BamTools::IBamIODevice* createBamFtpDeviceCb(const std::string& source) +{ + if ( source.find("ftp://") == 0 ) + return new BamFtp(source); + return 0; +} + +struct RegisterBamFtpCallback{ + RegisterBamFtpCallback(){ + BamTools::IBamIODevice::RegisterCreatorCallback(createBamFtpDeviceCb); + } +}; +static RegisterBamFtpCallback _cbInitializer; //Global ctor sets up BamFtp as device + + namespace BamTools { namespace Internal { diff --git a/src/api/internal/io/BamHttp_p.cpp b/src/api/internal/io/BamHttp_p.cpp index 377be820..303cab69 100644 --- a/src/api/internal/io/BamHttp_p.cpp +++ b/src/api/internal/io/BamHttp_p.cpp @@ -20,6 +20,21 @@ using namespace BamTools::Internal; #include using namespace std; +static BamTools::IBamIODevice* createBamHttpDeviceCb(const std::string& source) +{ + if ( source.find("http://") == 0 ) + return new BamHttp(source); + return 0; +} + +struct RegisterBamHttpCallback{ + RegisterBamHttpCallback(){ + BamTools::IBamIODevice::RegisterCreatorCallback(createBamHttpDeviceCb); + } +}; +static RegisterBamHttpCallback _cbInitializer; //Global ctor sets up BamHttp as device + + namespace BamTools { namespace Internal { diff --git a/src/api/internal/utils/BamException_p.cpp b/src/api/internal/utils/BamException_p.cpp index 103e34b0..961ca25d 100644 --- a/src/api/internal/utils/BamException_p.cpp +++ b/src/api/internal/utils/BamException_p.cpp @@ -12,4 +12,4 @@ using namespace BamTools; using namespace BamTools::Internal; using namespace std; -const string BamException::SEPARATOR = ": "; +//const string BamException::SEPARATOR = ": "; //Use EX_SEPARATOR instead diff --git a/src/api/internal/utils/BamException_p.h b/src/api/internal/utils/BamException_p.h index 51997371..4518d61c 100644 --- a/src/api/internal/utils/BamException_p.h +++ b/src/api/internal/utils/BamException_p.h @@ -1,3 +1,4 @@ + // *************************************************************************** // BamException_p.h (c) 2011 Derek Barnett // Marth Lab, Department of Biology, Boston College @@ -23,6 +24,7 @@ #include #include +#define EX_SEPARATOR ": " //Use this instead of a static const std::string class member which creates nasty link dependencies namespace BamTools { namespace Internal { @@ -31,7 +33,7 @@ class BamException : public std::exception { public: inline BamException(const std::string& where, const std::string& message) : std::exception() - , m_errorString(where + SEPARATOR + message) + , m_errorString(where + std::string(EX_SEPARATOR) + message) { } inline ~BamException(void) throw() { } @@ -42,7 +44,6 @@ class BamException : public std::exception { private: std::string m_errorString; - static const std::string SEPARATOR; }; } // namespace Internal