EBook-Ishmael
view release on metacpan or search on metacpan
lib/EBook/Ishmael/EBook/Mobi.pm view on Meta::CPAN
my $data = shift;
my $res = 0;
my $trail = substr $data, -4;
for my $c (unpack "C4", $trail) {
if ($c & 0x80) {
$res = 0;
}
$res = ($res << 7) | ($c & 0x7f);
}
return $res;
}
sub _trailing_entries_size {
my $self = shift;
my $data = shift;
my $res = 0;
for my $i (0 .. $self->{_trailers} - 1) {
my $n = _trailing_entry_size($data);
$res += $n;
substr $data, -$n, $n, '';
}
if ($self->{_extra_data} & 1) {
$res += (ord(substr $data, -1) & 3) + 1;
}
return $res;
}
# Index processing code was adapted from KindleUnpack
sub _get_index_data {
my $self = shift;
my $idx = shift;
return {} if $idx == $NULL_INDEX;
my $outtbl = [];
my $ctoc = {};
my $data;
$$data = $self->{_pdb}->record($idx)->data;
my ($idxhdr, $hordt1, $hordt2) = $self->_parse_indx_header($data);
my $icount = $idxhdr->{count};
my $roff = 0;
my $off = $idx + $icount + 1;
for my $i (0 .. $idxhdr->{nctoc} - 1) {
my $cdata = $self->{_pdb}->record($off + $i)->data;
my $ctocdict = $self->_read_ctoc(\$cdata);
for my $j (sort keys %$ctocdict) {
$ctoc->{ $j + $roff } = $ctocdict->{ $j };
}
$roff += 0x10000;
}
my $tagstart = $idxhdr->{len};
my ($ctrlcount, $tagtbl) = _read_tag_section($tagstart, $data);
for my $i ($idx + 1 .. $idx + 1 + $icount - 1) {
my $d = $self->{_pdb}->record($i)->data;
my ($hdrinfo, $ordt1, $ordt2) = $self->_parse_indx_header(\$d);
my $idxtpos = $hdrinfo->{start};
my $ecount = $hdrinfo->{count};
my $idxposits = [];
for my $j (0 .. $ecount - 1) {
my $pos = unpack "n", substr $d, $idxtpos + 4 + (2 * $j), 2;
push @$idxposits, $pos;
}
for my $j (0 .. $ecount - 1) {
my $spos = $idxposits->[$j];
my $epos = $idxposits->[$j + 1];
my $txtlen = ord(substr $d, $spos, 1);
my $txt = substr $d, $spos + 1, $txtlen;
if (@$hordt2) {
$txt = join '',
map { chr $hordt2->[ ord $_ ] }
split //, $txt;
}
my $tagmap = _get_tagmap(
$ctrlcount,
$tagtbl,
\$d,
$spos + 1 + $txtlen,
$epos
);
push @$outtbl, [ $txt, $tagmap ];
}
}
return ( $outtbl, $ctoc );
}
sub _parse_indx_header {
my $self = shift;
my $data = shift;
unless (substr($$data, 0, 4) eq 'INDX') {
die "Index section is not INDX\n";
}
my @words = qw(
len nul1 type gen start count code lng total ordt ligt nligt nctoc
);
my $num = scalar @words;
my @values = unpack "N$num", substr $$data, 4, 4 * $num;
my $header = {};
( run in 0.620 second using v1.01-cache-2.11-cpan-6aa56a78535 )