* fpc_Val_SInt_ShortStr: bug fixes and improvements by Bart B

This commit is contained in:
florian 2022-01-08 14:45:12 +01:00
parent 38c06e64c7
commit f39a6a7755

View File

@ -1154,33 +1154,41 @@ end;
Function fpc_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_SHORTSTR']; compilerproc;
var
temp, prev, maxPrevValue, maxNewValue: ValUInt;
temp, prev, maxPrevValue: ValUInt;
base,u : byte;
negative, RolledOver: boolean;
SignedLower, SignedUpper: Int64;
UnsignedUpper: UInt64;
RolledOverAt: integer;
RollOverPoint: ValUInt;
negative: boolean;
UnsignedUpperLimit: ValUInt;
const
ValueArray : array['0'..'f'] of byte = (0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
ValueArray : array['0'..'f'] of byte = (0,1,2,3,4,5,6,7,8,9,$FF,$FF,$FF,$FF,$FF,$FF,$FF,10,11,12,13,14,15,
$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
10,11,12,13,14,15);
begin
fpc_Val_SInt_ShortStr := 0;
Temp:=0;
Code:=InitVal(s,negative,base);
case DestSize of
1: begin SignedLower:=Low(ShortInt); SignedUpper:=(High(ShortInt)); UnSignedUpper:=High(Byte) end;
2: begin SignedLower:=Low(SmallInt); SignedUpper:=(High(SmallInt)); UnSignedUpper:=High(Word) end;
4: begin SignedLower:=Low(LongInt); SignedUpper:=(High(LongInt)); UnSignedUpper:=High(DWord) end;
8: begin SignedLower:=Low(Int64); SignedUpper:=(High(Int64)); UnSignedUpper:=High(QWord) end;
end;
RolledOver:=False;
if negative then
RollOverPoint:=-SignedLower
if (base=10) or negative then
begin //always limit to either Low(DestType) or High(DestType)
case DestSize of
1: UnsignedUpperLimit := ValUInt(High(ShortInt))+Ord(negative);
2: UnsignedUpperLimit := ValUInt(High(SmallInt))+Ord(negative);
4: UnsignedUpperLimit := ValUInt(High(LongInt))+Ord(negative);
{$ifdef CPU64}
8: UnsignedUpperLimit := ValUInt(High(Int64))+Ord(negative);
{$endif CPU64}
end;
end
else
RollOverPoint:=SignedUpper;
begin //not decimal and not negative
case DestSize of
1: UnsignedUpperLimit := High(Byte);
2: UnsignedUpperLimit := High(Word);
4: UnsignedUpperLimit := High(DWord);
{$ifdef CPU64}
8: UnsignedUpperLimit := High(UInt64);
{$endif CPU64}
end;
end;
if Code>length(s) then
exit;
@ -1190,11 +1198,8 @@ begin
Code:=0;
exit;
end;
maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base);
if (base = 10) then
maxNewValue := MaxSIntValue + ord(negative)
else
maxNewValue := MaxUIntValue;
while Code<=Length(s) do
begin
@ -1208,19 +1213,14 @@ begin
Prev := Temp;
Temp := Temp*ValUInt(base);
If (u >= base) or
(ValUInt(maxNewValue-u) < Temp) or
(prev > maxPrevValue) or
((Temp+u)>UnsignedUpper) Then
(prev > maxPrevValue)
or ((Temp)>(UnsignedUpperLimit-u)) Then
Begin
fpc_Val_SInt_ShortStr := 0;
Exit
End;
if (not RolledOver) and ((Temp+u)>RollOverPoint) then
begin
RolledOver := True;
RolledOverAt := Code;
end;
Temp:=Temp+u;
inc(code);
end;
@ -1230,13 +1230,6 @@ begin
If Negative Then
fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr;
if RolledOver and ((base=10) or ((base<>10) and (negative))) {and (not negative)} then
begin
fpc_Val_SInt_ShortStr:=0;
Code := RolledOverAt;
exit;
end;
If Not(Negative) and (base <> 10) Then
{sign extend the result to allow proper range checking}
Case DestSize of