Rebase against 13cdcdae1a9e58f2eec9cd99b7b7f7899b4d111b

This commit is contained in:
Alistair Leslie-Hughes 2018-10-26 08:23:40 +11:00
parent 2802df41dc
commit eb630f686f
13 changed files with 1075 additions and 1878 deletions

View File

@ -1,488 +1,488 @@
From 83053c7a7379900ac0ca1922e7551298848216d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Wed, 4 Apr 2018 10:49:39 -0500
Subject: [PATCH 1/3] tools/make_unicode: Implement full Unicode character
decomposition.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
libs/port/mbtowc.c | 14 +-
tools/make_unicode | 333 ++++++++++++++++++++++++++++++++++++---------
2 files changed, 279 insertions(+), 68 deletions(-)
diff --git a/libs/port/mbtowc.c b/libs/port/mbtowc.c
index 4977c82d8b..6976f89722 100644
--- a/libs/port/mbtowc.c
+++ b/libs/port/mbtowc.c
@@ -22,7 +22,7 @@
#include "wine/unicode.h"
-extern unsigned int wine_decompose( WCHAR ch, WCHAR *dst, unsigned int dstlen ) DECLSPEC_HIDDEN;
+extern int wine_unicode_decompose_string( int compat, const WCHAR *src, int srclen, WCHAR *dst, int dstlen );
/* check the code whether it is in Unicode Private Use Area (PUA). */
/* MB_ERR_INVALID_CHARS raises an error converting from 1-byte character to PUA. */
@@ -101,19 +101,19 @@ static int mbstowcs_sbcs_decompose( const struct sbcs_table *table, int flags,
WCHAR *dst, unsigned int dstlen )
{
const WCHAR * const cp2uni = (flags & MB_USEGLYPHCHARS) ? table->cp2uni_glyphs : table->cp2uni;
- unsigned int len;
+ int len;
if (!dstlen) /* compute length */
{
WCHAR dummy[4]; /* no decomposition is larger than 4 chars */
for (len = 0; srclen; srclen--, src++)
- len += wine_decompose( cp2uni[*src], dummy, 4 );
+ len += wine_unicode_decompose_string( 0, &cp2uni[*src], 1, dummy, 4 );
return len;
}
for (len = dstlen; srclen && len; srclen--, src++)
{
- unsigned int res = wine_decompose( cp2uni[*src], dst, len );
+ int res = wine_unicode_decompose_string( 0, &cp2uni[*src], 1, dst, len );
if (!res) break;
len -= res;
dst += res;
@@ -203,7 +203,7 @@ static int mbstowcs_dbcs_decompose( const struct dbcs_table *table,
{
const WCHAR * const cp2uni = table->cp2uni;
const unsigned char * const cp2uni_lb = table->cp2uni_leadbytes;
- unsigned int len, res;
+ int len, res;
WCHAR ch;
if (!dstlen) /* compute length */
@@ -219,7 +219,7 @@ static int mbstowcs_dbcs_decompose( const struct dbcs_table *table,
ch = cp2uni[(off << 8) + *src];
}
else ch = cp2uni[*src];
- len += wine_decompose( ch, dummy, 4 );
+ len += wine_unicode_decompose_string( 0, &ch, 1, dummy, 4 );
}
return len;
}
@@ -234,7 +234,7 @@ static int mbstowcs_dbcs_decompose( const struct dbcs_table *table,
ch = cp2uni[(off << 8) + *src];
}
else ch = cp2uni[*src];
- if (!(res = wine_decompose( ch, dst, len ))) break;
+ if (!(res = wine_unicode_decompose_string( 0, &ch, 1, dst, len ))) break;
dst += res;
len -= res;
}
diff --git a/tools/make_unicode b/tools/make_unicode
index 56d1905656..2aa063bff6 100755
--- a/tools/make_unicode
+++ b/tools/make_unicode
@@ -472,6 +472,28 @@ sub READ_DEFAULTS($)
next if $decomp eq ""; # no decomposition, skip it
+ # store decomposition table
+ if ($decomp =~ /^<([a-zA-Z]+)>(\s+[0-9a-fA-F]+)+$/)
+ {
+ my @seq = ();
+ for my $ch (split /\s+/, (split /\s+/, $decomp, 2)[1])
+ {
+ push @seq, (hex $ch);
+ }
+ $decomp_table[$src] = [1, \@seq];
+ }
+ elsif ($decomp =~ /^([0-9a-fA-F]+)(\s+([0-9a-fA-F]+))*$/)
+ {
+ my @seq = ();
+ for my $ch (split /\s+/, $decomp)
+ {
+ # we don't support surrogates at the moment
+ next if hex $ch > 0xffff;
+ push @seq, (hex $ch);
+ }
+ $decomp_table[$src] = [0, \@seq];
+ }
+
if ($decomp =~ /^<([a-zA-Z]+)>\s+([0-9a-fA-F]+)$/)
{
# decomposition of the form "<foo> 1234" -> use char if type is known
@@ -506,16 +528,13 @@ sub READ_DEFAULTS($)
# decomposition contains only char values without prefix -> use first char
$dst = hex $1;
$category_table[$src] |= $category_table[$dst] if defined $category_table[$dst];
- # store decomposition if it contains two chars
if ($decomp =~ /^([0-9a-fA-F]+)\s+([0-9a-fA-F]+)$/)
{
- $decomp_table[$src] = [ hex $1, hex $2 ];
push @compose_table, [ hex $1, hex $2, $src ];
}
elsif ($decomp =~ /^(<[a-z]+>\s)*([0-9a-fA-F]+)$/ &&
(($src >= 0xf900 && $src < 0xfb00) || ($src >= 0xfe30 && $src < 0xfffd)))
{
- # Single char decomposition in the compatibility range
$compatmap_table[$src] = hex $2;
}
}
@@ -2264,6 +2283,51 @@ EOF
save_file($filename);
}
+sub do_decomp
+{
+ my ($char, $table_ref, $compat) = @_;
+
+ return ($char) unless defined $table_ref->[$char];
+ my $data = $table_ref->[$char];
+ return ($char) if $data->[0] && !$compat;
+ my @mapping = ();
+ for my $ch (@{$data->[1]})
+ {
+ push @mapping, $ch;
+ }
+ return @mapping;
+}
+
+sub expand_pairs
+{
+ my @data = @_;
+ my @result = ();
+
+ for my $ch (@data)
+ {
+ if ($ch <= 0xFFFF)
+ {
+ push @result, $ch;
+ }
+ elsif ($ch >= 2097152) # 2**21
+ {
+ die sprintf "Invalid Unicode character %04x\n", $ch;
+ }
+ else
+ {
+ my $hx = $ch & 0xFFFF;
+ my $hu = ($ch >> 16) & ((1 << 5) - 1);
+ my $hw = ($hu - 1) & 0xFFFF;
+ my $hi = 0xD800 | ($hw << 6) | ($hx >> 10);
+ my $lx = $ch & 0xFFFF;
+ my $lo = (0xDC00 | ($lx & ((1 << 10) - 1))) & 0xFFFF;
+ push @result, $hi;
+ push @result, $lo;
+ }
+ }
+ return @result;
+}
+
################################################################
# dump the char decomposition table
sub dump_decompose_table($)
@@ -2272,98 +2336,245 @@ sub dump_decompose_table($)
open OUTPUT,">$filename.new" or die "Cannot create $filename";
print "Building $filename\n";
- print OUTPUT "/* Unicode char composition */\n";
+ print OUTPUT "/* Unicode char decomposition */\n";
print OUTPUT "/* generated from $UNIDATA/UnicodeData.txt */\n";
print OUTPUT "/* DO NOT EDIT!! */\n\n";
print OUTPUT "#include \"wine/unicode.h\"\n\n";
- # first determine all the 16-char subsets that contain something
+ # limit code points to BMP
+ my $utflim = 65536;
+ my %nfd_lookup = ();
+ my %nfkd_lookup = ();
+ my %decomp_lookup = ();
+ my @decomp_data = (0);
+ my $pos = 1;
+ my $lastchar_decomp;
- my @filled = (0) x 4096;
- my $pos = 16*2; # for the null subset
- for (my $i = 0; $i < 65536; $i++)
+ for (my $i = 0; $i < $utflim; $i++)
{
next unless defined $decomp_table[$i];
- $filled[$i >> 4] = $pos;
- $pos += 16*2;
- $i |= 15;
+
+ if (defined $decomp_table[$i])
+ {
+ $lastchar_decomp = $i;
+ # fully expand input and mappings
+
+ my @char;
+ push @char, $i;
+ push @char, 0;
+ my $char = pack "n*", @char;
+
+ my @nfd = do_decomp( $i, \@decomp_table, 0 );
+ push @nfd, 0;
+ my $nfd = pack "n*", @nfd;
+
+ my @nfkd = do_decomp( $i, \@decomp_table, 1 );
+ push @nfkd, 0;
+ my $nfkd = pack "n*", @nfkd;
+
+ # lookup or add mappings
+
+ if ($nfd eq $char)
+ {
+ $nfd = undef;
+ }
+ elsif (exists $decomp_lookup{$nfd})
+ {
+ $nfd_lookup{$i} = $decomp_lookup{$nfd};
+ }
+ else
+ {
+ push @decomp_data, @nfd;
+ $decomp_lookup{$nfd} = $pos;
+ $nfd_lookup{$i} = $pos;
+ $pos += @nfd;
+ }
+
+ if ($nfkd eq $char)
+ {
+ $nfkd = undef;
+ }
+ elsif (exists $decomp_lookup{$nfkd})
+ {
+ $nfkd_lookup{$i} = $decomp_lookup{$nfkd};
+ }
+ else
+ {
+ push @decomp_data, @nfkd;
+ $decomp_lookup{$nfkd} = $pos;
+ $nfkd_lookup{$i} = $pos;
+ $pos += @nfkd;
+ }
+ }
}
- my $total = $pos;
- # now count the 256-char subsets that contain something
+ printf OUTPUT "static const UINT last_decomposable = 0x%x;\n\n", $lastchar_decomp;
- my @filled_idx = (256) x 256;
- $pos = 256 + 16;
- for (my $i = 0; $i < 4096; $i++)
+ # dump decomposition data
+
+ printf OUTPUT "static const WCHAR data_decomp[%d] =\n", $pos;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @decomp_data );
+ print OUTPUT "\n};\n\n";
+
+ # find 256-char subsets that contain something
+
+ my $filled_pos = 1;
+ my $filled_lim = ($lastchar_decomp >> 8) + 1;
+ my @filled = (0) x $filled_lim;
+ for (my $i = 0; $i < $utflim; $i++)
+ {
+ last if $i > $lastchar_decomp;
+ next unless exists $nfd_lookup{$i} || exists $nfkd_lookup{$i};
+ $filled[$i >> 8] = $filled_pos++;
+ $i |= 255;
+ }
+
+ # dump index of 256-char subsets
+
+ printf OUTPUT "static const BYTE idx1_decomp[%d] =\n", $filled_lim;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @filled );
+ print OUTPUT "\n};\n\n";
+
+ # for 256-char subsets, find non-empty 16-char subsets
+
+ my $sub_filled_pos = 1;
+ my %sub_filled = ();
+ for (my $i = 0; $i < $filled_lim; $i++)
{
next unless $filled[$i];
- $filled_idx[$i >> 4] = $pos;
- $pos += 16;
- $i |= 15;
+ for (my $j = 0; $j < 256; $j++)
+ {
+ my $idx = ($i << 8) | $j;
+ next unless exists $nfd_lookup{$idx} || exists $nfkd_lookup{$idx};
+ $sub_filled{$idx >> 4} = $sub_filled_pos++;
+ $j |= 15;
+ }
}
- my $null_offset = $pos; # null mapping
- $total += $pos;
- # add the index offsets to the subsets positions
+ # dump index of 16-char subsets
- for (my $i = 0; $i < 4096; $i++)
+ printf OUTPUT "static const USHORT idx2_decomp[%d] =\n", $filled_pos * 16;
+ print OUTPUT "{\n";
+ my @null_idx = (0) x 16;
+ print OUTPUT " /* null sub-index */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+ for (my $i = 0; $i < $filled_lim; $i++)
{
next unless $filled[$i];
- $filled[$i] += $null_offset;
+ printf OUTPUT ",\n /* sub-index 0x%02x */\n", $filled[$i];
+
+ my @sub_idx;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($i << 4) | $j;
+ $sub_idx[$j] = $sub_filled{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
}
+ print OUTPUT "\n};\n\n";
- # dump the main index
+ # dump the 16-char subsets
- printf OUTPUT "static const WCHAR table[%d] =\n", $total;
- printf OUTPUT "{\n /* index */\n";
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @filled_idx );
- printf OUTPUT ",\n /* null sub-index */\n%s", DUMP_ARRAY( "0x%04x", 0, ($null_offset) x 16 );
+ printf OUTPUT "static const USHORT offsets_decomp[%d] =\n", 32 * $sub_filled_pos;
+ print OUTPUT "{\n";
+ print OUTPUT " /* (nfd, nfkd) x 16 */\n";
+ my @null_table = (0) x 32;
+ print OUTPUT " /* no decomposition */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+ for my $key (sort {$a <=> $b} keys %sub_filled)
+ {
+ printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+ my @sub_table;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($key << 4) | $j;
+ $sub_table[2 * $j] = $nfd_lookup{$idx} || 0;
+ $sub_table[2 * $j + 1] = $nfkd_lookup{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+ }
+ print OUTPUT "\n};\n\n";
- # dump the second-level indexes
+ print OUTPUT <<"EOF";
+static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1, UINT scale_idx1,
+ const USHORT *idx2, UINT scale_idx2, const USHORT *offsets,
+ UINT scale_off, const WCHAR *data, UINT scale_data )
+{
+ USHORT a, b, c, d;
- for (my $i = 0; $i < 256; $i++)
+ a = idx1[cp >> scale_idx1];
+ b = idx2[(a << scale_idx2) + ((cp >> scale_idx2) & 0xf)];
+ c = (b << scale_off) + ((cp & 0xf) << scale_data);
+ if (compat) ++c;
+ d = offsets[c];
+
+ return &data[d];
+}
+
+static int decompose_char_recursive( int compat, UINT ch, WCHAR *dst, int dstlen )
+{
+ int total_decomp = 0;
+ int size_decomp;
+ const WCHAR *map;
+
+ if (ch < 0xa0) /* fast path */
{
- next unless ($filled_idx[$i] > 256);
- my @table = @filled[($i<<4)..($i<<4)+15];
- for (my $j = 0; $j < 16; $j++) { $table[$j] ||= $null_offset; }
- printf OUTPUT ",\n /* sub-index %02x */\n", $i;
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @table );
+ if (dstlen) *dst = (WCHAR)ch;
+ return 1;
+ }
+ else if (ch > last_decomposable ||
+ !*(map = unicode_table_lookup( ch, compat, idx1_decomp, 8,
+ idx2_decomp, 4, offsets_decomp, 5, data_decomp, 1 )))
+ {
+ if (dstlen) *dst = (WCHAR)ch;
+ return 1;
}
+ else {
+ while (*map)
+ {
+ size_decomp = decompose_char_recursive( compat, *map, dst, dstlen );
+ dstlen -= size_decomp;
+ if (dstlen < 0) dstlen = 0;
+ dst += size_decomp;
+ map++;
+ total_decomp += size_decomp;
+ }
+ return total_decomp;
+ }
+}
- # dump the 16-char subsets
+int wine_unicode_decompose_string( int compat, const WCHAR *src,
+ int srclen, WCHAR *dst, int dstlen )
+{
+ UINT ch;
+ int srcpos = 0, dstpos = 0;
+ int decomp_len;
- printf OUTPUT ",\n /* null mapping */\n";
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, (0) x 32 );
+ if (dstlen < 0) dstlen = 0;
- for (my $i = 0; $i < 4096; $i++)
+ while (srcpos < srclen)
{
- next unless $filled[$i];
- my @table = (0) x 32;
- for (my $j = 0; $j < 16; $j++)
+ ch = src[srcpos];
+
+ decomp_len = decompose_char_recursive( compat, ch, dst+dstpos, dstlen );
+ dstpos += decomp_len;
+
+ if (dstlen > 0)
{
- if (defined $decomp_table[($i<<4) + $j])
+ dstlen -= decomp_len;
+ while (dstlen < 0)
{
- $table[2 * $j] = ${$decomp_table[($i << 4) + $j]}[0];
- $table[2 * $j + 1] = ${$decomp_table[($i << 4) + $j]}[1];
+ dstpos--;
+ dstlen++;
}
}
- printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $i, $i;
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @table );
+
+ ++srcpos;
}
- printf OUTPUT "\n};\n\n";
- print OUTPUT <<"EOF";
-unsigned int DECLSPEC_HIDDEN wine_decompose( WCHAR ch, WCHAR *dst, unsigned int dstlen )
-{
- const WCHAR *ptr = table + table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + 2 * (ch & 0xf);
- unsigned int res;
-
- *dst = ch;
- if (!*ptr) return 1;
- if (dstlen <= 1) return 0;
- /* apply the decomposition recursively to the first char */
- if ((res = wine_decompose( *ptr, dst, dstlen-1 ))) dst[res++] = ptr[1];
- return res;
+ return dstpos;
}
EOF
close OUTPUT;
--
2.17.1
From c19686947741c4035d22337e3004ce7c0ee51039 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Wed, 4 Apr 2018 10:49:39 -0500
Subject: [PATCH 1/4] tools/make_unicode: Implement full Unicode character
decomposition.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
libs/port/mbtowc.c | 14 +--
tools/make_unicode | 333 +++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 279 insertions(+), 68 deletions(-)
diff --git a/libs/port/mbtowc.c b/libs/port/mbtowc.c
index 4977c82..6976f89 100644
--- a/libs/port/mbtowc.c
+++ b/libs/port/mbtowc.c
@@ -22,7 +22,7 @@
#include "wine/unicode.h"
-extern unsigned int wine_decompose( WCHAR ch, WCHAR *dst, unsigned int dstlen ) DECLSPEC_HIDDEN;
+extern int wine_unicode_decompose_string( int compat, const WCHAR *src, int srclen, WCHAR *dst, int dstlen );
/* check the code whether it is in Unicode Private Use Area (PUA). */
/* MB_ERR_INVALID_CHARS raises an error converting from 1-byte character to PUA. */
@@ -101,19 +101,19 @@ static int mbstowcs_sbcs_decompose( const struct sbcs_table *table, int flags,
WCHAR *dst, unsigned int dstlen )
{
const WCHAR * const cp2uni = (flags & MB_USEGLYPHCHARS) ? table->cp2uni_glyphs : table->cp2uni;
- unsigned int len;
+ int len;
if (!dstlen) /* compute length */
{
WCHAR dummy[4]; /* no decomposition is larger than 4 chars */
for (len = 0; srclen; srclen--, src++)
- len += wine_decompose( cp2uni[*src], dummy, 4 );
+ len += wine_unicode_decompose_string( 0, &cp2uni[*src], 1, dummy, 4 );
return len;
}
for (len = dstlen; srclen && len; srclen--, src++)
{
- unsigned int res = wine_decompose( cp2uni[*src], dst, len );
+ int res = wine_unicode_decompose_string( 0, &cp2uni[*src], 1, dst, len );
if (!res) break;
len -= res;
dst += res;
@@ -203,7 +203,7 @@ static int mbstowcs_dbcs_decompose( const struct dbcs_table *table,
{
const WCHAR * const cp2uni = table->cp2uni;
const unsigned char * const cp2uni_lb = table->cp2uni_leadbytes;
- unsigned int len, res;
+ int len, res;
WCHAR ch;
if (!dstlen) /* compute length */
@@ -219,7 +219,7 @@ static int mbstowcs_dbcs_decompose( const struct dbcs_table *table,
ch = cp2uni[(off << 8) + *src];
}
else ch = cp2uni[*src];
- len += wine_decompose( ch, dummy, 4 );
+ len += wine_unicode_decompose_string( 0, &ch, 1, dummy, 4 );
}
return len;
}
@@ -234,7 +234,7 @@ static int mbstowcs_dbcs_decompose( const struct dbcs_table *table,
ch = cp2uni[(off << 8) + *src];
}
else ch = cp2uni[*src];
- if (!(res = wine_decompose( ch, dst, len ))) break;
+ if (!(res = wine_unicode_decompose_string( 0, &ch, 1, dst, len ))) break;
dst += res;
len -= res;
}
diff --git a/tools/make_unicode b/tools/make_unicode
index 56d1905..2aa063b 100755
--- a/tools/make_unicode
+++ b/tools/make_unicode
@@ -472,6 +472,28 @@ sub READ_DEFAULTS($)
next if $decomp eq ""; # no decomposition, skip it
+ # store decomposition table
+ if ($decomp =~ /^<([a-zA-Z]+)>(\s+[0-9a-fA-F]+)+$/)
+ {
+ my @seq = ();
+ for my $ch (split /\s+/, (split /\s+/, $decomp, 2)[1])
+ {
+ push @seq, (hex $ch);
+ }
+ $decomp_table[$src] = [1, \@seq];
+ }
+ elsif ($decomp =~ /^([0-9a-fA-F]+)(\s+([0-9a-fA-F]+))*$/)
+ {
+ my @seq = ();
+ for my $ch (split /\s+/, $decomp)
+ {
+ # we don't support surrogates at the moment
+ next if hex $ch > 0xffff;
+ push @seq, (hex $ch);
+ }
+ $decomp_table[$src] = [0, \@seq];
+ }
+
if ($decomp =~ /^<([a-zA-Z]+)>\s+([0-9a-fA-F]+)$/)
{
# decomposition of the form "<foo> 1234" -> use char if type is known
@@ -506,16 +528,13 @@ sub READ_DEFAULTS($)
# decomposition contains only char values without prefix -> use first char
$dst = hex $1;
$category_table[$src] |= $category_table[$dst] if defined $category_table[$dst];
- # store decomposition if it contains two chars
if ($decomp =~ /^([0-9a-fA-F]+)\s+([0-9a-fA-F]+)$/)
{
- $decomp_table[$src] = [ hex $1, hex $2 ];
push @compose_table, [ hex $1, hex $2, $src ];
}
elsif ($decomp =~ /^(<[a-z]+>\s)*([0-9a-fA-F]+)$/ &&
(($src >= 0xf900 && $src < 0xfb00) || ($src >= 0xfe30 && $src < 0xfffd)))
{
- # Single char decomposition in the compatibility range
$compatmap_table[$src] = hex $2;
}
}
@@ -2264,6 +2283,51 @@ EOF
save_file($filename);
}
+sub do_decomp
+{
+ my ($char, $table_ref, $compat) = @_;
+
+ return ($char) unless defined $table_ref->[$char];
+ my $data = $table_ref->[$char];
+ return ($char) if $data->[0] && !$compat;
+ my @mapping = ();
+ for my $ch (@{$data->[1]})
+ {
+ push @mapping, $ch;
+ }
+ return @mapping;
+}
+
+sub expand_pairs
+{
+ my @data = @_;
+ my @result = ();
+
+ for my $ch (@data)
+ {
+ if ($ch <= 0xFFFF)
+ {
+ push @result, $ch;
+ }
+ elsif ($ch >= 2097152) # 2**21
+ {
+ die sprintf "Invalid Unicode character %04x\n", $ch;
+ }
+ else
+ {
+ my $hx = $ch & 0xFFFF;
+ my $hu = ($ch >> 16) & ((1 << 5) - 1);
+ my $hw = ($hu - 1) & 0xFFFF;
+ my $hi = 0xD800 | ($hw << 6) | ($hx >> 10);
+ my $lx = $ch & 0xFFFF;
+ my $lo = (0xDC00 | ($lx & ((1 << 10) - 1))) & 0xFFFF;
+ push @result, $hi;
+ push @result, $lo;
+ }
+ }
+ return @result;
+}
+
################################################################
# dump the char decomposition table
sub dump_decompose_table($)
@@ -2272,98 +2336,245 @@ sub dump_decompose_table($)
open OUTPUT,">$filename.new" or die "Cannot create $filename";
print "Building $filename\n";
- print OUTPUT "/* Unicode char composition */\n";
+ print OUTPUT "/* Unicode char decomposition */\n";
print OUTPUT "/* generated from $UNIDATA/UnicodeData.txt */\n";
print OUTPUT "/* DO NOT EDIT!! */\n\n";
print OUTPUT "#include \"wine/unicode.h\"\n\n";
- # first determine all the 16-char subsets that contain something
+ # limit code points to BMP
+ my $utflim = 65536;
+ my %nfd_lookup = ();
+ my %nfkd_lookup = ();
+ my %decomp_lookup = ();
+ my @decomp_data = (0);
+ my $pos = 1;
+ my $lastchar_decomp;
- my @filled = (0) x 4096;
- my $pos = 16*2; # for the null subset
- for (my $i = 0; $i < 65536; $i++)
+ for (my $i = 0; $i < $utflim; $i++)
{
next unless defined $decomp_table[$i];
- $filled[$i >> 4] = $pos;
- $pos += 16*2;
- $i |= 15;
+
+ if (defined $decomp_table[$i])
+ {
+ $lastchar_decomp = $i;
+ # fully expand input and mappings
+
+ my @char;
+ push @char, $i;
+ push @char, 0;
+ my $char = pack "n*", @char;
+
+ my @nfd = do_decomp( $i, \@decomp_table, 0 );
+ push @nfd, 0;
+ my $nfd = pack "n*", @nfd;
+
+ my @nfkd = do_decomp( $i, \@decomp_table, 1 );
+ push @nfkd, 0;
+ my $nfkd = pack "n*", @nfkd;
+
+ # lookup or add mappings
+
+ if ($nfd eq $char)
+ {
+ $nfd = undef;
+ }
+ elsif (exists $decomp_lookup{$nfd})
+ {
+ $nfd_lookup{$i} = $decomp_lookup{$nfd};
+ }
+ else
+ {
+ push @decomp_data, @nfd;
+ $decomp_lookup{$nfd} = $pos;
+ $nfd_lookup{$i} = $pos;
+ $pos += @nfd;
+ }
+
+ if ($nfkd eq $char)
+ {
+ $nfkd = undef;
+ }
+ elsif (exists $decomp_lookup{$nfkd})
+ {
+ $nfkd_lookup{$i} = $decomp_lookup{$nfkd};
+ }
+ else
+ {
+ push @decomp_data, @nfkd;
+ $decomp_lookup{$nfkd} = $pos;
+ $nfkd_lookup{$i} = $pos;
+ $pos += @nfkd;
+ }
+ }
}
- my $total = $pos;
- # now count the 256-char subsets that contain something
+ printf OUTPUT "static const UINT last_decomposable = 0x%x;\n\n", $lastchar_decomp;
- my @filled_idx = (256) x 256;
- $pos = 256 + 16;
- for (my $i = 0; $i < 4096; $i++)
+ # dump decomposition data
+
+ printf OUTPUT "static const WCHAR data_decomp[%d] =\n", $pos;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @decomp_data );
+ print OUTPUT "\n};\n\n";
+
+ # find 256-char subsets that contain something
+
+ my $filled_pos = 1;
+ my $filled_lim = ($lastchar_decomp >> 8) + 1;
+ my @filled = (0) x $filled_lim;
+ for (my $i = 0; $i < $utflim; $i++)
+ {
+ last if $i > $lastchar_decomp;
+ next unless exists $nfd_lookup{$i} || exists $nfkd_lookup{$i};
+ $filled[$i >> 8] = $filled_pos++;
+ $i |= 255;
+ }
+
+ # dump index of 256-char subsets
+
+ printf OUTPUT "static const BYTE idx1_decomp[%d] =\n", $filled_lim;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @filled );
+ print OUTPUT "\n};\n\n";
+
+ # for 256-char subsets, find non-empty 16-char subsets
+
+ my $sub_filled_pos = 1;
+ my %sub_filled = ();
+ for (my $i = 0; $i < $filled_lim; $i++)
{
next unless $filled[$i];
- $filled_idx[$i >> 4] = $pos;
- $pos += 16;
- $i |= 15;
+ for (my $j = 0; $j < 256; $j++)
+ {
+ my $idx = ($i << 8) | $j;
+ next unless exists $nfd_lookup{$idx} || exists $nfkd_lookup{$idx};
+ $sub_filled{$idx >> 4} = $sub_filled_pos++;
+ $j |= 15;
+ }
}
- my $null_offset = $pos; # null mapping
- $total += $pos;
- # add the index offsets to the subsets positions
+ # dump index of 16-char subsets
- for (my $i = 0; $i < 4096; $i++)
+ printf OUTPUT "static const USHORT idx2_decomp[%d] =\n", $filled_pos * 16;
+ print OUTPUT "{\n";
+ my @null_idx = (0) x 16;
+ print OUTPUT " /* null sub-index */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+ for (my $i = 0; $i < $filled_lim; $i++)
{
next unless $filled[$i];
- $filled[$i] += $null_offset;
+ printf OUTPUT ",\n /* sub-index 0x%02x */\n", $filled[$i];
+
+ my @sub_idx;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($i << 4) | $j;
+ $sub_idx[$j] = $sub_filled{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
}
+ print OUTPUT "\n};\n\n";
- # dump the main index
+ # dump the 16-char subsets
- printf OUTPUT "static const WCHAR table[%d] =\n", $total;
- printf OUTPUT "{\n /* index */\n";
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @filled_idx );
- printf OUTPUT ",\n /* null sub-index */\n%s", DUMP_ARRAY( "0x%04x", 0, ($null_offset) x 16 );
+ printf OUTPUT "static const USHORT offsets_decomp[%d] =\n", 32 * $sub_filled_pos;
+ print OUTPUT "{\n";
+ print OUTPUT " /* (nfd, nfkd) x 16 */\n";
+ my @null_table = (0) x 32;
+ print OUTPUT " /* no decomposition */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+ for my $key (sort {$a <=> $b} keys %sub_filled)
+ {
+ printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+ my @sub_table;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($key << 4) | $j;
+ $sub_table[2 * $j] = $nfd_lookup{$idx} || 0;
+ $sub_table[2 * $j + 1] = $nfkd_lookup{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+ }
+ print OUTPUT "\n};\n\n";
- # dump the second-level indexes
+ print OUTPUT <<"EOF";
+static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1, UINT scale_idx1,
+ const USHORT *idx2, UINT scale_idx2, const USHORT *offsets,
+ UINT scale_off, const WCHAR *data, UINT scale_data )
+{
+ USHORT a, b, c, d;
- for (my $i = 0; $i < 256; $i++)
+ a = idx1[cp >> scale_idx1];
+ b = idx2[(a << scale_idx2) + ((cp >> scale_idx2) & 0xf)];
+ c = (b << scale_off) + ((cp & 0xf) << scale_data);
+ if (compat) ++c;
+ d = offsets[c];
+
+ return &data[d];
+}
+
+static int decompose_char_recursive( int compat, UINT ch, WCHAR *dst, int dstlen )
+{
+ int total_decomp = 0;
+ int size_decomp;
+ const WCHAR *map;
+
+ if (ch < 0xa0) /* fast path */
{
- next unless ($filled_idx[$i] > 256);
- my @table = @filled[($i<<4)..($i<<4)+15];
- for (my $j = 0; $j < 16; $j++) { $table[$j] ||= $null_offset; }
- printf OUTPUT ",\n /* sub-index %02x */\n", $i;
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @table );
+ if (dstlen) *dst = (WCHAR)ch;
+ return 1;
+ }
+ else if (ch > last_decomposable ||
+ !*(map = unicode_table_lookup( ch, compat, idx1_decomp, 8,
+ idx2_decomp, 4, offsets_decomp, 5, data_decomp, 1 )))
+ {
+ if (dstlen) *dst = (WCHAR)ch;
+ return 1;
}
+ else {
+ while (*map)
+ {
+ size_decomp = decompose_char_recursive( compat, *map, dst, dstlen );
+ dstlen -= size_decomp;
+ if (dstlen < 0) dstlen = 0;
+ dst += size_decomp;
+ map++;
+ total_decomp += size_decomp;
+ }
+ return total_decomp;
+ }
+}
- # dump the 16-char subsets
+int wine_unicode_decompose_string( int compat, const WCHAR *src,
+ int srclen, WCHAR *dst, int dstlen )
+{
+ UINT ch;
+ int srcpos = 0, dstpos = 0;
+ int decomp_len;
- printf OUTPUT ",\n /* null mapping */\n";
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, (0) x 32 );
+ if (dstlen < 0) dstlen = 0;
- for (my $i = 0; $i < 4096; $i++)
+ while (srcpos < srclen)
{
- next unless $filled[$i];
- my @table = (0) x 32;
- for (my $j = 0; $j < 16; $j++)
+ ch = src[srcpos];
+
+ decomp_len = decompose_char_recursive( compat, ch, dst+dstpos, dstlen );
+ dstpos += decomp_len;
+
+ if (dstlen > 0)
{
- if (defined $decomp_table[($i<<4) + $j])
+ dstlen -= decomp_len;
+ while (dstlen < 0)
{
- $table[2 * $j] = ${$decomp_table[($i << 4) + $j]}[0];
- $table[2 * $j + 1] = ${$decomp_table[($i << 4) + $j]}[1];
+ dstpos--;
+ dstlen++;
}
}
- printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $i, $i;
- printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @table );
+
+ ++srcpos;
}
- printf OUTPUT "\n};\n\n";
- print OUTPUT <<"EOF";
-unsigned int DECLSPEC_HIDDEN wine_decompose( WCHAR ch, WCHAR *dst, unsigned int dstlen )
-{
- const WCHAR *ptr = table + table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + 2 * (ch & 0xf);
- unsigned int res;
-
- *dst = ch;
- if (!*ptr) return 1;
- if (dstlen <= 1) return 0;
- /* apply the decomposition recursively to the first char */
- if ((res = wine_decompose( *ptr, dst, dstlen-1 ))) dst[res++] = ptr[1];
- return res;
+ return dstpos;
}
EOF
close OUTPUT;
--
1.9.1

View File

@ -1,400 +1,400 @@
From 0f35e862eb3e0d2e230431b8d71c30ac34b6b329 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Tue, 27 Mar 2018 07:28:02 -0500
Subject: [PATCH 2/3] tools/make_unicode: Implement canonical composition for
use in normalization.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
tools/make_unicode | 302 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 301 insertions(+), 1 deletion(-)
diff --git a/tools/make_unicode b/tools/make_unicode
index 2aa063bff6..4b1c46fde2 100755
--- a/tools/make_unicode
+++ b/tools/make_unicode
@@ -360,6 +360,8 @@ my @joining_table = ();
my @direction_table = ();
my @decomp_table = ();
my @compose_table = ();
+my @comb_class_table = ();
+my @full_comp_table = ();
my $default_char;
my $default_wchar;
@@ -470,6 +472,11 @@ sub READ_DEFAULTS($)
}
}
+ if ($comb != 0)
+ {
+ $comb_class_table[$src] = (hex $comb);
+ }
+
next if $decomp eq ""; # no decomposition, skip it
# store decomposition table
@@ -562,6 +569,25 @@ sub READ_DEFAULTS($)
my $flag = $ctype{$cat};
foreach my $i (@{$special_categories{$cat}}) { $category_table[$i] |= $flag; }
}
+
+ my $UNICODE_DERIVED = open_data_file( $UNIDATA, "DerivedNormalizationProps.txt" );
+ while (<$UNICODE_DERIVED>)
+ {
+ next unless (/^([0-9a-fA-F.]+)\s+;\s+Full_Composition_Exclusion/);
+ my ($first, $last) = split /\.\./,$1;
+ $first = hex $first;
+ if (defined $last)
+ {
+ $last = hex $last;
+ while ($last gt $first)
+ {
+ $full_comp_table[$last] = 1;
+ $last--;
+ }
+ }
+ $full_comp_table[$first] = 1;
+ }
+ close $UNICODE_DERIVED;
}
@@ -2255,6 +2281,8 @@ sub dump_compose_table($)
}
print OUTPUT "\n};\n\n";
print OUTPUT <<"EOF";
+#include "decompose.c"
+
static inline int binary_search( WCHAR ch, int low, int high )
{
while (low <= high)
@@ -2278,6 +2306,59 @@ WCHAR DECLSPEC_HIDDEN wine_compose( const WCHAR *str )
count = table[2 * pos + 3];
}
}
+
+static inline int is_blocked(WCHAR *ptr1, WCHAR *ptr2)
+{
+ if (ptr1 >= ptr2) return -1;
+
+ while (++ptr1 < ptr2)
+ {
+ const WCHAR *map1, *map2;
+ map1 = unicode_table_lookup( *ptr1, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ map2 = unicode_table_lookup( *ptr2, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ if (*map1 == 0 || *map2 <= *map1) return 1;
+ }
+ return 0;
+}
+
+static inline int is_fullexcl(WCHAR ch)
+{
+ const WCHAR *map = unicode_table_lookup( ch, 0, idx1_fullcomp, 8, idx2_fullcomp,
+ 4, offsets_fullcomp, 4, data_fullcomp, 0 );
+ return (int)*map;
+}
+
+int unicode_canonical_composition( WCHAR *str, int strlen )
+{
+ int i, j;
+ WCHAR dum[3] = {0};
+
+ if (strlen == 0) strlen = strlenW( str );
+
+ for (i = 1; i < strlen; i++)
+ {
+ WCHAR *ptr_comp = str+i-1, comp;
+ if (str[i] == 0) break;
+ while (ptr_comp - str > 0)
+ {
+ if (is_starter( *ptr_comp )) break;
+ --ptr_comp;
+ }
+ if (!is_starter( *ptr_comp ) || is_blocked( ptr_comp, str+i )) continue;
+ dum[0] = *ptr_comp;
+ dum[1] = str[i];
+ comp = wine_compose( dum );
+ if (!comp || is_fullexcl( comp )) continue;
+ *ptr_comp = comp;
+ for (j = i; j < strlen-1; j++) str[j] = str[j+1];
+ strlen--;
+ i--;
+ }
+
+ return strlen;
+}
EOF
close OUTPUT;
save_file($filename);
@@ -2346,13 +2427,21 @@ sub dump_decompose_table($)
my %nfd_lookup = ();
my %nfkd_lookup = ();
my %decomp_lookup = ();
+ my %comb_lookup = ();
+ my %fullcomp_lookup = ();
my @decomp_data = (0);
+ my @comb_data = (0);
+ my @full_comp_data = (0);
my $pos = 1;
+ my $pos_comb = 1;
+ my $pos_fullcomp = 1;
my $lastchar_decomp;
+ my $lastchar_comb;
+ my $lastchar_fullcomp;
for (my $i = 0; $i < $utflim; $i++)
{
- next unless defined $decomp_table[$i];
+ next unless defined $decomp_table[$i] || defined $comb_class_table[$i] || defined $full_comp_table[$i];
if (defined $decomp_table[$i])
{
@@ -2406,6 +2495,20 @@ sub dump_decompose_table($)
$pos += @nfkd;
}
}
+ if (defined $comb_class_table[$i])
+ {
+ push @comb_data, $comb_class_table[$i];
+ $lastchar_comb = $i;
+ $comb_lookup{$i} = $pos_comb;
+ $pos_comb++;
+ }
+ if (defined $full_comp_table[$i])
+ {
+ push @full_comp_data, $full_comp_table[$i];
+ $lastchar_fullcomp = $i;
+ $fullcomp_lookup{$i} = $pos_fullcomp;
+ $pos_fullcomp++;
+ }
}
printf OUTPUT "static const UINT last_decomposable = 0x%x;\n\n", $lastchar_decomp;
@@ -2497,6 +2600,154 @@ sub dump_decompose_table($)
}
print OUTPUT "\n};\n\n";
+ # now for Compatibility Class
+
+ printf OUTPUT "static const WCHAR data_comb[%d] =\n", $pos_comb;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @comb_data );
+ print OUTPUT "\n};\n\n";
+
+ my $comb_pos = 1;
+ my $comb_lim = ($lastchar_comb >> 8) + 1;
+ my @comb_filled = (0) x $comb_lim;
+ for (my $i = 0; $i < $utflim; $i++)
+ {
+ last if $i > $lastchar_comb;
+ next unless defined $comb_class_table[$i];
+ $comb_filled[$i >> 8] = $comb_pos++;
+ $i |= 255;
+ }
+ printf OUTPUT "static const BYTE idx1_comb[%d] =\n", $comb_lim;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @comb_filled );
+ print OUTPUT "\n};\n\n";
+
+ my $sub_comb_filled_pos = 1;
+ my %sub_comb_filled = ();
+ for (my $i = 0; $i < $comb_lim; $i++)
+ {
+ next unless $comb_filled[$i];
+ for (my $j = 0; $j < 256; $j++)
+ {
+ my $idx = ($i << 8) | $j;
+ next unless defined $comb_class_table[$idx];
+ $sub_comb_filled{$idx >> 4} = $sub_comb_filled_pos++;
+ $j |= 15;
+ }
+ }
+
+ printf OUTPUT "static const USHORT idx2_comb[%d] =\n", $comb_pos * 16;
+ print OUTPUT "{\n";
+ @null_idx = (0) x 16;
+ print OUTPUT " /* all-zero 256-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+ for (my $i = 0; $i < $comb_lim; $i++)
+ {
+ next unless $comb_filled[$i];
+ printf OUTPUT ",\n /* sub-index 0x%02x */\n", $comb_filled[$i];
+
+ my @sub_idx;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($i << 4) | $j;
+ $sub_idx[$j] = $sub_comb_filled{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
+ }
+ print OUTPUT "\n};\n\n";
+
+ printf OUTPUT "static const USHORT offsets_comb[%d] =\n", 16 * $sub_comb_filled_pos;
+ print OUTPUT "{\n";
+ @null_table = (0) x 16;
+ print OUTPUT " /* all-zero 16-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+ for my $key (sort {$a <=> $b} keys %sub_comb_filled)
+ {
+ printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+ my @sub_table;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($key << 4) | $j;
+ $sub_table[$j] = $comb_lookup{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+ }
+ print OUTPUT "\n};\n\n";
+
+ # now for Full Composition Exclusion
+
+ printf OUTPUT "const WCHAR data_fullcomp[%d] =\n", $pos_fullcomp;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @full_comp_data );
+ print OUTPUT "\n};\n\n";
+
+ my $fullcomp_pos = 1;
+ my $fullcomp_lim = ($lastchar_fullcomp >> 8) + 1;
+ my @fullcomp_filled = (0) x $fullcomp_lim;
+ for (my $i = 0; $i < $utflim; $i++)
+ {
+ last if $i > $lastchar_fullcomp;
+ next unless defined $full_comp_table[$i];
+ $fullcomp_filled[$i >> 8] = $fullcomp_pos++;
+ $i |= 255;
+ }
+ printf OUTPUT "const BYTE idx1_fullcomp[%d] =\n", $fullcomp_lim;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @fullcomp_filled );
+ print OUTPUT "\n};\n\n";
+
+ my $sub_fullcomp_filled_pos = 1;
+ my %sub_fullcomp_filled = ();
+ for (my $i = 0; $i < $fullcomp_lim; $i++)
+ {
+ next unless $fullcomp_filled[$i];
+ for (my $j = 0; $j < 256; $j++)
+ {
+ my $idx = ($i << 8) | $j;
+ next unless defined $full_comp_table[$idx];
+ $sub_fullcomp_filled{$idx >> 4} = $sub_fullcomp_filled_pos++;
+ $j |= 15;
+ }
+ }
+
+ printf OUTPUT "const USHORT idx2_fullcomp[%d] =\n", $fullcomp_pos * 16;
+ print OUTPUT "{\n";
+ @null_idx = (0) x 16;
+ print OUTPUT " /* all-zero 256-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+ for (my $i = 0; $i < $fullcomp_lim; $i++)
+ {
+ next unless $fullcomp_filled[$i];
+ printf OUTPUT ",\n /* sub-index 0x%02x */\n", $fullcomp_filled[$i];
+
+ my @sub_idx;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($i << 4) | $j;
+ $sub_idx[$j] = $sub_fullcomp_filled{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
+ }
+ print OUTPUT "\n};\n\n";
+
+ printf OUTPUT "const USHORT offsets_fullcomp[%d] =\n", 16 * $sub_fullcomp_filled_pos;
+ print OUTPUT "{\n";
+ @null_table = (0) x 16;
+ print OUTPUT " /* all-zero 16-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+ for my $key (sort {$a <=> $b} keys %sub_fullcomp_filled)
+ {
+ printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+ my @sub_table;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($key << 4) | $j;
+ $sub_table[$j] = $fullcomp_lookup{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+ }
+ print OUTPUT "\n};\n\n";
+
print OUTPUT <<"EOF";
static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1, UINT scale_idx1,
const USHORT *idx2, UINT scale_idx2, const USHORT *offsets,
@@ -2513,6 +2764,20 @@ static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1,
return &data[d];
}
+static inline int reorderable_pair( WCHAR ch1, WCHAR ch2 )
+{
+ const WCHAR *cc1, *cc2;
+
+ if (ch1 == 0 || ch2 == 0) return 0;
+
+ cc1 = unicode_table_lookup( ch1, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ cc2 = unicode_table_lookup( ch2, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ if (*cc2 < *cc1) return 1;
+ else return 0;
+}
+
static int decompose_char_recursive( int compat, UINT ch, WCHAR *dst, int dstlen )
{
int total_decomp = 0;
@@ -2576,6 +2841,41 @@ int wine_unicode_decompose_string( int compat, const WCHAR *src,
return dstpos;
}
+
+int is_starter( WCHAR ch )
+{
+ const WCHAR *map = unicode_table_lookup( ch, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ return (*map == 0) ? 1 : 0;
+}
+
+void unicode_canon_order( WCHAR *str, int strlen )
+{
+ int i, j, m;
+ int sublen = 0, tot_sublen = 0;
+ WCHAR *substr = str;
+
+ for (m = 1; m <= strlen; m++)
+ {
+ if (m == strlen || is_starter( str[m] )) sublen = m - tot_sublen;
+ else continue;
+
+ for (i = 0; i < sublen; i++)
+ {
+ for (j = 1; j < sublen; j++)
+ {
+ if (reorderable_pair( substr[j-1], substr[j] ))
+ {
+ WCHAR swp = substr[j-1];
+ substr[j-1] = substr[j];
+ substr[j] = swp;
+ }
+ }
+ }
+ tot_sublen += m;
+ substr = str+m;
+ }
+}
EOF
close OUTPUT;
save_file($filename);
--
2.17.1
From 1f362267f8196f6017e4e08a9dd4dca589c494d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Tue, 27 Mar 2018 07:28:02 -0500
Subject: [PATCH 2/4] tools/make_unicode: Implement canonical composition for
use in normalization.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
tools/make_unicode | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 301 insertions(+), 1 deletion(-)
diff --git a/tools/make_unicode b/tools/make_unicode
index 2aa063b..4b1c46f 100755
--- a/tools/make_unicode
+++ b/tools/make_unicode
@@ -360,6 +360,8 @@ my @joining_table = ();
my @direction_table = ();
my @decomp_table = ();
my @compose_table = ();
+my @comb_class_table = ();
+my @full_comp_table = ();
my $default_char;
my $default_wchar;
@@ -470,6 +472,11 @@ sub READ_DEFAULTS($)
}
}
+ if ($comb != 0)
+ {
+ $comb_class_table[$src] = (hex $comb);
+ }
+
next if $decomp eq ""; # no decomposition, skip it
# store decomposition table
@@ -562,6 +569,25 @@ sub READ_DEFAULTS($)
my $flag = $ctype{$cat};
foreach my $i (@{$special_categories{$cat}}) { $category_table[$i] |= $flag; }
}
+
+ my $UNICODE_DERIVED = open_data_file( $UNIDATA, "DerivedNormalizationProps.txt" );
+ while (<$UNICODE_DERIVED>)
+ {
+ next unless (/^([0-9a-fA-F.]+)\s+;\s+Full_Composition_Exclusion/);
+ my ($first, $last) = split /\.\./,$1;
+ $first = hex $first;
+ if (defined $last)
+ {
+ $last = hex $last;
+ while ($last gt $first)
+ {
+ $full_comp_table[$last] = 1;
+ $last--;
+ }
+ }
+ $full_comp_table[$first] = 1;
+ }
+ close $UNICODE_DERIVED;
}
@@ -2255,6 +2281,8 @@ sub dump_compose_table($)
}
print OUTPUT "\n};\n\n";
print OUTPUT <<"EOF";
+#include "decompose.c"
+
static inline int binary_search( WCHAR ch, int low, int high )
{
while (low <= high)
@@ -2278,6 +2306,59 @@ WCHAR DECLSPEC_HIDDEN wine_compose( const WCHAR *str )
count = table[2 * pos + 3];
}
}
+
+static inline int is_blocked(WCHAR *ptr1, WCHAR *ptr2)
+{
+ if (ptr1 >= ptr2) return -1;
+
+ while (++ptr1 < ptr2)
+ {
+ const WCHAR *map1, *map2;
+ map1 = unicode_table_lookup( *ptr1, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ map2 = unicode_table_lookup( *ptr2, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ if (*map1 == 0 || *map2 <= *map1) return 1;
+ }
+ return 0;
+}
+
+static inline int is_fullexcl(WCHAR ch)
+{
+ const WCHAR *map = unicode_table_lookup( ch, 0, idx1_fullcomp, 8, idx2_fullcomp,
+ 4, offsets_fullcomp, 4, data_fullcomp, 0 );
+ return (int)*map;
+}
+
+int unicode_canonical_composition( WCHAR *str, int strlen )
+{
+ int i, j;
+ WCHAR dum[3] = {0};
+
+ if (strlen == 0) strlen = strlenW( str );
+
+ for (i = 1; i < strlen; i++)
+ {
+ WCHAR *ptr_comp = str+i-1, comp;
+ if (str[i] == 0) break;
+ while (ptr_comp - str > 0)
+ {
+ if (is_starter( *ptr_comp )) break;
+ --ptr_comp;
+ }
+ if (!is_starter( *ptr_comp ) || is_blocked( ptr_comp, str+i )) continue;
+ dum[0] = *ptr_comp;
+ dum[1] = str[i];
+ comp = wine_compose( dum );
+ if (!comp || is_fullexcl( comp )) continue;
+ *ptr_comp = comp;
+ for (j = i; j < strlen-1; j++) str[j] = str[j+1];
+ strlen--;
+ i--;
+ }
+
+ return strlen;
+}
EOF
close OUTPUT;
save_file($filename);
@@ -2346,13 +2427,21 @@ sub dump_decompose_table($)
my %nfd_lookup = ();
my %nfkd_lookup = ();
my %decomp_lookup = ();
+ my %comb_lookup = ();
+ my %fullcomp_lookup = ();
my @decomp_data = (0);
+ my @comb_data = (0);
+ my @full_comp_data = (0);
my $pos = 1;
+ my $pos_comb = 1;
+ my $pos_fullcomp = 1;
my $lastchar_decomp;
+ my $lastchar_comb;
+ my $lastchar_fullcomp;
for (my $i = 0; $i < $utflim; $i++)
{
- next unless defined $decomp_table[$i];
+ next unless defined $decomp_table[$i] || defined $comb_class_table[$i] || defined $full_comp_table[$i];
if (defined $decomp_table[$i])
{
@@ -2406,6 +2495,20 @@ sub dump_decompose_table($)
$pos += @nfkd;
}
}
+ if (defined $comb_class_table[$i])
+ {
+ push @comb_data, $comb_class_table[$i];
+ $lastchar_comb = $i;
+ $comb_lookup{$i} = $pos_comb;
+ $pos_comb++;
+ }
+ if (defined $full_comp_table[$i])
+ {
+ push @full_comp_data, $full_comp_table[$i];
+ $lastchar_fullcomp = $i;
+ $fullcomp_lookup{$i} = $pos_fullcomp;
+ $pos_fullcomp++;
+ }
}
printf OUTPUT "static const UINT last_decomposable = 0x%x;\n\n", $lastchar_decomp;
@@ -2497,6 +2600,154 @@ sub dump_decompose_table($)
}
print OUTPUT "\n};\n\n";
+ # now for Compatibility Class
+
+ printf OUTPUT "static const WCHAR data_comb[%d] =\n", $pos_comb;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @comb_data );
+ print OUTPUT "\n};\n\n";
+
+ my $comb_pos = 1;
+ my $comb_lim = ($lastchar_comb >> 8) + 1;
+ my @comb_filled = (0) x $comb_lim;
+ for (my $i = 0; $i < $utflim; $i++)
+ {
+ last if $i > $lastchar_comb;
+ next unless defined $comb_class_table[$i];
+ $comb_filled[$i >> 8] = $comb_pos++;
+ $i |= 255;
+ }
+ printf OUTPUT "static const BYTE idx1_comb[%d] =\n", $comb_lim;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @comb_filled );
+ print OUTPUT "\n};\n\n";
+
+ my $sub_comb_filled_pos = 1;
+ my %sub_comb_filled = ();
+ for (my $i = 0; $i < $comb_lim; $i++)
+ {
+ next unless $comb_filled[$i];
+ for (my $j = 0; $j < 256; $j++)
+ {
+ my $idx = ($i << 8) | $j;
+ next unless defined $comb_class_table[$idx];
+ $sub_comb_filled{$idx >> 4} = $sub_comb_filled_pos++;
+ $j |= 15;
+ }
+ }
+
+ printf OUTPUT "static const USHORT idx2_comb[%d] =\n", $comb_pos * 16;
+ print OUTPUT "{\n";
+ @null_idx = (0) x 16;
+ print OUTPUT " /* all-zero 256-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+ for (my $i = 0; $i < $comb_lim; $i++)
+ {
+ next unless $comb_filled[$i];
+ printf OUTPUT ",\n /* sub-index 0x%02x */\n", $comb_filled[$i];
+
+ my @sub_idx;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($i << 4) | $j;
+ $sub_idx[$j] = $sub_comb_filled{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
+ }
+ print OUTPUT "\n};\n\n";
+
+ printf OUTPUT "static const USHORT offsets_comb[%d] =\n", 16 * $sub_comb_filled_pos;
+ print OUTPUT "{\n";
+ @null_table = (0) x 16;
+ print OUTPUT " /* all-zero 16-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+ for my $key (sort {$a <=> $b} keys %sub_comb_filled)
+ {
+ printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+ my @sub_table;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($key << 4) | $j;
+ $sub_table[$j] = $comb_lookup{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+ }
+ print OUTPUT "\n};\n\n";
+
+ # now for Full Composition Exclusion
+
+ printf OUTPUT "const WCHAR data_fullcomp[%d] =\n", $pos_fullcomp;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @full_comp_data );
+ print OUTPUT "\n};\n\n";
+
+ my $fullcomp_pos = 1;
+ my $fullcomp_lim = ($lastchar_fullcomp >> 8) + 1;
+ my @fullcomp_filled = (0) x $fullcomp_lim;
+ for (my $i = 0; $i < $utflim; $i++)
+ {
+ last if $i > $lastchar_fullcomp;
+ next unless defined $full_comp_table[$i];
+ $fullcomp_filled[$i >> 8] = $fullcomp_pos++;
+ $i |= 255;
+ }
+ printf OUTPUT "const BYTE idx1_fullcomp[%d] =\n", $fullcomp_lim;
+ print OUTPUT "{\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @fullcomp_filled );
+ print OUTPUT "\n};\n\n";
+
+ my $sub_fullcomp_filled_pos = 1;
+ my %sub_fullcomp_filled = ();
+ for (my $i = 0; $i < $fullcomp_lim; $i++)
+ {
+ next unless $fullcomp_filled[$i];
+ for (my $j = 0; $j < 256; $j++)
+ {
+ my $idx = ($i << 8) | $j;
+ next unless defined $full_comp_table[$idx];
+ $sub_fullcomp_filled{$idx >> 4} = $sub_fullcomp_filled_pos++;
+ $j |= 15;
+ }
+ }
+
+ printf OUTPUT "const USHORT idx2_fullcomp[%d] =\n", $fullcomp_pos * 16;
+ print OUTPUT "{\n";
+ @null_idx = (0) x 16;
+ print OUTPUT " /* all-zero 256-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+ for (my $i = 0; $i < $fullcomp_lim; $i++)
+ {
+ next unless $fullcomp_filled[$i];
+ printf OUTPUT ",\n /* sub-index 0x%02x */\n", $fullcomp_filled[$i];
+
+ my @sub_idx;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($i << 4) | $j;
+ $sub_idx[$j] = $sub_fullcomp_filled{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
+ }
+ print OUTPUT "\n};\n\n";
+
+ printf OUTPUT "const USHORT offsets_fullcomp[%d] =\n", 16 * $sub_fullcomp_filled_pos;
+ print OUTPUT "{\n";
+ @null_table = (0) x 16;
+ print OUTPUT " /* all-zero 16-char blocks get mapped to here */\n";
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+ for my $key (sort {$a <=> $b} keys %sub_fullcomp_filled)
+ {
+ printf OUTPUT ",\n /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+ my @sub_table;
+ for (my $j = 0; $j < 16; $j++)
+ {
+ my $idx = ($key << 4) | $j;
+ $sub_table[$j] = $fullcomp_lookup{$idx} || 0;
+ }
+ printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+ }
+ print OUTPUT "\n};\n\n";
+
print OUTPUT <<"EOF";
static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1, UINT scale_idx1,
const USHORT *idx2, UINT scale_idx2, const USHORT *offsets,
@@ -2513,6 +2764,20 @@ static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1,
return &data[d];
}
+static inline int reorderable_pair( WCHAR ch1, WCHAR ch2 )
+{
+ const WCHAR *cc1, *cc2;
+
+ if (ch1 == 0 || ch2 == 0) return 0;
+
+ cc1 = unicode_table_lookup( ch1, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ cc2 = unicode_table_lookup( ch2, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ if (*cc2 < *cc1) return 1;
+ else return 0;
+}
+
static int decompose_char_recursive( int compat, UINT ch, WCHAR *dst, int dstlen )
{
int total_decomp = 0;
@@ -2576,6 +2841,41 @@ int wine_unicode_decompose_string( int compat, const WCHAR *src,
return dstpos;
}
+
+int is_starter( WCHAR ch )
+{
+ const WCHAR *map = unicode_table_lookup( ch, 0, idx1_comb, 8, idx2_comb, 4,
+ offsets_comb, 4, data_comb, 0 );
+ return (*map == 0) ? 1 : 0;
+}
+
+void unicode_canon_order( WCHAR *str, int strlen )
+{
+ int i, j, m;
+ int sublen = 0, tot_sublen = 0;
+ WCHAR *substr = str;
+
+ for (m = 1; m <= strlen; m++)
+ {
+ if (m == strlen || is_starter( str[m] )) sublen = m - tot_sublen;
+ else continue;
+
+ for (i = 0; i < sublen; i++)
+ {
+ for (j = 1; j < sublen; j++)
+ {
+ if (reorderable_pair( substr[j-1], substr[j] ))
+ {
+ WCHAR swp = substr[j-1];
+ substr[j-1] = substr[j];
+ substr[j] = swp;
+ }
+ }
+ }
+ tot_sublen += m;
+ substr = str+m;
+ }
+}
EOF
close OUTPUT;
save_file($filename);
--
1.9.1

View File

@ -1,183 +1,183 @@
From 965604cac1de3c3a6db44f99094da3a6ec91fc11 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Fri, 6 Apr 2018 10:29:39 -0500
Subject: [PATCH 3/3] kernel32: Implement NormalizeString API function.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
dlls/kernel32/locale.c | 88 ++++++++++++++++++++++++++++++++++--
dlls/kernel32/tests/locale.c | 44 ++++++++----------
2 files changed, 103 insertions(+), 29 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 4d1eac6ebe..607008fcc7 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -5358,15 +5358,93 @@ INT WINAPI GetUserDefaultLocaleName(LPWSTR localename, int buffersize)
return LCIDToLocaleName(userlcid, localename, buffersize, 0);
}
+static inline int is_valid_norm(NORM_FORM norm)
+{
+ if (norm == NormalizationC || norm == NormalizationD ||
+ norm == NormalizationKC || norm == NormalizationKD)
+ return 1;
+ else
+ return 0;
+}
+
/******************************************************************************
* NormalizeString (KERNEL32.@)
+ *
+ * Normalizes a string according to a Unicode Normalization Form.
+ *
+ * PARAMS
+ * norm [I] Normalization Form
+ * src [I] Source string to normalize
+ * srclen [I] Length of source string (if -1, source string is null-terminated)
+ * dst [O] Buffer to write normalized source string (can be NULL)
+ * dstlen [I] Length of dst string (can be 0)
+ *
+ * RETURNS
+ * Success: If dstlen is 0, return size needed, else return size of normalized string.
+ * Failure: ret <= 0. Use GetLastError to determine error.
*/
-INT WINAPI NormalizeString(NORM_FORM NormForm, LPCWSTR lpSrcString, INT cwSrcLength,
- LPWSTR lpDstString, INT cwDstLength)
+INT WINAPI NormalizeString(NORM_FORM norm, LPCWSTR src, INT srclen,
+ LPWSTR dst, INT dstlen)
{
- FIXME("%x %p %d %p %d\n", NormForm, lpSrcString, cwSrcLength, lpDstString, cwDstLength);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
+ extern int wine_unicode_decompose_string( int compat, const WCHAR *src,
+ int srclen, WCHAR *dst, int dstlen );
+ extern int unicode_canonical_composition( WCHAR *str, UINT strlen );
+ extern void unicode_canon_order( WCHAR *str, int strlen );
+
+ WCHAR *decomp = NULL;
+ INT compat = 0;
+ INT needed_len;
+
+ if (src == NULL || !is_valid_norm( norm ))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ if (norm == NormalizationKC || norm == NormalizationKD) compat++;
+
+ if (srclen == -1) srclen = strlenW( src ) + 1;
+
+ needed_len = wine_unicode_decompose_string( compat, src, srclen, NULL, 0 );
+
+ if (needed_len < 0)
+ {
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return needed_len;
+ }
+
+ if (norm == NormalizationC || norm == NormalizationKC)
+ {
+ decomp = HeapAlloc( GetProcessHeap(), 0, needed_len * sizeof( WCHAR ) );
+ wine_unicode_decompose_string( compat, src, srclen, decomp, needed_len );
+ unicode_canon_order( decomp, needed_len );
+ needed_len = unicode_canonical_composition( decomp, needed_len );
+ }
+
+ if (dstlen < needed_len && dstlen > 0)
+ {
+ if (decomp) HeapFree(GetProcessHeap(), 0, decomp);
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+ else if (dstlen <= 0)
+ {
+ if (decomp) HeapFree(GetProcessHeap(), 0, decomp);
+ return needed_len;
+ }
+
+ if (norm == NormalizationC || norm == NormalizationKC)
+ {
+ memcpy( dst, decomp, sizeof(WCHAR) * needed_len );
+ HeapFree(GetProcessHeap(), 0, decomp);
+ return needed_len;
+ }
+ else
+ {
+ int decomp_len = wine_unicode_decompose_string( compat, src, srclen, dst, needed_len );
+ unicode_canon_order( dst, needed_len );
+ return decomp_len;
+ }
}
/******************************************************************************
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index d3eb2ecf15..50c3f07a20 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -5656,10 +5656,8 @@ static void test_NormalizeString(void)
return;
}
- todo_wine {
- dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
- ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER\n");
- }
+ dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER");
/*
* For each string, first test passing -1 as srclen to NormalizeString,
@@ -5673,26 +5671,24 @@ static void test_NormalizeString(void)
for (i = 0; i < 4; i++)
{
- todo_wine {
- dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
- if (dstlen)
- {
- dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
- ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
- dstlen, strlenW( ptest->expected[i] )+1);
- str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
- ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
- }
-
- dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
- if (dstlen)
- {
- dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
- ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
- dstlen, strlenW( ptest->expected[i] ));
- str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
- ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
- }
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
+ if (dstlen)
+ {
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
+ ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
+ dstlen, strlenW( ptest->expected[i] )+1);
+ str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
+ ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
+ }
+
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
+ if (dstlen)
+ {
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
+ ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
+ dstlen, strlenW( ptest->expected[i] ));
+ str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
+ ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
}
}
ptest++;
--
2.17.1
From 91113cf4d4b65f961d9209d9508226094acad3ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Del=20Real?=
<sdelreal@codeweavers.com>
Date: Fri, 6 Apr 2018 10:29:39 -0500
Subject: [PATCH 3/4] kernel32: Implement NormalizeString API function.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Sergio Gómez Del Real <sdelreal@codeweavers.com>
---
dlls/kernel32/locale.c | 88 +++++++++++++++++++++++++++++++++++++++++---
dlls/kernel32/tests/locale.c | 44 ++++++++++------------
2 files changed, 103 insertions(+), 29 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 4d1eac6..607008f 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -5358,15 +5358,93 @@ INT WINAPI GetUserDefaultLocaleName(LPWSTR localename, int buffersize)
return LCIDToLocaleName(userlcid, localename, buffersize, 0);
}
+static inline int is_valid_norm(NORM_FORM norm)
+{
+ if (norm == NormalizationC || norm == NormalizationD ||
+ norm == NormalizationKC || norm == NormalizationKD)
+ return 1;
+ else
+ return 0;
+}
+
/******************************************************************************
* NormalizeString (KERNEL32.@)
+ *
+ * Normalizes a string according to a Unicode Normalization Form.
+ *
+ * PARAMS
+ * norm [I] Normalization Form
+ * src [I] Source string to normalize
+ * srclen [I] Length of source string (if -1, source string is null-terminated)
+ * dst [O] Buffer to write normalized source string (can be NULL)
+ * dstlen [I] Length of dst string (can be 0)
+ *
+ * RETURNS
+ * Success: If dstlen is 0, return size needed, else return size of normalized string.
+ * Failure: ret <= 0. Use GetLastError to determine error.
*/
-INT WINAPI NormalizeString(NORM_FORM NormForm, LPCWSTR lpSrcString, INT cwSrcLength,
- LPWSTR lpDstString, INT cwDstLength)
+INT WINAPI NormalizeString(NORM_FORM norm, LPCWSTR src, INT srclen,
+ LPWSTR dst, INT dstlen)
{
- FIXME("%x %p %d %p %d\n", NormForm, lpSrcString, cwSrcLength, lpDstString, cwDstLength);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
+ extern int wine_unicode_decompose_string( int compat, const WCHAR *src,
+ int srclen, WCHAR *dst, int dstlen );
+ extern int unicode_canonical_composition( WCHAR *str, UINT strlen );
+ extern void unicode_canon_order( WCHAR *str, int strlen );
+
+ WCHAR *decomp = NULL;
+ INT compat = 0;
+ INT needed_len;
+
+ if (src == NULL || !is_valid_norm( norm ))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ if (norm == NormalizationKC || norm == NormalizationKD) compat++;
+
+ if (srclen == -1) srclen = strlenW( src ) + 1;
+
+ needed_len = wine_unicode_decompose_string( compat, src, srclen, NULL, 0 );
+
+ if (needed_len < 0)
+ {
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return needed_len;
+ }
+
+ if (norm == NormalizationC || norm == NormalizationKC)
+ {
+ decomp = HeapAlloc( GetProcessHeap(), 0, needed_len * sizeof( WCHAR ) );
+ wine_unicode_decompose_string( compat, src, srclen, decomp, needed_len );
+ unicode_canon_order( decomp, needed_len );
+ needed_len = unicode_canonical_composition( decomp, needed_len );
+ }
+
+ if (dstlen < needed_len && dstlen > 0)
+ {
+ if (decomp) HeapFree(GetProcessHeap(), 0, decomp);
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+ else if (dstlen <= 0)
+ {
+ if (decomp) HeapFree(GetProcessHeap(), 0, decomp);
+ return needed_len;
+ }
+
+ if (norm == NormalizationC || norm == NormalizationKC)
+ {
+ memcpy( dst, decomp, sizeof(WCHAR) * needed_len );
+ HeapFree(GetProcessHeap(), 0, decomp);
+ return needed_len;
+ }
+ else
+ {
+ int decomp_len = wine_unicode_decompose_string( compat, src, srclen, dst, needed_len );
+ unicode_canon_order( dst, needed_len );
+ return decomp_len;
+ }
}
/******************************************************************************
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index d3eb2ec..50c3f07 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -5656,10 +5656,8 @@ static void test_NormalizeString(void)
return;
}
- todo_wine {
- dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
- ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER\n");
- }
+ dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER");
/*
* For each string, first test passing -1 as srclen to NormalizeString,
@@ -5673,26 +5671,24 @@ static void test_NormalizeString(void)
for (i = 0; i < 4; i++)
{
- todo_wine {
- dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
- if (dstlen)
- {
- dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
- ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
- dstlen, strlenW( ptest->expected[i] )+1);
- str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
- ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
- }
-
- dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
- if (dstlen)
- {
- dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
- ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
- dstlen, strlenW( ptest->expected[i] ));
- str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
- ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
- }
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
+ if (dstlen)
+ {
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
+ ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
+ dstlen, strlenW( ptest->expected[i] )+1);
+ str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
+ ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
+ }
+
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
+ if (dstlen)
+ {
+ dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
+ ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
+ dstlen, strlenW( ptest->expected[i] ));
+ str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
+ ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
}
}
ptest++;
--
1.9.1

View File

@ -1,7 +1,7 @@
From 1dc10e13ac59238f38a720e10e71bc03f41450ba Mon Sep 17 00:00:00 2001
From ac8934ad4af63d744ac71f8c5529cd5ba5b0934c Mon Sep 17 00:00:00 2001
From: Alistair Leslie-Hughes <leslie_alistair@hotmail.com>
Date: Thu, 25 Oct 2018 09:05:26 +1100
Subject: [PATCH] libs: Generated make_unicode files
Subject: [PATCH 4/4] libs: Generated make_unicode files
---
libs/port/compose.c | 55 +

View File

@ -1,179 +0,0 @@
From 9eb1c0e197164120ed601bd64e9339c0f5ea8acd Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 15 Oct 2016 19:50:46 +0200
Subject: ntdll: Implement FileIoCompletionNotificationInformation info class.
(v2)
FIXME: The tests do not seem to work on all testbots yet.
FIXME: Could we use the existing wineserver call instead?
---
dlls/kernel32/file.c | 13 ++++++++++---
dlls/ntdll/file.c | 17 +++++++++++++++++
dlls/ntdll/tests/file.c | 3 +--
server/fd.c | 23 ++++++++++++++++++++++-
server/protocol.def | 8 ++++++++
5 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index 3e93b0dfd78..f4e63bcaae6 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -1064,13 +1064,20 @@ BOOL WINAPI SetEndOfFile( HANDLE hFile )
return FALSE;
}
+
/**************************************************************************
* SetFileCompletionNotificationModes (KERNEL32.@)
*/
-BOOL WINAPI SetFileCompletionNotificationModes( HANDLE handle, UCHAR flags )
+BOOL WINAPI SetFileCompletionNotificationModes( HANDLE file, UCHAR flags )
{
- FIXME("%p %x - stub\n", handle, flags);
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+
+ info.Flags = flags;
+ status = NtSetInformationFile( file, &io, &info, sizeof(info), FileIoCompletionNotificationInformation );
+ if (status == STATUS_SUCCESS) return TRUE;
+ SetLastError( RtlNtStatusToDosError(status) );
return FALSE;
}
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index a82f081ee23..3c5d4e96876 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -2857,6 +2857,23 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
io->u.Status = STATUS_INVALID_PARAMETER_3;
break;
+ case FileIoCompletionNotificationInformation:
+ if (len >= sizeof(FILE_IO_COMPLETION_NOTIFICATION_INFORMATION))
+ {
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *info = ptr;
+
+ SERVER_START_REQ( set_fd_compl_info )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ req->flags = (info->Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) ?
+ COMPLETION_SKIP_ON_SUCCESS : 0;
+ io->u.Status = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+ } else
+ io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+
case FileAllInformation:
io->u.Status = STATUS_INVALID_INFO_CLASS;
break;
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index c0f4efc6c3c..08ac313c1a3 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -3082,12 +3082,11 @@ static void test_file_completion_information(void)
if (!(h = create_temp_file(0))) return;
status = pNtSetInformationFile(h, &io, &info, sizeof(info) - 1, FileIoCompletionNotificationInformation);
- todo_wine
ok(status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_INFO_CLASS /* XP */,
"expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED)
{
- skip("FileIoCompletionNotificationInformation class not supported\n");
+ win_skip("FileIoCompletionNotificationInformation class not supported\n");
CloseHandle(h);
return;
}
diff --git a/server/fd.c b/server/fd.c
index 9322e2c1c15..4cb46058b64 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -194,6 +194,7 @@ struct fd
struct async_queue wait_q; /* other async waiters of this fd */
struct completion *completion; /* completion object attached to this fd */
apc_param_t comp_key; /* completion key to set in completion events */
+ unsigned int comp_flags; /* completion flags */
};
static void fd_dump( struct object *obj, int verbose );
@@ -1604,6 +1605,7 @@ static struct fd *alloc_fd_object(void)
fd->fs_locks = 1;
fd->poll_index = -1;
fd->completion = NULL;
+ fd->comp_flags = 0;
init_async_queue( &fd->read_q );
init_async_queue( &fd->write_q );
init_async_queue( &fd->wait_q );
@@ -1639,6 +1641,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use
fd->fs_locks = 0;
fd->poll_index = -1;
fd->completion = NULL;
+ fd->comp_flags = 0;
fd->no_fd_status = STATUS_BAD_DEVICE_TYPE;
init_async_queue( &fd->read_q );
init_async_queue( &fd->write_q );
@@ -2360,6 +2363,7 @@ void fd_copy_completion( struct fd *src, struct fd *dst )
{
assert( !dst->completion );
dst->completion = fd_get_completion( src, &dst->comp_key );
+ dst->comp_flags = src->comp_flags;
}
/* flush a file buffers */
@@ -2543,12 +2547,29 @@ DECL_HANDLER(add_fd_completion)
struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
if (fd)
{
- if (fd->completion)
+ if (fd->completion && (!(fd->comp_flags & COMPLETION_SKIP_ON_SUCCESS) || req->status))
add_completion( fd->completion, fd->comp_key, req->cvalue, req->status, req->information );
release_object( fd );
}
}
+/* set fd completion information */
+DECL_HANDLER(set_fd_compl_info)
+{
+ struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
+ if (fd)
+ {
+ if (!(fd->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
+ {
+ /* removing COMPLETION_SKIP_ON_SUCCESS is not allowed */
+ fd->comp_flags |= req->flags;
+ }
+ else
+ set_error( STATUS_INVALID_PARAMETER );
+ release_object( fd );
+ }
+}
+
/* set fd disposition information */
DECL_HANDLER(set_fd_disp_info)
{
diff --git a/server/protocol.def b/server/protocol.def
index 1f88c6a5c86..3646b9a4349 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3651,6 +3651,14 @@ struct handle_info
@END
+/* set fd completion information */
+@REQ(set_fd_compl_info)
+ obj_handle_t handle; /* handle to a file or directory */
+ int flags; /* completion flags (see below) */
+@END
+#define COMPLETION_SKIP_ON_SUCCESS 0x01
+
+
/* set fd disposition information */
@REQ(set_fd_disp_info)
obj_handle_t handle; /* handle to a file or directory */
--
2.13.1

View File

@ -1,132 +0,0 @@
From 723fa05be459725140a88f614b315b19f90cc235 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 5 Feb 2017 11:27:49 +0100
Subject: ntdll: Allow to query file IO completion notification mode.
---
dlls/ntdll/file.c | 18 +++++++++++++++++-
dlls/ntdll/tests/file.c | 15 +++++++++++++++
server/fd.c | 11 +++++++++++
server/protocol.def | 8 ++++++++
4 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 00131f11cf7..fc72833e1a4 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -2357,7 +2357,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
0, /* FileIdFullDirectoryInformation */
0, /* FileValidDataLengthInformation */
0, /* FileShortNameInformation */
- 0, /* FileIoCompletionNotificationInformation, */
+ sizeof(FILE_IO_COMPLETION_NOTIFICATION_INFORMATION), /* FileIoCompletionNotificationInformation, */
0, /* FileIoStatusBlockRangeInformation */
0, /* FileIoPriorityHintInformation */
0, /* FileSfioReserveInformation */
@@ -2617,6 +2617,22 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
}
}
break;
+ case FileIoCompletionNotificationInformation:
+ {
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION *info = ptr;
+
+ SERVER_START_REQ( get_fd_compl_info )
+ {
+ req->handle = wine_server_obj_handle( hFile );
+ if (!(io->u.Status = wine_server_call( req )))
+ {
+ info->Flags = (reply->flags & COMPLETION_SKIP_ON_SUCCESS) ?
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS : 0;
+ }
+ }
+ SERVER_END_REQ;
+ }
+ break;
case FileIdInformation:
if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 0a114e7cc73..214c51a726a 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -3303,6 +3303,11 @@ static void test_file_completion_information(void)
CloseHandle(h);
if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return;
+ info.Flags = ~0U;
+ status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+ ok(!(info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS), "got %08x\n", info.Flags);
+
memset(&ov, 0, sizeof(ov));
ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
port = CreateIoCompletionPort(h, NULL, 0xdeadbeef, 0);
@@ -3337,6 +3342,11 @@ static void test_file_completion_information(void)
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+ info.Flags = 0;
+ status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+ ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
+
for (i = 0; i < 10; i++)
{
SetLastError(0xdeadbeef);
@@ -3362,6 +3372,11 @@ static void test_file_completion_information(void)
status = pNtSetInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+ info.Flags = 0;
+ status = pNtQueryInformationFile(h, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+ ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
+
for (i = 0; i < 10; i++)
{
SetLastError(0xdeadbeef);
diff --git a/server/fd.c b/server/fd.c
index 8ff5f9801ad..3d1a1d8befe 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2566,6 +2566,17 @@ DECL_HANDLER(set_fd_compl_info)
}
}
+/* get fd completion information */
+DECL_HANDLER(get_fd_compl_info)
+{
+ struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
+ if (fd)
+ {
+ reply->flags = fd->comp_flags;
+ release_object( fd );
+ }
+}
+
/* set fd disposition information */
DECL_HANDLER(set_fd_disp_info)
{
diff --git a/server/protocol.def b/server/protocol.def
index 73fef6fade6..935665b2005 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3665,6 +3665,14 @@ struct handle_info
#define COMPLETION_SKIP_ON_SUCCESS 0x01
+/* get fd completion information */
+@REQ(get_fd_compl_info)
+ obj_handle_t handle; /* handle to a file or directory */
+@REPLY
+ int flags; /* completion flags (see below) */
+@END
+
+
/* set fd disposition information */
@REQ(set_fd_disp_info)
obj_handle_t handle; /* handle to a file or directory */
--
2.11.0

View File

@ -1,79 +0,0 @@
From 4ca5b86202106da7569f8156e0769aa6318c275d Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 5 Feb 2017 11:54:21 +0100
Subject: ws2_32/tests: Add test for completion notification flags.
---
dlls/ws2_32/tests/sock.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 179ace4c6ae..5504a0862a9 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -85,6 +85,10 @@ static int (WINAPI *pWSAEnumNameSpaceProvidersA)(LPDWORD,LPWSANAMESPACE_INFOA)
static int (WINAPI *pWSAEnumNameSpaceProvidersW)(LPDWORD,LPWSANAMESPACE_INFOW);
static int (WINAPI *pWSAPoll)(WSAPOLLFD *,ULONG,INT);
+/* Function pointers from ntdll */
+static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
+static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
+
/* Function pointers from iphlpapi */
static DWORD (WINAPI *pGetAdaptersInfo)(PIP_ADAPTER_INFO,PULONG);
static DWORD (WINAPI *pGetIpForwardTable)(PMIB_IPFORWARDTABLE,PULONG,BOOL);
@@ -1310,7 +1314,11 @@ static void Init (void)
ntdll = LoadLibraryA("ntdll.dll");
if (ntdll)
+ {
pNtClose = (void *)GetProcAddress(ntdll, "NtClose");
+ pNtSetInformationFile = (void *)GetProcAddress(ntdll, "NtSetInformationFile");
+ pNtQueryInformationFile = (void *)GetProcAddress(ntdll, "NtQueryInformationFile");
+ }
ok ( WSAStartup ( ver, &data ) == 0, "WSAStartup failed\n" );
tls = TlsAlloc();
@@ -9623,10 +9631,13 @@ end:
static void test_completion_port(void)
{
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION io_info;
HANDLE previous_port, io_port;
WSAOVERLAPPED ov, *olp;
SOCKET src, dest, dup, connector = INVALID_SOCKET;
WSAPROTOCOL_INFOA info;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
char buf[1024];
WSABUF bufs;
DWORD num_bytes, flags;
@@ -10238,6 +10249,11 @@ static void test_completion_port(void)
io_port = CreateIoCompletionPort((HANDLE)dest, previous_port, 236, 0);
ok(io_port != NULL, "failed to create completion port %u\n", GetLastError());
+ io_info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile((HANDLE)dest, &io, &io_info, sizeof(io_info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS) /* XP */,
+ "expected STATUS_SUCCESS, got %08x\n", status);
+
bret = pAcceptEx(src, dest, buf, sizeof(buf) - 2*(sizeof(struct sockaddr_in) + 16),
sizeof(struct sockaddr_in) + 16, sizeof(struct sockaddr_in) + 16,
&num_bytes, &ov);
@@ -10263,6 +10279,13 @@ static void test_completion_port(void)
ok(olp == &ov, "Overlapped structure is at %p\n", olp);
ok(olp && (olp->Internal == (ULONG)STATUS_SUCCESS), "Internal status is %lx\n", olp ? olp->Internal : 0);
+ io_info.Flags = 0;
+ status = pNtQueryInformationFile((HANDLE)dest, &io, &io_info, sizeof(io_info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS) /* XP */,
+ "expected STATUS_SUCCESS, got %08x\n", status);
+ if (status == STATUS_SUCCESS)
+ ok((io_info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", io_info.Flags);
+
SetLastError(0xdeadbeef);
key = 0xdeadbeef;
num_bytes = 0xdeadbeef;
--
2.14.2

View File

@ -1,105 +0,0 @@
From 6a640e583277b35e4dd1ba2edffb45c379e4fd7e Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 9 Apr 2017 01:58:49 +0200
Subject: ntdll/tests: Add more tests for
FileIoCompletionNotificationInformation.
---
dlls/ntdll/tests/pipe.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index e242cb4c0f..fa0ca2da00 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -331,6 +331,77 @@ static void test_overlapped(void)
CloseHandle(hEvent);
}
+static void test_completion(void)
+{
+ static const char buf[] = "testdata";
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
+ HANDLE port, pipe, client;
+ IO_STATUS_BLOCK iosb;
+ OVERLAPPED ov, *pov;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ DWORD num_bytes;
+ ULONG_PTR key;
+ DWORD dwret;
+ BOOL ret;
+
+ memset(&ov, 0, sizeof(ov));
+ ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ ok(ov.hEvent != INVALID_HANDLE_VALUE, "CreateEvent failed, error %u\n", GetLastError());
+
+ status = create_pipe(&pipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */, 0);
+ ok(!status, "NtCreateNamedPipeFile returned %x\n", status);
+ status = listen_pipe(pipe, ov.hEvent, &iosb, FALSE);
+ ok(status == STATUS_PENDING, "NtFsControlFile returned %x\n", status);
+
+ client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %u\n", GetLastError());
+ dwret = WaitForSingleObject(ov.hEvent, 0);
+ ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
+
+ port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0);
+ ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
+
+ ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
+
+ key = 0;
+ pov = NULL;
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n", GetLastError());
+ ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key);
+ ok(pov == &ov, "expected %p, got %p\n", &ov, pov);
+
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+
+ info.Flags = 0;
+ status = pNtQueryInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
+ todo_wine
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+ todo_wine
+ ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got %08x\n", info.Flags);
+
+ ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n", num_bytes);
+
+ pov = (void *)0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
+ todo_wine
+ ok(!ret, "GetQueuedCompletionStatus succeeded\n");
+ todo_wine
+ ok(pov == NULL, "expected NULL, got %p\n", pov);
+
+ CloseHandle(ov.hEvent);
+ CloseHandle(client);
+ CloseHandle(pipe);
+ CloseHandle(port);
+}
+
static BOOL userapc_called;
static void CALLBACK userapc(ULONG_PTR dwParam)
{
@@ -1086,6 +1157,9 @@ START_TEST(pipe)
trace("starting overlapped tests\n");
test_overlapped();
+ trace("starting completion tests\n");
+ test_completion();
+
trace("starting FILE_PIPE_INFORMATION tests\n");
test_filepipeinfo();
--
2.11.0

View File

@ -1,132 +0,0 @@
From 66f2053d1f72e821bd1100d8bf2266e73e2e2163 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 9 Apr 2017 03:13:25 +0200
Subject: [PATCH] server: Skip async completion when possible.
---
dlls/ntdll/tests/pipe.c | 2 --
server/async.c | 10 ++++++++--
server/fd.c | 8 ++++----
server/file.h | 2 +-
4 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c
index bea849f..06be9eb 100644
--- a/dlls/ntdll/tests/pipe.c
+++ b/dlls/ntdll/tests/pipe.c
@@ -394,9 +394,7 @@ static void test_completion(void)
pov = (void *)0xdeadbeef;
ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
- todo_wine
ok(!ret, "GetQueuedCompletionStatus succeeded\n");
- todo_wine
ok(pov == NULL, "expected NULL, got %p\n", pov);
CloseHandle(ov.hEvent);
diff --git a/server/async.c b/server/async.c
index 4f1bcf1..11bbb25 100644
--- a/server/async.c
+++ b/server/async.c
@@ -53,6 +53,7 @@ struct async
int direct_result; /* a flag if we're passing result directly from request instead of APC */
struct completion *completion; /* completion associated with fd */
apc_param_t comp_key; /* completion key associated with fd */
+ unsigned int comp_flags; /* completion flags */
};
static void async_dump( struct object *obj, int verbose );
@@ -237,6 +238,7 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da
async->wait_handle = 0;
async->direct_result = 0;
async->completion = fd_get_completion( fd, &async->comp_key );
+ async->comp_flags = 0;
if (iosb) async->iosb = (struct iosb *)grab_object( iosb );
else async->iosb = NULL;
@@ -256,7 +258,7 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da
/* create an async associated with iosb for async-based requests
* returned async must be passed to async_handoff */
-struct async *create_request_async( struct fd *fd, const async_data_t *data )
+struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data )
{
struct async *async;
struct iosb *iosb;
@@ -274,6 +276,7 @@ struct async *create_request_async( struct fd *fd, const async_data_t *data )
return NULL;
}
async->direct_result = 1;
+ async->comp_flags = comp_flags;
}
return async;
}
@@ -375,8 +378,11 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
data.user.args[2] = 0;
thread_queue_apc( NULL, async->thread, NULL, &data );
}
- else if (async->data.apc_context)
+ else if (async->data.apc_context && (!async->direct_result ||
+ !(async->comp_flags & COMPLETION_SKIP_ON_SUCCESS)))
+ {
add_async_completion( async, async->data.apc_context, status, total );
+ }
if (async->event) set_event( async->event );
else if (async->fd) set_fd_signaled( async->fd, 1 );
diff --git a/server/fd.c b/server/fd.c
index a6a96d6..64dbd1b 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2434,7 +2434,7 @@ DECL_HANDLER(flush)
if (!fd) return;
- if ((async = create_request_async( fd, &req->async )))
+ if ((async = create_request_async( fd, fd->comp_flags, &req->async )))
{
reply->event = async_handoff( async, fd->fd_ops->flush( fd, async ), NULL );
release_object( async );
@@ -2533,7 +2533,7 @@ DECL_HANDLER(read)
if (!fd) return;
- if ((async = create_request_async( fd, &req->async )))
+ if ((async = create_request_async( fd, fd->comp_flags, &req->async )))
{
reply->wait = async_handoff( async, fd->fd_ops->read( fd, async, req->pos ), NULL );
reply->options = fd->options;
@@ -2550,7 +2550,7 @@ DECL_HANDLER(write)
if (!fd) return;
- if ((async = create_request_async( fd, &req->async )))
+ if ((async = create_request_async( fd, fd->comp_flags, &req->async )))
{
reply->wait = async_handoff( async, fd->fd_ops->write( fd, async, req->pos ), &reply->size );
reply->options = fd->options;
@@ -2568,7 +2568,7 @@ DECL_HANDLER(ioctl)
if (!fd) return;
- if ((async = create_request_async( fd, &req->async )))
+ if ((async = create_request_async( fd, fd->comp_flags, &req->async )))
{
reply->wait = async_handoff( async, fd->fd_ops->ioctl( fd, req->code, async ), NULL );
reply->options = fd->options;
diff --git a/server/file.h b/server/file.h
index 1d25961..ed42fc4 100644
--- a/server/file.h
+++ b/server/file.h
@@ -185,7 +185,7 @@ extern struct object *create_serial( struct fd *fd );
/* async I/O functions */
extern void free_async_queue( struct async_queue *queue );
extern struct async *create_async( struct fd *fd, struct thread *thread, const async_data_t *data, struct iosb *iosb );
-extern struct async *create_request_async( struct fd *fd, const async_data_t *data );
+extern struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data );
extern obj_handle_t async_handoff( struct async *async, int success, data_size_t *result );
extern void queue_async( struct async_queue *queue, struct async *async );
extern void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status );
--
1.9.1

View File

@ -1,134 +0,0 @@
From 38b105229bbdeca9a96da1245b7b467a9ef55e89 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 14 Jun 2017 14:47:33 +0200
Subject: ws2_32: Don't skip completion in AcceptEx.
Spotted by Jacek Caban.
FIXME: It would be better to get rid of the STATUS_MORE_PROCESSING_REQUIRED handling.
---
dlls/ws2_32/socket.c | 15 ++++++++-------
dlls/ws2_32/tests/sock.c | 5 +++++
server/fd.c | 2 +-
server/protocol.def | 1 +
4 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 06f1c26d7dd..3f898b494ae 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -640,7 +640,7 @@ static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, in
int WSAIOCTL_GetInterfaceCount(void);
int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
-static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG Information );
+static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG Information, BOOL force );
#define MAP_OPTION(opt) { WS_##opt, opt }
@@ -2457,7 +2457,7 @@ static NTSTATUS WS2_async_accept_recv( void *user, IO_STATUS_BLOCK *iosb, NTSTAT
return status;
if (wsa->cvalue)
- WS_AddCompletion( HANDLE2SOCKET(wsa->listen_socket), wsa->cvalue, iosb->u.Status, iosb->Information );
+ WS_AddCompletion( HANDLE2SOCKET(wsa->listen_socket), wsa->cvalue, iosb->u.Status, iosb->Information, TRUE );
release_async_io( &wsa->io );
return status;
@@ -3589,7 +3589,7 @@ static BOOL WINAPI WS2_ConnectEx(SOCKET s, const struct WS_sockaddr* name, int n
{
ov->Internal = _get_sock_error(s, FD_CONNECT_BIT);
ov->InternalHigh = 0;
- if (cvalue) WS_AddCompletion( s, cvalue, ov->Internal, ov->InternalHigh );
+ if (cvalue) WS_AddCompletion( s, cvalue, ov->Internal, ov->InternalHigh, FALSE );
if (ov->hEvent) NtSetEvent( ov->hEvent, NULL );
status = STATUS_PENDING;
}
@@ -5068,7 +5068,7 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
overlapped->Internal = status;
overlapped->InternalHigh = total;
if (overlapped->hEvent) NtSetEvent( overlapped->hEvent, NULL );
- if (cvalue) WS_AddCompletion( HANDLE2SOCKET(s), cvalue, status, total );
+ if (cvalue) WS_AddCompletion( HANDLE2SOCKET(s), cvalue, status, total, FALSE );
}
if (!status)
@@ -5463,7 +5463,7 @@ int WINAPI WSAPoll(WSAPOLLFD *wfds, ULONG count, int timeout)
/* helper to send completion messages for client-only i/o operation case */
static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus,
- ULONG Information )
+ ULONG Information, BOOL force )
{
SERVER_START_REQ( add_fd_completion )
{
@@ -5471,6 +5471,7 @@ static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS C
req->cvalue = CompletionValue;
req->status = CompletionStatus;
req->information = Information;
+ req->force = force;
wine_server_call( req );
}
SERVER_END_REQ;
@@ -5615,7 +5616,7 @@ static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
if (lpNumberOfBytesSent) *lpNumberOfBytesSent = n;
if (!wsa->completion_func)
{
- if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n );
+ if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n, FALSE );
if (lpOverlapped->hEvent) SetEvent( lpOverlapped->hEvent );
HeapFree( GetProcessHeap(), 0, wsa );
}
@@ -7937,7 +7938,7 @@ static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
iosb->Information = n;
if (!wsa->completion_func)
{
- if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n );
+ if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n, FALSE );
if (lpOverlapped->hEvent) SetEvent( lpOverlapped->hEvent );
HeapFree( GetProcessHeap(), 0, wsa );
}
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 6a77586ffd0..376532eb27d 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -10003,6 +10003,11 @@ static void test_completion_port(void)
ok(io_port != NULL, "failed to create completion port %u\n", GetLastError());
io_info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile((HANDLE)src, &io, &io_info, sizeof(io_info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS) /* XP */,
+ "expected STATUS_SUCCESS, got %08x\n", status);
+
+ io_info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
status = pNtSetInformationFile((HANDLE)dest, &io, &io_info, sizeof(io_info), FileIoCompletionNotificationInformation);
ok(status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS) /* XP */,
"expected STATUS_SUCCESS, got %08x\n", status);
diff --git a/server/fd.c b/server/fd.c
index d8f066c7219..e54a81e6a96 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2547,7 +2547,7 @@ DECL_HANDLER(add_fd_completion)
struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
if (fd)
{
- if (fd->completion && (!(fd->comp_flags & COMPLETION_SKIP_ON_SUCCESS) || req->status))
+ if (fd->completion && (!(fd->comp_flags & COMPLETION_SKIP_ON_SUCCESS) || req->status || req->force))
add_completion( fd->completion, fd->comp_key, req->cvalue, req->status, req->information );
release_object( fd );
}
diff --git a/server/protocol.def b/server/protocol.def
index c91fd0897a2..3e9f255d641 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3650,6 +3650,7 @@ struct handle_info
apc_param_t cvalue; /* completion value */
apc_param_t information; /* IO_STATUS_BLOCK Information */
unsigned int status; /* completion status */
+ int force; /* don't check if skip-on-success is set */
@END
--
2.13.1

View File

@ -1 +0,0 @@
Fixes: [38960] Add support for kernel32.SetFileCompletionNotificationModes

View File

@ -1,3 +1,2 @@
Fixes: Improve stub for NtQueryEaFile
# Depends: ntdll-Syscall_Wrappers
Depends: kernel32-SetFileCompletionNotificationModes

View File

@ -52,7 +52,7 @@ usage()
# Get the upstream commit sha
upstream_commit()
{
echo "363326678cd2f473b6fcf3d141846fa79007837d"
echo "13cdcdae1a9e58f2eec9cd99b7b7f7899b4d111b"
}
# Show version information
@ -169,7 +169,6 @@ patch_enable_all ()
enable_kernel32_Processor_Group="$1"
enable_kernel32_Profile="$1"
enable_kernel32_SCSI_Sysfs="$1"
enable_kernel32_SetFileCompletionNotificationModes="$1"
enable_kernelbase_PathCchCombineEx="$1"
enable_krnl386_exe16_GDT_LDT_Emulation="$1"
enable_krnl386_exe16_Invalid_Console_Handles="$1"
@ -673,9 +672,6 @@ patch_enable ()
kernel32-SCSI_Sysfs)
enable_kernel32_SCSI_Sysfs="$2"
;;
kernel32-SetFileCompletionNotificationModes)
enable_kernel32_SetFileCompletionNotificationModes="$2"
;;
kernelbase-PathCchCombineEx)
enable_kernelbase_PathCchCombineEx="$2"
;;
@ -2086,13 +2082,6 @@ if test "$enable_ntdll_Junction_Points" -eq 1; then
enable_ntdll_NtQueryEaFile=1
fi
if test "$enable_ntdll_NtQueryEaFile" -eq 1; then
if test "$enable_kernel32_SetFileCompletionNotificationModes" -gt 1; then
abort "Patchset kernel32-SetFileCompletionNotificationModes disabled, but ntdll-NtQueryEaFile depends on that."
fi
enable_kernel32_SetFileCompletionNotificationModes=1
fi
if test "$enable_ntdll_HashLinks" -eq 1; then
if test "$enable_ntdll_LDR_MODULE" -gt 1; then
abort "Patchset ntdll-LDR_MODULE disabled, but ntdll-HashLinks depends on that."
@ -4078,32 +4067,6 @@ if test "$enable_kernel32_SCSI_Sysfs" -eq 1; then
) >> "$patchlist"
fi
# Patchset kernel32-SetFileCompletionNotificationModes
# |
# | This patchset fixes the following Wine bugs:
# | * [#38960] Add support for kernel32.SetFileCompletionNotificationModes
# |
# | Modified files:
# | * dlls/kernel32/file.c, dlls/ntdll/file.c, dlls/ntdll/tests/file.c, dlls/ntdll/tests/pipe.c, dlls/ws2_32/socket.c,
# | dlls/ws2_32/tests/sock.c, server/async.c, server/fd.c, server/file.h, server/protocol.def
# |
if test "$enable_kernel32_SetFileCompletionNotificationModes" -eq 1; then
patch_apply kernel32-SetFileCompletionNotificationModes/0001-ntdll-Implement-FileIoCompletionNotificationInformat.patch
patch_apply kernel32-SetFileCompletionNotificationModes/0002-ntdll-Allow-to-query-file-IO-completion-notification.patch
patch_apply kernel32-SetFileCompletionNotificationModes/0003-ws2_32-tests-Add-test-for-completion-notification-fl.patch
patch_apply kernel32-SetFileCompletionNotificationModes/0004-ntdll-tests-Add-more-tests-for-FileIoCompletionNotif.patch
patch_apply kernel32-SetFileCompletionNotificationModes/0006-server-Skip-async-completion-when-possible.patch
patch_apply kernel32-SetFileCompletionNotificationModes/0007-ws2_32-Don-t-skip-completion-in-AcceptEx.patch
(
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Implement FileIoCompletionNotificationInformation info class.", 2 },';
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Allow to query file IO completion notification mode.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "ws2_32/tests: Add test for completion notification flags.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "ntdll/tests: Add more tests for FileIoCompletionNotificationInformation.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: Skip async completion when possible.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "ws2_32: Don'\''t skip completion in AcceptEx.", 1 },';
) >> "$patchlist"
fi
# Patchset kernelbase-PathCchCombineEx
# |
# | This patchset fixes the following Wine bugs:
@ -4766,9 +4729,6 @@ fi
# Patchset ntdll-NtQueryEaFile
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * kernel32-SetFileCompletionNotificationModes
# |
# | Modified files:
# | * dlls/ntdll/file.c, dlls/ntdll/tests/file.c
# |
@ -4782,7 +4742,7 @@ fi
# Patchset ntdll-Junction_Points
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * kernel32-SetFileCompletionNotificationModes, ntdll-NtQueryEaFile
# | * ntdll-NtQueryEaFile
# |
# | This patchset fixes the following Wine bugs:
# | * [#12401] Support for Junction Points