// BamHeader_p.cpp (c) 2010 Derek Barnett
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
-// Last modified: 21 March 2011 (DB)
+// Last modified: 7 October 2011 (DB)
// ---------------------------------------------------------------------------
// Provides the basic functionality for handling BAM headers.
// ***************************************************************************
#include <api/BamAux.h>
#include <api/BamConstants.h>
+#include <api/internal/BamException_p.h>
#include <api/internal/BamHeader_p.h>
#include <api/internal/BgzfStream_p.h>
using namespace BamTools;
using namespace BamTools::Internal;
-#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <iostream>
using namespace std;
+// ------------------------
+// static utility methods
+// ------------------------
+
+static inline
+bool isValidMagicNumber(const char* buffer) {
+ return ( strncmp(buffer, Constants::BAM_HEADER_MAGIC,
+ Constants::BAM_HEADER_MAGIC_LENGTH) == 0 );
+}
+
+// --------------------------
+// BamHeader implementation
+// --------------------------
+
// ctor
BamHeader::BamHeader(void) { }
BamHeader::~BamHeader(void) { }
// reads magic number from BGZF stream, returns true if valid
-bool BamHeader::CheckMagicNumber(BgzfStream* stream) {
+void BamHeader::CheckMagicNumber(BgzfStream* stream) {
// try to read magic number
char buffer[Constants::BAM_HEADER_MAGIC_LENGTH];
- if ( stream->Read(buffer, Constants::BAM_HEADER_MAGIC_LENGTH) != Constants::BAM_HEADER_MAGIC_LENGTH ) {
- fprintf(stderr, "BamHeader ERROR: could not read magic number\n");
- return false;
- }
+ const size_t numBytesRead = stream->Read(buffer, Constants::BAM_HEADER_MAGIC_LENGTH);
+ if ( numBytesRead != (int)Constants::BAM_HEADER_MAGIC_LENGTH )
+ throw BamException("BamHeader::CheckMagicNumber", "could not read magic number");
// validate magic number
- if ( strncmp(buffer, Constants::BAM_HEADER_MAGIC, Constants::BAM_HEADER_MAGIC_LENGTH) != 0 ) {
- fprintf(stderr, "BamHeader ERROR: invalid magic number\n");
- return false;
- }
-
- // all checks out
- return true;
+ if ( !isValidMagicNumber(buffer) )
+ throw BamException("BamHeader::CheckMagicNumber", "invalid magic number");
}
// clear SamHeader data
}
// load BAM header ('magic number' and SAM header text) from BGZF stream
-// returns true if all OK
-bool BamHeader::Load(BgzfStream* stream) {
+void BamHeader::Load(BgzfStream* stream) {
- // cannot load if invalid stream
- if ( stream == 0 )
- return false;
+ // read & check magic number
+ CheckMagicNumber(stream);
- // cannot load if magic number is invalid
- if ( !CheckMagicNumber(stream) )
- return false;
-
- // cannot load header if cannot read header length
+ // read header (length, then actual text)
uint32_t length(0);
- if ( !ReadHeaderLength(stream, length) )
- return false;
-
- // cannot load header if cannot read header text
- if ( !ReadHeaderText(stream, length) )
- return false;
-
- // otherwise, everything OK
- return true;
+ ReadHeaderLength(stream, length);
+ ReadHeaderText(stream, length);
}
// reads SAM header text length from BGZF stream, stores it in @length
-// returns read success/fail status
-bool BamHeader::ReadHeaderLength(BgzfStream* stream, uint32_t& length) {
+void BamHeader::ReadHeaderLength(BgzfStream* stream, uint32_t& length) {
- // attempt to read BAM header text length
+ // read BAM header text length
char buffer[sizeof(uint32_t)];
- if ( stream->Read(buffer, sizeof(uint32_t)) != sizeof(uint32_t) ) {
- fprintf(stderr, "BamHeader ERROR: could not read header length\n");
- return false;
- }
+ const size_t numBytesRead = stream->Read(buffer, sizeof(uint32_t));
+ if ( numBytesRead != sizeof(uint32_t) )
+ throw BamException("BamHeader::ReadHeaderLength", "could not read header length");
- // convert char buffer to length, return success
+ // convert char buffer to length
length = BamTools::UnpackUnsignedInt(buffer);
if ( BamTools::SystemIsBigEndian() )
BamTools::SwapEndian_32(length);
- return true;
}
// reads SAM header text from BGZF stream, stores in SamHeader object
-// returns read success/fail status
-bool BamHeader::ReadHeaderText(BgzfStream* stream, const uint32_t& length) {
+void BamHeader::ReadHeaderText(BgzfStream* stream, const uint32_t& length) {
- // set up destination buffer
+ // read header text
char* headerText = (char*)calloc(length + 1, 1);
+ const size_t bytesRead = stream->Read(headerText, length);
- // attempt to read header text
- const unsigned bytesRead = stream->Read(headerText, length);
- const bool readOk = ( bytesRead == length );
- if ( readOk )
- m_header.SetHeaderText( (string)((const char*)headerText) );
- else
- fprintf(stderr, "BamHeader ERROR: could not read header text\n");
+ // if error reading, clean up buffer & throw
+ if ( bytesRead != length ) {
+ free(headerText);
+ throw BamException("BamHeader::ReadHeaderText", "could not read header text");
+ }
- // clean up calloc-ed temp variable (on success or fail)
+ // otherwise, text was read OK
+ // store & cleanup
+ m_header.SetHeaderText( (string)((const char*)headerText) );
free(headerText);
-
- // return read success
- return readOk;
}
// returns *copy* of SamHeader data object