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   242 use 5.016;
  18         50  
3             our $VERSION = '2.05';
4 18     18   77 use strict;
  18         25  
  18         434  
5 18     18   62 use warnings;
  18         28  
  18         775  
6              
7 18     18   66 use EBook::Ishmael::CharDet::Constants qw(:CONSTANTS);
  18         33  
  18         9021  
8              
9             my $ONE_CHAR_PROB = 0.5;
10             my $THRESHOLD = 7;
11              
12             sub new {
13              
14 67     67 0 139 my ($class) = @_;
15              
16 67         467 my $self = {
17             Code => undef,
18             Left => 0,
19             MBs => 0,
20             Total => 0,
21             Bad => 0,
22             };
23 67         565 return bless $self, $class;
24              
25             }
26              
27             sub take {
28              
29 3410     3410 0 4058 my ($self, $bytes) = @_;
30              
31 3410 50       4689 return TAKE_BAD if $self->{Bad};
32 3410 50       4881 return TAKE_MUST_BE if $self->{MBs} >= $THRESHOLD;
33              
34 3410         4327 for my $i (0 .. length($bytes)-1) {
35 54002         54017 my $b = ord(substr $bytes, $i, 1) & 0xff;
36 54002 100       59977 if (not defined $self->{Code}) {
37             # ASCII
38 53653 100       56981 if (not $b & 0x80) {
    100          
    100          
    50          
39 53386         48991 $self->{Total}++;
40 53386         52134 next;
41             # 2-byte character (0b110...)
42             } elsif ($b >> 5 == 0b110) {
43 150         192 $self->{Code} = $b & 0b11111;
44 150         206 $self->{Left} = 1;
45             # 3-byte character (0b1110...)
46             } elsif ($b >> 4 == 0b1110) {
47 102         143 $self->{Code} = $b & 0b1111;
48 102         146 $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         32 $self->{Bad} = 1;
56 15         32 return TAKE_BAD;
57             }
58             } else {
59 349 100       508 if ($b >> 6 != 0b10) {
60 19         31 $self->{Bad} = 1;
61 19         45 return TAKE_BAD;
62             }
63 330         501 $self->{Code} = ($self->{Code} << 6) | ($b & 0b111111);
64 330         343 $self->{Left}--;
65 330 100       499 if ($self->{Left} == 0) {
66 233         276 $self->{Total}++;
67 233         246 $self->{MBs}++;
68 233         278 undef $self->{Code};
69 233 100       431 return TAKE_MUST_BE if $self->{MBs} >= $THRESHOLD;
70             }
71             }
72             }
73              
74 3343         4178 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 212 sub encoding { 'UTF-8' }
104              
105             1;