(********************************************************************) (* *) (* zlib.s7i Zlib (RFC 1950) compression support library *) (* Copyright (C) 2015, 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 "bitdata.s7i"; include "inflate.s7i"; include "deflate.s7i"; include "crc32.s7i"; (** * Decompress a string that was compressed with zlib (RFC 1950). * Zlib uses the DEFLATE compression algorithm. DEFLATE uses * a combination of the LZ77 algorithm and Huffman coding. * In addition to DEFLATE, zlib uses a small header. * @return the uncompressed string. * @exception RANGE_ERROR If ''compressed'' is not in zlib format. *) const func string: zlibDecompress (in string: compressed) is func result var string: uncompressed is ""; local var integer: compressionMethod is 0; var integer: cinfo is 0; var integer: flags is 0; var lsbInBitStream: compressedStream is lsbInBitStream.value; var boolean: bfinal is FALSE; var string: adler32 is ""; begin if (ord(compressed[1]) * 256 + ord(compressed[2])) mod 31 = 0 then compressionMethod := ord(compressed[1]) mod 16; cinfo := (ord(compressed[1]) >> 4) mod 16; flags := ord(compressed[2]); if compressionMethod = 8 then compressedStream := openLsbInBitStream(compressed); if odd(flags >> 5) then # Decompressing with a provided dictionary is not supported. raise RANGE_ERROR; else skipBits(compressedStream, 16); repeat processCompressedBlock(compressedStream, uncompressed, bfinal); until bfinal; adler32 := gets(compressedStream, 4); if length(adler32) <> 4 or bytes2Int(adler32, UNSIGNED, BE) <> ord(adler32(uncompressed)) then raise RANGE_ERROR; end if; end if; close(compressedStream); end if; end if; end func; (** * Compress a string with the zlib (RFC 1950) compression method. * Zlib uses the DEFLATE compression algorithm. DEFLATE uses * a combination of the LZ77 algorithm and Huffman coding. * In addition to DEFLATE, zlib uses a small header. * @return the compressed string. *) const func string: zlibCompress (in string: uncompressed) is func result var string: compressed is ""; local const string: GZ_MAGIC is "x\156;"; var lsbOutBitStream: compressedStream is lsbOutBitStream.value; begin write(compressedStream, GZ_MAGIC); deflate(uncompressed, compressedStream); flush(compressedStream); compressed := getBytes(compressedStream) & bytes(adler32(uncompressed), BE, 4); end func;