Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
c953c36d
Commit
c953c36d
authored
Nov 22, 2019
by
Piotr Caban
Committed by
Alexandre Julliard
Nov 22, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ucrtbase: Fix hexadecimal floats parsing in strtod.
Signed-off-by:
Piotr Caban
<
piotr@codeweavers.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
e2423823
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
239 additions
and
39 deletions
+239
-39
string.c
dlls/msvcrt/string.c
+226
-37
string.c
dlls/ucrtbase/tests/string.c
+13
-2
No files found.
dlls/msvcrt/string.c
View file @
c953c36d
...
...
@@ -325,6 +325,221 @@ void CDECL MSVCRT__swab(char* src, char* dst, int len)
}
}
#if _MSVCR_VER >= 140
enum
round
{
ROUND_ZERO
,
/* only used when dropped part contains only zeros */
ROUND_DOWN
,
ROUND_EVEN
,
ROUND_UP
};
static
double
make_double
(
int
sign
,
int
exp
,
ULONGLONG
m
,
enum
round
round
,
int
*
err
)
{
#define EXP_BITS 11
#define MANT_BITS 53
ULONGLONG
bits
=
0
;
TRACE
(
"%c %s *2^%d (round %d)
\n
"
,
sign
==
-
1
?
'-'
:
'+'
,
wine_dbgstr_longlong
(
m
),
exp
,
round
);
if
(
!
m
)
return
sign
*
0
.
0
;
/* make sure that we don't overflow modifying exponent */
if
(
exp
>
1
<<
EXP_BITS
)
{
if
(
err
)
*
err
=
MSVCRT_ERANGE
;
return
sign
*
INFINITY
;
}
if
(
exp
<
-
(
1
<<
EXP_BITS
))
{
if
(
err
)
*
err
=
MSVCRT_ERANGE
;
return
sign
*
0
.
0
;
}
exp
+=
MANT_BITS
-
1
;
/* normalize mantissa */
while
(
m
<
(
ULONGLONG
)
1
<<
(
MANT_BITS
-
1
))
{
m
<<=
1
;
exp
--
;
}
while
(
m
>=
(
ULONGLONG
)
1
<<
MANT_BITS
)
{
if
(
m
&
1
||
round
!=
ROUND_ZERO
)
{
if
(
!
(
m
&
1
))
round
=
ROUND_DOWN
;
else
if
(
round
==
ROUND_ZERO
)
round
=
ROUND_EVEN
;
else
round
=
ROUND_UP
;
}
m
>>=
1
;
exp
++
;
}
/* handle subnormal that falls into regular range due to rounding */
exp
+=
(
1
<<
(
EXP_BITS
-
1
))
-
1
;
if
(
!
exp
&&
(
round
==
ROUND_UP
||
(
round
==
ROUND_EVEN
&&
m
&
1
)))
{
if
(
m
+
1
>=
(
ULONGLONG
)
1
<<
MANT_BITS
)
{
m
++
;
m
>>=
1
;
exp
++
;
round
=
ROUND_DOWN
;
}
}
/* handle subnormals */
if
(
exp
<=
0
)
m
>>=
1
;
while
(
m
&&
exp
<
0
)
{
m
>>=
1
;
exp
++
;
}
/* round mantissa */
if
(
round
==
ROUND_UP
||
(
round
==
ROUND_EVEN
&&
m
&
1
))
{
m
++
;
if
(
m
>=
(
ULONGLONG
)
1
<<
MANT_BITS
)
{
exp
++
;
m
>>=
1
;
}
}
if
(
exp
>=
1
<<
EXP_BITS
)
{
if
(
err
)
*
err
=
MSVCRT_ERANGE
;
return
sign
*
INFINITY
;
}
if
(
!
m
||
exp
<
0
)
{
if
(
err
)
*
err
=
MSVCRT_ERANGE
;
return
sign
*
0
.
0
;
}
if
(
sign
==
-
1
)
bits
|=
(
ULONGLONG
)
1
<<
(
MANT_BITS
+
EXP_BITS
-
1
);
bits
|=
(
ULONGLONG
)
exp
<<
(
MANT_BITS
-
1
);
bits
|=
m
&
(((
ULONGLONG
)
1
<<
(
MANT_BITS
-
1
))
-
1
);
TRACE
(
"returning %s
\n
"
,
wine_dbgstr_longlong
(
bits
));
return
*
((
double
*
)
&
bits
);
}
static
inline
int
hex2int
(
char
c
)
{
if
(
c
>=
'0'
&&
c
<=
'9'
)
return
c
-
'0'
;
else
if
(
c
>=
'a'
&&
c
<=
'f'
)
return
c
-
'a'
+
10
;
else
if
(
c
>=
'A'
&&
c
<=
'F'
)
return
c
-
'A'
+
10
;
return
-
1
;
}
static
double
strtod16
(
int
sign
,
const
char
*
p
,
char
**
end
,
MSVCRT_pthreadlocinfo
locinfo
,
int
*
err
)
{
enum
round
round
=
ROUND_ZERO
;
BOOL
found_digit
=
FALSE
;
ULONGLONG
m
=
0
;
int
val
,
exp
=
0
;
while
(
m
<
MSVCRT_UI64_MAX
/
16
)
{
val
=
hex2int
(
*
p
);
if
(
val
==
-
1
)
break
;
found_digit
=
TRUE
;
p
++
;
m
=
m
*
16
+
val
;
}
while
(
1
)
{
val
=
hex2int
(
*
p
);
if
(
val
==
-
1
)
break
;
p
++
;
exp
+=
4
;
if
(
val
||
round
!=
ROUND_ZERO
)
{
if
(
val
<
8
)
round
=
ROUND_DOWN
;
else
if
(
val
==
8
&&
round
==
ROUND_ZERO
)
round
=
ROUND_EVEN
;
else
round
=
ROUND_UP
;
}
}
if
(
*
p
==
*
locinfo
->
lconv
->
decimal_point
)
p
++
;
else
if
(
!
found_digit
)
{
if
(
end
)
*
end
=
(
char
*
)
p
-
1
;
return
0
.
0
;
}
while
(
m
<=
MSVCRT_UI64_MAX
/
16
)
{
val
=
hex2int
(
*
p
);
if
(
val
==
-
1
)
break
;
found_digit
=
TRUE
;
p
++
;
m
=
m
*
16
+
val
;
exp
-=
4
;
}
while
(
1
)
{
val
=
hex2int
(
*
p
);
if
(
val
==
-
1
)
break
;
p
++
;
if
(
val
||
round
!=
ROUND_ZERO
)
{
if
(
val
<
8
)
round
=
ROUND_DOWN
;
else
if
(
val
==
8
&&
round
==
ROUND_ZERO
)
round
=
ROUND_EVEN
;
else
round
=
ROUND_UP
;
}
}
if
(
!
found_digit
)
{
if
(
end
)
*
end
=
(
char
*
)
p
-
2
;
return
0
.
0
;
}
if
(
*
p
==
'p'
||
*
p
==
'P'
)
{
int
e
=
0
,
s
=
1
;
p
++
;
if
(
*
p
==
'-'
)
{
s
=
-
1
;
p
++
;
}
else
if
(
*
p
==
'+'
)
p
++
;
if
(
*
p
>=
'0'
&&
*
p
<=
'9'
)
{
while
(
*
p
>=
'0'
&&
*
p
<=
'9'
)
{
if
(
e
>
INT_MAX
/
10
||
(
e
=
e
*
10
+*
p
-
'0'
)
<
0
)
e
=
INT_MAX
;
p
++
;
}
e
*=
s
;
if
(
exp
<
0
&&
e
<
0
&&
exp
+
e
>=
0
)
exp
=
INT_MIN
;
else
if
(
exp
>
0
&&
e
>
0
&&
exp
+
e
<
0
)
exp
=
INT_MAX
;
else
exp
+=
e
;
}
else
{
if
(
*
p
==
'-'
||
*
p
==
'+'
)
p
--
;
p
--
;
}
}
if
(
end
)
*
end
=
(
char
*
)
p
;
return
make_double
(
sign
,
exp
,
m
,
round
,
err
);
}
#endif
static
double
strtod_helper
(
const
char
*
str
,
char
**
end
,
MSVCRT__locale_t
locale
,
int
*
err
)
{
MSVCRT_pthreadlocinfo
locinfo
;
...
...
@@ -335,7 +550,6 @@ static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale
double
ret
;
long
double
lret
=
1
,
expcnt
=
10
;
BOOL
found_digit
=
FALSE
,
negexp
;
int
base
=
10
;
if
(
err
)
*
err
=
0
;
...
...
@@ -379,33 +593,22 @@ static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale
return
NAN
;
}
if
(
p
[
0
]
==
'0'
&&
MSVCRT__tolower_l
(
p
[
1
],
locale
)
==
'x'
)
{
base
=
16
;
expcnt
=
2
;
if
(
p
[
0
]
==
'0'
&&
(
p
[
1
]
==
'x'
||
p
[
1
]
==
'X'
))
{
p
+=
2
;
return
strtod16
(
sign
,
p
,
end
,
locinfo
,
err
);
}
#endif
while
((
*
p
>=
'0'
&&
*
p
<=
'9'
)
||
(
base
==
16
&&
((
*
p
>=
'a'
&&
*
p
<=
'f'
)
||
(
*
p
>=
'A'
&&
*
p
<=
'F'
))))
{
char
c
=
*
p
++
;
int
val
;
while
(
*
p
>=
'0'
&&
*
p
<=
'9'
)
{
found_digit
=
TRUE
;
if
(
c
>=
'0'
&&
c
<=
'9'
)
val
=
c
-
'0'
;
else
if
(
c
>=
'a'
&&
c
<=
'f'
)
val
=
10
+
c
-
'a'
;
else
val
=
10
+
c
-
'A'
;
hlp
=
d
*
base
+
val
;
if
(
d
>
MSVCRT_UI64_MAX
/
base
||
hlp
<
d
)
{
hlp
=
d
*
10
+
*
p
++
-
'0'
;
if
(
d
>
MSVCRT_UI64_MAX
/
10
||
hlp
<
d
)
{
exp
++
;
break
;
}
else
d
=
hlp
;
}
while
((
*
p
>=
'0'
&&
*
p
<=
'9'
)
||
(
base
==
16
&&
((
*
p
>=
'a'
&&
*
p
<=
'f'
)
||
(
*
p
>=
'A'
&&
*
p
<=
'F'
))))
{
while
(
*
p
>=
'0'
&&
*
p
<=
'9'
)
{
exp
++
;
p
++
;
}
...
...
@@ -413,25 +616,15 @@ static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale
if
(
*
p
==
*
locinfo
->
lconv
->
decimal_point
)
p
++
;
while
((
*
p
>=
'0'
&&
*
p
<=
'9'
)
||
(
base
==
16
&&
((
*
p
>=
'a'
&&
*
p
<=
'f'
)
||
(
*
p
>=
'A'
&&
*
p
<=
'F'
))))
{
char
c
=
*
p
++
;
int
val
;
while
(
*
p
>=
'0'
&&
*
p
<=
'9'
)
{
found_digit
=
TRUE
;
if
(
c
>=
'0'
&&
c
<=
'9'
)
val
=
c
-
'0'
;
else
if
(
c
>=
'a'
&&
c
<=
'f'
)
val
=
10
+
c
-
'a'
;
else
val
=
10
+
c
-
'A'
;
hlp
=
d
*
base
+
val
;
if
(
d
>
MSVCRT_UI64_MAX
/
base
||
hlp
<
d
)
hlp
=
d
*
10
+
*
p
++
-
'0'
;
if
(
d
>
MSVCRT_UI64_MAX
/
10
||
hlp
<
d
)
break
;
d
=
hlp
;
exp
--
;
}
while
((
*
p
>=
'0'
&&
*
p
<=
'9'
)
||
(
base
==
16
&&
((
*
p
>=
'a'
&&
*
p
<=
'f'
)
||
(
*
p
>=
'A'
&&
*
p
<=
'F'
))))
while
(
*
p
>=
'0'
&&
*
p
<=
'9'
)
p
++
;
if
(
!
found_digit
)
{
...
...
@@ -440,11 +633,7 @@ static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale
return
0
.
0
;
}
if
(
base
==
16
)
exp
*=
4
;
if
((
base
==
10
&&
(
*
p
==
'e'
||
*
p
==
'E'
||
*
p
==
'd'
||
*
p
==
'D'
))
||
(
base
==
16
&&
(
*
p
==
'p'
||
*
p
==
'P'
)))
{
if
(
*
p
==
'e'
||
*
p
==
'E'
||
*
p
==
'd'
||
*
p
==
'D'
)
{
int
e
=
0
,
s
=
1
;
p
++
;
...
...
dlls/ucrtbase/tests/string.c
View file @
c953c36d
...
...
@@ -125,9 +125,9 @@ static void _test_strtod_str(int line, const char* string, double value, int len
double
d
;
d
=
p_strtod
(
string
,
&
end
);
if
(
local_isnan
(
value
))
ok_
(
__FILE__
,
line
)(
local_isnan
(
d
),
"d = %
lf
(
\"
%s
\"
)
\n
"
,
d
,
string
);
ok_
(
__FILE__
,
line
)(
local_isnan
(
d
),
"d = %
.16le
(
\"
%s
\"
)
\n
"
,
d
,
string
);
else
ok_
(
__FILE__
,
line
)(
d
==
value
,
"d = %
lf
(
\"
%s
\"
)
\n
"
,
d
,
string
);
ok_
(
__FILE__
,
line
)(
d
==
value
,
"d = %
.16le
(
\"
%s
\"
)
\n
"
,
d
,
string
);
ok_
(
__FILE__
,
line
)(
end
==
string
+
length
,
"incorrect end (%d,
\"
%s
\"
)
\n
"
,
(
int
)(
end
-
string
),
string
);
}
...
...
@@ -162,6 +162,17 @@ static void test_strtod(void)
test_strtod_str
(
"0x1.1p1"
,
2
.
125
,
7
);
test_strtod_str
(
"0x1.A"
,
1
.
625
,
5
);
test_strtod_str
(
"0x1p1a"
,
2
,
5
);
test_strtod_str
(
"0xp3"
,
0
,
1
);
test_strtod_str
(
"0x."
,
0
,
1
);
test_strtod_str
(
"0x.8"
,
0
.
5
,
4
);
test_strtod_str
(
"0x.8p"
,
0
.
5
,
4
);
test_strtod_str
(
"0x0p10000000000000000000000000"
,
0
,
30
);
test_strtod_str
(
"0x1p-1026"
,
1.3906711615670009e-309
,
9
);
test_strtod_str
(
"0x1ffffffffffffe.80000000000000000000"
,
9007199254740990
.
0
,
37
);
test_strtod_str
(
"0x1ffffffffffffe.80000000000000000001"
,
9007199254740991
.
0
,
37
);
test_strtod_str
(
"0x1fffffffffffff.80000000000000000000"
,
9007199254740992
.
0
,
37
);
test_strtod_str
(
"0x1fffffffffffff.80000000000000000001"
,
9007199254740992
.
0
,
37
);
}
static
void
test__memicmp
(
void
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment