File Coverage

blib/lib/EBook/Ishmael/CharDet/UTF8.pm
Criterion Covered Total %
statement 41 51 80.3
branch 17 24 70.8
condition 0 3 0.0
subroutine 7 9 77.7
pod 0 5 0.0
total 65 92 70.6


line stmt bran cond sub pod time code
1             package EBook::Ishmael::CharDet::UTF8;
2 18     18   322 use 5.016;
  18         68  
3             our $VERSION = '2.03';
4 18     18   123 use strict;
  18         35  
  18         554  
5 18     18   86 use warnings;
  18         37  
  18         1091  
6              
7 18     18   121 use EBook::Ishmael::CharDet::Constants qw(:CONSTANTS);
  18         34  
  18         13334  
8              
9             my $ONE_CHAR_PROB = 0.5;
10             my $THRESHOLD = 7;
11              
12             sub new {
13              
14 67     67 0 216 my ($class) = @_;
15              
16 67         678 my $self = {
17             Code => undef,
18             Left => 0,
19             MBs => 0,
20             Total => 0,
21             Bad => 0,
22             };
23 67         745 return bless $self, $class;
24              
25             }
26              
27             sub take {
28              
29 3410     3410 0 7044 my ($self, $bytes) = @_;
30              
31 3410 50       7987 return TAKE_BAD if $self->{Bad};
32 3410 50       8141 return TAKE_MUST_BE if $self->{MBs} >= $THRESHOLD;
33              
34 3410         6997 for my $i (0 .. length($bytes)-1) {
35 54002         87320 my $b = ord(substr $bytes, $i, 1) & 0xff;
36 54002 100       95687 if (not defined $self->{Code}) {
37             # ASCII
38 53653 100       91106 if (not $b & 0x80) {
    100          
    100          
    50          
39 53386         77497 $self->{Total}++;
40 53386         85820 next;
41             # 2-byte character (0b110...)
42             } elsif ($b >> 5 == 0b110) {
43 150         286 $self->{Code} = $b & 0b11111;
44 150         306 $self->{Left} = 1;
45             # 3-byte character (0b1110...)
46             } elsif ($b >> 4 == 0b1110) {
47 102         274 $self->{Code} = $b & 0b1111;
48 102         221 $self->{Left} = 2;
49             # 4-byte character (0b11110...)
50             } elsif ($b >> 3 == 0b11110) {
51 0         0 $self->{Code} = $b & 0b111;
52 0         0 $self->{Left} = 3;
53             # Invalid UTF8
54             } else {
55 15         41 $self->{Bad} = 1;
56 15         55 return TAKE_BAD;
57             }
58             } else {
59 349 100       897 if ($b >> 6 != 0b10) {
60 19         42 $self->{Bad} = 1;
61 19         67 return TAKE_BAD;
62             }
63 330         710 $self->{Code} = ($self->{Code} << 6) | ($b & 0b111111);
64 330         510 $self->{Left}--;
65 330 100       777 if ($self->{Left} == 0) {
66 233         343 $self->{Total}++;
67 233         385 $self->{MBs}++;
68 233         416 undef $self->{Code};
69 233 100       1564 return TAKE_MUST_BE if $self->{MBs} >= $THRESHOLD;
70             }
71             }
72             }
73              
74 3343         8834 return TAKE_OK;
75              
76             }
77              
78             sub confidence {
79              
80 0     0 0 0 my ($self) = @_;
81              
82 0 0 0     0 if ($self->{Bad} or $self->{MBs} == 0) {
83 0         0 return 0;
84             }
85              
86             # >= 6, we effectively get 0.99
87 0 0       0 if ($self->{MBs} < 6) {
88 0         0 return 1.0 - ($ONE_CHAR_PROB ** $self->{MBs});
89             } else {
90 0         0 return 0.99;
91             }
92              
93             }
94              
95             sub bad {
96              
97 0     0 0 0 my ($self) = @_;
98              
99 0         0 return $self->{Bad};
100              
101             }
102              
103 33     33 0 289 sub encoding { 'UTF-8' }
104              
105             1;