Howdy all - I’m currently pretty new to Ada and working on some sample projects to teach myself. As part of this, I’m trying to build a subprogram to convert an array of bytes to a string of Base64 Characters per the algorithm specified in RFC4648, which operates on groups of 3 bytes to produce 4 characters. I have functional code for this (ignoring padding bytes), but I already feel that it is very inelegant, and I’m also having a lot of trouble getting it to pass gnatprove
. I’d like to focus on the inelegancies for now. Here is what I have come up with:
function Bytes_To_B64_String (Input : Bytes) return B64_String is
Input_Iterator : Integer range Input'First .. Input'Last + 1 := Input'First;
Output : B64_String (1 .. (Input'Length / 3 * 4)) := (others => '='); -- Output String
Output_Iterator : Integer range Output'First .. Output'Last + 1 := Output'First;
Byte_Trio : Bytes (1 .. 3) := [others => 0];
Byte_Quad : Bytes (1 .. 4) := [others => 0];
B64_Quad : B64_String (1 .. 4) := [others => '='];
begin
while Input_Iterator <= Input'Last - 2 loop
Byte_Trio (1) := Input (Input_Iterator);
Byte_Trio (2) := Input (Input_Iterator + 1);
Byte_Trio (3) := Input (Input_Iterator + 2);
Byte_Quad (1) := Shift_Right (Byte_Trio (1), 2) and 2#00111111#;
Byte_Quad (2) := (Shift_Left (Byte_Trio (1), 4) or Shift_Right (Byte_Trio (2), 4)) and 2#00111111#;
Byte_Quad (3) := (Shift_Left (Byte_Trio (2), 2) or Shift_Right (Byte_Trio (3), 6)) and 2#00111111#;
Byte_Quad (4) := (Byte_Trio (3) and 2#00111111#);
B64_Quad (1) := Byte_To_B64_Character_Lookup (Byte_Quad (1));
B64_Quad (2) := Byte_To_B64_Character_Lookup (Byte_Quad (2));
B64_Quad (3) := Byte_To_B64_Character_Lookup (Byte_Quad (3));
B64_Quad (4) := Byte_To_B64_Character_Lookup (Byte_Quad (4));
Output (Output_Iterator) := B64_Quad (1);
Output (Output_Iterator + 1) := B64_Quad (2);
Output (Output_Iterator + 2) := B64_Quad (3);
Output (Output_Iterator + 3) := B64_Quad (4);
Input_Iterator := Input_Iterator + 3;
Output_Iterator := Output_Iterator + 4;
end loop;
return Output;
end Bytes_To_B64_String;
My first primary complaint in this is the use of a while
loop to iterate over elements. Is there Ada syntax that will allow me to iterate over the input array in groups of 3? In C, for example,
for (int i = 0; i < len(foo); i += 3)
.
Second, I am not happy that I gave Input_Iterator
and Output_Iterator
ranges of N+1 to avoid overflows when they are incremented in the last execution of the loop. If I can’t avoid the for
loop, is there at least a clean way to avoid this that I’m not seeing?
Thanks in advance for any help; I’m enjoying working with Ada, but I still think I’m fighting the language a bit.