Checksum creation with 4GL

Maviee

New Member
Hi there,

for a new project I need to create a crc32 or md5 checksum from a given file and save it back to the database. The last part is, of course, easy and not my problem.

I searched across the web and wasn't able to find a solution for my problem, as I don't want to use an external 3rd party DLL for this task (would have to register this dll on about 300 clients ...). So my question is, if you every accomplished the above task and if yes, how?

I'm thankful for every hint or help, so thanks in advance.

Greetings
André
 

RKR

Member
Hi there,

for a new project I need to create a crc32 or md5 checksum from a given file and save it back to the database. The last part is, of course, easy and not my problem.

I searched across the web and wasn't able to find a solution for my problem, as I don't want to use an external 3rd party DLL for this task (would have to register this dll on about 300 clients ...). So my question is, if you every accomplished the above task and if yes, how?

I'm thankful for every hint or help, so thanks in advance.

Greetings
André

Hello Andre,

If you are on openedge 10.1 or higher you can use the following example.

Code:
DEFINE VARIABLE mFileIn         AS MEMPTR       NO-UNDO.
DEFINE VARIABLE rCheckSum       AS RAW          NO-UNDO.
DEFINE VARIABLE cKey            AS CHARACTER    NO-UNDO.
 
/* Read your file into a memptr type variable */
COPY-LOB FROM FILE "c:\temp\test.txt" TO mFileIn.
 
/* Generate a 16-byte binary message digest value as a RAW value. */
rCheckSum = MD5-DIGEST(mFileIn,cKey).
 
/* rChecksum can then be assigned to a database field with datatype raw. */
 

Cecil

19+ years progress programming and still learning.
I know this might be a bit late coming but here is my version of the CRC-32 checksum function. I'm quite chuffed with it because it only took me about 51 minutes to write and it worked not the first time but the second time testing. I've compare the outputting results and it does compare with other CRC32 hashing utilities.

It help that I've built up my little section of BitWise operator functions so most of the hard work done for me. Enjoy.

Code:
FUNCTION BinaryXOR RETURNS INT64(INPUT intOperand1 AS INT64,
                                 INPUT intOperand2 AS INT64):

    DEFINE VARIABLE iByteLoop  AS INTEGER NO-UNDO.
    DEFINE VARIABLE iXOResult  AS INT64 NO-UNDO.
    DEFINE VARIABLE lFirstBit  AS LOGICAL NO-UNDO.
    DEFINE VARIABLE lSecondBit AS LOGICAL NO-UNDO.

    iXOResult = 0.

    /*spin through each byte of each char*/
    DO iByteLoop = 1 TO 64: /* as processing a double byte character */
        /*find state (true / false) of each integer's byte*/
        ASSIGN
        lFirstBit  = LOGICAL(GET-BITS(intOperand1,iByteLoop  ,1))
        lSecondBit = LOGICAL(GET-BITS(intOperand2,iByteLoop , 1)).

        /* XOR each bit*/
        IF (lFirstBit  AND NOT lSecondBit) OR
           (lSecondBit AND NOT lFirstBit) THEN
            iXOResult = iXOResult + EXP(2, iByteLoop - 1).
    END.                                              
    RETURN iXOResult.
END FUNCTION. /*End of METHOD BinaryXOR */        

FUNCTION ShiftRight RETURNS INT64(INPUT in_Operand_A AS INT64,
                                  INPUT in_Operand_B AS INTEGER):
  /** Bit Shift Right **/
   RETURN INT64( TRUNCATE( in_Operand_A / EXP(2,in_Operand_B), 0 ) ).

END FUNCTION.

FUNCTION BinaryAND RETURNS INTEGER (INPUT in_Operand_A AS INT64,
                                    INPUT in_Operand_B AS INT64):

   DEFINE VARIABLE in_cbit     AS INTEGER     NO-UNDO.
   DEFINE VARIABLE in_result   AS INT64     NO-UNDO.

   DO in_cbit = 1 TO 64:
      IF LOGICAL( GET-BITS( in_Operand_A, in_cbit, 1 ) ) AND
         LOGICAL( GET-BITS( in_Operand_B, in_cbit, 1 ) )
      THEN
         PUT-BITS( in_result, in_cbit, 1 ) = 1.
  END.

  RETURN in_result.

END FUNCTION. /* End of FUNCTION BinaryAND */

FUNCTION intToHex RETURNS CHARACTER (i_iint AS INT64):
   DEF VAR chex  AS CHAR NO-UNDO.
   DEF VAR rbyte AS RAW  NO-UNDO.
   DO WHILE i_iint > 0:
      PUT-BYTE( rbyte, 1 ) = i_iint MODULO 256.
      chex = STRING( HEX-ENCODE( rbyte ) ) + chex.
      i_iint = TRUNCATE( i_iint / 256, 0 ).
   END.
   RETURN chex.
END FUNCTION.

FUNCTION crc32Table RETURNS INT64 EXTENT 256  ():

    DEFINE VARIABLE crc32_tab       AS INT64     NO-UNDO EXTENT 256 INITIAL
        [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
        0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
        0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
        0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
        0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
        0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
        0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
        0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
        0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
        0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
        0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
        0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
        0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
        0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
        0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
        0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
        0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
        0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
        0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
        0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
        0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
        0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D].

    RETURN crc32_tab.

END FUNCTION.

FUNCTION CRC32 RETURNS INT64 (INPUT mpData AS MEMPTR):

    DEFINE VARIABLE IN_BYtes_Size   AS INTEGER   NO-UNDO.
    DEFINE VARIABLE in_byte         AS INTEGER   NO-UNDO.
    DEFINE VARIABLE crc_value       AS INT64     NO-UNDO.
    DEFINE VARIABLE tmp             AS INT64     NO-UNDO.
    DEFINE VARIABLE crc32_tab       AS INT64     NO-UNDO EXTENT 256.
    DEFINE VARIABLE in_loop         AS INTEGER     NO-UNDO.

    /** OOABL this would a STATIC varable**/
    crc32_tab = crc32Table().
  
    crc_value = 0xffffffff.
    In_Bytes_Size = GET-SIZE(mpData).

    MESSAGE "byte size:" In_Bytes_Size.
  
    DO in_loop = 1 TO In_Bytes_Size:
        tmp = BinaryXOR(crc_value, GET-BYTE(mpData,in_loop )).
        crc_value = BinaryXOR( ShiftRight(crc_value, 8), crc32_tab[BinaryAND(tmp,0x00ff) + 1 ] ).
    END.
  
    crc_value = BinaryXOR(crc_value, 0xffffffff).
  
    RETURN crc_value.

END FUNCTION.

/** MAIN-BLOCK**/
DEFINE VARIABLE mpData          AS MEMPTR      NO-UNDO.
DEFINE VARIABLE chStringData    AS CHARACTER   NO-UNDO.
DEFINE VARIABLE inLength AS INTEGER     NO-UNDO.

chStringData = "password".
inLength     = LENGTH(chStringData, 'raw').

set-size(mpData) = 0. /** ALWAYS ZERO YOUR MEMPTRs **/
set-size(mpData) = inLength.
PUT-STRING(mpData,1,inLength) = chStringData.

/* In theory I could pass it blob but I not sure how fast that would be??*/

MESSAGE CAPS( intToHex(CRC32(INPUT mpData)) )
    VIEW-AS ALERT-BOX INFO.
set-size(mpData) = 0. /** ALWAYS ZERO YOUR MEMPTRs **/
 

Cecil

19+ years progress programming and still learning.
I was using the iEXP constant extent variable originally but I found that I was getting array out of bound errors for this crc32 hashing code.. Guess it something to do with using 64bit arrays.
I should try and make a longer variable extent to handle 64bit numbers.
 

Cecil

19+ years progress programming and still learning.
Initial code generator to populate the iEXT variable.

Code:
DEFINE VARIABLE iEXT AS INT64 EXTENT 32  NO-UNDO.
DEFINE VARIABLE i AS INTEGER     NO-UNDO.

DO I = 1 TO EXTENT(iEXT):
    IF i EQ 1 THEN
        iEXT[1] = 1.
    ELSE
        iEXT[i] = iEXT[i - 1] * 2.
END.
 

Stefan

Well-Known Member
Code:
DEFINE VARIABLE iexp AS INT64    NO-UNDO EXTENT 32 INITIAL 1.
DEFINE VARIABLE ii   AS INTEGER  NO-UNDO.

DO ii = 2 TO EXTENT( iexp ):
   iexp[ii] = iexp[ii - 1] * 2.
END.
 

Cecil

19+ years progress programming and still learning.
Code:
DEFINE VARIABLE iexp AS INT64    NO-UNDO EXTENT 32 INITIAL 1.
DEFINE VARIABLE ii   AS INTEGER  NO-UNDO.

DO ii = 2 TO EXTENT( iexp ):
   iexp[ii] = iexp[ii - 1] * 2.
END.
That's better. What was I thinking of: iEXT, I totally should've called it iEXP (iexp).
 
Last edited:
Top