BamInterface.cpp
/*
* Copyright (C) 2010 Regents of the University of Michigan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BamInterface.h"
#include "CharBuffer.h"
BamInterface::BamInterface()
{
}
BamInterface::~BamInterface()
{
}
// Read a BAM file's header.
bool BamInterface::readHeader(IFILE filePtr, SamFileHeader& header,
SamStatus& status)
{
if(filePtr == NULL)
{
// File is not open, return false.
status.setStatus(SamStatus::FAIL_ORDER,
"Cannot read header since the file pointer is null");
return(false);
}
if(filePtr->isOpen() == false)
{
status.setStatus(SamStatus::FAIL_ORDER,
"Cannot read header since the file is not open");
return(false);
}
// Clear the passed in header.
header.resetHeader();
int32_t headerLength;
int readSize = ifread(filePtr, &headerLength, sizeof(headerLength));
if(readSize != sizeof(headerLength))
{
String errMsg = "Failed to read the BAM header length, read ";
errMsg += readSize;
errMsg += " bytes instead of ";
errMsg += (unsigned int)sizeof(headerLength);
status.setStatus(SamStatus::FAIL_IO, errMsg.c_str());
return(false);
}
String headerStr;
if(headerLength > 0)
{
// Read the header.
readSize =
ifread(filePtr, headerStr.LockBuffer(headerLength + 1), headerLength);
headerStr[headerLength] = 0;
headerStr.UnlockBuffer();
if(readSize != headerLength)
{
// Failed to read the header.
status.setStatus(SamStatus::FAIL_IO, "Failed to read the BAM header.");
return(false);
}
}
// Parse the header that was read.
if(!header.addHeader(headerStr))
{
// Status is set in the method on failure.
status.setStatus(SamStatus::FAIL_PARSE, header.getErrorMessage());
return(false);
}
int referenceCount;
// Read the number of references sequences.
ifread(filePtr, &referenceCount, sizeof(int));
// Get and clear the reference info so it can be set
// from the bam reference table.
SamReferenceInfo& refInfo =
header.getReferenceInfoForBamInterface();
refInfo.clear();
CharBuffer refName;
// Read each reference sequence
for (int i = 0; i < referenceCount; i++)
{
int nameLength;
int rc;
// Read the length of the reference name.
rc = ifread(filePtr, &nameLength, sizeof(int));
if(rc != sizeof(int))
{
status.setStatus(SamStatus::FAIL_IO,
"Failed to read the BAM reference dictionary.");
return(false);
}
// Read the name.
refName.readFromFile(filePtr, nameLength);
// Read the length of the reference sequence.
int32_t refLen;
rc = ifread(filePtr, &refLen, sizeof(int));
if(rc != sizeof(int)) {
status.setStatus(SamStatus::FAIL_IO,
"Failed to read the BAM reference dictionary.");
return(false);
}
refInfo.add(refName.c_str(), refLen);
}
// Successfully read the file.
return(true);
}
bool BamInterface::writeHeader(IFILE filePtr, SamFileHeader& header,
SamStatus& status)
{
if((filePtr == NULL) || (filePtr->isOpen() == false))
{
// File is not open, return false.
status.setStatus(SamStatus::FAIL_ORDER,
"Cannot write header since the file pointer is null");
return(false);
}
char magic[4];
magic[0] = 'B';
magic[1] = 'A';
magic[2] = 'M';
magic[3] = 1;
// Write magic to the file.
ifwrite(filePtr, magic, 4);
////////////////////////////////
// Write the header to the file.
////////////////////////////////
// Construct a string containing the entire header.
std::string headerString = "";
header.getHeaderString(headerString);
int32_t headerLen = headerString.length();
int numWrite = 0;
// Write the header length.
numWrite = ifwrite(filePtr, &headerLen, sizeof(int32_t));
if(numWrite != sizeof(int32_t))
{
status.setStatus(SamStatus::FAIL_IO,
"Failed to write the BAM header length.");
return(false);
}
// Write the header to the file.
numWrite = ifwrite(filePtr, headerString.c_str(), headerLen);
if(numWrite != headerLen)
{
status.setStatus(SamStatus::FAIL_IO,
"Failed to write the BAM header.");
return(false);
}
////////////////////////////////////////////////////////
// Write the Reference Information.
const SamReferenceInfo& refInfo = header.getReferenceInfo();
// Get the number of sequences.
int32_t numSeq = refInfo.getNumEntries();
ifwrite(filePtr, &numSeq, sizeof(int32_t));
// Write each reference sequence
for (int i = 0; i < numSeq; i++)
{
const char* refName = refInfo.getReferenceName(i);
// Add one for the null value.
int32_t nameLength = strlen(refName) + 1;
// Write the length of the reference name.
ifwrite(filePtr, &nameLength, sizeof(int32_t));
// Write the name.
ifwrite(filePtr, refName, nameLength);
// Write the length of the reference sequence.
int32_t refLen = refInfo.getReferenceLength(i);
ifwrite(filePtr, &refLen, sizeof(int32_t));
}
return(true);
}
void BamInterface::readRecord(IFILE filePtr, SamFileHeader& header,
SamRecord& record,
SamStatus& samStatus)
{
// TODO - need to validate there are @SQ lines in both sam/bam - MAYBE!
// SetBufferFromFile will reset the record prior to reading a new one.
if(record.setBufferFromFile(filePtr, header) != SamStatus::SUCCESS)
{
// Failed, so add the error message.
samStatus.addError(record.getStatus());
}
}
SamStatus::Status BamInterface::writeRecord(IFILE filePtr,
SamFileHeader& header,
SamRecord& record,
SamRecord::SequenceTranslation translation)
{
// Write the file, returning the status.
return(record.writeRecordBuffer(filePtr, translation));
}
ifread
unsigned int ifread(IFILE file, void *buffer, unsigned int size)
Read up to size bytes from the file into the buffer.
Definition: InputFile.h:600
ifwrite
unsigned int ifwrite(IFILE file, const void *buffer, unsigned int size)
Write the specified number of bytes from the specified buffer into the file.
Definition: InputFile.h:669
CharBuffer
Definition: CharBuffer.h:25
InputFile
Class for easily reading/writing files without having to worry about file type (uncompressed,...
Definition: InputFile.h:37
InputFile::isOpen
bool isOpen() const
Returns whether or not the file was successfully opened.
Definition: InputFile.h:423
SamFileHeader
This class allows a user to get/set the fields in a SAM/BAM Header.
Definition: SamFileHeader.h:35
SamFileHeader::getReferenceInfo
const SamReferenceInfo & getReferenceInfo() const
Get the Reference Information.
Definition: SamFileHeader.cpp:165
SamFileHeader::getHeaderString
bool getHeaderString(std::string &header) const
Set the passed in string to the entire header string, clearing its current contents.
Definition: SamFileHeader.cpp:131
SamFileHeader::resetHeader
void resetHeader()
Initialize the header.
Definition: SamFileHeader.cpp:90
SamFileHeader::addHeader
bool addHeader(const char *header)
Add a header that is already preformatted in a const char*.
Definition: SamFileHeader.cpp:204
SamFileHeader::getErrorMessage
const char * getErrorMessage()
Get the failure message if a method returned failure.
Definition: SamFileHeader.h:423
SamRecord
Class providing an easy to use interface to get/set/operate on the fields in a SAM/BAM record.
Definition: SamRecord.h:52
SamRecord::SequenceTranslation
SequenceTranslation
Enum containing the settings on how to translate the sequence if a reference is available.
Definition: SamRecord.h:57
SamRecord::writeRecordBuffer
SamStatus::Status writeRecordBuffer(IFILE filePtr)
Write the record as a BAM into the specified already opened file.
Definition: SamRecord.cpp:1237
SamRecord::setBufferFromFile
SamStatus::Status setBufferFromFile(IFILE filePtr, SamFileHeader &header)
Read the BAM record from a file.
Definition: SamRecord.cpp:558
SamRecord::getStatus
const SamStatus & getStatus()
Returns the status associated with the last method that sets the status.
Definition: SamRecord.cpp:2403
SamReferenceInfo
Class for tracking the reference information mapping between the reference ids and the reference name...
Definition: SamReferenceInfo.h:28
SamReferenceInfo::clear
void clear()
Reset this reference info.
Definition: SamReferenceInfo.cpp:123
SamReferenceInfo::getNumEntries
int32_t getNumEntries() const
Get the number of entries contained here.
Definition: SamReferenceInfo.cpp:93
SamReferenceInfo::getReferenceName
const char * getReferenceName(int index) const
Return the reference name at the specified index, returning "" if the index is out of bounds.
Definition: SamReferenceInfo.cpp:100
SamReferenceInfo::add
void add(const char *referenceSequenceName, int32_t referenceSequenceLength)
Add reference sequence name and reference sequence length.
Definition: SamReferenceInfo.cpp:35
SamReferenceInfo::getReferenceLength
int32_t getReferenceLength(int index) const
Return the reference length at the specified index, returning 0 if the index is out of bounds.
Definition: SamReferenceInfo.cpp:112
StatGenStatus
This class is used to track the status results of some methods in the BAM classes.
Definition: StatGenStatus.h:27
StatGenStatus::Status
Status
Return value enum for StatGenFile methods.
Definition: StatGenStatus.h:32
StatGenStatus::SUCCESS
@ SUCCESS
method completed successfully.
Definition: StatGenStatus.h:32
StatGenStatus::FAIL_IO
@ FAIL_IO
method failed due to an I/O issue.
Definition: StatGenStatus.h:37
StatGenStatus::FAIL_PARSE
@ FAIL_PARSE
failed to parse a record/header - invalid format.
Definition: StatGenStatus.h:42
StatGenStatus::FAIL_ORDER
@ FAIL_ORDER
FAIL_ORDER: method failed because it was called out of order, like trying to read a file without open...
Definition: StatGenStatus.h:41
StatGenStatus::setStatus
void setStatus(Status newStatus, const char *newMessage)
Set the status with the specified status enum and message.
Definition: StatGenStatus.cpp:83
StatGenStatus::addError
void addError(Status newStatus, const char *newMessage)
Add the specified error message to the status message, setting the status to newStatus if the current...
Definition: StatGenStatus.cpp:99
String
Definition: StringBasics.h:39