libStatGen Software
1
|
00001 /* 00002 * Copyright (C) 2010 Regents of the University of Michigan 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #include "SamHeaderRecord.h" 00019 00020 // Constructor 00021 SamHeaderRecord::SamHeaderRecord() 00022 : myTagHash(), 00023 myTags(), 00024 myNumActiveTags(0) 00025 { 00026 } 00027 00028 00029 // Destructor 00030 SamHeaderRecord::~SamHeaderRecord() 00031 { 00032 reset(); 00033 } 00034 00035 00036 // Set the fields from the passed in line. 00037 // Return true if successfully set. 00038 bool SamHeaderRecord::setFields(const StringArray& tokens) 00039 { 00040 bool status = true; 00041 00042 // Loop through the tags for this type. 00043 // The tags start in column 1 since column 0 contains the type. 00044 for(int columnIndex = 1; columnIndex < tokens.Length(); columnIndex++) 00045 { 00046 // Validate that the tag is at least 3 characters. Two for the token, 00047 // one for the ':'. 00048 if((tokens[columnIndex].Length() < 3) || 00049 (tokens[columnIndex][2] != ':')) 00050 { 00051 // Continue to the next tag, this one is too small/invalid. 00052 status = false; 00053 std::cerr << "ERROR: Poorly formatted tag in header: " 00054 << tokens[columnIndex] << std::endl; 00055 continue; 00056 } 00057 00058 // Get the tag from the token. 00059 char tag[3]; 00060 tag[0] = tokens[columnIndex][0]; 00061 tag[1] = tokens[columnIndex][1]; 00062 tag[2] = 0; 00063 00064 // The tag value is the rest of the substring. 00065 String tagValue = (tokens[columnIndex]).SubStr(3); 00066 00067 // Set the tag. 00068 status &= setTag(tag, tagValue.c_str()); 00069 } 00070 00071 status &= isValid(); 00072 00073 return(status); 00074 } 00075 00076 00077 // Check to see if the record is valid. 00078 bool SamHeaderRecord::isValid() 00079 { 00080 bool status = true; 00081 // Check that the required tags are set. If they aren't, return false. 00082 for(unsigned int reqIndex = 0; reqIndex < myRequiredTags.size(); reqIndex++) 00083 { 00084 // Check to see if the required tag at this index exists and has 00085 // a value. 00086 int index = myTagHash.Integer(myRequiredTags[reqIndex].c_str()); 00087 if((index < 0) || !(myTags[index]->hasValue())) 00088 { 00089 // Did not find the tag, stet status to false. 00090 std::cerr << "ERROR: Missing required tag: " 00091 << myRequiredTags[reqIndex] << "." << std::endl; 00092 status = false; 00093 } 00094 } 00095 return(status); 00096 } 00097 00098 00099 // Return the value associated with the specified tag. 00100 const char* SamHeaderRecord::getTagValue(const char* tag) const 00101 { 00102 // Look up the tag in myTags. 00103 int index = myTagHash.Integer(tag); 00104 if(index < 0) 00105 { 00106 // The tag was not found in the hash, so return "". 00107 return(""); 00108 } 00109 00110 // The tag was found in the hash, so return the tag value found at the 00111 // index associated with the tag. 00112 return(myTags[index]->getValue()); 00113 } 00114 00115 00116 // Set the value of the specified tag to the specified value. 00117 // Set value to NULL in order to delete the tag. 00118 // Returns whether or not it was successful. 00119 bool SamHeaderRecord::setTag(const char* tag, const char* value) 00120 { 00121 // Lookup the tag in the hash. 00122 int vectorIndex = myTagHash.Integer(tag); 00123 if(vectorIndex < 0) 00124 { 00125 // The tag was not found in the hash, so create a new one. 00126 SamHeaderTag* tagPtr = new SamHeaderTag(tag, value); 00127 00128 if(tagPtr == NULL) 00129 { 00130 // Failed to allocate the tag, return false. 00131 std::cerr << "Failed to allocate space (new) for a SamHeaderTag.\n"; 00132 return(false); 00133 } 00134 00135 // Add the new tag to the back of the tag values. 00136 vectorIndex = myTags.size(); 00137 myTags.push_back(tagPtr); 00138 00139 // If the value is not null, increment the number of active tags. 00140 if(value[0] != 0) 00141 { 00142 ++myNumActiveTags; 00143 } 00144 00145 // Add the tag to the hash. 00146 int hashIndex = myTagHash.Add(tag, vectorIndex); 00147 00148 if((myTagHash.Integer(hashIndex) != vectorIndex) || 00149 (myTagHash[hashIndex] != tag)) 00150 { 00151 // Failed to add the tag, so return false. 00152 std::cerr << "Failed to add tag, " << tag 00153 << ", to the hash." << std::endl; 00154 return(false); 00155 } 00156 return(true); 00157 } 00158 else if((unsigned int)vectorIndex < myTags.size()) 00159 { 00160 // Found the tag in the hash. So, update the tag if it 00161 // is not the key. 00162 if(myKeyTag != tag) 00163 { 00164 // Not the key, so update the tag. 00165 // If the new value is null and the old one is not, decrement the 00166 // number of active tags. 00167 if((value[0] == 0) && ((myTags[vectorIndex]->getValue())[0] != 0)) 00168 { 00169 // Tag was deleted since the new value is blank but the old 00170 // value was not. 00171 --myNumActiveTags; 00172 } 00173 else if((value[0] != 0) && 00174 ((myTags[vectorIndex]->getValue())[0] == 0)) 00175 { 00176 // Tag was added since the old value was blank and the new value 00177 // is not. 00178 ++myNumActiveTags; 00179 } 00180 00181 // Just modifying a tag, so this does not affect the number 00182 // of active tags. 00183 return(myTags[vectorIndex]->setValue(value)); 00184 } 00185 else if(strcmp(value, myTags[vectorIndex]->getValue()) == 0) 00186 { 00187 // The new key value is the same as the previous value, so 00188 // it is not a change, return true. 00189 return(true); 00190 } 00191 else 00192 { 00193 // Can't modify the key tag's value since that will 00194 // screw up the hash. 00195 std::cerr << "Can't modify the key tag, " << tag << " from " 00196 << myTags[vectorIndex]->getValue() << " to " 00197 << value << std::endl; 00198 return(false); 00199 } 00200 } 00201 00202 // Got an invalid index from the hash. This is not supposed to happen. 00203 // so return false. 00204 std::cerr << "Invalid tag index found: " << vectorIndex 00205 << ", but max index is " << myTags.size() << " for tag: " 00206 << tag << std::endl; 00207 return(false); 00208 } 00209 00210 00211 // Reset this header record to an empty state. 00212 void SamHeaderRecord::reset() 00213 { 00214 // Delete the tag hash. 00215 myTagHash.Clear(); 00216 00217 // Loop through deleting all the tags in the vector. 00218 for(unsigned int vectorIndex = 0; 00219 vectorIndex < myTags.size(); 00220 vectorIndex++) 00221 { 00222 delete myTags[vectorIndex]; 00223 myTags[vectorIndex] = NULL; 00224 } 00225 // Clear the tag vector. 00226 myTags.clear(); 00227 00228 myNumActiveTags = 0; 00229 } 00230 00231 00232 // Appends the string representation of this header record 00233 // to the passed in string. 00234 bool SamHeaderRecord::appendString(std::string& header) 00235 { 00236 // Track whether or not the header type has been written. 00237 // Only write the header type if at least one of the tags has 00238 // an associated value. 00239 bool writtenHeader = false; 00240 00241 if(isActiveHeaderRecord() && isValid()) 00242 { 00243 // Loop through all the entries in the tag vector. 00244 for(unsigned int vectorIndex = 0; 00245 vectorIndex < myTags.size(); 00246 vectorIndex++) 00247 { 00248 if(!writtenHeader && (myTags[vectorIndex]->hasValue())) 00249 { 00250 // The tag has a value and the header type has not yet been written, 00251 // so write it. 00252 header += "@"; 00253 header += myTypeString; 00254 writtenHeader = true; 00255 } 00256 myTags[vectorIndex]->getTagString(header); 00257 } 00258 00259 // If a header has been written, add a new line character. 00260 if(writtenHeader) 00261 { 00262 header += "\n"; 00263 return(true); 00264 } 00265 } 00266 00267 // Nothing was written, return false. 00268 return(false); 00269 } 00270 00271 00272 // Add the key tag with the specified value. 00273 bool SamHeaderRecord::addKey(const char* value) 00274 { 00275 if(myKeyTag.size() == 0) 00276 { 00277 return(false); 00278 } 00279 return(setTag(myKeyTag.data(), value)); 00280 } 00281 00282 00283 // Return the value associated with the specified tag. 00284 const char* SamHeaderRecord::getKeyValue() const 00285 { 00286 // Look up the tag in myTags. 00287 int index = myTagHash.Integer(myKeyTag.c_str()); 00288 if(index < 0) 00289 { 00290 // The tag was not found in the hash, so return "". 00291 return(""); 00292 } 00293 00294 // The tag was found in the hash, so return the tag value found at the 00295 // index associated with the tag. 00296 return(myTags[index]->getValue()); 00297 } 00298 00299 00300 // This header is active if there is at least one tag set. 00301 bool SamHeaderRecord::isActiveHeaderRecord() 00302 { 00303 return(myNumActiveTags != 0); 00304 } 00305 00306 00307 // Return the type of this header record. 00308 const char* SamHeaderRecord::getTypeString() 00309 { 00310 return(myTypeString.c_str()); 00311 } 00312 00313 00314 // Return the type of this header record. 00315 SamHeaderRecord::SamHeaderRecordType SamHeaderRecord::getType() 00316 { 00317 return(myType); 00318 } 00319 00320 00321 void SamHeaderRecord::addRequiredTag(const char* requiredTag) 00322 { 00323 myRequiredTags.push_back(requiredTag); 00324 } 00325 00326 00327 void SamHeaderRecord::internalCopy(SamHeaderRecord& newRec) const 00328 { 00329 newRec.myTagHash = myTagHash; 00330 00331 newRec.myTags.clear(); 00332 00333 // Loop through copying the tags. 00334 for(unsigned int vectorIndex = 0; 00335 vectorIndex < myTags.size(); 00336 vectorIndex++) 00337 { 00338 if(myTags[vectorIndex] != NULL) 00339 { 00340 newRec.myTags.push_back(new SamHeaderTag(*(myTags[vectorIndex]))); 00341 } 00342 } 00343 newRec.myRequiredTags = myRequiredTags; 00344 newRec.myNumActiveTags = myNumActiveTags; 00345 }