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__ |