package Whatpm::Charset::DecodeHandle;
use strict;
## NOTE: |Message::Charset::Info| uses this module without calling
## the constructor.
my $XML_AUTO_CHARSET = q;
my $IANA_CHARSET = q;
my $PERL_CHARSET = q;
my $XML_CHARSET = q;
## ->create_decode_handle ($charset_uri, $byte_stream, $onerror)
sub create_decode_handle ($$$;$) {
my $csdef = $Whatpm::Charset::CharsetDef->{$_[1]};
my $obj = {
char_buffer => \(my $s = ''),
char_buffer_pos => 0,
character_queue => [],
filehandle => $_[2],
charset => $_[1],
byte_buffer => '',
onerror => $_[3] || sub {},
};
if ($csdef->{uri}->{$XML_AUTO_CHARSET} or
$obj->{charset} eq $XML_AUTO_CHARSET) {
my $b = ''; # UTF-8 w/o BOM
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
if (read $obj->{filehandle}, $b, 256) {
no warnings "substr";
no warnings "uninitialized";
if (substr ($b, 0, 1) eq "<") {
if (substr ($b, 1, 1) eq "?") { # ASCII8
if ($b =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $obj->{input_encoding});
$csdef = $Whatpm::Charset::CharsetDef->{$uri};
if (not $csdef->{ascii8} or $csdef->{bom_required}) {
$obj->{onerror}->(undef, 'charset-name-mismatch-error',
charset_uri => $uri,
charset_name => $obj->{input_encoding});
}
} else {
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
}
if (defined $csdef->{no_bom_variant}) {
$csdef = $Whatpm::Charset::CharsetDef->{$csdef->{no_bom_variant}};
}
} elsif (substr ($b, 1, 1) eq "\x00") {
if (substr ($b, 2, 2) eq "?\x00") { # ASCII16LE
my $c = $b; $c =~ tr/\x00//d;
if ($c =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $obj->{input_encoding});
$csdef = $Whatpm::Charset::CharsetDef->{$uri};
if (not $csdef->{ascii16} or $csdef->{ascii16be} or
$csdef->{bom_required}) {
$obj->{onerror}->(undef, 'charset-name-mismatch-error',
charset_uri => $uri,
charset_name => $obj->{input_encoding});
}
} else {
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
}
if (defined $csdef->{no_bom_variant16le}) {
$csdef = $Whatpm::Charset::CharsetDef->{$csdef->{no_bom_variant16le}};
}
} elsif (substr ($b, 2, 2) eq "\x00\x00") { # ASCII32Endian4321
my $c = $b; $c =~ tr/\x00//d;
if ($c =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $obj->{input_encoding});
$csdef = $Whatpm::Charset::CharsetDef->{$uri};
if (not $csdef->{ascii32} or
$csdef->{ascii32endian1234} or
$csdef->{ascii32endian2143} or
$csdef->{ascii32endian3412} or
$csdef->{bom_required}) {
$obj->{onerror}->(undef, 'charset-name-mismatch-error',
charset_uri => $uri,
charset_name => $obj->{input_encoding});
}
} else {
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
}
if (defined $csdef->{no_bom_variant32endian4321}) {
$csdef = $Whatpm::Charset::CharsetDef->{$csdef->{no_bom_variant32endian4321}};
}
}
}
} elsif (substr ($b, 0, 3) eq "\xEF\xBB\xBF") { # UTF8
$obj->{has_bom} = 1;
substr ($b, 0, 3) = '';
my $c = $b;
if ($c =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $obj->{input_encoding});
$csdef = $Whatpm::Charset::CharsetDef->{$uri};
if (not $csdef->{utf8_encoding_scheme} or
not $csdef->{bom_allowed}) {
$obj->{onerror}->(undef, 'charset-name-mismatch-error',
charset_uri => $uri,
charset_name => $obj->{input_encoding});
}
} else {
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
}
if (defined $csdef->{no_bom_variant}) {
$csdef = $Whatpm::Charset::CharsetDef->{$csdef->{no_bom_variant}};
}
} elsif (substr ($b, 0, 2) eq "\x00<") {
if (substr ($b, 2, 2) eq "\x00?") { # ASCII16BE
my $c = $b; $c =~ tr/\x00//d;
if ($c =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $obj->{input_encoding});
$csdef = $Whatpm::Charset::CharsetDef->{$uri};
if (not $csdef->{ascii16} or $csdef->{ascii16le} or
$csdef->{bom_required}) {
$obj->{onerror}->(undef, 'charset-name-mismatch-error',
charset_uri => $uri,
charset_name => $obj->{input_encoding});
}
} else {
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
}
if (defined $csdef->{no_bom_variant16be}) {
$csdef = $Whatpm::Charset::CharsetDef->{$csdef->{no_bom_variant16be}};
}
} elsif (substr ($b, 2, 2) eq "\x00\x00") { # ASCII32Endian3412
my $c = $b; $c =~ tr/\x00//d;
if ($c =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $obj->{input_encoding});
$csdef = $Whatpm::Charset::CharsetDef->{$uri};
if (not $csdef->{ascii32} or
$csdef->{ascii32endian1234} or
$csdef->{ascii32endian2143} or
$csdef->{ascii32endian4321} or
$csdef->{bom_required}) {
$obj->{onerror}->(undef, 'charset-name-mismatch-error',
charset_uri => $uri,
charset_name => $obj->{input_encoding});
}
} else {
$csdef = $Whatpm::Charset::CharsetDef->{$PERL_CHARSET.'utf-8'};
$obj->{input_encoding} = 'UTF-8';
}
if (defined $csdef->{no_bom_variant32endian3412}) {
$csdef = $Whatpm::Charset::CharsetDef->{$csdef->{no_bom_variant32endian3412}};
}
}
} elsif (substr ($b, 0, 2) eq "\xFE\xFF") {
if (substr ($b, 2, 2) eq "\x00<") { # ASCII16BE
$obj->{has_bom} = 1;
substr ($b, 0, 2) = '';
my $c = $b; $c =~ tr/\x00//d;
if ($c =~ /^<\?xml\s+(?:version\s*=\s*["'][^"']*["']\s*)?
encoding\s*=\s*["']([^"']*)/x) {
$obj->{input_encoding} = $1;
my $uri = name_to_uri (undef, 'xml', $