a CRC32 algorithm in Ada


-- package spec

-- CRC32 Algorithm (spec)
-- Christophe GOUIRAN (christophe@e-motive.com)
-- Any corrections/suggestions are welcome

with Interfaces;

package crc32 is

   -- mod 2**16
   subtype crc is Interfaces.Unsigned_32;
   
   -- This function return the CRC32 of a given file.
   -- It may throw all the exceptions declared at the end of the package.
   function Get_File_Crc32 ( file : String ) return crc;

   FILE_OPEN_ERROR,
   FILE_READ_ERROR,
   FILE_CLOSE_ERROR : exception;

end crc32;

-- package body

-- CRC32 Algorithm (body)
-- Christophe GOUIRAN (christophe@e-motive.com)
-- Any corrections/suggestions are welcome

with Interfaces; use Interfaces;
with Interfaces.C; use Interfaces.C;
with Interfaces.C_Streams; use Interfaces.C_Streams;
with System.Address_To_Access_Conversions;
use System;

package body crc32 is

   -- Take a buffer of 32k for reading operations
   Buffer_Size : constant := 32 * 1024;

   -- Internal type to specify what we read read from the file/URL.
   type byte is mod 255;
   for byte'size use 8;

   -- Internal CRC Table.
   -- We use crc type for indexes and values to make Logical operations
easier.

   CRC32Table : array(crc range 0 .. 255) of crc :=
   (0,16#77073096#,16#EE0E612C#,16#990951BA#,
    16#76DC419#,16#706AF48F#,16#E963A535#,16#9E6495A3#,
    16#EDB8832#,16#79DCB8A4#,16#E0D5E91E#,16#97D2D988#,
    16#9B64C2B#,16#7EB17CBD#,16#E7B82D07#,16#90BF1D91#,
    16#1DB71064#,16#6AB020F2#,16#F3B97148#,16#84BE41DE#,
    16#1ADAD47D#,16#6DDDE4EB#,16#F4D4B551#,16#83D385C7#,
    16#136C9856#,16#646BA8C0#,16#FD62F97A#,16#8A65C9EC#,
    16#14015C4F#,16#63066CD9#,16#FA0F3D63#,16#8D080DF5#,
    16#3B6E20C8#,16#4C69105E#,16#D56041E4#,16#A2677172#,
    16#3C03E4D1#,16#4B04D447#,16#D20D85FD#,16#A50AB56B#,
    16#35B5A8FA#,16#42B2986C#,16#DBBBC9D6#,16#ACBCF940#,
    16#32D86CE3#,16#45DF5C75#,16#DCD60DCF#,16#ABD13D59#,
    16#26D930AC#,16#51DE003A#,16#C8D75180#,16#BFD06116#,
    16#21B4F4B5#,16#56B3C423#,16#CFBA9599#,16#B8BDA50F#,
    16#2802B89E#,16#5F058808#,16#C60CD9B2#,16#B10BE924#,
    16#2F6F7C87#,16#58684C11#,16#C1611DAB#,16#B6662D3D#,
    16#76DC4190#,16#1DB7106#,16#98D220BC#,16#EFD5102A#,
    16#71B18589#,16#6B6B51F#,16#9FBFE4A5#,16#E8B8D433#,
    16#7807C9A2#,16#F00F934#,16#9609A88E#,16#E10E9818#,
    16#7F6A0DBB#,16#86D3D2D#,16#91646C97#,16#E6635C01#,
    16#6B6B51F4#,16#1C6C6162#,16#856530D8#,16#F262004E#,
    16#6C0695ED#,16#1B01A57B#,16#8208F4C1#,16#F50FC457#,
    16#65B0D9C6#,16#12B7E950#,16#8BBEB8EA#,16#FCB9887C#,
    16#62DD1DDF#,16#15DA2D49#,16#8CD37CF3#,16#FBD44C65#,
    16#4DB26158#,16#3AB551CE#,16#A3BC0074#,16#D4BB30E2#,
    16#4ADFA541#,16#3DD895D7#,16#A4D1C46D#,16#D3D6F4FB#,
    16#4369E96A#,16#346ED9FC#,16#AD678846#,16#DA60B8D0#,
    16#44042D73#,16#33031DE5#,16#AA0A4C5F#,16#DD0D7CC9#,
    16#5005713C#,16#270241AA#,16#BE0B1010#,16#C90C2086#,
    16#5768B525#,16#206F85B3#,16#B966D409#,16#CE61E49F#,
    16#5EDEF90E#,16#29D9C998#,16#B0D09822#,16#C7D7A8B4#,
    16#59B33D17#,16#2EB40D81#,16#B7BD5C3B#,16#C0BA6CAD#,
    16#EDB88320#,16#9ABFB3B6#,16#3B6E20C#,16#74B1D29A#,
    16#EAD54739#,16#9DD277AF#,16#4DB2615#,16#73DC1683#,
    16#E3630B12#,16#94643B84#,16#D6D6A3E#,16#7A6A5AA8#,
    16#E40ECF0B#,16#9309FF9D#,16#A00AE27#,16#7D079EB1#,
    16#F00F9344#,16#8708A3D2#,16#1E01F268#,16#6906C2FE#,
    16#F762575D#,16#806567CB#,16#196C3671#,16#6E6B06E7#,
    16#FED41B76#,16#89D32BE0#,16#10DA7A5A#,16#67DD4ACC#,
    16#F9B9DF6F#,16#8EBEEFF9#,16#17B7BE43#,16#60B08ED5#,
    16#D6D6A3E8#,16#A1D1937E#,16#38D8C2C4#,16#4FDFF252#,
    16#D1BB67F1#,16#A6BC5767#,16#3FB506DD#,16#48B2364B#,
    16#D80D2BDA#,16#AF0A1B4C#,16#36034AF6#,16#41047A60#,
    16#DF60EFC3#,16#A867DF55#,16#316E8EEF#,16#4669BE79#,
    16#CB61B38C#,16#BC66831A#,16#256FD2A0#,16#5268E236#,
    16#CC0C7795#,16#BB0B4703#,16#220216B9#,16#5505262F#,
    16#C5BA3BBE#,16#B2BD0B28#,16#2BB45A92#,16#5CB36A04#,
    16#C2D7FFA7#,16#B5D0CF31#,16#2CD99E8B#,16#5BDEAE1D#,
    16#9B64C2B0#,16#EC63F226#,16#756AA39C#,16#26D930A#,
    16#9C0906A9#,16#EB0E363F#,16#72076785#,16#5005713#,
    16#95BF4A82#,16#E2B87A14#,16#7BB12BAE#,16#CB61B38#,
    16#92D28E9B#,16#E5D5BE0D#,16#7CDCEFB7#,16#BDBDF21#,
    16#86D3D2D4#,16#F1D4E242#,16#68DDB3F8#,16#1FDA836E#,
    16#81BE16CD#,16#F6B9265B#,16#6FB077E1#,16#18B74777#,
    16#88085AE6#,16#FF0F6A70#,16#66063BCA#,16#11010B5C#,
    16#8F659EFF#,16#F862AE69#,16#616BFFD3#,16#166CCF45#,
    16#A00AE278#,16#D70DD2EE#,16#4E048354#,16#3903B3C2#,
    16#A7672661#,16#D06016F7#,16#4969474D#,16#3E6E77DB#,
    16#AED16A4A#,16#D9D65ADC#,16#40DF0B66#,16#37D83BF0#,
    16#A9BCAE53#,16#DEBB9EC5#,16#47B2CF7F#,16#30B5FFE9#,
    16#BDBDF21C#,16#CABAC28A#,16#53B39330#,16#24B4A3A6#,
    16#BAD03605#,16#CDD70693#,16#54DE5729#,16#23D967BF#,
    16#B3667A2E#,16#C4614AB8#,16#5D681B02#,16#2A6F2B94#,
    16#B40BBE37#,16#C30C8EA1#,16#5A05DF1B#,16#2D02EF8D#);
   
   function Update_Crc ( value : crc ; item : Byte ) return crc is
   begin
      return Shift_Right(value, 8) xor Crc32Table((value xor
Byte'pos(item)) and 16#FF#);   
   end Update_Crc;
   
   function Get_File_Crc32 ( file : String ) return crc is

      -- Parameters passed to the fopen function
      file_c : aliased char_array := To_C(file);
      mode : aliased char_array := To_C("rb");

      -- Final result to be returned
      Result : crc := Not 0;
            
      -- Useful for passing filename and opening mode to the fopen function
      package C_To_A is new
System.Address_To_Access_Conversions(char_array);
      use C_To_A;
      
      fd_file : C_Streams.Files;
      
      type T_Buffer is array(Interfaces.C_Streams.size_t range 0 ..
Buffer_Size - 1) of aliased Byte;
      for T_Buffer'Component_Size use 8;
      
      buffer : aliased T_Buffer;-- := (others => 0); -- slow down the
code, enable it only for debugging purpose
      
      
      -- Useful for passing our buffer to the fread function
      package C_To_A2 is new
System.Address_To_Access_Conversions(t_buffer);
      use C_To_A2;

      -- Bytes read from the file
      To_Process : Interfaces.C_Streams.size_t := 0;

   begin
   
      fd_file := fopen(To_Address(file_c'access), To_Address(mode'access));
      
      if fd_file = System.Null_Address
      then
         raise FILE_OPEN_ERROR;
      end if;   
   
      while feof(fd_file) /= EOF
      loop
         To_Process := fread(To_Address(buffer'access), 1, Buffer_Size,
fd_file);
         
         if To_Process < 0
         then
            raise FILE_READ_ERROR;
         end if;   
         
         exit when To_Process = 0;
         
         for i in 0 .. To_Process - 1
         loop
            result := Update_CRC(result, buffer(i));
         end loop;         
      end loop;

      if fclose(fd_file) /= 0
      then
         raise FILE_CLOSE_ERROR;
      end if;   
   
      return Not result;
   
   end Get_File_Crc32;
   
end crc32;

-- example program

-- CRC32 Algorithm (example test)
-- Christophe GOUIRAN (christophe@e-motive.com)
-- Any corrections/suggestions are welcome

with Ada.Command_Line; use Ada.Command_Line; 
with crc32; use crc32;
with text_IO; use text_IO;

procedure example is

   package crc_io is new modular_io(crc);
   use crc_io;

begin

   if Argument_Count = 0
   then
      put("Syntax : " & Command_Name & " file_to_check.");
      new_line;
   else   
      put(Get_File_CRC32(Argument(1)), Base => 16);
      new_line;
   end if;   
   
end;

Contributed by: Christophe Gouiran
Contributed on: November 8, 2000
License: Public Domain

Back