From ee21f714a90ec023fde3b8dc805c2e2d42772017 Mon Sep 17 00:00:00 2001
From: Sebastião Guerra <sebastiao.luiz.guerra@gmail.com>
Date: Tue, 1 Sep 2026 10:33:52 -0300
Subject: Add Lzip compression support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Sebastião Guerra <sebastiao.luiz.guerra@gmail.com>
---
 CMakeLists.txt                      |  45 ++++++
 config.h.cmake                      |   3 +
 tdeio/tdeio/kfilterdev.cpp          |   5 +
 tdeio/tdeio/ktar.cpp                |  41 +++--
 tdeio/tdeio/ktar.h                  |   4 +-
 tdeio/tests/kfiltertest.cpp         |  87 ++++++++++-
 tdeioslave/CMakeLists.txt           |   1 +
 tdeioslave/lzip/CMakeLists.txt      |  42 +++++
 tdeioslave/lzip/klzipfilter.cpp     | 299 ++++++++++++++++++++++++++++++++++++
 tdeioslave/lzip/klzipfilter.desktop |   5 +
 tdeioslave/lzip/klzipfilter.h       |  59 +++++++
 tdeioslave/xz/kxzfilter.cpp         |   4 -
 tdeioslave/xz/kxzfilter.h           |   5 -
 13 files changed, 565 insertions(+), 35 deletions(-)
 create mode 100644 tdeioslave/lzip/CMakeLists.txt
 create mode 100644 tdeioslave/lzip/klzipfilter.cpp
 create mode 100644 tdeioslave/lzip/klzipfilter.desktop
 create mode 100644 tdeioslave/lzip/klzipfilter.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab7ea76c0..8766284c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,6 +131,7 @@ option( WITH_PCSC "Enable PC/SC SmartCard support" ${WITH_ALL_OPTIONS} )
 option( WITH_PKCS "Enable PKCS support" ${WITH_ALL_OPTIONS} )
 option( WITH_CRYPTSETUP "Enable cryptsetup support" ${WITH_ALL_OPTIONS} )
 option( WITH_LZMA "Enable support for LZMA/XZ" ${WITH_ALL_OPTIONS} )
+option( WITH_LZIP "Enable support for Lzip" ${WITH_ALL_OPTIONS} )
 option( WITH_LIBBFD "Enable pretty backtraces with libbfd from GNU binutils" OFF )
 option( WITH_XRANDR "Build the tderandr library" ON )
 option( WITH_XCOMPOSITE "Enable xcomposite support" ON )
@@ -743,6 +744,50 @@ if( WITH_LZMA )
 endif( WITH_LZMA )
 
 
+##### check for lzip ###########################
+
+if( WITH_LZIP )
+  find_path( LZIP_INCLUDE_DIR lzlib.h )
+  find_library( LZIP_LIBRARY NAMES lz )
+  if( LZIP_LIBRARY AND LZIP_INCLUDE_DIR )
+    message( STATUS "Found Lzip: ${LZIP_LIBRARY}" )
+    set( LZIP_INCLUDE_DIRS ${LZIP_INCLUDE_DIR} )
+    set( LZIP_LIBRARIES ${LZIP_LIBRARY} )
+  else( )
+    tde_message_fatal( "Lzip support is requested, but lzlib was not found on your system" )
+  endif( )
+
+  tde_save_and_set( CMAKE_REQUIRED_INCLUDES ${LZIP_INCLUDE_DIRS} )
+  tde_save_and_set( CMAKE_REQUIRED_LIBRARIES ${LZIP_LIBRARIES} )
+  check_c_source_compiles( "
+    #include <stdint.h>
+    #include <lzlib.h>
+    int main(void)
+    {
+      struct LZ_Decoder *decoder = LZ_decompress_open();
+      struct LZ_Encoder *encoder = LZ_compress_open( 1 << 23, 36, 1ULL << 51 );
+      if( decoder )
+      {
+        LZ_decompress_finish( decoder );
+        LZ_decompress_close( decoder );
+      }
+      if( encoder )
+      {
+        LZ_compress_finish( encoder );
+        LZ_compress_close( encoder );
+      }
+      return decoder && encoder ? 0 : 1;
+    }" LZIP_CAN_COMPILE )
+  tde_restore( CMAKE_REQUIRED_INCLUDES )
+  tde_restore( CMAKE_REQUIRED_LIBRARIES )
+
+  if( NOT LZIP_CAN_COMPILE )
+    tde_message_fatal( "Lzip support is requested, but lzlib could not compile a simple program" )
+  endif( )
+  set( HAVE_LZIP_SUPPORT 1 )
+endif( WITH_LZIP )
+
+
 ##### check for pcsc ############################
 
 if( WITH_TDEHWLIB AND WITH_PCSC )
diff --git a/config.h.cmake b/config.h.cmake
index 6c30c3085..c5d663b46 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -100,6 +100,9 @@
 /* Defines if lzma/xz is compiled */
 #cmakedefine HAVE_XZ_SUPPORT 1
 
+/* Defines if lzip is compiled */
+#cmakedefine HAVE_LZIP_SUPPORT 1
+
 /* Define OpenSC provider library */
 #cmakedefine OPENSC_PKCS11_PROVIDER_LIBRARY "@OPENSC_PKCS11_PROVIDER_LIBRARY@"
 
diff --git a/tdeio/tdeio/kfilterdev.cpp b/tdeio/tdeio/kfilterdev.cpp
index 4df335090..fbc4cfc59 100644
--- a/tdeio/tdeio/kfilterdev.cpp
+++ b/tdeio/tdeio/kfilterdev.cpp
@@ -316,6 +316,11 @@ TQ_LONG KFilterDev::readBlock( char *data, TQ_ULONG maxlen )
         if (d->result == KFilterBase::ERROR)
         {
             kdWarning(7005) << "KFilterDev: Error when uncompressing data" << endl;
+            // If no data has been produced in this call, propagate the error
+            // immediately.  Otherwise return the already produced data and
+            // report the error on the next readBlock() call.
+            if ( dataReceived == 0 )
+                return -1;
             break;
         }
 
diff --git a/tdeio/tdeio/ktar.cpp b/tdeio/tdeio/ktar.cpp
index 6d90954b4..abe1c2e37 100644
--- a/tdeio/tdeio/ktar.cpp
+++ b/tdeio/tdeio/ktar.cpp
@@ -101,20 +101,27 @@ KTar::KTar( const TQString& filename, const TQString & _mimetype )
                     if ( fourthByte == 4 )
                         mimetype = "application/x-zip";
                 }
-		else if ( firstByte == 0xfd && secondByte == '7' && thirdByte == 'z' )
-		{
-			unsigned char fourthByte = file.getch();
-			unsigned char fifthByte = file.getch();
-			unsigned char sixthByte = file.getch();
-			if ( fourthByte == 'X' && fifthByte == 'Z' && sixthByte == 0x00 )
-				mimetype = "application/x-xz";
-		}
-		else if ( firstByte == 0x5d && secondByte == 0x00 && thirdByte == 0x00 )
-		{
-			unsigned char fourthByte = file.getch();
-			if ( fourthByte == 0x80 )
-				mimetype = "application/x-lzma";
-		}
+                else if ( firstByte == 0xfd && secondByte == '7' && thirdByte == 'z' )
+                {
+                    unsigned char fourthByte = file.getch();
+                    unsigned char fifthByte = file.getch();
+                    unsigned char sixthByte = file.getch();
+                    if ( fourthByte == 'X' && fifthByte == 'Z' && sixthByte == 0x00 )
+                        mimetype = "application/x-xz";
+                }
+                else if ( firstByte == 0x5d && secondByte == 0x00 && thirdByte == 0x00 )
+                {
+                    unsigned char fourthByte = file.getch();
+                    if ( fourthByte == 0x80 )
+                        mimetype = "application/x-lzma";
+                }
+                else if ( firstByte == 'L' && secondByte == 'Z' && thirdByte == 'I' )
+                {
+                    unsigned char fourthByte = file.getch();
+                    unsigned char fifthByte = file.getch();
+                    if ( fourthByte == 'P' && fifthByte == 0x01 )
+                        mimetype = "application/x-lzip";
+                }
             }
             file.close();
         }
@@ -301,7 +308,8 @@ bool KTar::KTarPrivate::fillTempFile( const TQString & filename) {
     if( "application/x-gzip" == mimetype
         || "application/x-bzip2" == mimetype
         || "application/x-lzma" == mimetype
-        || "application/x-xz" == mimetype)
+        || "application/x-xz" == mimetype
+        || "application/x-lzip" == mimetype)
             forced = true;
 
     TQIODevice *filterDev = KFilterDev::deviceForFile( filename, mimetype, forced );
@@ -518,7 +526,8 @@ bool KTar::KTarPrivate::writeBackTempFile( const TQString & filename ) {
     if( "application/x-gzip" == mimetype
         || "application/x-bzip2" == mimetype
         || "application/x-lzma" == mimetype
-        || "application/x-xz" == mimetype)
+        || "application/x-xz" == mimetype
+        || "application/x-lzip" == mimetype)
             forced = true;
 
     TQIODevice *dev = KFilterDev::deviceForFile( filename, mimetype, forced );
diff --git a/tdeio/tdeio/ktar.h b/tdeio/tdeio/ktar.h
index fc238073c..2ddfd602b 100644
--- a/tdeio/tdeio/ktar.h
+++ b/tdeio/tdeio/ktar.h
@@ -33,7 +33,7 @@
  * A class for reading / writing (optionally compressed) tar archives.
  *
  * KTar allows you to read and write tar archives, including those 
- * that are compressed using gzip, bzip2, or xz.
+ * that are compressed using gzip, bzip2, xz, or lzip.
  * 
  * @author Torben Weis <weis@kde.org>, David Faure <faure@kde.org>
  */
@@ -46,7 +46,7 @@ public:
      *
      * @param filename is a local path (e.g. "/home/weis/myfile.tgz")
      * @param mimetype "application/x-gzip", "application/x-bzip2",
-     * or "application/x-xz"
+     * "application/x-xz", or "application/x-lzip"
      * Do not use application/x-tgz or similar - you only need to
      * specify the compression layer !  If the mimetype is omitted, it
      * will be determined from the filename.
diff --git a/tdeio/tests/kfiltertest.cpp b/tdeio/tests/kfiltertest.cpp
index 5e0fdfba4..6f85da9a3 100644
--- a/tdeio/tests/kfiltertest.cpp
+++ b/tdeio/tests/kfiltertest.cpp
@@ -16,6 +16,8 @@
  *  Boston, MA 02110-1301, USA.
  */
 
+#include <config.h>
+
 #include "kfilterdev.h"
 #include "kfilterbase.h"
 #include <unistd.h>
@@ -86,23 +88,69 @@ void test_textstream(  const TQString & fileName )
     delete dev;
 }
 
+#if HAVE_LZIP_SUPPORT
+static bool test_truncated( const TQString & fileName )
+{
+    TQFile file( fileName );
+    if ( !file.open( IO_ReadOnly ) )
+        return false;
+
+    TQByteArray data( file.size() );
+    const TQ_LONG size = data.size();
+    if ( size <= 8 || file.readBlock( data.data(), size ) != size )
+    {
+        file.close();
+        return false;
+    }
+    file.close();
+
+    data.resize( data.size() - 8 );
+    if ( !file.open( IO_WriteOnly | IO_Truncate ) )
+        return false;
+    if ( file.writeBlock( data.data(), data.size() ) != (TQ_LONG)data.size() )
+    {
+        file.close();
+        return false;
+    }
+    file.close();
+
+    TQIODevice *dev = KFilterDev::deviceForFile( fileName );
+    if ( !dev || !dev->open( IO_ReadOnly ) )
+    {
+        delete dev;
+        return false;
+    }
+
+    TQByteArray buffer( 1024 );
+    TQ_LONG n;
+    do
+    {
+        n = dev->readBlock( buffer.data(), buffer.size() );
+    }
+    while ( n > 0 );
+
+    dev->close();
+    delete dev;
+
+    if ( n >= 0 )
+    {
+        kdWarning() << "Truncated stream was not reported as an error" << endl;
+        return false;
+    }
+    return true;
+}
+#endif
+
 int main()
 {
     TDEInstance instance("kfiltertest");
 
     char currentdir[PATH_MAX+1];
     getcwd( currentdir, PATH_MAX );
-    TQString pathgz = TQFile::decodeName(currentdir) + "/test.gz";
-    TQString pathbz2 = TQFile::decodeName(currentdir) + "/test.bz2";
-    TQString pathxz = TQFile::decodeName(currentdir) + "/test.xz";
 
+    TQString pathgz = TQFile::decodeName(currentdir) + "/test.gz";
     kdDebug() << " -- test_block_write gzip -- " << endl;
     test_block_write(pathgz);
-    kdDebug() << " -- test_block_write bzip2 -- " << endl;
-    test_block_write(pathbz2);
-    kdDebug() << " -- test_block_write xz -- " << endl;
-    test_block_write(pathxz);
-
     kdDebug() << " -- test_block gzip -- " << endl;
     test_block(pathgz);
     kdDebug() << " -- test_getch gzip -- " << endl;
@@ -110,6 +158,9 @@ int main()
     kdDebug() << " -- test_textstream gzip -- " << endl;
     test_textstream(pathgz);
 
+    TQString pathbz2 = TQFile::decodeName(currentdir) + "/test.bz2";
+    kdDebug() << " -- test_block_write bzip2 -- " << endl;
+    test_block_write(pathbz2);
     kdDebug() << " -- test_block bzip2 -- " << endl;
     test_block(pathbz2);
     kdDebug() << " -- test_getch bzip2 -- " << endl;
@@ -117,12 +168,32 @@ int main()
     kdDebug() << " -- test_textstream bzip2 -- " << endl;
     test_textstream(pathbz2);
 
+#if HAVE_XZ_SUPPORT
+    TQString pathxz = TQFile::decodeName(currentdir) + "/test.xz";
+    kdDebug() << " -- test_block_write xz -- " << endl;
+    test_block_write(pathxz);
     kdDebug() << " -- test_block xz -- " << endl;
     test_block(pathxz);
     kdDebug() << " -- test_getch xz -- " << endl;
     test_getch(pathxz);
     kdDebug() << " -- test_textstream xz -- " << endl;
     test_textstream(pathxz);
+#endif
+
+#if HAVE_LZIP_SUPPORT
+    TQString pathlz = TQFile::decodeName(currentdir) + "/test.lz";
+    kdDebug() << " -- test_block_write lzip -- " << endl;
+    test_block_write(pathlz);
+    kdDebug() << " -- test_block lzip -- " << endl;
+    test_block(pathlz);
+    kdDebug() << " -- test_getch lzip -- " << endl;
+    test_getch(pathlz);
+    kdDebug() << " -- test_textstream lzip -- " << endl;
+    test_textstream(pathlz);
+    kdDebug() << " -- test_truncated lzip -- " << endl;
+    if ( !test_truncated( pathlz ) )
+        return 1;
+#endif
 
     return 0;
 }
diff --git a/tdeioslave/CMakeLists.txt b/tdeioslave/CMakeLists.txt
index 36c54239c..929f99fd4 100644
--- a/tdeioslave/CMakeLists.txt
+++ b/tdeioslave/CMakeLists.txt
@@ -15,5 +15,6 @@ add_subdirectory( ftp )
 add_subdirectory( gzip )
 add_subdirectory( bzip2 )
 tde_conditional_add_subdirectory( WITH_LZMA xz )
+tde_conditional_add_subdirectory( WITH_LZIP lzip )
 add_subdirectory( metainfo )
 add_subdirectory( iso )
diff --git a/tdeioslave/lzip/CMakeLists.txt b/tdeioslave/lzip/CMakeLists.txt
new file mode 100644
index 000000000..57b352e08
--- /dev/null
+++ b/tdeioslave/lzip/CMakeLists.txt
@@ -0,0 +1,42 @@
+#################################################
+#
+#  Lzip compression filter
+#
+#################################################
+
+include_directories(
+  ${TQT_INCLUDE_DIRS}
+  ${LZIP_INCLUDE_DIRS}
+  ${CMAKE_BINARY_DIR}
+  ${CMAKE_BINARY_DIR}/tdecore
+  ${CMAKE_SOURCE_DIR}/tdecore
+  ${CMAKE_SOURCE_DIR}/tdeio/tdeio
+)
+
+link_directories(
+  ${TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+tde_create_translated_desktop(
+  SOURCE klzipfilter.desktop
+  DESTINATION ${SERVICES_INSTALL_DIR}
+  PO_DIR tdeioslave-desktops
+)
+
+
+##### klzipfilter ###############################
+
+set( target klzipfilter )
+
+set( ${target}_SRCS
+  klzipfilter.cpp
+)
+
+tde_add_kpart( ${target} AUTOMOC
+  SOURCES ${${target}_SRCS}
+  LINK tdeio-shared ${LZIP_LIBRARIES}
+  DESTINATION ${PLUGIN_INSTALL_DIR}
+)
diff --git a/tdeioslave/lzip/klzipfilter.cpp b/tdeioslave/lzip/klzipfilter.cpp
new file mode 100644
index 000000000..0521d6640
--- /dev/null
+++ b/tdeioslave/lzip/klzipfilter.cpp
@@ -0,0 +1,299 @@
+/* This file is part of the TDE libraries
+   Copyright (C) 2026 Sebastião Guerra <sebastiao.luiz.guerra@gmail.com>
+
+   Based on KXzFilter:
+   Copyright (C) 2007-2008 Per Øyvind Karlsen <peroyvind@mandriva.org>
+
+   Based on KBzip2Filter:
+   Copyright (C) 2000-2005 David Faure <faure@kde.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#include "klzipfilter.h"
+#include <klibloader.h>
+
+#include <stdint.h>
+extern "C" {
+#include <lzlib.h>
+}
+
+#include <kdebug.h>
+#include <tqiodevice.h>
+
+class KLzipFilterFactory : public KLibFactory
+{
+public:
+    KLzipFilterFactory() : KLibFactory() {}
+    virtual ~KLzipFilterFactory() {}
+    TQObject *createObject( TQObject *, const char *, const char*, const TQStringList & )
+    {
+        return new KLzipFilter;
+    }
+};
+
+K_EXPORT_COMPONENT_FACTORY( klzipfilter, KLzipFilterFactory )
+
+
+class KLzipFilter::Private
+{
+public:
+    Private()
+        : encoder( 0 ), decoder( 0 ), nextIn( 0 ), availIn( 0 ),
+          nextOut( 0 ), availOut( 0 ), mode( 0 ), initialized( false ),
+          inputFinished( false ), finishCalled( false )
+    {
+    }
+
+    struct LZ_Encoder *encoder;
+    struct LZ_Decoder *decoder;
+    const uint8_t *nextIn;
+    uint availIn;
+    uint8_t *nextOut;
+    uint availOut;
+    int mode;
+    bool initialized;
+    bool inputFinished;
+    bool finishCalled;
+};
+
+
+KLzipFilter::KLzipFilter()
+    : d( new Private )
+{
+}
+
+
+KLzipFilter::~KLzipFilter()
+{
+    terminate();
+    delete d;
+}
+
+
+void KLzipFilter::init( int mode )
+{
+    if ( d->initialized || d->encoder || d->decoder )
+        terminate();
+
+    d->mode = mode;
+    d->nextIn = 0;
+    d->availIn = 0;
+    d->inputFinished = false;
+    d->finishCalled = false;
+
+    if ( mode == IO_ReadOnly )
+    {
+        d->decoder = LZ_decompress_open();
+        d->initialized = d->decoder && LZ_decompress_errno( d->decoder ) == LZ_ok;
+        if ( !d->initialized )
+            kdWarning(7005) << "Unable to initialize Lzip decoder" << endl;
+    }
+    else if ( mode == IO_WriteOnly )
+    {
+        // Match lzip's default level -6: 8 MiB dictionary and match length 36.
+        // The 2 PiB member limit is also lzip's default.
+        d->encoder = LZ_compress_open( 1 << 23, 36, 1ULL << 51 );
+        d->initialized = d->encoder && LZ_compress_errno( d->encoder ) == LZ_ok;
+        if ( !d->initialized )
+            kdWarning(7005) << "Unable to initialize Lzip encoder" << endl;
+    }
+    else
+    {
+        kdWarning(7005) << "KLzipFilter: Unsupported mode " << mode
+                        << ". Only IO_ReadOnly and IO_WriteOnly supported" << endl;
+    }
+}
+
+
+int KLzipFilter::mode() const
+{
+    return d->mode;
+}
+
+
+void KLzipFilter::terminate()
+{
+    if ( d->encoder )
+    {
+        LZ_compress_close( d->encoder );
+        d->encoder = 0;
+    }
+    if ( d->decoder )
+    {
+        LZ_decompress_close( d->decoder );
+        d->decoder = 0;
+    }
+
+    d->nextIn = 0;
+    d->availIn = 0;
+    d->initialized = false;
+    d->inputFinished = false;
+    d->finishCalled = false;
+}
+
+
+void KLzipFilter::reset()
+{
+    const int oldMode = d->mode;
+    terminate();
+    init( oldMode );
+}
+
+
+void KLzipFilter::setOutBuffer( char * data, uint maxlen )
+{
+    d->nextOut = reinterpret_cast<uint8_t *>( data );
+    d->availOut = maxlen;
+}
+
+
+void KLzipFilter::setInBuffer( const char * data, uint size )
+{
+    d->nextIn = reinterpret_cast<const uint8_t *>( data );
+    d->availIn = size;
+}
+
+
+int KLzipFilter::inBufferAvailable() const
+{
+    return d->availIn;
+}
+
+
+int KLzipFilter::outBufferAvailable() const
+{
+    return d->availOut;
+}
+
+
+KLzipFilter::Result KLzipFilter::uncompress()
+{
+    if ( !d->initialized || !d->decoder )
+        return ERROR;
+
+    if ( d->availIn )
+    {
+        const int written = LZ_decompress_write( d->decoder, d->nextIn,
+                                                static_cast<int>( d->availIn ) );
+        if ( written < 0 )
+        {
+            kdWarning(7005) << "LZ_decompress_write failed: "
+                            << LZ_strerror( LZ_decompress_errno( d->decoder ) ) << endl;
+            return ERROR;
+        }
+        d->nextIn += written;
+        d->availIn -= written;
+    }
+
+    // lzlib needs to be told explicitly when no more compressed input
+    // will arrive so it can validate the final member and detect
+    // truncated input.
+    if ( !d->inputFinished &&
+         d->availIn == 0 &&
+         device() &&
+         device()->atEnd() )
+    {
+        LZ_decompress_finish( d->decoder );
+        d->inputFinished = true;
+    }
+
+    while ( d->availOut )
+    {
+        const int received = LZ_decompress_read( d->decoder, d->nextOut,
+                                                static_cast<int>( d->availOut ) );
+        if ( received < 0 || LZ_decompress_errno( d->decoder ) != LZ_ok )
+        {
+            kdWarning(7005) << "LZ_decompress_read failed: "
+                            << LZ_strerror( LZ_decompress_errno( d->decoder ) ) << endl;
+            return ERROR;
+        }
+
+        d->nextOut += received;
+        d->availOut -= received;
+
+        if ( LZ_decompress_finished( d->decoder ) == 1 )
+            return END;
+
+        const bool memberFinished =
+            LZ_decompress_member_finished( d->decoder ) == 1;
+
+        // Lzlib deliberately makes LZ_decompress_read() return at least once
+        // for each member.  In particular it may return 0 at a member
+        // boundary even when another concatenated member is already buffered.
+        // Keep reading across that boundary instead of exposing a false EOF to
+        // KFilterDev.
+        if ( memberFinished )
+            continue;
+
+        if ( received == 0 || !d->inputFinished )
+            break;
+    }
+
+    return OK;
+}
+
+
+KLzipFilter::Result KLzipFilter::compress( bool finish )
+{
+    if ( !d->initialized || !d->encoder )
+        return ERROR;
+
+    if ( d->availIn )
+    {
+        const int written = LZ_compress_write( d->encoder, d->nextIn,
+                                              static_cast<int>( d->availIn ) );
+        if ( written < 0 )
+        {
+            kdWarning(7005) << "LZ_compress_write failed: "
+                            << LZ_strerror( LZ_compress_errno( d->encoder ) ) << endl;
+            return ERROR;
+        }
+        d->nextIn += written;
+        d->availIn -= written;
+    }
+
+    if ( finish && !d->finishCalled && d->availIn == 0 )
+    {
+        LZ_compress_finish( d->encoder );
+        if ( LZ_compress_errno( d->encoder ) != LZ_ok )
+        {
+            kdWarning(7005) << "LZ_compress_finish failed: "
+                            << LZ_strerror( LZ_compress_errno( d->encoder ) ) << endl;
+            return ERROR;
+        }
+        d->finishCalled = true;
+    }
+
+    if ( d->availOut )
+    {
+        const int produced = LZ_compress_read( d->encoder, d->nextOut,
+                                              static_cast<int>( d->availOut ) );
+        if ( produced < 0 || LZ_compress_errno( d->encoder ) != LZ_ok )
+        {
+            kdWarning(7005) << "LZ_compress_read failed: "
+                            << LZ_strerror( LZ_compress_errno( d->encoder ) ) << endl;
+            return ERROR;
+        }
+        d->nextOut += produced;
+        d->availOut -= produced;
+    }
+
+    if ( d->finishCalled && LZ_compress_finished( d->encoder ) == 1 )
+        return END;
+
+    return OK;
+}
diff --git a/tdeioslave/lzip/klzipfilter.desktop b/tdeioslave/lzip/klzipfilter.desktop
new file mode 100644
index 000000000..07fb94ae3
--- /dev/null
+++ b/tdeioslave/lzip/klzipfilter.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Type=Service
+Name=Lzip Filter
+X-TDE-Library=klzipfilter
+X-TDE-ServiceTypes=TDECompressionFilter,application/x-lzip,application/x-tlz
diff --git a/tdeioslave/lzip/klzipfilter.h b/tdeioslave/lzip/klzipfilter.h
new file mode 100644
index 000000000..962feff59
--- /dev/null
+++ b/tdeioslave/lzip/klzipfilter.h
@@ -0,0 +1,59 @@
+/* This file is part of the TDE libraries
+   Copyright (C) 2026 Sebastião Guerra <sebastiao.luiz.guerra@gmail.com>
+
+   Based on KXzFilter:
+   Copyright (C) 2007-2008 Per Øyvind Karlsen <peroyvind@mandriva.org>
+
+   Based on KBzip2Filter:
+   Copyright (C) 2000 David Faure <faure@kde.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public License
+   along with this library; see the file COPYING.LIB.  If not, write to
+   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLZIPFILTER_H
+#define KLZIPFILTER_H
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KFilterDev for Lzip streams.
+ * @internal
+ */
+class KLzipFilter : public KFilterBase
+{
+public:
+    KLzipFilter();
+    virtual ~KLzipFilter();
+
+    virtual void init( int mode );
+    virtual int mode() const;
+    virtual void terminate();
+    virtual void reset();
+    virtual bool readHeader() { return true; }
+    virtual bool writeHeader( const TQCString & ) { return true; }
+    virtual void setOutBuffer( char * data, uint maxlen );
+    virtual void setInBuffer( const char * data, uint size );
+    virtual int inBufferAvailable() const;
+    virtual int outBufferAvailable() const;
+    virtual Result uncompress();
+    virtual Result compress( bool finish );
+
+private:
+    class Private;
+    Private* const d;
+};
+
+#endif // KLZIPFILTER_H
diff --git a/tdeioslave/xz/kxzfilter.cpp b/tdeioslave/xz/kxzfilter.cpp
index 2172ce2c8..f9aa641d7 100644
--- a/tdeioslave/xz/kxzfilter.cpp
+++ b/tdeioslave/xz/kxzfilter.cpp
@@ -23,8 +23,6 @@
 #include "kxzfilter.h"
 #include <klibloader.h>
 
-#include <config.h>
-#if HAVE_XZ_SUPPORT
 extern "C" {
 	#include <lzma.h>
 }
@@ -185,5 +183,3 @@ KXzFilter::Result KXzFilter::compress( bool finish )
                 break;
     }
 }
-
-#endif  /* HAVE_XZ_SUPPORT */
diff --git a/tdeioslave/xz/kxzfilter.h b/tdeioslave/xz/kxzfilter.h
index b2ef164ae..cb7e675e0 100644
--- a/tdeioslave/xz/kxzfilter.h
+++ b/tdeioslave/xz/kxzfilter.h
@@ -23,9 +23,6 @@
 #ifndef KXZFILTER_H
 #define KXZFILTER_H
 
-#include <config.h>
-#if HAVE_XZ_SUPPORT
-
 #include "kfilterbase.h"
 
 /**
@@ -55,6 +52,4 @@ private:
     Private* const d;
 };
 
-#endif
-
 #endif // KXZFILTER_H
-- 
cgit v1.2.3

