]> git.ipfire.org Git - thirdparty/sarg.git/commitdiff
Add support to decompress xz files master
authorFrederic Marchal <fmarchal@users.sourceforge.net>
Sun, 30 Oct 2016 10:53:21 +0000 (11:53 +0100)
committerFrederic Marchal <fmarchal@users.sourceforge.net>
Sun, 30 Oct 2016 10:53:21 +0000 (11:53 +0100)
Xz files are supported if liblzma is available when compiling sarg.

configure.ac
decomp.c

index e084593ba2eb8af3e0d40bb332da8bd555025a91..1a598ad13a86393d497e576dd64cb33d01d8a6b2 100644 (file)
@@ -222,6 +222,30 @@ AS_IF([test "x$with_bzlib" != "xno" ],
        bzlib_status="disabled"
 ])
 
+# Build with liblzma
+AC_ARG_WITH([liblzma],
+       AS_HELP_STRING([--with-liblzma],[Compile with support to decompress xz files]),
+       [],[with_liblzma=check])
+AS_IF([test "x$with_liblzma" != "xno" ],
+[
+       AC_CHECK_HEADERS(lzma.h)
+       AS_IF([test "x$ac_cv_header_lzma_h" = "xyes"],
+       [
+               AC_CHECK_LIB([lzma],[lzma_stream_decoder],
+               [
+                       LIBS="-llzma ${LIBS}"
+                       HAVE_LIBLZMA_LIB="yes"
+               ],[
+                       HAVE_LIBLZMA_LIB=""
+               ])
+               AS_IF([test "x$HAVE_LIBLZMA_LIB" != "xyes"],[AC_MSG_ERROR([liblzma was not found])])
+       ],[
+               liblzma_status="not found"
+       ])
+],[
+       liblzma_status="disabled"
+])
+
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_STRUCT_TM
@@ -480,3 +504,9 @@ AS_IF([test "x$bzlib_status" = "xdisabled"],[
 ],[test "x$bzlib_status" = "xnot found"],[
        AC_MSG_NOTICE([bzlib.h was not found so it won't be possible to process bzipped files])
 ])
+
+AS_IF([test "x$liblzma_status" = "xdisabled"],[
+       AC_MSG_NOTICE([Not building with liblzma as requested on the configuration command line])
+],[test "x$liblzma_status" = "xnot found"],[
+       AC_MSG_NOTICE([lzma.h was not found so it won't be possible to process xz files])
+])
index 93d5de2cd47c2b0a4a18023de248128397cfce22..36a3f0e7d3c41b12ac5f3ad14ecf8497832092e7 100644 (file)
--- a/decomp.c
+++ b/decomp.c
@@ -32,6 +32,9 @@
 #ifdef HAVE_BZLIB_H
 #include "bzlib.h"
 #endif
+#ifdef HAVE_LZMA_H
+#include "lzma.h"
+#endif
 
 #ifdef HAVE_ZLIB_H
 /*!
@@ -277,6 +280,193 @@ static FileObject *Bzip_Open(int fd)
 }
 #endif
 
+#ifdef HAVE_LZMA_H
+
+struct LzmaInternalFile
+{
+       //! Lzma stream.
+       lzma_stream Stream;
+       //! \c True if end of file is reached.
+       bool Eof;
+       //! Original file in case a rewind is necessary.
+       FILE *File;
+       //! Input buffer to store data read from the log file.
+       unsigned char InputBuffer[128*1024];
+};
+
+/*!
+ * Read from xz file.
+ *
+ * \param Data The file object.
+ * \param Buffer The boffer to store the data read.
+ * \param Size How many bytes to read.
+ *
+ * \return The number of bytes read.
+ */
+static int Lzma_Read(void *Data,void *Buffer,int Size)
+{
+       struct LzmaInternalFile *BData=(struct LzmaInternalFile *)Data;
+       lzma_ret zerr;
+
+       BData->Stream.next_out=Buffer;
+       BData->Stream.avail_out=Size;
+       while (BData->Stream.avail_out>0 && !BData->Eof)
+       {
+               if (BData->Stream.avail_in==0 && !BData->Eof)
+               {
+                       BData->Stream.next_in=BData->InputBuffer;
+                       BData->Stream.avail_in=fread(BData->InputBuffer,1,sizeof(BData->InputBuffer),BData->File);
+                       if (feof(BData->File))
+                               BData->Eof=true;
+               }
+               zerr=lzma_code(&BData->Stream,(BData->Eof) ? LZMA_FINISH : LZMA_RUN);
+               if (zerr==LZMA_STREAM_END)
+               {
+                       BData->Eof=true;
+               }
+               else if (zerr!=LZMA_OK)
+               {
+                       debuga(__FILE__,__LINE__,_("Error decompressiong xz file (lzma library returned error %d)"),zerr);
+                       return(0);
+               }
+       }
+       return(Size-BData->Stream.avail_out);
+}
+
+/*!
+ * Check if end of file is reached.
+ *
+ * \param Data The file object.
+ *
+ * \return \c True if end of file is reached.
+ */
+static int Lzma_Eof(void *Data)
+{
+       struct LzmaInternalFile *BData=(struct LzmaInternalFile *)Data;
+       return(BData->Eof);
+}
+
+/*!
+ * Initialize the lzma decoding stream.
+ *
+ * \param Stream Lzma stream to initialize.
+ *
+ * \return 0 on success or -1 if the intialization failed. A suitable
+ * error message is displayed in case of error.
+ */
+static int Lzma_InitDecoder(lzma_stream *Stream)
+{
+       lzma_ret zerr;
+
+       zerr=lzma_stream_decoder(Stream,UINT64_MAX,LZMA_CONCATENATED);
+       if (zerr!=LZMA_OK)
+       {
+               switch (zerr)
+               {
+                       case LZMA_MEM_ERROR:
+                               FileObject_SetLastOpenError(_("Not enough memory to initialize LZMA decoder"));
+                               break;
+                       case LZMA_OPTIONS_ERROR:
+                               FileObject_SetLastOpenError(_("Failed to initialize LZMA decoder due to invalid option passed to the decoder"));
+                               break;
+                       default:
+                       {
+                               char ErrMsg[80];
+
+                               snprintf(ErrMsg,sizeof(ErrMsg),_("Failed to initialize LZMA decoder with unknown error %d"),zerr);
+                               FileObject_SetLastOpenError(ErrMsg);
+                               break;
+                       }
+               }
+               return(-1);
+       }
+       return(0);
+}
+
+/*!
+ * Return to the beginnig of the file.
+ *
+ * \param Data The file object.
+ */
+static void Lzma_Rewind(void *Data)
+{
+       struct LzmaInternalFile *BData=(struct LzmaInternalFile *)Data;
+
+       rewind(BData->File);
+       BData->Eof=false;
+       memset(&BData->Stream,0,sizeof(BData->Stream));
+       if (Lzma_InitDecoder(&BData->Stream)<0)
+       {
+               debuga(__FILE__,__LINE__,_("Failed to rewind the xz file (see previous LZMA error)\n"));
+               exit(EXIT_FAILURE);
+       }
+}
+
+/*!
+ * Close the file.
+ *
+ * \param Data File to close.
+ *
+ * \return 0 on success or -1 on error.
+ */
+static int Lzma_Close(void *Data)
+{
+       struct LzmaInternalFile *BData=(struct LzmaInternalFile *)Data;
+
+       fclose(BData->File);
+       lzma_end(&BData->Stream);
+       free(BData);
+       return(0);
+}
+
+/*!
+ * Open a file object to read from a xz file.
+ *
+ * \return The object to pass to other function in this module.
+ */
+static FileObject *Lzma_Open(int fd)
+{
+       FileObject *File;
+       struct LzmaInternalFile *BData;
+
+       FileObject_SetLastOpenError(NULL);
+       File=calloc(1,sizeof(*File));
+       if (!File)
+       {
+               FileObject_SetLastOpenError(_("Not enough memory"));
+               return(NULL);
+       }
+       BData=calloc(1,sizeof(*BData));
+       if (!BData)
+       {
+               free(File);
+               FileObject_SetLastOpenError(_("Not enough memory"));
+               return(NULL);
+       }
+       BData->File=fdopen(fd,"rb");
+       if (BData->File==NULL)
+       {
+               free(BData);
+               free(File);
+               FileObject_SetLastOpenError(_("Error duplicating file descriptor"));
+               return(NULL);
+       }
+       if (Lzma_InitDecoder(&BData->Stream)<0)
+       {
+               fclose(BData->File);
+               free(BData);
+               free(File);
+               return(NULL);
+       }
+       File->Data=BData;
+       File->Read=Lzma_Read;
+       File->Eof=Lzma_Eof;
+       File->Rewind=Lzma_Rewind;
+       File->Close=Lzma_Close;
+       return(File);
+}
+#endif
+
 
 /*!
 Open the log file. If it is compressed, uncompress it with the proper library.
@@ -292,7 +482,7 @@ FileObject *decomp(const char *arq)
 {
        int fd;
        FileObject *fi;
-       unsigned char buf[3];
+       unsigned char buf[5];
        ssize_t nread;
 
        // guess file type
@@ -306,7 +496,7 @@ FileObject *decomp(const char *arq)
                debuga(__FILE__,__LINE__,_("Error while reading \"%s\" to guess its type: %s\n"),arq,strerror(errno));
                exit(EXIT_FAILURE);
        }
-       if (nread<3) {
+       if (nread<sizeof(buf)) {
                debuga(__FILE__,__LINE__,_("File \"%s\" is too small to guess its type\n"),arq);
                exit(EXIT_FAILURE);
        }
@@ -331,6 +521,15 @@ FileObject *decomp(const char *arq)
 #else
                debuga(__FILE__,__LINE__,_("Sarg was not compiled with bzip support to read file \"%s\"\n"),arq);
                exit(EXIT_FAILURE);
+#endif
+       }
+       else if (buf[0]==0xFD && buf[1]=='7' && buf[2]=='z' && buf[3]=='X' && buf[4]=='Z')//xz file
+       {
+#ifdef HAVE_LZMA_H
+               fi=Lzma_Open(fd);
+#else
+               debuga(__FILE__,__LINE__,_("Sarg was not compiled with xz support to read file \"%s\"\n"),arq);
+               exit(EXIT_FAILURE);
 #endif
        }
        else if (buf[0]==0x1F && (buf[1]==0x9D || buf[1]==0xA0))//LZW and LZH compressed file