Resolved Base32 Decoder and Encoder

I think I have figured it out.

Code:
Function charToValue returns integer (input charByte as character):

    DEFINE VARIABLE inCharByte AS INTEGER     NO-UNDO.
            
    inCharByte = asc(charByte).

    //65-90 == uppercase letters
    if inCharByte < 91 and inCharByte > 64 then
        return inCharByte - 65.
    
    //50-55 == numbers 2-7
    if inCharByte < 56 and inCharByte > 49 then
        return inCharByte - 24.
    
    //97-122 == lowercase letters
    if(inCharByte < 123 and inCharByte > 96) then
        return inCharByte - 97.

    return ?.
end function.

FUNCTION bitOR RETURNS INTEGER (INPUT X AS INTEGER, INPUT Y AS INTEGER):
   DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
   DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
   DEFINE VARIABLE n  AS INTEGER NO-UNDO.
   DEFINE VARIABLE Z  AS INTEGER NO-UNDO.

   DO n = 1 TO 32:
     ASSIGN
       b1 = GET-BITS(X, n, 1)
       b2 = GET-BITS(Y, n, 1)
       .
       IF b1 = 1 OR b2 = 1 THEN
        PUT-BITS(Z, n, 1) = 1.
   END.

   RETURN Z.
END FUNCTION.

Function arithmeticLeftShift return integer (input x as integer, input z as integer):

    DEFINE VARIABLE buff AS INTEGER     NO-UNDO.
    DEFINE VARIABLE ishift AS INTEGER     NO-UNDO.
    DEFINE variable y AS INTEGER     NO-UNDO.
    
    Do ishift = 1 to z:
    
        put-bits(y, 2, 31) = get-bits(x, 1, 31).   
        put-bits(y, 1, 1)  = 0.  // The empty position in the least significant bit is filled with a zero.
    
        x = y.
    
    End.
    
    return x.

end function.


Function arithmeticRightShift return integer (input x as integer, input z as integer):

    DEFINE VARIABLE buff AS INTEGER     NO-UNDO.
    DEFINE VARIABLE ishift AS INTEGER     NO-UNDO.
    DEFINE variable y AS INTEGER     NO-UNDO.
    
    Do ishift = 1 to z:
    
        put-bits(y, 32, 1) = get-bits(x, 32, 1).   //The empty position in the most significant bit is filled with a copy of the original MSB
        put-bits(y, 1, 31) = get-bits(x, 2, 31).
    
        x = y.
    
    End.
    
    return x.
end function.


Function base32decode return memptr (input base32EncodedValue as character):

    DEFINE VARIABLE returnArray     AS MEMPTR      NO-UNDO.
    
    DEFINE VARIABLE cCharByte       AS CHARACTER   NO-UNDO.
    
    DEFINE VARIABLE iValue          AS INTEGER     NO-UNDO.   
    DEFINE VARIABLE iCharIndex      AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iLength         AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iByteCount      AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iBitsRemaining  AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iMask           AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iCurrentByte    AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iBytePosition   AS INTEGER     NO-UNDO.
    
    set-byte-order(returnArray ) = big-endian.
    
    // Terminiate if no value has be inputted 
    if base32EncodedValue eq "" Then
        return ?.
    
    assign
        //base32EncodedValue = lc(base32EncodedValue)
        base32EncodedValue = replace(base32EncodedValue,' ','')
        base32EncodedValue = replace(base32EncodedValue,'=','')
        .
        
    assign   
        iLength    = length(base32EncodedValue, "RAW")   
        iByteCount = truncate(iLength * 5 / 8, 0)
        .
    
    set-size(returnArray ) = 0.
    set-size(returnArray ) = iByteCount.     
    
    assign
        iBitsRemaining = 8
        iMask          = 0
        iCurrentByte   = 0
        iBytePosition  = 0.
                                  
    CHARACTER_BYTE:
    do iCharIndex = 1 to iLength:
    
        cCharByte = substring(base32EncodedValue, iCharIndex, 1, "RAW").
        
        iValue = charToValue(input cCharByte).
        
        // Ignore invalid charactes and move on.
        if iValue eq ? Then
            next CHARACTER_BYTE.
        
        If iBitsRemaining gt 5 Then
        Do:
        
            iMask = arithmeticLeftShift(iValue , (iBitsRemaining - 5) ).
        
            iCurrentByte = bitOR(iCurrentByte, iMask).
        
            iBitsRemaining = iBitsRemaining - 5.
            
        end.
        else
        do:
            
            iMask = arithmeticRightShift(iValue , (5 - iBitsRemaining) ).
        
            iCurrentByte = bitOR(iCurrentByte, iMask).
        
            iBytePosition  = iBytePosition + 1.
            put-byte(returnArray, iBytePosition) = iCurrentByte.
            
            iCurrentByte = arithmeticLeftShift(iValue , (3 + iBitsRemaining) ).
            
            iBitsRemaining = iBitsRemaining + 3.       
        end.
    End.
    
    if iBytePosition ne iByteCount then
    do:
        //iBytePosition  = iBytePosition + 1.
        put-byte(returnArray, iBytePosition + 1) = iCurrentByte.
        
    end.
    
    return returnArray.
    
    // Garbage collection
    finally:
        set-size(returnArray) = 0.
    end finally.
    
end.



/************* MAIN BLOCK ****************/


DEFINE VARIABLE mBase32Decoded AS MEMPTR      NO-UNDO.

etime(true).

set-size(mBase32Decoded) = 0.

mBase32Decoded = base32decode(input "jbsw y3dp ehpk 3pxp").

message 'SIZE:' get-size(mBase32Decoded).
message 'HEX:' string(hex-encode(mBase32Decoded)) .
message 'etime:' etime .

// Garbage collection
finally:

    set-size(mBase32Decoded) = 0.

end finally.
 
I've re-opened this thread. I now have a situation where I need to write a base32 encoder function/method.
Any ideas how to do this in the ABL?

c# code I've tried to reserve into progress.

C#:
public class Base32Encoder
{
    private static readonly char[] Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray();

    public static string Encode(byte[] data)
    {
        if (data == null || data.Length == 0)
        {
            throw new ArgumentNullException(nameof(data));
        }

        int outputLength = (data.Length * 8 + 4) / 5; // Calculate the length of the output string
        StringBuilder result = new StringBuilder(outputLength);

        int buffer = data[0];
        int next = 1;
        int bitsLeft = 8;
        while (bitsLeft > 0 || next < data.Length)
        {
            if (bitsLeft < 5)
            {
                if (next < data.Length)
                {
                    buffer <<= 8;
                    buffer |= (data[next++] & 0xFF);
                    bitsLeft += 8;
                }
                else
                {
                    int pad = 5 - bitsLeft;
                    buffer <<= pad;
                    bitsLeft += pad;
                }
            }

            int index = (buffer >> (bitsLeft - 5)) & 0x1F;
            bitsLeft -= 5;
            result.Append(Base32Chars[index]);
        }

        return result.ToString();
    }

    public static void Main(string[] args)
    {
        // Test example
        byte[] data = Encoding.UTF8.GetBytes("hello world");
        string encoded = Encode(data);
        Console.WriteLine("Original: " + Encoding.UTF8.GetString(data));
        Console.WriteLine("Base32 Encoded: " + encoded);
    }
}
 
I've given it another crack and I think I've got it.

C#:
method public static character Encode( input rawDataBytes as raw  ):
        
        define variable Base32Chars   as character no-undo initial "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".
        
        define variable base32String  as character no-undo.
        define variable outputLength  as integer   no-undo.
        define variable byteBuffer    as int64     no-undo.
        define variable nextByte      as int64     no-undo.
        define variable bitsLeft      as integer   no-undo.
        define variable currentByte   as int64     no-undo.
        define variable maskedByte    as int64     no-undo.
        define variable pad           as integer   no-undo.
        define variable indexPos      as integer   no-undo.
        //define variable shiftAmount   as integer   no-undo.
        define variable shiftedBuffer as int64     no-undo.
        define variable maskedIndex   as int64     no-undo.
        
        if rawDataBytes eq ? or length(rawDataBytes) eq 0 then
            return "".
            
        outputLength = integer( truncate(  (length(rawDataBytes) * 8 + 4) / 5,0) ).
        
        byteBuffer = get-byte(rawDataBytes, 1).
        nextByte = 2.
        bitsLeft = 8.
        
        do while (bitsLeft gt 0 or nextByte lt length(rawDataBytes)):

            if (bitsLeft lt 5) then
            do:
                
                if (nextByte < length(rawDataBytes)) then
                do:
                    assign
                        currentByte = get-byte(rawDataBytes, nextByte)
                        nextByte    = nextByte + 1
                        maskedByte  = BitWise:bitAnd(currentByte, 0xFF)
                        byteBuffer  = BitWise:arithmeticLeftShift(byteBuffer, 8)
                        byteBuffer  = BitWise:bitOR(byteBuffer, maskedByte)
                        bitsLeft    = bitsLeft + 8.
                end.
                else
                do:
                    assign
                        pad        = 8 - bitsLeft
                        byteBuffer = BitWise:arithmeticLeftShift(byteBuffer, pad)
                        bitsLeft   = bitsLeft + pad.
                end.
                
            end.
            
            assign         
                shiftedBuffer = BitWise:arithmeticRightShift(byteBuffer, (bitsLeft - 5) )
                maskedIndex   = BitWise:bitAnd(shiftedBuffer, 0x1F)
                indexPos      = maskedIndex           
                bitsLeft      = bitsLeft - 5           
                base32String  = base32String + substring(Base32Chars,indexPos + 1, 1).
            
        end.
        
        return base32String.

    end method.
 
The reason for needing to create Base32 Encoding is for the use of create QR codes to provision TOTP authenticators.
The result of the base32 becomes a shared secret key.

Example:
generate-uuid --> base32 encoding --> JBSW-Y3DP-EHPK-3PXP
 
The reason for needing to create Base32 Encoding is for the use of create QR codes to provision TOTP authenticators.
The result of the base32 becomes a shared secret key.

Example:
generate-uuid --> base32 encoding --> JBSW-Y3DP-EHPK-3PXP

Maybe I should read the subject line properly ... :eek: . Sorry for the noise.
 
Back
Top