]> git.donarmstrong.com Git - bamtools.git/blob - src/api/internal/SamFormatParser_p.cpp
Brought API up to compliance with recent SAM Format Spec (v1.4-r962)
[bamtools.git] / src / api / internal / SamFormatParser_p.cpp
1 // ***************************************************************************
2 // SamFormatParser.cpp (c) 2010 Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // All rights reserved.
5 // ---------------------------------------------------------------------------
6 // Last modified: 19 April 2011 (DB)
7 // ---------------------------------------------------------------------------
8 // Provides functionality for parsing SAM header text into SamHeader object
9 // ***************************************************************************
10
11 #include <api/SamConstants.h>
12 #include <api/SamHeader.h>
13 #include <api/internal/SamFormatParser_p.h>
14 using namespace BamTools;
15 using namespace BamTools::Internal;
16
17 #include <iostream>
18 #include <sstream>
19 #include <vector>
20 using namespace std;
21
22 SamFormatParser::SamFormatParser(SamHeader& header)
23     : m_header(header)
24 { }
25
26 SamFormatParser::~SamFormatParser(void) { }
27
28 void SamFormatParser::Parse(const string& headerText) {
29
30     // clear header's prior contents
31     m_header.Clear();
32
33     // empty header is OK, but skip processing
34     if ( headerText.empty() )
35         return;
36
37     // other wise parse SAM lines
38     istringstream headerStream(headerText);
39     string headerLine("");
40     while ( getline(headerStream, headerLine) )
41          ParseSamLine(headerLine);
42 }
43
44 void SamFormatParser::ParseSamLine(const string& line) {
45
46     // skip if line is not long enough to contain true values
47     if (line.length() < 5 ) return;
48
49     // determine token at beginning of line
50     const string firstToken = line.substr(0,3);
51     string restOfLine = line.substr(4);
52     if      ( firstToken == Constants::SAM_HD_BEGIN_TOKEN) ParseHDLine(restOfLine);
53     else if ( firstToken == Constants::SAM_SQ_BEGIN_TOKEN) ParseSQLine(restOfLine);
54     else if ( firstToken == Constants::SAM_RG_BEGIN_TOKEN) ParseRGLine(restOfLine);
55     else if ( firstToken == Constants::SAM_PG_BEGIN_TOKEN) ParsePGLine(restOfLine);
56     else if ( firstToken == Constants::SAM_CO_BEGIN_TOKEN) ParseCOLine(restOfLine);
57     else
58         cerr << "SamFormatParser ERROR: unknown token: " << firstToken << endl;
59 }
60
61 void SamFormatParser::ParseHDLine(const string& line) {
62
63     // split HD lines into tokens
64     vector<string> tokens = Split(line, Constants::SAM_TAB);
65
66     // iterate over tokens
67     vector<string>::const_iterator tokenIter = tokens.begin();
68     vector<string>::const_iterator tokenEnd  = tokens.end();
69     for ( ; tokenIter != tokenEnd; ++tokenIter ) {
70
71         // get tag/value
72         const string tokenTag = (*tokenIter).substr(0,2);
73         const string tokenValue = (*tokenIter).substr(3);
74
75         // set header contents
76         if      ( tokenTag == Constants::SAM_HD_VERSION_TAG    ) m_header.Version    = tokenValue;
77         else if ( tokenTag == Constants::SAM_HD_SORTORDER_TAG  ) m_header.SortOrder  = tokenValue;
78         else if ( tokenTag == Constants::SAM_HD_GROUPORDER_TAG ) m_header.GroupOrder = tokenValue;
79         else
80             cerr << "SamFormatParser ERROR: unknown HD tag: " << tokenTag << endl;
81     }
82
83     // if @HD line exists, VN must be provided
84     if ( !m_header.HasVersion() )
85         cerr << "SamFormatParser ERROR: @HD line is missing VN tag" << endl;
86 }
87
88 void SamFormatParser::ParseSQLine(const string& line) {
89
90     SamSequence seq;
91
92     // split SQ line into tokens
93     vector<string> tokens = Split(line, Constants::SAM_TAB);
94
95     // iterate over tokens
96     vector<string>::const_iterator tokenIter = tokens.begin();
97     vector<string>::const_iterator tokenEnd  = tokens.end();
98     for ( ; tokenIter != tokenEnd; ++tokenIter ) {
99
100         // get tag/value
101         const string tokenTag = (*tokenIter).substr(0,2);
102         const string tokenValue = (*tokenIter).substr(3);
103
104         // set sequence contents
105         if      ( tokenTag == Constants::SAM_SQ_NAME_TAG       ) seq.Name = tokenValue;
106         else if ( tokenTag == Constants::SAM_SQ_LENGTH_TAG     ) seq.Length = tokenValue;
107         else if ( tokenTag == Constants::SAM_SQ_ASSEMBLYID_TAG ) seq.AssemblyID = tokenValue;
108         else if ( tokenTag == Constants::SAM_SQ_CHECKSUM_TAG   ) seq.Checksum = tokenValue;
109         else if ( tokenTag == Constants::SAM_SQ_SPECIES_TAG    ) seq.Species = tokenValue;
110         else if ( tokenTag == Constants::SAM_SQ_URI_TAG        ) seq.URI = tokenValue;
111         else
112             cerr << "SamFormatParser ERROR: unknown SQ tag: " << tokenTag << endl;
113     }
114
115     bool isMissingRequiredFields = false;
116
117     // if @SQ line exists, SN must be provided
118     if ( !seq.HasName() ) {
119         isMissingRequiredFields = true;
120         cerr << "SamFormatParser ERROR: @SQ line is missing SN tag" << endl;
121     }
122
123     // if @SQ line exists, LN must be provided
124     if ( !seq.HasLength() ) {
125         isMissingRequiredFields = true;
126         cerr << "SamFormatParser ERROR: @SQ line is missing LN tag" << endl;
127     }
128
129     // store SAM sequence entry
130     if ( !isMissingRequiredFields )
131         m_header.Sequences.Add(seq);
132 }
133
134 void SamFormatParser::ParseRGLine(const string& line) {
135
136     SamReadGroup rg;
137
138     // split string into tokens
139     vector<string> tokens = Split(line, Constants::SAM_TAB);
140
141     // iterate over tokens
142     vector<string>::const_iterator tokenIter = tokens.begin();
143     vector<string>::const_iterator tokenEnd  = tokens.end();
144     for ( ; tokenIter != tokenEnd; ++tokenIter ) {
145
146         // get token tag/value
147         const string tokenTag = (*tokenIter).substr(0,2);
148         const string tokenValue = (*tokenIter).substr(3);
149
150         // set read group contents
151         if      ( tokenTag == Constants::SAM_RG_ID_TAG                  ) rg.ID = tokenValue;
152         else if ( tokenTag == Constants::SAM_RG_DESCRIPTION_TAG         ) rg.Description = tokenValue;
153         else if ( tokenTag == Constants::SAM_RG_FLOWORDER_TAG           ) rg.FlowOrder = tokenValue;
154         else if ( tokenTag == Constants::SAM_RG_KEYSEQUENCE_TAG         ) rg.KeySequence = tokenValue;
155         else if ( tokenTag == Constants::SAM_RG_LIBRARY_TAG             ) rg.Library = tokenValue;
156         else if ( tokenTag == Constants::SAM_RG_PLATFORMUNIT_TAG        ) rg.PlatformUnit = tokenValue;
157         else if ( tokenTag == Constants::SAM_RG_PREDICTEDINSERTSIZE_TAG ) rg.PredictedInsertSize = tokenValue;
158         else if ( tokenTag == Constants::SAM_RG_PRODUCTIONDATE_TAG      ) rg.ProductionDate = tokenValue;
159         else if ( tokenTag == Constants::SAM_RG_PROGRAM_TAG             ) rg.Program = tokenValue;
160         else if ( tokenTag == Constants::SAM_RG_SAMPLE_TAG              ) rg.Sample = tokenValue;
161         else if ( tokenTag == Constants::SAM_RG_SEQCENTER_TAG           ) rg.SequencingCenter = tokenValue;
162         else if ( tokenTag == Constants::SAM_RG_SEQTECHNOLOGY_TAG       ) rg.SequencingTechnology = tokenValue;
163         else
164             cerr << "SamFormatParser ERROR: unknown RG tag: " << tokenTag << endl;
165     }
166
167     bool isMissingRequiredFields = false;
168
169     // if @RG line exists, ID must be provided
170     if ( !rg.HasID() ) {
171         isMissingRequiredFields = true;
172         cerr << "SamFormatParser ERROR: @RG line is missing ID tag" << endl;
173     }
174
175     // store SAM read group entry
176     if ( !isMissingRequiredFields )
177         m_header.ReadGroups.Add(rg);
178 }
179
180 void SamFormatParser::ParsePGLine(const string& line) {
181
182     SamProgram pg;
183
184     // split string into tokens
185     vector<string> tokens = Split(line, Constants::SAM_TAB);
186
187     // iterate over tokens
188     vector<string>::const_iterator tokenIter = tokens.begin();
189     vector<string>::const_iterator tokenEnd  = tokens.end();
190     for ( ; tokenIter != tokenEnd; ++tokenIter ) {
191
192         // get token tag/value
193         const string tokenTag = (*tokenIter).substr(0,2);
194         const string tokenValue = (*tokenIter).substr(3);
195
196         // set program record contents
197         if      ( tokenTag == Constants::SAM_PG_ID_TAG              ) pg.ID = tokenValue;
198         else if ( tokenTag == Constants::SAM_PG_NAME_TAG            ) pg.Name = tokenValue;
199         else if ( tokenTag == Constants::SAM_PG_COMMANDLINE_TAG     ) pg.CommandLine = tokenValue;
200         else if ( tokenTag == Constants::SAM_PG_PREVIOUSPROGRAM_TAG ) pg.PreviousProgramID = tokenValue;
201         else if ( tokenTag == Constants::SAM_PG_VERSION_TAG         ) pg.Version = tokenValue;
202         else
203             cerr << "SamFormatParser ERROR: unknown PG tag: " << tokenTag << endl;
204     }
205
206     bool isMissingRequiredFields = false;
207
208     // if @PG line exists, ID must be provided
209     if ( !pg.HasID() ) {
210         isMissingRequiredFields = true;
211         cerr << "SamFormatParser ERROR: @PG line is missing ID tag" << endl;
212     }
213
214     // store SAM program record
215     if ( !isMissingRequiredFields )
216         m_header.Programs.Add(pg);
217 }
218
219 void SamFormatParser::ParseCOLine(const string& line) {
220     // simply add line to comments list
221     m_header.Comments.push_back(line);
222 }
223
224 const vector<string> SamFormatParser::Split(const string& line, const char delim) {
225     vector<string> tokens;
226     stringstream lineStream(line);
227     string token;
228     while ( getline(lineStream, token, delim) )
229         tokens.push_back(token);
230     return tokens;
231 }