SamHeaderRecord.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 "SamHeaderRecord.h"
// Constructor
SamHeaderRecord::SamHeaderRecord()
: myTagHash(),
myTags(),
myNumActiveTags(0)
{
}
// Destructor
SamHeaderRecord::~SamHeaderRecord()
{
reset();
}
// Set the fields from the passed in line.
// Return true if successfully set.
bool SamHeaderRecord::setFields(const StringArray& tokens)
{
bool status = true;
// Loop through the tags for this type.
// The tags start in column 1 since column 0 contains the type.
for(int columnIndex = 1; columnIndex < tokens.Length(); columnIndex++)
{
// Validate that the tag is at least 3 characters. Two for the token,
// one for the ':'.
if((tokens[columnIndex].Length() < 3) ||
(tokens[columnIndex][2] != ':'))
{
// Continue to the next tag, this one is too small/invalid.
status = false;
std::cerr << "ERROR: Poorly formatted tag in header: "
<< tokens[columnIndex] << std::endl;
continue;
}
// Get the tag from the token.
char tag[3];
tag[0] = tokens[columnIndex][0];
tag[1] = tokens[columnIndex][1];
tag[2] = 0;
// The tag value is the rest of the substring.
String tagValue = (tokens[columnIndex]).SubStr(3);
// Set the tag.
status &= setTag(tag, tagValue.c_str());
}
status &= isValid();
return(status);
}
// Check to see if the record is valid.
bool SamHeaderRecord::isValid()
{
bool status = true;
// Check that the required tags are set. If they aren't, return false.
for(unsigned int reqIndex = 0; reqIndex < myRequiredTags.size(); reqIndex++)
{
// Check to see if the required tag at this index exists and has
// a value.
int index = myTagHash.Integer(myRequiredTags[reqIndex].c_str());
if((index < 0) || !(myTags[index]->hasValue()))
{
// Did not find the tag, stet status to false.
std::cerr << "ERROR: Missing required tag: "
<< myRequiredTags[reqIndex] << "." << std::endl;
status = false;
}
}
return(status);
}
// Return the value associated with the specified tag.
const char* SamHeaderRecord::getTagValue(const char* tag) const
{
// Look up the tag in myTags.
int index = myTagHash.Integer(tag);
if(index < 0)
{
// The tag was not found in the hash, so return "".
return("");
}
// The tag was found in the hash, so return the tag value found at the
// index associated with the tag.
return(myTags[index]->getValue());
}
// Set the value of the specified tag to the specified value.
// Set value to NULL in order to delete the tag.
// Returns whether or not it was successful.
bool SamHeaderRecord::setTag(const char* tag, const char* value)
{
// Lookup the tag in the hash.
int vectorIndex = myTagHash.Integer(tag);
if(vectorIndex < 0)
{
// The tag was not found in the hash, so create a new one.
SamHeaderTag* tagPtr = new SamHeaderTag(tag, value);
if(tagPtr == NULL)
{
// Failed to allocate the tag, return false.
std::cerr << "Failed to allocate space (new) for a SamHeaderTag.\n";
return(false);
}
// Add the new tag to the back of the tag values.
vectorIndex = myTags.size();
myTags.push_back(tagPtr);
// If the value is not null, increment the number of active tags.
if(value[0] != 0)
{
++myNumActiveTags;
}
// Add the tag to the hash.
int hashIndex = myTagHash.Add(tag, vectorIndex);
if((myTagHash.Integer(hashIndex) != vectorIndex) ||
(myTagHash[hashIndex] != tag))
{
// Failed to add the tag, so return false.
std::cerr << "Failed to add tag, " << tag
<< ", to the hash." << std::endl;
return(false);
}
return(true);
}
else if((unsigned int)vectorIndex < myTags.size())
{
// Found the tag in the hash. So, update the tag if it
// is not the key.
if(myKeyTag != tag)
{
// Not the key, so update the tag.
// If the new value is null and the old one is not, decrement the
// number of active tags.
if((value[0] == 0) && ((myTags[vectorIndex]->getValue())[0] != 0))
{
// Tag was deleted since the new value is blank but the old
// value was not.
--myNumActiveTags;
}
else if((value[0] != 0) &&
((myTags[vectorIndex]->getValue())[0] == 0))
{
// Tag was added since the old value was blank and the new value
// is not.
++myNumActiveTags;
}
// Just modifying a tag, so this does not affect the number
// of active tags.
return(myTags[vectorIndex]->setValue(value));
}
else if(strcmp(value, myTags[vectorIndex]->getValue()) == 0)
{
// The new key value is the same as the previous value, so
// it is not a change, return true.
return(true);
}
else
{
// Can't modify the key tag's value since that will
// screw up the hash.
std::cerr << "Can't modify the key tag, " << tag << " from "
<< myTags[vectorIndex]->getValue() << " to "
<< value << std::endl;
return(false);
}
}
// Got an invalid index from the hash. This is not supposed to happen.
// so return false.
std::cerr << "Invalid tag index found: " << vectorIndex
<< ", but max index is " << myTags.size() << " for tag: "
<< tag << std::endl;
return(false);
}
// Reset this header record to an empty state.
void SamHeaderRecord::reset()
{
// Delete the tag hash.
myTagHash.Clear();
// Loop through deleting all the tags in the vector.
for(unsigned int vectorIndex = 0;
vectorIndex < myTags.size();
vectorIndex++)
{
delete myTags[vectorIndex];
myTags[vectorIndex] = NULL;
}
// Clear the tag vector.
myTags.clear();
myNumActiveTags = 0;
}
// Appends the string representation of this header record
// to the passed in string.
bool SamHeaderRecord::appendString(std::string& header)
{
// Track whether or not the header type has been written.
// Only write the header type if at least one of the tags has
// an associated value.
bool writtenHeader = false;
if(isActiveHeaderRecord() && isValid())
{
// Loop through all the entries in the tag vector.
for(unsigned int vectorIndex = 0;
vectorIndex < myTags.size();
vectorIndex++)
{
if(!writtenHeader && (myTags[vectorIndex]->hasValue()))
{
// The tag has a value and the header type has not yet been written,
// so write it.
header += "@";
header += myTypeString;
writtenHeader = true;
}
myTags[vectorIndex]->getTagString(header);
}
// If a header has been written, add a new line character.
if(writtenHeader)
{
header += "\n";
return(true);
}
}
// Nothing was written, return false.
return(false);
}
// Add the key tag with the specified value.
bool SamHeaderRecord::addKey(const char* value)
{
if(myKeyTag.size() == 0)
{
return(false);
}
return(setTag(myKeyTag.data(), value));
}
// Return the value associated with the specified tag.
const char* SamHeaderRecord::getKeyValue() const
{
// Look up the tag in myTags.
int index = myTagHash.Integer(myKeyTag.c_str());
if(index < 0)
{
// The tag was not found in the hash, so return "".
return("");
}
// The tag was found in the hash, so return the tag value found at the
// index associated with the tag.
return(myTags[index]->getValue());
}
// This header is active if there is at least one tag set.
bool SamHeaderRecord::isActiveHeaderRecord()
{
return(myNumActiveTags != 0);
}
// Return the type of this header record.
const char* SamHeaderRecord::getTypeString()
{
return(myTypeString.c_str());
}
// Return the type of this header record.
SamHeaderRecord::SamHeaderRecordType SamHeaderRecord::getType()
{
return(myType);
}
void SamHeaderRecord::addRequiredTag(const char* requiredTag)
{
myRequiredTags.push_back(requiredTag);
}
void SamHeaderRecord::internalCopy(SamHeaderRecord& newRec) const
{
newRec.myTagHash = myTagHash;
newRec.myTags.clear();
// Loop through copying the tags.
for(unsigned int vectorIndex = 0;
vectorIndex < myTags.size();
vectorIndex++)
{
if(myTags[vectorIndex] != NULL)
{
newRec.myTags.push_back(new SamHeaderTag(*(myTags[vectorIndex])));
}
}
newRec.myRequiredTags = myRequiredTags;
newRec.myNumActiveTags = myNumActiveTags;
}
SamHeaderRecord::SamHeaderRecord
SamHeaderRecord()
Constructor.
Definition: SamHeaderRecord.cpp:21
SamHeaderRecord::isActiveHeaderRecord
bool isActiveHeaderRecord()
This record is active (true) if there is at least one tag set.
Definition: SamHeaderRecord.cpp:301
SamHeaderRecord::getTagValue
const char * getTagValue(const char *tag) const
Return the value associated with the specified tag.
Definition: SamHeaderRecord.cpp:100
SamHeaderRecord::~SamHeaderRecord
virtual ~SamHeaderRecord()
Destructor.
Definition: SamHeaderRecord.cpp:30
String
Definition: StringBasics.h:38
SamHeaderRecord::getTypeString
const char * getTypeString()
Return the type of this header record (HD, SQ, RG, or PG) as a string.
Definition: SamHeaderRecord.cpp:308
SamHeaderTag
Definition: SamHeaderTag.h:23
SamHeaderRecord::isValid
bool isValid()
Check to see if the record is valid.
Definition: SamHeaderRecord.cpp:78
SamHeaderRecord::setFields
bool setFields(const StringArray &tokens)
Set the fields from the passed in line.
Definition: SamHeaderRecord.cpp:38
SamHeaderRecord::getKeyValue
const char * getKeyValue() const
Get the value associated with the key tag. Returns "" if it is not set.
Definition: SamHeaderRecord.cpp:284
SamHeaderRecord::addKey
bool addKey(const char *value)
Add the key tag with the specified value (not for HD headers).
Definition: SamHeaderRecord.cpp:273
SamHeaderRecord::appendString
bool appendString(std::string &header)
Appends the string representation of this header record to the passed in string.
Definition: SamHeaderRecord.cpp:234
SamHeaderRecord::SamHeaderRecordType
SamHeaderRecordType
Specifies the Type for the sam header record (line).
Definition: SamHeaderRecord.h:31
SamHeaderRecord::reset
void reset()
Reset this header record to an empty state with no tags.
Definition: SamHeaderRecord.cpp:212
SamHeaderRecord::getType
SamHeaderRecordType getType()
Return the type of this header record (HD, SQ, RG, or PG) as an enum.
Definition: SamHeaderRecord.cpp:315
SamHeaderRecord
This class encapsulates the tag value pairs contained with a SAM Header line with accessors for getti...
Definition: SamHeaderRecord.h:27
SamHeaderRecord::setTag
bool setTag(const char *tag, const char *value)
Set the value of the specified tag to the specified value, deletes the tag when value is NULL.
Definition: SamHeaderRecord.cpp:119
StringArray
Definition: StringArray.h:23