diff options
Diffstat (limited to 'intl/unicharutil')
22 files changed, 4424 insertions, 0 deletions
diff --git a/intl/unicharutil/moz.build b/intl/unicharutil/moz.build new file mode 100644 index 0000000000..ec7b335f9d --- /dev/null +++ b/intl/unicharutil/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +DIRS += ["util"] + +EXPORTS += [ + "nsUGenCategory.h", +] + +FINAL_LIBRARY = "xul" diff --git a/intl/unicharutil/nsUGenCategory.h b/intl/unicharutil/nsUGenCategory.h new file mode 100644 index 0000000000..8506c39820 --- /dev/null +++ b/intl/unicharutil/nsUGenCategory.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsUGenCategory_h +#define nsUGenCategory_h + +/** + * Read http://unicode.org/reports/tr44/#General_Category_Values + * for the detailed definition of the following categories + */ +enum class nsUGenCategory { + kUndefined = 0, + kMark = 1, // Mn, Mc, and Me + kNumber = 2, // Nd, Nl, and No + kSeparator = 3, // Zs, Zl, and Zp + kOther = 4, // Cc, Cf, Cs, Co, and Cn + kLetter = 5, // Lu, Ll, Lt, Lm, and Lo + kPunctuation = 6, // Pc, Pd, Ps, Pe, Pi, Pf, and Po + kSymbol = 7 // Sm, Sc, Sk, and So +}; + +#endif // nsUGenCategory_h diff --git a/intl/unicharutil/tools/README.txt b/intl/unicharutil/tools/README.txt new file mode 100644 index 0000000000..7295547f11 --- /dev/null +++ b/intl/unicharutil/tools/README.txt @@ -0,0 +1,3 @@ +Instructions for using these tools are on the Mozilla Wiki. + +https://wiki.mozilla.org/I18n:Updating_Unicode_version diff --git a/intl/unicharutil/tools/genSpecialCasingData.pl b/intl/unicharutil/tools/genSpecialCasingData.pl new file mode 100755 index 0000000000..9800688683 --- /dev/null +++ b/intl/unicharutil/tools/genSpecialCasingData.pl @@ -0,0 +1,309 @@ +#!/usr/bin/env perl + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +# This tool is used to extract "special" (one-to-many) case mappings +# into a form that can be used by nsTextRunTransformations. + +use strict; + +if ($#ARGV != 1) { + print <<__EOT; +# Run this tool using a command line of the form +# +# perl genSpecialCasingData.pl UnicodeData.txt SpecialCasing.txt +# +# The nsSpecialCasingData.cpp file will be written to standard output. +# +# This tool will also write up-to-date versions of the test files +# all-{upper,lower,title}.html +# and corresponding -ref files in the current directory. +# +__EOT + exit 0; +} + +my %allLower; +my %allUpper; +my %allTitle; +my %compositions; +my %gc; +open FH, "< $ARGV[0]" or die "can't open $ARGV[0] (should be UnicodeData.txt)\n"; +while (<FH>) { + chomp; + my @fields = split /;/; + next if ($fields[1] =~ /</); # ignore ranges etc + my $usv = hex "0x$fields[0]"; + $allUpper{$usv} = $fields[12] if $fields[12] ne ''; + $allLower{$usv} = $fields[13] if $fields[13] ne ''; + $allTitle{$usv} = $fields[14] if $fields[14] ne ''; + $gc{$usv} = $fields[2]; + # we only care about non-singleton canonical decomps + my $decomp = $fields[5]; + next if $decomp eq '' or $decomp =~ /</ or not $decomp =~ / /; + $compositions{$decomp} = sprintf("%04X", $usv); +} +close FH; + +my %specialLower; +my %specialUpper; +my %specialTitle; +my %charName; +my @headerLines; +open FH, "< $ARGV[1]" or die "can't open $ARGV[1] (should be SpecialCasing.txt)\n"; +while (<FH>) { + chomp; + m/#\s*(.+)$/; + my $comment = $1; + if ($comment =~ /^(SpecialCasing-|Date:)/) { + push @headerLines, $comment; + next; + } + s/#.*//; + s/;\s*$//; + next if $_ eq ''; + my @fields = split /; */; + next unless (scalar @fields) == 4; + my $usv = hex "0x$fields[0]"; + addIfSpecial(\%specialLower, $usv, $fields[1]); + addIfSpecial(\%specialTitle, $usv, $fields[2]); + addIfSpecial(\%specialUpper, $usv, $fields[3]); + $charName{$usv} = $comment; +} +close FH; + +print <<__END__; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Auto-generated from files in the Unicode Character Database + by genSpecialCasingData.pl - do not edit! */ + +#include "nsSpecialCasingData.h" +#include "mozilla/ArrayUtils.h" // for ArrayLength +#include <stdlib.h> // for bsearch + +__END__ +map { print "/* $_ */\n" } @headerLines; + +print <<__END__; + +using mozilla::unicode::MultiCharMapping; + +__END__ + +printMappings('Lower', \%specialLower); +printMappings('Upper', \%specialUpper); +printMappings('Title', \%specialTitle); + +print <<__END__; +static int CompareMCM(const void* aKey, const void* aElement) +{ + const uint32_t ch = *static_cast<const uint32_t*>(aKey); + const MultiCharMapping* mcm = static_cast<const MultiCharMapping*>(aElement); + return int(ch) - int(mcm->mOriginalChar); +} + +#define MAKE_SPECIAL_CASE_ACCESSOR(which) \\ + const MultiCharMapping* \\ + Special##which(uint32_t aChar) \\ + { \\ + const void* p = bsearch(&aChar, CaseSpecials_##which, \\ + mozilla::ArrayLength(CaseSpecials_##which), \\ + sizeof(MultiCharMapping), CompareMCM); \\ + return static_cast<const MultiCharMapping*>(p); \\ + } + +namespace mozilla { +namespace unicode { + +MAKE_SPECIAL_CASE_ACCESSOR(Lower) +MAKE_SPECIAL_CASE_ACCESSOR(Upper) +MAKE_SPECIAL_CASE_ACCESSOR(Title) + +} // namespace unicode +} // namespace mozilla +__END__ + +addSpecialsTo(\%allLower, \%specialLower); +addSpecialsTo(\%allUpper, \%specialUpper); +addSpecialsTo(\%allTitle, \%specialTitle); + +my $testFont = "../fonts/dejavu-sans/DejaVuSans.ttf"; +genTest('lower', \%allLower); +genTest('upper', \%allUpper); +genTitleTest(); + +sub printMappings { + my ($whichMapping, $hash) = @_; + print "static const MultiCharMapping CaseSpecials_${whichMapping}[] = {\n"; + foreach my $key (sort { $a <=> $b } keys %$hash) { + my @chars = split(/ /, $hash->{$key}); + printf " { 0x%04x, {0x%04x, 0x%04x, 0x%04x} }, // %s\n", $key, + hex "0x0$chars[0]", hex "0x0$chars[1]", hex "0x0$chars[2]", + "$charName{$key}"; + } + print "};\n\n"; +}; + +sub addIfSpecial { + my ($hash, $usv, $mapping) = @_; + return unless $mapping =~ / /; + # only do compositions that start with the initial char + foreach (keys %compositions) { + $mapping =~ s/^$_/$compositions{$_}/; + } + $hash->{$usv} = $mapping; +}; + +sub addSpecialsTo { + my ($hash, $specials) = @_; + foreach my $key (keys %$specials) { + $hash->{$key} = $specials->{$key}; + } +}; + +sub genTest { + my ($whichMapping, $hash) = @_; + open OUT, "> all-$whichMapping.html"; + print OUT <<__END__; +<!DOCTYPE html> +<!-- GENERATED FILE, DO NOT EDIT --> +<html> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <style type="text/css"> + \@font-face { font-family: foo; src: url($testFont); } + p { font-family: foo; font-size: 12px; text-transform: ${whichMapping}case; } + </style> + </head> + <body> + <p> +__END__ + foreach my $key (sort { $a <=> $b } keys %$hash) { + # Bug 1476304: we exclude Georgian letters U+10D0..10FF because of lack + # of widespread font support for the corresponding Mtavruli characters + # at this time (July 2018). + # This condition is to be removed once the major platforms ship with + # fonts that support U+1C90..1CBF. + my $skippedGeorgian = $whichMapping eq "upper" && $key >= 0x10D0 && $key <= 0x10FF; + print OUT "<!-- " if $skippedGeorgian; + printf OUT "&#x%04X;", $key; + print OUT " -->" if $skippedGeorgian; + print OUT " <!-- $charName{$key} -->" if exists $charName{$key}; + print OUT " <!-- Temporarily skipped, see bug 1476304. -->" if $skippedGeorgian; + print OUT "\n"; + } + print OUT <<__END__; + </p> + </body> +</html> +__END__ + close OUT; + + open OUT, "> all-$whichMapping-ref.html"; + print OUT <<__END__; +<!DOCTYPE html> +<!-- GENERATED FILE, DO NOT EDIT --> +<html> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <style type="text/css"> + \@font-face { font-family: foo; src: url($testFont); } + p { font-family: foo; font-size: 12px; } + </style> + </head> + <body> + <p> +__END__ + foreach my $key (sort { $a <=> $b } keys %$hash) { + # Bug 1476304: we exclude Georgian letters U+10D0..10FF because of lack + # of widespread font support for the corresponding Mtavruli characters + # at this time (July 2018). + # This condition is to be removed once the major platforms ship with + # fonts that support U+1C90..1CBF. + my $skippedGeorgian = $whichMapping eq "upper" && $key >= 0x10D0 && $key <= 0x10FF; + print OUT "<!-- " if $skippedGeorgian; + print OUT join('', map { sprintf("&#x%s;", $_) } split(/ /, $hash->{$key})); + print OUT " -->" if $skippedGeorgian; + print OUT " <!-- $charName{$key} -->" if exists $charName{$key}; + print OUT " <!-- Temporarily skipped, see bug 1476304. -->" if $skippedGeorgian; + print OUT "\n"; + } + print OUT <<__END__; + </p> + </body> +</html> +__END__ + close OUT; +}; + +sub genTitleTest { + open OUT, "> all-title.html"; + print OUT <<__END__; +<!DOCTYPE html> +<!-- GENERATED FILE, DO NOT EDIT --> +<html> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <style type="text/css"> + \@font-face { font-family: foo; src: url($testFont); } + p { font-family: foo; text-transform: capitalize; } + </style> + </head> + <body> + <p> +__END__ + foreach my $key (sort { $a <=> $b } keys %allTitle) { + printf OUT "&#x%04X;x", $key; + print OUT " <!-- $charName{$key} -->" if exists $charName{$key}; + print OUT "\n"; + } + print OUT <<__END__; + </p> + </body> +</html> +__END__ + close OUT; + + open OUT, "> all-title-ref.html"; + print OUT <<__END__; +<!DOCTYPE html> +<!-- GENERATED FILE, DO NOT EDIT --> +<html> + <head> + <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <style type="text/css"> + \@font-face { font-family: foo; src: url($testFont); } + p { font-family: foo; } + </style> + </head> + <body> + <p> +__END__ + foreach my $key (sort { $a <=> $b } keys %allTitle) { + # capitalize is only applied to characters with GC=L* or N*... + if ($gc{$key} =~ /^[LN]/) { + # ...and those that are already uppercase are not transformed + if (exists $allUpper{$key}) { + print OUT join('', map { sprintf("&#x%s;", $_) } split(/ /, $allTitle{$key})); + } else { + printf OUT "&#x%04X;", $key; + } + print OUT "x"; + } else { + printf OUT "&#x%04X;X", $key; + } + print OUT " <!-- $charName{$key} -->" if exists $charName{$key}; + print OUT "\n"; + } + print OUT <<__END__; + </p> + </body> +</html> +__END__ + close OUT; +}; diff --git a/intl/unicharutil/tools/genUnicodePropertyData.pl b/intl/unicharutil/tools/genUnicodePropertyData.pl new file mode 100755 index 0000000000..6b2190e4d2 --- /dev/null +++ b/intl/unicharutil/tools/genUnicodePropertyData.pl @@ -0,0 +1,508 @@ +#!/usr/bin/env perl + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# This tool is used to prepare lookup tables of Unicode character properties +# needed by gfx code to support text shaping operations. The properties are +# read from the Unicode Character Database and compiled into multi-level arrays +# for efficient lookup. +# +# Note that for most properties, we now rely on ICU; this tool and the tables +# it generates are used only for a couple of properties not readily exposed +# via ICU APIs. +# +# To regenerate the tables in nsUnicodePropertyData.cpp: +# +# (1) Download the current Unicode data files from +# +# https://www.unicode.org/Public/UNIDATA/ +# +# NB: not all the files are actually needed; currently, we require +# - UnicodeData.txt +# - ReadMe.txt (to record version/date of the UCD) +# - Unihan_Variants.txt (from Unihan.zip) +# though this may change if we find a need for additional properties. +# +# The Unicode data files listed above should be together in one directory. +# +# We also require the file +# https://www.unicode.org/Public/security/latest/IdentifierStatus.txt +# This file should be in a sub-directory "security" immediately below the +# directory containing the other Unicode data files. +# +# We also require the latest data file for UTR50, currently revision-17: +# https://www.unicode.org/Public/vertical/revision-17/VerticalOrientation-17.txt +# This file should be in a sub-directory "vertical" immediately below the +# directory containing the other Unicode data files. +# +# +# (2) Run this tool using a command line of the form +# +# perl genUnicodePropertyData.pl \ +# /path/to/icu/common/unicode \ +# /path/to/UCD-directory +# +# This will generate (or overwrite!) the files +# +# nsUnicodePropertyData.cpp +# nsUnicodeScriptCodes.h +# +# in the current directory. + +use strict; +use List::Util qw(first); + +if ($#ARGV != 1) { + print <<__EOT; +# Run this tool using a command line of the form +# +# perl genUnicodePropertyData.pl \\ +# /path/to/icu/common/unicode \\ +# /path/to/UCD-directory +# +# where icu/common/unicode is the directory containing ICU 'common' headers, +# and UCD-directory is a directory containing the current Unicode Character +# Database files (UnicodeData.txt, etc), available from +# https://www.unicode.org/Public/UNIDATA/, with additional resources as +# detailed in the source comments. +# +# This will generate (or overwrite!) the files +# +# nsUnicodePropertyData.cpp +# nsUnicodeScriptCodes.h +# +# in the current directory. +__EOT + exit 0; +} + +my $ICU = $ARGV[0]; +my $UNICODE = $ARGV[1]; + +my @scriptCodeToName; +my @idtype; + +my $sc = -1; + +sub readIcuHeader +{ + my $file = shift; + open FH, "< $ICU/$file" or die "can't open ICU header $ICU/$file\n"; + while (<FH>) { + # adjust for ICU vs UCD naming discrepancies + s/LANNA/TAI_THAM/; + s/MEITEI_MAYEK/MEETEI_MAYEK/; + s/ORKHON/OLD_TURKIC/; + s/MENDE/MENDE_KIKAKUI/; + s/SIGN_WRITING/SIGNWRITING/; + if (m|USCRIPT_([A-Z_]+)\s*=\s*([0-9]+),\s*/\*\s*([A-Z][a-z]{3})\s*\*/|) { + $sc = $2; + $scriptCodeToName[$sc] = $1; + } + } + close FH; +} + +&readIcuHeader("uscript.h"); + +die "didn't find ICU script codes\n" if $sc == -1; + +# We don't currently store these values; %idType is used only to check that +# properties listed in the IdentifierType.txt file are recognized. We record +# only the %mappedIdType values that are used by nsIDNService::isLabelSafe. +# In practice, it would be sufficient for us to read only the last value in +# IdentifierType.txt, but we check that all values are known so that we'll get +# a warning if future updates introduce new ones, and can consider whether +# they need to be taken into account. +my %idType = ( + "Not_Character" => 0, + "Recommended" => 1, + "Inclusion" => 2, + "Uncommon_Use" => 3, + "Technical" => 4, + "Obsolete" => 5, + "Aspirational" => 6, + "Limited_Use" => 7, + "Exclusion" => 8, + "Not_XID" => 9, + "Not_NFKC" => 10, + "Default_Ignorable" => 11, + "Deprecated" => 12 +); + +# These match the IdentifierType enum in nsUnicodeProperties.h. +my %mappedIdType = ( + "Restricted" => 0, + "Allowed" => 1 +); + +my %verticalOrientationCode = ( + 'U' => 0, # U - Upright, the same orientation as in the code charts + 'R' => 1, # R - Rotated 90 degrees clockwise compared to the code charts + 'Tu' => 2, # Tu - Transformed typographically, with fallback to Upright + 'Tr' => 3 # Tr - Transformed typographically, with fallback to Rotated +); + +# initialize default properties +my @hanVariant; +my @fullWidth; +my @fullWidthInverse; +my @verticalOrientation; +for (my $i = 0; $i < 0x110000; ++$i) { + $hanVariant[$i] = 0; + $fullWidth[$i] = 0; + $fullWidthInverse[$i] = 0; + $verticalOrientation[$i] = 1; # default for unlisted codepoints is 'R' +} + +# read ReadMe.txt +my @versionInfo; +open FH, "< $UNICODE/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n"; +while (<FH>) { + chomp; + push @versionInfo, $_; +} +close FH; + +# read UnicodeData.txt +open FH, "< $UNICODE/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n"; +while (<FH>) { + chomp; + my @fields = split /;/; + if ($fields[1] =~ /First/) { + my $first = hex "0x$fields[0]"; + $_ = <FH>; + @fields = split /;/; + if ($fields[1] =~ /Last/) { + my $last = hex "0x$fields[0]"; + do { + if ($fields[1] =~ /CJK/) { + @hanVariant[$first] = 3; + } + $first++; + } while ($first <= $last); + } else { + die "didn't find Last code for range!\n"; + } + } else { + my $usv = hex "0x$fields[0]"; + if ($fields[1] =~ /CJK/) { + @hanVariant[$usv] = 3; + } + if ($fields[5] =~ /^<narrow>/) { + my $wideChar = hex(substr($fields[5], 9)); + die "didn't expect supplementary-plane values here" if $usv > 0xffff || $wideChar > 0xffff; + $fullWidth[$usv] = $wideChar; + $fullWidthInverse[$wideChar] = $usv; + } + elsif ($fields[5] =~ /^<wide>/) { + my $narrowChar = hex(substr($fields[5], 7)); + die "didn't expect supplementary-plane values here" if $usv > 0xffff || $narrowChar > 0xffff; + $fullWidth[$narrowChar] = $usv; + $fullWidthInverse[$usv] = $narrowChar; + } + } +} +close FH; + +# read IdentifierStatus.txt +open FH, "< $UNICODE/security/IdentifierStatus.txt" or die "can't open UCD file IdentifierStatus.txt\n"; +push @versionInfo, ""; +while (<FH>) { + chomp; + s/\xef\xbb\xbf//; + push @versionInfo, $_; + last if /Date:/; +} +while (<FH>) { + if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s+;\s+Allowed/) { + my $start = hex "0x$1"; + my $end = (defined $2) ? hex "0x$2" : $start; + for (my $i = $start; $i <= $end; ++$i) { + $idtype[$i] = $mappedIdType{'Allowed'}; + } + } +} +close FH; + +open FH, "< $UNICODE/Unihan_Variants.txt" or die "can't open UCD file Unihan_Variants.txt (from Unihan.zip)\n"; +push @versionInfo, ""; +while (<FH>) { + chomp; + push @versionInfo, $_; + last if /Date:/; +} +my $savedusv = 0; +my $hasTC = 0; +my $hasSC = 0; +while (<FH>) { + chomp; + if (m/U\+([0-9A-F]{4,6})\s+k([^ ]+)Variant/) { + my $usv = hex "0x$1"; + if ($usv != $savedusv) { + unless ($savedusv == 0) { + if ($hasTC && !$hasSC) { + $hanVariant[$savedusv] = 1; + } elsif (!$hasTC && $hasSC) { + $hanVariant[$savedusv] = 2; + } + } + $savedusv = $usv; + $hasTC = 0; + $hasSC = 0; + } + if ($2 eq "Traditional") { + $hasTC = 1; + } + if ($2 eq "Simplified") { + $hasSC = 1; + } + } +} +close FH; + +# read VerticalOrientation-17.txt +open FH, "< $UNICODE/vertical/VerticalOrientation-17.txt" or die "can't open UTR50 data file VerticalOrientation-17.txt\n"; +push @versionInfo, ""; +while (<FH>) { + chomp; + push @versionInfo, $_; + last if /Date:/; +} +while (<FH>) { + chomp; + s/#.*//; + if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s*;\s*([^ ]+)/) { + my $vo = $3; + warn "unknown Vertical_Orientation code $vo" + unless exists $verticalOrientationCode{$vo}; + $vo = $verticalOrientationCode{$vo}; + my $start = hex "0x$1"; + my $end = (defined $2) ? hex "0x$2" : $start; + for (my $i = $start; $i <= $end; ++$i) { + $verticalOrientation[$i] = $vo; + } + } +} +close FH; + +my $timestamp = gmtime(); + +open DATA_TABLES, "> nsUnicodePropertyData.cpp" or die "unable to open nsUnicodePropertyData.cpp for output"; + +my $licenseBlock = q[ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Derived from the Unicode Character Database by genUnicodePropertyData.pl + * + * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html + */ +]; + +my $versionInfo = join("\n", @versionInfo); + +print DATA_TABLES <<__END; +$licenseBlock +/* + * Created on $timestamp from UCD data files with version info: + * + +$versionInfo + + * + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ + +#include <stdint.h> +#include "harfbuzz/hb.h" + +__END + +open HEADER, "> nsUnicodeScriptCodes.h" or die "unable to open nsUnicodeScriptCodes.h for output"; + +print HEADER <<__END; +$licenseBlock +/* + * Created on $timestamp from UCD data files with version info: + * + +$versionInfo + + * + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ + +#ifndef NS_UNICODE_SCRIPT_CODES +#define NS_UNICODE_SCRIPT_CODES + +__END + +our $totalData = 0; + +sub sprintCharProps2_short +{ + my $usv = shift; + return sprintf("{%d,%d},", + $verticalOrientation[$usv], $idtype[$usv]); +} +my $type = q| +struct nsCharProps2 { + // Currently only 4 bits are defined here, so 4 more could be added without + // affecting the storage requirements for this struct. Or we could pack two + // records per byte, at the cost of a slightly more complex accessor. + unsigned char mVertOrient:2; + unsigned char mIdType:2; +}; +|; +&genTables("CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1); + +sub sprintHanVariants +{ + my $baseUsv = shift; + my $varShift = 0; + my $val = 0; + while ($varShift < 8) { + $val |= $hanVariant[$baseUsv++] << $varShift; + $varShift += 2; + } + return sprintf("0x%02x,", $val); +} +## Han Variant data currently unused but may be needed in future, see bug 857481 +## &genTables("HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4); + +sub sprintFullWidth +{ + my $usv = shift; + return sprintf("0x%04x,", $fullWidth[$usv]); +} +&genTables("FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1); + +sub sprintFullWidthInverse +{ + my $usv = shift; + return sprintf("0x%04x,", $fullWidthInverse[$usv]); +} +&genTables("FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1); + +print STDERR "Total data = $totalData\n"; + +sub genTables +{ + my ($prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_; + + if ($typedef ne '') { + print HEADER "$typedef\n"; + } + + print DATA_TABLES "#define k${prefix}MaxPlane $maxPlane\n"; + print DATA_TABLES "#define k${prefix}IndexBits $indexBits\n"; + print DATA_TABLES "#define k${prefix}CharBits $charBits\n"; + + my $indexLen = 1 << $indexBits; + my $charsPerPage = 1 << $charBits; + my %charIndex = (); + my %pageMapIndex = (); + my @pageMap = (); + my @char = (); + + my $planeMap = "\x00" x $maxPlane; + foreach my $plane (0 .. $maxPlane) { + my $pageMap = "\x00" x $indexLen * 2; + foreach my $page (0 .. $indexLen - 1) { + my $charValues = ""; + for (my $ch = 0; $ch < $charsPerPage; $ch += $charsPerEntry) { + my $usv = $plane * 0x10000 + $page * $charsPerPage + $ch; + $charValues .= &$func($usv); + } + chop $charValues; + + unless (exists $charIndex{$charValues}) { + $charIndex{$charValues} = scalar keys %charIndex; + $char[$charIndex{$charValues}] = $charValues; + } + substr($pageMap, $page * 2, 2) = pack('S', $charIndex{$charValues}); + } + + unless (exists $pageMapIndex{$pageMap}) { + $pageMapIndex{$pageMap} = scalar keys %pageMapIndex; + $pageMap[$pageMapIndex{$pageMap}] = $pageMap; + } + if ($plane > 0) { + substr($planeMap, $plane - 1, 1) = pack('C', $pageMapIndex{$pageMap}); + } + } + + if ($maxPlane) { + print DATA_TABLES "static const uint8_t s${prefix}Planes[$maxPlane] = {"; + print DATA_TABLES join(',', map { sprintf("%d", $_) } unpack('C*', $planeMap)); + print DATA_TABLES "};\n\n"; + } + + my $chCount = scalar @char; + my $pmBits = $chCount > 255 ? 16 : 8; + my $pmCount = scalar @pageMap; + if ($maxPlane == 0) { + die "there should only be one pageMap entry!" if $pmCount > 1; + print DATA_TABLES "static const uint${pmBits}_t s${prefix}Pages[$indexLen] = {\n"; + } else { + print DATA_TABLES "static const uint${pmBits}_t s${prefix}Pages[$pmCount][$indexLen] = {\n"; + } + for (my $i = 0; $i < scalar @pageMap; ++$i) { + print DATA_TABLES $maxPlane > 0 ? " {" : " "; + print DATA_TABLES join(',', map { sprintf("%d", $_) } unpack('S*', $pageMap[$i])); + print DATA_TABLES $maxPlane > 0 ? ($i < $#pageMap ? "},\n" : "}\n") : "\n"; + } + print DATA_TABLES "};\n\n"; + + my $pageLen = $charsPerPage / $charsPerEntry; + print DATA_TABLES "static const $type s${prefix}Values[$chCount][$pageLen] = {\n"; + for (my $i = 0; $i < scalar @char; ++$i) { + print DATA_TABLES " {"; + print DATA_TABLES $char[$i]; + print DATA_TABLES $i < $#char ? "},\n" : "}\n"; + } + print DATA_TABLES "};\n"; + + my $dataSize = $pmCount * $indexLen * $pmBits/8 + + $chCount * $pageLen * $bytesPerEntry + + $maxPlane; + $totalData += $dataSize; + + print STDERR "Data for $prefix = $dataSize\n"; +} + +print DATA_TABLES <<__END; +/* + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ +__END + +close DATA_TABLES; + +print HEADER "namespace mozilla {\n"; +print HEADER "namespace unicode {\n"; +print HEADER "enum class Script : int16_t {\n"; +for (my $i = 0; $i < scalar @scriptCodeToName; ++$i) { + print HEADER " ", $scriptCodeToName[$i], " = ", $i, ",\n"; +} +print HEADER "\n NUM_SCRIPT_CODES = ", scalar @scriptCodeToName, ",\n"; +print HEADER "\n INVALID = -1\n"; +print HEADER "};\n"; +print HEADER "} // namespace unicode\n"; +print HEADER "} // namespace mozilla\n\n"; + +print HEADER <<__END; +#endif +/* + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ +__END + +close HEADER; + diff --git a/intl/unicharutil/util/GreekCasing.cpp b/intl/unicharutil/util/GreekCasing.cpp new file mode 100644 index 0000000000..5c7e7d506e --- /dev/null +++ b/intl/unicharutil/util/GreekCasing.cpp @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GreekCasing.h" +#include "nsUnicharUtils.h" +#include "nsUnicodeProperties.h" + +// Custom uppercase mapping for Greek; see bug 307039 for details +#define GREEK_LOWER_ALPHA 0x03B1 +#define GREEK_LOWER_ALPHA_TONOS 0x03AC +#define GREEK_LOWER_ALPHA_OXIA 0x1F71 +#define GREEK_LOWER_EPSILON 0x03B5 +#define GREEK_LOWER_EPSILON_TONOS 0x03AD +#define GREEK_LOWER_EPSILON_OXIA 0x1F73 +#define GREEK_LOWER_ETA 0x03B7 +#define GREEK_LOWER_ETA_TONOS 0x03AE +#define GREEK_LOWER_ETA_OXIA 0x1F75 +#define GREEK_LOWER_IOTA 0x03B9 +#define GREEK_LOWER_IOTA_TONOS 0x03AF +#define GREEK_LOWER_IOTA_OXIA 0x1F77 +#define GREEK_LOWER_IOTA_DIALYTIKA 0x03CA +#define GREEK_LOWER_IOTA_DIALYTIKA_TONOS 0x0390 +#define GREEK_LOWER_IOTA_DIALYTIKA_OXIA 0x1FD3 +#define GREEK_LOWER_OMICRON 0x03BF +#define GREEK_LOWER_OMICRON_TONOS 0x03CC +#define GREEK_LOWER_OMICRON_OXIA 0x1F79 +#define GREEK_LOWER_UPSILON 0x03C5 +#define GREEK_LOWER_UPSILON_TONOS 0x03CD +#define GREEK_LOWER_UPSILON_OXIA 0x1F7B +#define GREEK_LOWER_UPSILON_DIALYTIKA 0x03CB +#define GREEK_LOWER_UPSILON_DIALYTIKA_TONOS 0x03B0 +#define GREEK_LOWER_UPSILON_DIALYTIKA_OXIA 0x1FE3 +#define GREEK_LOWER_OMEGA 0x03C9 +#define GREEK_LOWER_OMEGA_TONOS 0x03CE +#define GREEK_LOWER_OMEGA_OXIA 0x1F7D +#define GREEK_UPPER_ALPHA 0x0391 +#define GREEK_UPPER_EPSILON 0x0395 +#define GREEK_UPPER_ETA 0x0397 +#define GREEK_UPPER_IOTA 0x0399 +#define GREEK_UPPER_IOTA_DIALYTIKA 0x03AA +#define GREEK_UPPER_OMICRON 0x039F +#define GREEK_UPPER_UPSILON 0x03A5 +#define GREEK_UPPER_UPSILON_DIALYTIKA 0x03AB +#define GREEK_UPPER_OMEGA 0x03A9 +#define GREEK_UPPER_ALPHA_TONOS 0x0386 +#define GREEK_UPPER_ALPHA_OXIA 0x1FBB +#define GREEK_UPPER_EPSILON_TONOS 0x0388 +#define GREEK_UPPER_EPSILON_OXIA 0x1FC9 +#define GREEK_UPPER_ETA_TONOS 0x0389 +#define GREEK_UPPER_ETA_OXIA 0x1FCB +#define GREEK_UPPER_IOTA_TONOS 0x038A +#define GREEK_UPPER_IOTA_OXIA 0x1FDB +#define GREEK_UPPER_OMICRON_TONOS 0x038C +#define GREEK_UPPER_OMICRON_OXIA 0x1FF9 +#define GREEK_UPPER_UPSILON_TONOS 0x038E +#define GREEK_UPPER_UPSILON_OXIA 0x1FEB +#define GREEK_UPPER_OMEGA_TONOS 0x038F +#define GREEK_UPPER_OMEGA_OXIA 0x1FFB +#define COMBINING_ACUTE_ACCENT 0x0301 +#define COMBINING_DIAERESIS 0x0308 +#define COMBINING_ACUTE_TONE_MARK 0x0341 +#define COMBINING_GREEK_DIALYTIKA_TONOS 0x0344 + +namespace mozilla { + +uint32_t GreekCasing::UpperCase(uint32_t aCh, GreekCasing::State& aState, + bool& aMarkEtaPos, bool& aUpdateMarkedEta) { + aMarkEtaPos = false; + aUpdateMarkedEta = false; + + uint8_t category = unicode::GetGeneralCategory(aCh); + + if (aState == kEtaAccMarked) { + switch (category) { + case HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK: + aUpdateMarkedEta = true; + break; + default: + break; + } + aState = kEtaAcc; + } + + switch (aCh) { + case GREEK_UPPER_ALPHA: + case GREEK_LOWER_ALPHA: + aState = kAlpha; + return GREEK_UPPER_ALPHA; + + case GREEK_UPPER_EPSILON: + case GREEK_LOWER_EPSILON: + aState = kEpsilon; + return GREEK_UPPER_EPSILON; + + case GREEK_UPPER_ETA: + case GREEK_LOWER_ETA: + aState = kEta; + return GREEK_UPPER_ETA; + + case GREEK_UPPER_IOTA: + aState = kIota; + return GREEK_UPPER_IOTA; + + case GREEK_UPPER_OMICRON: + case GREEK_LOWER_OMICRON: + aState = kOmicron; + return GREEK_UPPER_OMICRON; + + case GREEK_UPPER_UPSILON: + switch (aState) { + case kOmicron: + aState = kOmicronUpsilon; + break; + default: + aState = kUpsilon; + break; + } + return GREEK_UPPER_UPSILON; + + case GREEK_UPPER_OMEGA: + case GREEK_LOWER_OMEGA: + aState = kOmega; + return GREEK_UPPER_OMEGA; + + // iota and upsilon may be the second vowel of a diphthong + case GREEK_LOWER_IOTA: + switch (aState) { + case kAlphaAcc: + case kEpsilonAcc: + case kOmicronAcc: + case kUpsilonAcc: + aState = kInWord; + return GREEK_UPPER_IOTA_DIALYTIKA; + default: + break; + } + aState = kIota; + return GREEK_UPPER_IOTA; + + case GREEK_LOWER_UPSILON: + switch (aState) { + case kAlphaAcc: + case kEpsilonAcc: + case kEtaAcc: + case kOmicronAcc: + aState = kInWord; + return GREEK_UPPER_UPSILON_DIALYTIKA; + case kOmicron: + aState = kOmicronUpsilon; + break; + default: + aState = kUpsilon; + break; + } + return GREEK_UPPER_UPSILON; + + case GREEK_UPPER_IOTA_DIALYTIKA: + case GREEK_LOWER_IOTA_DIALYTIKA: + case GREEK_UPPER_UPSILON_DIALYTIKA: + case GREEK_LOWER_UPSILON_DIALYTIKA: + case COMBINING_DIAERESIS: + aState = kDiaeresis; + return ToUpperCase(aCh); + + // remove accent if it follows a vowel or diaeresis, + // and set appropriate state for diphthong detection + case COMBINING_ACUTE_ACCENT: + case COMBINING_ACUTE_TONE_MARK: + switch (aState) { + case kAlpha: + aState = kAlphaAcc; + return uint32_t(-1); // omit this char from result string + case kEpsilon: + aState = kEpsilonAcc; + return uint32_t(-1); + case kEta: + aState = kEtaAcc; + return uint32_t(-1); + case kIota: + aState = kIotaAcc; + return uint32_t(-1); + case kOmicron: + aState = kOmicronAcc; + return uint32_t(-1); + case kUpsilon: + aState = kUpsilonAcc; + return uint32_t(-1); + case kOmicronUpsilon: + aState = kInWord; // this completed a diphthong + return uint32_t(-1); + case kOmega: + aState = kOmegaAcc; + return uint32_t(-1); + case kDiaeresis: + aState = kInWord; + return uint32_t(-1); + default: + break; + } + break; + + // combinations with dieresis+accent just strip the accent, + // and reset to start state (don't form diphthong with following vowel) + case GREEK_LOWER_IOTA_DIALYTIKA_TONOS: + case GREEK_LOWER_IOTA_DIALYTIKA_OXIA: + aState = kInWord; + return GREEK_UPPER_IOTA_DIALYTIKA; + + case GREEK_LOWER_UPSILON_DIALYTIKA_TONOS: + case GREEK_LOWER_UPSILON_DIALYTIKA_OXIA: + aState = kInWord; + return GREEK_UPPER_UPSILON_DIALYTIKA; + + case COMBINING_GREEK_DIALYTIKA_TONOS: + aState = kInWord; + return COMBINING_DIAERESIS; + + // strip accents from vowels, and note the vowel seen so that we can detect + // diphthongs where diaeresis needs to be added + case GREEK_LOWER_ALPHA_TONOS: + case GREEK_LOWER_ALPHA_OXIA: + case GREEK_UPPER_ALPHA_TONOS: + case GREEK_UPPER_ALPHA_OXIA: + aState = kAlphaAcc; + return GREEK_UPPER_ALPHA; + + case GREEK_LOWER_EPSILON_TONOS: + case GREEK_LOWER_EPSILON_OXIA: + case GREEK_UPPER_EPSILON_TONOS: + case GREEK_UPPER_EPSILON_OXIA: + aState = kEpsilonAcc; + return GREEK_UPPER_EPSILON; + + case GREEK_LOWER_ETA_TONOS: + case GREEK_UPPER_ETA_TONOS: + if (aState == kStart) { + aState = kEtaAccMarked; + aMarkEtaPos = true; // mark in case we need to remove the tonos later + return GREEK_UPPER_ETA_TONOS; // treat as disjunctive eta for now + } + // if not in initial state, fall through to strip the accent + [[fallthrough]]; + + case GREEK_LOWER_ETA_OXIA: + case GREEK_UPPER_ETA_OXIA: + aState = kEtaAcc; + return GREEK_UPPER_ETA; + + case GREEK_LOWER_IOTA_TONOS: + case GREEK_LOWER_IOTA_OXIA: + case GREEK_UPPER_IOTA_TONOS: + case GREEK_UPPER_IOTA_OXIA: + aState = kIotaAcc; + return GREEK_UPPER_IOTA; + + case GREEK_LOWER_OMICRON_TONOS: + case GREEK_LOWER_OMICRON_OXIA: + case GREEK_UPPER_OMICRON_TONOS: + case GREEK_UPPER_OMICRON_OXIA: + aState = kOmicronAcc; + return GREEK_UPPER_OMICRON; + + case GREEK_LOWER_UPSILON_TONOS: + case GREEK_LOWER_UPSILON_OXIA: + case GREEK_UPPER_UPSILON_TONOS: + case GREEK_UPPER_UPSILON_OXIA: + switch (aState) { + case kOmicron: + aState = kInWord; // this completed a diphthong + break; + default: + aState = kUpsilonAcc; + break; + } + return GREEK_UPPER_UPSILON; + + case GREEK_LOWER_OMEGA_TONOS: + case GREEK_LOWER_OMEGA_OXIA: + case GREEK_UPPER_OMEGA_TONOS: + case GREEK_UPPER_OMEGA_OXIA: + aState = kOmegaAcc; + return GREEK_UPPER_OMEGA; + } + + // all other characters just reset the state to either kStart or kInWord, + // and use standard mappings + switch (category) { + case HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER: + case HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK: + aState = kInWord; + break; + default: + aState = kStart; + break; + } + + return ToUpperCase(aCh); +} + +} // namespace mozilla diff --git a/intl/unicharutil/util/GreekCasing.h b/intl/unicharutil/util/GreekCasing.h new file mode 100644 index 0000000000..f46f607e05 --- /dev/null +++ b/intl/unicharutil/util/GreekCasing.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GreekCasing_h_ +#define GreekCasing_h_ + +#include <stdint.h> +#include "mozilla/Attributes.h" + +namespace mozilla { + +class GreekCasing { + // When doing an Uppercase transform in Greek, we need to keep track of the + // current state while iterating through the string, to recognize and process + // diphthongs correctly. For clarity, we define a state for each vowel and + // each vowel with accent, although a few of these do not actually need any + // special treatment and could be folded into kStart. + private: + enum GreekStates { + kStart, + kInWord, + kAlpha, + kEpsilon, + kEta, + kIota, + kOmicron, + kUpsilon, + kOmega, + kAlphaAcc, + kEpsilonAcc, + kEtaAcc, + kEtaAccMarked, + kIotaAcc, + kOmicronAcc, + kUpsilonAcc, + kOmegaAcc, + kOmicronUpsilon, + kDiaeresis + }; + + public: + class State { + public: + State() : mState(kStart) {} + + MOZ_IMPLICIT State(const GreekStates& aState) : mState(aState) {} + + void Reset() { mState = kStart; } + + operator GreekStates() const { return mState; } + + private: + GreekStates mState; + }; + + static uint32_t UpperCase(uint32_t aCh, State& aState, bool& aMarkEtaPos, + bool& aUpdateMarkedEta); +}; + +} // namespace mozilla + +#endif diff --git a/intl/unicharutil/util/ICUUtils.cpp b/intl/unicharutil/util/ICUUtils.cpp new file mode 100644 index 0000000000..3aa0b84ac4 --- /dev/null +++ b/intl/unicharutil/util/ICUUtils.cpp @@ -0,0 +1,269 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef MOZILLA_INTERNAL_API + +# include "mozilla/Assertions.h" +# include "mozilla/UniquePtr.h" + +# include "ICUUtils.h" +# include "mozilla/StaticPrefs_dom.h" +# include "mozilla/intl/LocaleService.h" +# include "nsIContent.h" +# include "mozilla/dom/Document.h" +# include "nsString.h" +# include "unicode/uloc.h" +# include "unicode/unum.h" + +using namespace mozilla; +using mozilla::intl::LocaleService; + +class NumberFormatDeleter { + public: + void operator()(UNumberFormat* aPtr) { + MOZ_ASSERT(aPtr != nullptr, + "UniquePtr deleter shouldn't be called for nullptr"); + unum_close(aPtr); + } +}; + +using UniqueUNumberFormat = UniquePtr<UNumberFormat, NumberFormatDeleter>; + +void ICUUtils::LanguageTagIterForContent::GetNext(nsACString& aBCP47LangTag) { + if (mCurrentFallbackIndex < 0) { + mCurrentFallbackIndex = 0; + // Try the language specified by a 'lang'/'xml:lang' attribute on mContent + // or any ancestor, if such an attribute is specified: + nsAutoString lang; + mContent->GetLang(lang); + if (!lang.IsEmpty()) { + CopyUTF16toUTF8(lang, aBCP47LangTag); + return; + } + } + + if (mCurrentFallbackIndex < 1) { + mCurrentFallbackIndex = 1; + // Else try the language specified by any Content-Language HTTP header or + // pragma directive: + nsAutoString lang; + mContent->OwnerDoc()->GetContentLanguage(lang); + if (!lang.IsEmpty()) { + CopyUTF16toUTF8(lang, aBCP47LangTag); + return; + } + } + + if (mCurrentFallbackIndex < 2) { + mCurrentFallbackIndex = 2; + // Else take the app's locale: + + nsAutoCString appLocale; + LocaleService::GetInstance()->GetAppLocaleAsBCP47(aBCP47LangTag); + return; + } + + // TODO: Probably not worth it, but maybe have a fourth fallback to using + // the OS locale? + + aBCP47LangTag.Truncate(); // Signal iterator exhausted +} + +/* static */ +bool ICUUtils::LocalizeNumber(double aValue, + LanguageTagIterForContent& aLangTags, + nsAString& aLocalizedValue) { + MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing"); + + static const int32_t kBufferSize = 256; + + UChar buffer[kBufferSize]; + + nsAutoCString langTag; + aLangTags.GetNext(langTag); + while (!langTag.IsEmpty()) { + UErrorCode status = U_ZERO_ERROR; + UniqueUNumberFormat format( + unum_open(UNUM_DECIMAL, nullptr, 0, langTag.get(), nullptr, &status)); + // Since unum_setAttribute have no UErrorCode parameter, we have to + // check error status. + if (U_FAILURE(status)) { + aLangTags.GetNext(langTag); + continue; + } + unum_setAttribute(format.get(), UNUM_GROUPING_USED, + StaticPrefs::dom_forms_number_grouping()); + // ICU default is a maximum of 3 significant fractional digits. We don't + // want that limit, so we set it to the maximum that a double can represent + // (14-16 decimal fractional digits). + unum_setAttribute(format.get(), UNUM_MAX_FRACTION_DIGITS, 16); + int32_t length = unum_formatDouble(format.get(), aValue, buffer, + kBufferSize, nullptr, &status); + NS_ASSERTION(length < kBufferSize && status != U_BUFFER_OVERFLOW_ERROR && + status != U_STRING_NOT_TERMINATED_WARNING, + "Need a bigger buffer?!"); + if (U_SUCCESS(status)) { + ICUUtils::AssignUCharArrayToString(buffer, length, aLocalizedValue); + return true; + } + aLangTags.GetNext(langTag); + } + return false; +} + +/* static */ +double ICUUtils::ParseNumber(nsAString& aValue, + LanguageTagIterForContent& aLangTags) { + MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing"); + + if (aValue.IsEmpty()) { + return std::numeric_limits<float>::quiet_NaN(); + } + + uint32_t length = aValue.Length(); + + nsAutoCString langTag; + aLangTags.GetNext(langTag); + while (!langTag.IsEmpty()) { + UErrorCode status = U_ZERO_ERROR; + UniqueUNumberFormat format( + unum_open(UNUM_DECIMAL, nullptr, 0, langTag.get(), nullptr, &status)); + if (!StaticPrefs::dom_forms_number_grouping()) { + unum_setAttribute(format.get(), UNUM_GROUPING_USED, UBool(0)); + } + int32_t parsePos = 0; + static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2, + "Unexpected character size - the following cast is unsafe"); + double val = unum_parseDouble(format.get(), + (const UChar*)PromiseFlatString(aValue).get(), + length, &parsePos, &status); + if (U_SUCCESS(status) && parsePos == (int32_t)length) { + return val; + } + aLangTags.GetNext(langTag); + } + return std::numeric_limits<float>::quiet_NaN(); +} + +/* static */ +void ICUUtils::AssignUCharArrayToString(UChar* aICUString, int32_t aLength, + nsAString& aMozString) { + // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can + // cast here. + + static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2, + "Unexpected character size - the following cast is unsafe"); + + aMozString.Assign((const nsAString::char_type*)aICUString, aLength); + + NS_ASSERTION((int32_t)aMozString.Length() == aLength, "Conversion failed"); +} + +/* static */ +nsresult ICUUtils::UErrorToNsResult(const UErrorCode aErrorCode) { + if (U_SUCCESS(aErrorCode)) { + return NS_OK; + } + + switch (aErrorCode) { + case U_ILLEGAL_ARGUMENT_ERROR: + return NS_ERROR_INVALID_ARG; + + case U_MEMORY_ALLOCATION_ERROR: + return NS_ERROR_OUT_OF_MEMORY; + + default: + return NS_ERROR_FAILURE; + } +} + +# if 0 +/* static */ +Locale +ICUUtils::BCP47CodeToLocale(const nsAString& aBCP47Code) +{ + MOZ_ASSERT(!aBCP47Code.IsEmpty(), "Don't pass an empty BCP 47 code"); + + Locale locale; + locale.setToBogus(); + + // BCP47 codes are guaranteed to be ASCII, so lossy conversion is okay + NS_LossyConvertUTF16toASCII bcp47code(aBCP47Code); + + UErrorCode status = U_ZERO_ERROR; + int32_t needed; + + char localeID[256]; + needed = uloc_forLanguageTag(bcp47code.get(), localeID, + PR_ARRAY_SIZE(localeID) - 1, nullptr, + &status); + MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(localeID)) - 1, + "Need a bigger buffer"); + if (needed <= 0 || U_FAILURE(status)) { + return locale; + } + + char lang[64]; + needed = uloc_getLanguage(localeID, lang, PR_ARRAY_SIZE(lang) - 1, + &status); + MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(lang)) - 1, + "Need a bigger buffer"); + if (needed <= 0 || U_FAILURE(status)) { + return locale; + } + + char country[64]; + needed = uloc_getCountry(localeID, country, PR_ARRAY_SIZE(country) - 1, + &status); + MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(country)) - 1, + "Need a bigger buffer"); + if (needed > 0 && U_SUCCESS(status)) { + locale = Locale(lang, country); + } + + if (locale.isBogus()) { + // Using the country resulted in a bogus Locale, so try with only the lang + locale = Locale(lang); + } + + return locale; +} + +/* static */ +void +ICUUtils::ToMozString(UnicodeString& aICUString, nsAString& aMozString) +{ + // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can + // cast here. + + static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2, + "Unexpected character size - the following cast is unsafe"); + + const nsAString::char_type* buf = + (const nsAString::char_type*)aICUString.getTerminatedBuffer(); + aMozString.Assign(buf); + + NS_ASSERTION(aMozString.Length() == (uint32_t)aICUString.length(), + "Conversion failed"); +} + +/* static */ +void +ICUUtils::ToICUString(nsAString& aMozString, UnicodeString& aICUString) +{ + // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can + // cast here. + + static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2, + "Unexpected character size - the following cast is unsafe"); + + aICUString.setTo((UChar*)PromiseFlatString(aMozString).get(), + aMozString.Length()); + + NS_ASSERTION(aMozString.Length() == (uint32_t)aICUString.length(), + "Conversion failed"); +} +# endif + +#endif /* MOZILLA_INTERNAL_API */ diff --git a/intl/unicharutil/util/ICUUtils.h b/intl/unicharutil/util/ICUUtils.h new file mode 100644 index 0000000000..6d14c604eb --- /dev/null +++ b/intl/unicharutil/util/ICUUtils.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ICUUtils_h__ +#define mozilla_ICUUtils_h__ + +// The ICU utils implementation needs internal things like XPCOM strings and +// nsGkAtom, so we only build when included into internal libs: +#ifdef MOZILLA_INTERNAL_API + +# include "nsString.h" +# include "unicode/unum.h" // for UNumberFormat + +class nsIContent; + +class ICUUtils { + public: + /** + * This class is used to encapsulate an nsIContent object to allow lazy + * iteration over its primary and fallback BCP 47 language tags. + */ + class LanguageTagIterForContent { + public: + explicit LanguageTagIterForContent(nsIContent* aContent) + : mContent(aContent), mCurrentFallbackIndex(-1) {} + + /** + * Used to iterate over the nsIContent object's primary language tag and + * its fallbacks tags. The following sources of language tag information + * are tried in turn: + * + * 1) the "lang" of the nsIContent object (which is based on the 'lang'/ + * 'xml:lang' attribute on itself or the nearest ancestor to have such + * an attribute, if any); + * 2) the Content-Language HTTP pragma directive or HTTP header; + * 3) the configured language tag of the user-agent. + * + * Once all fallbacks have been exhausted then this function will set + * aBCP47LangTag to the empty string. + */ + void GetNext(nsACString& aBCP47LangTag); + + bool IsAtStart() const { return mCurrentFallbackIndex < 0; } + + private: + nsIContent* mContent; + int8_t mCurrentFallbackIndex; + }; + + /** + * Attempts to localize aValue and return the result via the aLocalizedValue + * outparam. Returns true on success. Returns false on failure, in which + * case aLocalizedValue will be untouched. + */ + static bool LocalizeNumber(double aValue, + LanguageTagIterForContent& aLangTags, + nsAString& aLocalizedValue); + + /** + * Parses the localized number that is serialized in aValue using aLangTags + * and returns the result as a double. Returns NaN on failure. + */ + static double ParseNumber(nsAString& aValue, + LanguageTagIterForContent& aLangTags); + + static void AssignUCharArrayToString(UChar* aICUString, int32_t aLength, + nsAString& aMozString); + + /** + * Map ICU UErrorCode to nsresult + */ + static nsresult UErrorToNsResult(const UErrorCode aErrorCode); + +# if 0 + // Currently disabled because using C++ API doesn't play nicely with enabling + // system ICU. + + /** + * Converts an IETF BCP 47 language code to an ICU Locale. + */ + static Locale BCP47CodeToLocale(const nsAString& aBCP47Code); + + static void ToMozString(UnicodeString& aICUString, nsAString& aMozString); + static void ToICUString(nsAString& aMozString, UnicodeString& aICUString); +# endif +}; + +#endif /* MOZILLA_INTERNAL_API */ + +#endif /* mozilla_ICUUtils_h__ */ diff --git a/intl/unicharutil/util/IrishCasing.cpp b/intl/unicharutil/util/IrishCasing.cpp new file mode 100644 index 0000000000..5de8a529ae --- /dev/null +++ b/intl/unicharutil/util/IrishCasing.cpp @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/****************************************************************************** + +This file provides a finite state machine to support Irish Gaelic uppercasing +rules. + +The caller will need to iterate through a string, passing a State variable +along with the current character to each UpperCase call and checking the flags +that are returned: + + If aMarkPos is true, caller must remember the current index in the string as + a possible target for a future action. + + If aAction is non-zero, then one or more characters from the marked index are + to be modified: + 1 lowercase the marked letter + 2 lowercase the marked letter and its successor + 3 lowercase the marked letter, and delete its successor + + +### Rules from https://bugzilla.mozilla.org/show_bug.cgi?id=1014639, +### comments 1 and 4: + +v = [a,á,e,é,i,í,o,ó,u,ú] +V = [A,Á,E,É,I,Í,O,Ó,U,Ú] + +bhf -> bhF +bhF -> bhF +bp -> bP +bP -> bP +dt -> dT +dT -> dT +gc -> gC +gC -> gC +h{V} -> h{V} +mb -> mB +mB -> mB +n-{v} -> n{V} +n{V} -> n{V} +nd -> nD +nD -> nD +ng -> nG +nG -> nG +t-{v} -> t{V} +t{V} -> t{V} +ts{v} -> tS{V} +tS{v} -> tS{V} +tS{V} -> tS{V} +tsl -> tSL +tSl -> tSL +tSL -> tSL +tsn -> tSN +tSn -> tSN +tSN -> tSN +tsr -> tSR +tSr -> tSR +tSR -> tSR + +### Create table of states and actions for each input class. + +Start (non-word) state is #; generic in-word state is _, once we know there's +no special action to do in this word. + + # _ b bh d g h m n n- t t- ts +input\state +b b' _ _ _ _ _ _ 1 _ _ _ _ _ +B _ _ _ _ _ _ _ 1 _ _ _ _ _ +c _ _ _ _ _ 1 _ _ _ _ _ _ _ +C _ _ _ _ _ 1 _ _ _ _ _ _ _ +d d' _ _ _ _ _ _ _ 1 _ _ _ _ +D _ _ _ _ _ _ _ _ 1 _ _ _ _ +f _ _ _ 2 _ _ _ _ _ _ _ _ _ +F _ _ _ 2 _ _ _ _ _ _ _ _ _ +g g' _ _ _ _ _ _ _ 1 _ _ _ _ +G _ _ _ _ _ _ _ _ 1 _ _ _ _ +h h' _ bh _ _ _ _ _ _ _ _ _ _ +l _ _ _ _ _ _ _ _ _ _ _ _ 1 +L _ _ _ _ _ _ _ _ _ _ _ _ 1 +m m' _ _ _ _ _ _ _ _ _ _ _ _ +n n' _ _ _ _ _ _ _ _ _ _ _ 1 +N _ _ _ _ _ _ _ _ _ _ _ _ 1 +p _ _ 1 _ _ _ _ _ _ _ _ _ _ +P _ _ 1 _ _ _ _ _ _ _ _ _ _ +r _ _ _ _ _ _ _ _ _ _ _ _ 1 +R _ _ _ _ _ _ _ _ _ _ _ _ 1 +s _ _ _ _ _ _ _ _ _ _ ts _ _ +S _ _ _ _ _ _ _ _ _ _ ts _ _ +t t' _ _ _ 1 _ _ _ _ _ _ _ _ +T _ _ _ _ 1 _ _ _ _ _ _ _ _ +vowel _ _ _ _ _ _ _ _ _ 1d _ 1d 1 +Vowel _ _ _ _ _ _ 1 _ 1 _ 1 _ 1 +hyph _ _ _ _ _ _ _ _ n- _ t- _ _ +letter _ _ _ _ _ _ _ _ _ _ _ _ _ +other # # # # # # # # # # # # # + +Actions: + 1 lowercase one letter at start of word + 2 lowercase two letters at start of word + 1d lowercase one letter at start of word, and delete next + (and then go to state _, nothing further to do in this word) + +else just go to the given state; suffix ' indicates mark start-of-word. + +### Consolidate identical states and classes: + + 0 1 2 3 4 5 6 7 8 9 A B + # _ b bh d g h m n [nt]- t ts +input\state +b b' _ _ _ _ _ _ 1 _ _ _ _ +B _ _ _ _ _ _ _ 1 _ _ _ _ +[cC] _ _ _ _ _ 1 _ _ _ _ _ _ +d d' _ _ _ _ _ _ _ 1 _ _ _ +[DG] _ _ _ _ _ _ _ _ 1 _ _ _ +[fF] _ _ _ 2 _ _ _ _ _ _ _ _ +g g' _ _ _ _ _ _ _ 1 _ _ _ +h h' _ bh _ _ _ _ _ _ _ _ _ +[lLNrR] _ _ _ _ _ _ _ _ _ _ _ 1 +m m' _ _ _ _ _ _ _ _ _ _ _ +n n' _ _ _ _ _ _ _ _ _ _ 1 +[pP] _ _ 1 _ _ _ _ _ _ _ _ _ +[sS] _ _ _ _ _ _ _ _ _ _ ts _ +t t' _ _ _ 1 _ _ _ _ _ _ _ +T _ _ _ _ 1 _ _ _ _ _ _ _ +vowel _ _ _ _ _ _ _ _ _ 1d _ 1 +Vowel _ _ _ _ _ _ 1 _ 1 _ 1 1 +hyph _ _ _ _ _ _ _ _ [nt-] _ [nt-] _ +letter _ _ _ _ _ _ _ _ _ _ _ _ +other # # # # # # # # # # # # + +So we have 20 input classes, and 12 states. + +State table array will contain bytes that encode action and new state: + + 0x80 - bit flag: mark start-of-word position + 0x40 - currently unused + 0x30 - action mask: 4 values + 0x00 - do nothing + 0x10 - lowercase one letter + 0x20 - lowercase two letters + 0x30 - lowercase one, delete one + 0x0F - next-state mask +******************************************************************************/ + +#include "IrishCasing.h" + +#include "nsUnicodeProperties.h" +#include "nsUnicharUtils.h" + +namespace mozilla { + +const uint8_t IrishCasing::sUppercaseStateTable[kNumClasses][kNumStates] = { + // # _ b bh d g h m n [nt]- t ts + {0x82, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, + 0x01}, // b + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, + 0x01}, // B + {0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // [cC] + {0x84, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, + 0x01}, // d + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, + 0x01}, // [DG] + {0x01, 0x01, 0x01, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // [fF] + {0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, + 0x01}, // g + {0x86, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // h + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x11}, // [lLNrR] + {0x87, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // m + {0x88, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x11}, // n + {0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // [pP] + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0B, + 0x01}, // [sS] + {0x8A, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // t + {0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // T + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x31, 0x01, + 0x11}, // vowel + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, + 0x11}, // Vowel + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x01, 0x09, + 0x01}, // hyph + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01}, // letter + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} // other +}; + +#define HYPHEN 0x2010 +#define NO_BREAK_HYPHEN 0x2011 +#define a_ACUTE 0x00e1 +#define e_ACUTE 0x00e9 +#define i_ACUTE 0x00ed +#define o_ACUTE 0x00f3 +#define u_ACUTE 0x00fa +#define A_ACUTE 0x00c1 +#define E_ACUTE 0x00c9 +#define I_ACUTE 0x00cd +#define O_ACUTE 0x00d3 +#define U_ACUTE 0x00da + +const uint8_t IrishCasing::sLcClasses[26] = { + kClass_vowel, kClass_b, kClass_cC, kClass_d, kClass_vowel, + kClass_fF, kClass_g, kClass_h, kClass_vowel, kClass_letter, + kClass_letter, kClass_lLNrR, kClass_m, kClass_n, kClass_vowel, + kClass_pP, kClass_letter, kClass_lLNrR, kClass_sS, kClass_t, + kClass_vowel, kClass_letter, kClass_letter, kClass_letter, kClass_letter, + kClass_letter}; + +const uint8_t IrishCasing::sUcClasses[26] = { + kClass_Vowel, kClass_B, kClass_cC, kClass_DG, kClass_Vowel, + kClass_fF, kClass_DG, kClass_letter, kClass_Vowel, kClass_letter, + kClass_letter, kClass_lLNrR, kClass_letter, kClass_lLNrR, kClass_Vowel, + kClass_pP, kClass_letter, kClass_lLNrR, kClass_sS, kClass_T, + kClass_Vowel, kClass_letter, kClass_letter, kClass_letter, kClass_letter, + kClass_letter}; + +uint8_t IrishCasing::GetClass(uint32_t aCh) { + using mozilla::unicode::GetGenCategory; + if (aCh >= 'a' && aCh <= 'z') { + return sLcClasses[aCh - 'a']; + } else if (aCh >= 'A' && aCh <= 'Z') { + return sUcClasses[aCh - 'A']; + } else if (GetGenCategory(aCh) == nsUGenCategory::kLetter) { + if (aCh == a_ACUTE || aCh == e_ACUTE || aCh == i_ACUTE || aCh == o_ACUTE || + aCh == u_ACUTE) { + return kClass_vowel; + } else if (aCh == A_ACUTE || aCh == E_ACUTE || aCh == I_ACUTE || + aCh == O_ACUTE || aCh == U_ACUTE) { + return kClass_Vowel; + } else { + return kClass_letter; + } + } else if (aCh == '-' || aCh == HYPHEN || aCh == NO_BREAK_HYPHEN) { + return kClass_hyph; + } else { + return kClass_other; + } +} + +uint32_t IrishCasing::UpperCase(uint32_t aCh, State& aState, bool& aMarkPos, + uint8_t& aAction) { + uint8_t cls = GetClass(aCh); + uint8_t stateEntry = sUppercaseStateTable[cls][aState]; + aMarkPos = !!(stateEntry & kMarkPositionFlag); + aAction = (stateEntry & kActionMask) >> kActionShift; + aState = State(stateEntry & kNextStateMask); + + return ToUpperCase(aCh); +} + +} // namespace mozilla diff --git a/intl/unicharutil/util/IrishCasing.h b/intl/unicharutil/util/IrishCasing.h new file mode 100644 index 0000000000..f5a6582a06 --- /dev/null +++ b/intl/unicharutil/util/IrishCasing.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef IrishCasing_h_ +#define IrishCasing_h_ + +#include <stdint.h> +#include "mozilla/Attributes.h" + +namespace mozilla { + +class IrishCasing { + private: + enum IrishStates { + kState_Start, + kState_InWord, + kState_b, + kState_bh, + kState_d, + kState_g, + kState_h, + kState_m, + kState_n, + kState_nt_, + kState_t, + kState_ts, + kNumStates + }; + + enum IrishClasses { + kClass_b, + kClass_B, + kClass_cC, + kClass_d, + kClass_DG, + kClass_fF, + kClass_g, + kClass_h, + kClass_lLNrR, + kClass_m, + kClass_n, + kClass_pP, + kClass_sS, + kClass_t, + kClass_T, + kClass_vowel, + kClass_Vowel, + kClass_hyph, + kClass_letter, + kClass_other, + kNumClasses + }; + + public: + class State { + friend class IrishCasing; + + public: + State() : mState(kState_Start) {} + + MOZ_IMPLICIT State(const IrishStates& aState) : mState(aState) {} + + void Reset() { mState = kState_Start; } + + operator IrishStates() const { return mState; } + + private: + explicit State(uint8_t aState) : mState(IrishStates(aState)) {} + + uint8_t GetClass(uint32_t aCh); + + IrishStates mState; + }; + + enum { + kMarkPositionFlag = 0x80, + kActionMask = 0x30, + kActionShift = 4, + kNextStateMask = 0x0f + }; + + static const uint8_t sUppercaseStateTable[kNumClasses][kNumStates]; + static const uint8_t sLcClasses[26]; + static const uint8_t sUcClasses[26]; + + static uint32_t UpperCase(uint32_t aCh, State& aState, bool& aMarkPos, + uint8_t& aAction); + + static bool IsUpperVowel(uint32_t aCh) { + return GetClass(aCh) == kClass_Vowel; + } + + private: + static uint8_t GetClass(uint32_t aCh); +}; + +} // namespace mozilla + +#endif diff --git a/intl/unicharutil/util/moz.build b/intl/unicharutil/util/moz.build new file mode 100644 index 0000000000..993daf7ded --- /dev/null +++ b/intl/unicharutil/util/moz.build @@ -0,0 +1,28 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + "GreekCasing.h", + "ICUUtils.h", + "IrishCasing.h", + "nsBidiUtils.h", + "nsSpecialCasingData.h", + "nsUnicharUtils.h", + "nsUnicodeProperties.h", + "nsUnicodeScriptCodes.h", +] + +UNIFIED_SOURCES += [ + "GreekCasing.cpp", + "ICUUtils.cpp", + "IrishCasing.cpp", + "nsBidiUtils.cpp", + "nsSpecialCasingData.cpp", + "nsUnicharUtils.cpp", + "nsUnicodeProperties.cpp", +] + +FINAL_LIBRARY = "xul" diff --git a/intl/unicharutil/util/nsBidiUtils.cpp b/intl/unicharutil/util/nsBidiUtils.cpp new file mode 100644 index 0000000000..fb7a20917a --- /dev/null +++ b/intl/unicharutil/util/nsBidiUtils.cpp @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsBidiUtils.h" + +namespace mozilla { +static const uint32_t kMinRTLChar = 0x0590; +} // namespace mozilla + +#define ARABIC_TO_HINDI_DIGIT_INCREMENT \ + (START_HINDI_DIGITS - START_ARABIC_DIGITS) +#define PERSIAN_TO_HINDI_DIGIT_INCREMENT \ + (START_HINDI_DIGITS - START_FARSI_DIGITS) +#define ARABIC_TO_PERSIAN_DIGIT_INCREMENT \ + (START_FARSI_DIGITS - START_ARABIC_DIGITS) +#define NUM_TO_ARABIC(c) \ + ((((c) >= START_HINDI_DIGITS) && ((c) <= END_HINDI_DIGITS)) \ + ? ((c) - (uint16_t)ARABIC_TO_HINDI_DIGIT_INCREMENT) \ + : ((((c) >= START_FARSI_DIGITS) && ((c) <= END_FARSI_DIGITS)) \ + ? ((c) - (uint16_t)ARABIC_TO_PERSIAN_DIGIT_INCREMENT) \ + : (c))) +#define NUM_TO_HINDI(c) \ + ((((c) >= START_ARABIC_DIGITS) && ((c) <= END_ARABIC_DIGITS)) \ + ? ((c) + (uint16_t)ARABIC_TO_HINDI_DIGIT_INCREMENT) \ + : ((((c) >= START_FARSI_DIGITS) && ((c) <= END_FARSI_DIGITS)) \ + ? ((c) + (uint16_t)PERSIAN_TO_HINDI_DIGIT_INCREMENT) \ + : (c))) +#define NUM_TO_PERSIAN(c) \ + ((((c) >= START_HINDI_DIGITS) && ((c) <= END_HINDI_DIGITS)) \ + ? ((c) - (uint16_t)PERSIAN_TO_HINDI_DIGIT_INCREMENT) \ + : ((((c) >= START_ARABIC_DIGITS) && ((c) <= END_ARABIC_DIGITS)) \ + ? ((c) + (uint16_t)ARABIC_TO_PERSIAN_DIGIT_INCREMENT) \ + : (c))) + +char16_t HandleNumberInChar(char16_t aChar, bool aPrevCharArabic, + uint32_t aNumFlag) { + // IBMBIDI_NUMERAL_NOMINAL * + // IBMBIDI_NUMERAL_REGULAR + // IBMBIDI_NUMERAL_HINDICONTEXT + // IBMBIDI_NUMERAL_ARABIC + // IBMBIDI_NUMERAL_HINDI + + switch (aNumFlag) { + case IBMBIDI_NUMERAL_HINDI: + return NUM_TO_HINDI(aChar); + case IBMBIDI_NUMERAL_ARABIC: + return NUM_TO_ARABIC(aChar); + case IBMBIDI_NUMERAL_PERSIAN: + return NUM_TO_PERSIAN(aChar); + case IBMBIDI_NUMERAL_REGULAR: + case IBMBIDI_NUMERAL_HINDICONTEXT: + case IBMBIDI_NUMERAL_PERSIANCONTEXT: + // for clipboard handling + // XXX do we really want to convert numerals when copying text? + if (aPrevCharArabic) { + return aNumFlag == IBMBIDI_NUMERAL_PERSIANCONTEXT + ? NUM_TO_PERSIAN(aChar) + : NUM_TO_HINDI(aChar); + } + return NUM_TO_ARABIC(aChar); + case IBMBIDI_NUMERAL_NOMINAL: + default: + return aChar; + } +} + +nsresult HandleNumbers(char16_t* aBuffer, uint32_t aSize, uint32_t aNumFlag) { + uint32_t i; + + switch (aNumFlag) { + case IBMBIDI_NUMERAL_HINDI: + case IBMBIDI_NUMERAL_ARABIC: + case IBMBIDI_NUMERAL_PERSIAN: + case IBMBIDI_NUMERAL_REGULAR: + case IBMBIDI_NUMERAL_HINDICONTEXT: + case IBMBIDI_NUMERAL_PERSIANCONTEXT: + for (i = 0; i < aSize; i++) + aBuffer[i] = HandleNumberInChar( + aBuffer[i], !!(i > 0 ? aBuffer[i - 1] : 0), aNumFlag); + break; + case IBMBIDI_NUMERAL_NOMINAL: + default: + break; + } + return NS_OK; +} diff --git a/intl/unicharutil/util/nsBidiUtils.h b/intl/unicharutil/util/nsBidiUtils.h new file mode 100644 index 0000000000..21a7ee7ffa --- /dev/null +++ b/intl/unicharutil/util/nsBidiUtils.h @@ -0,0 +1,295 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsBidiUtils_h__ +#define nsBidiUtils_h__ + +#include "nsString.h" +#include "encoding_rs_mem.h" + +/** + * Read ftp://ftp.unicode.org/Public/UNIDATA/ReadMe-Latest.txt + * section BIDIRECTIONAL PROPERTIES + * for the detailed definition of the following categories + * + * The values here must match the equivalents in %bidicategorycode in + * mozilla/intl/unicharutil/tools/genUnicodePropertyData.pl, + * and must also match the values used by ICU's UCharDirection. + */ + +enum nsCharType { + eCharType_LeftToRight = 0, + eCharType_RightToLeft = 1, + eCharType_EuropeanNumber = 2, + eCharType_EuropeanNumberSeparator = 3, + eCharType_EuropeanNumberTerminator = 4, + eCharType_ArabicNumber = 5, + eCharType_CommonNumberSeparator = 6, + eCharType_BlockSeparator = 7, + eCharType_SegmentSeparator = 8, + eCharType_WhiteSpaceNeutral = 9, + eCharType_OtherNeutral = 10, + eCharType_LeftToRightEmbedding = 11, + eCharType_LeftToRightOverride = 12, + eCharType_RightToLeftArabic = 13, + eCharType_RightToLeftEmbedding = 14, + eCharType_RightToLeftOverride = 15, + eCharType_PopDirectionalFormat = 16, + eCharType_DirNonSpacingMark = 17, + eCharType_BoundaryNeutral = 18, + eCharType_FirstStrongIsolate = 19, + eCharType_LeftToRightIsolate = 20, + eCharType_RightToLeftIsolate = 21, + eCharType_PopDirectionalIsolate = 22, + eCharType_CharTypeCount +}; + +/** + * This specifies the language directional property of a character set. + */ +typedef enum nsCharType nsCharType; + +/** + * Find the direction of an embedding level or paragraph level set by + * the Unicode Bidi Algorithm. (Even levels are left-to-right, odd + * levels right-to-left. + */ +#define IS_LEVEL_RTL(level) (((level)&1) == 1) + +/** + * Check whether two bidi levels have the same parity and thus the same + * directionality + */ +#define IS_SAME_DIRECTION(level1, level2) (((level1 ^ level2) & 1) == 0) + +/** + * Convert from nsBidiLevel to nsBidiDirection + */ +#define DIRECTION_FROM_LEVEL(level) \ + ((IS_LEVEL_RTL(level)) ? NSBIDI_RTL : NSBIDI_LTR) + +/** + * definitions of bidirection character types by category + */ + +#define CHARTYPE_IS_RTL(val) \ + (((val) == eCharType_RightToLeft) || ((val) == eCharType_RightToLeftArabic)) + +#define CHARTYPE_IS_WEAK(val) \ + (((val) == eCharType_EuropeanNumberSeparator) || \ + ((val) == eCharType_EuropeanNumberTerminator) || \ + (((val) > eCharType_ArabicNumber) && \ + ((val) != eCharType_RightToLeftArabic))) + +/** + * Inspects a Unichar, converting numbers to Arabic or Hindi forms and + * returning them + * @param aChar is the character + * @param aPrevCharArabic is true if the previous character in the string is + * an Arabic char + * @param aNumFlag specifies the conversion to perform: + * IBMBIDI_NUMERAL_NOMINAL: don't do any conversion + * IBMBIDI_NUMERAL_HINDI: convert to Hindi forms + * (Unicode 0660-0669) + * IBMBIDI_NUMERAL_ARABIC: convert to Arabic forms + * (Unicode 0030-0039) + * IBMBIDI_NUMERAL_HINDICONTEXT: convert numbers in Arabic text to + * Hindi, otherwise to Arabic + * @return the converted Unichar + */ +char16_t HandleNumberInChar(char16_t aChar, bool aPrevCharArabic, + uint32_t aNumFlag); + +/** + * Scan a Unichar string, converting numbers to Arabic or Hindi forms in + * place + * @param aBuffer is the string + * @param aSize is the size of aBuffer + * @param aNumFlag specifies the conversion to perform: + * IBMBIDI_NUMERAL_NOMINAL: don't do any conversion + * IBMBIDI_NUMERAL_HINDI: convert to Hindi forms + * (Unicode 0660-0669) + * IBMBIDI_NUMERAL_ARABIC: convert to Arabic forms + * (Unicode 0030-0039) + * IBMBIDI_NUMERAL_HINDICONTEXT: convert numbers in Arabic text to + * Hindi, otherwise to Arabic + */ +nsresult HandleNumbers(char16_t* aBuffer, uint32_t aSize, uint32_t aNumFlag); + +/** + * Give a UTF-32 codepoint + * return true if the codepoint is a Bidi control character (LRM, RLM, ALM; + * LRE, RLE, PDF, LRO, RLO; LRI, RLI, FSI, PDI). + * Return false, otherwise + */ +#define LRM_CHAR 0x200e +#define RLM_CHAR 0x200f + +#define LRE_CHAR 0x202a +#define RLE_CHAR 0x202b +#define PDF_CHAR 0x202c +#define LRO_CHAR 0x202d +#define RLO_CHAR 0x202e + +#define LRI_CHAR 0x2066 +#define RLI_CHAR 0x2067 +#define FSI_CHAR 0x2068 +#define PDI_CHAR 0x2069 + +#define ALM_CHAR 0x061C +inline bool IsBidiControl(uint32_t aChar) { + return ((LRE_CHAR <= aChar && aChar <= RLO_CHAR) || + (LRI_CHAR <= aChar && aChar <= PDI_CHAR) || (aChar == ALM_CHAR) || + (aChar & 0xfffffe) == LRM_CHAR); +} + +/** + * Give a UTF-32 codepoint + * Return true if the codepoint is a Bidi control character that may result + * in RTL directionality and therefore needs to trigger bidi resolution; + * return false otherwise. + */ +inline bool IsBidiControlRTL(uint32_t aChar) { + return aChar == RLM_CHAR || aChar == RLE_CHAR || aChar == RLO_CHAR || + aChar == RLI_CHAR || aChar == ALM_CHAR; +} + +/** + * Give a 16-bit (UTF-16) text buffer + * @return true if the string contains right-to-left characters + */ +inline bool HasRTLChars(mozilla::Span<const char16_t> aBuffer) { + // Span ensures we never pass a nullptr to Rust--even if the + // length of the buffer is zero. + return encoding_mem_is_utf16_bidi(aBuffer.Elements(), aBuffer.Length()); +} + +// These values are shared with Preferences dialog +// ------------------ +// If Pref values are to be changed +// in the XUL file of Prefs. the values +// Must be changed here too.. +// ------------------ +// +#define IBMBIDI_TEXTDIRECTION_STR "bidi.direction" +#define IBMBIDI_TEXTTYPE_STR "bidi.texttype" +#define IBMBIDI_NUMERAL_STR "bidi.numeral" + +// ------------------ +// Text Direction +// ------------------ +// bidi.direction +#define IBMBIDI_TEXTDIRECTION_LTR 1 // 1 = directionLTRBidi * +#define IBMBIDI_TEXTDIRECTION_RTL 2 // 2 = directionRTLBidi +// ------------------ +// Text Type +// ------------------ +// bidi.texttype +#define IBMBIDI_TEXTTYPE_CHARSET 1 // 1 = charsettexttypeBidi * +#define IBMBIDI_TEXTTYPE_LOGICAL 2 // 2 = logicaltexttypeBidi +#define IBMBIDI_TEXTTYPE_VISUAL 3 // 3 = visualtexttypeBidi +// ------------------ +// Numeral Style +// ------------------ +// bidi.numeral +#define IBMBIDI_NUMERAL_NOMINAL 0 // 0 = nominalnumeralBidi * +#define IBMBIDI_NUMERAL_REGULAR 1 // 1 = regularcontextnumeralBidi +#define IBMBIDI_NUMERAL_HINDICONTEXT 2 // 2 = hindicontextnumeralBidi +#define IBMBIDI_NUMERAL_ARABIC 3 // 3 = arabicnumeralBidi +#define IBMBIDI_NUMERAL_HINDI 4 // 4 = hindinumeralBidi +#define IBMBIDI_NUMERAL_PERSIANCONTEXT 5 // 5 = persiancontextnumeralBidi +#define IBMBIDI_NUMERAL_PERSIAN 6 // 6 = persiannumeralBidi + +#define IBMBIDI_DEFAULT_BIDI_OPTIONS \ + ((IBMBIDI_TEXTDIRECTION_LTR << 0) | (IBMBIDI_TEXTTYPE_CHARSET << 4) | \ + (IBMBIDI_NUMERAL_NOMINAL << 8)) + +#define GET_BIDI_OPTION_DIRECTION(bo) \ + (((bo) >> 0) & 0x0000000F) /* 4 bits for DIRECTION */ +#define GET_BIDI_OPTION_TEXTTYPE(bo) \ + (((bo) >> 4) & 0x0000000F) /* 4 bits for TEXTTYPE */ +#define GET_BIDI_OPTION_NUMERAL(bo) \ + (((bo) >> 8) & 0x0000000F) /* 4 bits for NUMERAL */ + +#define SET_BIDI_OPTION_DIRECTION(bo, dir) \ + { (bo) = ((bo)&0xFFFFFFF0) | (((dir)&0x0000000F) << 0); } +#define SET_BIDI_OPTION_TEXTTYPE(bo, tt) \ + { (bo) = ((bo)&0xFFFFFF0F) | (((tt)&0x0000000F) << 4); } +#define SET_BIDI_OPTION_NUMERAL(bo, num) \ + { (bo) = ((bo)&0xFFFFF0FF) | (((num)&0x0000000F) << 8); } + +/* Constants related to the position of numerics in the codepage */ +#define START_HINDI_DIGITS 0x0660 +#define END_HINDI_DIGITS 0x0669 +#define START_ARABIC_DIGITS 0x0030 +#define END_ARABIC_DIGITS 0x0039 +#define START_FARSI_DIGITS 0x06f0 +#define END_FARSI_DIGITS 0x06f9 +#define IS_HINDI_DIGIT(u) \ + (((u) >= START_HINDI_DIGITS) && ((u) <= END_HINDI_DIGITS)) +#define IS_ARABIC_DIGIT(u) \ + (((u) >= START_ARABIC_DIGITS) && ((u) <= END_ARABIC_DIGITS)) +#define IS_FARSI_DIGIT(u) \ + (((u) >= START_FARSI_DIGITS) && ((u) <= END_FARSI_DIGITS)) +/** + * Arabic numeric separator and numeric formatting characters: + * U+0600;ARABIC NUMBER SIGN + * U+0601;ARABIC SIGN SANAH + * U+0602;ARABIC FOOTNOTE MARKER + * U+0603;ARABIC SIGN SAFHA + * U+066A;ARABIC PERCENT SIGN + * U+066B;ARABIC DECIMAL SEPARATOR + * U+066C;ARABIC THOUSANDS SEPARATOR + * U+06DD;ARABIC END OF AYAH + */ +#define IS_ARABIC_SEPARATOR(u) \ + ((/*(u) >= 0x0600 &&*/ (u) <= 0x0603) || ((u) >= 0x066A && (u) <= 0x066C) || \ + ((u) == 0x06DD)) + +#define IS_BIDI_DIACRITIC(u) \ + (((u) >= 0x0591 && (u) <= 0x05A1) || ((u) >= 0x05A3 && (u) <= 0x05B9) || \ + ((u) >= 0x05BB && (u) <= 0x05BD) || ((u) == 0x05BF) || ((u) == 0x05C1) || \ + ((u) == 0x05C2) || ((u) == 0x05C4) || ((u) >= 0x064B && (u) <= 0x0652) || \ + ((u) == 0x0670) || ((u) >= 0x06D7 && (u) <= 0x06E4) || ((u) == 0x06E7) || \ + ((u) == 0x06E8) || ((u) >= 0x06EA && (u) <= 0x06ED)) + +#define IS_HEBREW_CHAR(c) \ + (((0x0590 <= (c)) && ((c) <= 0x05FF)) || (((c) >= 0xfb1d) && ((c) <= 0xfb4f))) +#define IS_ARABIC_CHAR(c) \ + ((0x0600 <= (c) && (c) <= 0x08FF) && \ + ((c) <= 0x06ff || ((c) >= 0x0750 && (c) <= 0x077f) || (c) >= 0x08a0)) +#define IS_ARABIC_ALPHABETIC(c) \ + (IS_ARABIC_CHAR(c) && \ + !(IS_HINDI_DIGIT(c) || IS_FARSI_DIGIT(c) || IS_ARABIC_SEPARATOR(c))) + +/** + * The codepoint ranges in the following macros are based on the blocks + * allocated, or planned to be allocated, to right-to-left characters in the + * BMP (Basic Multilingual Plane) and SMP (Supplementary Multilingual Plane) + * according to + * http://unicode.org/Public/UNIDATA/extracted/DerivedBidiClass.txt and + * http://www.unicode.org/roadmaps/ + */ + +#define IS_IN_BMP_RTL_BLOCK(c) ((0x590 <= (c)) && ((c) <= 0x8ff)) +#define IS_RTL_PRESENTATION_FORM(c) \ + (((0xfb1d <= (c)) && ((c) <= 0xfdff)) || ((0xfe70 <= (c)) && ((c) <= 0xfefe))) +#define IS_IN_SMP_RTL_BLOCK(c) \ + (((0x10800 <= (c)) && ((c) <= 0x10fff)) || \ + ((0x1e800 <= (c)) && ((c) <= 0x1eFFF))) +// Due to the supplementary-plane RTL blocks being identifiable from the +// high surrogate without examining the low surrogate, it is correct to +// use this by-code-unit check on potentially astral text without doing +// the math to decode surrogate pairs into code points. However, unpaired +// high surrogates that are RTL high surrogates then count as RTL even +// though, if replaced by the REPLACEMENT CHARACTER, it would not be +// RTL. +#define UTF16_CODE_UNIT_IS_BIDI(c) \ + ((IS_IN_BMP_RTL_BLOCK(c)) || (IS_RTL_PRESENTATION_FORM(c)) || \ + (c) == 0xD802 || (c) == 0xD803 || (c) == 0xD83A || (c) == 0xD83B) +#define UTF32_CHAR_IS_BIDI(c) \ + ((IS_IN_BMP_RTL_BLOCK(c)) || (IS_RTL_PRESENTATION_FORM(c)) || \ + (IS_IN_SMP_RTL_BLOCK(c))) +#endif /* nsBidiUtils_h__ */ diff --git a/intl/unicharutil/util/nsSpecialCasingData.cpp b/intl/unicharutil/util/nsSpecialCasingData.cpp new file mode 100644 index 0000000000..e23346f934 --- /dev/null +++ b/intl/unicharutil/util/nsSpecialCasingData.cpp @@ -0,0 +1,202 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Auto-generated from files in the Unicode Character Database + by genSpecialCasingData.pl - do not edit! */ + +#include "nsSpecialCasingData.h" +#include "mozilla/ArrayUtils.h" // for ArrayLength +#include <stdlib.h> // for bsearch + +/* SpecialCasing-13.0.0.txt */ +/* Date: 2019-09-08, 23:31:24 GMT */ + +using mozilla::unicode::MultiCharMapping; + +static const MultiCharMapping CaseSpecials_Lower[] = { + { 0x0130, {0x0069, 0x0307, 0x0000} }, // LATIN CAPITAL LETTER I WITH DOT ABOVE +}; + +static const MultiCharMapping CaseSpecials_Upper[] = { + { 0x00df, {0x0053, 0x0053, 0x0000} }, // LATIN SMALL LETTER SHARP S + { 0x0149, {0x02bc, 0x004e, 0x0000} }, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + { 0x01f0, {0x004a, 0x030c, 0x0000} }, // LATIN SMALL LETTER J WITH CARON + { 0x0390, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + { 0x03b0, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + { 0x0587, {0x0535, 0x0552, 0x0000} }, // ARMENIAN SMALL LIGATURE ECH YIWN + { 0x1e96, {0x0048, 0x0331, 0x0000} }, // LATIN SMALL LETTER H WITH LINE BELOW + { 0x1e97, {0x0054, 0x0308, 0x0000} }, // LATIN SMALL LETTER T WITH DIAERESIS + { 0x1e98, {0x0057, 0x030a, 0x0000} }, // LATIN SMALL LETTER W WITH RING ABOVE + { 0x1e99, {0x0059, 0x030a, 0x0000} }, // LATIN SMALL LETTER Y WITH RING ABOVE + { 0x1e9a, {0x0041, 0x02be, 0x0000} }, // LATIN SMALL LETTER A WITH RIGHT HALF RING + { 0x1f50, {0x03a5, 0x0313, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PSILI + { 0x1f52, {0x03a5, 0x0313, 0x0300} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA + { 0x1f54, {0x03a5, 0x0313, 0x0301} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA + { 0x1f56, {0x03a5, 0x0313, 0x0342} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI + { 0x1f80, {0x1f08, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI + { 0x1f81, {0x1f09, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI + { 0x1f82, {0x1f0a, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI + { 0x1f83, {0x1f0b, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI + { 0x1f84, {0x1f0c, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI + { 0x1f85, {0x1f0d, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI + { 0x1f86, {0x1f0e, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI + { 0x1f87, {0x1f0f, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI + { 0x1f88, {0x1f08, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI + { 0x1f89, {0x1f09, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI + { 0x1f8a, {0x1f0a, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI + { 0x1f8b, {0x1f0b, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI + { 0x1f8c, {0x1f0c, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI + { 0x1f8d, {0x1f0d, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI + { 0x1f8e, {0x1f0e, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1f8f, {0x1f0f, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1f90, {0x1f28, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI + { 0x1f91, {0x1f29, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI + { 0x1f92, {0x1f2a, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI + { 0x1f93, {0x1f2b, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI + { 0x1f94, {0x1f2c, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI + { 0x1f95, {0x1f2d, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI + { 0x1f96, {0x1f2e, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI + { 0x1f97, {0x1f2f, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI + { 0x1f98, {0x1f28, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI + { 0x1f99, {0x1f29, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI + { 0x1f9a, {0x1f2a, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI + { 0x1f9b, {0x1f2b, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI + { 0x1f9c, {0x1f2c, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI + { 0x1f9d, {0x1f2d, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI + { 0x1f9e, {0x1f2e, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1f9f, {0x1f2f, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1fa0, {0x1f68, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI + { 0x1fa1, {0x1f69, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI + { 0x1fa2, {0x1f6a, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI + { 0x1fa3, {0x1f6b, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI + { 0x1fa4, {0x1f6c, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI + { 0x1fa5, {0x1f6d, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI + { 0x1fa6, {0x1f6e, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI + { 0x1fa7, {0x1f6f, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI + { 0x1fa8, {0x1f68, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI + { 0x1fa9, {0x1f69, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI + { 0x1faa, {0x1f6a, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI + { 0x1fab, {0x1f6b, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI + { 0x1fac, {0x1f6c, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI + { 0x1fad, {0x1f6d, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI + { 0x1fae, {0x1f6e, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1faf, {0x1f6f, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI + { 0x1fb2, {0x1fba, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI + { 0x1fb3, {0x0391, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI + { 0x1fb4, {0x0386, 0x0399, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI + { 0x1fb6, {0x0391, 0x0342, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI + { 0x1fb7, {0x0391, 0x0342, 0x0399} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI + { 0x1fbc, {0x0391, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI + { 0x1fc2, {0x1fca, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI + { 0x1fc3, {0x0397, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI + { 0x1fc4, {0x0389, 0x0399, 0x0000} }, // GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI + { 0x1fc6, {0x0397, 0x0342, 0x0000} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI + { 0x1fc7, {0x0397, 0x0342, 0x0399} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI + { 0x1fcc, {0x0397, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI + { 0x1fd2, {0x03aa, 0x0300, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA + { 0x1fd3, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA + { 0x1fd6, {0x0399, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH PERISPOMENI + { 0x1fd7, {0x03aa, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI + { 0x1fe2, {0x03ab, 0x0300, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA + { 0x1fe3, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA + { 0x1fe4, {0x03a1, 0x0313, 0x0000} }, // GREEK SMALL LETTER RHO WITH PSILI + { 0x1fe6, {0x03a5, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PERISPOMENI + { 0x1fe7, {0x03ab, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI + { 0x1ff2, {0x1ffa, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI + { 0x1ff3, {0x03a9, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI + { 0x1ff4, {0x038f, 0x0399, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI + { 0x1ff6, {0x03a9, 0x0342, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI + { 0x1ff7, {0x03a9, 0x0342, 0x0399} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI + { 0x1ffc, {0x03a9, 0x0399, 0x0000} }, // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI + { 0xfb00, {0x0046, 0x0046, 0x0000} }, // LATIN SMALL LIGATURE FF + { 0xfb01, {0x0046, 0x0049, 0x0000} }, // LATIN SMALL LIGATURE FI + { 0xfb02, {0x0046, 0x004c, 0x0000} }, // LATIN SMALL LIGATURE FL + { 0xfb03, {0x0046, 0x0046, 0x0049} }, // LATIN SMALL LIGATURE FFI + { 0xfb04, {0x0046, 0x0046, 0x004c} }, // LATIN SMALL LIGATURE FFL + { 0xfb05, {0x0053, 0x0054, 0x0000} }, // LATIN SMALL LIGATURE LONG S T + { 0xfb06, {0x0053, 0x0054, 0x0000} }, // LATIN SMALL LIGATURE ST + { 0xfb13, {0x0544, 0x0546, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN NOW + { 0xfb14, {0x0544, 0x0535, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN ECH + { 0xfb15, {0x0544, 0x053b, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN INI + { 0xfb16, {0x054e, 0x0546, 0x0000} }, // ARMENIAN SMALL LIGATURE VEW NOW + { 0xfb17, {0x0544, 0x053d, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN XEH +}; + +static const MultiCharMapping CaseSpecials_Title[] = { + { 0x00df, {0x0053, 0x0073, 0x0000} }, // LATIN SMALL LETTER SHARP S + { 0x0149, {0x02bc, 0x004e, 0x0000} }, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + { 0x01f0, {0x004a, 0x030c, 0x0000} }, // LATIN SMALL LETTER J WITH CARON + { 0x0390, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + { 0x03b0, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + { 0x0587, {0x0535, 0x0582, 0x0000} }, // ARMENIAN SMALL LIGATURE ECH YIWN + { 0x1e96, {0x0048, 0x0331, 0x0000} }, // LATIN SMALL LETTER H WITH LINE BELOW + { 0x1e97, {0x0054, 0x0308, 0x0000} }, // LATIN SMALL LETTER T WITH DIAERESIS + { 0x1e98, {0x0057, 0x030a, 0x0000} }, // LATIN SMALL LETTER W WITH RING ABOVE + { 0x1e99, {0x0059, 0x030a, 0x0000} }, // LATIN SMALL LETTER Y WITH RING ABOVE + { 0x1e9a, {0x0041, 0x02be, 0x0000} }, // LATIN SMALL LETTER A WITH RIGHT HALF RING + { 0x1f50, {0x03a5, 0x0313, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PSILI + { 0x1f52, {0x03a5, 0x0313, 0x0300} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA + { 0x1f54, {0x03a5, 0x0313, 0x0301} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA + { 0x1f56, {0x03a5, 0x0313, 0x0342} }, // GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI + { 0x1fb2, {0x1fba, 0x0345, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI + { 0x1fb4, {0x0386, 0x0345, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI + { 0x1fb6, {0x0391, 0x0342, 0x0000} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI + { 0x1fb7, {0x0391, 0x0342, 0x0345} }, // GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI + { 0x1fc2, {0x1fca, 0x0345, 0x0000} }, // GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI + { 0x1fc4, {0x0389, 0x0345, 0x0000} }, // GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI + { 0x1fc6, {0x0397, 0x0342, 0x0000} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI + { 0x1fc7, {0x0397, 0x0342, 0x0345} }, // GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI + { 0x1fd2, {0x03aa, 0x0300, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA + { 0x1fd3, {0x03aa, 0x0301, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA + { 0x1fd6, {0x0399, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH PERISPOMENI + { 0x1fd7, {0x03aa, 0x0342, 0x0000} }, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI + { 0x1fe2, {0x03ab, 0x0300, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA + { 0x1fe3, {0x03ab, 0x0301, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA + { 0x1fe4, {0x03a1, 0x0313, 0x0000} }, // GREEK SMALL LETTER RHO WITH PSILI + { 0x1fe6, {0x03a5, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH PERISPOMENI + { 0x1fe7, {0x03ab, 0x0342, 0x0000} }, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI + { 0x1ff2, {0x1ffa, 0x0345, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI + { 0x1ff4, {0x038f, 0x0345, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI + { 0x1ff6, {0x03a9, 0x0342, 0x0000} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI + { 0x1ff7, {0x03a9, 0x0342, 0x0345} }, // GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI + { 0xfb00, {0x0046, 0x0066, 0x0000} }, // LATIN SMALL LIGATURE FF + { 0xfb01, {0x0046, 0x0069, 0x0000} }, // LATIN SMALL LIGATURE FI + { 0xfb02, {0x0046, 0x006c, 0x0000} }, // LATIN SMALL LIGATURE FL + { 0xfb03, {0x0046, 0x0066, 0x0069} }, // LATIN SMALL LIGATURE FFI + { 0xfb04, {0x0046, 0x0066, 0x006c} }, // LATIN SMALL LIGATURE FFL + { 0xfb05, {0x0053, 0x0074, 0x0000} }, // LATIN SMALL LIGATURE LONG S T + { 0xfb06, {0x0053, 0x0074, 0x0000} }, // LATIN SMALL LIGATURE ST + { 0xfb13, {0x0544, 0x0576, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN NOW + { 0xfb14, {0x0544, 0x0565, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN ECH + { 0xfb15, {0x0544, 0x056b, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN INI + { 0xfb16, {0x054e, 0x0576, 0x0000} }, // ARMENIAN SMALL LIGATURE VEW NOW + { 0xfb17, {0x0544, 0x056d, 0x0000} }, // ARMENIAN SMALL LIGATURE MEN XEH +}; + +static int CompareMCM(const void* aKey, const void* aElement) +{ + const uint32_t ch = *static_cast<const uint32_t*>(aKey); + const MultiCharMapping* mcm = static_cast<const MultiCharMapping*>(aElement); + return int(ch) - int(mcm->mOriginalChar); +} + +#define MAKE_SPECIAL_CASE_ACCESSOR(which) \ + const MultiCharMapping* \ + Special##which(uint32_t aChar) \ + { \ + const void* p = bsearch(&aChar, CaseSpecials_##which, \ + mozilla::ArrayLength(CaseSpecials_##which), \ + sizeof(MultiCharMapping), CompareMCM); \ + return static_cast<const MultiCharMapping*>(p); \ + } + +namespace mozilla { +namespace unicode { + +MAKE_SPECIAL_CASE_ACCESSOR(Lower) +MAKE_SPECIAL_CASE_ACCESSOR(Upper) +MAKE_SPECIAL_CASE_ACCESSOR(Title) + +} // namespace unicode +} // namespace mozilla diff --git a/intl/unicharutil/util/nsSpecialCasingData.h b/intl/unicharutil/util/nsSpecialCasingData.h new file mode 100644 index 0000000000..b0ba4d7dcc --- /dev/null +++ b/intl/unicharutil/util/nsSpecialCasingData.h @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdint.h> + +namespace mozilla { +namespace unicode { + +// Multi-character mappings (from SpecialCasing.txt) map a single Unicode +// value to a sequence of 2 or 3 Unicode characters. There are currently none +// defined outside the BMP, so we can use char16_t here. Unused trailing +// positions in mMappedChars are set to 0. +struct MultiCharMapping { + char16_t mOriginalChar; + char16_t mMappedChars[3]; +}; + +// Return a pointer to the special case mapping for the given character; +// returns nullptr if no such mapping is defined. +const MultiCharMapping* SpecialUpper(uint32_t aCh); +const MultiCharMapping* SpecialLower(uint32_t aCh); +const MultiCharMapping* SpecialTitle(uint32_t aCh); + +} // namespace unicode +} // namespace mozilla diff --git a/intl/unicharutil/util/nsUnicharUtils.cpp b/intl/unicharutil/util/nsUnicharUtils.cpp new file mode 100644 index 0000000000..fb4c4f8d2c --- /dev/null +++ b/intl/unicharutil/util/nsUnicharUtils.cpp @@ -0,0 +1,521 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsUnicharUtils.h" +#include "nsUTF8Utils.h" +#include "nsUnicodeProperties.h" +#include "mozilla/Likely.h" +#include "mozilla/HashFunctions.h" + +// We map x -> x, except for upper-case letters, +// which we map to their lower-case equivalents. +static const uint8_t gASCIIToLower[128] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, + 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, +}; + +// We want ToLowerCase(uint32_t) and ToLowerCaseASCII(uint32_t) to be fast +// when they're called from within the case-insensitive comparators, so we +// define inlined versions. +static MOZ_ALWAYS_INLINE uint32_t ToLowerCase_inline(uint32_t aChar) { + if (IS_ASCII(aChar)) { + return gASCIIToLower[aChar]; + } + + return mozilla::unicode::GetLowercase(aChar); +} + +static MOZ_ALWAYS_INLINE uint32_t +ToLowerCaseASCII_inline(const uint32_t aChar) { + if (IS_ASCII(aChar)) { + return gASCIIToLower[aChar]; + } + + return aChar; +} + +void ToLowerCase(nsAString& aString) { + char16_t* buf = aString.BeginWriting(); + ToLowerCase(buf, buf, aString.Length()); +} + +void ToLowerCaseASCII(nsAString& aString) { + char16_t* buf = aString.BeginWriting(); + ToLowerCaseASCII(buf, buf, aString.Length()); +} + +char ToLowerCaseASCII(char aChar) { + if (aChar >= 'A' && aChar <= 'Z') { + return aChar + 0x20; + } + return aChar; +} + +char16_t ToLowerCaseASCII(char16_t aChar) { + if (aChar >= 'A' && aChar <= 'Z') { + return aChar + 0x20; + } + return aChar; +} + +char32_t ToLowerCaseASCII(char32_t aChar) { + if (aChar >= 'A' && aChar <= 'Z') { + return aChar + 0x20; + } + return aChar; +} + +char ToUpperCaseASCII(char aChar) { + if (aChar >= 'a' && aChar <= 'z') { + return aChar - 0x20; + } + return aChar; +} + +char16_t ToUpperCaseASCII(char16_t aChar) { + if (aChar >= 'a' && aChar <= 'z') { + return aChar - 0x20; + } + return aChar; +} + +char32_t ToUpperCaseASCII(char32_t aChar) { + if (aChar >= 'a' && aChar <= 'z') { + return aChar - 0x20; + } + return aChar; +} + +void ToLowerCase(const nsAString& aSource, nsAString& aDest) { + const char16_t* in = aSource.BeginReading(); + uint32_t len = aSource.Length(); + + aDest.SetLength(len); + char16_t* out = aDest.BeginWriting(); + + ToLowerCase(in, out, len); +} + +void ToLowerCaseASCII(const nsAString& aSource, nsAString& aDest) { + const char16_t* in = aSource.BeginReading(); + uint32_t len = aSource.Length(); + + aDest.SetLength(len); + char16_t* out = aDest.BeginWriting(); + + ToLowerCaseASCII(in, out, len); +} + +uint32_t ToLowerCaseASCII(const uint32_t aChar) { + return ToLowerCaseASCII_inline(aChar); +} + +void ToUpperCase(nsAString& aString) { + char16_t* buf = aString.BeginWriting(); + ToUpperCase(buf, buf, aString.Length()); +} + +void ToUpperCase(const nsAString& aSource, nsAString& aDest) { + const char16_t* in = aSource.BeginReading(); + uint32_t len = aSource.Length(); + + aDest.SetLength(len); + char16_t* out = aDest.BeginWriting(); + + ToUpperCase(in, out, len); +} + +#ifdef MOZILLA_INTERNAL_API + +uint32_t ToFoldedCase(uint32_t aChar) { + if (IS_ASCII(aChar)) return gASCIIToLower[aChar]; + return mozilla::unicode::GetFoldedcase(aChar); +} + +void ToFoldedCase(nsAString& aString) { + char16_t* buf = aString.BeginWriting(); + ToFoldedCase(buf, buf, aString.Length()); +} + +void ToFoldedCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen) { + for (uint32_t i = 0; i < aLen; i++) { + uint32_t ch = aIn[i]; + if (i < aLen - 1 && NS_IS_SURROGATE_PAIR(ch, aIn[i + 1])) { + ch = mozilla::unicode::GetFoldedcase(SURROGATE_TO_UCS4(ch, aIn[i + 1])); + NS_ASSERTION(!IS_IN_BMP(ch), "case mapping crossed BMP/SMP boundary!"); + aOut[i++] = H_SURROGATE(ch); + aOut[i] = L_SURROGATE(ch); + continue; + } + aOut[i] = ToFoldedCase(ch); + } +} + +uint32_t ToNaked(uint32_t aChar) { + if (IS_ASCII(aChar)) { + return aChar; + } + return mozilla::unicode::GetNaked(aChar); +} + +void ToNaked(nsAString& aString) { + uint32_t i = 0; + while (i < aString.Length()) { + uint32_t ch = aString[i]; + if (i < aString.Length() - 1 && NS_IS_SURROGATE_PAIR(ch, aString[i + 1])) { + ch = SURROGATE_TO_UCS4(ch, aString[i + 1]); + if (mozilla::unicode::IsCombiningDiacritic(ch)) { + aString.Cut(i, 2); + } else { + ch = mozilla::unicode::GetNaked(ch); + NS_ASSERTION(!IS_IN_BMP(ch), "stripping crossed BMP/SMP boundary!"); + aString.Replace(i++, 1, H_SURROGATE(ch)); + aString.Replace(i++, 1, L_SURROGATE(ch)); + } + continue; + } + if (mozilla::unicode::IsCombiningDiacritic(ch)) { + aString.Cut(i, 1); + } else { + aString.Replace(i++, 1, ToNaked(ch)); + } + } +} + +int32_t nsCaseInsensitiveStringComparator(const char16_t* lhs, + const char16_t* rhs, uint32_t lLength, + uint32_t rLength) { + return (lLength == rLength) ? CaseInsensitiveCompare(lhs, rhs, lLength) + : (lLength > rLength) ? 1 + : -1; +} + +int32_t nsCaseInsensitiveUTF8StringComparator(const char* lhs, const char* rhs, + uint32_t lLength, + uint32_t rLength) { + return CaseInsensitiveCompare(lhs, rhs, lLength, rLength); +} + +int32_t nsASCIICaseInsensitiveStringComparator(const char16_t* lhs, + const char16_t* rhs, + uint32_t lLength, + uint32_t rLength) { + if (lLength != rLength) { + if (lLength > rLength) return 1; + return -1; + } + + while (rLength) { + // we don't care about surrogates here, because we're only + // lowercasing the ASCII range + char16_t l = *lhs++; + char16_t r = *rhs++; + if (l != r) { + l = ToLowerCaseASCII_inline(l); + r = ToLowerCaseASCII_inline(r); + + if (l > r) + return 1; + else if (r > l) + return -1; + } + rLength--; + } + + return 0; +} + +#endif // MOZILLA_INTERNAL_API + +uint32_t ToLowerCase(uint32_t aChar) { return ToLowerCase_inline(aChar); } + +void ToLowerCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen) { + for (uint32_t i = 0; i < aLen; i++) { + uint32_t ch = aIn[i]; + if (i < aLen - 1 && NS_IS_SURROGATE_PAIR(ch, aIn[i + 1])) { + ch = mozilla::unicode::GetLowercase(SURROGATE_TO_UCS4(ch, aIn[i + 1])); + NS_ASSERTION(!IS_IN_BMP(ch), "case mapping crossed BMP/SMP boundary!"); + aOut[i++] = H_SURROGATE(ch); + aOut[i] = L_SURROGATE(ch); + continue; + } + aOut[i] = ToLowerCase(ch); + } +} + +void ToLowerCaseASCII(const char16_t* aIn, char16_t* aOut, uint32_t aLen) { + for (uint32_t i = 0; i < aLen; i++) { + char16_t ch = aIn[i]; + aOut[i] = IS_ASCII_UPPER(ch) ? (ch + 0x20) : ch; + } +} + +uint32_t ToUpperCase(uint32_t aChar) { + if (IS_ASCII(aChar)) { + if (IS_ASCII_LOWER(aChar)) { + return aChar - 0x20; + } + return aChar; + } + + return mozilla::unicode::GetUppercase(aChar); +} + +void ToUpperCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen) { + for (uint32_t i = 0; i < aLen; i++) { + uint32_t ch = aIn[i]; + if (i < aLen - 1 && NS_IS_SURROGATE_PAIR(ch, aIn[i + 1])) { + ch = mozilla::unicode::GetUppercase(SURROGATE_TO_UCS4(ch, aIn[i + 1])); + NS_ASSERTION(!IS_IN_BMP(ch), "case mapping crossed BMP/SMP boundary!"); + aOut[i++] = H_SURROGATE(ch); + aOut[i] = L_SURROGATE(ch); + continue; + } + aOut[i] = ToUpperCase(ch); + } +} + +uint32_t ToTitleCase(uint32_t aChar) { + if (IS_ASCII(aChar)) { + return ToUpperCase(aChar); + } + + return mozilla::unicode::GetTitlecaseForLower(aChar); +} + +int32_t CaseInsensitiveCompare(const char16_t* a, const char16_t* b, + uint32_t len) { + NS_ASSERTION(a && b, "Do not pass in invalid pointers!"); + + if (len) { + do { + uint32_t c1 = *a++; + uint32_t c2 = *b++; + + // Unfortunately, we need to check for surrogates BEFORE we check + // for equality, because we could have identical high surrogates + // but non-identical characters, so we can't just skip them + + // If c1 isn't a surrogate, we don't bother to check c2; + // in the case where it _is_ a surrogate, we're definitely going to get + // a mismatch, and don't need to interpret and lowercase it + + if (len > 1 && NS_IS_SURROGATE_PAIR(c1, *a)) { + c1 = SURROGATE_TO_UCS4(c1, *a++); + if (NS_IS_SURROGATE_PAIR(c2, *b)) { + c2 = SURROGATE_TO_UCS4(c2, *b++); + } + // If c2 wasn't a surrogate, decrementing len means we'd stop + // short of the end of string b, but that doesn't actually matter + // because we're going to find a mismatch and return early + --len; + } + + if (c1 != c2) { + c1 = ToLowerCase_inline(c1); + c2 = ToLowerCase_inline(c2); + if (c1 != c2) { + if (c1 < c2) { + return -1; + } + return 1; + } + } + } while (--len != 0); + } + return 0; +} + +// Inlined definition of GetLowerUTF8Codepoint, which we use because we want +// to be fast when called from the case-insensitive comparators. +static MOZ_ALWAYS_INLINE uint32_t GetLowerUTF8Codepoint_inline( + const char* aStr, const char* aEnd, const char** aNext) { + // Convert to unsigned char so that stuffing chars into PRUint32s doesn't + // sign extend. + const unsigned char* str = (unsigned char*)aStr; + + if (UTF8traits::isASCII(str[0])) { + // It's ASCII; just convert to lower-case and return it. + *aNext = aStr + 1; + return gASCIIToLower[*str]; + } + if (UTF8traits::is2byte(str[0]) && MOZ_LIKELY(aStr + 1 < aEnd)) { + // It's a two-byte sequence, so it looks like + // 110XXXXX 10XXXXXX. + // This is definitely in the BMP, so we can store straightaway into a + // uint16_t. + + uint16_t c; + c = (str[0] & 0x1F) << 6; + c += (str[1] & 0x3F); + + // we don't go through ToLowerCase here, because we know this isn't + // an ASCII character so the ASCII fast-path there is useless + c = mozilla::unicode::GetLowercase(c); + + *aNext = aStr + 2; + return c; + } + if (UTF8traits::is3byte(str[0]) && MOZ_LIKELY(aStr + 2 < aEnd)) { + // It's a three-byte sequence, so it looks like + // 1110XXXX 10XXXXXX 10XXXXXX. + // This will just barely fit into 16-bits, so store into a uint16_t. + + uint16_t c; + c = (str[0] & 0x0F) << 12; + c += (str[1] & 0x3F) << 6; + c += (str[2] & 0x3F); + + c = mozilla::unicode::GetLowercase(c); + + *aNext = aStr + 3; + return c; + } + if (UTF8traits::is4byte(str[0]) && MOZ_LIKELY(aStr + 3 < aEnd)) { + // It's a four-byte sequence, so it looks like + // 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX. + + uint32_t c; + c = (str[0] & 0x07) << 18; + c += (str[1] & 0x3F) << 12; + c += (str[2] & 0x3F) << 6; + c += (str[3] & 0x3F); + + c = mozilla::unicode::GetLowercase(c); + + *aNext = aStr + 4; + return c; + } + + // Hm, we don't understand this sequence. + return -1; +} + +uint32_t GetLowerUTF8Codepoint(const char* aStr, const char* aEnd, + const char** aNext) { + return GetLowerUTF8Codepoint_inline(aStr, aEnd, aNext); +} + +int32_t CaseInsensitiveCompare(const char* aLeft, const char* aRight, + uint32_t aLeftBytes, uint32_t aRightBytes) { + const char* leftEnd = aLeft + aLeftBytes; + const char* rightEnd = aRight + aRightBytes; + + while (aLeft < leftEnd && aRight < rightEnd) { + uint32_t leftChar = GetLowerUTF8Codepoint_inline(aLeft, leftEnd, &aLeft); + if (MOZ_UNLIKELY(leftChar == uint32_t(-1))) return -1; + + uint32_t rightChar = + GetLowerUTF8Codepoint_inline(aRight, rightEnd, &aRight); + if (MOZ_UNLIKELY(rightChar == uint32_t(-1))) return -1; + + // Now leftChar and rightChar are lower-case, so we can compare them. + if (leftChar != rightChar) { + if (leftChar > rightChar) return 1; + return -1; + } + } + + // Make sure that if one string is longer than the other we return the + // correct result. + if (aLeft < leftEnd) return 1; + if (aRight < rightEnd) return -1; + + return 0; +} + +static MOZ_ALWAYS_INLINE uint32_t +GetLowerUTF8Codepoint_inline(const char* aStr, const char* aEnd, + const char** aNext, bool aMatchDiacritics) { + uint32_t c; + for (;;) { + c = GetLowerUTF8Codepoint_inline(aStr, aEnd, aNext); + if (aMatchDiacritics) { + break; + } + if (!mozilla::unicode::IsCombiningDiacritic(c)) { + break; + } + aStr = *aNext; + } + return c; +} + +bool CaseInsensitiveUTF8CharsEqual(const char* aLeft, const char* aRight, + const char* aLeftEnd, const char* aRightEnd, + const char** aLeftNext, + const char** aRightNext, bool* aErr, + bool aMatchDiacritics) { + NS_ASSERTION(aLeftNext, "Out pointer shouldn't be null."); + NS_ASSERTION(aRightNext, "Out pointer shouldn't be null."); + NS_ASSERTION(aErr, "Out pointer shouldn't be null."); + NS_ASSERTION(aLeft < aLeftEnd, "aLeft must be less than aLeftEnd."); + NS_ASSERTION(aRight < aRightEnd, "aRight must be less than aRightEnd."); + + uint32_t leftChar = GetLowerUTF8Codepoint_inline(aLeft, aLeftEnd, aLeftNext, + aMatchDiacritics); + if (MOZ_UNLIKELY(leftChar == uint32_t(-1))) { + *aErr = true; + return false; + } + + uint32_t rightChar = GetLowerUTF8Codepoint_inline( + aRight, aRightEnd, aRightNext, aMatchDiacritics); + if (MOZ_UNLIKELY(rightChar == uint32_t(-1))) { + *aErr = true; + return false; + } + + // Can't have an error past this point. + *aErr = false; + + if (!aMatchDiacritics) { + leftChar = ToNaked(leftChar); + rightChar = ToNaked(rightChar); + } + + return leftChar == rightChar; +} + +namespace mozilla { + +uint32_t HashUTF8AsUTF16(const char* aUTF8, uint32_t aLength, bool* aErr) { + uint32_t hash = 0; + const char* s = aUTF8; + const char* end = aUTF8 + aLength; + + *aErr = false; + + while (s < end) { + uint32_t ucs4 = UTF8CharEnumerator::NextChar(&s, end, aErr); + if (*aErr) { + return 0; + } + + if (ucs4 < PLANE1_BASE) { + hash = AddToHash(hash, ucs4); + } else { + hash = AddToHash(hash, H_SURROGATE(ucs4), L_SURROGATE(ucs4)); + } + } + + return hash; +} + +bool IsSegmentBreakSkipChar(uint32_t u) { + return unicode::IsEastAsianWidthFHWexcludingEmoji(u) && + unicode::GetScriptCode(u) != unicode::Script::HANGUL; +} + +} // namespace mozilla diff --git a/intl/unicharutil/util/nsUnicharUtils.h b/intl/unicharutil/util/nsUnicharUtils.h new file mode 100644 index 0000000000..ffbbabf2c6 --- /dev/null +++ b/intl/unicharutil/util/nsUnicharUtils.h @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsUnicharUtils_h__ +#define nsUnicharUtils_h__ + +#include "nsString.h" + +/* (0x3131u <= (u) && (u) <= 0x318eu) => Hangul Compatibility Jamo */ +/* (0xac00u <= (u) && (u) <= 0xd7a3u) => Hangul Syllables */ +#define IS_CJ_CHAR(u) \ + ((0x2e80u <= (u) && (u) <= 0x312fu) || (0x3190u <= (u) && (u) <= 0xabffu) || \ + (0xf900u <= (u) && (u) <= 0xfaffu) || (0xff00u <= (u) && (u) <= 0xffefu)) + +#define IS_ZERO_WIDTH_SPACE(u) ((u) == 0x200B) + +#define IS_ASCII(u) ((u) < 0x80) +#define IS_ASCII_UPPER(u) (('A' <= (u)) && ((u) <= 'Z')) +#define IS_ASCII_LOWER(u) (('a' <= (u)) && ((u) <= 'z')) +#define IS_ASCII_ALPHA(u) (IS_ASCII_UPPER(u) || IS_ASCII_LOWER(u)) +#define IS_ASCII_SPACE(u) (' ' == (u)) + +void ToLowerCase(nsAString& aString); +void ToLowerCaseASCII(nsAString& aString); +void ToUpperCase(nsAString& aString); + +void ToLowerCase(const nsAString& aSource, nsAString& aDest); +void ToLowerCaseASCII(const nsAString& aSource, nsAString& aDest); +void ToUpperCase(const nsAString& aSource, nsAString& aDest); + +uint32_t ToLowerCase(uint32_t aChar); +uint32_t ToUpperCase(uint32_t aChar); +uint32_t ToTitleCase(uint32_t aChar); + +void ToLowerCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen); +void ToLowerCaseASCII(const char16_t* aIn, char16_t* aOut, uint32_t aLen); +void ToUpperCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen); + +char ToLowerCaseASCII(const char aChar); +char16_t ToLowerCaseASCII(const char16_t aChar); +char32_t ToLowerCaseASCII(const char32_t aChar); + +char ToUpperCaseASCII(const char aChar); +char16_t ToUpperCaseASCII(const char16_t aChar); +char32_t ToUpperCaseASCII(const char32_t aChar); + +inline bool IsUpperCase(uint32_t c) { return ToLowerCase(c) != c; } + +inline bool IsLowerCase(uint32_t c) { return ToUpperCase(c) != c; } + +#ifdef MOZILLA_INTERNAL_API + +uint32_t ToFoldedCase(uint32_t aChar); +void ToFoldedCase(nsAString& aString); +void ToFoldedCase(const char16_t* aIn, char16_t* aOut, uint32_t aLen); + +uint32_t ToNaked(uint32_t aChar); +void ToNaked(nsAString& aString); + +int32_t nsCaseInsensitiveStringComparator(const char16_t*, const char16_t*, + uint32_t, uint32_t); + +int32_t nsCaseInsensitiveUTF8StringComparator(const char*, const char*, + uint32_t, uint32_t); + +class nsCaseInsensitiveStringArrayComparator { + public: + template <class A, class B> + bool Equals(const A& a, const B& b) const { + return a.Equals(b, nsCaseInsensitiveStringComparator); + } +}; + +int32_t nsASCIICaseInsensitiveStringComparator(const char16_t*, const char16_t*, + uint32_t, uint32_t); + +inline bool CaseInsensitiveFindInReadable( + const nsAString& aPattern, nsAString::const_iterator& aSearchStart, + nsAString::const_iterator& aSearchEnd) { + return FindInReadable(aPattern, aSearchStart, aSearchEnd, + nsCaseInsensitiveStringComparator); +} + +inline bool CaseInsensitiveFindInReadable(const nsAString& aPattern, + const nsAString& aHay) { + nsAString::const_iterator searchBegin, searchEnd; + return FindInReadable(aPattern, aHay.BeginReading(searchBegin), + aHay.EndReading(searchEnd), + nsCaseInsensitiveStringComparator); +} + +#endif // MOZILLA_INTERNAL_API + +int32_t CaseInsensitiveCompare(const char16_t* a, const char16_t* b, + uint32_t len); + +int32_t CaseInsensitiveCompare(const char* aLeft, const char* aRight, + uint32_t aLeftBytes, uint32_t aRightBytes); + +/** + * Calculates the lower-case of the codepoint of the UTF8 sequence starting at + * aStr. Sets aNext to the byte following the end of the sequence. + * + * If the sequence is invalid, or if computing the codepoint would take us off + * the end of the string (as marked by aEnd), returns -1 and does not set + * aNext. Note that this function doesn't check that aStr < aEnd -- it assumes + * you've done that already. + */ +uint32_t GetLowerUTF8Codepoint(const char* aStr, const char* aEnd, + const char** aNext); + +/** + * This function determines whether the UTF-8 sequence pointed to by aLeft is + * case insensitively equal to the UTF-8 sequence pointed to by aRight (or + * optionally, case and diacritic insensitively equal), as defined by having + * matching (naked) lower-cased codepoints. + * + * aLeftEnd marks the first memory location past aLeft that is not part of + * aLeft; aRightEnd similarly marks the end of aRight. + * + * The function assumes that aLeft < aLeftEnd and aRight < aRightEnd. + * + * The function stores the addresses of the next characters in the sequence + * into aLeftNext and aRightNext. It's up to the caller to make sure that the + * returned pointers are valid -- i.e. the function may return aLeftNext >= + * aLeftEnd or aRightNext >= aRightEnd. + * + * If the function encounters invalid text, it sets aErr to true and returns + * false, possibly leaving aLeftNext and aRightNext uninitialized. If the + * function returns true, aErr is guaranteed to be false and both aLeftNext and + * aRightNext are guaranteed to be initialized. + * + * If aMatchDiacritics is false, the comparison is neither case-sensitive nor + * diacritic-sensitive. + */ +bool CaseInsensitiveUTF8CharsEqual(const char* aLeft, const char* aRight, + const char* aLeftEnd, const char* aRightEnd, + const char** aLeftNext, + const char** aRightNext, bool* aErr, + bool aMatchDiacritics = true); + +namespace mozilla { + +/** + * Hash a UTF8 string as though it were a UTF16 string. + * + * The value returned is the same as if we converted the string to UTF16 and + * then ran HashString() on the result. + * + * The given |length| is in bytes. + */ +uint32_t HashUTF8AsUTF16(const char* aUTF8, uint32_t aLength, bool* aErr); + +bool IsSegmentBreakSkipChar(uint32_t u); + +} // namespace mozilla + +#endif /* nsUnicharUtils_h__ */ diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp new file mode 100644 index 0000000000..244b7818ca --- /dev/null +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -0,0 +1,387 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=4 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsUnicodeProperties.h" +#include "nsUnicodePropertyData.cpp" + +#include "mozilla/ArrayUtils.h" +#include "mozilla/HashTable.h" +#include "nsCharTraits.h" + +#include "unicode/uchar.h" +#include "unicode/unorm2.h" + +#define UNICODE_BMP_LIMIT 0x10000 +#define UNICODE_LIMIT 0x110000 + +const nsCharProps2& GetCharProps2(uint32_t aCh) { + if (aCh < UNICODE_BMP_LIMIT) { + return sCharProp2Values[sCharProp2Pages[0][aCh >> kCharProp2CharBits]] + [aCh & ((1 << kCharProp2CharBits) - 1)]; + } + if (aCh < (kCharProp2MaxPlane + 1) * 0x10000) { + return sCharProp2Values[sCharProp2Pages[sCharProp2Planes[(aCh >> 16) - 1]] + [(aCh & 0xffff) >> + kCharProp2CharBits]] + [aCh & ((1 << kCharProp2CharBits) - 1)]; + } + + MOZ_ASSERT_UNREACHABLE( + "Getting CharProps for codepoint outside Unicode " + "range"); + + // Default values for unassigned + using namespace mozilla::unicode; + static const nsCharProps2 undefined = { + VERTICAL_ORIENTATION_R, + 0 // IdentifierType + }; + return undefined; +} + +namespace mozilla { + +namespace unicode { + +/* +To store properties for a million Unicode codepoints compactly, we use +a three-level array structure, with the Unicode values considered as +three elements: Plane, Page, and Char. + +Space optimization happens because multiple Planes can refer to the same +Page array, and multiple Pages can refer to the same Char array holding +the actual values. In practice, most of the higher planes are empty and +thus share the same data; and within the BMP, there are also many pages +that repeat the same data for any given property. + +Plane is usually zero, so we skip a lookup in this case, and require +that the Plane 0 pages are always the first set of entries in the Page +array. + +The division of the remaining 16 bits into Page and Char fields is +adjusted for each property (by experiment using the generation tool) +to provide the most compact storage, depending on the distribution +of values. +*/ + +const nsUGenCategory sDetailedToGeneralCategory[] = { + // clang-format off + /* + * The order here corresponds to the HB_UNICODE_GENERAL_CATEGORY_* constants + * of the hb_unicode_general_category_t enum in gfx/harfbuzz/src/hb-unicode.h. + */ + /* CONTROL */ nsUGenCategory::kOther, + /* FORMAT */ nsUGenCategory::kOther, + /* UNASSIGNED */ nsUGenCategory::kOther, + /* PRIVATE_USE */ nsUGenCategory::kOther, + /* SURROGATE */ nsUGenCategory::kOther, + /* LOWERCASE_LETTER */ nsUGenCategory::kLetter, + /* MODIFIER_LETTER */ nsUGenCategory::kLetter, + /* OTHER_LETTER */ nsUGenCategory::kLetter, + /* TITLECASE_LETTER */ nsUGenCategory::kLetter, + /* UPPERCASE_LETTER */ nsUGenCategory::kLetter, + /* COMBINING_MARK */ nsUGenCategory::kMark, + /* ENCLOSING_MARK */ nsUGenCategory::kMark, + /* NON_SPACING_MARK */ nsUGenCategory::kMark, + /* DECIMAL_NUMBER */ nsUGenCategory::kNumber, + /* LETTER_NUMBER */ nsUGenCategory::kNumber, + /* OTHER_NUMBER */ nsUGenCategory::kNumber, + /* CONNECT_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* DASH_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* CLOSE_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* FINAL_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* INITIAL_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* OTHER_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* OPEN_PUNCTUATION */ nsUGenCategory::kPunctuation, + /* CURRENCY_SYMBOL */ nsUGenCategory::kSymbol, + /* MODIFIER_SYMBOL */ nsUGenCategory::kSymbol, + /* MATH_SYMBOL */ nsUGenCategory::kSymbol, + /* OTHER_SYMBOL */ nsUGenCategory::kSymbol, + /* LINE_SEPARATOR */ nsUGenCategory::kSeparator, + /* PARAGRAPH_SEPARATOR */ nsUGenCategory::kSeparator, + /* SPACE_SEPARATOR */ nsUGenCategory::kSeparator + // clang-format on +}; + +const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = { + // clang-format off + HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // U_GENERAL_OTHER_TYPES = 0, + HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, // U_UPPERCASE_LETTER = 1, + HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, // U_LOWERCASE_LETTER = 2, + HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, // U_TITLECASE_LETTER = 3, + HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, // U_MODIFIER_LETTER = 4, + HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, // U_OTHER_LETTER = 5, + HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, // U_NON_SPACING_MARK = 6, + HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, // U_ENCLOSING_MARK = 7, + HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, // U_COMBINING_SPACING_MARK = 8, + HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, // U_DECIMAL_DIGIT_NUMBER = 9, + HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, // U_LETTER_NUMBER = 10, + HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, // U_OTHER_NUMBER = 11, + HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, // U_SPACE_SEPARATOR = 12, + HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, // U_LINE_SEPARATOR = 13, + HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, // U_PARAGRAPH_SEPARATOR = 14, + HB_UNICODE_GENERAL_CATEGORY_CONTROL, // U_CONTROL_CHAR = 15, + HB_UNICODE_GENERAL_CATEGORY_FORMAT, // U_FORMAT_CHAR = 16, + HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, // U_PRIVATE_USE_CHAR = 17, + HB_UNICODE_GENERAL_CATEGORY_SURROGATE, // U_SURROGATE = 18, + HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, // U_DASH_PUNCTUATION = 19, + HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, // U_START_PUNCTUATION = 20, + HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, // U_END_PUNCTUATION = 21, + HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, // U_CONNECTOR_PUNCTUATION = 22, + HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, // U_OTHER_PUNCTUATION = 23, + HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, // U_MATH_SYMBOL = 24, + HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, // U_CURRENCY_SYMBOL = 25, + HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, // U_MODIFIER_SYMBOL = 26, + HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, // U_OTHER_SYMBOL = 27, + HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28, + HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29, + // clang-format on +}; + +#define DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(prefix_) \ + uint32_t Get##prefix_(uint32_t aCh) { \ + if (aCh >= UNICODE_BMP_LIMIT) { \ + return aCh; \ + } \ + auto page = s##prefix_##Pages[aCh >> k##prefix_##CharBits]; \ + auto index = aCh & ((1 << k##prefix_##CharBits) - 1); \ + uint32_t v = s##prefix_##Values[page][index]; \ + return v ? v : aCh; \ + } + +// full-width mappings only exist for BMP characters; all others are +// returned unchanged +DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(FullWidth) +DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(FullWidthInverse) + +bool IsClusterExtender(uint32_t aCh, uint8_t aCategory) { + return ( + (aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK && + aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) || + (aCh >= 0x200c && aCh <= 0x200d) || // ZWJ, ZWNJ + (aCh >= 0xff9e && aCh <= 0xff9f) || // katakana sound marks + (aCh >= 0x1F3FB && aCh <= 0x1F3FF) || // fitzpatrick skin tone modifiers + (aCh >= 0xe0020 && aCh <= 0xe007f)); // emoji (flag) tag characters +} + +enum HSType { + HST_NONE = U_HST_NOT_APPLICABLE, + HST_L = U_HST_LEADING_JAMO, + HST_V = U_HST_VOWEL_JAMO, + HST_T = U_HST_TRAILING_JAMO, + HST_LV = U_HST_LV_SYLLABLE, + HST_LVT = U_HST_LVT_SYLLABLE +}; + +static HSType GetHangulSyllableType(uint32_t aCh) { + return HSType(u_getIntPropertyValue(aCh, UCHAR_HANGUL_SYLLABLE_TYPE)); +} + +void ClusterIterator::Next() { + if (AtEnd()) { + NS_WARNING("ClusterIterator has already reached the end"); + return; + } + + uint32_t ch = *mPos++; + + if (mPos < mLimit && NS_IS_SURROGATE_PAIR(ch, *mPos)) { + ch = SURROGATE_TO_UCS4(ch, *mPos++); + } else if ((ch & ~0xff) == 0x1100 || (ch >= 0xa960 && ch <= 0xa97f) || + (ch >= 0xac00 && ch <= 0xd7ff)) { + // Handle conjoining Jamo that make Hangul syllables + HSType hangulState = GetHangulSyllableType(ch); + while (mPos < mLimit) { + ch = *mPos; + HSType hangulType = GetHangulSyllableType(ch); + switch (hangulType) { + case HST_L: + case HST_LV: + case HST_LVT: + if (hangulState == HST_L) { + hangulState = hangulType; + mPos++; + continue; + } + break; + case HST_V: + if ((hangulState != HST_NONE) && (hangulState != HST_T) && + (hangulState != HST_LVT)) { + hangulState = hangulType; + mPos++; + continue; + } + break; + case HST_T: + if (hangulState != HST_NONE && hangulState != HST_L) { + hangulState = hangulType; + mPos++; + continue; + } + break; + default: + break; + } + break; + } + } + + const uint32_t kVS16 = 0xfe0f; + const uint32_t kZWJ = 0x200d; + // UTF-16 surrogate values for Fitzpatrick type modifiers + const uint32_t kFitzpatrickHigh = 0xD83C; + const uint32_t kFitzpatrickLowFirst = 0xDFFB; + const uint32_t kFitzpatrickLowLast = 0xDFFF; + + bool baseIsEmoji = (GetEmojiPresentation(ch) == EmojiDefault) || + (GetEmojiPresentation(ch) == TextDefault && + ((mPos < mLimit && *mPos == kVS16) || + (mPos + 1 < mLimit && *mPos == kFitzpatrickHigh && + *(mPos + 1) >= kFitzpatrickLowFirst && + *(mPos + 1) <= kFitzpatrickLowLast))); + bool prevWasZwj = false; + + while (mPos < mLimit) { + ch = *mPos; + size_t chLen = 1; + + // Check for surrogate pairs; note that isolated surrogates will just + // be treated as generic (non-cluster-extending) characters here, + // which is fine for cluster-iterating purposes + if (mPos < mLimit - 1 && NS_IS_SURROGATE_PAIR(ch, *(mPos + 1))) { + ch = SURROGATE_TO_UCS4(ch, *(mPos + 1)); + chLen = 2; + } + + bool extendCluster = + IsClusterExtender(ch) || + (baseIsEmoji && prevWasZwj && + ((GetEmojiPresentation(ch) == EmojiDefault) || + (GetEmojiPresentation(ch) == TextDefault && mPos + chLen < mLimit && + *(mPos + chLen) == kVS16))); + if (!extendCluster) { + break; + } + + prevWasZwj = (ch == kZWJ); + mPos += chLen; + } + + NS_ASSERTION(mText < mPos && mPos <= mLimit, + "ClusterIterator::Next has overshot the string!"); +} + +void ClusterReverseIterator::Next() { + if (AtEnd()) { + NS_WARNING("ClusterReverseIterator has already reached the end"); + return; + } + + uint32_t ch; + do { + ch = *--mPos; + + if (mPos > mLimit && NS_IS_SURROGATE_PAIR(*(mPos - 1), ch)) { + ch = SURROGATE_TO_UCS4(*--mPos, ch); + } + + if (!IsClusterExtender(ch)) { + break; + } + } while (mPos > mLimit); + + // XXX May need to handle conjoining Jamo + + NS_ASSERTION(mPos >= mLimit, + "ClusterReverseIterator::Next has overshot the string!"); +} + +uint32_t CountGraphemeClusters(const char16_t* aText, uint32_t aLength) { + ClusterIterator iter(aText, aLength); + uint32_t result = 0; + while (!iter.AtEnd()) { + ++result; + iter.Next(); + } + return result; +} + +uint32_t GetNaked(uint32_t aCh) { + using namespace mozilla; + + static const UNormalizer2* normalizer; + static HashMap<uint32_t, uint32_t> nakedCharCache; + + NS_ASSERTION(!IsCombiningDiacritic(aCh), + "This character needs to be skipped"); + + HashMap<uint32_t, uint32_t>::Ptr entry = nakedCharCache.lookup(aCh); + if (entry.found()) { + return entry->value(); + } + + UErrorCode error = U_ZERO_ERROR; + if (!normalizer) { + normalizer = unorm2_getNFDInstance(&error); + if (U_FAILURE(error)) { + return aCh; + } + } + + static const size_t MAX_DECOMPOSITION_SIZE = 16; + UChar decomposition[MAX_DECOMPOSITION_SIZE]; + UChar* combiners; + int32_t decompositionLen; + uint32_t baseChar, nextChar; + decompositionLen = unorm2_getDecomposition(normalizer, aCh, decomposition, + MAX_DECOMPOSITION_SIZE, &error); + if (decompositionLen < 1) { + // The character does not decompose. + return aCh; + } + + if (NS_IS_HIGH_SURROGATE(decomposition[0])) { + baseChar = SURROGATE_TO_UCS4(decomposition[0], decomposition[1]); + combiners = decomposition + 2; + } else { + baseChar = decomposition[0]; + combiners = decomposition + 1; + } + + if (IS_IN_BMP(baseChar) != IS_IN_BMP(aCh)) { + // Mappings that would change the length of a UTF-16 string are not + // currently supported. + baseChar = aCh; + goto cache; + } + + if (decompositionLen > 1) { + if (NS_IS_HIGH_SURROGATE(combiners[0])) { + nextChar = SURROGATE_TO_UCS4(combiners[0], combiners[1]); + } else { + nextChar = combiners[0]; + } + if (!IsCombiningDiacritic(nextChar)) { + // Hangul syllables decompose but do not actually have diacritics. + // This also excludes decompositions with the Japanese marks U+3099 and + // U+309A (COMBINING KATAKANA-HIRAGANA [SEMI-]VOICED SOUND MARK), which + // we should not ignore for searching (bug 1624244). + baseChar = aCh; + } + } + +cache: + if (!nakedCharCache.putNew(aCh, baseChar)) { + // We're out of memory, so delete the cache to free some up. + nakedCharCache.clearAndCompact(); + } + + return baseChar; +} + +} // end namespace unicode + +} // end namespace mozilla diff --git a/intl/unicharutil/util/nsUnicodeProperties.h b/intl/unicharutil/util/nsUnicodeProperties.h new file mode 100644 index 0000000000..11566cbffc --- /dev/null +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=4 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NS_UNICODEPROPERTIES_H +#define NS_UNICODEPROPERTIES_H + +#include "nsBidiUtils.h" +#include "nsUGenCategory.h" +#include "nsUnicodeScriptCodes.h" +#include "harfbuzz/hb.h" + +#include "unicode/uchar.h" +#include "unicode/uscript.h" + +const nsCharProps2& GetCharProps2(uint32_t aCh); + +namespace mozilla { + +namespace unicode { + +extern const nsUGenCategory sDetailedToGeneralCategory[]; + +/* This MUST match the values assigned by genUnicodePropertyData.pl! */ +enum VerticalOrientation { + VERTICAL_ORIENTATION_U = 0, + VERTICAL_ORIENTATION_R = 1, + VERTICAL_ORIENTATION_Tu = 2, + VERTICAL_ORIENTATION_Tr = 3 +}; + +/* This MUST match the values assigned by genUnicodePropertyData.pl! */ +enum PairedBracketType { + PAIRED_BRACKET_TYPE_NONE = 0, + PAIRED_BRACKET_TYPE_OPEN = 1, + PAIRED_BRACKET_TYPE_CLOSE = 2 +}; + +/* Flags for Unicode security IdentifierType.txt attributes. Only a subset + of these are currently checked by Gecko, so we only define flags for the + ones we need. */ +enum IdentifierType { + IDTYPE_RESTRICTED = 0, + IDTYPE_ALLOWED = 1, +}; + +enum EmojiPresentation { TextOnly = 0, TextDefault = 1, EmojiDefault = 2 }; + +const uint32_t kVariationSelector15 = 0xFE0E; // text presentation +const uint32_t kVariationSelector16 = 0xFE0F; // emoji presentation + +// Unicode values for EMOJI MODIFIER FITZPATRICK TYPE-* +const uint32_t kEmojiSkinToneFirst = 0x1f3fb; +const uint32_t kEmojiSkinToneLast = 0x1f3ff; + +extern const hb_unicode_general_category_t sICUtoHBcategory[]; + +inline uint32_t GetMirroredChar(uint32_t aCh) { return u_charMirror(aCh); } + +inline bool HasMirroredChar(uint32_t aCh) { return u_isMirrored(aCh); } + +inline uint8_t GetCombiningClass(uint32_t aCh) { + return u_getCombiningClass(aCh); +} + +inline uint8_t GetGeneralCategory(uint32_t aCh) { + return sICUtoHBcategory[u_charType(aCh)]; +} + +inline nsCharType GetBidiCat(uint32_t aCh) { + return nsCharType(u_charDirection(aCh)); +} + +inline int8_t GetNumericValue(uint32_t aCh) { + UNumericType type = + UNumericType(u_getIntPropertyValue(aCh, UCHAR_NUMERIC_TYPE)); + return type == U_NT_DECIMAL || type == U_NT_DIGIT + ? int8_t(u_getNumericValue(aCh)) + : -1; +} + +inline uint8_t GetLineBreakClass(uint32_t aCh) { + return u_getIntPropertyValue(aCh, UCHAR_LINE_BREAK); +} + +inline Script GetScriptCode(uint32_t aCh) { + UErrorCode err = U_ZERO_ERROR; + return Script(uscript_getScript(aCh, &err)); +} + +inline bool HasScript(uint32_t aCh, Script aScript) { + return uscript_hasScript(aCh, UScriptCode(aScript)); +} + +inline uint32_t GetScriptTagForCode(Script aScriptCode) { + const char* tag = uscript_getShortName(UScriptCode(aScriptCode)); + if (tag) { + return HB_TAG(tag[0], tag[1], tag[2], tag[3]); + } + // return UNKNOWN script tag (running with older ICU?) + return HB_SCRIPT_UNKNOWN; +} + +inline PairedBracketType GetPairedBracketType(uint32_t aCh) { + return PairedBracketType( + u_getIntPropertyValue(aCh, UCHAR_BIDI_PAIRED_BRACKET_TYPE)); +} + +inline uint32_t GetPairedBracket(uint32_t aCh) { + return u_getBidiPairedBracket(aCh); +} + +inline uint32_t GetUppercase(uint32_t aCh) { return u_toupper(aCh); } + +inline uint32_t GetLowercase(uint32_t aCh) { return u_tolower(aCh); } + +inline uint32_t GetTitlecaseForLower( + uint32_t aCh) // maps LC to titlecase, UC unchanged +{ + return u_isULowercase(aCh) ? u_totitle(aCh) : aCh; +} + +inline uint32_t GetTitlecaseForAll( + uint32_t aCh) // maps both UC and LC to titlecase +{ + return u_totitle(aCh); +} + +inline uint32_t GetFoldedcase(uint32_t aCh) { + // Handle dotted capital I and dotless small i specially because we want to + // use a combination of ordinary case-folding rules and Turkish case-folding + // rules. + if (aCh == 0x0130 || aCh == 0x0131) { + return 'i'; + } + return u_foldCase(aCh, U_FOLD_CASE_DEFAULT); +} + +inline bool IsEastAsianWidthFHWexcludingEmoji(uint32_t aCh) { + switch (u_getIntPropertyValue(aCh, UCHAR_EAST_ASIAN_WIDTH)) { + case U_EA_FULLWIDTH: + case U_EA_HALFWIDTH: + return true; + case U_EA_WIDE: + return u_hasBinaryProperty(aCh, UCHAR_EMOJI) ? false : true; + case U_EA_AMBIGUOUS: + case U_EA_NARROW: + case U_EA_NEUTRAL: + return false; + } + return false; +} + +inline bool IsEastAsianWidthAFW(uint32_t aCh) { + switch (u_getIntPropertyValue(aCh, UCHAR_EAST_ASIAN_WIDTH)) { + case U_EA_AMBIGUOUS: + case U_EA_FULLWIDTH: + case U_EA_WIDE: + return true; + case U_EA_HALFWIDTH: + case U_EA_NARROW: + case U_EA_NEUTRAL: + return false; + } + return false; +} + +inline bool IsDefaultIgnorable(uint32_t aCh) { + return u_hasBinaryProperty(aCh, UCHAR_DEFAULT_IGNORABLE_CODE_POINT); +} + +inline EmojiPresentation GetEmojiPresentation(uint32_t aCh) { + if (!u_hasBinaryProperty(aCh, UCHAR_EMOJI)) { + return TextOnly; + } + + if (u_hasBinaryProperty(aCh, UCHAR_EMOJI_PRESENTATION)) { + return EmojiDefault; + } + return TextDefault; +} + +// returns the simplified Gen Category as defined in nsUGenCategory +inline nsUGenCategory GetGenCategory(uint32_t aCh) { + return sDetailedToGeneralCategory[GetGeneralCategory(aCh)]; +} + +inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) { + return VerticalOrientation(GetCharProps2(aCh).mVertOrient); +} + +inline IdentifierType GetIdentifierType(uint32_t aCh) { + return IdentifierType(GetCharProps2(aCh).mIdType); +} + +uint32_t GetFullWidth(uint32_t aCh); +// This is the reverse function of GetFullWidth which guarantees that +// for every codepoint c, GetFullWidthInverse(GetFullWidth(c)) == c. +// Note that, this function does not guarantee to convert all wide +// form characters to their possible narrow form. +uint32_t GetFullWidthInverse(uint32_t aCh); + +bool IsClusterExtender(uint32_t aCh, uint8_t aCategory); + +inline bool IsClusterExtender(uint32_t aCh) { + return IsClusterExtender(aCh, GetGeneralCategory(aCh)); +} + +// A simple iterator for a string of char16_t codepoints that advances +// by Unicode grapheme clusters +class ClusterIterator { + public: + ClusterIterator(const char16_t* aText, uint32_t aLength) + : mPos(aText), + mLimit(aText + aLength) +#ifdef DEBUG + , + mText(aText) +#endif + { + } + + operator const char16_t*() const { return mPos; } + + bool AtEnd() const { return mPos >= mLimit; } + + void Next(); + + private: + const char16_t* mPos; + const char16_t* mLimit; +#ifdef DEBUG + const char16_t* mText; +#endif +}; + +// Count the number of grapheme clusters in the given string +uint32_t CountGraphemeClusters(const char16_t* aText, uint32_t aLength); + +// Determine whether a character is a "combining diacritic" for the purpose +// of diacritic-insensitive text search. Examples of such characters include +// European accents and Hebrew niqqud, but not Hangul components or Thaana +// vowels, even though Thaana vowels are combining nonspacing marks that could +// be considered diacritics. +// As an exception to strictly following Unicode properties, we exclude the +// Japanese kana voicing marks +// 3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM +// 309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM +// which users report should not be ignored (bug 1624244). +inline bool IsCombiningDiacritic(uint32_t aCh) { + uint8_t cc = u_getCombiningClass(aCh); + return cc != HB_UNICODE_COMBINING_CLASS_NOT_REORDERED && + cc != HB_UNICODE_COMBINING_CLASS_KANA_VOICING; +} + +// Remove diacritics from a character +uint32_t GetNaked(uint32_t aCh); + +// A simple reverse iterator for a string of char16_t codepoints that +// advances by Unicode grapheme clusters +class ClusterReverseIterator { + public: + ClusterReverseIterator(const char16_t* aText, uint32_t aLength) + : mPos(aText + aLength), mLimit(aText) {} + + operator const char16_t*() const { return mPos; } + + bool AtEnd() const { return mPos <= mLimit; } + + void Next(); + + private: + const char16_t* mPos; + const char16_t* mLimit; +}; + +} // end namespace unicode + +} // end namespace mozilla + +#endif /* NS_UNICODEPROPERTIES_H */ diff --git a/intl/unicharutil/util/nsUnicodePropertyData.cpp b/intl/unicharutil/util/nsUnicodePropertyData.cpp new file mode 100644 index 0000000000..2127bc1f17 --- /dev/null +++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp @@ -0,0 +1,206 @@ + +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Derived from the Unicode Character Database by genUnicodePropertyData.pl + * + * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html + */ + +/* + * Created on Thu Mar 12 09:57:47 2020 from UCD data files with version info: + * + +# Unicode Character Database +# Date: 2020-03-06, 20:34:00 GMT [KW] +# © 2020 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see https://www.unicode.org/terms_of_use.html +# +# For documentation, see the following: +# NamesList.html +# UAX #38, "Unicode Han Database (Unihan)" +# UAX #44, "Unicode Character Database" +# UTS #51, "Unicode Emoji" +# +# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode13.0.0/ + +This directory contains the final data files +for the Unicode Character Database, for Version 13.0.0 of the Unicode Standard. + +# IdentifierStatus.txt +# Date: 2020-02-07, 22:02:47 GMT + +# +# Unihan_Variants.txt +# Date: 2020-02-18 18:27:33 GMT [JHJ] + +# VerticalOrientation-17.txt +# Date: 2016-10-20, 07:00:00 GMT [EM, KI, LI] + + * + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ + +#include <stdint.h> +#include "harfbuzz/hb.h" + +#define kCharProp2MaxPlane 16 +#define kCharProp2IndexBits 9 +#define kCharProp2CharBits 7 +static const uint8_t sCharProp2Planes[16] = {1,2,3,4,4,4,4,4,4,4,4,4,4,4,5,5}; + +static const uint8_t sCharProp2Pages[6][512] = { + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,39,34,34,34,34,16,16,40,16,41,16,16,16,16,16,16,16,42,16,16,43,44,45,46,47,48,49,50,51,16,52,53,54,34,16,55,56,34,57,58,16,16,16,16,16,16,59,60,16,16,61,62,16,34,34,34,63,64,65,66,34,34,67,34,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,69,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,70,34,34,34,34,34,34,34,34,34,71,16,16,72,16,73,74,16,16,75,76,77,16,78,16,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,79,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,80,34,16,16,16,16,16,16,81,16,82,83}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,84,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,85,16,16,16,16,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,34,34,34,86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,87,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,88,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,16,16,34,16,16,16,16,16,16,16,16,16,34,34,34,34,34,86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,34,34,34,34,89,34,34,34,34,34,34,34,34,34,34,34,16,16,34,34,16,16,16,16,16,16,16,16,16,16,16,16}, + {68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,90,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,91,68,92,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,93,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,94,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,95}, + {68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,96,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,95}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}, + {34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,95} +}; + +static const nsCharProps2 sCharProp2Values[97][128] = { + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{0,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{0,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0}}, + {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{0,0},{2,0},{2,0},{0,0},{0,0},{0,1},{0,1},{0,1},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{0,0},{0,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}}, + {{0,1},{0,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{2,1},{0,0},{0,0},{0,1},{0,1},{2,0},{2,0},{0,1},{0,1},{0,0},{3,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{2,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{3,1},{0,1},{0,1},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{2,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0}}, + {{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{2,0},{2,0},{2,0},{2,0},{2,0}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1}}, + {{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,0},{0,1},{0,0},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,0},{0,1},{0,0},{0,1},{0,1},{0,0},{0,0},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{2,0},{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{0,0},{0,0},{2,0},{1,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{1,0},{1,0},{1,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{0,0},{3,0},{0,0},{3,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{3,0},{3,0},{3,0},{3,0},{3,0},{3,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{3,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{0,0},{0,0},{1,0},{1,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,1},{1,0},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,1},{1,1},{1,1},{1,1},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0},{1,0}}, + {{2,0},{2,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, + {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{1,0},{1,0}}, + {{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}} +}; +#define kFullWidthMaxPlane 0 +#define kFullWidthIndexBits 10 +#define kFullWidthCharBits 6 +static const uint8_t sFullWidthPages[1024] = { + 0,1,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,6,7,8 +}; + +static const uint16_t sFullWidthValues[9][64] = { + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3000,0xff01,0xff02,0xff03,0xff04,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f}, + {0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xff5e,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe0,0xffe1,0x0000,0xffe5,0xffe4,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe2,0x0000,0x0000,0xffe3,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe6,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0xff5f,0xff60,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3002,0x300c,0x300d,0x3001,0x30fb,0x30f2,0x30a1,0x30a3,0x30a5,0x30a7,0x30a9,0x30e3,0x30e5,0x30e7,0x30c3,0x30fc,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,0x30ad,0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,0x30bd}, + {0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f3,0x3099,0x309a,0x3164,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f,0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x0000}, + {0x0000,0x0000,0x314f,0x3150,0x3151,0x3152,0x3153,0x3154,0x0000,0x0000,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,0x0000,0x0000,0x315b,0x315c,0x315d,0x315e,0x315f,0x3160,0x0000,0x0000,0x3161,0x3162,0x3163,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2502,0x2190,0x2191,0x2192,0x2193,0x25a0,0x25cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000} +}; +#define kFullWidthInverseMaxPlane 0 +#define kFullWidthInverseIndexBits 10 +#define kFullWidthInverseCharBits 6 +static const uint8_t sFullWidthInversePages[1024] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,7,8,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,0,12 +}; + +static const uint16_t sFullWidthInverseValues[13][64] = { + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffe9,0xffea,0xffeb,0xffec,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0xffe8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffed,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0020,0xff64,0xff61,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff62,0xff63,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff9e,0xff9f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff67,0xff71,0xff68,0xff72,0xff69,0xff73,0xff6a,0xff74,0xff6b,0xff75,0xff76,0x0000,0xff77,0x0000,0xff78,0x0000,0xff79,0x0000,0xff7a,0x0000,0xff7b,0x0000,0xff7c,0x0000,0xff7d,0x0000,0xff7e,0x0000,0xff7f,0x0000,0xff80}, + {0x0000,0xff81,0x0000,0xff6f,0xff82,0x0000,0xff83,0x0000,0xff84,0x0000,0xff85,0xff86,0xff87,0xff88,0xff89,0xff8a,0x0000,0x0000,0xff8b,0x0000,0x0000,0xff8c,0x0000,0x0000,0xff8d,0x0000,0x0000,0xff8e,0x0000,0x0000,0xff8f,0xff90,0xff91,0xff92,0xff93,0xff6c,0xff94,0xff6d,0xff95,0xff6e,0xff96,0xff97,0xff98,0xff99,0xff9a,0xff9b,0x0000,0xff9c,0x0000,0x0000,0xff66,0xff9d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xff65,0xff70,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffa1,0xffa2,0xffa3,0xffa4,0xffa5,0xffa6,0xffa7,0xffa8,0xffa9,0xffaa,0xffab,0xffac,0xffad,0xffae,0xffaf}, + {0xffb0,0xffb1,0xffb2,0xffb3,0xffb4,0xffb5,0xffb6,0xffb7,0xffb8,0xffb9,0xffba,0xffbb,0xffbc,0xffbd,0xffbe,0xffc2,0xffc3,0xffc4,0xffc5,0xffc6,0xffc7,0xffca,0xffcb,0xffcc,0xffcd,0xffce,0xffcf,0xffd2,0xffd3,0xffd4,0xffd5,0xffd6,0xffd7,0xffda,0xffdb,0xffdc,0xffa0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f}, + {0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2985,0x2986,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x00a2,0x00a3,0x00ac,0x00af,0x00a6,0x00a5,0x20a9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000} +}; +/* + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ diff --git a/intl/unicharutil/util/nsUnicodeScriptCodes.h b/intl/unicharutil/util/nsUnicodeScriptCodes.h new file mode 100644 index 0000000000..6c8fb24009 --- /dev/null +++ b/intl/unicharutil/util/nsUnicodeScriptCodes.h @@ -0,0 +1,267 @@ + +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Derived from the Unicode Character Database by genUnicodePropertyData.pl + * + * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html + */ + +/* + * Created on Thu Mar 12 09:57:47 2020 from UCD data files with version info: + * + +# Unicode Character Database +# Date: 2020-03-06, 20:34:00 GMT [KW] +# © 2020 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see https://www.unicode.org/terms_of_use.html +# +# For documentation, see the following: +# NamesList.html +# UAX #38, "Unicode Han Database (Unihan)" +# UAX #44, "Unicode Character Database" +# UTS #51, "Unicode Emoji" +# +# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode13.0.0/ + +This directory contains the final data files +for the Unicode Character Database, for Version 13.0.0 of the Unicode Standard. + +# IdentifierStatus.txt +# Date: 2020-02-07, 22:02:47 GMT + +# +# Unihan_Variants.txt +# Date: 2020-02-18 18:27:33 GMT [JHJ] + +# VerticalOrientation-17.txt +# Date: 2016-10-20, 07:00:00 GMT [EM, KI, LI] + + * + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ + +#ifndef NS_UNICODE_SCRIPT_CODES +#define NS_UNICODE_SCRIPT_CODES + + +struct nsCharProps2 { + // Currently only 4 bits are defined here, so 4 more could be added without + // affecting the storage requirements for this struct. Or we could pack two + // records per byte, at the cost of a slightly more complex accessor. + unsigned char mVertOrient:2; + unsigned char mIdType:2; +}; + +namespace mozilla { +namespace unicode { +enum class Script : int16_t { + COMMON = 0, + INHERITED = 1, + ARABIC = 2, + ARMENIAN = 3, + BENGALI = 4, + BOPOMOFO = 5, + CHEROKEE = 6, + COPTIC = 7, + CYRILLIC = 8, + DESERET = 9, + DEVANAGARI = 10, + ETHIOPIC = 11, + GEORGIAN = 12, + GOTHIC = 13, + GREEK = 14, + GUJARATI = 15, + GURMUKHI = 16, + HAN = 17, + HANGUL = 18, + HEBREW = 19, + HIRAGANA = 20, + KANNADA = 21, + KATAKANA = 22, + KHMER = 23, + LAO = 24, + LATIN = 25, + MALAYALAM = 26, + MONGOLIAN = 27, + MYANMAR = 28, + OGHAM = 29, + OLD_ITALIC = 30, + ORIYA = 31, + RUNIC = 32, + SINHALA = 33, + SYRIAC = 34, + TAMIL = 35, + TELUGU = 36, + THAANA = 37, + THAI = 38, + TIBETAN = 39, + CANADIAN_ABORIGINAL = 40, + YI = 41, + TAGALOG = 42, + HANUNOO = 43, + BUHID = 44, + TAGBANWA = 45, + BRAILLE = 46, + CYPRIOT = 47, + LIMBU = 48, + LINEAR_B = 49, + OSMANYA = 50, + SHAVIAN = 51, + TAI_LE = 52, + UGARITIC = 53, + KATAKANA_OR_HIRAGANA = 54, + BUGINESE = 55, + GLAGOLITIC = 56, + KHAROSHTHI = 57, + SYLOTI_NAGRI = 58, + NEW_TAI_LUE = 59, + TIFINAGH = 60, + OLD_PERSIAN = 61, + BALINESE = 62, + BATAK = 63, + BLISSYMBOLS = 64, + BRAHMI = 65, + CHAM = 66, + CIRTH = 67, + OLD_CHURCH_SLAVONIC_CYRILLIC = 68, + DEMOTIC_EGYPTIAN = 69, + HIERATIC_EGYPTIAN = 70, + EGYPTIAN_HIEROGLYPHS = 71, + KHUTSURI = 72, + SIMPLIFIED_HAN = 73, + TRADITIONAL_HAN = 74, + PAHAWH_HMONG = 75, + OLD_HUNGARIAN = 76, + HARAPPAN_INDUS = 77, + JAVANESE = 78, + KAYAH_LI = 79, + LATIN_FRAKTUR = 80, + LATIN_GAELIC = 81, + LEPCHA = 82, + LINEAR_A = 83, + MANDAIC = 84, + MAYAN_HIEROGLYPHS = 85, + MEROITIC_HIEROGLYPHS = 86, + NKO = 87, + OLD_TURKIC = 88, + OLD_PERMIC = 89, + PHAGS_PA = 90, + PHOENICIAN = 91, + MIAO = 92, + RONGORONGO = 93, + SARATI = 94, + ESTRANGELO_SYRIAC = 95, + WESTERN_SYRIAC = 96, + EASTERN_SYRIAC = 97, + TENGWAR = 98, + VAI = 99, + VISIBLE_SPEECH = 100, + CUNEIFORM = 101, + UNWRITTEN_LANGUAGES = 102, + UNKNOWN = 103, + CARIAN = 104, + JAPANESE = 105, + TAI_THAM = 106, + LYCIAN = 107, + LYDIAN = 108, + OL_CHIKI = 109, + REJANG = 110, + SAURASHTRA = 111, + SIGNWRITING = 112, + SUNDANESE = 113, + MOON = 114, + MEETEI_MAYEK = 115, + IMPERIAL_ARAMAIC = 116, + AVESTAN = 117, + CHAKMA = 118, + KOREAN = 119, + KAITHI = 120, + MANICHAEAN = 121, + INSCRIPTIONAL_PAHLAVI = 122, + PSALTER_PAHLAVI = 123, + BOOK_PAHLAVI = 124, + INSCRIPTIONAL_PARTHIAN = 125, + SAMARITAN = 126, + TAI_VIET = 127, + MATHEMATICAL_NOTATION = 128, + SYMBOLS = 129, + BAMUM = 130, + LISU = 131, + NAKHI_GEBA = 132, + OLD_SOUTH_ARABIAN = 133, + BASSA_VAH = 134, + DUPLOYAN = 135, + ELBASAN = 136, + GRANTHA = 137, + KPELLE = 138, + LOMA = 139, + MENDE_KIKAKUI = 140, + MEROITIC_CURSIVE = 141, + OLD_NORTH_ARABIAN = 142, + NABATAEAN = 143, + PALMYRENE = 144, + KHUDAWADI = 145, + WARANG_CITI = 146, + AFAKA = 147, + JURCHEN = 148, + MRO = 149, + NUSHU = 150, + SHARADA = 151, + SORA_SOMPENG = 152, + TAKRI = 153, + TANGUT = 154, + WOLEAI = 155, + ANATOLIAN_HIEROGLYPHS = 156, + KHOJKI = 157, + TIRHUTA = 158, + CAUCASIAN_ALBANIAN = 159, + MAHAJANI = 160, + AHOM = 161, + HATRAN = 162, + MODI = 163, + MULTANI = 164, + PAU_CIN_HAU = 165, + SIDDHAM = 166, + ADLAM = 167, + BHAIKSUKI = 168, + MARCHEN = 169, + NEWA = 170, + OSAGE = 171, + HAN_WITH_BOPOMOFO = 172, + JAMO = 173, + SYMBOLS_EMOJI = 174, + MASARAM_GONDI = 175, + SOYOMBO = 176, + ZANABAZAR_SQUARE = 177, + DOGRA = 178, + GUNJALA_GONDI = 179, + MAKASAR = 180, + MEDEFAIDRIN = 181, + HANIFI_ROHINGYA = 182, + SOGDIAN = 183, + OLD_SOGDIAN = 184, + ELYMAIC = 185, + NYIAKENG_PUACHUE_HMONG = 186, + NANDINAGARI = 187, + WANCHO = 188, + CHORASMIAN = 189, + DIVES_AKURU = 190, + KHITAN_SMALL_SCRIPT = 191, + YEZIDI = 192, + + NUM_SCRIPT_CODES = 193, + + INVALID = -1 +}; +} // namespace unicode +} // namespace mozilla + +#endif +/* + * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * * + */ |