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', $