| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package BioX::Seq::Stream; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
489
|
use 5.012; |
|
|
1
|
|
|
|
|
4
|
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
19
|
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
26
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
5
|
use IPC::Cmd qw/can_run/; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
45
|
|
|
8
|
1
|
|
|
1
|
|
6
|
use Scalar::Util qw/blessed openhandle/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
63
|
|
|
9
|
1
|
|
|
1
|
|
7
|
use BioX::Seq; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
21
|
|
|
10
|
1
|
|
|
1
|
|
6
|
use POSIX qw/ceil/; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
8
|
|
|
11
|
1
|
|
|
1
|
|
465
|
use Cwd qw/abs_path/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
49
|
|
|
12
|
1
|
|
|
1
|
|
6
|
use File::Basename qw/fileparse/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
175
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# define or search for binary locations |
|
15
|
|
|
|
|
|
|
# if these are not available |
|
16
|
|
|
|
|
|
|
our $GZIP_BIN = can_run('pigz') // can_run('gzip'); |
|
17
|
|
|
|
|
|
|
our $BZIP_BIN = can_run('pbzip2') // can_run('bzip2'); |
|
18
|
|
|
|
|
|
|
our $ZSTD_BIN = can_run('pzstd') // can_run('zstd'); |
|
19
|
|
|
|
|
|
|
our $DSRC_BIN = can_run('dsrc2') // can_run('dsrc'); |
|
20
|
|
|
|
|
|
|
our $FQZC_BIN = can_run('fqz_comp'); |
|
21
|
|
|
|
|
|
|
our $XZ_BIN = can_run('xz'); |
|
22
|
|
|
|
|
|
|
|
|
23
|
1
|
|
|
1
|
|
6
|
use constant MAGIC_GZIP => pack('C3', 0x1f, 0x8b, 0x08); |
|
|
1
|
|
|
|
|
10
|
|
|
|
1
|
|
|
|
|
78
|
|
|
24
|
1
|
|
|
1
|
|
7
|
use constant MAGIC_DSRC => pack('C2', 0xaa, 0x02); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
47
|
|
|
25
|
1
|
|
|
1
|
|
5
|
use constant MAGIC_BZIP => 'BZh'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
57
|
|
|
26
|
1
|
|
|
1
|
|
6
|
use constant MAGIC_FQZC => '.fqz'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
64
|
|
|
27
|
1
|
|
|
1
|
|
6
|
use constant MAGIC_BAM => pack('C4', 0x42, 0x41, 0x4d, 0x01); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
51
|
|
|
28
|
1
|
|
|
1
|
|
5
|
use constant MAGIC_2BIT => pack('C4', 0x1a, 0x41, 0x27, 0x43); |
|
|
1
|
|
|
|
|
11
|
|
|
|
1
|
|
|
|
|
64
|
|
|
29
|
1
|
|
|
1
|
|
6
|
use constant MAGIC_ZSTD => pack('C4', 0x28, 0xB5, 0x2F, 0xFD); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
50
|
|
|
30
|
1
|
|
|
1
|
|
5
|
use constant MAGIC_XZ => pack('C6', 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
965
|
|
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new { |
|
33
|
|
|
|
|
|
|
|
|
34
|
25
|
|
|
25
|
1
|
7669
|
my ($class,$fn, %args) = @_; |
|
35
|
|
|
|
|
|
|
|
|
36
|
25
|
|
|
|
|
85
|
my $self = bless {} => $class; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# 'fast' mode turns off parser sanity-checking in places |
|
39
|
25
|
100
|
|
|
|
110
|
if ($args{fast}) { |
|
40
|
1
|
|
|
|
|
12
|
$self->fast( $args{fast} ); |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
25
|
100
|
|
|
|
63
|
if (defined $fn) { |
|
44
|
|
|
|
|
|
|
|
|
45
|
24
|
|
|
|
|
66
|
my $fh = openhandle($fn); # can pass filehandle too; |
|
46
|
24
|
100
|
|
|
|
55
|
if (! defined $fh) { # otherwise assume filename |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
#if passed a filename, try to determine if compressed |
|
49
|
22
|
100
|
|
|
|
974
|
open $fh, '<', $fn or die "Error opening $fn for reading\n"; |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
#read first six bytes as raw |
|
52
|
|
|
|
|
|
|
#this causes a memory leak as opened filehandles are not properly |
|
53
|
|
|
|
|
|
|
#closed again. Should work without setting binary mode anyway. |
|
54
|
|
|
|
|
|
|
#my $old_layers = join '', map {":$_"} PerlIO::get_layers($fh); |
|
55
|
|
|
|
|
|
|
#binmode($fh); |
|
56
|
21
|
|
|
|
|
466
|
read( $fh, my $magic, 6 ); |
|
57
|
|
|
|
|
|
|
#binmode($fh, $old_layers); |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
#check for compression and open stream if found |
|
60
|
21
|
100
|
|
|
|
264
|
if (substr($magic,0,3) eq MAGIC_GZIP) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
61
|
5
|
|
|
|
|
71
|
close $fh; |
|
62
|
5
|
100
|
|
|
|
20
|
if (! defined $GZIP_BIN) { |
|
63
|
|
|
|
|
|
|
# fall back on Perl-based method (but can be SLOOOOOW!) |
|
64
|
1
|
|
|
|
|
1846
|
require IO::Uncompress::Gunzip; |
|
65
|
1
|
|
|
|
|
37953
|
$fh = IO::Uncompress::Gunzip->new($fn, MultiStream => 1); |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
else { |
|
68
|
4
|
100
|
|
|
|
13007
|
open $fh, '-|', $GZIP_BIN, '-dc', $fn |
|
69
|
|
|
|
|
|
|
or die "Error opening gzip stream: $!\n"; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
elsif (substr($magic,0,3) eq MAGIC_BZIP) { |
|
73
|
3
|
|
|
|
|
49
|
close $fh; |
|
74
|
3
|
100
|
|
|
|
19
|
if (! defined $BZIP_BIN) { |
|
75
|
|
|
|
|
|
|
# fall back on Perl-based method (but can be SLOOOOOW!) |
|
76
|
1
|
|
|
|
|
2886
|
require IO::Uncompress::Bunzip2; |
|
77
|
1
|
|
|
|
|
9093
|
$fh = IO::Uncompress::Bunzip2->new($fn, MultiStream => 1); |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
else { |
|
80
|
2
|
100
|
|
|
|
8997
|
open $fh, '-|', $BZIP_BIN, '-dc', $fn |
|
81
|
|
|
|
|
|
|
or die "Error opening bzip2 stream: $!\n"; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
} |
|
84
|
|
|
|
|
|
|
elsif (substr($magic,0,4) eq MAGIC_ZSTD) { |
|
85
|
2
|
100
|
|
|
|
31
|
die "no zstd backend found\n" if (! defined $ZSTD_BIN); |
|
86
|
1
|
|
|
|
|
14
|
close $fh; |
|
87
|
1
|
50
|
|
|
|
3831
|
open $fh, '-|', $ZSTD_BIN, '-dc', $fn |
|
88
|
|
|
|
|
|
|
or die "Error opening zstd stream: $!\n"; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
elsif (substr($magic,0,2) eq MAGIC_DSRC) { |
|
91
|
2
|
100
|
|
|
|
48
|
die "no dsrc backend found\n" if (! defined $DSRC_BIN); |
|
92
|
1
|
|
|
|
|
25
|
close $fh; |
|
93
|
1
|
50
|
|
|
|
3475
|
open $fh, '-|', $DSRC_BIN, 'd', '-s', $fn |
|
94
|
|
|
|
|
|
|
or die "Error opening dsrc stream: $!\n"; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
elsif (substr($magic,0,4) eq MAGIC_FQZC) { |
|
97
|
2
|
100
|
|
|
|
67
|
die "no fqz backend found\n" if (! defined $FQZC_BIN); |
|
98
|
1
|
|
|
|
|
28
|
close $fh; |
|
99
|
1
|
50
|
|
|
|
3917
|
open $fh, '-|', $FQZC_BIN, '-d', $fn |
|
100
|
|
|
|
|
|
|
or die "Error opening fqz_comp stream: $!\n"; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
elsif (substr($magic,0,6) eq MAGIC_XZ) { |
|
103
|
1
|
50
|
|
|
|
6
|
die "no xz backend found\n" if (! defined $XZ_BIN); |
|
104
|
1
|
|
|
|
|
18
|
close $fh; |
|
105
|
1
|
50
|
|
|
|
5450
|
open $fh, '-|', $XZ_BIN, '-dc', $fn |
|
106
|
|
|
|
|
|
|
or die "Error opening xz stream: $!\n"; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
else { |
|
109
|
6
|
|
|
|
|
69
|
seek($fh,0,0); |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
} |
|
113
|
15
|
|
|
|
|
4524
|
$self->{fh} = $fh; |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
else { |
|
117
|
1
|
|
|
|
|
4
|
$self->{fh} = \*STDIN; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# handle files coming from different platforms |
|
121
|
|
|
|
|
|
|
#my @layers = PerlIO::get_layers($self->{fh}); |
|
122
|
|
|
|
|
|
|
#binmode($self->{fh},':unix:stdio:crlf'); |
|
123
|
|
|
|
|
|
|
|
|
124
|
16
|
|
|
|
|
160
|
$self->_guess_format; |
|
125
|
|
|
|
|
|
|
|
|
126
|
14
|
|
|
|
|
64
|
$self->_init; |
|
127
|
|
|
|
|
|
|
|
|
128
|
12
|
|
|
|
|
407
|
return $self; |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub fast { |
|
133
|
|
|
|
|
|
|
|
|
134
|
1
|
|
|
1
|
1
|
3
|
my ($self, $bool) = @_; |
|
135
|
1
|
|
50
|
|
|
38
|
$self->{fast} = $bool // 1; |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub _guess_format { |
|
140
|
|
|
|
|
|
|
|
|
141
|
16
|
|
|
16
|
|
59
|
my ($self) = @_; |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Filetype guessing must be based on first two bytes (or less) |
|
144
|
|
|
|
|
|
|
# which are stored in an object buffer |
|
145
|
16
|
|
|
|
|
6750
|
my $r = (read $self->{fh}, $self->{buffer}, 2); |
|
146
|
16
|
100
|
|
|
|
216
|
die "failed to read initial bytes" if ($r != 2); |
|
147
|
|
|
|
|
|
|
|
|
148
|
15
|
|
|
|
|
1171
|
my $search_path = abs_path(__FILE__); |
|
149
|
15
|
|
|
|
|
246
|
$search_path =~ s/\.pm$//i; |
|
150
|
15
|
|
|
|
|
42
|
my @matched; |
|
151
|
15
|
|
|
|
|
1711
|
for my $module ( glob "$search_path/*.pm" ) { |
|
152
|
45
|
|
|
|
|
1872
|
my ($name,$path,$suff) = fileparse($module, qr/\.pm/i); |
|
153
|
45
|
|
|
|
|
312
|
my $classname = blessed($self) . "::$name"; |
|
154
|
45
|
|
|
|
|
3240
|
eval "require $classname"; |
|
155
|
45
|
100
|
|
|
|
393
|
if ($classname->_check_type($self)) { |
|
156
|
14
|
|
|
|
|
49
|
push @matched, $classname; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
15
|
100
|
|
|
|
78
|
die "Failed to guess filetype\n" if (scalar(@matched) < 1); |
|
161
|
|
|
|
|
|
|
# uncoverable branch true |
|
162
|
14
|
50
|
|
|
|
33
|
die "Multiple filetypes matched\n" if (scalar(@matched) > 1); |
|
163
|
|
|
|
|
|
|
|
|
164
|
14
|
|
|
|
|
676
|
eval "require $matched[0]"; |
|
165
|
14
|
|
|
|
|
62
|
bless $self => $matched[0]; |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
1; |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
__END__ |