From a672c527d4e8a33732b0cb66b1f20ca820be4dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Van=20Canneyt?= Date: Mon, 13 Jun 2022 10:10:36 +0200 Subject: [PATCH] * Patch from Bart, Fix issue #39778 (cherry picked from commit 480199a7d974b23fb1b790079cb206bad7d4829f) --- packages/rtl-objpas/src/inc/convutil.inc | 214 ++++++++++++++++++----- 1 file changed, 169 insertions(+), 45 deletions(-) diff --git a/packages/rtl-objpas/src/inc/convutil.inc b/packages/rtl-objpas/src/inc/convutil.inc index de710f0ac1..4ca5406eac 100644 --- a/packages/rtl-objpas/src/inc/convutil.inc +++ b/packages/rtl-objpas/src/inc/convutil.inc @@ -46,6 +46,9 @@ Function RegisterConversionFamily(Const S : String):TConvFamily; Function RegisterConversionType(Fam:TConvFamily;Const S:String;Value:TConvUtilFloat):TConvType; Function RegisterConversionType(Fam:TConvFamily;Const S:String;const AToCommonFunc, AFromCommonFunc: TConversionProc): TConvType; +procedure UnregisterConversionFamily(const AFamily: TConvFamily); +procedure UnregisterConversionType(const AType: TConvType); + function Convert ( const Measurement : Double; const FromType, ToType : TConvType ) :TConvUtilFloat; function Convert ( const Measurement : Double; const FromType1, FromType2, ToType1, ToType2 : TConvType ) :TConvUtilFloat; @@ -79,6 +82,9 @@ function ConvUnitToStr(const AValue: Double; const AType: TConvType): string; function DescriptionToConvFamily(const ADescription: String; out AFamily: TConvFamily): Boolean; function DescriptionToConvType(const ADescription: String; out AType: TConvType): Boolean; overload; function DescriptionToConvType(const AFamily: TConvFamily; const ADescription: String; out AType: TConvType): Boolean; overload; +function TryStrToConvUnit(AText: string; out AValue: Double; out AType: TConvType): Boolean; +function StrToConvUnit(AText: string; out AType: TConvType): Double; + procedure GetConvFamilies(out AFamilies: TConvFamilyArray); procedure GetConvTypes(const AFamily: TConvFamily; out ATypes: TConvTypeArray); @@ -142,11 +148,61 @@ Type ResourceData = record ToCommonFunc : TConversionProc; FromCommonFunc: TConversionProc; Fam : TConvFamily; + Deleted : Boolean; end; + TFamilyData = record + Description: String; + Deleted : Boolean; + end; var TheUnits : array of ResourceData =nil; - TheFamilies : array of string =nil; + TheFamilies : array of TFamilyData =nil; + +function FindFamily(const ADescription: String; out AFam: TConvFamily): Boolean; + +var + i: Integer; + +begin + result:=False; + for i := 0 to Length(TheFamilies)-1 do + begin + if (TheFamilies[i].Description=ADescription) and (not TheFamilies[i].Deleted) then + begin + result:=True; + AFam:=TConvFamily(i); + Exit; + end; + end; +end; + +function FindConvType(AFam: TConvFamily; const ADescription: string; out AResourceData: ResourceData): Boolean; + +var + i: Integer; + +begin + result:=False; + for i := 0 to Length(TheUnits)-1 do + begin + if (TheUnits[i].Fam=AFam) and (TheUnits[i].Description=ADescription) and (not TheUnits[i].Deleted) then + begin + result:=True; + AResourceData:=TheUnits[i]; + end; + end; +end; + +function FindConvType(AFam: TConvFamily; const ADescription: string): Boolean; + +var + Data: ResourceData; + +begin + result:=FindConvType(AFam, ADescription, Data); +end; + function ConvUnitDec(const AValue: Double; const AType: TConvType; const AAmount: Double; const AAmountType: TConvType): TConvUtilFloat; @@ -209,8 +265,8 @@ end; function ConvFamilyToDescription(const AFamily: TConvFamily): string; begin - if AFamilyTheFamilies[i]) do inc(i); - if i=l Then - begin - SetLength(TheFamilies,l+1); - TheFamilies[l]:=s; - end; - Result:=i; - end; + len:=Length(TheFamilies); + if len>0 then + if FindFamily(S, fam) then + raise EConversionError.CreateFmt(SConvDuplicateFamily,[S]); + if len=Integer(High(TConvFamily))+1 then + raise EConversionError.CreateFmt(SConvTooManyConvFamilies,[High(TConvFamily)]); + SetLength(TheFamilies,len+1); + TheFamilies[len].Description:=S; + TheFamilies[len].Deleted:=False; + result:=len; +end; + +procedure UnregisterConversionFamily(const AFamily: TConvFamily); + +var + i: Integer; + +begin + //Apparently this procedure is not supposed to raise exceptions + TheFamilies[AFamily].Deleted:=True; + for i:=0 to Length(TheUnits)-1 do + begin + if TheUnits[i].Fam=AFamily then + TheUnits[i].Deleted:=True; + end; end; Function CheckFamily(i:TConvFamily):Boolean; begin - Result:=i0 then + if FindConvType(Fam, S) then + raise EConversionError.CreateFmt(SConvDuplicateType,[S,ConvFamilyToDescription(Fam)]); + if l1=Integer(High(TConvType))+1 then raise EConversionError.CreateFmt(SConvTooManyConvTypes,[High(TConvType)]); Setlength(theunits,l1+1); theunits[l1].description:=s; @@ -421,6 +529,7 @@ begin theunits[l1].ToCommonFunc:=AToCommonFunc; theunits[l1].FromCommonFunc:=AFromCommonFunc; theunits[l1].fam:=fam; + theunits[l1].deleted:=false; Result:=l1; end; @@ -435,13 +544,13 @@ begin result:=InternalRegisterConversionType(Fam,S,(AToCommonFunc(1)-AToCommonFunc(0)),AToCommonFunc,AFromCommonFunc); end; -function SearchConvert(TheType:TConvType; var r:ResourceData):Boolean; +function SearchConvert(TheType:TConvType; out r:ResourceData):Boolean; var l1 : longint; begin l1:=length(TheUnits); - if thetype>=l1 then + if (thetype>=l1) or (theunits[thetype].Deleted) then exit(false); r:=theunits[thetype]; result:=true; @@ -470,10 +579,17 @@ begin common:=Measurement*fromrec.value; if assigned(torec.FromCommonFunc) then result:=torec.FromCommonFunc(common) - else + else begin + if IsZero(torec.value) then + raise EZeroDivide.CreateFmt(SConvFactorZero,[torec.Description]); result:=common/torec.value; - end else + end; + end else begin + //Note: Delphi 7 raises an EZeroDivide even if fromrec.value=0, which is a bit odd + if IsZero(torec.value) then + raise EZeroDivide.CreateFmt(SConvFactorZero,[torec.Description]); result:=Measurement*fromrec.value/torec.value; + end; end; function Convert ( const Measurement : Double; const FromType1, FromType2, ToType1, ToType2 : TConvType ) :TConvUtilFloat; @@ -498,6 +614,10 @@ begin ConvFamilyToDescription(torec2.fam) ]); //using ToCommonFunc() and FromCommonFunc makes no sense in this context + if IsZero(fromrec2.value) then + raise EZeroDivide.CreateFmt(SConvFactorZero,[fromrec2.Description]); + if IsZero(torec2.value) then + raise EZeroDivide.CreateFmt(SConvFactorZero,[torec2.Description]); result:=Measurement*(fromrec1.value/fromrec2.value)/(torec1.value/torec2.value); end; @@ -526,7 +646,11 @@ begin if Assigned(torec.FromCommonFunc) then result:=torec.FromCommonFunc(AValue) else + begin + if IsZero(torec.value) then + raise EZeroDivide.CreateFmt(SConvFactorZero,[torec.Description]); result:=Avalue/torec.value; + end; end; function ConvUnitCompareValue(const AValue1: Double; const AType1: TConvType; @@ -544,7 +668,7 @@ end; function ConvUnitSameValue(const AValue1: Double; const AType1: TConvType; const AValue2: Double; const AType2: TConvType): Boolean; begin - result:=ConvUnitCompareValue(Avalue1, AType1, AValue2, AType2)=0; + result:=ConvUnitCompareValue(Avalue1, AType1, AValue2, AType2)=EqualsValue; end;