]> git.donarmstrong.com Git - bamtools.git/blob - src/api/internal/BamHeader_p.cpp
c613b12f8580bdbb4fc8c5fc25867d6782b8d036
[bamtools.git] / src / api / internal / BamHeader_p.cpp
1 // ***************************************************************************
2 // BamHeader_p.cpp (c) 2010 Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // All rights reserved.
5 // ---------------------------------------------------------------------------
6 // Last modified: 25 December 2010 (DB)
7 // ---------------------------------------------------------------------------
8 // Provides the basic functionality for handling BAM headers.
9 // ***************************************************************************
10
11 #include <api/BamAux.h>
12 #include <api/BamConstants.h>
13 #include <api/BGZF.h>
14 #include <api/internal/BamHeader_p.h>
15 using namespace BamTools;
16 using namespace BamTools::Internal;
17
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 #include <iostream>
22 using namespace std;
23
24 // ---------------------------------
25 // BamHeaderPrivate implementation
26
27 struct BamHeader::BamHeaderPrivate {
28
29     // data members
30     SamHeader* m_samHeader;
31
32     // ctor
33     BamHeaderPrivate(void)
34         : m_samHeader(0)
35     { }
36
37     // 'public' interface
38     bool Load(BgzfData* stream);
39
40     // internal methods
41     bool CheckMagicNumber(BgzfData* stream);
42     bool ReadHeaderLength(BgzfData* stream, uint32_t& length);
43     bool ReadHeaderText(BgzfData* stream, const uint32_t& length);
44 };
45
46 bool BamHeader::BamHeaderPrivate::Load(BgzfData* stream) {
47
48     // cannot load if invalid stream
49     if ( stream == 0 )
50         return false;
51
52     // cannot load if magic number is invalid
53     if ( !CheckMagicNumber(stream) )
54         return false;
55
56     // cannot load header if cannot read header length
57     uint32_t length(0);
58     if ( !ReadHeaderLength(stream, length) )
59         return false;
60
61     // cannot load header if cannot read header text
62     if ( !ReadHeaderText(stream, length) )
63         return false;
64
65     // otherwise, everything OK
66     return true;
67 }
68
69 bool BamHeader::BamHeaderPrivate::CheckMagicNumber(BgzfData* stream) {
70
71     // try to read magic number
72     char buffer[Constants::BAM_HEADER_MAGIC_SIZE];
73     if ( stream->Read(buffer, Constants::BAM_HEADER_MAGIC_SIZE) != (int)Constants::BAM_HEADER_MAGIC_SIZE ) {
74         fprintf(stderr, "BAM header error - could not read magic number\n");
75         return false;
76     }
77
78     // validate magic number
79     if ( strncmp(buffer, Constants::BAM_HEADER_MAGIC, Constants::BAM_HEADER_MAGIC_SIZE) != 0 ) {
80         fprintf(stderr, "BAM header error - invalid magic number\n");
81         return false;
82     }
83
84     // all checks out
85     return true;
86 }
87
88 bool BamHeader::BamHeaderPrivate::ReadHeaderLength(BgzfData* stream, uint32_t& length) {
89
90     // attempt to read BAM header text length
91     char buffer[sizeof(uint32_t)];
92     if ( stream->Read(buffer, sizeof(uint32_t)) != sizeof(uint32_t) ) {
93         fprintf(stderr, "BAM header error - could not read header length\n");
94         return false;
95     }
96
97     // convert char buffer to length, return success
98     length = BgzfData::UnpackUnsignedInt(buffer);
99     if ( BamTools::SystemIsBigEndian() )
100         SwapEndian_32(length);
101     return true;
102 }
103
104 bool BamHeader::BamHeaderPrivate::ReadHeaderText(BgzfData* stream, const uint32_t& length) {
105
106     // set up destination buffer
107     char* headerText = (char*)calloc(length + 1, 1);
108
109     // attempt to read header text
110     const unsigned bytesRead = stream->Read(headerText, length);
111     const bool readOk = ( bytesRead == length );
112     if ( readOk )
113         m_samHeader = new SamHeader( (string)((const char*)headerText) );
114     else
115         fprintf(stderr, "BAM header error - could not read header text\n");
116
117     // clean up calloc-ed temp variable (on success or fail)
118     free(headerText);
119
120     // return read success
121     return readOk;
122 }
123
124 // --------------------------
125 // BamHeader implementation
126
127 BamHeader::BamHeader(void)
128     : d(new BamHeaderPrivate)
129 { }
130
131 BamHeader::~BamHeader(void) {
132     delete d;
133     d = 0;
134 }
135
136 void BamHeader::Clear(void) {
137     delete d->m_samHeader;
138     d->m_samHeader = new SamHeader("");
139 }
140
141 bool BamHeader::IsValid(void) const {
142     return d->m_samHeader->IsValid();
143 }
144
145 bool BamHeader::Load(BgzfData* stream) {
146     return d->Load(stream);
147 }
148
149 SamHeader BamHeader::ToSamHeader(void) const {
150     return *(d->m_samHeader);
151 }
152
153 string BamHeader::ToString(void) const {
154     return d->m_samHeader->ToString();
155 }