libStatGen Software  1
SamHeaderRecord.cpp
1 /*
2  * Copyright (C) 2010 Regents of the University of Michigan
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "SamHeaderRecord.h"
19 
20 // Constructor
22  : myTagHash(),
23  myTags(),
24  myNumActiveTags(0)
25 {
26 }
27 
28 
29 // Destructor
31 {
32  reset();
33 }
34 
35 
36 // Set the fields from the passed in line.
37 // Return true if successfully set.
39 {
40  bool status = true;
41 
42  // Loop through the tags for this type.
43  // The tags start in column 1 since column 0 contains the type.
44  for(int columnIndex = 1; columnIndex < tokens.Length(); columnIndex++)
45  {
46  // Validate that the tag is at least 3 characters. Two for the token,
47  // one for the ':'.
48  if((tokens[columnIndex].Length() < 3) ||
49  (tokens[columnIndex][2] != ':'))
50  {
51  // Continue to the next tag, this one is too small/invalid.
52  status = false;
53  std::cerr << "ERROR: Poorly formatted tag in header: "
54  << tokens[columnIndex] << std::endl;
55  continue;
56  }
57 
58  // Get the tag from the token.
59  char tag[3];
60  tag[0] = tokens[columnIndex][0];
61  tag[1] = tokens[columnIndex][1];
62  tag[2] = 0;
63 
64  // The tag value is the rest of the substring.
65  String tagValue = (tokens[columnIndex]).SubStr(3);
66 
67  // Set the tag.
68  status &= setTag(tag, tagValue.c_str());
69  }
70 
71  status &= isValid();
72 
73  return(status);
74 }
75 
76 
77 // Check to see if the record is valid.
79 {
80  bool status = true;
81  // Check that the required tags are set. If they aren't, return false.
82  for(unsigned int reqIndex = 0; reqIndex < myRequiredTags.size(); reqIndex++)
83  {
84  // Check to see if the required tag at this index exists and has
85  // a value.
86  int index = myTagHash.Integer(myRequiredTags[reqIndex].c_str());
87  if((index < 0) || !(myTags[index]->hasValue()))
88  {
89  // Did not find the tag, stet status to false.
90  std::cerr << "ERROR: Missing required tag: "
91  << myRequiredTags[reqIndex] << "." << std::endl;
92  status = false;
93  }
94  }
95  return(status);
96 }
97 
98 
99 // Return the value associated with the specified tag.
100 const char* SamHeaderRecord::getTagValue(const char* tag) const
101 {
102  // Look up the tag in myTags.
103  int index = myTagHash.Integer(tag);
104  if(index < 0)
105  {
106  // The tag was not found in the hash, so return "".
107  return("");
108  }
109 
110  // The tag was found in the hash, so return the tag value found at the
111  // index associated with the tag.
112  return(myTags[index]->getValue());
113 }
114 
115 
116 // Set the value of the specified tag to the specified value.
117 // Set value to NULL in order to delete the tag.
118 // Returns whether or not it was successful.
119 bool SamHeaderRecord::setTag(const char* tag, const char* value)
120 {
121  // Lookup the tag in the hash.
122  int vectorIndex = myTagHash.Integer(tag);
123  if(vectorIndex < 0)
124  {
125  // The tag was not found in the hash, so create a new one.
126  SamHeaderTag* tagPtr = new SamHeaderTag(tag, value);
127 
128  if(tagPtr == NULL)
129  {
130  // Failed to allocate the tag, return false.
131  std::cerr << "Failed to allocate space (new) for a SamHeaderTag.\n";
132  return(false);
133  }
134 
135  // Add the new tag to the back of the tag values.
136  vectorIndex = myTags.size();
137  myTags.push_back(tagPtr);
138 
139  // If the value is not null, increment the number of active tags.
140  if(value[0] != 0)
141  {
142  ++myNumActiveTags;
143  }
144 
145  // Add the tag to the hash.
146  int hashIndex = myTagHash.Add(tag, vectorIndex);
147 
148  if((myTagHash.Integer(hashIndex) != vectorIndex) ||
149  (myTagHash[hashIndex] != tag))
150  {
151  // Failed to add the tag, so return false.
152  std::cerr << "Failed to add tag, " << tag
153  << ", to the hash." << std::endl;
154  return(false);
155  }
156  return(true);
157  }
158  else if((unsigned int)vectorIndex < myTags.size())
159  {
160  // Found the tag in the hash. So, update the tag if it
161  // is not the key.
162  if(myKeyTag != tag)
163  {
164  // Not the key, so update the tag.
165  // If the new value is null and the old one is not, decrement the
166  // number of active tags.
167  if((value[0] == 0) && ((myTags[vectorIndex]->getValue())[0] != 0))
168  {
169  // Tag was deleted since the new value is blank but the old
170  // value was not.
171  --myNumActiveTags;
172  }
173  else if((value[0] != 0) &&
174  ((myTags[vectorIndex]->getValue())[0] == 0))
175  {
176  // Tag was added since the old value was blank and the new value
177  // is not.
178  ++myNumActiveTags;
179  }
180 
181  // Just modifying a tag, so this does not affect the number
182  // of active tags.
183  return(myTags[vectorIndex]->setValue(value));
184  }
185  else if(strcmp(value, myTags[vectorIndex]->getValue()) == 0)
186  {
187  // The new key value is the same as the previous value, so
188  // it is not a change, return true.
189  return(true);
190  }
191  else
192  {
193  // Can't modify the key tag's value since that will
194  // screw up the hash.
195  std::cerr << "Can't modify the key tag, " << tag << " from "
196  << myTags[vectorIndex]->getValue() << " to "
197  << value << std::endl;
198  return(false);
199  }
200  }
201 
202  // Got an invalid index from the hash. This is not supposed to happen.
203  // so return false.
204  std::cerr << "Invalid tag index found: " << vectorIndex
205  << ", but max index is " << myTags.size() << " for tag: "
206  << tag << std::endl;
207  return(false);
208 }
209 
210 
211 // Reset this header record to an empty state.
213 {
214  // Delete the tag hash.
215  myTagHash.Clear();
216 
217  // Loop through deleting all the tags in the vector.
218  for(unsigned int vectorIndex = 0;
219  vectorIndex < myTags.size();
220  vectorIndex++)
221  {
222  delete myTags[vectorIndex];
223  myTags[vectorIndex] = NULL;
224  }
225  // Clear the tag vector.
226  myTags.clear();
227 
228  myNumActiveTags = 0;
229 }
230 
231 
232 // Appends the string representation of this header record
233 // to the passed in string.
234 bool SamHeaderRecord::appendString(std::string& header)
235 {
236  // Track whether or not the header type has been written.
237  // Only write the header type if at least one of the tags has
238  // an associated value.
239  bool writtenHeader = false;
240 
241  if(isActiveHeaderRecord() && isValid())
242  {
243  // Loop through all the entries in the tag vector.
244  for(unsigned int vectorIndex = 0;
245  vectorIndex < myTags.size();
246  vectorIndex++)
247  {
248  if(!writtenHeader && (myTags[vectorIndex]->hasValue()))
249  {
250  // The tag has a value and the header type has not yet been written,
251  // so write it.
252  header += "@";
253  header += myTypeString;
254  writtenHeader = true;
255  }
256  myTags[vectorIndex]->getTagString(header);
257  }
258 
259  // If a header has been written, add a new line character.
260  if(writtenHeader)
261  {
262  header += "\n";
263  return(true);
264  }
265  }
266 
267  // Nothing was written, return false.
268  return(false);
269 }
270 
271 
272 // Add the key tag with the specified value.
273 bool SamHeaderRecord::addKey(const char* value)
274 {
275  if(myKeyTag.size() == 0)
276  {
277  return(false);
278  }
279  return(setTag(myKeyTag.data(), value));
280 }
281 
282 
283 // Return the value associated with the specified tag.
284 const char* SamHeaderRecord::getKeyValue() const
285 {
286  // Look up the tag in myTags.
287  int index = myTagHash.Integer(myKeyTag.c_str());
288  if(index < 0)
289  {
290  // The tag was not found in the hash, so return "".
291  return("");
292  }
293 
294  // The tag was found in the hash, so return the tag value found at the
295  // index associated with the tag.
296  return(myTags[index]->getValue());
297 }
298 
299 
300 // This header is active if there is at least one tag set.
302 {
303  return(myNumActiveTags != 0);
304 }
305 
306 
307 // Return the type of this header record.
309 {
310  return(myTypeString.c_str());
311 }
312 
313 
314 // Return the type of this header record.
316 {
317  return(myType);
318 }
319 
320 
321 void SamHeaderRecord::addRequiredTag(const char* requiredTag)
322 {
323  myRequiredTags.push_back(requiredTag);
324 }
325 
326 
327 void SamHeaderRecord::internalCopy(SamHeaderRecord& newRec) const
328 {
329  newRec.myTagHash = myTagHash;
330 
331  newRec.myTags.clear();
332 
333  // Loop through copying the tags.
334  for(unsigned int vectorIndex = 0;
335  vectorIndex < myTags.size();
336  vectorIndex++)
337  {
338  if(myTags[vectorIndex] != NULL)
339  {
340  newRec.myTags.push_back(new SamHeaderTag(*(myTags[vectorIndex])));
341  }
342  }
343  newRec.myRequiredTags = myRequiredTags;
344  newRec.myNumActiveTags = myNumActiveTags;
345 }
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