package Utf8Checker;

use strict;

#
# The Unicode Standard, Version 4.0, 3.10 Unicode Encoding Schemes,
# Table 3-6 "Well-formed UTF-8 Byte Sequences".
#

sub check {
  my ($s) = @_;

  my $ind = sub {
    my ($i) = @_;
    return ord(substr($s, $i, 1));
  };

  my $istrail = sub {
    my ($i) = @_;
    return &$ind($i) >= 0x80 && &$ind($i) <= 0xBF;
  };

  my $inseq = sub {
    my ($i, $f, $t) = @_;
    return &$ind($i) >= $f && &$ind($i) <= $t;
  };

  my $l = length($s);
  for(my $i = 0; $i < $l; ++$i) {
    if (&$ind($i) <= 0x7F) {
      next;
    } elsif (&$inseq($i, 0xC2, 0xDF)) {
      next if &$istrail(++$i);
    } elsif (&$ind($i) == 0xE0) {
      next if &$inseq(++$i, 0xA0, 0xBF) && &$istrail(++$i);
    } elsif (&$inseq($i, 0xE1, 0xEC)) {
      next if &$istrail(++$i) && &$istrail(++$i);
    } elsif (&$ind($i) == 0xED) {
      next if &$inseq(++$i, 0x80, 0x9F) && &$istrail(++$i);
    } elsif (&$inseq($i, 0xEE, 0xEF)) {
      next if &$istrail(++$i) && &$istrail(++$i);
    } elsif (&$ind($i) == 0xF0) {
      next if &$inseq(++$i, 0x90, 0xBF) && &$istrail(++$i) && &$istrail(++$i);
    } elsif (&$inseq($i, 0xF1, 0xF3)) {
      next if &$istrail(++$i) && &$istrail(++$i) && &$istrail(++$i);
    } elsif (&$ind($i) ==  0xF4) {
      next if &$inseq(++$i, 0x80, 0x8F) && &$istrail(++$i) && &$istrail(++$i);
    }
    return;
  }

  return 1;
}

# sub selftest {
#   my %a = ( 'blahblah' => 1,
#             'блахблах' => 0 );
#
#   foreach my $k (keys (%a)) {
#     print $k;
#     print "\n";
#     print "$k => " . check($k) . " (expected " . $a{$k} . ")\n";
#   }
# }

1;
