supermario/base/SuperMarioProj.1994-02-09/Toolbox/AppleEventMgr/AECoercion.inc1.p
2019-06-29 23:17:50 +08:00

808 lines
33 KiB
OpenEdge ABL

{
File: AECoercion.inc1.p
Contains: xxx put contents here xxx
Written by: xxx put writers here xxx
Copyright: © 1990 by Apple Computer, Inc., all rights reserved.
This file is used in these builds: BigBang
Change History (most recent first):
<3> 2/5/91 Lai BM,#81596: Also for bug jfr101 on whiteboard. Move the
functionality of making a 'reco' in coercion to AECreateDesc and
just call AECreateDesc.
<2> 1/17/91 Lai In StdCoercion, check for overflow going from 'sing' to 'doub'
because source may be equal to 'INF'.
<1> 12/13/90 Lai first checked in after subdividing into smaller modules
To Do:
}
{ Copyright © 1984-1991 by Apple Computer Inc. All rights reserved. }
CONST
singPrecision = 8; { from SANE manual page 14 }
doubPrecision = 16; { from SANE manual page 14 }
compPrecision = 19; { from SANE manual page 14 }
extePrecision = 20; { from SANE manual page 14 }
magnPrecision = 10;
TYPE
CompOrTwoLong = RECORD
CASE Boolean OF
FALSE:
(asComp: Comp);
TRUE:
(asLong: ARRAY [0..1] OF LONGINT);
END;
UnivNum = RECORD
CASE Integer OF
1:
(asSignedByte: SignedByte);
2:
(asInteger: Integer);
3:
(asLongint: Longint);
4:
(asReal: Real);
5:
(asComp: Comp);
6:
(asDouble: Double);
7:
(asExtended: Extended);
8:
(asResType: ResType);
END;
{--------------------------------------------------------------------------------}
FUNCTION CallPtrCoercion(typeCode: DescType;
dataPtr: Ptr;
dataSize: LONGINT;
toType: DescType;
refcon: LONGINT;
VAR result: AEDesc;
DoProc: ProcPtr): OSErr;
{ inline is equivalent to : movea.l (a7)+,a0; jsr (a0) }
INLINE $205F, $4E90;
{--------------------------------------------------------------------------------}
FUNCTION CallDescCoercion(desc: AEDesc;
toType: DescType;
refcon: LONGINT;
VAR result: AEDesc;
DoProc: ProcPtr): OSErr;
{ inline is equivalent to : movea.l (a7)+,a0; jsr (a0) }
INLINE $205F, $4E90;
{--------------------------------------------------------------------------------}
{ we need these from AEInteract }
FUNCTION AE_InteractWithUser(timeOutInTicks: LONGINT; { how long are you willing to wait }
nmReqPtr: NMRecPtr; { your own custom notification }
idleProc: IdleProcPtr { your own idle procedure }
): OSErr; EXTERNAL;
{--------------------------------------------------------------------------------}
{ we need these from AEDFWrapper }
FUNCTION AE_CountItems(VAR theAEDescList: AEDescList; { VAR is for efficiency only }
VAR theCount: LONGINT): OSErr;
EXTERNAL;
FUNCTION AE_PutPtr(VAR theAEDescList: AEDescList; { VAR is for efficiency only }
index: LONGINT;
typeCode: DescType;
dataPtr: Ptr;
dataSize: LONGINT): OSErr;
EXTERNAL;
FUNCTION AE_GetNthDesc(VAR theAEDescList: AEDescList; { VAR is for efficiency only }
index: LONGINT;
desiredType: DescType;
VAR theAEKeyword: AEKeyWord;
VAR theAEDesc: AEDesc): OSErr;
EXTERNAL;
FUNCTION AE_DisposeDesc(VAR theAEDesc: AEDesc): OSErr;
EXTERNAL;
{--------------------------------------------------------------------------------}
FUNCTION StdCoercion(fromType: DescType;
dataPtr: Ptr;
dataSize: LONGINT;
toType: DescType;
VAR result: AEDesc): OSErr;
FORWARD;
{--------------------------------------------------------------------------------}
{ coerce data froma a buffer to a desc }
{ not that if the coercion routine is for desc to desc, we have to make a desc first }
FUNCTION AE_CoercePtr(typeCode: DescType;
dataPtr: Ptr;
dataSize: LONGINT;
toType: DescType;
VAR result: AEDesc): OSErr;
VAR
err: OSErr;
tempDesc: AEDesc;
FUNCTION TryFromTable(aGlobal: GlobalRecHandle): OSErr;
VAR
theHandlerRec: HandlerRec;
hasProc: Boolean;
err: OSErr;
BEGIN
err := errAECoercionFail;
IF aGlobal <> NIL THEN
BEGIN
WITH aGlobal^^ DO
IF coercionHashTable <> NIL THEN
IF GetTableInfo(coercionHashTable, typeCode, toType, theHandlerRec) THEN
WITH theHandlerRec DO
BEGIN
IF BTst(ord(theProc), 0) { odd(ord(theCoercionProc))} THEN
BEGIN { it is the format from desc to desc }
{ since it is desc to desc, we have to make one first }
err := AE_CreateDesc(typeCode, dataPtr, dataSize, tempDesc);
IF err = noErr THEN
BEGIN
{ now we call coerce it, the real address is off by 1 }
err := CallDescCoercion(tempDesc, toType, theRefCon, result,
ProcPtr(ord(theProc) - 1));
IgnoreOSErr(AE_DisposeDesc(tempDesc));
END;
END
ELSE { otherwise we can do it directly }
err := CallPtrCoercion(typeCode, dataPtr, dataSize, toType, theRefCon,
result, theProc);
END;
END;
TryFromTable := err;
END;
BEGIN
err := TryFromTable(GetGlobalRef);
IF err = errAECoercionFail THEN err := TryFromTable(GetSysGlobal);
IF err = errAECoercionFail THEN
err := StdCoercion(typeCode, dataPtr, dataSize, toType, result);
IF err <> noErr THEN NukeIt(result);
AE_CoercePtr := err;
END;
{--------------------------------------------------------------------------------}
{ coerce data from a desc to a desc }
{ the built in desc to desc coercion is here rather than in StdCercion because
StdCoercion is for ptr to desc }
{ the built in ones are
AEList to anything, fetch the only item in the list
AERecord to anything, same format
AppleEvent to typeAppParameters, so it can be used in launch
Alias to FSS, because it is useful for the required events }
FUNCTION AE_CoerceDesc(VAR desc: AEDesc; { VAR is for efficiency only }
toType: DescType;
VAR result: AEDesc): OSErr;
VAR
err: OSErr;
flags: SignedByte;
count: LONGINT; { number of elements in the list }
dummyKey: AEKeyWord;
dataSize: LONGINT;
aHandle: Handle;
aFSS: FSSpec;
aBool: boolean;
refcon: LONGINT;
aliasCount: Integer;
FUNCTION TryFromTable(aGlobal: GlobalRecHandle): OSErr;
VAR
theHandlerRec: HandlerRec;
hasProc: Boolean;
err: OSErr;
BEGIN
err := errAECoercionFail;
IF aGlobal <> NIL THEN
BEGIN
WITH aGlobal^^ DO
IF coercionHashTable <> NIL THEN
IF GetTableInfo(coercionHashTable, desc.descriptorType, toType,
theHandlerRec) THEN
WITH theHandlerRec DO
BEGIN
IF BTst(ord(theProc), 0) { odd(ord(theCoercionProc))} THEN
BEGIN { it is the format from desc to desc, value of proc is off by 1 }
err := CallDescCoercion(desc, toType, theRefCon, result,
ProcPtr(ord(theProc) - 1));
END
ELSE
WITH desc DO
BEGIN
IF dataHandle <> NIL THEN
BEGIN
flags := HGetState(dataHandle);
HLock(dataHandle);
dataSize := GetHandleSize(dataHandle)
END
ELSE
dataSize := 0;
err := CallPtrCoercion(descriptorType, dataHandle^, dataSize,
toType, theRefCon, result, theProc);
HSetState(dataHandle, flags);
END;
END;
END;
TryFromTable := err;
END;
BEGIN
err := TryFromTable(GetGlobalRef);
IF err = errAECoercionFail THEN err := TryFromTable(GetSysGlobal);
IF err = errAECoercionFail THEN
WITH desc DO
BEGIN
IF (LONGINT(descriptorType) = LONGINT(toType)) THEN
err := AE_DuplicateDesc(desc, result)
ELSE IF (LONGINT(descriptorType) = LONGINT(typeAEList)) AND (LONGINT(toType) <>
LONGINT(typeWildCard)) THEN
BEGIN { special handling for list since it cannot be done as pointer to data }
{ get the first element if there is only one element }
IF AE_CountItems(desc, count) = noErr THEN
IF count = 1 THEN
BEGIN { get first and only element and coerce it to right type }
{ note that this means it can be recurseive, so if you have an element in a list
in a list in a list etc, it would still be fetched }
err := AE_GetNthDesc(desc, 1, toType, dummyKey, result);
END;
END
ELSE IF (LONGINT(descriptorType) = LONGINT(typeAERecord)) AND
(LONGINT(toType) <> LONGINT(typeWildCard)) THEN
WITH desc DO
BEGIN
{ special case for AERecord, anything can be have the same format as AERecord
if you ask to coerce AERecord to any type, it is assumed that you know that
the format is the same as AERecord, so if it is not, as in the case
you try to coerce an AERecord into a 'PICT', it is your mistake }
flags := HGetState(dataHandle);
HLock(dataHandle);
WITH ListHdrHdl(dataHandle)^^ DO
err := PtrToHand(Ptr(ord(dataHandle^) + SizeOf(listClassRec)),
result.dataHandle, GetHandleSize(dataHandle) -
SizeOf(listClassRec));
result.descriptorType := toType;
HSetState(dataHandle, flags);
END
ELSE IF (LONGINT(descriptorType) = LONGINT(kCoreEventClass)) AND (LONGINT(toType) =
LONGINT(typeAppParameters)) THEN
BEGIN
{ this convert an AppleEvent into the data strucutre used in launch }
{ count is offset to the begin of AppleEvent }
count := SizeOf(MsgHdr) - SizeOf(TargetID) + MsgHdrHdl(desc.dataHandle)^^.
msgAddrSize;
dataSize := GetHandleSize(dataHandle) - count;
aHandle := NewHandle(dataSize + SizeOf(EventRecord) + 8);
err := MemError;
IF aHandle <> NIL THEN
BEGIN
WITH MsgHdrHdl(desc.dataHandle)^^, AppParametersPtr(aHandle^)^ DO
BEGIN
WITH theMsgEvent DO
BEGIN
what := kHighLevelEvent;
message := LONGINT(thisAEEventClass);
where := Point(thisAEEventID);
modifiers := 0;
END;
eventRefCon := ReturnID;
messageLength := dataSize;
END;
BlockMove(Ptr(ord(desc.dataHandle^) + count), Ptr(ord(aHandle^) +
SizeOf(EventRecord) + 8),
dataSize);
WITH result DO
BEGIN
descriptorType := toType;
dataHandle := aHandle;
END;
END;
END
ELSE IF (LONGINT(descriptorType) = LONGINT(typeAlias)) AND (LONGINT(toType) =
LONGINT(typeFSS)) THEN
BEGIN
{ alias to SFS is just resolve alias }
{ err := ResolveAlias(NIL, AliasHandle(desc.dataHandle), aFSS, aBool); }
{ we can use MatchAlias instead because we may not want to involve user }
aliasCount := 1;
err := MatchAlias(NIL, kARMsearch + kARMmountVol + kARMnoUI, AliasHandle(desc.dataHandle), aliasCount,
@aFSS, aBool, NIL, NIL);
{ if volume is not mounted, we try again to mount volume if we can interact }
IF err = nsvErr THEN
IF AE_InteractWithUser(kAEDefaultTimeout, NIL, NIL) = noErr THEN
BEGIN
aliasCount := 1;
err := MatchAlias(NIL, kARMsearch + kARMmountVol, AliasHandle(desc.dataHandle), aliasCount,
@aFSS, aBool, NIL, NIL);
END;
IF err = noErr THEN
BEGIN
err := PtrToHand(@aFSS, result.dataHandle, SizeOf(aFSS));
result.descriptorType := typeFSS;
END;
END
ELSE
BEGIN { point to data and call AE_CoercePtr }
{ we cannot do it with standard desc to desc coercion
maybe we can do it with standard buffer to desc coercion }
flags := HGetState(dataHandle);
HLock(dataHandle);
err := StdCoercion(descriptorType, dataHandle^, GetHandleSize(dataHandle),
toType, result);
HSetState(dataHandle, flags);
END;
END;
IF err <> noErr THEN NukeIt(result);
AE_CoerceDesc := err;
END;
{--------------------------------------------------------------------------------}
{ whether the data type is a kind of boolean, and is what is the value }
FUNCTION BooleanType(fromType: DescType;
dataPtr: Ptr;
VAR result: integer): Boolean;
VAR
booleanAsInteger: Integer;
BEGIN
booleanAsInteger := - 1; { an illegal value }
IF LONGINT(fromType) = LONGINT(typeBoolean) THEN
booleanAsInteger := dataPtr^
ELSE IF LONGINT(fromType) = LONGINT(typeTrue) THEN
booleanAsInteger := 1
ELSE IF LONGINT(fromType) = LONGINT(typeFalse) THEN
booleanAsInteger := 0
ELSE IF LONGINT(fromType) = LONGINT(typeEnumerated) THEN
BEGIN
IF LONGINTPtr(dataPtr)^ = LONGINT(typeTrue) THEN
booleanAsInteger := 1
ELSE IF LONGINTPtr(dataPtr)^ = LONGINT(typeFalse) THEN booleanAsInteger := 0;
END
ELSE IF LONGINT(fromType) = LONGINT(typeShortInteger) THEN
booleanAsInteger := IntegerPtr(dataPtr)^;
BooleanType := (booleanAsInteger = 0) OR (booleanAsInteger = 1);
result := booleanAsInteger;
END;
{--------------------------------------------------------------------------------}
{ Check to see the buffer look anything like an AERecord buffer at all }
FUNCTION CheckIsRecord(dataPtr: Ptr;
dataLen: longint): boolean;
TYPE
factoredHeader = RECORD
parameterCount: LONGINT;
sizeOfPrefix: LONGINT;
typeOfData: OSType;
eachItemSize: LONGINT;
END;
factoredHeaderPtr = ^factoredHeader;
VAR
dataEnd, count, prefixSize, index: longint;
aPtr: ptr;
BEGIN
CheckIsRecord := false;
{ dataEnd := ord(dataPtr) + RoundUp(dataLen); }
dataEnd := ord(dataPtr) + BAnd(dataLen + RoundUpValue, roundUpMask); { this is the end of
the record }
WITH factoredHeaderPtr(dataPtr)^ DO
BEGIN
count := parameterCount;
prefixSize := sizeOfPrefix;
IF count < 0 THEN EXIT(CheckIsRecord);
{ skip to the beginning of first record }
{ we skip parameterCount and sizeOfPrefix field, i.e. 8 bytes then the prefix }
{ aPtr := Ptr(ord(dataPtr) + RoundUp(prefixSize+8)); }
aPtr := Ptr(ord(dataPtr) + BAnd(prefixSize + 8 + RoundUpValue, roundUpMask));
IF prefixSize >= 8 THEN
BEGIN
{ factorout is RoundUp(prefixSize - 8), so real item size is eachItemSize - RoundUp(prefixSize + 8) }
{ and we need to add 4 for the keyword }
{ aPtr := Ptr(ord(aPtr) + RoundUp(eachItemSize - RoundUp(prefixSize + 8) + 4) * count); }
aPtr := Ptr(ord(aPtr) + BAnd(eachItemSize - BAnd(prefixSize + 8 + RoundUpValue,
RoundUpMask) + 4 + RoundUpValue,
RoundUpMask) * count);
END
ELSE
BEGIN
IF prefixSize <> 0 THEN IF prefixSize <> 4 THEN exit(CheckIsRecord);
FOR index := count DOWNTO 1 DO
BEGIN
{ prefixSize is either 0 or 4 }
{ LONGINTPtr(ord(aPtr) + 8 - prefixSize)^ points to the the length of field }
{ 12 - prefixSize is either 12 in the case of key type length or
8 in the case of key length }
{ so the following skip a field }
{ aPtr := Ptr(ord(aPtr) + RoundUp(LONGINTPtr(ord(aPtr) + 8 - prefixSize)^ + 12 - prefixSize)); }
aPtr := Ptr(ord(aPtr) + BAnd(LONGINTPtr(ord(aPtr) + 8 - prefixSize)^ +
12 + RoundUpValue - prefixSize, RoundUpMask));
IF ord(aPtr) > dataEnd THEN exit(CheckIsRecord);
END;
END;
END;
IF ord(aPtr) = dataEnd THEN CheckIsRecord := true;
END;
{--------------------------------------------------------------------------------}
{ take a descriptor and convert its value to an Extended }
FUNCTION DescToExtd(theType: DescType;
dataPtr: Ptr;
dataSize: LONGINT;
VAR precisionDigits: Integer;
VAR anExtended: Extended): boolean;
VAR
aComp: CompOrTwoLong;
aPtr: LONGINTPtr;
aStr: DecStr;
theNumClass: NumClass;
saneDecimal: Decimal;
validPrefix: Boolean;
conversionResult: Boolean;
index: Integer;
BEGIN
conversionResult := TRUE;
IF LONGINT(theType) = LONGINT(TypeChar) THEN
BEGIN
conversionResult := FALSE;
IF dataSize <= DecStrLen THEN { not too long for SANE }
BEGIN
aStr[0] := chr(dataSize);
BlockMove(dataPtr, @aStr[1], dataSize);
index := 1; { we start scanning from 1 }
Str2Dec(aStr, index, saneDecimal, validPrefix);
IF validPrefix AND (index > dataSize) THEN
BEGIN { it is valid }
anExtended := Dec2Num(saneDecimal); { ask SANE to finish the job }
conversionResult := TRUE;
END;
END;
END
ELSE IF (LONGINT(theType) = LONGINT(typeLongInteger)) AND (dataSize = SizeOf(LONGINT)) THEN
anExtended := LONGINTPtr(dataPtr)^
ELSE IF (LONGINT(theType) = LONGINT(typeShortInteger)) AND (dataSize = SizeOf(Integer)) THEN
anExtended := IntegerPtr(dataPtr)^
ELSE IF (LONGINT(theType) = LONGINT(typeComp)) AND (dataSize = SizeOf(Comp)) THEN
BEGIN
anExtended := CompPtr(dataPtr)^;
precisionDigits := compPrecision;
END
ELSE IF (LONGINT(theType) = LONGINT(typeShortFloat)) AND (dataSize = SizeOf(Real)) THEN
BEGIN
anExtended := RealPtr(dataPtr)^;
precisionDigits := singPrecision;
END
ELSE IF (LONGINT(theType) = LONGINT(typeLongFloat)) AND (dataSize = SizeOf(Double)) THEN
BEGIN
anExtended := DoublePtr(dataPtr)^;
precisionDigits := doubPrecision;
END
ELSE IF (LONGINT(theType) = LONGINT(typeExtended)) AND (dataSize = SizeOf(Extended)) THEN
BEGIN
anExtended := ExtendedPtr(dataPtr)^;
precisionDigits := extePrecision;
END
ELSE IF (LONGINT(theType) = LONGINT(typeMagnitude)) AND (dataSize = SizeOf(LONGINT)) THEN
BEGIN { first make it into comp, then coerce to extend }
aComp.asLong[0] := 0;
aComp.asLong[1] := LONGINTPtr(dataPtr)^;
anExtended := aComp.asComp;
precisionDigits := magnPrecision;
END
ELSE
conversionResult := FALSE;
{ valid only if it is zeroNum, NormalNum or DenormalNum }
IF conversionResult THEN
conversionResult := (ClassExtended(anExtended) >= ZeroNum);
DescToExtd := conversionResult;
END;
{--------------------------------------------------------------------------------}
{ take an extened and convert it to the type toType }
FUNCTION ExtdToNum(VAR x: Extended; { VAR is for efficiency purpose only }
toType: DescType;
VAR anUnivNum: UnivNum): boolean;
VAR
saneEnvironment: Environment;
canConvert: boolean;
aComp: CompOrTwoLong;
BEGIN
GetEnvironment(saneEnvironment);
{ clear all flags and halt but preserve rounding direction and precision }
SetEnvironment(BAnd(saneEnvironment, $6060));
canConvert := TRUE;
IF LONGINT(toType) = LONGINT(typeShortInteger) THEN
anUnivNum.asInteger := Num2Integer(x)
ELSE IF LONGINT(toType) = LONGINT(typeLongInteger) THEN
anUnivNum.asLongint := Num2Longint(x)
ELSE IF LONGINT(toType) = LONGINT(typeShortFloat) THEN
anUnivNum.asReal := Num2Real(x)
ELSE IF LONGINT(toType) = LONGINT(typeLongFloat) THEN
anUnivNum.asDouble := Num2Double(x)
ELSE IF LONGINT(toType) = LONGINT(typeComp) THEN
anUnivNum.asComp := Num2Comp(x)
ELSE IF LONGINT(toType) = LONGINT(typeMagnitude) THEN
BEGIN
aComp.asComp := Num2Comp(x);
canConvert := (aComp.asLong[0] = 0);
anUnivNum.asLongint := aComp.asLong[1];
END
ELSE
canConvert := FALSE;
ExtdToNum := canConvert AND (NOT TestException(Invalid + Overflow));
SetEnvironment(saneEnvironment); { restore original state }
END;
{--------------------------------------------------------------------------------}
{ convert an extended to text, make reasonable assumption about float/fixed
and number of decimal places }
PROCEDURE ExtdToText(precisionDigits: Integer;
VAR anExtended: Extended;
VAR aStr: Str255);
VAR
form: DecForm;
aPtr: Ptr;
saneDecimal: decimal;
saneEnvironment: Environment;
integerDigit: integer;
BEGIN
GetEnvironment(saneEnvironment);
{ clear all flags and halt but preserve rounding direction and precision }
SetEnvironment(BAnd(saneEnvironment, $6060));
WITH form DO
BEGIN
style := floatDecimal;
digits := precisionDigits;
END;
{ we first convert to immediate form so we can find out number of decimal places needed }
Num2Dec(form, anExtended, saneDecimal);
WITH saneDecimal DO
BEGIN
{ we elminiate trailing zeroes, adjusting exp at the same time }
aPtr := Ptr(ord(@sig) + length(sig));
WHILE (aPtr^ = ord('0')) DO
BEGIN
exp := exp + 1;
aPtr := Ptr(ord(aPtr) - 1);
END;
{ now we know number of significant digits, use it if it is floating point }
form.digits := ord(aPtr) - ord(@sig);
{ integerDigit is the number of digits in the integer part }
integerDigit := exp + form.digits;
IF exp < 0 THEN
BEGIN { we have some digits after decimal point, so it cannot be too large }
IF integerDigit >= - 5 THEN
BEGIN { but we still need to do floating point if it is less than 1e-6 }
form.style := FixedDecimal;
form.digits := - exp;
END;
END
ELSE
BEGIN { no digit after decimal point, digits = 0 if in fixed point }
IF integerDigit <= precisionDigits THEN
BEGIN { use fixed point only if number is not too large }
form.style := FixedDecimal;
form.digits := 0;
END;
END;
END;
Num2Str(form, anExtended, DecStr(aStr));
SetEnvironment(saneEnvironment); { restore original state }
END;
{--------------------------------------------------------------------------------}
{ This is the built in coercion routine }
FUNCTION StdCoercion(fromType: DescType;
dataPtr: Ptr;
dataSize: LONGINT;
toType: DescType;
VAR result: AEDesc): OSErr;
VAR
err: OSErr;
anUnivNum: UnivNum;
canDo: boolean;
anExtended: Extended;
rstDataSize: Integer;
rstDataPtr: Ptr;
aStr: Str255;
precisionDigits: Integer;
BEGIN
err := errAECoercionFail;
result.descriptorType := toType;
IF LONGINT(toType) = LONGINT(fromType) THEN
err := AE_CreateDesc(toType, dataPtr, dataSize, result) { just create it }
ELSE IF LONGINT(toType) = LONGINT(typeAEList) THEN
BEGIN { make a list of one element }
err := CreateList(NIL, 0, FALSE, result, DescType(0));
IF err = noErr THEN
BEGIN
err := AE_PutPtr(result, 0, fromType, dataPtr, dataSize);
IF err <> noErr THEN IgnoreOSErr(AE_DisposeDesc(result));
END;
END
ELSE IF LONGINT(toType) = LONGINT(typeAERecord) THEN
BEGIN
IF CheckIsRecord(dataPtr, dataSize) THEN
BEGIN { check to make sure this is really a record }
err := AE_CreateDesc(toType, dataPtr, dataSize, result);
IF err = NoErr THEN
ListHdrHdl(result.dataHandle)^^.listClassHeader.metaCountOrObjType := LONGINT(fromType);
END;
END
ELSE
BEGIN { we always do PtrToHand for the following coercions }
canDo := FALSE;
rstDataPtr := @anUnivNum; { most likely value }
rstDataSize := 4; { most like value }
IF (LONGINT(toType) = LONGINT(typeChar)) THEN
BEGIN
aStr[0] := chr(0); { empty string }
IF (LONGINT(fromType)) = LONGINT(typeShortInteger) THEN
NumToString(IntegerPtr(dataPtr)^, aStr)
ELSE IF (LONGINT(fromType)) = LONGINT(typeLongInteger) THEN
NumToString(LONGINTPtr(dataPtr)^, aStr)
ELSE IF DescToExtd(fromType, dataPtr, dataSize, precisionDigits, anExtended) THEN
ExtdToText(precisionDigits, anExtended, aStr); { make an extended to text string
}
rstDataSize := length(aStr);
IF rstDataSize > 0 THEN
BEGIN
canDo := TRUE;
rstDataPtr := @aStr[1];
END;
END
ELSE IF (LONGINT(toType) = LONGINT(typeBoolean)) THEN
BEGIN
IF BooleanType(fromType, dataPtr, anUnivNum.asInteger) THEN { is this a kind of
boolean ? }
BEGIN
canDo := TRUE;
rstDataPtr := Ptr(ord(@anUnivNum) + 1);
rstDataSize := 1;
END;
END
ELSE IF LONGINT(toType) = LONGINT(typeShortInteger) THEN
BEGIN
rstDataSize := SizeOf(Integer);
IF LONGINT(fromType) = LONGINT(typeLongInteger) THEN
BEGIN { long to short is done often, so we special case it }
IF LONGINTPtr(dataPtr)^ >= - (MAXINT + 1) THEN
IF LONGINTPtr(dataPtr)^ <= MAXINT THEN
BEGIN { it is within range }
anUnivNum.asInteger := LONGINTPtr(dataPtr)^;
canDo := TRUE;
END;
END
ELSE IF BooleanType(fromType, dataPtr, anUnivNum.asInteger) THEN
canDo := TRUE { it is a basic boolean type }
ELSE { convert to extended and back }
BEGIN
IF DescToExtd(fromType, dataPtr, dataSize, precisionDigits, anExtended) THEN
canDo := ExtdToNum(anExtended, toType, anUnivNum)
END;
END
ELSE IF LONGINT(toType) = LONGINT(typeLongInteger) THEN
BEGIN
{ rstDataSize := SizeOf(LONGINT); not needed since it is same as 4 }
IF LONGINT(fromType) = LONGINT(typeMagnitude) THEN
BEGIN
anUnivNum.asLongint := LONGINTPtr(dataPtr)^;
IF anUnivNum.asLongint >= 0 THEN canDo := TRUE;
END
ELSE IF LONGINT(fromType) = LONGINT(typeShortInteger) THEN
BEGIN
anUnivNum.asLongint := IntegerPtr(dataPtr)^;
canDo := TRUE;
END
ELSE { convert to extended and back }
BEGIN
IF DescToExtd(fromType, dataPtr, dataSize, precisionDigits, anExtended) THEN
canDo := ExtdToNum(anExtended, toType, anUnivNum)
END;
END
ELSE IF (LONGINT(toType) = LONGINT(typeMagnitude)) OR (LONGINT(toType) =
LONGINT(typeComp)) OR (LONGINT(toType) = LONGINT(typeShortFloat)) OR
(LONGINT(toType) = LONGINT(typeLongFloat)) THEN
BEGIN
IF DescToExtd(fromType, dataPtr, dataSize, precisionDigits, anExtended) THEN
BEGIN
canDo := ExtdToNum(anExtended, toType, anUnivNum);
{ IF LONGINT(toType) = LONGINT(typeMagnitude) THEN rstDataSize := 4 not needed since it is same as 4 }
IF LONGINT(toType) = LONGINT(typeComp) THEN
rstDataSize := SizeOf(Comp)
ELSE IF LONGINT(toType) = LONGINT(typeLongFloat) THEN
rstDataSize := SizeOf(Double);
{ IF LONGINT(toType) = LONGINT(typeMagnitude) THEN rstDataSize := SizeOf(LONGINT) not needed since it is same as 4 }
{ IF LONGINT(toType) = LONGINT(typeShortFloat) THEN rstDataSize := SizeOf(Real) not needed since it is same as 4 }
END;
END
ELSE IF LONGINT(toType) = LONGINT(typeExtended) THEN
BEGIN
IF DescToExtd(fromType, dataPtr, dataSize, precisionDigits,
anUnivNum.asExtended) THEN
BEGIN
canDo := TRUE;
rstDataSize := SizeOf(Extended);
END;
END
ELSE IF LONGINT(toType) = LONGINT(typeEnumerated) THEN
BEGIN
{ rstDataSize := SizeOf(ResType); not needed since it is same as 4 }
IF BooleanType(fromType, dataPtr, anUnivNum.asInteger) THEN
BEGIN
canDo := TRUE;
IF anUnivNum.asInteger = 0 THEN
anUnivNum.asResType := typeFalse
ELSE
anUnivNum.asResType := typeTrue;
END;
END
ELSE IF LONGINT(toType) = LONGINT(typeSectionH) THEN
BEGIN
IF LONGINT(fromType) = LONGINT('tid ') THEN
IF dataSize = 8 THEN { must be 8 byte for sect record }
IF LONGINTPtr(dataPtr)^ = LONGINT(typeSectionH) THEN { first 4 byte must be
'sect' }
BEGIN
canDo := TRUE;
{ rstDataSize := 4; not needed since it is same as 4 }
rstDataPtr := Ptr(ORD(dataPtr) + 4);
END;
END;
IF canDo THEN err := PtrToHand(rstDataPtr, result.dataHandle, rstDataSize);
END;
StdCoercion := err;
END;
{--------------------------------------------------------------------------------}