USING Progress.Lang.*.

BLOCK-LEVEL ON ERROR UNDO, THROW.

CLASS task.HexUtils:
    METHOD PUBLIC STATIC CHARACTER intToHex(INPUT vInt AS INTEGER):
        IF vInt = 0 THEN RETURN "0".
        IF vInt = ? THEN RETURN "?".

        DEFINE VARIABLE hexDigits AS CHARACTER INITIAL "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F" NO-UNDO.
        DEFINE VARIABLE hexResult AS CHARACTER NO-UNDO.
        DEFINE VARIABLE r AS INTEGER NO-UNDO.
        DO WHILE vInt > 0:
            r = vInt MODULO 16.
            hexResult = ENTRY(r + 1, hexDigits) + hexResult.
            vInt = TRUNCATE(vInt / 16, 0).
        END.

        RETURN hexResult.
    END METHOD.

    METHOD PUBLIC STATIC CHARACTER rawToHex(INPUT ch AS RAW):
        DEFINE VARIABLE res AS CHARACTER INITIAL "" NO-UNDO.
        DEFINE VARIABLE i   AS INTEGER              NO-UNDO.

        IF LENGTH(ch, "RAW") = 0 THEN RETURN "0".

        DO i = 1 TO LENGTH(ch, "RAW"):
            res = res + intToHex(GET-BYTE(ch, i)) + "  ".
        END.

        RETURN TRIM(res).
    END METHOD.

    METHOD PUBLIC STATIC INTEGER rawToInt(INPUT rData AS RAW):
        DEFINE VARIABLE i       AS INTEGER NO-UNDO.
        DEFINE VARIABLE iByte   AS INTEGER NO-UNDO.
        DEFINE VARIABLE iResult AS INTEGER NO-UNDO.

        DO i = 1 TO LENGTH(rData, "RAW"):
            iByte = GET-BYTE(rData, i).

            // Shift the previous result left by 8 bits (multiply by 256)
            iResult = (iResult * 256) + iByte.
        END.

        RETURN iResult.
    END METHOD.

    METHOD PUBLIC STATIC VOID crossValidation(INPUT code     AS INTEGER,
                                              INPUT subject  AS INTEGER,
                                              INPUT sourceCp AS CHARACTER,
                                              INPUT targetCp AS CHARACTER):
        DEFINE VARIABLE result      AS INTEGER      NO-UNDO.
        DEFINE VARIABLE sourceChar  AS CHARACTER    NO-UNDO.

        // Get the encoding of the character <code> from the source code page
        sourceChar = CHR(code, sourceCp, sourceCp).

        // The case for the null byte
        IF LENGTH(sourceChar, "RAW") = 0 THEN result = 0.
        ELSE DO:
            result = ASC(sourceChar, targetCp, sourceCp).
        END.

        IF NOT subject = result THEN DO:
            MESSAGE "<========== WARNING: Cross-validation failed for the next line. ==========>".
            MESSAGE "Code:" code "; CHR result:" subject "; ASC result:" result "; Source cp:" sourceCp "; Target cp:" targetCp.
        END.
    END METHOD.
    // METHOD PUBLIC STATIC INTEGER findDecCodePoint(INPUT code AS INTEGER,
    //                                                 INPUT sourceCp AS CHARACTER,
    //                                                 INPUT targetCp AS CHARACTER):
    //     DEFINE VARIABLE res         AS INTEGER      NO-UNDO.
    //     DEFINE VARIABLE sourceChar  AS CHARACTER    NO-UNDO.

    //     // Find the character with the endpoint <code> from the source code page
    //     sourceChar = CHR(code, sourceCp, sourceCp).

    //     // The case for the null byte
    //     IF LENGTH(sourceChar, "RAW") = 0 THEN RETURN 0.

    //     // Get the convmap value
    //     res = ASC(sourceChar, targetCp, sourceCp).
    //     RETURN res.
    // END METHOD.

END CLASS.