-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreader.go
154 lines (146 loc) · 3.89 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package gfa
import (
"bufio"
"bytes"
"fmt"
"io"
)
// Reader implements GFA format reading.
type Reader struct {
reader *bufio.Reader
gfa *GFA
}
// NewReader returns a new Reader, reading from the given io.Reader
func NewReader(r io.Reader) (*Reader, error) {
gfaReader := &Reader{
reader: bufio.NewReader(r),
gfa: NewGFA(),
}
// check there is something in the file
_, err := gfaReader.reader.Peek(1)
if err != nil {
return nil, err
}
// get the header lines, ignore comments and stop looking once a non header/comment line encountered
for {
peek, err := gfaReader.reader.Peek(1)
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
// only look at lines beginning with H (72) and # (35)
if (peek[0] == 72) || (peek[0] == 35) {
line, err := gfaReader.reader.ReadBytes('\n')
if err != nil {
return nil, io.ErrUnexpectedEOF
}
if bytes.Contains(line, []byte("VN:Z:1")) {
err := gfaReader.gfa.AddVersion(1)
if err != nil {
return nil, err
}
} else if bytes.Contains(line, []byte("VN:Z:2")) {
err := gfaReader.gfa.AddVersion(2)
if err != nil {
return nil, err
}
}
if line[0] == '#' {
gfaReader.gfa.AddComment(line[1 : len(line)-1])
}
} else {
break
}
}
return gfaReader, nil
}
// CollectGFA returns the GFA instance held by the reader
func (r *Reader) CollectGFA() *GFA {
return r.gfa
}
// Read returns the next (non H/#) GFA line from the reader
func (r *Reader) Read() (gfaLine, error) {
bytesLine, err := r.reader.ReadBytes('\n')
if err != nil {
return nil, err
}
// ignore empty lines TODO: I need a better fix than this
if len(bytesLine) <= 1 {
return nil, fmt.Errorf("Encountered empty line, quiting")
}
// trim the line
bytesLine = bytesLine[:len(bytesLine)-1]
if bytesLine[len(bytesLine)-1] == '\r' {
bytesLine = bytesLine[:len(bytesLine)-1]
}
var line gfaLine
// split the line on tab
fields := bytes.Split(bytesLine, []byte("\t"))
if len(fields) < 3 {
return nil, fmt.Errorf("Not enough fields in GFA line: %v", string(bytesLine))
}
// determine what type of line it is and then create a gfaLine using the required fields
switch bytesLine[0] {
// segment line (S)
case 83:
line, err = NewSegment(fields[1], fields[2])
if err != nil {
return nil, fmt.Errorf("Could not read segment line: %v", err)
}
fields = fields[3:]
// link line (L)
case 76:
line, err = NewLink(fields[1], fields[2], fields[3], fields[4], fields[5])
if err != nil {
return nil, fmt.Errorf("Could not read link line: %v", err)
}
fields = fields[6:]
// containment line (C)
case 67:
line, err = NewSegment([]byte("dummy4containment"), []byte("actg"))
if err != nil {
return nil, fmt.Errorf("Could not read containment line: %v", err)
}
fields = fields[3:]
// path line (P)
case 80:
line, err = NewPath(fields[1], bytes.Split(fields[2], []byte(",")), bytes.Split(fields[3], []byte(",")))
if err != nil {
return nil, fmt.Errorf("Could not read path line: %v", err)
}
fields = fields[4:]
default:
return nil, fmt.Errorf("Encountered unknown line type: %v", string(bytesLine[0]))
}
// fields slice will now only contain optional fields (if present)
if len(fields) != 0 {
oFs, err := NewOptionalFields(fields...)
if err != nil {
return nil, fmt.Errorf("Could not parse optional fields: %v", err)
}
line.AddOptionalFields(oFs)
}
return line, nil
}
// GFAwriter implements GFA format writing
type GFAwriter struct {
w io.Writer
}
// NewWriter returns a Writer to the given io.Writer
func NewWriter(w io.Writer, myGFA *GFA) (*GFAwriter, error) {
writer := &GFAwriter{w: w}
_, err := writer.w.Write(myGFA.MarshalHeader())
if err != nil {
return nil, err
}
return writer, nil
}
// Write writes a line to the GFA stream
func (myWriter *GFAwriter) Write(line gfaLine) error {
b := []byte(line.PrintGFAline())
b = append(b, '\n')
_, err := myWriter.w.Write(b)
return err
}