(********************************************************************)
(*                                                                  *)
(*  crc32.s7i     CRC-32 cyclic redundancy check support library    *)
(*  Copyright (C) 2013, 2019, 2024 - 2026  Thomas Mertes            *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library is distributed in the hope that it    *)
(*  will be useful, but WITHOUT ANY WARRANTY; without even the      *)
(*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(*  PURPOSE.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


include "bin32.s7i";


const type: crc32TableType is array [0 .. 255] bin32;


const func crc32TableType: createCrc32Table is func
  result
    var crc32TableType: crc32Table is crc32TableType.value;
  local
    # Reversed / reflected (LSB-First) standard IEEE 802.3 CRC-32 polynomial.
    const bin32: IEEE_802_3_POLYNOMIAL is bin32(16#edb88320);
    var bin32: crc is bin32(0); # crc shift register
    var integer: i is 0;        # counter for all possible eight bit values
  begin
    for i range 1 to 255 do
      crc := bin32(i);
      for 8 do
        if crc & bin32(1) <> bin32(0) then
          crc := (crc >> 1) >< IEEE_802_3_POLYNOMIAL;
        else
          crc >>:= 1;
        end if;
      end for;
      crc32Table[i] := crc;
    end for;
  end func;


const crc32TableType: crc32Table is createCrc32Table;


(**
 *  Compute the CRC-32 cyclic redundancy check code.
 *   crc32("123456789")  returns bin32(16#cbf43926)
 *)
const func bin32: crc32 (in string: stri) is func
  result
    var bin32: crc is bin32(16#ffffffff);
  local
    var char: ch is ' ';
  begin
    for ch range stri do
      crc := crc32Table[ord(crc >< bin32(ch)) mod 256] >< crc >> 8;
    end for;
    crc ><:= bin32(16#ffffffff);
  end func;


(**
 *  Compute the CRC-32 cyclic redundancy check code with ''interimCrc''.
 *  This function can be used to compute the CRC-32 with multiple steps:
 *   interimCrc := crc32(data1);
 *   interimCrc := crc32(data2, interimCrc);
 *   finalCrc   := crc32(data3, interimCrc);
 *)
const func bin32: crc32 (in string: stri, in bin32: interimCrc) is func
  result
    var bin32: crc is bin32(0);
  local
    var char: ch is ' ';
  begin
    crc := interimCrc >< bin32(16#ffffffff);
    for ch range stri do
      crc := crc32Table[ord(crc >< bin32(ch)) mod 256] >< crc >> 8;
    end for;
    crc ><:= bin32(16#ffffffff);
  end func;


const func crc32TableType: createBzip2Crc32Table is func
  result
    var crc32TableType: crc32Table is crc32TableType.value;
  local
    # Standard IEEE 802.3 Polynomial (Unreflected) used by bzip2.
    const bin32: BZIP2_POLYNOMIAL is bin32(16#04C11DB7);
    var bin32: crc is bin32(0); # crc shift register
    var integer: i is 0;        # counter for all possible eight bit values
  begin
    for i range 1 to 255 do
      crc := bin32(i << 24);
      for 8 do
        if crc & bin32(16#80000000) <> bin32(0) then
          crc := (crc << 1) >< BZIP2_POLYNOMIAL;
        else
          crc <<:= 1;
        end if;
      end for;
      crc32Table[i] := crc & bin32(16#ffffffff);
    end for;
  end func;


const crc32TableType: bzip2Crc32Table is createBzip2Crc32Table;


(**
 *  Compute the CRC-32 cyclic redundancy check code of BZIP2.
 *   bzip2Crc32("123456789")  returns bin32(16#fc891918)
 *)
const func bin32: bzip2Crc32 (in string: stri) is func
  result
    var bin32: crc is bin32(16#ffffffff);
  local
    var char: ch is ' ';
  begin
    for ch range stri do
      crc := bzip2Crc32Table[ord((crc >> 24) >< bin32(ch)) mod 256] ><
             ((crc << 8) & bin32(16#ffffffff));
    end for;
    crc ><:= bin32(16#ffffffff);
  end func;


(**
 *  Compute the CRC-32 cyclic redundancy check code of BZIP2 with ''interimCrc''.
 *  This function can be used to compute the CRC-32 with multiple steps:
 *   interimCrc := bzip2Crc32(data1);
 *   interimCrc := bzip2Crc32(data2, interimCrc);
 *   finalCrc   := bzip2Crc32(data3, interimCrc);
 *)
const func bin32: bzip2Crc32 (in string: stri, in bin32: interimCrc) is func
  result
    var bin32: crc is bin32(0);
  local
    var char: ch is ' ';
  begin
    crc := interimCrc >< bin32(16#ffffffff);
    for ch range stri do
      crc := bzip2Crc32Table[ord((crc >> 24) >< bin32(ch)) mod 256] ><
             ((crc << 8) & bin32(16#ffffffff));
    end for;
    crc ><:= bin32(16#ffffffff);
  end func;