| 1 |
package Whatpm::Charset::DecodeHandle; |
package Whatpm::Charset::DecodeHandle; |
| 2 |
use strict; |
use strict; |
| 3 |
|
|
| 4 |
|
## NOTE: |Message::Charset::Info| uses this module without calling |
| 5 |
|
## the constructor. |
| 6 |
|
|
| 7 |
my $XML_AUTO_CHARSET = q<http://suika.fam.cx/www/2006/03/xml-entity/>; |
my $XML_AUTO_CHARSET = q<http://suika.fam.cx/www/2006/03/xml-entity/>; |
| 8 |
my $IANA_CHARSET = q<urn:x-suika-fam-cx:charset:>; |
my $IANA_CHARSET = q<urn:x-suika-fam-cx:charset:>; |
| 9 |
my $PERL_CHARSET = q<http://suika.fam.cx/~wakaba/archive/2004/dis/Charset/Perl.>; |
my $PERL_CHARSET = q<http://suika.fam.cx/~wakaba/archive/2004/dis/Charset/Perl.>; |
| 13 |
sub create_decode_handle ($$$;$) { |
sub create_decode_handle ($$$;$) { |
| 14 |
my $csdef = $Whatpm::Charset::CharsetDef->{$_[1]}; |
my $csdef = $Whatpm::Charset::CharsetDef->{$_[1]}; |
| 15 |
my $obj = { |
my $obj = { |
| 16 |
|
char_buffer => \(my $s = ''), |
| 17 |
character_queue => [], |
character_queue => [], |
| 18 |
filehandle => $_[2], |
filehandle => $_[2], |
| 19 |
charset => $_[1], |
charset => $_[1], |
| 549 |
my $pos = length $self->{buffer}; |
my $pos = length $self->{buffer}; |
| 550 |
my $r = $self->{filehandle}->read ($self->{buffer}, $_[1], $pos); |
my $r = $self->{filehandle}->read ($self->{buffer}, $_[1], $pos); |
| 551 |
substr ($_[0], $_[2]) = substr ($self->{buffer}, $pos); |
substr ($_[0], $_[2]) = substr ($self->{buffer}, $pos); |
| 552 |
|
## NOTE: This would do different behavior from Perl's standard |
| 553 |
|
## |read| when $pos points beyond the end of the string. |
| 554 |
return $r; |
return $r; |
| 555 |
} # read |
} # read |
| 556 |
|
|
| 565 |
sub close ($) { $_[0]->{filehandle}->close } |
sub close ($) { $_[0]->{filehandle}->close } |
| 566 |
|
|
| 567 |
sub getc ($) { |
sub getc ($) { |
| 568 |
|
my $c = ''; |
| 569 |
|
my $l = $_[0]->read ($c, 1); |
| 570 |
|
if ($l) { |
| 571 |
|
return $c; |
| 572 |
|
} else { |
| 573 |
|
return undef; |
| 574 |
|
} |
| 575 |
|
} # getc |
| 576 |
|
|
| 577 |
|
sub read ($$$;$) { |
| 578 |
my $self = $_[0]; |
my $self = $_[0]; |
| 579 |
return shift @{$self->{character_queue}} if @{$self->{character_queue}}; |
# $scalar = $_[1]; |
| 580 |
|
my $length = $_[2]; |
| 581 |
|
my $offset = $_[3] || 0; |
| 582 |
|
my $count = 0; |
| 583 |
|
my $eof; |
| 584 |
|
|
| 585 |
|
A: { |
| 586 |
|
return $count if $length < 1; |
| 587 |
|
|
| 588 |
|
if (my $l = length ${$self->{char_buffer}}) { |
| 589 |
|
if ($l >= $length) { |
| 590 |
|
substr ($_[1], $offset) = substr (${$self->{char_buffer}}, 0, $length); |
| 591 |
|
$count += $length; |
| 592 |
|
substr (${$self->{char_buffer}}, 0, $length) = ''; |
| 593 |
|
$length = 0; |
| 594 |
|
return $count; |
| 595 |
|
} else { |
| 596 |
|
substr ($_[1], $offset) = ${$self->{char_buffer}}; |
| 597 |
|
$count += $l; |
| 598 |
|
$length -= $l; |
| 599 |
|
${$self->{char_buffer}} = ''; |
| 600 |
|
} |
| 601 |
|
$offset = length $_[1]; |
| 602 |
|
} |
| 603 |
|
|
| 604 |
|
if ($eof) { |
| 605 |
|
return $count; |
| 606 |
|
} |
| 607 |
|
|
| 608 |
my $error; |
my $error; |
| 609 |
if ($self->{continue}) { |
if ($self->{continue}) { |
| 615 |
} |
} |
| 616 |
$self->{continue} = 0; |
$self->{continue} = 0; |
| 617 |
} elsif (512 > length $self->{byte_buffer}) { |
} elsif (512 > length $self->{byte_buffer}) { |
| 618 |
$self->{filehandle}->read ($self->{byte_buffer}, 256, |
if ($self->{filehandle}->read ($self->{byte_buffer}, 256, |
| 619 |
length $self->{byte_buffer}); |
length $self->{byte_buffer})) { |
| 620 |
|
# |
| 621 |
|
} else { |
| 622 |
|
$eof = 1; |
| 623 |
|
} |
| 624 |
} |
} |
| 625 |
|
|
|
my $r; |
|
| 626 |
unless ($error) { |
unless ($error) { |
| 627 |
if (not $self->{bom_checked}) { |
if (not $self->{bom_checked}) { |
| 628 |
if (defined $self->{bom_pattern}) { |
if (defined $self->{bom_pattern}) { |
| 637 |
$self->{byte_buffer}, |
$self->{byte_buffer}, |
| 638 |
Encode::FB_QUIET ()); |
Encode::FB_QUIET ()); |
| 639 |
if (length $string) { |
if (length $string) { |
| 640 |
push @{$self->{character_queue}}, split //, $string; |
$self->{char_buffer} = \$string; |
|
$r = shift @{$self->{character_queue}}; |
|
| 641 |
if (length $self->{byte_buffer}) { |
if (length $self->{byte_buffer}) { |
| 642 |
$self->{continue} = 1; |
$self->{continue} = 1; |
| 643 |
} |
} |
| 645 |
if (length $self->{byte_buffer}) { |
if (length $self->{byte_buffer}) { |
| 646 |
$error = 1; |
$error = 1; |
| 647 |
} else { |
} else { |
| 648 |
$r = undef; |
## NOTE: No further input |
| 649 |
|
redo A; |
| 650 |
} |
} |
| 651 |
} |
} |
| 652 |
} |
} |
| 653 |
|
|
| 654 |
if ($error) { |
if ($error) { |
| 655 |
$r = substr $self->{byte_buffer}, 0, 1, ''; |
my $r = substr $self->{byte_buffer}, 0, 1, ''; |
| 656 |
my $fallback = $self->{fallback}->{$r}; |
my $fallback = $self->{fallback}->{$r}; |
| 657 |
if (defined $fallback) { |
if (defined $fallback) { |
| 658 |
## NOTE: This is an HTML5 parse error. |
## NOTE: This is an HTML5 parse error. |
| 659 |
$self->{onerror}->($self, 'fallback-char-error', octets => \$r, |
$self->{onerror}->($self, 'fallback-char-error', octets => \$r, |
| 660 |
char => \$fallback, |
char => \$fallback, |
| 661 |
level => $self->{level}->{$self->{error_level}->{'fallback-char-error'}}); |
level => $self->{level}->{$self->{error_level}->{'fallback-char-error'}}); |
| 662 |
return $fallback; |
${$self->{char_buffer}} .= $fallback; |
| 663 |
} elsif (exists $self->{fallback}->{$r}) { |
} elsif (exists $self->{fallback}->{$r}) { |
| 664 |
## NOTE: This is an HTML5 parse error. In addition, the octet |
## NOTE: This is an HTML5 parse error. In addition, the octet |
| 665 |
## is not assigned with a character. |
## is not assigned with a character. |
| 666 |
$self->{onerror}->($self, 'fallback-unassigned-error', octets => \$r, |
$self->{onerror}->($self, 'fallback-unassigned-error', octets => \$r, |
| 667 |
level => $self->{level}->{$self->{error_level}->{'fallback-unassigned-error'}}); |
level => $self->{level}->{$self->{error_level}->{'fallback-unassigned-error'}}); |
| 668 |
|
${$self->{char_buffer}} .= $r; |
| 669 |
} else { |
} else { |
| 670 |
$self->{onerror}->($self, 'illegal-octets-error', octets => \$r, |
$self->{onerror}->($self, 'illegal-octets-error', octets => \$r, |
| 671 |
level => $self->{level}->{$self->{error_level}->{'illegal-octets-error'}}); |
level => $self->{level}->{$self->{error_level}->{'illegal-octets-error'}}); |
| 672 |
|
${$self->{char_buffer}} .= $r; |
| 673 |
} |
} |
| 674 |
} |
} |
| 675 |
|
|
| 676 |
return $r; |
redo A; |
| 677 |
|
} # A |
| 678 |
} # getc |
} # getc |
| 679 |
|
|
| 680 |
sub has_bom ($) { $_[0]->{has_bom} } |
sub has_bom ($) { $_[0]->{has_bom} } |
| 772 |
return $r; |
return $r; |
| 773 |
} # getc |
} # getc |
| 774 |
|
|
| 775 |
|
## TODO: This is not good for performance. Should be replaced |
| 776 |
|
## by read-centric implementation. |
| 777 |
|
sub read ($$$;$) { |
| 778 |
|
#my ($self, $scalar, $length, $offset) = @_; |
| 779 |
|
my $length = $_[2]; |
| 780 |
|
my $r = ''; |
| 781 |
|
while ($length > 0) { |
| 782 |
|
my $c = $_[0]->getc; |
| 783 |
|
last unless defined $c; |
| 784 |
|
$r .= $c; |
| 785 |
|
$length--; |
| 786 |
|
} |
| 787 |
|
substr ($_[1], $_[3]) = $r; |
| 788 |
|
## NOTE: This would do different thing from what Perl's |read| do |
| 789 |
|
## if $offset points beyond the end of the $scalar. |
| 790 |
|
return length $r; |
| 791 |
|
} # read |
| 792 |
|
|
| 793 |
package Whatpm::Charset::DecodeHandle::ISO2022JP; |
package Whatpm::Charset::DecodeHandle::ISO2022JP; |
| 794 |
push our @ISA, 'Whatpm::Charset::DecodeHandle::Encode'; |
push our @ISA, 'Whatpm::Charset::DecodeHandle::Encode'; |
| 795 |
|
|
| 910 |
return $r; |
return $r; |
| 911 |
} # getc |
} # getc |
| 912 |
|
|
| 913 |
|
## TODO: This is not good for performance. Should be replaced |
| 914 |
|
## by read-centric implementation. |
| 915 |
|
sub read ($$$;$) { |
| 916 |
|
#my ($self, $scalar, $length, $offset) = @_; |
| 917 |
|
my $length = $_[2]; |
| 918 |
|
my $r = ''; |
| 919 |
|
while ($length > 0) { |
| 920 |
|
my $c = $_[0]->getc; |
| 921 |
|
last unless defined $c; |
| 922 |
|
$r .= $c; |
| 923 |
|
$length--; |
| 924 |
|
} |
| 925 |
|
substr ($_[1], $_[3]) = $r; |
| 926 |
|
## NOTE: This would do different thing from what Perl's |read| do |
| 927 |
|
## if $offset points beyond the end of the $scalar. |
| 928 |
|
return length $r; |
| 929 |
|
} # read |
| 930 |
|
|
| 931 |
package Whatpm::Charset::DecodeHandle::ShiftJIS; |
package Whatpm::Charset::DecodeHandle::ShiftJIS; |
| 932 |
push our @ISA, 'Whatpm::Charset::DecodeHandle::Encode'; |
push our @ISA, 'Whatpm::Charset::DecodeHandle::Encode'; |
| 933 |
|
|
| 991 |
return $r; |
return $r; |
| 992 |
} # getc |
} # getc |
| 993 |
|
|
| 994 |
|
## TODO: This is not good for performance. Should be replaced |
| 995 |
|
## by read-centric implementation. |
| 996 |
|
sub read ($$$;$) { |
| 997 |
|
#my ($self, $scalar, $length, $offset) = @_; |
| 998 |
|
my $length = $_[2]; |
| 999 |
|
my $r = ''; |
| 1000 |
|
while ($length > 0) { |
| 1001 |
|
my $c = $_[0]->getc; |
| 1002 |
|
last unless defined $c; |
| 1003 |
|
$r .= $c; |
| 1004 |
|
$length--; |
| 1005 |
|
} |
| 1006 |
|
substr ($_[1], $_[3]) = $r; |
| 1007 |
|
## NOTE: This would do different thing from what Perl's |read| do |
| 1008 |
|
## if $offset points beyond the end of the $scalar. |
| 1009 |
|
return length $r; |
| 1010 |
|
} # read |
| 1011 |
|
|
| 1012 |
$Whatpm::Charset::CharsetDef->{'urn:x-suika-fam-cx:charset:us-ascii'} = |
$Whatpm::Charset::CharsetDef->{'urn:x-suika-fam-cx:charset:us-ascii'} = |
| 1013 |
$Whatpm::Charset::CharsetDef->{'urn:x-suika-fam-cx:charset:us'} = |
$Whatpm::Charset::CharsetDef->{'urn:x-suika-fam-cx:charset:us'} = |
| 1014 |
$Whatpm::Charset::CharsetDef->{'urn:x-suika-fam-cx:charset:iso646-us'} = |
$Whatpm::Charset::CharsetDef->{'urn:x-suika-fam-cx:charset:iso646-us'} = |