mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-01-28 22:04:43 -08:00
Rebase against 13cdcdae1a9e58f2eec9cd99b7b7f7899b4d111b
This commit is contained in:
parent
2802df41dc
commit
eb630f686f
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 +
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1 +0,0 @@
|
||||
Fixes: [38960] Add support for kernel32.SetFileCompletionNotificationModes
|
@ -1,3 +1,2 @@
|
||||
Fixes: Improve stub for NtQueryEaFile
|
||||
# Depends: ntdll-Syscall_Wrappers
|
||||
Depends: kernel32-SetFileCompletionNotificationModes
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user