diff --git a/dlls/kernelbase/kernelbase.rgs b/dlls/kernelbase/kernelbase.rgs index bcebfe61a07..82a3cecb3c1 100644 --- a/dlls/kernelbase/kernelbase.rgs +++ b/dlls/kernelbase/kernelbase.rgs @@ -84,6 +84,127 @@ HKLM val '6' = s 'normnfkd.nls' val 'd' = s 'normidna.nls' } + Sorting + { + Ids = s '{00000001-57ee-1e5c-00b4-d0000bb1e11e}' + { + val 'arn' = s '{00000012-57ee-1e5c-00b4-d0000bb1e11e}' + val 'as' = s '{00000031-57ee-1e5c-00b4-d0000bb1e11e}' + val 'az' = s '{00000023-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ba' = s '{0000003d-57ee-1e5c-00b4-d0000bb1e11e}' + val 'bg' = s '{0000004a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'bn' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'bo' = s '{00000034-57ee-1e5c-00b4-d0000bb1e11e}' + val 'br' = s '{0000000f-57ee-1e5c-00b4-d0000bb1e11e}' + val 'bs' = s '{00000019-57ee-1e5c-00b4-d0000bb1e11e}' + val 'co' = s '{0000000e-57ee-1e5c-00b4-d0000bb1e11e}' + val 'cs' = s '{0000001c-57ee-1e5c-00b4-d0000bb1e11e}' + val 'cy' = s '{0000002c-57ee-1e5c-00b4-d0000bb1e11e}' + val 'da' = s '{0000001f-57ee-1e5c-00b4-d0000bb1e11e}' + val 'de-DE_phoneb' = s '{0000003f-57ee-1e5c-00b4-d0000bb1e11e}' + val 'dv' = s '{00000045-57ee-1e5c-00b4-d0000bb1e11e}' + val 'es' = s '{0000002b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'es-ES_tradnl' = s '{0000002a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'et' = s '{00000027-57ee-1e5c-00b4-d0000bb1e11e}' + val 'fa' = s '{00000041-57ee-1e5c-00b4-d0000bb1e11e}' + val 'fi' = s '{0000001a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'fr' = s '{00000003-57ee-1e5c-00b4-d0000bb1e11e}' + val 'fy' = s '{0000003e-57ee-1e5c-00b4-d0000bb1e11e}' + val 'gu' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'haw' = s '{00000002-57ee-1e5c-00b4-d0000bb1e11e}' + val 'hi' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'hr' = s '{00000019-57ee-1e5c-00b4-d0000bb1e11e}' + val 'hsb' = s '{00000013-57ee-1e5c-00b4-d0000bb1e11e}' + val 'hu' = s '{00000004-57ee-1e5c-00b4-d0000bb1e11e}' + val 'hu-HU_technl' = s '{00000026-57ee-1e5c-00b4-d0000bb1e11e}' + val 'is' = s '{00000025-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ja' = s '{00000046-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ja-JP_radstr' = s '{00000036-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ka-GE_modern' = s '{00000048-57ee-1e5c-00b4-d0000bb1e11e}' + val 'kk' = s '{0000000b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'kl' = s '{0000001f-57ee-1e5c-00b4-d0000bb1e11e}' + val 'km' = s '{0000000c-57ee-1e5c-00b4-d0000bb1e11e}' + val 'kn' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ko' = s '{00000047-57ee-1e5c-00b4-d0000bb1e11e}' + val 'kok' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ky' = s '{0000004a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'lo' = s '{0000002e-57ee-1e5c-00b4-d0000bb1e11e}' + val 'lt' = s '{00000028-57ee-1e5c-00b4-d0000bb1e11e}' + val 'lv' = s '{00000005-57ee-1e5c-00b4-d0000bb1e11e}' + val 'lv-LV_tradnl' = s '{00000006-57ee-1e5c-00b4-d0000bb1e11e}' + val 'mi' = s '{00000014-57ee-1e5c-00b4-d0000bb1e11e}' + val 'mk' = s '{0000000a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ml' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'mn' = s '{0000004a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'moh' = s '{00000010-57ee-1e5c-00b4-d0000bb1e11e}' + val 'mr' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'mt' = s '{0000002d-57ee-1e5c-00b4-d0000bb1e11e}' + val 'nb' = s '{00000020-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ne' = s '{00000033-57ee-1e5c-00b4-d0000bb1e11e}' + val 'nn' = s '{00000020-57ee-1e5c-00b4-d0000bb1e11e}' + val 'no' = s '{00000020-57ee-1e5c-00b4-d0000bb1e11e}' + val 'oc' = s '{00000003-57ee-1e5c-00b4-d0000bb1e11e}' + val 'or' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'pa' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'pa-Arab' = s '{00000007-57ee-1e5c-00b4-d0000bb1e11e}' + val 'pl' = s '{0000001d-57ee-1e5c-00b4-d0000bb1e11e}' + val 'prs' = s '{00000016-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ps' = s '{00000016-57ee-1e5c-00b4-d0000bb1e11e}' + val 'quc' = s '{0000002b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'qut' = s '{0000002b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'rm' = s '{00000011-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ro' = s '{00000024-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ru' = s '{0000004a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sa' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sah' = s '{00000009-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sd' = s '{00000007-57ee-1e5c-00b4-d0000bb1e11e}' + val 'se' = s '{00000021-57ee-1e5c-00b4-d0000bb1e11e}' + val 'se-FI' = s '{0000001b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'se-SE' = s '{0000001b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'si' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sk' = s '{00000029-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sl' = s '{0000001e-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sma' = s '{0000001b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sma-NO' = s '{00000021-57ee-1e5c-00b4-d0000bb1e11e}' + val 'smj' = s '{0000001b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'smj-NO' = s '{00000021-57ee-1e5c-00b4-d0000bb1e11e}' + val 'smn' = s '{0000001b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sms' = s '{0000001b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sq' = s '{00000018-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sr' = s '{00000019-57ee-1e5c-00b4-d0000bb1e11e}' + val 'sv' = s '{0000001a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'syr' = s '{00000044-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ta' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'te' = s '{00000032-57ee-1e5c-00b4-d0000bb1e11e}' + val 'tg' = s '{0000004a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'th' = s '{0000002f-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ti' = s '{0000003c-57ee-1e5c-00b4-d0000bb1e11e}' + val 'tk' = s '{00000008-57ee-1e5c-00b4-d0000bb1e11e}' + val 'tr' = s '{00000022-57ee-1e5c-00b4-d0000bb1e11e}' + val 'tt' = s '{00000043-57ee-1e5c-00b4-d0000bb1e11e}' + val 'tzm' = s '{0000000d-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ug' = s '{00000017-57ee-1e5c-00b4-d0000bb1e11e}' + val 'uk' = s '{00000040-57ee-1e5c-00b4-d0000bb1e11e}' + val 'ur' = s '{00000015-57ee-1e5c-00b4-d0000bb1e11e}' + val 'uz-Cyrl' = s '{0000004a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'vi' = s '{00000030-57ee-1e5c-00b4-d0000bb1e11e}' + val 'wo' = s '{00000003-57ee-1e5c-00b4-d0000bb1e11e}' + val 'x-IV_mathan' = s '{00000035-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh' = s '{0000003a-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-CN_phoneb' = s '{0000004b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-CN_stroke' = s '{00000039-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-HK' = s '{00000037-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-HK_radstr' = s '{0000003b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-Hant' = s '{00000037-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-MO' = s '{00000037-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-MO_radstr' = s '{0000003b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-SG_phoneb' = s '{0000004b-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-SG_stroke' = s '{00000039-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-TW' = s '{00000037-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-TW_pronun' = s '{00000038-57ee-1e5c-00b4-d0000bb1e11e}' + val 'zh-TW_radstr' = s '{0000003b-57ee-1e5c-00b4-d0000bb1e11e}' + } + } } } } diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 253f0e2c297..6e0cb212531 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -30,7 +30,7 @@ signature="$CHICAGO$" RegisterDlls=RegisterDllsSection WineFakeDlls=FakeDllsWin32,FakeDlls UpdateInis=SystemIni -CopyFiles=InfFiles,NlsFiles +CopyFiles=InfFiles,NlsFiles,SortFiles AddReg=\ Classes,\ ContentIndex,\ @@ -54,7 +54,7 @@ AddReg=\ RegisterDlls=RegisterDllsSection WineFakeDlls=FakeDllsWin32,FakeDlls UpdateInis=SystemIni -CopyFiles=InfFiles,NlsFiles +CopyFiles=InfFiles,NlsFiles,SortFiles AddReg=\ Classes,\ ContentIndex,\ @@ -80,7 +80,7 @@ RegisterDlls=RegisterDllsSection WineFakeDlls=FakeDllsWin64,FakeDlls WinePreInstall=Wow64 UpdateInis=SystemIni -CopyFiles=InfFiles,NlsFiles +CopyFiles=InfFiles,NlsFiles,SortFiles AddReg=\ Classes,\ ContentIndex,\ @@ -107,7 +107,7 @@ RegisterDlls=RegisterDllsSection WineFakeDlls=FakeDllsWin64,FakeDlls WinePreInstall=Wow64 UpdateInis=SystemIni -CopyFiles=InfFiles,NlsFiles +CopyFiles=InfFiles,NlsFiles,SortFiles AddReg=\ Classes,\ ContentIndex,\ @@ -3893,9 +3893,14 @@ normnfd.nls normnfkc.nls normnfkd.nls +[SortFiles] +sortdefault.nls + [WineSourceDirs] -NlsFiles=nls +NlsFiles = nls +SortFiles = nls [DestinationDirs] -InfFiles = 17 -NlsFiles = 11 +InfFiles = 17 +NlsFiles = 11 +SortFiles = 10,globalization\sorting diff --git a/nls/Makefile.in b/nls/Makefile.in index f3e517a48ef..9a87a73a5ab 100644 --- a/nls/Makefile.in +++ b/nls/Makefile.in @@ -69,4 +69,5 @@ SOURCES = \ normnfc.nls \ normnfd.nls \ normnfkc.nls \ - normnfkd.nls + normnfkd.nls \ + sortdefault.nls diff --git a/nls/sortdefault.nls b/nls/sortdefault.nls new file mode 100644 index 00000000000..fcd92d90c4a Binary files /dev/null and b/nls/sortdefault.nls differ diff --git a/tools/make_makefiles b/tools/make_makefiles index a788c00a93b..bae52dfdbae 100755 --- a/tools/make_makefiles +++ b/tools/make_makefiles @@ -74,6 +74,7 @@ my @source_vars = ( ); my (@makefiles, %makefiles); +my @inf_files; my @nls_files; sub dirname($) @@ -382,6 +383,10 @@ sub assign_sources_to_makefiles(@) { push @{${$make}{"=MANPAGES"}}, $name; } + elsif ($name =~ /\.inf\.in$/) + { + push @inf_files, $name unless $name eq "wine.inf.in"; + } elsif ($name =~ /\.in$/) { push @{${$make}{"=IN_SRCS"}}, $name; @@ -487,8 +492,12 @@ sub update_makefiles(@) sub update_wine_inf() { - my @lines = ("[NlsFiles]", @nls_files, "\n" ); - replace_in_file "loader/wine.inf.in", '^\[NlsFiles\]', '^$', join( "\n", @lines ); + my @lines; + push @lines, "[InfFiles]", sort grep { s/\.in$//; } @inf_files; + push @lines, "\n[NlsFiles]", sort grep(!/^sort/, @nls_files); + push @lines, "\n[SortFiles]", sort grep(/^sort/, @nls_files); + push @lines, "\n[WineSourceDirs]\n"; + replace_in_file "loader/wine.inf.in", '^\[InfFiles\]', '^\[WineSourceDirs\]', join( "\n", @lines ); my @codepages = grep /c_\d+\.nls/, @nls_files; @lines = ( "[Nls]" ); diff --git a/tools/make_unicode b/tools/make_unicode index 4d73864b143..1b778e853bb 100755 --- a/tools/make_unicode +++ b/tools/make_unicode @@ -370,7 +370,7 @@ my %c2_types = "ET" => 5, # C2_EUROPETERMINATOR "AN" => 6, # C2_ARABICNUMBER "CS" => 7, # C2_COMMONSEPARATOR - "NSM" => 0, # C2_NOTAPPLICABLE + "NSM" => 11, # C2_OTHERNEUTRAL "BN" => 0, # C2_NOTAPPLICABLE "B" => 8, # C2_BLOCKSEPARATOR "S" => 9, # C2_SEGMENTSEPARATOR @@ -2356,6 +2356,386 @@ sub dump_msdata_codepage($) output_codepage_file( $codepage ); } +################################################################ +# align a string length +sub align_string($$) +{ + my ($align, $str) = @_; + $str .= pack "C*", (0) x ($align - length($str) % $align) if length($str) % $align; + return $str; +} + +################################################################ +# pack a GUID string +sub pack_guid($) +{ + $_ = shift; + /([0-9A-Fa-f]{8})-([0-9A-Fa-f]{4})-([0-9A-Fa-f]{4})-([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})-([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})/; + return pack "L scalar @{$b} || + $a->[4] <=> $b->[4] || + $a->[5] <=> $b->[5] || + $a->[6] <=> $b->[6] || + $a->[7] <=> $b->[7] || + $a->[8] <=> $b->[8] || + $a->[9] <=> $b->[9] || + $a->[10] <=> $b->[10] || + $a->[11] <=> $b->[11] || + $a->[12] <=> $b->[12]; +} + +################################################################ +# build a binary sort keys table +sub dump_sortkey_table($$) +{ + my ($filename, $download) = @_; + + my @keys; + my ($part, $section, $subsection, $guid, $version); + my @multiple_weights; + my @expansions; + my @compressions; + my @exceptions; + my @except_guid; + my %guids; + my %locales; + my $default_guid = "00000001-57ee-1e5c-00b4-d0000bb1e11e"; + my $jamostr = ""; + + my $re_hex = '0x[0-9A-Fa-f]+'; + my $re_key = '(\d+\s+\d+\s+\d+\s+\d+)'; + $guids{$default_guid} = { }; + + my %flags = ( "HAS_3_BYTE_WEIGHTS" => 0x01, "REVERSEDIACRITICS" => 0x10, "DOUBLECOMPRESSION" => 0x20, "INVERSECASING" => 0x40 ); + + my $KEYS = open_data_file( $MSDATA, $download ); + + printf "Building $filename\n"; + + while (<$KEYS>) + { + s/\s*;.*$//; + next if /^\s*$/; # skip empty lines + if (/^\s*(SORTKEY|SORTTABLES)/) + { + $part = $1; + next; + } + if (/^\s*(ENDSORTKEY|ENDSORTTABLES)/) + { + $part = $section = ""; + next; + } + if (/^\s*(DEFAULT|RELEASE|REVERSEDIACRITICS|DOUBLECOMPRESSION|INVERSECASING|MULTIPLEWEIGHTS|EXPANSION|COMPATIBILITY|COMPRESSION|EXCEPTION|JAMOSORT)\s+/) + { + $section = $1; + $guid = undef; + next; + } + next unless $part; + if ("$part.$section" eq "SORTKEY.DEFAULT") + { + if (/^\s*($re_hex)\s+$re_key/) + { + $keys[hex $1] = [ split(/\s+/,$2) ]; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.RELEASE") + { + if (/^\s*NLSVERSION\s+0x([0-9A-Fa-f]+)/) + { + $version = hex $1; + next; + } + if (/^\s*DEFINEDVERSION\s+0x([0-9A-Fa-f]+)/) + { + # ignore for now + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.REVERSEDIACRITICS" || + "$part.$section" eq "SORTTABLES.DOUBLECOMPRESSION" || + "$part.$section" eq "SORTTABLES.INVERSECASING") + { + if (/^\s*SORTGUID\s+([-0-9A-Fa-f]+)/) + { + $guid = lc $1; + $guids{$guid} = { } unless defined $guids{$guid}; + $guids{$guid}->{flags} |= $flags{$section}; + next; + } + if (/^\s*LOCALENAME\s+([A-Za-z0-9-_]+)/) + { + $locales{$1} = $guid; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.MULTIPLEWEIGHTS") + { + if (/^\s*(\d+)\s+(\d+)/) + { + push @multiple_weights, $1, $2; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.EXPANSION") + { + if (/^\s*0x([0-9A-Fa-f]+)\s+0x([0-9A-Fa-f]+)\s+0x([0-9A-Fa-f]+)/) + { + my $pos = scalar @expansions / 2; + $keys[hex $1] = [ 2, 0, $pos & 0xff, $pos >> 8 ] unless defined $keys[hex $1]; + push @expansions, hex $2, hex $3; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.COMPATIBILITY") + { + if (/^\s*0x([0-9A-Fa-f]+)\s+0x([0-9A-Fa-f]+)/) + { + $keys[hex $1] = $keys[hex $2]; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.COMPRESSION") + { + if (/^\s*SORTGUID\s+([-0-9A-Fa-f]+)\s+\d*\s*([A-Z0-9_]+)?/) + { + if ($subsection || !$guid) # start a new one + { + $guid = lc $1; + $subsection = ""; + $guids{$guid} = { } unless defined $guids{$guid}; + $guids{$guid}->{flags} |= $flags{$2} if $2; + $guids{$guid}->{compr} = @compressions; + push @compressions, [ ]; + } + else # merge with current one + { + $guids{lc $1} = { } unless defined $guids{lc $1}; + $guids{lc $1}->{flags} |= $flags{$2} if $2; + $guids{lc $1}->{compr} = $guids{$guid}->{compr}; + } + next; + } + if (/^\s*LOCALENAME\s+([A-Za-z0-9-_]+)/) + { + $locales{$1} = $guid; + next; + } + if (/^\s*(TWO|THREE|FOUR|FIVE|SIX|SEVEN|EIGHT)/) + { + $subsection = $1; + next; + } + if ($subsection && /^\s*(($re_hex\s+){2,8})$re_key/) + { + push @{$compressions[$#compressions]}, [ split(/\s+/,$3), map { hex $_; } split(/\s+/,$1) ]; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.EXCEPTION") + { + if (/^\s*SORTGUID\s+([-0-9A-Fa-f]+)\s+\d*\s*(LINGUISTIC_CASING)?/) + { + $guid = lc $1; + $guids{$guid} = { } unless defined $guids{lc $1}; + push @except_guid, ($2 ? "+" : "-") . $guid; + push @exceptions, [ ]; + next; + } + if (/^\s*LOCALENAME\s+([A-Za-z0-9-_]+)/) + { + $locales{$1} = $guid; + next; + } + if (/^\s*($re_hex)\s+$re_key/) + { + ${$exceptions[$#exceptions]}[hex $1] = [ split(/\s+/,$2) ]; + next; + } + } + elsif ("$part.$section" eq "SORTTABLES.JAMOSORT") + { + if (/^\s*$re_hex\s+(($re_hex\s*){5})/) + { + $jamostr .= pack "C8", map { hex $_; } split /\s+/, $1; + next; + } + } + die "$download: $part.$section: unrecognized line $_\n"; + } + close $KEYS; + + # Sortkey table + + my $table; + for (my $i = 0; $i < 0x10000; $i++) + { + my @k = defined $keys[$i] ? @{$keys[$i]} : (0) x 4; + $table .= pack "C4", $k[1], $k[0], $k[2], $k[3]; + } + + for (my $i = 0; $i < @exceptions; $i++) + { + my $pos = length($table) / 4; + my @exc = @{$exceptions[$i]}; + my @filled; + my $key = (substr($except_guid[$i],0,1) eq "+" ? "ling_except" : "except"); + $guids{substr( $except_guid[$i], 1 )}->{$key} = $pos; + $pos += 0x100; + for (my $j = 0; $j < 0x10000; $j++) + { + next unless defined $exc[$j]; + $filled[$j >> 8] = 1; + $j |= 0xff; + } + for (my $j = 0; $j < 0x100; $j++) + { + $table .= pack "L<", $filled[$j] ? $pos : $j * 0x100; + $pos += 0x100 if $filled[$j]; + } + for (my $j = 0; $j < 0x10000; $j++) + { + next unless $filled[$j >> 8]; + my @k = defined $exc[$j] ? @{$exc[$j]} : defined $keys[$j] ? @{$keys[$j]} : (0) x 4; + $table .= pack "C4", $k[1], $k[0], $k[2], $k[3]; + } + } + + # Case mapping tables + + # standard table + my @casemaps; + my @upper = @toupper_table; + my @lower = @tolower_table; + remove_linguistic_mappings( \@upper, \@lower ); + $casemaps[0] = pack( "S<*", 1) . dump_binary_case_table( @upper ) . dump_binary_case_table( @lower ); + + # linguistic table + $casemaps[1] = pack( "S<*", 1) . dump_binary_case_table( @toupper_table ) . dump_binary_case_table( @tolower_table ); + + # Turkish table + @upper = @toupper_table; + @lower = @tolower_table; + $upper[ord 'i'] = 0x130; # LATIN CAPITAL LETTER I WITH DOT ABOVE + $lower[ord 'I'] = 0x131; # LATIN SMALL LETTER DOTLESS I + $casemaps[2] = pack( "S<*", 1) . dump_binary_case_table( @upper ) . dump_binary_case_table( @lower ); + my $casemaps = align_string( 8, $casemaps[0] . $casemaps[1] . $casemaps[2] ); + + # Char type table + + my @table; + my $types = ""; + my %typestr; + for (my $i = 0; $i < 0x10000; $i++) + { + my $str = pack "S<3", + ($category_table[$i] || 0) & 0xffff, + defined($direction_table[$i]) ? $c2_types{$direction_table[$i]} : 0, + ($category_table[$i] || 0) >> 16; + + if (!defined($typestr{$str})) + { + $typestr{$str} = length($types) / 6; + $types .= $str; + } + $table[$i] = $typestr{$str}; + } + + my @rows = compress_array( 4096, 0, @table[0..65535] ); + my @array = compress_array( 256, 0, @rows[0..4095] ); + for (my $i = 0; $i < 256; $i++) { $array[$i] *= 2; } # we need byte offsets + for (my $i = 256; $i < @array; $i++) { $array[$i] += 2 * @array - 4096; } + + my $arraystr = pack("S<*", @array) . pack("C*", @rows[4096..$#rows]); + my $chartypes = pack "S<2", 4 + length($types) + length($arraystr), 2 + length($types); + $chartypes = align_string( 8, $chartypes . $types . $arraystr ); + + # Sort tables + + # guids + my $sorttables = pack "L<2", $version, scalar %guids; + foreach my $id (sort keys %guids) + { + my %guid = %{$guids{$id}}; + my $flags = $guid{flags} || 0; + my $map = length($casemaps[0]) + (defined $guid{ling_except} ? length($casemaps[1]) : 0); + $sorttables .= pack_guid($id) . pack "L<5", + $flags, + defined($guid{compr}) ? $guid{compr} : 0xffffffff, + $guid{except} || 0, + $guid{ling_except} || 0, + $map / 2; + } + + # expansions + $sorttables .= pack "L $val; + $max = $val if $max < $val; + } + $rowstr .= align_string( 4, pack "S<*", @row[4..$#row] ); + $rowstr .= pack "C4", $row[1], $row[0], $row[2], $row[3]; + } + $sorttables .= pack "L 1 && defined($locales{$parts[0]}) && $locales{$parts[0]} eq $locales{$loc}; + next if @parts > 2 && defined($locales{"$parts[0]-$parts[1]"}) && $locales{"$parts[0]-$parts[1]"} eq $locales{$loc}; + add_registry_value( "Sorting\\Ids", $loc, "\{$locales{$loc}\}" ); + } + + # File header + + my @header; + $header[0] = 16; + $header[1] = $header[0] + length $table; + $header[2] = $header[1] + length $casemaps; + $header[3] = $header[2] + length $chartypes; + + open OUTPUT, ">$filename.new" or die "Cannot create $filename"; + print OUTPUT pack "L<*", @header; + print OUTPUT $table, $casemaps, $chartypes, $sorttables; + close OUTPUT; + save_file($filename); +} + ################################################################ # build the script to create registry keys @@ -2437,6 +2817,7 @@ dump_norm_table( "nls/normnfd.nls" ); dump_norm_table( "nls/normnfkc.nls" ); dump_norm_table( "nls/normnfkd.nls" ); dump_norm_table( "nls/normidna.nls" ); +dump_sortkey_table( "nls/sortdefault.nls", "Windows 10 Sorting Weight Table.txt" ); foreach my $file (@allfiles) { dump_msdata_codepage( $file ); } dump_eucjp_codepage(); dump_registry_script( "dlls/kernelbase/kernelbase.rgs", %registry_keys );