with Bits; use Bits;
package body Keccak_C is
   -- C interface

   procedure C_Get_Size(Size: out Interfaces.C.size_t) is
   begin
      Size := C_Context'Size / 8;
   end C_Get_Size;

   function C_Begin return C_Context_Access is
      Result : C_Context_Access;
   begin
      Result := new C_Context;
      KeccakBegin(Result.all);
      return Result;
   end C_Begin;

   procedure C_Hash(Ctx: in C_Context_Access;
                    Input: Char_Star;
                    Len: Interfaces.C.size_t) is
      Buffer_Size: constant Natural := 2048;
      Byte_Size: constant Natural := 8;
      N: Natural := 0;
      I: Natural := 0;
      L: Natural := Natural(Len);
      Buf: String(1..Buffer_Size);
      B: Bitstream(1..Buf'Length*Byte_Size);
      Ptr: Char_Star := Input;
   begin
      if Input = null then
         raise Strings.Dereference_Error;
      end if;
      while L > I loop
         N := 0;
         for Chr of Buf loop
               exit when L <= I;
               Chr := Character(Ptr.all);
               Char_Ptrs.Increment(Ptr);
               N := N + 1;
               I := I + 1;
         end loop;
         ToBitstream(Buf(1..N), B(1..N*Byte_Size));
         KeccakHash(Ctx.all, B(1..N*Byte_Size));
      end loop;
   end C_Hash;

   procedure C_End(Ctx: C_Context_Access;
                   Output: Char_Star;
                   Len: Interfaces.C.Size_T) is
      L: Natural := Natural(Len);
      S: String(1..L);
      B: Bitstream(1..S'Length*8);
      Ptr: Char_Star := Output;
   begin
      if Output = null then
         raise Strings.Dereference_Error;
      end if;
      KeccakEnd(Ctx.all, B);
      ToString(B, S);
      for Chr of S loop
         Ptr.all := Interfaces.C.char(Chr);
         Char_Ptrs.Increment(Ptr);
      end loop;
      -- Len = Count
   end C_End;

   procedure C_Context_Deallocate is new Ada.Unchecked_Deallocation
     (C_Context, C_Context_Access);

   procedure C_Deallocate(Ctx: in out C_Context_Access) is
   begin
      C_Context_Deallocate(Ctx);
   end C_Deallocate;
end Keccak_C;
