// BamToolsIndex.cpp (c) 2010 Derek Barnett
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
-// Last modified: 27 April 2011 (DB)
+// Last modified: 10 October 2011 (DB)
// ---------------------------------------------------------------------------
// Provides index operations for the BamTools index format (".bti")
// ***************************************************************************
-#include <api/BamAlignment.h>
-#include <api/internal/BamReader_p.h>
-#include <api/internal/BamToolsIndex_p.h>
-#include <api/internal/BgzfStream_p.h>
+#include "api/BamAlignment.h"
+#include "api/internal/BamException_p.h"
+#include "api/internal/BamReader_p.h"
+#include "api/internal/BamToolsIndex_p.h"
+#include "api/internal/BgzfStream_p.h"
using namespace BamTools;
using namespace BamTools::Internal;
#include <map>
using namespace std;
+// --------------------------------
// static BamToolsIndex constants
-const int BamToolsIndex::DEFAULT_BLOCK_LENGTH = 1000;
+// --------------------------------
+
+const uint32_t BamToolsIndex::DEFAULT_BLOCK_LENGTH = 1000;
const string BamToolsIndex::BTI_EXTENSION = ".bti";
const char* const BamToolsIndex::BTI_MAGIC = "BTI\1";
const int BamToolsIndex::SIZEOF_BLOCK = sizeof(int32_t)*2 + sizeof(int64_t);
+// ----------------------------
+// RaiiWrapper implementation
+// ----------------------------
+
+BamToolsIndex::RaiiWrapper::RaiiWrapper(void)
+ : IndexStream(0)
+{ }
+
+BamToolsIndex::RaiiWrapper::~RaiiWrapper(void) {
+ if ( IndexStream )
+ fclose(IndexStream);
+}
+
+// ------------------------------
+// BamToolsIndex implementation
+// ------------------------------
+
// ctor
BamToolsIndex::BamToolsIndex(Internal::BamReaderPrivate* reader)
: BamIndex(reader)
- , m_indexStream(0)
, m_cacheMode(BamIndex::LimitedIndexCaching)
, m_blockSize(BamToolsIndex::DEFAULT_BLOCK_LENGTH)
, m_inputVersion(0)
- , m_outputVersion(BTI_1_2) // latest version - used for writing new index files
+ , m_outputVersion(BTI_2_0) // latest version - used for writing new index files
{
m_isBigEndian = BamTools::SystemIsBigEndian();
}
CloseFile();
}
-bool BamToolsIndex::CheckMagicNumber(void) {
+void BamToolsIndex::CheckMagicNumber(void) {
- // check 'magic number' to see if file is BTI index
+ // read magic number
char magic[4];
- size_t elementsRead = fread(magic, sizeof(char), 4, m_indexStream);
- if ( elementsRead != 4 ) {
- cerr << "BamToolsIndex ERROR: could not read format 'magic' number" << endl;
- return false;
- }
-
- if ( strncmp(magic, BamToolsIndex::BTI_MAGIC, 4) != 0 ) {
- cerr << "BamToolsIndex ERROR: invalid format" << endl;
- return false;
- }
+ size_t elementsRead = fread(magic, sizeof(char), 4, Resources.IndexStream);
+ if ( elementsRead != 4 )
+ throw BamException("BamToolsIndex::CheckMagicNumber", "could not read BTI magic number");
- // otherwise ok
- return true;
+ // validate expected magic number
+ if ( strncmp(magic, BamToolsIndex::BTI_MAGIC, 4) != 0 )
+ throw BamException("BamToolsIndex::CheckMagicNumber", "invalid BTI magic number");
}
// check index file version, return true if OK
-bool BamToolsIndex::CheckVersion(void) {
+void BamToolsIndex::CheckVersion(void) {
// read version from file
- size_t elementsRead = fread(&m_inputVersion, sizeof(m_inputVersion), 1, m_indexStream);
- if ( elementsRead != 1 ) return false;
+ size_t elementsRead = fread(&m_inputVersion, sizeof(m_inputVersion), 1, Resources.IndexStream);
+ if ( elementsRead != 1 )
+ throw BamException("BamToolsIndex::CheckVersion", "could not read format version");
if ( m_isBigEndian ) SwapEndian_32(m_inputVersion);
// if version is negative, or zero
- if ( m_inputVersion <= 0 ) {
- cerr << "BamToolsIndex ERROR: could not load index file: invalid version."
- << endl;
- return false;
- }
+ if ( m_inputVersion <= 0 )
+ throw BamException("BamToolsIndex::CheckVersion", "invalid format version");
// if version is newer than can be supported by this version of bamtools
else if ( m_inputVersion > m_outputVersion ) {
- cerr << "BamToolsIndex ERROR: could not load index file. This version of BamTools does not recognize new index file version"
- << endl
- << "Please update BamTools to a more recent version to support this index file."
- << endl;
- return false;
+ const string message = "unsupported format: this index was created by a newer version of BamTools. "
+ "Update your local version of BamTools to use the index file.";
+ throw BamException("BamToolsIndex::CheckVersion", message);
}
// ------------------------------------------------------------------
// check for deprecated, unsupported versions
- // (typically whose format did not accomodate a particular bug fix)
-
- else if ( (Version)m_inputVersion == BamToolsIndex::BTI_1_0 ) {
- cerr << "BamToolsIndex ERROR: could not load index file. This version of the index contains a bug related to accessing data near reference ends."
- << endl << endl
- << "Please run 'bamtools index -bti -in yourData.bam' to generate an up-to-date, fixed BTI file."
- << endl << endl;
- return false;
+ // (the format had to be modified to accomodate a particular bug fix)
+
+ // Version 2.0: introduced support for half-open intervals, instead of the old closed intervals
+ // respondBy: throwing exception - we're not going to try to handle the old BTI files.
+ else if ( (Version)m_inputVersion < BamToolsIndex::BTI_2_0 ) {
+ const string message = "unsupported format: this version of the index may not properly handle "
+ "coordinate intervals. Please run 'bamtools index -bti -in yourData.bam' "
+ "to generate an up-to-date, fixed BTI file.";
+ throw BamException("BamToolsIndex::CheckVersion", message);
}
-
- else if ( (Version)m_inputVersion == BamToolsIndex::BTI_1_1 ) {
- cerr << "BamToolsIndex ERROR: could not load index file. This version of the index contains a bug related to handling empty references."
- << endl << endl
- << "Please run 'bamtools index -bti -in yourData.bam' to generate an up-to-date, fixed BTI file."
- << endl << endl;
- return false;
- }
-
- // otherwise ok
- else return true;
}
void BamToolsIndex::ClearReferenceEntry(BtiReferenceEntry& refEntry) {
}
void BamToolsIndex::CloseFile(void) {
- if ( IsFileOpen() )
- fclose(m_indexStream);
+ if ( IsFileOpen() ) {
+ fclose(Resources.IndexStream);
+ Resources.IndexStream = 0;
+ }
m_indexFileSummary.clear();
}
// builds index from associated BAM file & writes out to index file
bool BamToolsIndex::Create(void) {
- // return false if BamReader is invalid or not open
+ // skip if BamReader is invalid or not open
if ( m_reader == 0 || !m_reader->IsOpen() ) {
- cerr << "BamToolsIndex ERROR: BamReader is not open"
- << ", aborting index creation" << endl;
+ SetErrorString("BamToolsIndex::Create", "could not create index: reader is not open");
return false;
}
// rewind BamReader
if ( !m_reader->Rewind() ) {
- cerr << "BamToolsIndex ERROR: could not rewind BamReader to create index"
- << ", aborting index creation" << endl;
+ const string readerError = m_reader->GetErrorString();
+ const string message = "could not create index: \n\t" + readerError;
+ SetErrorString("BamToolsIndex::Create", message);
return false;
}
- // open new index file (read & write)
- string indexFilename = m_reader->Filename() + Extension();
- if ( !OpenFile(indexFilename, "w+b") ) {
- cerr << "BamToolsIndex ERROR: could not open ouput index file " << indexFilename
- << ", aborting index creation" << endl;
- return false;
- }
+ try {
+ // open new index file (read & write)
+ const string indexFilename = m_reader->Filename() + Extension();
+ OpenFile(indexFilename, "w+b");
- // initialize BtiFileSummary with number of references
- const int& numReferences = m_reader->GetReferenceCount();
- InitializeFileSummary(numReferences);
+ // initialize BtiFileSummary with number of references
+ const int& numReferences = m_reader->GetReferenceCount();
+ InitializeFileSummary(numReferences);
- // initialize output file
- bool createdOk = true;
- createdOk &= WriteHeader();
+ // intialize output file header
+ WriteHeader();
- // index building markers
- int32_t currentBlockCount = 0;
- int64_t currentAlignmentOffset = m_reader->Tell();
- int32_t blockRefId = -1;
- int32_t blockMaxEndPosition = -1;
- int64_t blockStartOffset = currentAlignmentOffset;
- int32_t blockStartPosition = -1;
+ // index building markers
+ uint32_t currentBlockCount = 0;
+ int64_t currentAlignmentOffset = m_reader->Tell();
+ int32_t blockRefId = -1;
+ int32_t blockMaxEndPosition = -1;
+ int64_t blockStartOffset = currentAlignmentOffset;
+ int32_t blockStartPosition = -1;
- // plow through alignments, storing index entries
- BamAlignment al;
- BtiReferenceEntry refEntry;
- while ( m_reader->LoadNextAlignment(al) ) {
+ // plow through alignments, storing index entries
+ BamAlignment al;
+ BtiReferenceEntry refEntry;
+ while ( m_reader->LoadNextAlignment(al) ) {
- // if moved to new reference
- if ( al.RefID != blockRefId ) {
+ // if moved to new reference
+ if ( al.RefID != blockRefId ) {
- // if first pass, check:
- if ( currentBlockCount == 0 ) {
+ // if first pass, check:
+ if ( currentBlockCount == 0 ) {
- // write any empty references up to (but not including) al.RefID
- for ( int i = 0; i < al.RefID; ++i ) {
- BtiReferenceEntry emptyEntry(i);
- createdOk &= WriteReferenceEntry(emptyEntry);
+ // write any empty references up to (but not including) al.RefID
+ for ( int i = 0; i < al.RefID; ++i )
+ WriteReferenceEntry( BtiReferenceEntry(i) );
}
- }
- // not first pass:
- else {
+ // not first pass:
+ else {
- // store previous BTI block data in reference entry
- BtiBlock block(blockMaxEndPosition, blockStartOffset, blockStartPosition);
- refEntry.Blocks.push_back(block);
+ // store previous BTI block data in reference entry
+ const BtiBlock block(blockMaxEndPosition, blockStartOffset, blockStartPosition);
+ refEntry.Blocks.push_back(block);
+
+ // write reference entry, then clear
+ WriteReferenceEntry(refEntry);
+ ClearReferenceEntry(refEntry);
- // write reference entry, then clear
- createdOk &= WriteReferenceEntry(refEntry);
- ClearReferenceEntry(refEntry);
+ // write any empty references between (but not including)
+ // the last blockRefID and current al.RefID
+ for ( int i = blockRefId+1; i < al.RefID; ++i )
+ WriteReferenceEntry( BtiReferenceEntry(i) );
- // write any empty references between (but not including) the last blockRefID and current al.RefID
- for ( int i = blockRefId+1; i < al.RefID; ++i ) {
- BtiReferenceEntry emptyEntry(i);
- createdOk &= WriteReferenceEntry(emptyEntry);
+ // reset block count
+ currentBlockCount = 0;
}
- // reset block count
- currentBlockCount = 0;
+ // set ID for new reference entry
+ refEntry.ID = al.RefID;
}
- // set ID for new reference entry
- refEntry.ID = al.RefID;
- }
+ // if beginning of block, update counters
+ if ( currentBlockCount == 0 ) {
+ blockRefId = al.RefID;
+ blockStartOffset = currentAlignmentOffset;
+ blockStartPosition = al.Position;
+ blockMaxEndPosition = al.GetEndPosition();
+ }
- // if beginning of block, update counters
- if ( currentBlockCount == 0 ) {
- blockRefId = al.RefID;
- blockStartOffset = currentAlignmentOffset;
- blockStartPosition = al.Position;
- blockMaxEndPosition = al.GetEndPosition();
- }
+ // increment block counter
+ ++currentBlockCount;
- // increment block counter
- ++currentBlockCount;
+ // check end position
+ const int32_t alignmentEndPosition = al.GetEndPosition();
+ if ( alignmentEndPosition > blockMaxEndPosition )
+ blockMaxEndPosition = alignmentEndPosition;
- // check end position
- int32_t alignmentEndPosition = al.GetEndPosition();
- if ( alignmentEndPosition > blockMaxEndPosition )
- blockMaxEndPosition = alignmentEndPosition;
+ // if block is full, get offset for next block, reset currentBlockCount
+ if ( currentBlockCount == m_blockSize ) {
- // if block is full, get offset for next block, reset currentBlockCount
- if ( currentBlockCount == m_blockSize ) {
+ // store previous block data in reference entry
+ const BtiBlock block(blockMaxEndPosition, blockStartOffset, blockStartPosition);
+ refEntry.Blocks.push_back(block);
- // store previous block data in reference entry
- BtiBlock block(blockMaxEndPosition, blockStartOffset, blockStartPosition);
- refEntry.Blocks.push_back(block);
+ // update markers
+ blockStartOffset = m_reader->Tell();
+ currentBlockCount = 0;
+ }
- // update markers
- blockStartOffset = m_reader->Tell();
- currentBlockCount = 0;
+ // not the best name, but for the next iteration, this value will be the offset of the
+ // *current* alignment. this is necessary because we won't know if this next alignment
+ // is on a new reference until we actually read it
+ currentAlignmentOffset = m_reader->Tell();
}
- // not the best name, but for the next iteration, this value will be the offset of the *current* alignment
- // necessary because we won't know if this next alignment is on a new reference until we actually read it
- currentAlignmentOffset = m_reader->Tell();
- }
+ // after finishing alignments, if any data was read, check:
+ if ( blockRefId >= 0 ) {
- // after finishing alignments, if any data was read, check:
- if ( blockRefId >= 0 ) {
-
- // store last BTI block data in reference entry
- BtiBlock block(blockMaxEndPosition, blockStartOffset, blockStartPosition);
- refEntry.Blocks.push_back(block);
+ // store last BTI block data in reference entry
+ const BtiBlock block(blockMaxEndPosition, blockStartOffset, blockStartPosition);
+ refEntry.Blocks.push_back(block);
- // write last reference entry, then clear
- createdOk &= WriteReferenceEntry(refEntry);
- ClearReferenceEntry(refEntry);
+ // write last reference entry, then clear
+ WriteReferenceEntry(refEntry);
+ ClearReferenceEntry(refEntry);
- // then write any empty references remaining at end of file
- for ( int i = blockRefId+1; i < numReferences; ++i ) {
- BtiReferenceEntry emptyEntry(i);
- createdOk &= WriteReferenceEntry(emptyEntry);
+ // then write any empty references remaining at end of file
+ for ( int i = blockRefId+1; i < numReferences; ++i )
+ WriteReferenceEntry( BtiReferenceEntry(i) );
}
+
+ } catch ( BamException& e ) {
+ m_errorString = e.what();
+ return false;
}
- // rewind reader & return result
- createdOk &= m_reader->Rewind();
+ // rewind BamReader
+ if ( !m_reader->Rewind() ) {
+ const string readerError = m_reader->GetErrorString();
+ const string message = "could not create index: \n\t" + readerError;
+ SetErrorString("BamToolsIndex::Create", message);
+ return false;
+ }
- // return result
- return createdOk;
+ // return success
+ return true;
}
// returns format's file extension
return BamToolsIndex::BTI_EXTENSION;
}
-bool BamToolsIndex::GetOffset(const BamRegion& region, int64_t& offset, bool* hasAlignmentsInRegion) {
+void BamToolsIndex::GetOffset(const BamRegion& region, int64_t& offset, bool* hasAlignmentsInRegion) {
// return false ref ID is not a valid index in file summary data
if ( region.LeftRefID < 0 || region.LeftRefID >= (int)m_indexFileSummary.size() )
- return false;
+ throw BamException("BamToolsIndex::GetOffset", "invalid region requested");
// retrieve reference index data for left bound reference
BtiReferenceEntry refEntry(region.LeftRefID);
- if ( !ReadReferenceEntry(refEntry) ) {
- cerr << "BamToolsIndex ERROR: could not retrieve index data from BTI file" << endl;
- return false;
- }
+ ReadReferenceEntry(refEntry);
// binary search for an overlapping block (may not be first one though)
bool found = false;
const BtiBlock& block = (*blockIter);
if ( block.StartPosition <= region.RightPosition ) {
- if ( block.MaxEndPosition >= region.LeftPosition ) {
+ if ( block.MaxEndPosition > region.LeftPosition ) {
offset = block.StartOffset;
break;
}
--blockIter;
const BtiBlock& previousBlock = (*blockIter);
- if ( previousBlock.MaxEndPosition < region.LeftPosition ) {
+ if ( previousBlock.MaxEndPosition <= region.LeftPosition ) {
offset = currentBlock.StartOffset;
found = true;
break;
// sets to false if blocks container is empty, or if no matching block could be found
*hasAlignmentsInRegion = found;
-
- // return success
- return true;
}
// returns whether reference has alignments or no
return ( refSummary.NumBlocks > 0 );
}
+// pre-allocates space for each reference's summary data
void BamToolsIndex::InitializeFileSummary(const int& numReferences) {
m_indexFileSummary.clear();
for ( int i = 0; i < numReferences; ++i )
m_indexFileSummary.push_back( BtiReferenceSummary() );
}
+// returns true if the index stream is open
bool BamToolsIndex::IsFileOpen(void) const {
- return ( m_indexStream != 0 );
+ return ( Resources.IndexStream != 0 );
}
// attempts to use index data to jump to @region, returns success/fail
*hasAlignmentsInRegion = false;
// skip if invalid reader or not open
- if ( m_reader == 0 || !m_reader->IsOpen() )
+ if ( m_reader == 0 || !m_reader->IsOpen() ) {
+ SetErrorString("BamToolsIndex::Jump", "could not jump: reader is not open");
return false;
+ }
// make sure left-bound position is valid
const RefVector& references = m_reader->GetReferenceData();
- if ( region.LeftPosition > references.at(region.LeftRefID).RefLength )
+ if ( region.LeftPosition > references.at(region.LeftRefID).RefLength ) {
+ SetErrorString("BamToolsIndex::Jump", "could not create index: invalid region requested");
return false;
+ }
// calculate nearest offset to jump to
int64_t offset;
- if ( !GetOffset(region, offset, hasAlignmentsInRegion) ) {
- cerr << "BamToolsIndex ERROR: could not jump"
- << ", unable to calculate offset for specified region" << endl;
+ try {
+ GetOffset(region, offset, hasAlignmentsInRegion);
+ } catch ( BamException& e ) {
+ m_errorString = e.what();
return false;
}
// loads existing data from file into memory
bool BamToolsIndex::Load(const std::string& filename) {
- // attempt open index file (read-only)
- if ( !OpenFile(filename, "rb") ) {
- cerr << "BamToolsIndex ERROR: could not open input index file " << filename
- << ", aborting index load" << endl;
- return false;
- }
+ try {
- // attempt to load & validate BTI header data
- if ( !LoadHeader() ) {
- cerr << "BamToolsIndex ERROR: could load header from index file " << filename
- << ", aborting index load" << endl;
- CloseFile();
- return false;
- }
+ // attempt to open file (read-only)
+ OpenFile(filename, "rb");
+
+ // load metadata & generate in-memory summary
+ LoadHeader();
+ LoadFileSummary();
+
+ // return success
+ return true;
- // attempt to load index file summary
- if ( !LoadFileSummary() ) {
- cerr << "BamToolsIndex ERROR: could not generate a summary of index file " << filename
- << ", aborting index load" << endl;
- CloseFile();
+ } catch ( BamException& e ) {
+ m_errorString = e.what();
return false;
}
-
- // if we get here, index summary is loaded OK
- return true;
}
-bool BamToolsIndex::LoadFileSummary(void) {
+void BamToolsIndex::LoadFileSummary(void) {
// load number of reference sequences
int numReferences;
- if ( !LoadNumReferences(numReferences) )
- return false;
+ LoadNumReferences(numReferences);
// initialize file summary data
InitializeFileSummary(numReferences);
- // iterate over reference entries
- bool loadedOk = true;
+ // load summary for each reference
BtiFileSummary::iterator summaryIter = m_indexFileSummary.begin();
BtiFileSummary::iterator summaryEnd = m_indexFileSummary.end();
for ( ; summaryIter != summaryEnd; ++summaryIter )
- loadedOk &= LoadReferenceSummary(*summaryIter);
-
- // return result
- return loadedOk;
+ LoadReferenceSummary(*summaryIter);
}
-bool BamToolsIndex::LoadHeader(void) {
+void BamToolsIndex::LoadHeader(void) {
- // if invalid format 'magic number'
- if ( !CheckMagicNumber() )
- return false;
-
- // if invalid BTI version
- if ( !CheckVersion() )
- return false;
+ // check BTI file metadata
+ CheckMagicNumber();
+ CheckVersion();
// use file's BTI block size to set member variable
- size_t elementsRead = fread(&m_blockSize, sizeof(m_blockSize), 1, m_indexStream);
+ const size_t elementsRead = fread(&m_blockSize, sizeof(m_blockSize), 1, Resources.IndexStream);
if ( m_isBigEndian ) SwapEndian_32(m_blockSize);
- return ( elementsRead == 1 );
+ if ( elementsRead != 1 )
+ throw BamException("BamToolsIndex::LoadHeader", "could not read BTI block size");
}
-bool BamToolsIndex::LoadNumBlocks(int& numBlocks) {
- size_t elementsRead = 0;
- elementsRead += fread(&numBlocks, sizeof(numBlocks), 1, m_indexStream);
+void BamToolsIndex::LoadNumBlocks(int& numBlocks) {
+ const size_t elementsRead = fread(&numBlocks, sizeof(numBlocks), 1, Resources.IndexStream);
if ( m_isBigEndian ) SwapEndian_32(numBlocks);
- return ( elementsRead == 1 );
+ if ( elementsRead != 1 )
+ throw BamException("BamToolsIndex::LoadNumBlocks", "could not read number of BTI blocks");
}
-bool BamToolsIndex::LoadNumReferences(int& numReferences) {
- size_t elementsRead = 0;
- elementsRead += fread(&numReferences, sizeof(numReferences), 1, m_indexStream);
+void BamToolsIndex::LoadNumReferences(int& numReferences) {
+ const size_t elementsRead = fread(&numReferences, sizeof(numReferences), 1, Resources.IndexStream);
if ( m_isBigEndian ) SwapEndian_32(numReferences);
- return ( elementsRead == 1 );
+ if ( elementsRead != 1 )
+ throw BamException("BamToolsIndex::LoadNumReferences", "could not read number of references");
}
-bool BamToolsIndex::LoadReferenceSummary(BtiReferenceSummary& refSummary) {
+void BamToolsIndex::LoadReferenceSummary(BtiReferenceSummary& refSummary) {
// load number of blocks
int numBlocks;
- if ( !LoadNumBlocks(numBlocks) )
- return false;
+ LoadNumBlocks(numBlocks);
// store block summary data for this reference
refSummary.NumBlocks = numBlocks;
refSummary.FirstBlockFilePosition = Tell();
- // skip blocks in index file (and return status)
- return SkipBlocks(numBlocks);
+ // skip reference's blocks
+ SkipBlocks(numBlocks);
}
-bool BamToolsIndex::OpenFile(const std::string& filename, const char* mode) {
+void BamToolsIndex::OpenFile(const std::string& filename, const char* mode) {
// make sure any previous index file is closed
CloseFile();
// attempt to open file
- m_indexStream = fopen(filename.c_str(), mode);
- return IsFileOpen();
+ Resources.IndexStream = fopen(filename.c_str(), mode);
+ if ( !IsFileOpen() ) {
+ const string message = string("could not open file: ") + filename;
+ throw BamException("BamToolsIndex::OpenFile", message);
+ }
}
-bool BamToolsIndex::ReadBlock(BtiBlock& block) {
+void BamToolsIndex::ReadBlock(BtiBlock& block) {
// read in block data members
size_t elementsRead = 0;
- elementsRead += fread(&block.MaxEndPosition, sizeof(block.MaxEndPosition), 1, m_indexStream);
- elementsRead += fread(&block.StartOffset, sizeof(block.StartOffset), 1, m_indexStream);
- elementsRead += fread(&block.StartPosition, sizeof(block.StartPosition), 1, m_indexStream);
+ elementsRead += fread(&block.MaxEndPosition, sizeof(block.MaxEndPosition), 1, Resources.IndexStream);
+ elementsRead += fread(&block.StartOffset, sizeof(block.StartOffset), 1, Resources.IndexStream);
+ elementsRead += fread(&block.StartPosition, sizeof(block.StartPosition), 1, Resources.IndexStream);
// swap endian-ness if necessary
if ( m_isBigEndian ) {
SwapEndian_32(block.StartPosition);
}
- // return success/failure
- return ( elementsRead == 3 );
+ if ( elementsRead != 3 )
+ throw BamException("BamToolsIndex::ReadBlock", "could not read block");
}
-bool BamToolsIndex::ReadBlocks(const BtiReferenceSummary& refSummary, BtiBlockVector& blocks) {
+void BamToolsIndex::ReadBlocks(const BtiReferenceSummary& refSummary, BtiBlockVector& blocks) {
// prep blocks container
blocks.clear();
blocks.reserve(refSummary.NumBlocks);
// skip to first block entry
- if ( !Seek( refSummary.FirstBlockFilePosition, SEEK_SET ) ) {
- cerr << "BamToolsIndex ERROR: could not seek to position "
- << refSummary.FirstBlockFilePosition << endl;
- return false;
- }
+ Seek( refSummary.FirstBlockFilePosition, SEEK_SET );
// read & store block entries
- bool readOk = true;
BtiBlock block;
for ( int i = 0; i < refSummary.NumBlocks; ++i ) {
- readOk &= ReadBlock(block);
+ ReadBlock(block);
blocks.push_back(block);
}
- return readOk;
}
-bool BamToolsIndex::ReadReferenceEntry(BtiReferenceEntry& refEntry) {
+void BamToolsIndex::ReadReferenceEntry(BtiReferenceEntry& refEntry) {
// return false if refId not valid index in file summary structure
if ( refEntry.ID < 0 || refEntry.ID >= (int)m_indexFileSummary.size() )
- return false;
+ throw BamException("BamToolsIndex::ReadReferenceEntry", "invalid reference requested");
// use index summary to assist reading the reference's BTI blocks
const BtiReferenceSummary& refSummary = m_indexFileSummary.at(refEntry.ID);
- return ReadBlocks(refSummary, refEntry.Blocks);
+ ReadBlocks(refSummary, refEntry.Blocks);
}
-bool BamToolsIndex::Seek(const int64_t& position, const int& origin) {
- return ( fseek64(m_indexStream, position, origin) == 0 );
+void BamToolsIndex::Seek(const int64_t& position, const int& origin) {
+ if ( fseek64(Resources.IndexStream, position, origin) != 0 )
+ throw BamException("BamToolsIndex::Seek", "could not seek in BAI file");
}
// change the index caching behavior
// do nothing else here ? cache mode will be ignored from now on, most likely
}
-bool BamToolsIndex::SkipBlocks(const int& numBlocks) {
- return Seek( numBlocks*BamToolsIndex::SIZEOF_BLOCK, SEEK_CUR );
+void BamToolsIndex::SkipBlocks(const int& numBlocks) {
+ Seek( numBlocks*BamToolsIndex::SIZEOF_BLOCK, SEEK_CUR );
}
int64_t BamToolsIndex::Tell(void) const {
- return ftell64(m_indexStream);
+ return ftell64(Resources.IndexStream);
}
-bool BamToolsIndex::WriteBlock(const BtiBlock& block) {
+void BamToolsIndex::WriteBlock(const BtiBlock& block) {
// copy entry data
int32_t maxEndPosition = block.MaxEndPosition;
// write the reference index entry
size_t elementsWritten = 0;
- elementsWritten += fwrite(&maxEndPosition, sizeof(maxEndPosition), 1, m_indexStream);
- elementsWritten += fwrite(&startOffset, sizeof(startOffset), 1, m_indexStream);
- elementsWritten += fwrite(&startPosition, sizeof(startPosition), 1, m_indexStream);
- return ( elementsWritten == 3 );
+ elementsWritten += fwrite(&maxEndPosition, sizeof(maxEndPosition), 1, Resources.IndexStream);
+ elementsWritten += fwrite(&startOffset, sizeof(startOffset), 1, Resources.IndexStream);
+ elementsWritten += fwrite(&startPosition, sizeof(startPosition), 1, Resources.IndexStream);
+ if ( elementsWritten != 3 )
+ throw BamException("BamToolsIndex::WriteBlock", "could not write BTI block");
}
-bool BamToolsIndex::WriteBlocks(const BtiBlockVector& blocks) {
- bool writtenOk = true;
+void BamToolsIndex::WriteBlocks(const BtiBlockVector& blocks) {
BtiBlockVector::const_iterator blockIter = blocks.begin();
BtiBlockVector::const_iterator blockEnd = blocks.end();
for ( ; blockIter != blockEnd; ++blockIter )
- writtenOk &= WriteBlock(*blockIter);
- return writtenOk;
+ WriteBlock(*blockIter);
}
-bool BamToolsIndex::WriteHeader(void) {
+void BamToolsIndex::WriteHeader(void) {
size_t elementsWritten = 0;
// write BTI index format 'magic number'
- elementsWritten += fwrite(BamToolsIndex::BTI_MAGIC, 1, 4, m_indexStream);
+ elementsWritten += fwrite(BamToolsIndex::BTI_MAGIC, 1, 4, Resources.IndexStream);
// write BTI index format version
int32_t currentVersion = (int32_t)m_outputVersion;
if ( m_isBigEndian ) SwapEndian_32(currentVersion);
- elementsWritten += fwrite(¤tVersion, sizeof(currentVersion), 1, m_indexStream);
+ elementsWritten += fwrite(¤tVersion, sizeof(currentVersion), 1, Resources.IndexStream);
// write block size
- int32_t blockSize = m_blockSize;
+ uint32_t blockSize = m_blockSize;
if ( m_isBigEndian ) SwapEndian_32(blockSize);
- elementsWritten += fwrite(&blockSize, sizeof(blockSize), 1, m_indexStream);
+ elementsWritten += fwrite(&blockSize, sizeof(blockSize), 1, Resources.IndexStream);
// write number of references
int32_t numReferences = m_indexFileSummary.size();
if ( m_isBigEndian ) SwapEndian_32(numReferences);
- elementsWritten += fwrite(&numReferences, sizeof(numReferences), 1, m_indexStream);
+ elementsWritten += fwrite(&numReferences, sizeof(numReferences), 1, Resources.IndexStream);
- // return success/failure of write
- return ( elementsWritten == 7 );
+ if ( elementsWritten != 7 )
+ throw BamException("BamToolsIndex::WriteHeader", "could not write BTI header");
}
-bool BamToolsIndex::WriteReferenceEntry(const BtiReferenceEntry& refEntry) {
-
- size_t elementsWritten = 0;
+void BamToolsIndex::WriteReferenceEntry(const BtiReferenceEntry& refEntry) {
// write number of blocks this reference
uint32_t numBlocks = refEntry.Blocks.size();
if ( m_isBigEndian ) SwapEndian_32(numBlocks);
- elementsWritten += fwrite(&numBlocks, sizeof(numBlocks), 1, m_indexStream);
+ const size_t elementsWritten = fwrite(&numBlocks, sizeof(numBlocks), 1, Resources.IndexStream);
+ if ( elementsWritten != 1 )
+ throw BamException("BamToolsIndex::WriteReferenceEntry", "could not write number of blocks");
// write actual block entries
- const bool blocksOk = WriteBlocks(refEntry.Blocks);
-
- // return success/fail
- return ( elementsWritten == 1) && blocksOk;
+ WriteBlocks(refEntry.Blocks);
}