]> git.donarmstrong.com Git - bamtools.git/blob - bamtools_convert.cpp
Began rolling over bamtools_sam into bamtools_convert. Kinda hacky setup for now...
[bamtools.git] / bamtools_convert.cpp
1 // ***************************************************************************
2 // bamtools_convert.cpp (c) 2010 Derek Barnett, Erik Garrison
3 // Marth Lab, Department of Biology, Boston College
4 // All rights reserved.
5 // ---------------------------------------------------------------------------
6 // Last modified: 7 June 2010
7 // ---------------------------------------------------------------------------
8 // Converts between BAM and a number of other formats
9 // ***************************************************************************
10
11 #include <iostream>
12 #include <sstream>
13 #include <string>
14 #include <vector>
15
16 #include "bamtools_convert.h"
17 #include "bamtools_format.h"
18 #include "bamtools_options.h"
19 #include "BGZF.h"
20 #include "BamReader.h"
21 #include "BamMultiReader.h"
22
23 using namespace std;
24 using namespace BamTools;
25   
26 static RefVector references;  
27   
28 namespace BamTools {
29   
30     static const string FORMAT_FASTA = "fasta";
31     static const string FORMAT_FASTQ = "fastq";
32     static const string FORMAT_JSON  = "json";
33     static const string FORMAT_SAM   = "sam";
34   
35     void PrintFASTA(const BamAlignment& a);
36     void PrintFASTQ(const BamAlignment& a);
37     void PrintJSON(const BamAlignment& a);
38     void PrintSAM(const BamAlignment& a);
39     
40 } // namespace BamTools
41   
42 // ---------------------------------------------
43 // ConvertSettings implementation
44
45 struct ConvertTool::ConvertSettings {
46
47     // flags
48     bool HasInputBamFilename;
49     bool HasOutputBamFilename;
50     bool HasFormat;
51
52     // filenames
53     string InputFilename;
54     string OutputFilename;
55     string Format;
56     
57     // constructor
58     ConvertSettings(void)
59         : HasInputBamFilename(false)
60         , HasOutputBamFilename(false)
61         , InputFilename(Options::StandardIn())
62         , OutputFilename(Options::StandardOut())
63     { } 
64 };  
65
66 // ---------------------------------------------
67 // ConvertTool implementation
68
69 ConvertTool::ConvertTool(void)
70     : AbstractTool()
71     , m_settings(new ConvertSettings)
72 {
73     // set program details
74     Options::SetProgramInfo("bamtools convert", "converts between BAM and a number of other formats", "-in <filename> -out <filename> -format <FORMAT>");
75     
76     // set up options 
77     OptionGroup* IO_Opts = Options::CreateOptionGroup("Input & Output");
78     Options::AddValueOption("-in",     "BAM filename", "the input BAM file(s)", "", m_settings->HasInputBamFilename,  m_settings->InputFilename,  IO_Opts, Options::StandardIn());
79     Options::AddValueOption("-out",    "BAM filename", "the output BAM file",   "", m_settings->HasOutputBamFilename, m_settings->OutputFilename, IO_Opts, Options::StandardOut());
80     Options::AddValueOption("-format", "FORMAT", "the output file format - see README for recognized formats", "", m_settings->HasFormat, m_settings->Format, IO_Opts);
81 }
82
83 ConvertTool::~ConvertTool(void) {
84     delete m_settings;
85     m_settings = 0;
86 }
87
88 int ConvertTool::Help(void) {
89     Options::DisplayHelp();
90     return 0;
91 }
92
93 int ConvertTool::Run(int argc, char* argv[]) {
94   
95     bool convertedOk = true;
96   
97     // parse command line arguments
98     Options::Parse(argc, argv, 1);
99     
100     // open files
101     BamReader reader;
102     reader.Open(m_settings->InputFilename);
103     references = reader.GetReferenceData();
104         
105     // ----------------------------------------
106     // do conversion,depending on desired output format
107
108     // FASTA
109     if ( m_settings->Format == FORMAT_FASTA ) {
110         cout << "Converting to FASTA" << endl;
111     }
112     
113     // FASTQ
114     else if ( m_settings->Format == FORMAT_FASTQ) {
115         cout << "Converting to FASTQ" << endl;
116     }
117     
118     // JSON
119     else if ( m_settings->Format == FORMAT_JSON ) {
120         cout << "Converting to JSON" << endl;
121     }
122     
123     // SAM
124     else if ( m_settings->Format == FORMAT_SAM ) {
125         BamAlignment alignment;
126         while ( reader.GetNextAlignment(alignment) ) {
127             PrintSAM(alignment);
128         }
129     }
130     
131     // uncrecognized format
132     else { 
133         cerr << "Unrecognized format: " << m_settings->Format << endl;
134         cerr << "Please see help|README (?) for details on supported formats " << endl;
135         convertedOk = false;
136     }
137     
138     // ------------------------
139     // clean up & exit
140     reader.Close();
141     return (int)convertedOk;
142 }
143
144 // ----------------------------------------------------------
145 // Conversion/output methods
146 // ----------------------------------------------------------
147
148 // print BamAlignment in FASTA format
149 void BamTools::PrintFASTA(const BamAlignment& a) { 
150
151 }
152
153 // print BamAlignment in FASTQ format
154 void BamTools::PrintFASTQ(const BamAlignment& a) { 
155
156 }
157
158 // print BamAlignment in JSON format
159 void BamTools::PrintJSON(const BamAlignment& a) { 
160
161 }
162
163 // print BamAlignment in SAM format
164 void BamTools::PrintSAM(const BamAlignment& a) {
165   
166     // tab-delimited
167     // <QNAME> <FLAG> <RNAME> <POS> <MAPQ> <CIGAR> <MRNM> <MPOS> <ISIZE> <SEQ> <QUAL> [ <TAG>:<VTYPE>:<VALUE> [...] ]
168   
169     ostringstream sb("");
170     
171     // write name & alignment flag
172     cout << a.Name << "\t" << a.AlignmentFlag << "\t";
173     
174     // write reference name
175     if ( (a.RefID >= 0) && (a.RefID < (int)references.size()) ) cout << references[a.RefID].RefName << "\t";
176     else cout << "*\t";
177     
178     // write position & map quality
179     cout << a.Position+1 << "\t" << a.MapQuality << "\t";
180     
181     // write CIGAR
182     const vector<CigarOp>& cigarData = a.CigarData;
183     if ( cigarData.empty() ) cout << "*\t";
184     else {
185         vector<CigarOp>::const_iterator cigarIter = cigarData.begin();
186         vector<CigarOp>::const_iterator cigarEnd  = cigarData.end();
187         for ( ; cigarIter != cigarEnd; ++cigarIter ) {
188             const CigarOp& op = (*cigarIter);
189             cout << op.Length << op.Type;
190         }
191         cout << "\t";
192     }
193     
194     // write mate reference name, mate position, & insert size
195     if ( a.IsPaired() && (a.MateRefID >= 0) && (a.MateRefID < (int)references.size()) ) {
196         if ( a.MateRefID == a.RefID ) cout << "=\t";
197         else cout << references[a.MateRefID].RefName << "\t";
198         cout << a.MatePosition+1 << "\t" << a.InsertSize << "\t";
199     } 
200     else cout << "*\t0\t0\t";
201     
202     // write sequence
203     if ( a.QueryBases.empty() ) cout << "*\t";
204     else cout << a.QueryBases << "\t";
205     
206     // write qualities
207     if ( a.Qualities.empty() ) cout << "*";
208     else cout << a.Qualities;
209     
210     // write tag data
211     const char* tagData = a.TagData.c_str();
212     const size_t tagDataLength = a.TagData.length();
213     size_t index = 0;
214     while ( index < tagDataLength ) {
215         
216         // write tag name
217         cout << "\t" << a.TagData.substr(index, 2) << ":";
218         index += 2;
219         
220         // get data type
221         char type = a.TagData.at(index);
222         ++index;
223         
224         switch (type) {
225             case('A') : 
226                 cout << "A:" << tagData[index]; 
227                 ++index; 
228                 break;
229             
230             case('C') : 
231                 cout << "i:" << atoi(&tagData[index]); 
232                 ++index; 
233                 break;
234             
235             case('c') : 
236                 cout << "i:" << atoi(&tagData[index]);
237                 ++index; 
238                 break;
239             
240             case('S') : 
241                 cout << "i:" << BgzfData::UnpackUnsignedShort(&tagData[index]); 
242                 index += 2; 
243                 break;
244                 
245             case('s') : 
246                 cout << "i:" << BgzfData::UnpackSignedShort(&tagData[index]);
247                 index += 2; 
248                 break;
249             
250             case('I') : 
251                 cout << "i:" << BgzfData::UnpackUnsignedInt(&tagData[index]);
252                 index += 4; 
253                 break;
254             
255             case('i') : 
256                 cout << "i:" << BgzfData::UnpackSignedInt(&tagData[index]);
257                 index += 4; 
258                 break;
259             
260             case('f') : 
261                 cout << "f:" << BgzfData::UnpackFloat(&tagData[index]);
262                 index += 4; 
263                 break;
264             
265             case('d') : 
266                 cout << "d:" << BgzfData::UnpackDouble(&tagData[index]);
267                 index += 8; 
268                 break;
269             
270             case('Z') :
271             case('H') : 
272                 cout << type << ":"; 
273                 while (tagData[index]) {
274                     cout << tagData[index];
275                     ++index;
276                 }
277                 ++index; 
278                 break;      
279         }
280     }
281     
282     // write stream to stdout
283     cout << sb.str() << endl;
284 }