[Runtime] Optimized 2 functions

[Runtime] Optimized 2 functions

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System.Text
USING System.Globalization
USING System.Collections.Generic
USING System.Reflection

INTERNAL STATIC CLASS XSharp.ConversionHelpers
    STATIC INTERNAL usCulture AS CultureInfo
    STATIC CONSTRUCTOR
        usCulture := CultureInfo{"en-US"}
END CLASS

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2dw/*" />
FUNCTION Bin2DW(cUnsignedInt AS STRING) AS DWORD
    LOCAL dwResult := 0 AS DWORD
    IF cUnsignedInt!= NULL .AND. cUnsignedInt:Length >= 4
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{4}
        aBytes[0] := (BYTE) _AND(cUnsignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cUnsignedInt:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cUnsignedInt:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cUnsignedInt:Chars[3], 0xFF)
        dwResult := BitConverter.ToUInt32(aBytes, 0)
    ENDIF
    RETURN dwResult

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2i/*" />
FUNCTION Bin2I(cSignedInt AS STRING) AS SHORT
    LOCAL siResult := 0 AS SHORT
    IF cSignedInt!= NULL .AND. cSignedInt:Length >= 2
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{2}
        aBytes[0] := (BYTE) _AND(cSignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cSignedInt:Chars[1], 0xFF)
        siResult := BitConverter.ToInt16(aBytes, 0)
    ENDIF
    RETURN siResult

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2l/*" />
FUNCTION Bin2L(cSignedInt AS STRING) AS LONG
    LOCAL liResult := 0 AS LONG
    IF cSignedInt!= NULL .AND. cSignedInt:Length >= 4
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{4}
        aBytes[0] := (BYTE) _AND(cSignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cSignedInt:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cSignedInt:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cSignedInt:Chars[3], 0xFF)
        liResult := BitConverter.ToInt32(aBytes, 0)
    ENDIF
    RETURN liResult

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2logic/*" />
FUNCTION Bin2Logic(pszLogical AS STRING) AS LOGIC
    RETURN pszLogical != NULL .AND. pszLogical[0] != 0

///
/// Convert a intptr to a string
///
/// <include file="CoreComments.xml" path="Comments/PtrBin/*" />
/// <seealso cref='Bin2Ptr' >Bin2Ptr</seealso>
FUNCTION Ptr2Bin(p AS IntPtr) AS STRING
    IF IntPtr.Size == 4
        RETURN L2Bin( p:ToInt32())
    ELSE
        THROW NotSupportedException{}
    ENDIF

///
///
/// <param name="cPointer"></param>
/// <include file="CoreComments.xml" path="Comments/PtrBin/*" />
/// <seealso cref='Ptr2Bin' >Ptr2Bin</seealso>
FUNCTION Bin2Ptr(cPointer AS STRING) AS IntPtr
    IF IntPtr.Size == 4
        RETURN (IntPtr) Bin2L(cPointer)
    ELSE
        THROW NotSupportedException{}
    ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2real4/*" />
FUNCTION Bin2Real4(cFloat AS STRING) AS REAL4
    LOCAL r4Result := 0 AS REAL4
    IF cFloat!= NULL .AND. cFloat:Length >= 4
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{4}
        aBytes[0] := (BYTE) _AND(cFloat:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cFloat:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cFloat:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cFloat:Chars[3], 0xFF)
        r4Result := BitConverter.ToSingle(aBytes, 0)
    ENDIF
    RETURN r4Result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2real8/*" />
FUNCTION Bin2Real8(cFloat AS STRING) AS REAL8
    LOCAL r8Result := 0 AS REAL8
    IF cFloat!= NULL .AND. cFloat:Length >= 8
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{8}
        aBytes[0] := (BYTE) _AND(cFloat:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cFloat:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cFloat:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cFloat:Chars[3], 0xFF)
        aBytes[4] := (BYTE) _AND(cFloat:Chars[4], 0xFF)
        aBytes[5] := (BYTE) _AND(cFloat:Chars[5], 0xFF)
        aBytes[6] := (BYTE) _AND(cFloat:Chars[6], 0xFF)
        aBytes[7] := (BYTE) _AND(cFloat:Chars[7], 0xFF)
        r8Result := BitConverter.ToDouble(aBytes, 0)
    ENDIF
    RETURN r8Result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2w/*" />
FUNCTION Bin2W(cUnsignedInt AS STRING) AS WORD
    LOCAL wResult := 0 AS WORD
    IF cUnsignedInt!= NULL .AND. cUnsignedInt:Length >= 2
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{2}
        aBytes[0] := (BYTE) _AND(cUnsignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cUnsignedInt:Chars[1], 0xFF)
        wResult := BitConverter.ToUInt16(aBytes, 0)
    ENDIF
    RETURN wResult

///
/// Convert a string value to a logic.
///
/// <param name="c"></param>
/// <returns>
/// </returns>
/// <seealso cref='LTOC' >LTOC</seealso>
/// <seealso cref='Logic2Bin' >Logic2Bin</seealso>

FUNCTION CTOL(c AS STRING) AS LOGIC
    IF c != NULL
        IF c[0] == 'T' .OR. c[0] == 't' .OR. c[0] == 'Y' .OR. c[0] =='y'
            RETURN TRUE
        ENDIF
    ENDIF
    RETURN FALSE

/// Convert a string value to a hexadecimal string.
/// <param name="cSource">String to convert</param>
/// <param name="lAddSpace">When TRUE then the inidividual characters are separated with a space in the result string</param>
/// <returns>A string with the hex representation of the value</returns>
/// <example>
///  ? _C2Hex("abcdef", TRUE)                // 61 62 63 64 65 66

///  ? _C2Hex("abcdef", FALSE)               // 616263646566

/// </example>
/// <seealso cref='M:XSharp.RT.Functions.AsHexString(XSharp.__Usual)' >AsHexString</seealso>
/// <seealso cref='C2Hex' >C2Hex</seealso>
FUNCTION _C2Hex(cSource AS STRING, lAddSpace as LOGIC) AS STRING
    LOCAL sb AS StringBuilder
    sb := StringBuilder{cSource:Length*2}
    FOREACH c AS CHAR IN cSource
        IF sb:Length > 0 .and. lAddSpace
            sb:Append(' ')
        ENDIF
        var s := String.Format("{0:X2}",(INT) c)
        sb:Append(s)
    NEXT
    RETURN sb:ToString()

/// Convert a string value to a hexadecimal string.
/// <param name="cSource">String to convert</param>
/// <returns>A string with the hex representation of the value</returns>
/// <example>
///  ? C2Hex("abcdef")               // 616263646566

/// </example>
/// <seealso cref='M:XSharp.RT.Functions.AsHexString(XSharp.__Usual)' >AsHexString</seealso>
/// <seealso cref='_C2Hex' >_C2Hex</seealso>
FUNCTION C2Hex(cSource AS STRING) AS STRING
    RETURN _C2Hex(cSource, FALSE)

// helper function to convert bytes to string

INTERNAL FUNCTION _bytes2String(byteArray AS BYTE[]) AS STRING
    LOCAL sb AS StringBuilder
    sb := StringBuilder{}
    FOREACH VAR b IN byteArray
        sb:Append( (CHAR) b)
    NEXT
    RETURN sb:ToString()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dw2bin/*" />
FUNCTION DW2Bin(dwValue AS DWORD) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( dwValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/hibyte/*" />
FUNCTION HiByte(wValue AS WORD) AS BYTE
    RETURN (BYTE) (wValue >> 8)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/hiword/*" />
FUNCTION HiWord(dwValue AS DWORD) AS WORD
    RETURN (WORD) (dwValue >> 16)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/i2bin/*" />
/// <seealso cref='Bin2I' >Bin2I</seealso>
FUNCTION I2Bin(siValue AS SHORT) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( siValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/l2bin/*" />
FUNCTION L2Bin(liValue AS LONG) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( liValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/lobyte/*" />
FUNCTION LoByte(wValue AS WORD) AS BYTE
    RETURN (BYTE) _AND(wValue, 0x00FF)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/loword/*" />
FUNCTION LoWord(dwValue AS DWORD) AS WORD
    RETURN (WORD) _AND(dwValue , 0xFFFF)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/logic2bin/*" />
FUNCTION Logic2Bin(lValue AS LOGIC) AS STRING
    IF lValue
        RETURN e"\x0001"
    ELSE
        RETURN e"\x0000"
    ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ltoc/*" />
FUNCTION LTOC(lValue AS LOGIC) AS STRING
    IF lValue
        RETURN "T"
    ELSE
        RETURN "F"
    ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/real42bin/*" />
FUNCTION Real42Bin(r4Value AS REAL4) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( r4Value ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/real82bin/*" />
FUNCTION Real82Bin(r8Value AS REAL8) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( r8Value ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/w2bin/*" />
FUNCTION W2Bin(wValue AS WORD) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( wValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/val/*" />
FUNCTION _Val(cNumber AS STRING) AS OBJECT
    IF String.IsNullOrEmpty(cNumber)
      RETURN 0
    ENDIF
    cNumber := cNumber:Trim():ToUpper()
    // find non numeric characters in cNumber and trim the field to that length
    VAR pos := 0
    VAR done := FALSE
    VAR hex  := FALSE
    VAR hasdec := FALSE
    VAR hasexp := FALSE
    VAR cDec := (CHAR) RuntimeState.DecimalSep

    IF cDec != '.'
        cNumber := cNumber:Replace('.', cDec) // VO behavior...
        cNumber := cNumber:Replace(cDec, '.')
    ENDIF
    FOREACH VAR c IN cNumber
        SWITCH c
        CASE '0'
        CASE '1'
        CASE '2'
        CASE '3'
        CASE '4'
        CASE '5'
        CASE '6'
        CASE '7'
        CASE '8'
        CASE '9'
        CASE '-'
        CASE '+'
            NOP
        CASE '.'
        CASE ','
            IF c == ',' .AND. cDec != ',' // Don't ask, VO...
                done := TRUE
            ELSEIF hasdec
                done := TRUE
            ELSE
                hasdec := TRUE
            ENDIF
        CASE 'A'
        CASE 'B'
        CASE 'C'
        CASE 'D'
        CASE 'F'
            IF !hex
                done := TRUE
            ENDIF
        CASE 'E'
            // exponentional notation only allowed if decimal separator was there
            IF hasdec
                hasexp := TRUE
            ELSE
                IF !hex
                    done := TRUE
                ENDIF
            ENDIF
        CASE 'L'	// LONG result
        CASE 'U'	// DWORD result
            done := TRUE
        CASE 'X'
            IF pos == 1
                hex := TRUE
            ELSE
                done := TRUE
            ENDIF
        OTHERWISE
            done := TRUE
        END SWITCH
        IF done
            EXIT
        ENDIF
        pos += 1
    NEXT
    IF pos < cNumber:Length
        cNumber := cNumber:Substring(0, pos)
    ENDIF
    IF cNumber:IndexOfAny(<CHAR> {'.'}) > -1
        LOCAL r8Result := 0 AS REAL8
        IF cDec != '.'
            cNumber := cNumber:Replace(cDec, '.')
        ENDIF
        VAR style := NumberStyles.Number
        IF hasexp
            style |= NumberStyles.AllowExponent
        ENDIF
        IF System.Double.TryParse(cNumber, style, ConversionHelpers.usCulture, OUT r8Result)
            RETURN r8Result
        ENDIF
    ELSE
        LOCAL iResult := 0 AS INT64
        LOCAL style AS NumberStyles
        IF hex
            cNumber := cNumber:Substring(2)
            style := NumberStyles.HexNumber
        ELSE
            style := NumberStyles.Integer
        ENDIF
        IF System.Int64.TryParse(cNumber, style, ConversionHelpers.usCulture, OUT iResult)
            IF iResult < Int32.MaxValue .AND. iResult > Int32.MinValue
                RETURN (INT) iResult
            ENDIF
            RETURN iResult
        ENDIF
    ENDIF
    RETURN 0

FUNCTION GetPartialEnumName(cName as STRING, oType as System.Type) AS STRING
    LOCAL aFields   := oType:GetFields() AS FieldInfo[]
    LOCAL aNames    := List<STRING>{} AS List<STRING>
    FOREACH VAR oFld IN aFields
        IF oFld:IsLiteral .AND. oFld:Name:StartsWith(cName, StringComparison.OrdinalIgnoreCase)
            aNames:Add(oFld:Name)
        ENDIF
    NEXT
    IF aNames:Count == 1
        cName := aNames[0]
    ELSE
        cName := ""
    ENDIF
    RETURN cName

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System.Text
USING System.Globalization
USING System.Collections.Generic
USING System.Reflection

INTERNAL STATIC CLASS XSharp.ConversionHelpers
    STATIC INTERNAL usCulture AS CultureInfo
    STATIC CONSTRUCTOR
        usCulture := CultureInfo{"en-US"}
END CLASS

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2dw/*" />
FUNCTION Bin2DW(cUnsignedInt AS STRING) AS DWORD
    LOCAL dwResult := 0 AS DWORD
    IF cUnsignedInt!= NULL .AND. cUnsignedInt:Length >= 4
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{4}
        aBytes[0] := (BYTE) _AND(cUnsignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cUnsignedInt:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cUnsignedInt:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cUnsignedInt:Chars[3], 0xFF)
        dwResult := BitConverter.ToUInt32(aBytes, 0)
    ENDIF
    RETURN dwResult

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2i/*" />
FUNCTION Bin2I(cSignedInt AS STRING) AS SHORT
    LOCAL siResult := 0 AS SHORT
    IF cSignedInt!= NULL .AND. cSignedInt:Length >= 2
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{2}
        aBytes[0] := (BYTE) _AND(cSignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cSignedInt:Chars[1], 0xFF)
        siResult := BitConverter.ToInt16(aBytes, 0)
    ENDIF
    RETURN siResult

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2l/*" />
FUNCTION Bin2L(cSignedInt AS STRING) AS LONG
    LOCAL liResult := 0 AS LONG
    IF cSignedInt!= NULL .AND. cSignedInt:Length >= 4
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{4}
        aBytes[0] := (BYTE) _AND(cSignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cSignedInt:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cSignedInt:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cSignedInt:Chars[3], 0xFF)
        liResult := BitConverter.ToInt32(aBytes, 0)
    ENDIF
    RETURN liResult

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2logic/*" />
FUNCTION Bin2Logic(pszLogical AS STRING) AS LOGIC
    RETURN pszLogical != NULL .AND. pszLogical[0] != 0

///
/// Convert a intptr to a string
///
/// <include file="CoreComments.xml" path="Comments/PtrBin/*" />
/// <seealso cref='Bin2Ptr' >Bin2Ptr</seealso>
FUNCTION Ptr2Bin(p AS IntPtr) AS STRING
    IF IntPtr.Size == 4
        RETURN L2Bin( p:ToInt32())
    ELSE
        THROW NotSupportedException{}
    ENDIF

///
///
/// <param name="cPointer"></param>
/// <include file="CoreComments.xml" path="Comments/PtrBin/*" />
/// <seealso cref='Ptr2Bin' >Ptr2Bin</seealso>
FUNCTION Bin2Ptr(cPointer AS STRING) AS IntPtr
    IF IntPtr.Size == 4
        RETURN (IntPtr) Bin2L(cPointer)
    ELSE
        THROW NotSupportedException{}
    ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2real4/*" />
FUNCTION Bin2Real4(cFloat AS STRING) AS REAL4
    LOCAL r4Result := 0 AS REAL4
    IF cFloat!= NULL .AND. cFloat:Length >= 4
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{4}
        aBytes[0] := (BYTE) _AND(cFloat:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cFloat:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cFloat:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cFloat:Chars[3], 0xFF)
        r4Result := BitConverter.ToSingle(aBytes, 0)
    ENDIF
    RETURN r4Result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2real8/*" />
FUNCTION Bin2Real8(cFloat AS STRING) AS REAL8
    LOCAL r8Result := 0 AS REAL8
    IF cFloat!= NULL .AND. cFloat:Length >= 8
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{8}
        aBytes[0] := (BYTE) _AND(cFloat:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cFloat:Chars[1], 0xFF)
        aBytes[2] := (BYTE) _AND(cFloat:Chars[2], 0xFF)
        aBytes[3] := (BYTE) _AND(cFloat:Chars[3], 0xFF)
        aBytes[4] := (BYTE) _AND(cFloat:Chars[4], 0xFF)
        aBytes[5] := (BYTE) _AND(cFloat:Chars[5], 0xFF)
        aBytes[6] := (BYTE) _AND(cFloat:Chars[6], 0xFF)
        aBytes[7] := (BYTE) _AND(cFloat:Chars[7], 0xFF)
        r8Result := BitConverter.ToDouble(aBytes, 0)
    ENDIF
    RETURN r8Result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/bin2w/*" />
FUNCTION Bin2W(cUnsignedInt AS STRING) AS WORD
    LOCAL wResult := 0 AS WORD
    IF cUnsignedInt!= NULL .AND. cUnsignedInt:Length >= 2
        LOCAL aBytes AS BYTE[]
        aBytes := BYTE[]{2}
        aBytes[0] := (BYTE) _AND(cUnsignedInt:Chars[0], 0xFF)
        aBytes[1] := (BYTE) _AND(cUnsignedInt:Chars[1], 0xFF)
        wResult := BitConverter.ToUInt16(aBytes, 0)
    ENDIF
    RETURN wResult

///
/// Convert a string value to a logic.
///
/// <param name="c"></param>
/// <returns>
/// </returns>
/// <seealso cref='LTOC' >LTOC</seealso>
/// <seealso cref='Logic2Bin' >Logic2Bin</seealso>

FUNCTION CTOL(c AS STRING) AS LOGIC
    IF c != NULL
        IF c[0] == 'T' .OR. c[0] == 't' .OR. c[0] == 'Y' .OR. c[0] =='y'
            RETURN TRUE
        ENDIF
    ENDIF
    RETURN FALSE

/// Convert a string value to a hexadecimal string.
/// <param name="cSource">String to convert</param>
/// <param name="lAddSpace">When TRUE then the inidividual characters are separated with a space in the result string</param>
/// <returns>A string with the hex representation of the value</returns>
/// <example>
///  ? _C2Hex("abcdef", TRUE)                // 61 62 63 64 65 66

///  ? _C2Hex("abcdef", FALSE)               // 616263646566

/// </example>
/// <seealso cref='M:XSharp.RT.Functions.AsHexString(XSharp.__Usual)' >AsHexString</seealso>
/// <seealso cref='C2Hex' >C2Hex</seealso>
FUNCTION _C2Hex(cSource AS STRING, lAddSpace as LOGIC) AS STRING
    LOCAL sb AS StringBuilder
    sb := StringBuilder{cSource:Length*2}
    FOREACH c AS CHAR IN cSource
        IF sb:Length > 0 .and. lAddSpace
            sb:Append(' ')
        ENDIF
        var s := String.Format("{0:X2}",(INT) c)
        sb:Append(s)
    NEXT
    RETURN sb:ToString()

/// Convert a string value to a hexadecimal string.
/// <param name="cSource">String to convert</param>
/// <returns>A string with the hex representation of the value</returns>
/// <example>
///  ? C2Hex("abcdef")               // 616263646566

/// </example>
/// <seealso cref='M:XSharp.RT.Functions.AsHexString(XSharp.__Usual)' >AsHexString</seealso>
/// <seealso cref='_C2Hex' >_C2Hex</seealso>
FUNCTION C2Hex(cSource AS STRING) AS STRING
    RETURN _C2Hex(cSource, FALSE)

// helper function to convert bytes to string

INTERNAL FUNCTION _bytes2String(byteArray AS BYTE[]) AS STRING
    LOCAL sb AS StringBuilder
    sb := StringBuilder{}
    FOREACH VAR b IN byteArray
        sb:Append( (CHAR) b)
    NEXT
    RETURN sb:ToString()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/dw2bin/*" />
FUNCTION DW2Bin(dwValue AS DWORD) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( dwValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/hibyte/*" />
FUNCTION HiByte(wValue AS WORD) AS BYTE
    LOCAL upper := Convert.ToByte(wValue >> 8) AS BYTE
    RETURN (BYTE) upper

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/hiword/*" />
FUNCTION HiWord(dwValue AS DWORD) AS WORD
    LOCAL upper := Convert.ToUInt16(dwValue >> 16) AS WORD
    RETURN (WORD) upper

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/i2bin/*" />
/// <seealso cref='Bin2I' >Bin2I</seealso>
FUNCTION I2Bin(siValue AS SHORT) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( siValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/l2bin/*" />
FUNCTION L2Bin(liValue AS LONG) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( liValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/lobyte/*" />
FUNCTION LoByte(wValue AS WORD) AS BYTE
    RETURN (BYTE) (wValue & 0x00FF)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/loword/*" />
FUNCTION LoWord(dwValue AS DWORD) AS WORD
    RETURN (WORD) (dwValue & 0xFFFF)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/logic2bin/*" />
FUNCTION Logic2Bin(lValue AS LOGIC) AS STRING
    IF lValue
        RETURN e"\x0001"
    ELSE
        RETURN e"\x0000"
    ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ltoc/*" />
FUNCTION LTOC(lValue AS LOGIC) AS STRING
    IF lValue
        RETURN "T"
    ELSE
        RETURN "F"
    ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/real42bin/*" />
FUNCTION Real42Bin(r4Value AS REAL4) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( r4Value ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/real82bin/*" />
FUNCTION Real82Bin(r8Value AS REAL8) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( r8Value ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/w2bin/*" />
FUNCTION W2Bin(wValue AS WORD) AS STRING
    LOCAL byteArray := BitConverter.GetBytes( wValue ) AS BYTE[]
    RETURN _bytes2String(byteArray)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/val/*" />
FUNCTION _Val(cNumber AS STRING) AS OBJECT
    IF String.IsNullOrEmpty(cNumber)
      RETURN 0
    ENDIF
    cNumber := cNumber:Trim():ToUpper()
    // find non numeric characters in cNumber and trim the field to that length
    VAR pos := 0
    VAR done := FALSE
    VAR hex  := FALSE
    VAR hasdec := FALSE
    VAR hasexp := FALSE
    VAR cDec := (CHAR) RuntimeState.DecimalSep

    IF cDec != '.'
        cNumber := cNumber:Replace('.', cDec) // VO behavior...
        cNumber := cNumber:Replace(cDec, '.')
    ENDIF
    FOREACH VAR c IN cNumber
        SWITCH c
        CASE '0'
        CASE '1'
        CASE '2'
        CASE '3'
        CASE '4'
        CASE '5'
        CASE '6'
        CASE '7'
        CASE '8'
        CASE '9'
        CASE '-'
        CASE '+'
            NOP
        CASE '.'
        CASE ','
            IF c == ',' .AND. cDec != ',' // Don't ask, VO...
                done := TRUE
            ELSEIF hasdec
                done := TRUE
            ELSE
                hasdec := TRUE
            ENDIF
        CASE 'A'
        CASE 'B'
        CASE 'C'
        CASE 'D'
        CASE 'F'
            IF !hex
                done := TRUE
            ENDIF
        CASE 'E'
            // exponentional notation only allowed if decimal separator was there
            IF hasdec
                hasexp := TRUE
            ELSE
                IF !hex
                    done := TRUE
                ENDIF
            ENDIF
        CASE 'L'	// LONG result
        CASE 'U'	// DWORD result
            done := TRUE
        CASE 'X'
            IF pos == 1
                hex := TRUE
            ELSE
                done := TRUE
            ENDIF
        OTHERWISE
            done := TRUE
        END SWITCH
        IF done
            EXIT
        ENDIF
        pos += 1
    NEXT
    IF pos < cNumber:Length
        cNumber := cNumber:Substring(0, pos)
    ENDIF
    IF cNumber:IndexOfAny(<CHAR> {'.'}) > -1
        LOCAL r8Result := 0 AS REAL8
        IF cDec != '.'
            cNumber := cNumber:Replace(cDec, '.')
        ENDIF
        VAR style := NumberStyles.Number
        IF hasexp
            style |= NumberStyles.AllowExponent
        ENDIF
        IF System.Double.TryParse(cNumber, style, ConversionHelpers.usCulture, OUT r8Result)
            RETURN r8Result
        ENDIF
    ELSE
        LOCAL iResult := 0 AS INT64
        LOCAL style AS NumberStyles
        IF hex
            cNumber := cNumber:Substring(2)
            style := NumberStyles.HexNumber
        ELSE
            style := NumberStyles.Integer
        ENDIF
        IF System.Int64.TryParse(cNumber, style, ConversionHelpers.usCulture, OUT iResult)
            IF iResult < Int32.MaxValue .AND. iResult > Int32.MinValue
                RETURN (INT) iResult
            ENDIF
            RETURN iResult
        ENDIF
    ENDIF
    RETURN 0

FUNCTION GetPartialEnumName(cName as STRING, oType as System.Type) AS STRING
    LOCAL aFields   := oType:GetFields() AS FieldInfo[]
    LOCAL aNames    := List<STRING>{} AS List<STRING>
    FOREACH VAR oFld IN aFields
        IF oFld:IsLiteral .AND. oFld:Name:StartsWith(cName, StringComparison.OrdinalIgnoreCase)
            aNames:Add(oFld:Name)
        ENDIF
    NEXT
    IF aNames:Count == 1
        cName := aNames[0]
    ELSE
        cName := ""
    ENDIF
    RETURN cName


Correction so PROPERTY's prototype don't have final ()

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System
USING System.Text
USING System.Linq
USING System.Collections.Generic

BEGIN NAMESPACE XSharpModel

   STATIC CLASS TypeMemberExtensions

      STATIC METHOD ClipperParameters(SELF tm as IXMemberSymbol) AS STRING
          IF tm:Kind:HasParameters()
                VAR names := StringBuilder{}
                FOREACH var param in tm:Parameters
                    if names:Length > 0
                        names:Append(", ")
                    endif
                    names:Append(param:Name)
                NEXT
                return names:ToString()
          ENDIF
          RETURN ""

      STATIC METHOD GetProtoType(SELF tm as IXMemberSymbol, lApplyCallingConvention := FALSE AS LOGIC) AS STRING
         VAR vars := StringBuilder{}
         IF tm:TypeParameters?:Count > 0
            VAR delim := "<"
            FOREACH VAR typeParam IN tm:TypeParameters
               vars:Append(delim)
               delim := ","
               vars:Append(typeParam)
            NEXT
            vars:Append(">")
         ENDIF
         IF tm:Kind:HasParameters()
            IF ( tm:Kind == Kind.@@Constructor )
               vars:Append("{")
               if lApplyCallingConvention .and. tm:CallingConvention == CallingConvention.Clipper
                  vars:Append(tm:ClipperParameters())
               else
                  vars:Append(tm:ParameterList)
               endif
               vars:Append("}")
            ELSE
               IF ( !tm:Kind:IsProperty() )
                  vars:Append("(")
                  if lApplyCallingConvention .and. tm:CallingConvention == CallingConvention.Clipper
                    vars:Append(tm:ClipperParameters())
                  else
                    vars:Append(tm:ParameterList)
                  endif
                  vars:Append(")")
               ENDIF
            ENDIF
         ENDIF
         IF tm:Kind == Kind.VODefine .OR. tm:Kind == Kind.EnumMember
            vars:Append(" "+tm:Value)
         ENDIF

         IF ( tm:Kind == Kind.@@Constructor )
            // System.Exception{params}
            vars:Insert(0, tm:DeclaringType )
          ELSE
            // Compare(params)
            vars:Insert(0, tm:Name )
         ENDIF
         IF (tm:Kind != Kind.@@Constructor)
            vars:Append(XLiterals.AsKeyWord)
            vars:Append(tm:TypeName:GetXSharpTypeName())
         ENDIF

         RETURN vars:ToString()

      STATIC METHOD GetDescription(SELF tm AS IXMemberSymbol) AS STRING
         VAR desc := tm:ModVis
         IF ( tm:IsStatic )
            desc += "STATIC "
         ENDIF
         IF (tm:Kind != Kind.Field)
            desc := desc + tm:Kind:ToDisplayString()
            IF (tm:Kind == Kind.VODefine)
               RETURN desc + tm:Name
            ENDIF
         ENDIF
         RETURN desc + " "+tm:GetProtoType()

      STATIC METHOD GetFullName(SELF tm as IXMemberSymbol) AS STRING
         IF (tm:Parent != NULL)
            RETURN tm:Parent:FullName +"." + tm:Name
         ENDIF
         RETURN tm:Name

      STATIC METHOD GetOverloads(SELF tm as IXMemberSymbol) AS IXMemberSymbol[]
         var result := List<IXMemberSymbol>{}
         IF tm:ParentType != NULL
            VAR overloads := tm:ParentType:GetMembers(tm.Name, TRUE)
            result:AddRange(overloads:Where( { x => x:IsStatic == tm:IsStatic}))
         ENDIF
         RETURN result:ToArray()

      STATIC METHOD GetXmlSignature(SELF tm as IXMemberSymbol) AS STRING
         local prefix as String
         local name   as String
         // todo: need to handle type parameters !
         name := tm:Name
         SWITCH tm:Kind
         CASE Kind.Method
         CASE Kind.Function
            prefix  := "M:"
         CASE Kind.Constructor
           prefix   := "M:"
            name     := "#ctor"
         CASE Kind.Destructor
            prefix   := "M:"
            name     := "Finalize"
         CASE Kind.Property
         CASE Kind.Access
         CASE Kind.Assign
            prefix  := "P:"
         CASE Kind.Event
            prefix  := "E:"
         CASE Kind.Field
            prefix  := "F:"
         OTHERWISE
            RETURN ""
         END SWITCH
         var sb := StringBuilder{}
         sb:Append(prefix)
         sb:Append(tm:ParentType:FullName)
         sb:Append("."+name)
         IF tm:TypeParameters:Count > 0
            sb:Append("``"+tm:TypeParameters:Count:ToString())
         ENDIF
         IF tm:Parameters:Count > 0
            sb:Append( "(")
            FOR var iParam := 0 to tm:Parameters:Count-1
               var param := tm:Parameters[iParam]
               IF iParam > 0
                  sb:Append(",")
               ENDIF
               IF param IS XPEParameterSymbol VAR xrefpar
                  // check if the original parameter contains a type reference
                  VAR typeName := xrefpar:OriginalTypeName
                  VAR result   := typeName
                  IF typeName:Contains("<")
                     VAR nPos := typeName:IndexOf("<")
                     result   := typeName:Substring(0, nPos)
                     typeName := typeName:Substring(nPos+1):Replace(">","")
                     nPos := result:IndexOf("`")
                     IF  nPos > 0
                        result := result:Substring(0, nPos)
                     ENDIF
                     VAR vars := typeName:Split(",":ToCharArray())
                     VAR delim := "{"
                     FOREACH VAR parName IN vars
                        result += delim
                        delim  := ","
                        nPos := tm:TypeParameters:IndexOf(parName)
                        IF nPos >= 0
                           result += "``"+nPos:ToString()
                        ELSE
                           result += parName
                        ENDIF
                     NEXT
                     result += "}"
                     sb:Append(result)
                  ELSE
                     VAR nPos := tm:TypeParameters:IndexOf(typeName)
                     IF nPos >= 0
                        sb:Append("``"+nPos:ToString())
                     ELSE
                        sb:Append(typeName)
                     ENDIF
                  ENDIF
               endif
            NEXT
            sb:Append(")")
         ENDIF
         sb:Replace('&','@')  // Ampersand is not allowed in the string
         RETURN sb:ToString()

        STATIC METHOD IsVisible(SELF tm AS IXMemberSymbol, Wanted AS Modifiers) AS LOGIC
            VAR vis := tm:Visibility
            IF vis >= Wanted
                RETURN TRUE
            ELSE
                SWITCH vis
                CASE Modifiers.ProtectedInternal
                CASE Modifiers.Internal
                    RETURN tm IS IXSourceSymbol
                OTHERWISE
                    RETURN FALSE
                END SWITCH
            ENDIF

        STATIC METHOD IsMethodVisibleInSubclass(SELF m as IXMemberSymbol) AS LOGIC
            IF m.Visibility > Modifiers.Private .and. m.Kind != Kind.Constructor
                if m:Name:Length > 4 .and. m:Kind == Kind.Method
                    SWITCH m:Name:Substring(0,4)
                    CASE "set_"
                    CASE "get_"
                    CASE "add_"
                        RETURN FALSE
                    CASE "remo"
                        RETURN ! m:Name:StartsWith("remove_")
                    END SWITCH
                endif
                RETURN TRUE
            ENDIF
            RETURN FALSE

   END CLASS
END NAMESPACE

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System
USING System.Text
USING System.Linq
USING System.Collections.Generic

BEGIN NAMESPACE XSharpModel

   STATIC CLASS TypeMemberExtensions

      STATIC METHOD ClipperParameters(SELF tm as IXMemberSymbol) AS STRING
          IF tm:Kind:HasParameters()
                VAR names := StringBuilder{}
                FOREACH var param in tm:Parameters
                    if names:Length > 0
                        names:Append(", ")
                    endif
                    names:Append(param:Name)
                NEXT
                return names:ToString()
          ENDIF
          RETURN ""

      STATIC METHOD GetProtoType(SELF tm as IXMemberSymbol, lApplyCallingConvention := FALSE AS LOGIC) AS STRING
         VAR vars := StringBuilder{}
         IF tm:TypeParameters?:Count > 0
            VAR delim := "<"
            FOREACH VAR typeParam IN tm:TypeParameters
               vars:Append(delim)
               delim := ","
               vars:Append(typeParam)
            NEXT
            vars:Append(">")
         ENDIF
         IF tm:Kind:HasParameters()
            IF ( tm:Kind == Kind.@@Constructor )
               vars:Append("{")
               if lApplyCallingConvention .and. tm:CallingConvention == CallingConvention.Clipper
                  vars:Append(tm:ClipperParameters())
               else
                  vars:Append(tm:ParameterList)
               endif
               vars:Append("}")
            ELSE
               vars:Append("(")
               if lApplyCallingConvention .and. tm:CallingConvention == CallingConvention.Clipper
                 vars:Append(tm:ClipperParameters())
               else
                 vars:Append(tm:ParameterList)
               endif
               vars:Append(")")
            ENDIF
         ENDIF
         IF tm:Kind == Kind.VODefine .OR. tm:Kind == Kind.EnumMember
            vars:Append(" "+tm:Value)
         ENDIF

         IF ( tm:Kind == Kind.@@Constructor )
            // System.Exception{params}
            vars:Insert(0, tm:DeclaringType )
          ELSE
            // Compare(params)
            vars:Insert(0, tm:Name )
         ENDIF
         IF (tm:Kind != Kind.@@Constructor)
            vars:Append(XLiterals.AsKeyWord)
            vars:Append(tm:TypeName:GetXSharpTypeName())
         ENDIF

         RETURN vars:ToString()

      STATIC METHOD GetDescription(SELF tm AS IXMemberSymbol) AS STRING
         VAR desc := tm:ModVis
         IF ( tm:IsStatic )
            desc += "STATIC "
         ENDIF
         IF (tm:Kind != Kind.Field)
            desc := desc + tm:Kind:ToDisplayString()
            IF (tm:Kind == Kind.VODefine)
               RETURN desc + tm:Name
            ENDIF
         ENDIF
         RETURN desc + " "+tm:GetProtoType()

      STATIC METHOD GetFullName(SELF tm as IXMemberSymbol) AS STRING
         IF (tm:Parent != NULL)
            RETURN tm:Parent:FullName +"." + tm:Name
         ENDIF
         RETURN tm:Name

      STATIC METHOD GetOverloads(SELF tm as IXMemberSymbol) AS IXMemberSymbol[]
         var result := List<IXMemberSymbol>{}
         IF tm:ParentType != NULL
            VAR overloads := tm:ParentType:GetMembers(tm.Name, TRUE)
            result:AddRange(overloads:Where( { x => x:IsStatic == tm:IsStatic}))
         ENDIF
         RETURN result:ToArray()

      STATIC METHOD GetXmlSignature(SELF tm as IXMemberSymbol) AS STRING
         local prefix as String
         local name   as String
         // todo: need to handle type parameters !
         name := tm:Name
         SWITCH tm:Kind
         CASE Kind.Method
         CASE Kind.Function
            prefix  := "M:"
         CASE Kind.Constructor
           prefix   := "M:"
            name     := "#ctor"
         CASE Kind.Destructor
            prefix   := "M:"
            name     := "Finalize"
         CASE Kind.Property
         CASE Kind.Access
         CASE Kind.Assign
            prefix  := "P:"
         CASE Kind.Event
            prefix  := "E:"
         CASE Kind.Field
            prefix  := "F:"
         OTHERWISE
            RETURN ""
         END SWITCH
         var sb := StringBuilder{}
         sb:Append(prefix)
         sb:Append(tm:ParentType:FullName)
         sb:Append("."+name)
         IF tm:TypeParameters:Count > 0
            sb:Append("``"+tm:TypeParameters:Count:ToString())
         ENDIF
         IF tm:Parameters:Count > 0
            sb:Append( "(")
            FOR var iParam := 0 to tm:Parameters:Count-1
               var param := tm:Parameters[iParam]
               IF iParam > 0
                  sb:Append(",")
               ENDIF
               IF param IS XPEParameterSymbol VAR xrefpar
                  // check if the original parameter contains a type reference
                  VAR typeName := xrefpar:OriginalTypeName
                  VAR result   := typeName
                  IF typeName:Contains("<")
                     VAR nPos := typeName:IndexOf("<")
                     result   := typeName:Substring(0, nPos)
                     typeName := typeName:Substring(nPos+1):Replace(">","")
                     nPos := result:IndexOf("`")
                     IF  nPos > 0
                        result := result:Substring(0, nPos)
                     ENDIF
                     VAR vars := typeName:Split(",":ToCharArray())
                     VAR delim := "{"
                     FOREACH VAR parName IN vars
                        result += delim
                        delim  := ","
                        nPos := tm:TypeParameters:IndexOf(parName)
                        IF nPos >= 0
                           result += "``"+nPos:ToString()
                        ELSE
                           result += parName
                        ENDIF
                     NEXT
                     result += "}"
                     sb:Append(result)
                  ELSE
                     VAR nPos := tm:TypeParameters:IndexOf(typeName)
                     IF nPos >= 0
                        sb:Append("``"+nPos:ToString())
                     ELSE
                        sb:Append(typeName)
                     ENDIF
                  ENDIF
               endif
            NEXT
            sb:Append(")")
         ENDIF
         sb:Replace('&','@')  // Ampersand is not allowed in the string
         RETURN sb:ToString()

        STATIC METHOD IsVisible(SELF tm AS IXMemberSymbol, Wanted AS Modifiers) AS LOGIC
            VAR vis := tm:Visibility
            IF vis >= Wanted
                RETURN TRUE
            ELSE
                SWITCH vis
                CASE Modifiers.ProtectedInternal
                CASE Modifiers.Internal
                    RETURN tm IS IXSourceSymbol
                OTHERWISE
                    RETURN FALSE
                END SWITCH
            ENDIF

        STATIC METHOD IsMethodVisibleInSubclass(SELF m as IXMemberSymbol) AS LOGIC
            IF m.Visibility > Modifiers.Private .and. m.Kind != Kind.Constructor
                if m:Name:Length > 4 .and. m:Kind == Kind.Method
                    SWITCH m:Name:Substring(0,4)
                    CASE "set_"
                    CASE "get_"
                    CASE "add_"
                        RETURN FALSE
                    CASE "remo"
                        RETURN ! m:Name:StartsWith("remove_")
                    END SWITCH
                endif
                RETURN TRUE
            ENDIF
            RETURN FALSE

   END CLASS
END NAMESPACE