| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package EBook::Ishmael::EBook::zTXT; |
|
2
|
17
|
|
|
17
|
|
337
|
use 5.016; |
|
|
17
|
|
|
|
|
73
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '2.03'; |
|
4
|
17
|
|
|
17
|
|
110
|
use strict; |
|
|
17
|
|
|
|
|
48
|
|
|
|
17
|
|
|
|
|
524
|
|
|
5
|
17
|
|
|
17
|
|
83
|
use warnings; |
|
|
17
|
|
|
|
|
44
|
|
|
|
17
|
|
|
|
|
1056
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
17
|
|
|
17
|
|
121
|
use Encode qw(decode); |
|
|
17
|
|
|
|
|
452
|
|
|
|
17
|
|
|
|
|
1139
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
17
|
|
|
17
|
|
103
|
use EBook::Ishmael::CharDet; |
|
|
17
|
|
|
|
|
62
|
|
|
|
17
|
|
|
|
|
900
|
|
|
10
|
17
|
|
|
17
|
|
131
|
use EBook::Ishmael::EBook::Metadata; |
|
|
17
|
|
|
|
|
32
|
|
|
|
17
|
|
|
|
|
645
|
|
|
11
|
17
|
|
|
17
|
|
117
|
use EBook::Ishmael::PDB; |
|
|
17
|
|
|
|
|
43
|
|
|
|
17
|
|
|
|
|
423
|
|
|
12
|
17
|
|
|
17
|
|
79
|
use EBook::Ishmael::TextToHtml; |
|
|
17
|
|
|
|
|
48
|
|
|
|
17
|
|
|
|
|
22811
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my $TYPE = 'zTXT'; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# Minimum version we support is 1.40. Pre-1.40 is de-standardized. |
|
17
|
|
|
|
|
|
|
my $MINVER = 0x0128; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $RANDOM_ACCESS = 0x1; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Checks to see if the PDB type is 'zTXT'. The creator is ignored, as that can |
|
22
|
|
|
|
|
|
|
# differ between zTXT creators. |
|
23
|
|
|
|
|
|
|
sub heuristic { |
|
24
|
|
|
|
|
|
|
|
|
25
|
24
|
|
|
24
|
0
|
62
|
my $class = shift; |
|
26
|
24
|
|
|
|
|
50
|
my $file = shift; |
|
27
|
24
|
|
|
|
|
46
|
my $fh = shift; |
|
28
|
|
|
|
|
|
|
|
|
29
|
24
|
50
|
|
|
|
440
|
return 0 unless -s $file >= 68; |
|
30
|
|
|
|
|
|
|
|
|
31
|
24
|
|
|
|
|
147
|
seek $fh, 32, 0; |
|
32
|
24
|
|
|
|
|
205
|
read $fh, my ($null), 1; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Last byte in title must be null |
|
35
|
24
|
100
|
|
|
|
87
|
unless ($null eq "\0") { |
|
36
|
12
|
|
|
|
|
87
|
return 0; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
12
|
|
|
|
|
83
|
seek $fh, 60, 0; |
|
40
|
12
|
|
|
|
|
108
|
read $fh, my ($type), 4; |
|
41
|
|
|
|
|
|
|
|
|
42
|
12
|
|
|
|
|
103
|
return $type eq $TYPE; |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Should be called with record #1 first. |
|
47
|
|
|
|
|
|
|
sub _decode_record { |
|
48
|
|
|
|
|
|
|
|
|
49
|
21
|
|
|
21
|
|
36
|
my $self = shift; |
|
50
|
21
|
|
|
|
|
41
|
my $rec = shift; |
|
51
|
|
|
|
|
|
|
|
|
52
|
21
|
|
|
|
|
33
|
$rec++; |
|
53
|
|
|
|
|
|
|
|
|
54
|
21
|
|
|
|
|
88
|
my $out = $self->{_inflate}->inflate($self->{_pdb}->record($rec)->data); |
|
55
|
|
|
|
|
|
|
|
|
56
|
21
|
50
|
|
|
|
2098
|
unless (defined $out) { |
|
57
|
0
|
|
|
|
|
0
|
die "Error decompressing zTXT stream in $self->{Source}\n"; |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
21
|
|
|
|
|
292
|
return $out; |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub _text { |
|
65
|
|
|
|
|
|
|
|
|
66
|
7
|
|
|
7
|
|
15137
|
my $self = shift; |
|
67
|
|
|
|
|
|
|
|
|
68
|
7
|
|
|
|
|
1775
|
require Compress::Zlib; |
|
69
|
|
|
|
|
|
|
|
|
70
|
7
|
50
|
|
|
|
110789
|
$self->{_inflate} = Compress::Zlib::inflateInit(-WindowBits => 15) |
|
71
|
|
|
|
|
|
|
or die "Failed to initialize zlib inflator\n"; |
|
72
|
|
|
|
|
|
|
|
|
73
|
7
|
|
|
|
|
1845
|
my $text = join('', map { $self->_decode_record($_) } 0 .. $self->{_recnum} - 1); |
|
|
21
|
|
|
|
|
67
|
|
|
74
|
|
|
|
|
|
|
|
|
75
|
7
|
|
|
|
|
55
|
$self->{_inflate} = undef; |
|
76
|
|
|
|
|
|
|
|
|
77
|
7
|
|
|
|
|
29
|
return $text; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub new { |
|
82
|
|
|
|
|
|
|
|
|
83
|
11
|
|
|
11
|
0
|
48
|
my $class = shift; |
|
84
|
11
|
|
|
|
|
26
|
my $file = shift; |
|
85
|
11
|
|
|
|
|
27
|
my $enc = shift; |
|
86
|
|
|
|
|
|
|
|
|
87
|
11
|
|
|
|
|
128
|
my $self = { |
|
88
|
|
|
|
|
|
|
Source => undef, |
|
89
|
|
|
|
|
|
|
Metadata => EBook::Ishmael::EBook::Metadata->new, |
|
90
|
|
|
|
|
|
|
Encoding => $enc, |
|
91
|
|
|
|
|
|
|
_pdb => undef, |
|
92
|
|
|
|
|
|
|
_version => undef, |
|
93
|
|
|
|
|
|
|
_recnum => undef, |
|
94
|
|
|
|
|
|
|
_size => undef, |
|
95
|
|
|
|
|
|
|
_recsize => undef, |
|
96
|
|
|
|
|
|
|
_bookmarknum => undef, |
|
97
|
|
|
|
|
|
|
_bookmarkrec => undef, |
|
98
|
|
|
|
|
|
|
_annotnum => undef, |
|
99
|
|
|
|
|
|
|
_annotrec => undef, |
|
100
|
|
|
|
|
|
|
_flags => undef, |
|
101
|
|
|
|
|
|
|
_reserved => undef, |
|
102
|
|
|
|
|
|
|
_crc32 => undef, |
|
103
|
|
|
|
|
|
|
}; |
|
104
|
|
|
|
|
|
|
|
|
105
|
11
|
|
|
|
|
32
|
bless $self, $class; |
|
106
|
|
|
|
|
|
|
|
|
107
|
11
|
|
|
|
|
453
|
$self->{Source} = File::Spec->rel2abs($file); |
|
108
|
|
|
|
|
|
|
|
|
109
|
11
|
|
|
|
|
108
|
$self->{_pdb} = EBook::Ishmael::PDB->new($file); |
|
110
|
|
|
|
|
|
|
|
|
111
|
11
|
|
|
|
|
77
|
my $hdr = $self->{_pdb}->record(0)->data; |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
( |
|
114
|
|
|
|
|
|
|
$self->{_version}, |
|
115
|
|
|
|
|
|
|
$self->{_recnum}, |
|
116
|
|
|
|
|
|
|
$self->{_size}, |
|
117
|
|
|
|
|
|
|
$self->{_recsize}, |
|
118
|
|
|
|
|
|
|
$self->{_bookmarknum}, |
|
119
|
|
|
|
|
|
|
$self->{_bookmarkrec}, |
|
120
|
|
|
|
|
|
|
$self->{_annotnum}, |
|
121
|
|
|
|
|
|
|
$self->{_annotrec}, |
|
122
|
|
|
|
|
|
|
$self->{_flags}, |
|
123
|
|
|
|
|
|
|
$self->{_reserved}, |
|
124
|
|
|
|
|
|
|
$self->{_crc32}, |
|
125
|
|
|
|
|
|
|
undef |
|
126
|
11
|
|
|
|
|
118
|
) = unpack "n n N n n n n n C C N C4", $hdr; |
|
127
|
|
|
|
|
|
|
|
|
128
|
11
|
50
|
|
|
|
61
|
if ($self->{_version} < $MINVER) { |
|
129
|
|
|
|
|
|
|
die sprintf |
|
130
|
|
|
|
|
|
|
"%s zTXT is of an unsupported version, %d.%d (%d.%d and above are supported).\n", |
|
131
|
|
|
|
|
|
|
$self->{Source}, |
|
132
|
0
|
|
|
|
|
0
|
($self->{_version} >> 8) & 0xff, $self->{_version} & 0xff, |
|
133
|
|
|
|
|
|
|
($MINVER >> 8) & 0xff, $MINVER & 0xff; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
11
|
50
|
|
|
|
46
|
unless ($self->{_flags} & $RANDOM_ACCESS) { |
|
137
|
0
|
|
|
|
|
0
|
die "$self->{Source} zTXT uses unsupported compression method\n"; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
11
|
|
|
|
|
56
|
$self->{Metadata}->set_title($self->{_pdb}->name); |
|
141
|
|
|
|
|
|
|
|
|
142
|
11
|
50
|
|
|
|
47
|
if ($self->{_pdb}->cdate) { |
|
143
|
11
|
|
|
|
|
39
|
$self->{Metadata}->set_created($self->{_pdb}->cdate); |
|
144
|
|
|
|
|
|
|
} |
|
145
|
11
|
50
|
|
|
|
37
|
if ($self->{_pdb}->mdate) { |
|
146
|
11
|
|
|
|
|
39
|
$self->{Metadata}->set_modified($self->{_pdb}->mdate); |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
$self->{Metadata}->set_format( |
|
150
|
|
|
|
|
|
|
sprintf |
|
151
|
|
|
|
|
|
|
"zTXT %s.%s", |
|
152
|
|
|
|
|
|
|
($self->{_version} >> 8) & 0xff, |
|
153
|
11
|
|
|
|
|
82
|
$self->{_version} & 0xff |
|
154
|
|
|
|
|
|
|
); |
|
155
|
|
|
|
|
|
|
|
|
156
|
11
|
|
|
|
|
47
|
return $self; |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub html { |
|
161
|
|
|
|
|
|
|
|
|
162
|
3
|
|
|
3
|
0
|
11
|
my $self = shift; |
|
163
|
3
|
|
|
|
|
8
|
my $out = shift; |
|
164
|
|
|
|
|
|
|
|
|
165
|
3
|
|
|
|
|
91
|
my $html = text2html($self->raw); |
|
166
|
|
|
|
|
|
|
|
|
167
|
3
|
50
|
|
|
|
15
|
if (defined $out) { |
|
168
|
0
|
0
|
|
|
|
0
|
open my $fh, '>', $out |
|
169
|
|
|
|
|
|
|
or die "Failed to open $out for writing: $!\n"; |
|
170
|
0
|
|
|
|
|
0
|
binmode $fh, ':utf8'; |
|
171
|
0
|
|
|
|
|
0
|
print { $fh } $html; |
|
|
0
|
|
|
|
|
0
|
|
|
172
|
0
|
|
|
|
|
0
|
close $fh; |
|
173
|
0
|
|
|
|
|
0
|
return $out; |
|
174
|
|
|
|
|
|
|
} else { |
|
175
|
3
|
|
|
|
|
25
|
return $html; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub raw { |
|
181
|
|
|
|
|
|
|
|
|
182
|
6
|
|
|
6
|
0
|
18
|
my $self = shift; |
|
183
|
6
|
|
|
|
|
14
|
my $out = shift; |
|
184
|
|
|
|
|
|
|
|
|
185
|
6
|
|
|
|
|
29
|
my $raw = $self->_text; |
|
186
|
6
|
100
|
|
|
|
26
|
if (not defined $self->{Encoding}) { |
|
187
|
5
|
|
50
|
|
|
30
|
$self->{Encoding} = chardet($raw) // 'ASCII'; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
6
|
|
|
|
|
89
|
$raw = decode($self->{Encoding}, $raw); |
|
190
|
|
|
|
|
|
|
|
|
191
|
6
|
50
|
|
|
|
1936
|
if (defined $out) { |
|
192
|
0
|
0
|
|
|
|
0
|
open my $fh, '>', $out |
|
193
|
|
|
|
|
|
|
or die "Failed to open $out for writing: $!\n"; |
|
194
|
0
|
|
|
|
|
0
|
binmode $fh, ':utf8'; |
|
195
|
0
|
|
|
|
|
0
|
print { $fh } $raw; |
|
|
0
|
|
|
|
|
0
|
|
|
196
|
0
|
|
|
|
|
0
|
close $fh; |
|
197
|
0
|
|
|
|
|
0
|
return $out; |
|
198
|
|
|
|
|
|
|
} else { |
|
199
|
6
|
|
|
|
|
51
|
return $raw; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub metadata { |
|
205
|
|
|
|
|
|
|
|
|
206
|
4
|
|
|
4
|
0
|
12
|
my $self = shift; |
|
207
|
|
|
|
|
|
|
|
|
208
|
4
|
|
|
|
|
27
|
return $self->{Metadata}; |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
2
|
|
|
2
|
0
|
12
|
sub has_cover { 0 } |
|
213
|
|
|
|
|
|
|
|
|
214
|
1
|
|
|
1
|
0
|
6
|
sub cover { (undef, undef) } |
|
215
|
|
|
|
|
|
|
|
|
216
|
2
|
|
|
2
|
0
|
29
|
sub image_num { 0 } |
|
217
|
|
|
|
|
|
|
|
|
218
|
1
|
|
|
1
|
0
|
7
|
sub image { (undef, undef) } |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
1; |