[Forensics-changes] [SCM] debian-forensics/guymager branch, debian, updated. debian/0.5.9-3-7-g6e5e5c5

Michael Prokop mika at debian.org
Thu Mar 1 14:43:45 UTC 2012


The following commit has been merged in the debian branch:
commit 9cc475cb5f794054ef051046d97ec2983ccfd8fd
Author: Michael Prokop <mika at debian.org>
Date:   Thu Mar 1 12:00:50 2012 +0100

    Merging upstream version 0.6.5

diff --git a/aaff.cpp b/aaff.cpp
index 6ddb702..d221cfd 100644
--- a/aaff.cpp
+++ b/aaff.cpp
@@ -6,10 +6,10 @@
 //                  Service de Police Judiciaire
 //                  Section Nouvelles Technologies
 // ****************************************************************************
-//  Module:         Multithreaded AFF (AAFF = Avanced AFF)
+//  Module:         Multithreaded AFF (AAFF = Advanced AFF)
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -31,7 +31,7 @@
 
 #include <netinet/in.h>
 #include <string.h>
-#include <time.h>    //lint !e537 repeated include file
+#include <time.h>    //lint !e537 !e451 repeated include file
 #include <stdlib.h>
 #include <zlib.h>
 
@@ -78,8 +78,8 @@ typedef struct
    unsigned int NameLen;
    unsigned int DataLen;
    unsigned int Argument;          // Named "flags" in original aff source, named "arg" in afinfo output.
-   char         Name[];
-} t_AffSegmentHeader;
+   char         Name[];            //lint !e1501
+} __attribute__ ((packed)) t_AffSegmentHeader;
 
 // Between header and footer lie the segment name and the data
 
@@ -87,7 +87,7 @@ typedef struct
 {
    char         Magic[4];
    unsigned int SegmentLen;
-} t_AffSegmentFooter;
+} __attribute__ ((packed)) t_AffSegmentFooter;
 
 
 // ------------------
@@ -100,11 +100,16 @@ typedef struct _t_Aaff
    bool                 OpenedForWrite;
    unsigned long long   PagesWritten;
    unsigned long long   PagesRead;
+   t_HashContextMD5     HashContextMD5; // For image file MD5 calculation during verification
+   QString            *pFilename;
+
 
    t_AffSegmentHeader   SegmentHeader;  // Optimisation: This header and this footer only need to be
    t_AffSegmentFooter   SegmentFooter;  // allocated and initialised once, and can be used again and again
    unsigned char      *pUncompressBuffer;
    unsigned int         UncompressBufferLen;
+   unsigned long long   BytesVerified;
+   unsigned long long   DeviceSize;
 } t_Aaff;
 
 #define AAFF_MD5_LEN                16
@@ -120,33 +125,6 @@ unsigned char AaffBadSectorMarker[AAFF_BADSECTORMARKER_MAXLEN];
    if ((Fn) != 1)                         \
       CHK (ERROR_AAFF_CANNOT_WRITE_FILE)
 
-
-// -------------------
-//  Utility functions
-// -------------------
-
-static bool AaffIsZero (unsigned char *pData, unsigned int DataLen)
-{
-   long long          *pBuff    = (long long *)pData;   //lint !e826   Suspicious pointer-to-pointer conversion
-   const unsigned int   CmpSize = sizeof (long long);   // 64 bit operations for optimal performance on amd64 processors
-
-   while (DataLen >= CmpSize)
-   {
-      if (*pBuff++)
-        return false;
-      DataLen -= CmpSize;
-   }
-
-   pData = (unsigned char *) pBuff;
-   while (DataLen--)
-   {
-      if (*pData++)
-         return false;
-   }
-
-   return true;
-}
-
 // -------------------
 //  Segment functions
 // -------------------
@@ -226,22 +204,32 @@ APIRET AaffCopyBadSectorMarker (unsigned char *pBuffer, unsigned int Len)
 
 static APIRET AaffCreateHandle (t_pAaff *ppAaff)
 {
-   *ppAaff = (t_pAaff) UTIL_MEM_ALLOC(sizeof(t_Aaff));
-   if (*ppAaff == NULL)
+   t_pAaff pAaff;
+
+   pAaff = (t_pAaff) UTIL_MEM_ALLOC(sizeof(t_Aaff));
+   if (pAaff == NULL)
       CHK (ERROR_AAFF_MEMALLOC_FAILED)
 
-   memset (*ppAaff, 0, sizeof(t_Aaff));
+   memset (pAaff, 0, sizeof(t_Aaff));
+
+   pAaff->pFilename = new QString;
+
+   *ppAaff = pAaff;
 
    return NO_ERROR;
 }
 
 static APIRET AaffDestroyHandle (t_pAaff *ppAaff)
 {
-   if ((*ppAaff)->pUncompressBuffer)
-      free ((*ppAaff)->pUncompressBuffer);  // Must released with free, as realloc is used for allocating it
+   t_pAaff pAaff = *ppAaff;
+
+   if (pAaff->pUncompressBuffer)
+      free (pAaff->pUncompressBuffer);  // Must released with free, as realloc is used for allocating it
 
-   memset (*ppAaff, 0, sizeof(t_Aaff));
-   UTIL_MEM_FREE (*ppAaff);
+   delete pAaff->pFilename;
+
+   memset (pAaff, 0, sizeof(t_Aaff));
+   UTIL_MEM_FREE (pAaff);
    *ppAaff = NULL;
 
    return NO_ERROR;
@@ -262,6 +250,7 @@ APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long Devi
 
    CHK (AaffCreateHandle (&pAaff))
 
+   *(pAaff->pFilename) = pFilename;
    pAaff->OpenedForWrite = true;
    pAaff->pFile = fopen64 (pFilename, "w");
    if (pAaff->pFile == NULL)
@@ -296,14 +285,14 @@ APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long Devi
 }
 //lint -restore
 
-APIRET AaffClose (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, int Duration)
+APIRET AaffClose (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, uint Duration)
 {
    t_pAaff pAaff = *ppAaff;
 
-   CHK (AaffWriteSegmentU64 (pAaff, AFF_SEGNAME_BADSECTORS  , BadSectors))
-   CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_MD5         , 0, pMD5   , AAFF_MD5_LEN   ))
-   CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_SHA256      , 0, pSHA256, AAFF_SHA256_LEN))
-   CHK (AaffWriteSegmentArg (pAaff, AFF_SEGNAME_DURATION    , Duration))
+   CHK (AaffWriteSegmentU64 (pAaff, AFF_SEGNAME_BADSECTORS, BadSectors))
+   CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_MD5       , 0, pMD5   , AAFF_MD5_LEN   ))
+   CHK (AaffWriteSegment    (pAaff, AFF_SEGNAME_SHA256    , 0, pSHA256, AAFF_SHA256_LEN))
+   CHK (AaffWriteSegmentArg (pAaff, AFF_SEGNAME_DURATION  , Duration))
 
    if (fflush (pAaff->pFile))
    {
@@ -320,7 +309,7 @@ APIRET AaffClose (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned
 }
 
 //lint -save -esym(613,pPreProcess)   Possible use of null pointer
-APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut)
+APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, uint DataLenOut)
 {
    t_pAaffPreprocess pPreProcess;
    int                rc;
@@ -336,7 +325,7 @@ APIRET AaffPreprocess (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn,
 
    // Check if zero
    // -------------
-   pPreProcess->Zero = AaffIsZero (pDataIn, DataLenIn);
+   pPreProcess->Zero = UtilIsZero (pDataIn, DataLenIn);
    if (pPreProcess->Zero)
       return NO_ERROR;
 
@@ -382,7 +371,54 @@ APIRET AaffWrite (t_pAaff pAaff, t_pAaffPreprocess pPreprocess, const unsigned c
 //  API read functions
 // ---------------------
 
-APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename)
+static APIRET AaffReallocUncompressBuffer (t_pAaff pAaff, unsigned int NewLen)
+{
+   if (NewLen > pAaff->UncompressBufferLen)
+   {
+      pAaff->pUncompressBuffer = (unsigned char *) realloc (pAaff->pUncompressBuffer, NewLen);
+      if (pAaff->pUncompressBuffer == NULL)
+         return ERROR_AAFF_MEMALLOC_FAILED;
+      pAaff->UncompressBufferLen = NewLen;
+   }
+   return NO_ERROR;
+}
+
+static unsigned long long AaffGetCurrentSeekPos (t_Aaff *pAaff)
+{
+   return ftello64 (pAaff->pFile);
+}
+
+APIRET AaffGetImageFileSize  (t_Aaff *pAaff, unsigned long long *pSize)
+{
+   unsigned long long CurrentSeekPos;
+   int                rc;
+
+   CurrentSeekPos = AaffGetCurrentSeekPos (pAaff);
+   rc = fseeko64 (pAaff->pFile, 0, SEEK_END);
+   if (rc)
+      return ERROR_AAFF_CANNOT_SEEK;
+
+   *pSize = AaffGetCurrentSeekPos (pAaff);
+
+   rc = fseeko64 (pAaff->pFile, CurrentSeekPos, SEEK_SET);
+   if (rc)
+      return ERROR_AAFF_CANNOT_SEEK;
+
+   return NO_ERROR;
+}
+
+static APIRET AaffReadFile (t_Aaff *pAaff, void *pData, unsigned int DataLen)
+{
+   if (fread (pData, DataLen, 1, pAaff->pFile) != 1)
+      CHK (ERROR_AAFF_CANNOT_READ_DATA)
+
+   if (CONFIG(CalcImageFileMD5))
+      CHK (HashMD5Append (&pAaff->HashContextMD5, pData, DataLen))
+
+   return NO_ERROR;
+}
+
+APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize)
 {
    t_pAaff pAaff;
    char     Signature[strlen(AFF_HEADER)+1];
@@ -394,6 +430,13 @@ APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename)
    pAaff->pUncompressBuffer   = NULL;
    pAaff->UncompressBufferLen = 0;
    pAaff->PagesRead           = 0;
+   pAaff->BytesVerified       = 0;
+   pAaff->DeviceSize          = DeviceSize;
+   *(pAaff->pFilename)        = pFilename;
+
+   if (CONFIG(CalcImageFileMD5))
+      CHK (HashMD5Init (&pAaff->HashContextMD5))
+
    pAaff->pFile = fopen64 (pFilename, "r");
    if (pAaff->pFile == NULL)
    {
@@ -403,9 +446,7 @@ APIRET AaffOpen (t_pAaff *ppAaff, const char *pFilename)
 
    // Check signature
    // ---------------
-   if (fread (&Signature, sizeof(Signature), 1, pAaff->pFile) != 1)
-      return ERROR_AAFF_CANNOT_READ_SIGNATURE;
-
+   CHK (AaffReadFile (pAaff, &Signature, sizeof(Signature)))
    if (memcmp (Signature, AFF_HEADER, sizeof(Signature)) != 0)
       return ERROR_AAFF_INVALID_SIGNATURE;
 
@@ -425,7 +466,7 @@ APIRET AaffClose (t_pAaff *ppAaff)
 }
 
 
-APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDataLen)
+APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDataLen, QString *pImageFilename, t_pHashMD5Digest pMD5Digest, bool *pMD5Valid)
 {
    t_AffSegmentHeader Header;
    t_AffSegmentFooter Footer;
@@ -435,13 +476,16 @@ APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDat
    bool               Found=false;
    uLongf             DataLen = *pDataLen;
    int                rc;
+   unsigned long long BytesToNextHeader;
+
+   *pImageFilename = QString();
+   *pMD5Valid      = false;
 
    // Search for the next segment whose name starts with "page"
    // ---------------------------------------------------------
    do
    {
-      if (fread  (&Header, offsetof(t_AffSegmentHeader, Name), 1, pAaff->pFile) != 1)
-         return ERROR_AAFF_CANNOT_READ_HEADER;
+      CHK (AaffReadFile (pAaff, &Header, offsetof(t_AffSegmentHeader, Name)))
       if (strcmp (&Header.Magic[0], AFF_SEGMENT_HEADER_MAGIC) != 0)
          return ERROR_AAFF_INVALID_HEADER;
       Header.NameLen  = ntohl (Header.NameLen );
@@ -451,8 +495,7 @@ APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDat
       if (Header.NameLen >= sizeof(SegmentName))
          return ERROR_AAFF_INVALID_SEGMENT_NAME;
 
-      if (fread  (&SegmentName[0], Header.NameLen, 1, pAaff->pFile) != 1)
-         return ERROR_AAFF_CANNOT_READ_HEADER;
+      CHK (AaffReadFile (pAaff, &SegmentName[0], Header.NameLen))
       SegmentName[Header.NameLen] = '\0';
 
       Found            = (strncmp (&SegmentName[0], AFF_SEGNAME_PAGE, strlen(AFF_SEGNAME_PAGE)) == 0); // The segment name must start with "page"
@@ -461,9 +504,18 @@ APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDat
 
       if (!Found)
       {
-         rc = fseeko64 (pAaff->pFile, Header.DataLen+sizeof(t_AffSegmentFooter), SEEK_CUR);
-         if (rc)
-            return ERROR_AAFF_CANNOT_SEEK;
+         BytesToNextHeader = Header.DataLen + sizeof(t_AffSegmentFooter);
+         if (CONFIG (CalcImageFileMD5))          // Read the data between current pos and next header in order have image file MD5 calculated correctly
+         {
+            CHK (AaffReallocUncompressBuffer (pAaff, BytesToNextHeader))
+            CHK (AaffReadFile                (pAaff, pAaff->pUncompressBuffer, BytesToNextHeader))
+         }
+         else                                   // Simply seek to next header, which is faster
+         {
+            rc = fseeko64 (pAaff->pFile, BytesToNextHeader, SEEK_CUR);
+            if (rc)
+               return ERROR_AAFF_CANNOT_SEEK;
+         }
       }
    } while (!Found);
 
@@ -483,29 +535,19 @@ APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDat
    switch (Header.Argument)
    {
       case AFF_PAGEFLAGS_UNCOMPRESSED:
-         if (fread (pData, Header.DataLen, 1, pAaff->pFile) != 1)
-            return ERROR_AAFF_CANNOT_READ_DATA;
+         CHK (AaffReadFile (pAaff, pData, Header.DataLen))
          *pDataLen = Header.DataLen;
          break;
       case AFF_PAGEFLAGS_COMPRESSED_ZERO:
          unsigned int Len;
-         if (fread (&Len, sizeof(Len), 1, pAaff->pFile) != 1)
-            return ERROR_AAFF_CANNOT_READ_DATA;
+         CHK (AaffReadFile (pAaff, &Len, sizeof(Len)))
          Len = ntohl (Len);
          memset (pData, 0, Len);
          *pDataLen = Len;
          break;
       case AFF_PAGEFLAGS_COMPRESSED_ZLIB:
-         if (pAaff->UncompressBufferLen < Header.DataLen)
-         {
-            pAaff->pUncompressBuffer = (unsigned char *) realloc (pAaff->pUncompressBuffer, Header.DataLen);
-            if (pAaff->pUncompressBuffer == NULL)
-               CHK (ERROR_AAFF_MEMALLOC_FAILED)
-            pAaff->UncompressBufferLen = Header.DataLen;
-         }
-         if (fread (pAaff->pUncompressBuffer, Header.DataLen, 1, pAaff->pFile) != 1)
-            return ERROR_AAFF_CANNOT_READ_DATA;
-
+         CHK (AaffReallocUncompressBuffer (pAaff, Header.DataLen))
+         CHK (AaffReadFile                (pAaff, pAaff->pUncompressBuffer, Header.DataLen))
          rc = uncompress (pData, &DataLen, pAaff->pUncompressBuffer, Header.DataLen);
          *pDataLen = DataLen;
          if (rc != Z_OK)
@@ -521,8 +563,7 @@ APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDat
 
    // Check footer
    // ------------
-   if (fread (&Footer, sizeof(Footer), 1, pAaff->pFile) != 1)
-      return ERROR_AAFF_CANNOT_READ_FOOTER;
+   CHK (AaffReadFile (pAaff, &Footer, sizeof(Footer)))
    if (strcmp (&Footer.Magic[0], AFF_SEGMENT_FOOTER_MAGIC) != 0)
       return ERROR_AAFF_INVALID_FOOTER;
 
@@ -530,43 +571,62 @@ APIRET AaffReadNextPage (t_pAaff pAaff, unsigned char *pData, unsigned int *pDat
    if (ntohl(Footer.SegmentLen) != SegmentLen)
       return ERROR_AAFF_INVALID_SEGMENTLEN;
 
+   // Check if all data has been read
+   // -------------------------------
+   pAaff->BytesVerified += *pDataLen;
+   if (pAaff->BytesVerified == pAaff->DeviceSize)
+   {
+      if (CONFIG(CalcImageFileMD5))
+      {
+         unsigned long long ImageFileSize;
+         unsigned long long BytesRemaining;
+
+         CHK (AaffGetImageFileSize(pAaff, &ImageFileSize))
+         BytesRemaining = ImageFileSize - AaffGetCurrentSeekPos(pAaff);
+         CHK (AaffReadFile (pAaff, pAaff->pUncompressBuffer, BytesRemaining))
+         CHK (HashMD5Digest (&pAaff->HashContextMD5, pMD5Digest))
+         *pMD5Valid = true;
+      }
+      *pImageFilename = *(pAaff->pFilename);
+   }
+
    return NO_ERROR;
 }
 
 
 // -----------------------
-//  Module initialisation
+//      Misc. functions
 // -----------------------
 
+unsigned int AaffPreprocessExtraSpace (unsigned int FifoBlockSize)
+{
+   return UtilGetMaxZcompressedBufferSize (FifoBlockSize) - FifoBlockSize;
+}
+
 APIRET AaffInit (void)
 {
    int i;
 
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_MEMALLOC_FAILED        ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CREATE_FILE     ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_OPEN_FILE       ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_WRITE_FILE      ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CLOSE_FILE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_CREATE_FILE     ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_FLUSH_FILE      ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_SIGNATURE  ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_HEADER     ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_FOOTER     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_OPEN_FILE       ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_READ_DATA       ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_SEEK            ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_SECTORSIZE_TOO_BIG     ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_COMPRESSION_FAILED     ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SIGNATURE      ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_HEADER         ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_CANNOT_WRITE_FILE      ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_FOOTER         ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SEGMENTLEN     ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_ORDER     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_HEADER         ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_ARGUMENT  ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SEGMENT_NAME   ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_NUMBER    ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_PAGE_ORDER     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SEGMENTLEN     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SEGMENT_NAME   ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_INVALID_SIGNATURE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_MEMALLOC_FAILED        ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_PAGE_LARGER_THAN_BUFFER))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_SECTORSIZE_TOO_BIG     ))
    CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AAFF_UNCOMPRESS_FAILED      ))
 
-
    srandom (time (0));
 
    for (i=0; i<AAFF_BADSECTORMARKER_MAXLEN; i++)
diff --git a/aaff.h b/aaff.h
index 3950ccd..e0a039f 100644
--- a/aaff.h
+++ b/aaff.h
@@ -6,10 +6,10 @@
 //                  Service de Police Judiciaire
 //                  Section Nouvelles Technologies
 // ****************************************************************************
-//  Module:         Multithreaded AFF (AAFF = Avanced AFF)
+//  Module:         Multithreaded AFF (AAFF = Advanced AFF)
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -29,12 +29,14 @@
 #ifndef __AAFF_H__
 #define __AAFF_H__
 
+#include "hash.h"
+
 typedef struct _t_Aaff *t_pAaff;
 
 typedef struct
 {
-   bool Zero;         // Tells AafWrite that all data is 0
-   bool Compressed;   // Tells AafWrite whether the data should be written compressed or uncompresed
+   bool Zero;         // Tells AaffWrite that all data is 0
+   bool Compressed;   // Tells AaffWrite whether the data should be written compressed or uncompressed
    int  DataLenOut;   // If Compressed is true: The size of the compressed data
 } t_AaffPreprocess, *t_pAaffPreprocess;
 
@@ -49,15 +51,16 @@ typedef struct
 //              Functions
 // ------------------------------------
 
+
 // Write access functions
 APIRET AaffOpen         (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize, unsigned int SectorSize, unsigned int PageSize);
 APIRET AaffPreprocess   (t_pAaffPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut);
 APIRET AaffWrite        (t_pAaff   pAaff, t_pAaffPreprocess pPreprocess, const unsigned char *pData, unsigned int DataLen);
-APIRET AaffClose        (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, int Duration);
+APIRET AaffClose        (t_pAaff *ppAaff, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, uint Duration);
 
 // Read access functions
-APIRET AaffOpen         (t_pAaff *ppAaff, const char *pFilename);
-APIRET AaffReadNextPage (t_pAaff   pAaff, unsigned char *pData, unsigned int *pDataLen);
+APIRET AaffOpen         (t_pAaff *ppAaff, const char *pFilename, unsigned long long DeviceSize);
+APIRET AaffReadNextPage (t_pAaff   pAaff, unsigned char *pData, unsigned int *pDataLen, QString *pImageFilename, t_pHashMD5Digest pMD5Digest, bool *pMD5valid);
 APIRET AaffClose        (t_pAaff *ppAaff);
 
 
@@ -65,6 +68,9 @@ APIRET AaffWriteSegmentStr (t_pAaff pAaff, const char *pName, unsigned int Argum
 
 APIRET AaffCopyBadSectorMarker (unsigned char *pBuffer, unsigned int Len);
 
+// Misc. functions
+unsigned int AaffPreprocessExtraSpace (unsigned int FifoBlockSize);
+
 APIRET AaffInit   (void);
 APIRET AaffDeInit (void);
 
@@ -75,28 +81,24 @@ APIRET AaffDeInit (void);
 
 enum
 {
-   ERROR_AAFF_MEMALLOC_FAILED   = ERROR_BASE_AAFF + 1,
+   ERROR_AAFF_CANNOT_CLOSE_FILE   = ERROR_BASE_AAFF + 1,
    ERROR_AAFF_CANNOT_CREATE_FILE,
-   ERROR_AAFF_CANNOT_OPEN_FILE,
-   ERROR_AAFF_CANNOT_WRITE_FILE,
-   ERROR_AAFF_CANNOT_CLOSE_FILE,
    ERROR_AAFF_CANNOT_FLUSH_FILE,
-   ERROR_AAFF_CANNOT_READ_SIGNATURE,
-   ERROR_AAFF_CANNOT_READ_HEADER,
-   ERROR_AAFF_CANNOT_READ_FOOTER,
+   ERROR_AAFF_CANNOT_OPEN_FILE,
    ERROR_AAFF_CANNOT_READ_DATA,
    ERROR_AAFF_CANNOT_SEEK,
-   ERROR_AAFF_SECTORSIZE_TOO_BIG,
-   ERROR_AAFF_COMPRESSION_FAILED,
-   ERROR_AAFF_INVALID_SIGNATURE,
-   ERROR_AAFF_INVALID_HEADER,
+   ERROR_AAFF_CANNOT_WRITE_FILE,
    ERROR_AAFF_INVALID_FOOTER,
-   ERROR_AAFF_INVALID_SEGMENTLEN,
-   ERROR_AAFF_INVALID_PAGE_ORDER,
+   ERROR_AAFF_INVALID_HEADER,
    ERROR_AAFF_INVALID_PAGE_ARGUMENT,
-   ERROR_AAFF_INVALID_SEGMENT_NAME,
    ERROR_AAFF_INVALID_PAGE_NUMBER,
+   ERROR_AAFF_INVALID_PAGE_ORDER,
+   ERROR_AAFF_INVALID_SEGMENTLEN,
+   ERROR_AAFF_INVALID_SEGMENT_NAME,
+   ERROR_AAFF_INVALID_SIGNATURE,
+   ERROR_AAFF_MEMALLOC_FAILED,
    ERROR_AAFF_PAGE_LARGER_THAN_BUFFER,
+   ERROR_AAFF_SECTORSIZE_TOO_BIG,
    ERROR_AAFF_UNCOMPRESS_FAILED
 };
 
diff --git a/aewf.cpp b/aewf.cpp
index a2e7e5a..5b9bb7c 100644
--- a/aewf.cpp
+++ b/aewf.cpp
@@ -6,10 +6,10 @@
 //                  Service de Police Judiciaire
 //                  Section Nouvelles Technologies
 // ****************************************************************************
-//  Module:         Multithreaded AEWF (AEWF = Avanced EWF)
+//  Module:         Multithreaded AEWF (AEWF = Advanced EWF)
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -34,26 +34,198 @@
 #include <time.h>    //lint !e537 repeated include file
 #include <stdlib.h>
 #include <zlib.h>
+#include <libewf.h>
 
 #include <QString>
+#include <QStringList>
+#include <QtEndian>
 
 #include "util.h"
 #include "config.h"
 #include "aewf.h"
 
-// -----------------
-//  EWF definitions
-// -----------------
 
-#define EWF_ xx
+// ------------------
+//         Qt
+// ------------------
+
+// Qt inconsistently defines its little/big endian functions, see QTBUG-21208 on bugreports.qt.nokia.com
+// The following lines implement conversin for uchar and avoid the problems. 
+
+template <typename T> T qbswap(T source);
+template <> inline uchar qbswap<uchar>(uchar source)
+{
+   return source;
+}
 
 // ------------------
-//  Aewf definitions
+//  AEWF definitions
 // ------------------
 
-typedef struct _t_Aewf
+const uchar  AEWF_SIGNATURE[8]  = {0x45, 0x56, 0x46, 0x09, 0x0D, 0x0A, 0xFF, 0x00};
+const uchar  AEWF_STARTOFFIELDS = 0x01;
+const ushort AEWF_ENDOFFIELDS   = 0x0000;
+
+const char * AEWF_SECTIONNAME_HEADER2 = "header2";
+const char * AEWF_SECTIONNAME_HEADER  = "header" ;
+const char * AEWF_SECTIONNAME_VOLUME  = "volume" ;
+const char * AEWF_SECTIONNAME_SECTORS = "sectors";
+const char * AEWF_SECTIONNAME_TABLE   = "table"  ;
+const char * AEWF_SECTIONNAME_TABLE2  = "table2" ;
+const char * AEWF_SECTIONNAME_DATA    = "data"   ;
+const char * AEWF_SECTIONNAME_ERROR2  = "error2" ;
+const char * AEWF_SECTIONNAME_HASH    = "hash"   ;
+const char * AEWF_SECTIONNAME_NEXT    = "next"   ;
+const char * AEWF_SECTIONNAME_DONE    = "done"   ;
+
+const unsigned int AEWF_MAX_CHUNK_OFFSETS      = 65534;
+const unsigned int AEWF_MAX_SIZE_SECTIONSECTOR = 0x7FFFFFFF;
+
+const unsigned int AEWF_COMPRESSED_CHUNK = 0x80000000;
+
+const unsigned long long AEWF_SEEK_END = 0xFFFFFFFFFFFFFFFFULL;
+
+typedef struct
+{
+   uchar  Signature[8];
+   uchar  StartOfFields;
+   ushort SegmentNumber;
+   ushort EndOfFields;
+} __attribute__ ((packed)) t_AewfFileHeader, *t_pAewfFileHeader;
+
+typedef struct
+{
+   char    Name[16];
+   quint64 NextSectionOffset; // based on file start
+   quint64 SectionSize;
+   uchar   Padding[40];
+   uint    CRC;               // CRC of data from beginning of this section to the field before CRC
+   uchar   Data[];
+} __attribute__ ((packed)) t_AewfSection, *t_pAewfSection;
+
+typedef struct
 {
-} t_Aewf;
+   uchar   MediaType;
+   uchar   Unknown1[3];  // contains 0x00
+   uint    ChunkCount;
+   uint    SectorsPerChunk;
+   uint    BytesPerSector;
+   quint64 SectorCount;
+   uint    CHS_Cylinders;
+   uint    CHS_Heads;
+   uint    CHS_Sectors;
+   uchar   MediaFlags;
+   uchar   Unknown2[3];  // contains 0x00
+   uint    PalmVolumeStartSector;
+   uchar   Padding1[4];  // contains 0x00
+   uint    SmartLogsStartSector;
+   uchar   CompressionLevel;
+   uchar   Unknown3[3];  // contains 0x00
+   uint    ErrorBlockSize;
+   uchar   Unknown4[4];
+   uchar   AcquirySystemGUID[16];
+   uchar   Padding2[963];
+   uchar   Reserved [5];
+   uint    Checksum;
+} __attribute__ ((packed)) t_AewfSectionVolumeContents, *t_pAewfSectionVolumeContents;
+
+typedef struct
+{
+   uint    Offsets;
+   uint    Padding1;
+   quint64 BaseOffset;
+   uint    Padding2;
+   uint    CRC1;
+   uint    OffsetArr[];
+   uint    CRC2;
+} __attribute__ ((packed)) t_AewfSectionTableContents;
+
+typedef struct
+{
+   uint FirstSector;
+   uint NumberOfSectors;
+} __attribute__ ((packed)) t_AewfSectionErrorEntry;
+
+typedef struct
+{
+   uint                    NumberOfErrors;
+   uchar                   Padding[512];
+   uint                    CRC1;
+   t_AewfSectionErrorEntry ErrorArr[];
+   uint                    CRC2;
+} __attribute__ ((packed)) t_AewfSectionErrorContents;
+
+typedef struct
+{
+   uchar MD5    [16];
+   uchar Unknown[16];
+   uint  CRC;
+} __attribute__ ((packed)) t_AewfSectionHashContents;
+
+class t_Aewf
+{
+   public:
+      QString          SegmentFilename;      // The base path and filename, without extension
+      quint64          DeviceSize;
+      quint64          SegmentSize;
+      quint64          ChunkSize;
+      quint64          SectorSize;
+      t_AewfMediaType  MediaType;
+      t_AewfMediaFlags MediaFlags;
+      QString          Description;
+      QString          CaseNumber;
+      QString          EvidenceNumber;
+      QString          Examiner;
+      QString          Notes;
+      QString          DeviceModel;
+      QString          SerialNumber;
+      QString          ImagerVersion;
+      QString          OSVersion;
+
+      uint             SegmentFiles;
+      uchar            EwfCompressionLevel;
+      int              ZipCompressionLevel;
+      QStringList      SegmentFilenameList;
+      FILE           *pCurrentSegmentFile;
+      quint64          CurrentSectionSectorSeekPos;
+      quint64          CurrentSectionSectorContentSize;
+      t_AewfFileHeader FileHeaderCache;
+      quint64          ChunkBaseOffset;
+      uint             ChunkOffsetArr[AEWF_MAX_CHUNK_OFFSETS+1];  // Data is stored in little endian for speed optimisation here! +1 as we add a fake chunk offset marking the end of the section "sectors" when verifying the data
+      uint             ChunkOffsets;
+      uint             CurrentChunkOffset;           // For knowing the current chunk during verification
+
+      t_HashContextMD5 CurrentSegmentHashContextMD5; // For segment file MD5 calculation during verification
+      uchar          *pVerifyBuffer;                 // For uncompression and othe verification tasks
+      uint             VerifyBufferLen;
+
+      t_Aewf ()
+      {
+         pCurrentSegmentFile = NULL;
+         SegmentFiles        = 0;
+         pVerifyBuffer       = NULL;
+         VerifyBufferLen     = 0;
+
+         memcpy (FileHeaderCache.Signature, AEWF_SIGNATURE, sizeof (AEWF_SIGNATURE));
+         FileHeaderCache.StartOfFields = qToLittleEndian (AEWF_STARTOFFIELDS);
+         FileHeaderCache.SegmentNumber = qToLittleEndian (0);
+         FileHeaderCache.EndOfFields   = qToLittleEndian (AEWF_ENDOFFIELDS);
+         switch (CONFIG(EwfCompression))
+         {
+            case LIBEWF_COMPRESSION_NONE: ZipCompressionLevel = 0; EwfCompressionLevel = 0x00; break;
+            case LIBEWF_COMPRESSION_FAST: ZipCompressionLevel = 1; EwfCompressionLevel = 0x01; break;
+            case LIBEWF_COMPRESSION_BEST: ZipCompressionLevel = 9; EwfCompressionLevel = 0x02; break;
+            default: CHK_EXIT (ERROR_AEWF_INVALID_COMPRESSION_LEVEL)
+         }
+      }
+};
+
+// ----------------
+//   Global vars
+// ----------------
+unsigned char *pAewfZeroBlockCompressed;
+ulong           AewfZeroBlockCompressedLen;
+ulong           AewfZeroBlockUnCompressedLen;
 
 // ----------------
 //  Error handling
@@ -68,40 +240,610 @@ typedef struct _t_Aewf
 //  Utility functions
 // -------------------
 
+static int AewfCRC (const void *pBuffer, size_t Len)
+{
+   return adler32 (1, (const Bytef *) pBuffer, Len);
+}
 
-// -------------------
-//  Segment functions
-// -------------------
 
-// ---------------
-//  API functions
-// ---------------
+// EWF file extension calculation: That extension naming convention of EWF files most probably was a quick hack.
+// The known sequence is:
+//    E01 - E99
+//    EAA - EZZ
+//    FAA - ZZZ
+// Nobody exactly seems to know what follows then. Joachim Metz writes that maybe [AA would follow. If so, it
+// doesn't help a lot, as it only doubles the available naming space (the following ASCII character is \ and
+// thus cannot be used on Windows systems with their inconsistent usage of \ and / ).
+// So, I decided to continue with ZZZxxx, where xxx represents a numbers from 000 to ZZZ in base36 notation (i.e.
+// 0-9 and A-Z). After that, it would continue with ZZZxxxx and so on.
+// Old-fashionned Windows-file systems only allow 3 letters for the extension. If ever this occurs the acquisition
+// will fail. So, we simply tell the user 'bad luck' and that's all? Yes, but, wait a moment:
+//   a) nobody said he should use old-fashionned Windows FS
+//   b) why use Windows at all?
+
+const QString AewfGetExtension (uint SegmentFileNr)
+{
+   QString Extension;
+
+   if (SegmentFileNr == 0)
+      Extension = "Error_filenr_is_zero";
+   else if (SegmentFileNr < 100)
+      Extension = QString("E%1").arg(SegmentFileNr,2,10,QChar('0'));
+   else
+   {
+      SegmentFileNr += ('E' -'A') * 26 * 26 - 100; // The first extension after .E99 is .EAA. So, this is the offset we need
+      unsigned int DigitL =  SegmentFileNr % 26;
+      unsigned int DigitM = (SegmentFileNr / 26) % 26;
+      unsigned int DigitH = (SegmentFileNr / (26*26));
+      if (DigitH < 26)
+      {
+         Extension = QString (char (DigitH + 'A')) +
+                     QString (char (DigitM + 'A')) +
+                     QString (char (DigitL + 'A'));
+      }
+      else
+      {
+         SegmentFileNr -= 25*26*26 + 25*26 + 25; // substract ZZZ
+         Extension = QString("ZZZ%1").arg(SegmentFileNr,3,36,QChar('0')).toUpper();
+      }
+   }
+
+   return Extension;
+}
+
+// AewfCompress: No need to have an extra check if compression is set to "none". If this is the case, pAewf->ZipCompressionLevel
+// is set to 0 and compress2 won't do any compression (see libz / compress2 documentation).
+static APIRET AewfCompress (const t_pAewf pAewf, void *pDst, ulong *pDstLen, const void* pSrc, unsigned SrcLen)
+{
+   int rc;
+
+   if ((SrcLen == AewfZeroBlockUnCompressedLen) && UtilIsZero ((unsigned char *)pSrc, SrcLen))  // Check if pre-compressed
+   {                                                                                            // zero block can be used
+      if (*pDstLen < AewfZeroBlockCompressedLen)
+         return ERROR_AEWF_COMPRESSION_FAILED;
+      *pDstLen = AewfZeroBlockCompressedLen;
+      memcpy (pDst, pAewfZeroBlockCompressed, AewfZeroBlockCompressedLen);
+   }
+   else
+   {
+      rc = compress2 ((Bytef*)pDst, pDstLen, (Bytef*)pSrc, SrcLen, pAewf->ZipCompressionLevel);
+      if (rc != Z_OK)
+         return ERROR_AEWF_COMPRESSION_FAILED;
+   }
+   return NO_ERROR;
+}
+
+static APIRET AewfUncompress (void *pUncompressed, ulong *pUncompressedLen, void *pCompressed, ulong CompressedLen)
+{
+   int rc;
+   
+   if ((CompressedLen == AewfZeroBlockCompressedLen) &&
+       (memcmp(pCompressed, pAewfZeroBlockCompressed, CompressedLen) == 0))
+   {
+      if (*pUncompressedLen < AewfZeroBlockUnCompressedLen)
+         return ERROR_AEWF_UNCOMPRESS_FAILED;
+      *pUncompressedLen = AewfZeroBlockUnCompressedLen;
+      memset (pUncompressed, 0, AewfZeroBlockUnCompressedLen);
+   }
+   else
+   {
+      rc = uncompress ((Bytef*)pUncompressed, pUncompressedLen, (Bytef*)pCompressed, CompressedLen);
+      if (rc != Z_OK)
+         return ERROR_AEWF_UNCOMPRESS_FAILED;
+   }
+   return NO_ERROR;
+}
+
+static quint64 AewfGetCurrentSeekPos (t_Aewf *pAewf)
+{
+   if (pAewf->pCurrentSegmentFile)
+        return ftello64 (pAewf->pCurrentSegmentFile);
+   else return (quint64)(-1);
+}
 
+static APIRET AewfSetCurrentSeekPos (t_Aewf *pAewf, quint64 SeekPos)
+{
+   int rc;
+
+   if (pAewf->pCurrentSegmentFile == NULL)
+      CHK (ERROR_AEWF_NO_FILE_OPEN)
+
+   if (SeekPos == AEWF_SEEK_END)
+        rc = fseeko64 (pAewf->pCurrentSegmentFile, 0      , SEEK_END);
+   else rc = fseeko64 (pAewf->pCurrentSegmentFile, SeekPos, SEEK_SET);
+   if (rc)
+      return ERROR_AEWF_CANNOT_SEEK;
+   return NO_ERROR;
+}
 
 // ---------------------
-//  API write functions
+//  Low level functions
 // ---------------------
 
-APIRET AewfOpen (t_pAewf */*ppAewf*/, const char */*pFilename*/, unsigned long long /*DeviceSize*/, unsigned int /*SectorSize*/, unsigned int /*ChunkSize*/)
+static inline APIRET AewfWriteFile (t_pAewf pAewf, const void *pBuffer, size_t Len)
 {
+   if (pAewf->pCurrentSegmentFile == NULL)
+      CHK (ERROR_AEWF_NO_FILE_OPEN)
+
+   CHK_FWRITE (fwrite (pBuffer, Len, 1, pAewf->pCurrentSegmentFile))
+
+   // Simulate cases write error
+   // static int FakeWriteError=0;
+   // if (FakeWriteError++ == 1500)
+   //   CHK (ERROR_AEWF_CANNOT_WRITE_FILE)
+
    return NO_ERROR;
 }
 
+static APIRET AewfCreateFile (t_Aewf *pAewf)
+{
+   QString Extension;
+   QString Filename;
+
+   if (pAewf->pCurrentSegmentFile)
+      CHK (ERROR_AEWF_ANOTHER_FILE_STILL_OPEN)
+
+   // Get extension and open file
+   // ---------------------------
+   pAewf->SegmentFiles++;
+   Extension = AewfGetExtension (pAewf->SegmentFiles);
+   Filename  = pAewf->SegmentFilename + "." + Extension;
+
+   pAewf->pCurrentSegmentFile = fopen64 (QSTR_TO_PSZ(Filename), "w");
+   // Simulate cases open error
+   // static int FakeOpenError=0;
+   // if (FakeOpenError++ == 2)
+   //  pAewf->pCurrentSegmentFile = NULL;
+
+   if (pAewf->pCurrentSegmentFile == NULL)
+      CHK (ERROR_AEWF_CANNOT_CREATE_FILE)
+
+   pAewf->SegmentFilenameList += Filename;
+
+   // Reset fields related to current segment file
+   // --------------------------------------------
+   pAewf->ChunkBaseOffset                 = 0;
+   pAewf->CurrentSectionSectorSeekPos     = 0;
+   pAewf->CurrentSectionSectorContentSize = 0;
+   pAewf->ChunkOffsets                    = 0;
+
+   // Write file header
+   // -----------------
+   pAewf->FileHeaderCache.SegmentNumber = qToLittleEndian ((ushort)pAewf->SegmentFiles);
+   CHK (AewfWriteFile (pAewf, &pAewf->FileHeaderCache, sizeof (pAewf->FileHeaderCache)))
+
+   return NO_ERROR;
+}
+
+static APIRET AewfCloseFile (t_pAewf pAewf)
+{
+   FILE *pCurrentSegmentFile = pAewf->pCurrentSegmentFile;
+
+   if (pCurrentSegmentFile == NULL)
+      CHK (ERROR_AEWF_NO_FILE_OPEN)
+
+   pAewf->pCurrentSegmentFile = NULL;
 
-APIRET AewfClose (t_pAewf */*ppAewf*/, unsigned long long /*BadSectors*/, const unsigned char */*pMD5*/, const unsigned char */*pSHA256*/, int /*Duration*/)
+   if (fflush (pCurrentSegmentFile))
+   {
+      (void) fclose (pCurrentSegmentFile);
+      CHK (ERROR_AEWF_CANNOT_FLUSH_FILE)
+   }
+
+   if (fclose (pCurrentSegmentFile))
+      CHK (ERROR_AEWF_CANNOT_CLOSE_FILE)
+
+// Simulate cases close error
+//   static int FakeCloseError=0;
+//   if (FakeCloseError++ == 2)
+//      CHK (ERROR_AEWF_CANNOT_CLOSE_FILE)
+
+   return NO_ERROR;
+}
+
+static APIRET AewfWriteSection (t_pAewf pAewf, const char *pName, const void *pData, quint64 Len)
 {
+   t_AewfSection Section;
+
+   memset (Section.Padding, 0, sizeof (Section.Padding));
+   memset (Section.Name   , 0, sizeof (Section.Name   ));
+   strcpy (Section.Name, pName);
+   if ((pData==NULL) && (Len==0))
+   {
+      Section.NextSectionOffset = qToLittleEndian (AewfGetCurrentSeekPos(pAewf)); // Sections "next" and "done", the only ones without
+      Section.SectionSize       = 0;                                              // additional data, refer to themselves and have size set to 0
+   }
+   else
+   {
+      Section.NextSectionOffset = qToLittleEndian (AewfGetCurrentSeekPos(pAewf) + sizeof (t_AewfSection) + Len);
+      Section.SectionSize       = qToLittleEndian (sizeof (t_AewfSection) + Len);
+   }
+   Section.CRC = qToLittleEndian (AewfCRC (&Section, offsetof (t_AewfSection, CRC)));
+
+   CHK (AewfWriteFile (pAewf, &Section, sizeof (t_AewfSection)))
+   if (pData && Len)
+      CHK (AewfWriteFile (pAewf, pData, Len))
+
+   return NO_ERROR;
+}
+
+static APIRET AewfWriteSectionHeader (t_pAewf pAewf)  // Writes the sections header2, header2 and header alltogether
+{
+   QString        HeaderData;
+   time_t         NowT;
+   int            Utf16Codes, i;
+   ushort       *pArr;
+   ulong          ArrLen;
+   void         *pCompressed;
+   ulong          CompressedLen;
+   const ushort *pUtf16;
+   APIRET         rc;
+   QByteArray     ByteArr;
+   QString        TimeBuff;
+   struct tm      TM;
+
+   time (&NowT);
+   localtime_r (&NowT, &TM);
+
+   // Generate 2 sections "header2"
+   // -----------------------------
+   HeaderData  = QString ("3\nmain\n");                                    // 1 2
+   HeaderData += QString ("a\tc\tn\te\tt\tmd\tsn\tav\tov\tm\tu\tp\tdc\n"); // 3
+   HeaderData += QString ("%1\t%2\t%3\t%4\t%5\t%6\t%7\t%8\t%9\t%10\t%11\t\t\n") .arg(pAewf->Description)  .arg(pAewf->CaseNumber)    .arg(pAewf->EvidenceNumber)
+                                                                                .arg(pAewf->Examiner)     .arg(pAewf->Notes)         .arg(pAewf->DeviceModel)
+                                                                                .arg(pAewf->SerialNumber) .arg(pAewf->ImagerVersion) .arg(pAewf->OSVersion)
+                                                                                .arg(NowT)                .arg(NowT);    // 4
+   HeaderData += QString ("\nsrce\n0\t1\n");                               // 5 6 7
+   HeaderData += QString ("p\tn\tid\tev\ttb\tlo\tpo\tah\tgu\taq\n");       // 8
+   HeaderData += QString ("0\t0\n");                                       // 9
+   HeaderData += QString ("\t\t\t\t\t-1\t-1\t\t\t\n");                     // 10
+   HeaderData += QString ("\nsub\n0\t1\n");                                // 11 12 13
+   HeaderData += QString ("p\tn\tid\tnu\tco\tgu\n");                       // 14
+   HeaderData += QString ("0\t0\n\t\t\t\t1\t\n");                          // 15 16
+
+   pUtf16 = HeaderData.utf16();
+   Utf16Codes=0;
+   while (pUtf16[Utf16Codes] != 0)
+      Utf16Codes++;
+
+   ArrLen = (Utf16Codes+1)*sizeof(ushort);
+   pArr = (ushort *) UTIL_MEM_ALLOC (ArrLen);  // +1 for BOM
+   pArr[0] = qToLittleEndian((ushort)0xFEFF);  // BOM
+   for (i=0; i<Utf16Codes; i++)
+      pArr[i+1] = qToLittleEndian(pUtf16[i]);
+
+   CompressedLen = UtilGetMaxZcompressedBufferSize (ArrLen);
+   pCompressed   = UTIL_MEM_ALLOC (CompressedLen);
+   CHK (AewfCompress (pAewf, pCompressed, &CompressedLen, pArr, ArrLen))
+
+   rc = AewfWriteSection (pAewf, AEWF_SECTIONNAME_HEADER2, pCompressed, CompressedLen);
+   rc = AewfWriteSection (pAewf, AEWF_SECTIONNAME_HEADER2, pCompressed, CompressedLen);
+   UTIL_MEM_FREE (pArr);
+   UTIL_MEM_FREE (pCompressed);
+   CHK (rc)
+
+   // Generate section "header"
+   // -------------------------
+   TimeBuff = QString ("%1 %2 %3 %4 %5 %6") .arg (TM.tm_year+1900) .arg (TM.tm_mon+1) .arg (TM.tm_mday) .arg (TM.tm_hour) .arg (TM.tm_min) .arg (TM.tm_sec);
+
+   HeaderData  = QString ("1\nmain\n");                                    // 1 2
+   HeaderData += QString ("c\tn\ta\te\tt\tav\tov\tm\tu\tp\n");             // 3
+   HeaderData += QString ("%1\t%2\t%3\t%4\t%5\t%6\t%7\t%8\t%9\t0\n\n") .arg(pAewf->CaseNumber) .arg(pAewf->EvidenceNumber) .arg(pAewf->Description)
+                                                                       .arg(pAewf->Examiner)   .arg(pAewf->Notes)          .arg(pAewf->ImagerVersion)
+                                                                       .arg(pAewf->OSVersion)  .arg(TimeBuff)              .arg(TimeBuff);    // 4
+
+   ByteArr = HeaderData.toLatin1();
+   CompressedLen = UtilGetMaxZcompressedBufferSize (ByteArr.length());
+   pCompressed   = UTIL_MEM_ALLOC (CompressedLen);
+   CHK (AewfCompress (pAewf, pCompressed, &CompressedLen, ByteArr.constData(), ByteArr.length()))
+
+   rc = AewfWriteSection (pAewf, AEWF_SECTIONNAME_HEADER, pCompressed, CompressedLen);
+   UTIL_MEM_FREE (pCompressed);
+   CHK (rc)
+
    return NO_ERROR;
 }
 
+static APIRET AewfWriteSectionVolume (t_Aewf *pAewf, bool NameVolume=true)
+{
+   t_AewfSectionVolumeContents VolumeContents;
+   quint64                     Chunks;
+
+   Chunks = pAewf->DeviceSize / pAewf->ChunkSize;
+   if (pAewf->DeviceSize % pAewf->ChunkSize)
+      Chunks++;
+
+   memset (&VolumeContents, 0, sizeof(VolumeContents));
+   VolumeContents.MediaType        = qToLittleEndian ((uchar)pAewf->MediaType);
+   VolumeContents.ChunkCount       = qToLittleEndian ((uint)    Chunks);
+   VolumeContents.SectorsPerChunk  = qToLittleEndian ((uint)   (pAewf->ChunkSize / pAewf->SectorSize));
+   VolumeContents.BytesPerSector   = qToLittleEndian ((uint)    pAewf->SectorSize);
+   VolumeContents.SectorCount      = qToLittleEndian ((quint64) pAewf->DeviceSize / pAewf->SectorSize);
+   VolumeContents.MediaFlags       = qToLittleEndian ((uchar)  (pAewf->MediaFlags | AEWF_MEDIAFLAGS_IMAGE));
+   VolumeContents.CompressionLevel = qToLittleEndian ((uchar)   pAewf->EwfCompressionLevel);
+   VolumeContents.ErrorBlockSize   = qToLittleEndian ((uint)    1);
+   VolumeContents.Checksum         = qToLittleEndian (AewfCRC (&VolumeContents, offsetof(t_AewfSectionVolumeContents, Checksum)));
+   if (NameVolume)
+        CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_VOLUME, &VolumeContents, sizeof(VolumeContents)))
+   else CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_DATA  , &VolumeContents, sizeof(VolumeContents)))
+
+   return NO_ERROR;
+}
 
-APIRET AewfPreprocess (t_pAewfPreprocess */*ppPreprocess*/, unsigned char */*pDataIn*/, unsigned int /*DataLenIn*/, unsigned char */*pDataOut*/, unsigned int /*DataLenOut*/)
+static APIRET AewfFinishSectionSectors (t_Aewf *pAewf)
 {
+   CHK (AewfSetCurrentSeekPos (pAewf, pAewf->CurrentSectionSectorSeekPos))
+   CHK (AewfWriteSection      (pAewf, AEWF_SECTIONNAME_SECTORS, NULL, pAewf->CurrentSectionSectorContentSize))
+   CHK (AewfSetCurrentSeekPos (pAewf, AEWF_SEEK_END))
+
+   pAewf->CurrentSectionSectorSeekPos     = 0;
+   pAewf->CurrentSectionSectorContentSize = 0;
+
    return NO_ERROR;
 }
 
+static APIRET AewfWriteSectionTable (t_Aewf *pAewf)
+{
+   t_AewfSectionTableContents *pTableContents;
+   uint                         TableContentsSize;
+   quint64                      OffsetArrSize;
+   uint                       *pCRC2;
+
+   OffsetArrSize = pAewf->ChunkOffsets * sizeof (unsigned int);
+   TableContentsSize = sizeof (t_AewfSectionTableContents) + OffsetArrSize;
+   pTableContents = (t_AewfSectionTableContents *) UTIL_MEM_ALLOC (TableContentsSize);
 
-APIRET AewfWrite (t_pAewf /*pAewf*/, t_pAewfPreprocess /*pPreprocess*/, const unsigned char */*pData*/, unsigned int /*DataLen*/)
+   memset (pTableContents, 0, sizeof(t_AewfSectionTableContents));
+   pTableContents->Offsets    = qToLittleEndian (pAewf->ChunkOffsets   );
+   pTableContents->BaseOffset = qToLittleEndian (pAewf->ChunkBaseOffset);
+   pTableContents->CRC1       = qToLittleEndian (AewfCRC(pTableContents, offsetof(t_AewfSectionTableContents, CRC1)));
+   memcpy (&pTableContents->OffsetArr[0], &pAewf->ChunkOffsetArr[0], OffsetArrSize);     // pAewf->ChunkOffsetArr already is in little endian!
+   pCRC2 = (unsigned int *) (&pTableContents->OffsetArr[0] + pAewf->ChunkOffsets);
+   *pCRC2 = qToLittleEndian (AewfCRC(pTableContents->OffsetArr, OffsetArrSize));
+
+   CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_TABLE , pTableContents, sizeof(t_AewfSectionTableContents)+OffsetArrSize))
+   CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_TABLE2, pTableContents, sizeof(t_AewfSectionTableContents)+OffsetArrSize))
+   UTIL_MEM_FREE (pTableContents);
+
+   pAewf->ChunkOffsets    = 0;
+   pAewf->ChunkBaseOffset = 0;
+
+   return NO_ERROR;
+}
+
+static APIRET AewfWriteSectionError (t_Aewf *pAewf, QList<quint64> &BadSectors)
 {
+   t_AewfSectionErrorContents *pErrorContents;
+   uint                       *pCRC2;
+   uint                         Entries;
+   uint                         SectionSize;
+   quint64                      i, Count;
+   quint64                      From, To, Next;
+
+   Count = BadSectors.count();
+   if (Count == 0)
+      return NO_ERROR;
+
+   pErrorContents = (t_AewfSectionErrorContents *) UTIL_MEM_ALLOC (sizeof(t_AewfSectionErrorContents));
+   memset (pErrorContents, 0, sizeof(t_AewfSectionErrorContents));
+   Entries   = 0;
+   i         = 0;
+   while (i<Count)
+   {
+      From = BadSectors.at(i++);
+      To   = From;
+      while (i < Count)
+      {
+         Next = BadSectors.at(i);
+         if (Next != To+1)
+             break;
+         To = Next;
+         i++;
+      }
+      Entries++;
+      SectionSize = sizeof(t_AewfSectionErrorContents) + Entries * sizeof (t_AewfSectionErrorEntry);
+      pErrorContents = (t_AewfSectionErrorContents *) realloc (pErrorContents, SectionSize);
+      pErrorContents->ErrorArr[Entries-1].FirstSector     = qToLittleEndian (From);
+      pErrorContents->ErrorArr[Entries-1].NumberOfSectors = qToLittleEndian (To - From + 1);
+   }
+   pCRC2 = (unsigned int *) &pErrorContents->ErrorArr[Entries];
+   pErrorContents->NumberOfErrors = qToLittleEndian (Entries);
+   pErrorContents->CRC1           = qToLittleEndian (AewfCRC (pErrorContents, offsetof (t_AewfSectionErrorContents, CRC1)));
+   *pCRC2                         = qToLittleEndian (AewfCRC (&pErrorContents->ErrorArr[0], Entries * sizeof (t_AewfSectionErrorEntry)));
+
+   CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_ERROR2, pErrorContents, SectionSize))
+
+   return NO_ERROR;
+}
+
+static APIRET AewfWriteSectionHash (t_Aewf *pAewf, const uchar *pMD5)
+{
+   t_AewfSectionHashContents HashContents;
+
+   memset (&HashContents, 0, sizeof(HashContents));
+   memcpy (HashContents.MD5, pMD5, sizeof(HashContents.MD5));
+   HashContents.CRC = qToLittleEndian (AewfCRC (&HashContents, offsetof (t_AewfSectionHashContents, CRC)));
+
+   CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_HASH, &HashContents, sizeof(HashContents)))
+   return NO_ERROR;
+}
+
+static APIRET AewfWriteSectionNext (t_Aewf *pAewf)
+{
+   CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_NEXT, NULL, 0))
+   return NO_ERROR;
+}
+
+static APIRET AewfWriteSectionDone (t_Aewf *pAewf)
+{
+   CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_DONE, NULL, 0))
+   return NO_ERROR;
+}
+
+// ---------------------
+//      API functions
+// ---------------------
+
+APIRET AewfOpen (t_pAewf *ppAewf, const char *pFilename,
+                                  unsigned long long DeviceSize, unsigned long long SegmentSize,
+                                  unsigned int       ChunkSize , unsigned int       SectorSize,
+                                  t_AewfMediaType    MediaType,
+                                  t_AewfMediaFlags   MediaFlags,
+                                  QString Description, QString CaseNumber,  QString EvidenceNumber, QString Examiner,
+                                  QString Notes,       QString DeviceModel, QString SerialNumber,   QString ImagerVersion,
+                                  QString OSVersion)
+{
+   *ppAewf = new t_Aewf;
+   (*ppAewf)->SegmentFilename = pFilename;
+   (*ppAewf)->DeviceSize      = DeviceSize;
+   (*ppAewf)->SegmentSize     = SegmentSize;
+   (*ppAewf)->ChunkSize       = ChunkSize;
+   (*ppAewf)->SectorSize      = SectorSize;
+   (*ppAewf)->MediaType       = MediaType;
+   (*ppAewf)->MediaFlags      = MediaFlags;
+   (*ppAewf)->Description     = Description;
+   (*ppAewf)->CaseNumber      = CaseNumber;
+   (*ppAewf)->EvidenceNumber  = EvidenceNumber;
+   (*ppAewf)->Examiner        = Examiner;
+   (*ppAewf)->Notes           = Notes;
+   (*ppAewf)->DeviceModel     = DeviceModel;
+   (*ppAewf)->SerialNumber    = SerialNumber;
+   (*ppAewf)->ImagerVersion   = ImagerVersion;
+   (*ppAewf)->OSVersion       = OSVersion;
+
+   CHK (AewfCreateFile         (*ppAewf))
+   CHK (AewfWriteSectionHeader (*ppAewf))
+   CHK (AewfWriteSectionVolume (*ppAewf))
+
+   return NO_ERROR;
+}
+
+
+APIRET AewfPreprocess (t_Aewf *pAewf, t_pAewfPreprocess *ppPreprocess, uchar *pDataIn, unsigned int DataLenIn, uchar *pDataOut, unsigned int DataLenOut)
+{
+   t_pAewfPreprocess pPreProcess;
+   int                rc;
+   uLongf             LenOut;
+   uint             *pCRC;
+
+   *ppPreprocess = NULL;
+   pPreProcess = (t_pAewfPreprocess) UTIL_MEM_ALLOC(sizeof(t_AewfPreprocess));
+   if (pPreProcess == NULL)
+      CHK (ERROR_AEWF_MEMALLOC_FAILED)
+   *ppPreprocess = pPreProcess;
+   pPreProcess->Compressed = false;
+
+   if (CONFIG(EwfCompression) != LIBEWF_COMPRESSION_NONE)
+   {
+      LenOut = DataLenOut;
+      rc = AewfCompress (pAewf, pDataOut, &LenOut, pDataIn, DataLenIn);
+
+      pPreProcess->DataLenOut = LenOut;
+      if (rc != NO_ERROR)
+           LOG_ERROR ("compress2 returned %d - treating this block as uncompressed in order to resume", rc)
+//      else pPreProcess->Compressed = (LenOut < (DataLenIn + sizeof(unsigned int))); // This leads to problems in Encase
+      else pPreProcess->Compressed = (LenOut < DataLenIn);
+   }
+
+   if (!pPreProcess->Compressed)  // Add the CRC to the end of the non-compressed data. The FIFO buffer is
+   {                              // big enough for this (see extra space calculation)
+      pCRC = (unsigned int *) &pDataIn[DataLenIn];
+      *pCRC = qToLittleEndian (AewfCRC (pDataIn, DataLenIn));
+      pPreProcess->DataLenOut = DataLenIn + sizeof (unsigned int);
+   }
+   return NO_ERROR;
+}
+
+APIRET AewfWrite (t_Aewf *pAewf, t_AewfPreprocess *pPreprocess, const uchar *pData, unsigned int DataLen)
+{
+   quint64 SectionTableSize;
+   quint64 MinRemainingSize;
+   uint    OffsetArrEntry;
+
+   if (pAewf->pCurrentSegmentFile == NULL)
+      CHK (ERROR_AEWF_NO_FILE_OPEN)
+
+   //printf ("\nChunk: %d  %u bytes - %s", pAewf->ChunkOffsets, DataLen, pPreprocess->Compressed ? "compressed" : "uc");
+
+   // Check if enough space remaining in current segment file
+   // -------------------------------------------------------
+   SectionTableSize = sizeof (t_AewfSection) + sizeof (t_AewfSectionTableContents)
+                    + (pAewf->ChunkOffsets + 1)* sizeof(unsigned int);
+   MinRemainingSize =     DataLen
+                    + 2 * SectionTableSize                                              // Sections "table" and "table2"
+                    +     sizeof (t_AewfSection) + sizeof (t_AewfSectionVolumeContents) // Section "data"
+                    +     sizeof (t_AewfSection) + sizeof (t_AewfSectionHashContents  ) // Section "hash"
+                    +     sizeof (t_AewfSection)                                        // Section "done"
+                    +     sizeof (t_AewfSection) +                                      // In case we need to start a new section "sectors" (see below),
+                    + 2 * sizeof (t_AewfSection) + sizeof (t_AewfSectionTableContents); // which would also require additonal sections "table" and "table2"
+   if ((pAewf->SegmentSize - AewfGetCurrentSeekPos(pAewf)) < MinRemainingSize)
+   {
+      // Close the current segment and open a new one
+      CHK (AewfFinishSectionSectors(pAewf))
+      CHK (AewfWriteSectionTable   (pAewf))
+      CHK (AewfWriteSectionNext    (pAewf))
+      CHK (AewfCloseFile           (pAewf))
+      CHK (AewfCreateFile          (pAewf))
+      CHK (AewfWriteSectionVolume  (pAewf, false))
+   }
+
+   // Check if current sector section or offset table is full
+   // -------------------------------------------------------
+   if (((pAewf->CurrentSectionSectorContentSize + DataLen) > AEWF_MAX_SIZE_SECTIONSECTOR) || // Unlike libewf, we prefer to have the whole section "sectors" <= 2GiB (libewf
+        (pAewf->ChunkOffsets == AEWF_MAX_CHUNK_OFFSETS))                                     // allows to have the last chunk start below the 2GiB limit and span beyond)
+   {
+      CHK (AewfFinishSectionSectors (pAewf))
+      CHK (AewfWriteSectionTable    (pAewf))
+   }
+
+   // Write the data
+   // --------------
+   // Create a new section "sectors" if necessary
+   if (pAewf->CurrentSectionSectorContentSize == 0)
+   {
+      pAewf->CurrentSectionSectorSeekPos = AewfGetCurrentSeekPos(pAewf);
+      pAewf->ChunkBaseOffset             = AewfGetCurrentSeekPos(pAewf);  // We also could do this after section "sectors" has been written (thus gaining 76 bytes), but this mimics ewfacquire behaviour
+      CHK (AewfWriteSection (pAewf, AEWF_SECTIONNAME_SECTORS, NULL, 0))
+   }
+   OffsetArrEntry = AewfGetCurrentSeekPos(pAewf) - pAewf->ChunkBaseOffset;
+   if (pPreprocess->Compressed)
+      OffsetArrEntry |= AEWF_COMPRESSED_CHUNK;
+//   printf ("\nWrite chunk %d -- %d bytes", pAewf->ChunkOffsets, DataLen);
+   pAewf->ChunkOffsetArr[pAewf->ChunkOffsets++] = qToLittleEndian (OffsetArrEntry);
+   CHK (AewfWriteFile (pAewf, pData, DataLen))
+   pAewf->CurrentSectionSectorContentSize += DataLen;
+
+   UTIL_MEM_FREE (pPreprocess);
+
+   return NO_ERROR;
+}
+
+APIRET AewfClose (t_pAewf *ppAewf, QList<quint64> &BadSectors, const uchar *pMD5, const uchar */*pSHA256*/)
+{
+   t_Aewf *pAewf = *ppAewf;
+
+   if (pAewf->pCurrentSegmentFile) // This must be checked as pCurrentSegmentFile might be zero if an error occured (for example fwrite or fclose error during acquisition)
+   {
+      if (pAewf->CurrentSectionSectorContentSize)  // Is there an unfinished section "sectors"?
+      {
+         CHK (AewfFinishSectionSectors (pAewf))
+         CHK (AewfWriteSectionTable    (pAewf))
+      }
+
+      if (pAewf->SegmentFiles == 1)                  // Add section "data" if there was only 1 segment file
+         CHK (AewfWriteSectionVolume (pAewf, false))
+
+      if (BadSectors.count())
+         CHK (AewfWriteSectionError (pAewf, BadSectors))
+
+      CHK (AewfWriteSectionHash (pAewf, pMD5))
+      CHK (AewfWriteSectionDone (pAewf))
+
+      CHK (AewfCloseFile (pAewf))
+   }
+   delete pAewf;
+   *ppAewf = NULL;
+
    return NO_ERROR;
 }
 
@@ -109,34 +851,389 @@ APIRET AewfWrite (t_pAewf /*pAewf*/, t_pAewfPreprocess /*pPreprocess*/, const un
 //  API read functions
 // ---------------------
 
-APIRET AewfOpen (t_pAewf */*ppAewf*/, const char */*pFilename*/)
+#define CHK_LOG(pAewf, rc) \
+{                          \
+   int ChkRc = (rc);       \
+   if (ChkRc != NO_ERROR)  \
+      LOG_INFO ("AEWF verification error in file %s", QSTR_TO_PSZ(pAewf->SegmentFilenameList[pAewf->SegmentFiles-1])) \
+   CHK (ChkRc)             \
+}
+
+static APIRET AewfReallocVerifyBuffer (t_Aewf *pAewf, uint Len)
+{
+   if (pAewf->VerifyBufferLen < Len)
+   {
+      pAewf->pVerifyBuffer = (uchar *) realloc (pAewf->pVerifyBuffer, Len);
+      if (pAewf->pVerifyBuffer == NULL)
+         CHK (ERROR_AEWF_MEMALLOC_FAILED)
+      pAewf->VerifyBufferLen = Len;
+   }
+   return NO_ERROR;
+}
+
+APIRET AewfOpen (t_pAewf *ppAewf, const char *pFilename)
+{
+   t_Aewf *pAewf;
+
+   *ppAewf = new t_Aewf;
+   pAewf = *ppAewf;
+   pAewf->SegmentFilename = pFilename;
+
+   return NO_ERROR;
+}
+
+APIRET AewfClose (t_pAewf *ppAewf)
+{
+   t_Aewf *pAewf;
+
+   pAewf = *ppAewf;
+
+   if (pAewf->pVerifyBuffer)
+      free (pAewf->pVerifyBuffer);  // Must released with free, as realloc is used for allocating it
+
+   delete (pAewf);
+   *ppAewf = NULL;
+
+   return NO_ERROR;
+}
+
+static APIRET AewfReadFile (t_Aewf *pAewf, void *pData, uint DataLen, bool DisableMD5=false)
+{
+   if (fread (pData, DataLen, 1, pAewf->pCurrentSegmentFile) != 1)
+      CHK_LOG (pAewf, ERROR_AEWF_CANNOT_READ_DATA)
+
+   if (CONFIG(CalcImageFileMD5) && !DisableMD5)
+      CHK (HashMD5Append (&pAewf->CurrentSegmentHashContextMD5, pData, DataLen))
+
+   return NO_ERROR;
+}
+
+static APIRET AewfVerifyFileHeader (t_Aewf *pAewf)
+{
+   t_AewfFileHeader FileHeader;
+
+   CHK (AewfReadFile (pAewf, &FileHeader, sizeof(FileHeader)))
+
+   if (qFromLittleEndian (FileHeader.SegmentNumber) != pAewf->SegmentFiles)
+      CHK_LOG (pAewf, ERROR_AEWF_WRONG_SEGMENT_NUMBER)
+
+   return NO_ERROR;
+}
+
+static APIRET AewfReadSection (t_Aewf *pAewf, t_AewfSection *pSection, bool DisableMD5=false)
+{
+   unsigned int CRC;
+
+   CHK (AewfReadFile (pAewf, pSection, sizeof(t_AewfSection), DisableMD5))
+//   printf ("\nsection %s ", pSection->Name);
+   CRC = AewfCRC (pSection, offsetof (t_AewfSection, CRC));
+   pSection->NextSectionOffset = qFromLittleEndian (pSection->NextSectionOffset);
+   pSection->SectionSize       = qFromLittleEndian (pSection->SectionSize      );
+   pSection->CRC               = qFromLittleEndian (pSection->CRC              );
+   if (CRC != pSection->CRC)
+      CHK_LOG (pAewf, ERROR_AEWF_WRONG_SECTION_CRC)
+
+//   printf (" --  ok");
+   return NO_ERROR;
+}
+
+static APIRET AewfCheckSection (t_Aewf *pAewf, bool *pIsSectors, bool *pIsEof, bool *pIsEoi, quint64 *pNextSectionSeekPos)
 {
+   t_AewfSection Section;
+   int           RemainingLen;
+   bool          IsSectors;
+   bool          IsEof;
+   bool          IsEoi;
+   char          EofTest;
+
+   CHK (AewfReadSection (pAewf, &Section))
+   IsSectors = (strcmp(Section.Name, AEWF_SECTIONNAME_SECTORS) == 0);
+   IsEof     = (strcmp(Section.Name, AEWF_SECTIONNAME_NEXT   ) == 0);
+   IsEoi     = (strcmp(Section.Name, AEWF_SECTIONNAME_DONE   ) == 0);
+   if (IsEof || IsEoi)
+   {                                                               // In this case, there should be no more bytes. Lets try to
+      if (fread (&EofTest, 1, 1, pAewf->pCurrentSegmentFile) == 1) // read 1 more byte - this is one of the rare places where
+         CHK_LOG (pAewf, ERROR_AEWF_DATA_FOLLOWING_LAST_SECTION)   // successful reading leads to an error :-)
+   }
+   if (!IsSectors && !IsEof && !IsEoi)  // Read remaining section data for correct segment MD5 calculation
+   {
+      RemainingLen = Section.SectionSize - sizeof(Section);
+      if (RemainingLen)
+      {
+         if (RemainingLen < 0)
+         CHK_LOG (pAewf, ERROR_AEWF_WRONG_SECTION_LENGTH)
+
+//         printf ("\nCurrentSeekPos %llu - Remaining %u", AewfGetCurrentSeekPos(pAewf), RemainingLen);
+         CHK (AewfReallocVerifyBuffer(pAewf, RemainingLen))
+         CHK (AewfReadFile (pAewf, pAewf->pVerifyBuffer, RemainingLen))
+      }
+   }
+   if (pIsSectors)          *pIsSectors          = IsSectors;
+   if (pIsEof)              *pIsEof              = IsEof;
+   if (pIsEoi)              *pIsEoi              = IsEoi;
+   if (pNextSectionSeekPos) *pNextSectionSeekPos = Section.NextSectionOffset;
+
    return NO_ERROR;
 }
 
-APIRET AewfClose (t_pAewf */*ppAewf*/)
+static APIRET AewfReadTable (t_Aewf *pAewf)
 {
+   t_AewfSection              Section;
+   t_AewfSectionTableContents TableContents;
+   uint                       CalcCRC1;
+   uint                       CalcCRC2, StoredCRC2;
+   uint                       OffsetArrSize;
+   quint64                    DummyOffset;
+
+   DummyOffset = AewfGetCurrentSeekPos(pAewf);
+   CHK (AewfReadSection (pAewf, &Section, true))
+   if (strcmp (Section.Name, AEWF_SECTIONNAME_TABLE) != 0)
+      CHK_LOG (pAewf, ERROR_AEWF_EXPECTED_SECTION_TABLE)
+
+   CHK (AewfReadFile (pAewf, &TableContents, offsetof (t_AewfSectionTableContents, OffsetArr), true))
+   CalcCRC1 = AewfCRC(&TableContents, offsetof(t_AewfSectionTableContents, CRC1));
+   TableContents.Offsets    = qFromLittleEndian (TableContents.Offsets   );
+   TableContents.BaseOffset = qFromLittleEndian (TableContents.BaseOffset);
+   TableContents.CRC1       = qFromLittleEndian (TableContents.CRC1      );
+   if (TableContents.Offsets > AEWF_MAX_CHUNK_OFFSETS)
+      CHK_LOG (pAewf, ERROR_AEWF_TOO_MANY_TABLE_OFFSETS)
+   if (CalcCRC1 != TableContents.CRC1)
+      CHK_LOG (pAewf, ERROR_AEWF_TABLE_WRONG_CRC1)
+
+   pAewf->CurrentChunkOffset = 0;
+   pAewf->ChunkOffsets       = TableContents.Offsets;
+   pAewf->ChunkBaseOffset    = TableContents.BaseOffset;
+   OffsetArrSize = TableContents.Offsets * sizeof (unsigned int);
+   CHK (AewfReadFile (pAewf, &pAewf->ChunkOffsetArr[0], OffsetArrSize      , true))
+   CHK (AewfReadFile (pAewf, &StoredCRC2              , sizeof (StoredCRC2), true))
+   StoredCRC2 = qFromLittleEndian (StoredCRC2);
+   CalcCRC2   = AewfCRC (&pAewf->ChunkOffsetArr[0], OffsetArrSize);
+   if (CalcCRC2 != StoredCRC2)
+      CHK_LOG (pAewf, ERROR_AEWF_TABLE_WRONG_CRC2)
+
+   pAewf->ChunkOffsetArr[TableContents.Offsets] = qToLittleEndian ((uint)(DummyOffset - TableContents.BaseOffset));
+
    return NO_ERROR;
 }
 
-APIRET AewfReadNextChunk (t_pAewf /*pAewf*/, unsigned char */*pData*/, unsigned int */*pDataLen*/)
+// AewfReadNextChunk: Besides reading data chunk, the function returns image filenames and image file hashes "from time to time", i.e. when
+// finishing with the data found in a segment file. If ever this is the case, all 3 params (pSegmentFilename, pMD5Digest and pMD5Valid) are correctly
+// filled in. If not, ImageFilename simply is empty.
+// AewfReadNextChunk must be called again and again until pFinished is set to true, even if no data is returned. This must be done in order to have
+// the function return all segment file names with correct MD5 values.
+
+APIRET AewfReadNextChunk (t_Aewf *pAewf, uchar *pData, uint *pDataLen, QString *pSegmentFilename, t_pHashMD5Digest pMD5Digest, bool *pMD5valid, bool *pFinished)
 {
+   uint    Offset;
+   uint    NextOffset;
+   uint    ReadLen;
+   uint    CalcCRC, StoredCRC;
+   quint64 SavedSeekPos;
+   quint64 NextSectionSeekPos;
+   quint64 FullOffset;
+   bool    Compressed;
+   bool    IsSectors = false;
+   bool    IsEof     = false;  // end of file
+   bool    IsEoi     = false;  // end of image
+//   int     rc;
+   APIRET  rc;
+   uLongf  DataLen;
+
+   *pSegmentFilename = QString();
+   *pMD5valid        = false;
+   *pFinished        = false;
+
+   // Open segment file if necessary and check file header
+   // ----------------------------------------------------
+   if (!pAewf->pCurrentSegmentFile)
+   {
+      QString Extension, Filename;
+
+      // Open next segment file
+      // ----------------------
+      pAewf->SegmentFiles++;
+      Extension = AewfGetExtension (pAewf->SegmentFiles);
+      Filename  = pAewf->SegmentFilename + "." + Extension;
+      pAewf->SegmentFilenameList += Filename;
+
+//      printf ("\nOpening %s", QSTR_TO_PSZ(Filename));
+      pAewf->pCurrentSegmentFile = fopen64 (QSTR_TO_PSZ(Filename), "r");
+      if (pAewf->pCurrentSegmentFile == NULL)
+         CHK_LOG (pAewf, ERROR_AEWF_CANNOT_OPEN_FILE)
+
+      if (CONFIG(CalcImageFileMD5))
+         CHK (HashMD5Init (&pAewf->CurrentSegmentHashContextMD5))
+
+      CHK (AewfVerifyFileHeader (pAewf))
+      memset (pAewf->ChunkOffsetArr, 0, sizeof(pAewf->ChunkOffsetArr));
+      pAewf->ChunkBaseOffset    = 0;
+      pAewf->ChunkOffsets       = 0;
+      pAewf->CurrentChunkOffset = 0;
+   }
+
+   // Check if still chunks remain; search next section "sectors" if
+   // not; close segment file if no other section "sectors" is present
+   // -----------------------------------------------------------------
+   if (pAewf->CurrentChunkOffset == pAewf->ChunkOffsets)
+   {
+      do
+      {
+         CHK (AewfCheckSection (pAewf, &IsSectors, &IsEof, &IsEoi, &NextSectionSeekPos))    // Loop through sections until a new section "sectors" is found
+      }
+      while (!IsSectors && !IsEof && !IsEoi);
+      if (IsEof || IsEoi)
+      {
+//         printf ("\nClosing current file");
+         if (fclose (pAewf->pCurrentSegmentFile))
+            CHK_LOG (pAewf, ERROR_AEWF_CANNOT_CLOSE_FILE)
+         pAewf->pCurrentSegmentFile = NULL;
+
+         *pDataLen         = 0;
+         *pSegmentFilename = pAewf->SegmentFilenameList[pAewf->SegmentFiles-1];
+         *pFinished        = IsEoi;
+         if (CONFIG(CalcImageFileMD5))
+         {
+            CHK (HashMD5Digest (&pAewf->CurrentSegmentHashContextMD5, pMD5Digest))
+            *pMD5valid = true;
+         }
+         return NO_ERROR;
+      }
+      SavedSeekPos = AewfGetCurrentSeekPos(pAewf);
+      CHK (AewfSetCurrentSeekPos (pAewf, NextSectionSeekPos))
+      CHK (AewfReadTable         (pAewf))
+      CHK (AewfSetCurrentSeekPos (pAewf, SavedSeekPos))
+   }
+
+   // Read next chunk
+   // ---------------
+//   printf ("\nReading chunk %u", pAewf->CurrentChunkOffset);
+   Offset      = qFromLittleEndian (pAewf->ChunkOffsetArr[pAewf->CurrentChunkOffset++]);
+   NextOffset  = qFromLittleEndian (pAewf->ChunkOffsetArr[pAewf->CurrentChunkOffset  ]);
+   Compressed  = ((Offset & AEWF_COMPRESSED_CHUNK) != 0);
+   Offset     &= ~AEWF_COMPRESSED_CHUNK;
+   NextOffset &= ~AEWF_COMPRESSED_CHUNK;
+   ReadLen     = NextOffset - Offset;
+   FullOffset  = pAewf->ChunkBaseOffset + Offset;
+//   printf (" -- size %u", ReadLen);
+
+   if (AewfGetCurrentSeekPos(pAewf) != FullOffset)  // Check if table entry is correct
+   {
+      LOG_INFO ("AEWF section table: Offset is %llu, current seek pos is %llu", FullOffset, AewfGetCurrentSeekPos(pAewf))
+      CHK_LOG (pAewf, ERROR_AEWF_TABLE_CORRUPT)
+   }
+
+   if (!Compressed)
+   {
+      if (ReadLen > *pDataLen)
+         CHK_LOG (pAewf, ERROR_AEWF_VERIFY_BUFFER_TOO_SMALL)
+      CHK (AewfReadFile (pAewf, pData, ReadLen))
+
+      *pDataLen = ReadLen - sizeof (unsigned int);  // CRC is at the end of uncompressed data
+      CalcCRC   = AewfCRC (pData, *pDataLen);
+      StoredCRC = qFromLittleEndian (* ((unsigned int *) (&pData[*pDataLen])));
+      if (CalcCRC != StoredCRC)
+         CHK_LOG (pAewf, ERROR_AEWF_DATA_CRC_ERROR)
+   }
+   else
+   {
+      CHK (AewfReallocVerifyBuffer (pAewf, ReadLen))
+      CHK (AewfReadFile            (pAewf, pAewf->pVerifyBuffer, ReadLen))
+
+      DataLen = *pDataLen;
+//      rc = uncompress (pData, &DataLen, pAewf->pVerifyBuffer, ReadLen);
+      rc = AewfUncompress (pData, &DataLen, pAewf->pVerifyBuffer, ReadLen);
+      
+      *pDataLen = DataLen;
+//      if (rc != Z_OK)
+      if (rc != NO_ERROR)
+      {
+//         LOG_ERROR ("Zlib uncompress returned %d", rc)
+//         CHK_LOG (pAewf, ERROR_AEWF_UNCOMPRESS_FAILED)
+         CHK_LOG (pAewf, rc)
+      }
+   }
+
    return NO_ERROR;
 }
 
 // -----------------------
-//  Module initialisation
+//      Misc. functions
 // -----------------------
 
+unsigned int AewfPreprocessExtraSpace (uint FifoBlockSize)
+{
+   // AEWF needs some extra FIFO block buffer space in order to do the compression or to add the CRC
+   // at the ende of the uncompressed data. We take the max. value of both in order to be sure that
+   // enough space is available for both.
+
+   uint ExtraZ               = UtilGetMaxZcompressedBufferSize (FifoBlockSize) - FifoBlockSize;
+   uint ExtraUncompressedCRC = sizeof (unsigned int);
+
+   return GETMAX (ExtraZ, ExtraUncompressedCRC);
+}
+
+
 APIRET AewfInit (void)
 {
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_MEMALLOC_FAILED        ))
-   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_WRITE_FILE      ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_MEMALLOC_FAILED            ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_WRITE_FILE          ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_ANOTHER_FILE_STILL_OPEN    ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_NO_FILE_OPEN               ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_FLUSH_FILE          ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_CLOSE_FILE          ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_INVALID_COMPRESSION_LEVEL  ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_COMPRESSION_FAILED         ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_SEEK                ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_OPEN_FILE           ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_TABLE_CORRUPT              ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_VERIFY_BUFFER_TOO_SMALL    ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_CANNOT_READ_DATA           ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_DATA_CRC_ERROR             ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_UNCOMPRESS_FAILED          ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_WRONG_SEGMENT_NUMBER       ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_WRONG_SECTION_CRC          ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_ENDING_SECTION_MISSING     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_EXPECTED_SECTION_TABLE     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_TABLE_WRONG_CRC1           ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_TABLE_WRONG_CRC2           ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_TOO_MANY_TABLE_OFFSETS     ))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_DATA_FOLLOWING_LAST_SECTION))
+   CHK (TOOL_ERROR_REGISTER_CODE (ERROR_AEWF_WRONG_SECTION_LENGTH       ))
 
+   // Compressed zero buffer initialisation
+   // -------------------------------------
+   unsigned char  *pZeroBuff;
+   int              rc;
+   
+   AewfZeroBlockUnCompressedLen = CONFIG (FifoBlockSizeEWF);             // Alloc and initialise zero and compression buffers
+   AewfZeroBlockCompressedLen   = UtilGetMaxZcompressedBufferSize (AewfZeroBlockUnCompressedLen);
+   pZeroBuff                    = (unsigned char *) malloc (AewfZeroBlockUnCompressedLen); 
+   pAewfZeroBlockCompressed     = (unsigned char *) malloc (AewfZeroBlockUnCompressedLen);
+   if ((pZeroBuff == NULL) || (pAewfZeroBlockCompressed == NULL))
+      CHK (ERROR_AEWF_MEMALLOC_FAILED)
+   memset (pZeroBuff, 0, AewfZeroBlockUnCompressedLen);
+   
+   rc = compress2 ((Bytef*)pAewfZeroBlockCompressed, &AewfZeroBlockCompressedLen, (Bytef*)pZeroBuff, AewfZeroBlockUnCompressedLen, 9); // Compress zero buff
+   if (rc != Z_OK)
+      CHK (ERROR_AEWF_COMPRESSION_FAILED)
+   
+   free (pAewfZeroBlockCompressed);                                   // Realloc compressed to the size that is really needed
+   pAewfZeroBlockCompressed = (unsigned char *) malloc (AewfZeroBlockCompressedLen);
+   if (pAewfZeroBlockCompressed == NULL)
+      CHK (ERROR_AEWF_MEMALLOC_FAILED)
+   
+   rc = compress2 ((Bytef*)pAewfZeroBlockCompressed, &AewfZeroBlockCompressedLen, (Bytef*)pZeroBuff, AewfZeroBlockUnCompressedLen, 9);
+   if (rc != Z_OK)
+      CHK (ERROR_AEWF_COMPRESSION_FAILED)
+      
+   free (pZeroBuff);
+   
    return NO_ERROR;
 }
 
 APIRET AewfDeInit (void)
 {
+   free (pAewfZeroBlockCompressed);
+   
    return NO_ERROR;
 }
diff --git a/aewf.h b/aewf.h
index 5aa6bec..29741bb 100644
--- a/aewf.h
+++ b/aewf.h
@@ -6,10 +6,10 @@
 //                  Service de Police Judiciaire
 //                  Section Nouvelles Technologies
 // ****************************************************************************
-//  Module:         Multithreaded AEWF (AEWF = Avanced EWF)
+//  Module:         Multithreaded AEWF (AEWF = Advanced EWF)
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -29,32 +29,60 @@
 #ifndef __AEWF_H__
 #define __AEWF_H__
 
-typedef struct _t_Aewf *t_pAewf;
+#include "hash.h"
+
+class t_Aewf;
+typedef t_Aewf *t_pAewf;
 
 typedef struct
 {
-   bool Dummy;
+   bool Compressed;   // Tells AewfWrite whether the data should be written compressed or uncompressed
+   int  DataLenOut;   // If Compressed - is true:  The size of the compressed data
+                      //               - is false: The size of the original data + size of CRC
 } t_AewfPreprocess, *t_pAewfPreprocess;
 
+typedef enum
+{
+   AEWF_MEDIATYPE_REMOVABLE = 0x00,
+   AEWF_MEDIATYPE_FIXED     = 0x01,
+   AEWF_MEDIATYPE_OPTICAL   = 0x03
+} t_AewfMediaType;
+
+typedef enum
+{
+   AEWF_MEDIAFLAGS_IMAGE          = 0x01,
+   AEWF_MEDIAFLAGS_PHYSICAL       = 0x02,
+   AEWF_MEDIAFLAGS_FASTBLOCK_USED = 0x04,
+   AEWF_MEDIAFLAGS_TABLEAU_USED   = 0x08
+} t_AewfMediaFlags;
+
 // ------------------------------------
 //              Functions
 // ------------------------------------
 
 // Write access functions
-APIRET AewfOpen          (t_pAewf *ppAewf, const char *pFilename, unsigned long long DeviceSize, unsigned int SectorSize, unsigned int ChunkSize);
-APIRET AewfPreprocess    (t_pAewfPreprocess *ppPreprocess, unsigned char *pDataIn, unsigned int DataLenIn, unsigned char *pDataOut, unsigned int DataLenOut);
-APIRET AewfWrite         (t_pAewf   pAewf, t_pAewfPreprocess pPreprocess, const unsigned char *pData, unsigned int DataLen);
-APIRET AewfClose         (t_pAewf *ppAewf, unsigned long long BadSectors, const unsigned char *pMD5, const unsigned char *pSHA256, int Duration);
+// ----------------------
+APIRET AewfOpen (t_pAewf *ppAewf, const char *pFilename,
+                                  quint64 DeviceSize, quint64 SegmentSize,
+                                  uint    ChunkSize , uint    SectorSize,
+                                  t_AewfMediaType    MediaType,
+                                  t_AewfMediaFlags   MediaFlags,
+                                  QString Description, QString CaseNumber,  QString EvidenceNumber, QString Examiner,
+                                  QString Notes,       QString DeviceModel, QString SerialNumber,   QString ImagerVersion,
+                                  QString OSVersion);
+APIRET AewfPreprocess    (t_pAewf   pAewf, t_pAewfPreprocess *ppPreprocess, uchar *pDataIn, uint DataLenIn, uchar *pDataOut, uint DataLenOut);
+APIRET AewfWrite         (t_pAewf   pAewf, t_pAewfPreprocess pPreprocess, const uchar *pData, uint DataLen);
+APIRET AewfClose         (t_pAewf *ppAewf, QList<quint64> &BadSectors, const uchar *pMD5, const uchar *pSHA256);
 
 // Read access functions
+// ---------------------
 APIRET AewfOpen          (t_pAewf *ppAewf, const char *pFilename);
-APIRET AewfReadNextChunk (t_pAewf   pAewf, unsigned char *pData, unsigned int *pDataLen);
+APIRET AewfReadNextChunk (t_pAewf   pAewf, uchar *pData, uint *pDataLen, QString *pSegmentFilename, t_pHashMD5Digest pMD5, bool *pMD5valid, bool *pFinished);
 APIRET AewfClose         (t_pAewf *ppAewf);
 
-
-APIRET AewfWriteSegmentStr (t_pAewf pAewf, const char *pName, unsigned int Argument, const char *pStr);
-
-APIRET AewfCopyBadSectorMarker (unsigned char *pBuffer, unsigned int Len);
+// Misc. functions
+// ---------------
+uint AewfPreprocessExtraSpace (uint FifoBlockSize);
 
 APIRET AewfInit   (void);
 APIRET AewfDeInit (void);
@@ -67,7 +95,30 @@ APIRET AewfDeInit (void);
 enum
 {
    ERROR_AEWF_MEMALLOC_FAILED = ERROR_BASE_AEWF + 1,
-   ERROR_AEWF_CANNOT_WRITE_FILE
+   ERROR_AEWF_CANNOT_CREATE_FILE,
+   ERROR_AEWF_CANNOT_WRITE_FILE,
+   ERROR_AEWF_ANOTHER_FILE_STILL_OPEN,
+   ERROR_AEWF_NO_FILE_OPEN,
+   ERROR_AEWF_CANNOT_FLUSH_FILE,
+   ERROR_AEWF_CANNOT_CLOSE_FILE,
+   ERROR_AEWF_INVALID_COMPRESSION_LEVEL,
+   ERROR_AEWF_COMPRESSION_FAILED,
+   ERROR_AEWF_CANNOT_SEEK,
+   ERROR_AEWF_CANNOT_OPEN_FILE,
+   ERROR_AEWF_TABLE_CORRUPT,
+   ERROR_AEWF_VERIFY_BUFFER_TOO_SMALL,
+   ERROR_AEWF_CANNOT_READ_DATA,
+   ERROR_AEWF_DATA_CRC_ERROR,
+   ERROR_AEWF_UNCOMPRESS_FAILED,
+   ERROR_AEWF_WRONG_SEGMENT_NUMBER,
+   ERROR_AEWF_WRONG_SECTION_CRC,
+   ERROR_AEWF_ENDING_SECTION_MISSING,
+   ERROR_AEWF_EXPECTED_SECTION_TABLE,
+   ERROR_AEWF_TABLE_WRONG_CRC1,
+   ERROR_AEWF_TABLE_WRONG_CRC2,
+   ERROR_AEWF_TOO_MANY_TABLE_OFFSETS,
+   ERROR_AEWF_DATA_FOLLOWING_LAST_SECTION,
+   ERROR_AEWF_WRONG_SECTION_LENGTH
 };
 
 #endif
diff --git a/common.h b/common.h
index 51300ea..e596541 100644
--- a/common.h
+++ b/common.h
@@ -9,7 +9,7 @@
 //  Module:         Standard include file
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -26,9 +26,17 @@
 // You should have received a copy of the GNU General Public License
 // along with guymager. If not, see <http://www.gnu.org/licenses/>.
 
+
+#ifdef LINT_CODE_CHECK
+#include "macros_for_lint.h"
+#endif
+
 #ifndef __COMMON_H__
 #define __COMMON_H__
 
+#define USE_MD5_FROM_OPENSSL
+#define USE_SHA256_FROM_OPENSSL
+
 // GNU C lib definitions
 // ---------------------
 #ifndef _LARGEFILE_SOURCE
diff --git a/compileinfo.h b/compileinfo.h
index 7bc27b1..a8aa2cb 100644
--- a/compileinfo.h
+++ b/compileinfo.h
@@ -12,7 +12,7 @@
 // See .pro file as well.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/config.cpp b/config.cpp
index 8318d76..6774dad 100644
--- a/config.cpp
+++ b/config.cpp
@@ -9,7 +9,7 @@
 //  Module:         Application configuration data
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -195,6 +195,10 @@ static t_ToolCfgSet SetArrColor[] =
    // Name in cfg file          Corresponding value
    // ---------------------------------------------------------
    {  "LocalDevices"          , COLOR_LOCALDEVICES            },
+   {  "AdditionalState1"      , COLOR_ADDITIONALSTATE1        },
+   {  "AdditionalState2"      , COLOR_ADDITIONALSTATE2        },
+   {  "AdditionalState3"      , COLOR_ADDITIONALSTATE3        },
+   {  "AdditionalState4"      , COLOR_ADDITIONALSTATE4        },
    {  "StateIdle"             , COLOR_STATE_IDLE              },
    {  "StateAcquire"          , COLOR_STATE_ACQUIRE           },
    {  "StateAcquirePaused"    , COLOR_STATE_ACQUIRE_PAUSED    },
@@ -209,33 +213,35 @@ static t_ToolCfgSet SetArrColor[] =
 };
 
 
-static t_ToolCfgSet SetArrEwfFormat[] =
+static t_ToolCfgSet SetArrFormat[] =
 {
    // Name in cfg file   Corresponding value
    // ------------------------------------------
-   {  "Encase1",         LIBEWF_FORMAT_ENCASE1},
-   {  "Encase2",         LIBEWF_FORMAT_ENCASE2},
-   {  "Encase3",         LIBEWF_FORMAT_ENCASE3},
-   {  "Encase4",         LIBEWF_FORMAT_ENCASE4},
-   {  "Encase5",         LIBEWF_FORMAT_ENCASE5},
-   {  "Encase6",         LIBEWF_FORMAT_ENCASE6},
-   {  "Smart"  ,         LIBEWF_FORMAT_SMART  },
-   {  "FTK"    ,         LIBEWF_FORMAT_FTK    },
-   {  "Linen5" ,         LIBEWF_FORMAT_LINEN5 },
-   {  "Linen6" ,         LIBEWF_FORMAT_LINEN6 },
-   {  "LVF"    ,         LIBEWF_FORMAT_LVF    },
-   {   NULL    ,         0                    }
+   {  "DD"      ,        t_File::DD  },
+   {  "EWF"     ,        t_File::EWF },
+   {  "AFF"     ,        t_File::AAFF},
+   {  "AAFF"    ,        t_File::AAFF},
+   {   NULL     ,        0           }
 };
 
-
-static t_ToolCfgSet SetArrFormat[] =
+static t_ToolCfgSet SetArrEwfFormat[] =
 {
    // Name in cfg file   Corresponding value
    // ------------------------------------------
-   {  "DD"     ,         t_File::DD },
-   {  "EWF"    ,         t_File::EWF},
-   {  "AFF"    ,         t_File::AFF},
-   {   NULL    ,         0          }
+   {  "Encase1" ,         LIBEWF_FORMAT_ENCASE1},
+   {  "Encase2" ,         LIBEWF_FORMAT_ENCASE2},
+   {  "Encase3" ,         LIBEWF_FORMAT_ENCASE3},
+   {  "Encase4" ,         LIBEWF_FORMAT_ENCASE4},
+   {  "Encase5" ,         LIBEWF_FORMAT_ENCASE5},
+   {  "Encase6" ,         LIBEWF_FORMAT_ENCASE6},
+   {  "Smart"   ,         LIBEWF_FORMAT_SMART  },
+   {  "FTK"     ,         LIBEWF_FORMAT_FTK    },
+   {  "Linen5"  ,         LIBEWF_FORMAT_LINEN5 },
+   {  "Linen6"  ,         LIBEWF_FORMAT_LINEN6 },
+   {  "LVF"     ,         LIBEWF_FORMAT_LVF    },
+   {  "Guymager",         t_File::AEWF         }, // AEWF format is a format on its own (for the function calls) and at the same time a
+   {  "AEWF"    ,         t_File::AEWF         }, // subformat of EWF (for the user interface). Looks a bit strange at first sight, but
+   {   NULL     ,         0                    }  // probably is the best compromise.
 };
 
 
@@ -332,10 +338,14 @@ static t_ToolCfgParamDesc CfgParamDescArr[] =
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"AffCompression"                , CFGTYPE_INTEGER, ELT(AffCompression)                ,                0,       1,       9, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"AffMarkBadSectors"             , CFGTYPE_SET    , ELT(AffMarkBadSectors)             ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"SpecialFilenameChars"          , CFGTYPE_STRING , ELT_SIZ(SpecialFilenameChars)      ,                         0,       0, NULL                            }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"CalcImageFileMD5"              , CFGTYPE_SET    , ELT(CalcImageFileMD5)              ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"AvoidEncaseProblems"           , CFGTYPE_SET    , ELT(AvoidEncaseProblems)           ,                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
 
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"DeviceScanMethod"              , CFGTYPE_SET    , ELT(DeviceScanMethod)              ,                0,       0,       0, INIARR(SetArrDeviceScanMethod)  }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"ScanInterval"                  , CFGTYPE_INTEGER, ELT(ScanInterval                  ),                0,       1, 8640000, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"CommandGetSerialNumber"        , CFGTYPE_STRING , ELT_SIZ(CommandGetSerialNumber    ),                         0,       0, NULL                            }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"CommandGetAddStateInfo"        , CFGTYPE_STRING , ELT_SIZ(CommandGetAddStateInfo    ),                         0,       0, NULL                            }, CFG_FILLUP_FORLINT},
+   {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"DirectIO"                      , CFGTYPE_SET    , ELT(DirectIO                      ),                0,       0,       0, INIARR(SetArrBoolean)           }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoBlockSizeDD"               , CFGTYPE_INTEGER, ELT(FifoBlockSizeDD               ),                0,       0,99999999, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoBlockSizeEWF"              , CFGTYPE_INTEGER, ELT(FifoBlockSizeEWF              ),                0,       0,99999999, NULL                            }, CFG_FILLUP_FORLINT},
    {CFGASSIGN_BOTH_MULTIPLE, NULL       , {"FifoBlockSizeAFF"              , CFGTYPE_INTEGER, ELT(FifoBlockSizeAFF              ),                0,       0,99999999, NULL                            }, CFG_FILLUP_FORLINT},
diff --git a/config.h b/config.h
index de15270..15c5365 100644
--- a/config.h
+++ b/config.h
@@ -7,7 +7,7 @@
 //                  Section Nouvelles Technologies
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -76,6 +76,10 @@ typedef enum
 typedef enum
 {
    COLOR_LOCALDEVICES=0,
+   COLOR_ADDITIONALSTATE1,
+   COLOR_ADDITIONALSTATE2,
+   COLOR_ADDITIONALSTATE3,
+   COLOR_ADDITIONALSTATE4,
    COLOR_STATE_IDLE,
    COLOR_STATE_ACQUIRE,
    COLOR_STATE_ACQUIRE_PAUSED,
@@ -88,7 +92,7 @@ typedef enum
    COLOR_STATE_ABORTED_OTHER,
 
    COLOR_COUNT,
-   COLOR_DEFAULT  // Not really a color, but used for specifying, that a widget should switch to its default color (grey for a button, for instance)
+   COLOR_DEFAULT=-1  // Not really a color, but used for specifying, that a widget should switch to its default color (grey for a button, for instance)
 } t_CfgColor;
 
 typedef enum
@@ -129,6 +133,8 @@ typedef struct
    t_CfgScanMethod      DeviceScanMethod;
    int                  ScanInterval;
    char                 CommandGetSerialNumber[CFG_MAX_PATH_LEN+1];
+   char                 CommandGetAddStateInfo[CFG_MAX_PATH_LEN+1];
+   int                  DirectIO;
 
    int                  DefaultFormat;
    int                  EwfFormat;
@@ -136,6 +142,8 @@ typedef struct
    int                  AffCompression;
    int                  AffMarkBadSectors;
    char                 SpecialFilenameChars[CFG_MAX_MISC_LEN+1];
+   int                  CalcImageFileMD5;
+   int                  AvoidEncaseProblems;
 
    int                  FifoBlockSizeDD;
    int                  FifoBlockSizeEWF;
@@ -144,6 +152,7 @@ typedef struct
    int                  FifoMemoryManager;
    int                  UseSeparateHashThread;
    int                  CompressionThreads;
+
    int                  SignalHandling;
    int                  WriteToDevNull;
    int                  UseMemWatch;
@@ -249,7 +258,7 @@ class t_CfgDlgAcquireField
       QCheckBox            *pCheckBox;
       QComboBox            *pComboBox;
       QLabel               *pLabel;
-};
+}; //lint !e1553
 typedef t_CfgDlgAcquireField       *t_pCfgDlgAcquireField;
 typedef QList<t_pCfgDlgAcquireField> t_CfgDlgAcquireFields;
 typedef t_CfgDlgAcquireFields      *t_pCfgDlgAcquireFields;
@@ -260,7 +269,7 @@ class t_CfgDlgAcquireRule
       QString TriggerFieldName;
       QString DestFieldName;
       QString Value;
-};
+}; //lint !e1553
 typedef t_CfgDlgAcquireRule        *t_pCfgDlgAcquireRule;
 typedef QList<t_pCfgDlgAcquireRule> t_CfgDlgAcquireRules;
 typedef t_CfgDlgAcquireRules       *t_pCfgDlgAcquireRules;
diff --git a/device.cpp b/device.cpp
index 8d4a3fb..d7163f5 100644
--- a/device.cpp
+++ b/device.cpp
@@ -11,7 +11,7 @@
 //                  window.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -105,6 +105,7 @@ void t_Device::Initialise (void)
    memset (&this->SHA256Digest         , 0, sizeof(this->SHA256Digest         ));
    memset (&this->SHA256DigestVerifySrc, 0, sizeof(this->SHA256DigestVerifySrc));
    memset (&this->SHA256DigestVerifyDst, 0, sizeof(this->SHA256DigestVerifyDst));
+// this->ImageFileHashes
 
    this->pFifoCompressIn      = NULL;
    this->pFifoCompressOut     = NULL;
@@ -127,11 +128,16 @@ void t_Device::Initialise (void)
 //   this->Acquisition.Description   = QString();
 //   this->Acquisition.Notes         = QString();
 
+   this->AddStateInfo.CanBeAcquired = true   ;
+   this->AddStateInfo.Color         = COLOR_DEFAULT;
+// this->AddStateInfo.Info          = QString();
+   
    this->Info.SetDevice(this);
 
-   this->PrevTimestamp     = QTime();
-   this->PrevSpeed         = 0.0;
-   this->Checked           = false;
+   this->PrevTimestamp = QTime();
+   this->PrevSpeed     = 0.0;
+   this->Checked       = false;
+   this->AddedNow      = false;
 }
 
 void t_Device::InitialiseDeviceSpecific (const QString &SerialNumber, const QString &LinuxDevice, const QString &Model,
@@ -146,10 +152,13 @@ void t_Device::InitialiseDeviceSpecific (const QString &SerialNumber, const QStr
    this->SectorSizePhys = SectorSizePhys;
    this->Size           = Size;
 
+//   #define FAKE_DEVICE_SIZE
    #ifdef FAKE_DEVICE_SIZE
-      // this->Size = GETMIN (10737418240ULL, Size);  // 10 GiB For faster testing (we make guymager believe that the device is smaller)
-      // this->Size = GETMIN (   20485760ULL, Size);  // 20 MiB
-      // this->Size = GETMIN ( 1000000000ULL, Size);  //  1 GB
+   #warning "Debug code for device size faking still enabled"
+       this->Size = GETMIN ( 10*1024, Size);               // 10K
+      // this->Size = GETMIN ( 20971520ULL, Size);           // 20 MiB
+      // this->Size = GETMIN ( 1024*1024*1024ULL, Size);     //  1 GB
+      // this->Size = GETMIN (10737418240ULL, Size);         // 10 GiB
       // this->Size = 3ULL*1024ULL*1024ULL*1024ULL*1024ULL;  //  3 TB
       printf ("\nSize of all devices faked to %llu bytes", this->Size);
    #endif
@@ -187,8 +196,9 @@ bool t_Device::HasHashThread (void) const
 
 bool t_Device::HasCompressionThreads (void) const
 {
-   return (CONFIG (CompressionThreads) > 0) && ((Acquisition.Format == t_File::EWF) ||
-                                                (Acquisition.Format == t_File::AFF));
+   return (CONFIG (CompressionThreads) > 0) && ((Acquisition.Format == t_File::EWF ) ||
+                                                (Acquisition.Format == t_File::AAFF) ||
+                                                (Acquisition.Format == t_File::AEWF));
 }
 
 
@@ -199,6 +209,11 @@ QVariant t_Device::GetSerialNumber (t_pDevice pDevice)
    return pDevice->SerialNumber;
 }
 
+QVariant t_Device::GetAddStateInfo (t_pDevice pDevice)
+{
+   return pDevice->AddStateInfo.Info;
+}
+
 QVariant t_Device::GetLinuxDevice (t_pDevice pDevice)
 {
    return pDevice->LinuxDevice;
@@ -216,10 +231,22 @@ QVariant t_Device::GetState (t_pDevice pDevice)
    switch (pDevice->State)
    {
       case Idle         : if (pDevice->Local)
-                                    StrState = t_MainWindow::tr("Local device");
-                          else if (MainGetDeviceList()->UsedAsCloneDestination(pDevice))
-                                    StrState = t_MainWindow::tr("Used in clone operation");
-                               else StrState = t_MainWindow::tr("Idle");
+                          {
+                             StrState = t_MainWindow::tr("Local device");
+                          }
+                          else 
+                          {
+                             if (MainGetDeviceList()->UsedAsCloneDestination(pDevice))
+                             {
+                                StrState = t_MainWindow::tr("Used in clone operation");
+                             }
+                             else
+                             {
+                                StrState = t_MainWindow::tr("Idle");
+                                if (CONFIG (CommandGetAddStateInfo)[0])
+                                   StrState += " - " + pDevice->AddStateInfo.Info;
+                             }
+                          }
                           break;
       case Acquire      : if (pDevice->AbortRequest)
                                StrState = t_MainWindow::tr("Aborting..."        );
@@ -238,7 +265,7 @@ QVariant t_Device::GetState (t_pDevice pDevice)
                                 case  6: StrState += " just shut up"; break;
                                 case  7: StrState += " SHUT UP!"; break;
                                 case  8: StrState += " you want a segmentation fault?"; break;
-                                case  9: StrState += " you can have it if you want"; break;
+                                case  9: StrState += " you can have one if you want"; break;
                                 case 10: StrState += " I warn you"; break;
                                 case 11: StrState += " last warning"; break;
                                 case 12: StrState += " ultimate warning"; break;
@@ -285,6 +312,8 @@ QVariant t_Device::GetState (t_pDevice pDevice)
                         case t_Device::ThreadWriteWriteError : StrState = t_MainWindow::tr("Aborted - Image file write error" );  break;
                         case t_Device::ThreadWriteVerifyError: StrState = t_MainWindow::tr("Aborted - Image file verify error" ); break;
                         case t_Device::ThreadReadFileError   : StrState = t_MainWindow::tr("Aborted - Device read error" );       break;
+                        case t_Device::InfoWriteError        : StrState = t_MainWindow::tr("Aborted - Info file write error");    break;
+                        case t_Device::AcquisitionStartFailed: StrState = t_MainWindow::tr("Aborted - Acquisition start failure");break;
                         default                              : CHK_EXIT (ERROR_DEVICE_BAD_ABORTREASON)
                      }
                      break;
@@ -644,7 +673,15 @@ APIRET t_DeviceList::MatchDevice (t_pcDevice pDevCmp, t_pDevice &pDevMatch)
       }         
       else  // Not a special device, we can use normal matching
       {
-         if (pDevMatch->SerialNumber.isEmpty())
+// Lines below commented out, as somebody might change assignement of the devices starting with the names shown below after Guymager has done a device scan
+//         if ((pDevMatch->LinuxDevice.startsWidth("/dev/loop") ||  // These are devices generated internally by the loop device driver,
+//             (pDevMatch->LinuxDevice.startsWidth("/dev/dm-" ) ||  // LVM or DM. we can be sure that they have unique names, so let's
+//             (pDevMatch->LinuxDevice.startsWidth("/dev/md"  ))    // avoid all the problems with empty serial numbers and so on.
+//         {
+//            Found = (pDevMatch->LinuxDevice == pDevCmp->LinuxDevice);
+//         }
+//         else
+              if (pDevMatch->SerialNumber.isEmpty())
          {
             Found = (pDevCmp->SerialNumber.isEmpty() && (pDevMatch->State != t_Device::AcquirePaused) &&
                                                         (pDevMatch->State != t_Device::VerifyPaused ) &&
diff --git a/device.h b/device.h
index 523686a..103c398 100644
--- a/device.h
+++ b/device.h
@@ -7,7 +7,7 @@
 //                  Section Nouvelles Technologies
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -39,6 +39,7 @@
 #include "info.h"
 #include "file.h"
 #include "media.h"
+#include "config.h"
 
 class t_ThreadRead;
 class t_ThreadHash;
@@ -69,7 +70,9 @@ class t_Device
          UserRequest,
          ThreadWriteWriteError,
          ThreadWriteVerifyError,
-         ThreadReadFileError
+         ThreadReadFileError,
+         InfoWriteError,
+         AcquisitionStartFailed
       } t_AbortReason;
 
       static const int AutoFracLen       = -1;   // Use up to 2 digits after decimal point (min. 3 significant digits)
@@ -97,6 +100,39 @@ class t_Device
             quint64        SplitFileSize;    // 0 means do not split
       };
 
+      class t_ImageFileHash // Holds the hash of a complete image file (not just the image contents)
+      {
+         public:
+            t_ImageFileHash (const QString &Filename, t_pHashMD5Digest pMD5Digest=NULL, bool MD5ok=false)
+            {
+               this->Filename = Filename;
+               MD5Valid = (pMD5Digest != NULL) && MD5ok;
+               if (MD5Valid)
+                  MD5Digest = *pMD5Digest;
+            }
+
+         public:
+            QString         Filename;
+            bool            MD5Valid;
+            t_HashMD5Digest MD5Digest;
+      };
+
+      class t_AddStateInfo       // Allows the user to add state information to a device
+      {
+          public:
+             t_AddStateInfo () : CanBeAcquired(true),
+                                 Color(COLOR_DEFAULT)
+             {};
+
+          public:
+             QString Info;
+             bool    CanBeAcquired;
+             int     Color;         // Refers to the color AdditionalState1, AdditionalState2, ... in the configuration file.
+      };
+
+
+      typedef QList<t_ImageFileHash *> t_ImageFileHashList;
+
    public:
       t_Device (const QString &SerialNumber=QString(), const PedDevice *pPedDev=NULL);
       t_Device (const QString &SerialNumber, const QString &LinuxDevice, const QString &Model,
@@ -107,6 +143,7 @@ class t_Device
       static QVariant GetLinuxDevice         (t_pDevice pDevice);
       static QVariant GetModel               (t_pDevice pDevice);
       static QVariant GetState               (t_pDevice pDevice);
+      static QVariant GetAddStateInfo        (t_pDevice pDevice);
       static QVariant GetSectorSize          (t_pDevice pDevice);
       static QVariant GetSectorSizePhys      (t_pDevice pDevice);
       static QVariant GetBadSectorCount      (t_pDevice pDevice);
@@ -268,7 +305,8 @@ class t_Device
 
             t_State                   State;
    private: QString                   Message;          // Used by the threads to communicate messages displayed in spreadsheet field "state"
-   public:  bool                      AbortRequest;
+   public:  t_AddStateInfo            AddStateInfo;
+            bool                      AbortRequest;
             int                       AbortCount;       // Little easter egg  ;-)
             t_AbortReason             AbortReason;
             bool                      DeleteAfterAbort;
@@ -311,11 +349,13 @@ class t_Device
             t_HashSHA256Digest        SHA256Digest;
             t_HashSHA256Digest        SHA256DigestVerifySrc;
             t_HashSHA256Digest        SHA256DigestVerifyDst;
+            t_ImageFileHashList       ImageFileHashList;
 
    public:  quint64                   PrevPos;          // Some variables for
             QTime                     PrevTimestamp;    // the current speed
             double                    PrevSpeed;        // calculation.
-            bool                      Checked;          // Helper variable for matching algorithm in SlotScanFinished, not used elsewhere.
+            bool                      Checked;          // Helper variables for matching algorithm ...
+            bool                      AddedNow;         // ... in SlotScanFinished, not used elsewhere.
 
    private: QReadWriteLock            SemCurrentWritePos;
    private: QReadWriteLock            SemCurrentVerifyPosSrc;
diff --git a/devicelistmodel.h b/devicelistmodel.h
index 6ccf19c..ee255d1 100644
--- a/devicelistmodel.h
+++ b/devicelistmodel.h
@@ -10,7 +10,7 @@
 //                  screen
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgabort.cpp b/dlgabort.cpp
index 9eccef7..28fb99b 100644
--- a/dlgabort.cpp
+++ b/dlgabort.cpp
@@ -9,7 +9,7 @@
 //  Module:         Dialog that is opened when aborting an acquisition
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -26,6 +26,8 @@
 // You should have received a copy of the GNU General Public License
 // along with guymager. If not, see <http://www.gnu.org/licenses/>.
 
+#include <QtGui>
+
 #include "dlgabort.h"
 
 // -----------------------------
diff --git a/dlgabort.h b/dlgabort.h
index a7eec57..3616012 100644
--- a/dlgabort.h
+++ b/dlgabort.h
@@ -9,7 +9,7 @@
 //  Module:         Dialog that is opened when aborting an acquisition
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgacquire.cpp b/dlgacquire.cpp
index 5d8fef5..15c30cc 100644
--- a/dlgacquire.cpp
+++ b/dlgacquire.cpp
@@ -9,7 +9,7 @@
 //  Module:         Acquisition dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -70,6 +70,9 @@ class t_DlgAcquireLocal
       QPushButton     *pButtonCancel;
 
       t_pDevice        pDevice;
+
+      bool              OldSplitFileSwitch;              // Required to remember SplitFileSwitch when chaging forth and back
+                                                         // between formats that support split files and not.
 };
 
 static t_File::Format DlgAcquireLastUsedFormat = t_File::NotSet;  // For remembering the format that was used for the last acquisition
@@ -617,13 +620,13 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, bool Clone, t_pDeviceList pDevice
       pLayoutFormatSplit->addLayout (pLayoutSplit);
       pLayoutGroupBox   ->addLayout (pLayoutEwf);
 
-      CHK_EXIT (t_File::GetFormatDescription (t_File::DD , false, 0, Str))            ButtonTextDD  = "&" + Str;
-      CHK_EXIT (t_File::GetFormatDescription (t_File::EWF, false, 0, Str))            ButtonTextEWF = "&" + Str;
-      CHK_EXIT (t_File::GetFormatDescription (t_File::AFF, false, 0, Str))            ButtonTextAFF = "&" + Str;
-      CHK_EXIT (t_File::GetFormatExtension   (t_File::DD , false, 0, NULL, &Str))
-      CHK_EXIT (t_File::GetFormatExtension   (t_File::DD , false, 3, NULL, &StrAlt))  ButtonTextDD += " " + tr("(file extension %1 or %2)") .arg (Str) .arg (StrAlt);
-      CHK_EXIT (t_File::GetFormatExtension   (t_File::EWF, false, 0, NULL, &Str))     ButtonTextEWF+= " " + tr("(file extension %1)") .arg (Str);
-      CHK_EXIT (t_File::GetFormatExtension   (t_File::AFF, false, 0, NULL, &Str))     ButtonTextAFF+= " " + tr("(file extension %1)") .arg (Str);
+      CHK_EXIT (t_File::GetFormatDescription (t_File::DD  , false, 0, Str))            ButtonTextDD  = "&" + Str;
+      CHK_EXIT (t_File::GetFormatDescription (t_File::EWF , false, 0, Str))            ButtonTextEWF = "&" + Str;
+      CHK_EXIT (t_File::GetFormatDescription (t_File::AAFF, false, 0, Str))            ButtonTextAFF = "&" + Str;
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::DD  , false, 0, NULL, &Str))
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::DD  , false, 3, NULL, &StrAlt))  ButtonTextDD += " " + tr("(file extension %1 or %2)") .arg (Str) .arg (StrAlt);
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::EWF , false, 0, NULL, &Str))     ButtonTextEWF+= " " + tr("(file extension %1)") .arg (Str);
+      CHK_EXIT (t_File::GetFormatExtension   (t_File::AAFF, false, 0, NULL, &Str))     ButtonTextAFF+= " " + tr("(file extension %1)") .arg (Str);
 
       pOwn->pRadioButtonFormatDD  = new QRadioButton (ButtonTextDD , this);
       pOwn->pRadioButtonFormatEWF = new QRadioButton (ButtonTextEWF, this);
@@ -648,6 +651,7 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, bool Clone, t_pDeviceList pDevice
       CHK_EXIT (AddField (pDevice, pFieldSplitFileSwitch, pLayoutSplit, &Row, &Col))
       CHK_EXIT (AddField (pDevice, pFieldSplitFileSize  , pLayoutSplit, &Row, &Col))
       CHK_EXIT (AddField (pDevice, pFieldSplitFileUnit  , pLayoutSplit, &Row, &Col))
+      pOwn->OldSplitFileSwitch = pFieldSplitFileSwitch->pCheckBox->isChecked();
 
       Row = Col = 0;
       for (i=0; i<pDlgAcquireFields->count(); i++)
@@ -729,10 +733,10 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, bool Clone, t_pDeviceList pDevice
 
       switch (DlgAcquireLastUsedFormat)
       {
-         case t_File::DD : pOwn->pRadioButtonFormatDD ->setChecked (true); break;
-         case t_File::EWF: pOwn->pRadioButtonFormatEWF->setChecked (true); break;
-         case t_File::AFF: pOwn->pRadioButtonFormatAFF->setChecked (true); break;
-         default         : CHK_EXIT (ERROR_DLGACQUIRE_INVALID_FORMAT)
+         case t_File::DD  : pOwn->pRadioButtonFormatDD ->setChecked (true); break;
+         case t_File::EWF : pOwn->pRadioButtonFormatEWF->setChecked (true); break;
+         case t_File::AAFF: pOwn->pRadioButtonFormatAFF->setChecked (true); break;
+         default          : CHK_EXIT (ERROR_DLGACQUIRE_INVALID_FORMAT)
       }
    }
 
@@ -742,7 +746,7 @@ t_DlgAcquire::t_DlgAcquire (t_pDevice pDevice, bool Clone, t_pDeviceList pDevice
    // Adjust size
    // -----------
    // Qt limits dialogs to 2/3 of the screen height and width. That's why we adjust it with
-   //  the following code if the dialog is smaller then its size hint.
+   // the following code if the dialog is smaller then its size hint.
    adjustSize();  // Let Qt calculate the size (limited to 2/3 of the screen)
    QRect DialogRect = geometry ();
    
@@ -842,7 +846,7 @@ void t_DlgAcquire::SlotDeviceTableSelectionChanged (void)
    {
       if (Selected != pOwn->pDeviceTable->columnCount())
       {
-         LOG_INFO ("%d devices in device tabel for clone destination", Selected)
+         LOG_INFO ("%d devices in device table for clone destination", Selected)
          CHK_EXIT (ERROR_DLGACQUIRE_INVALID_SELECTION)
       }
       Row   = SelectedItemsList[0]->row();
@@ -880,27 +884,26 @@ void t_DlgAcquire::UpdateFieldState (void)
 
    // Split file fields
    // -----------------
-   static bool OldSplitFileSwitch = false;  // should be replaced
-
    t_pCfgDlgAcquireField pFieldSplitFileSwitch = DlgAcquireGetField (CFG_DLGACQUIRE_SPLITFILESWITCH);
    t_pCfgDlgAcquireField pFieldSplitFileSize   = DlgAcquireGetField (CFG_DLGACQUIRE_SPLITFILESIZE  );
    t_pCfgDlgAcquireField pFieldSplitFileUnit   = DlgAcquireGetField (CFG_DLGACQUIRE_SPLITFILEUNIT  );
+
    if (pOwn->pRadioButtonFormatDD->isChecked())
    {
-      pFieldSplitFileSwitch->pCheckBox->setChecked (OldSplitFileSwitch);
+      pFieldSplitFileSwitch->pCheckBox->setChecked (pOwn->OldSplitFileSwitch);
       pFieldSplitFileSwitch->pCheckBox->setEnabled (true);
    }
    else if (pOwn->pRadioButtonFormatEWF->isChecked())
    {
       if (pFieldSplitFileSwitch->pCheckBox->isEnabled())
-         OldSplitFileSwitch = pFieldSplitFileSwitch->pCheckBox->isChecked();
+         pOwn->OldSplitFileSwitch = pFieldSplitFileSwitch->pCheckBox->isChecked();
       pFieldSplitFileSwitch->pCheckBox->setChecked (true);
       pFieldSplitFileSwitch->pCheckBox->setEnabled (false);
    }
    else if (pOwn->pRadioButtonFormatAFF->isChecked())
    {
       if (pFieldSplitFileSwitch->pCheckBox->isEnabled())
-         OldSplitFileSwitch = pFieldSplitFileSwitch->pCheckBox->isChecked();
+         pOwn->OldSplitFileSwitch = pFieldSplitFileSwitch->pCheckBox->isChecked();
       pFieldSplitFileSwitch->pCheckBox->setChecked (false);
       pFieldSplitFileSwitch->pCheckBox->setEnabled (false);
    }
@@ -1120,12 +1123,13 @@ void t_DlgAcquire::SlotAccept (void)
             return;
          }
          SplitSize = NumValue * UnitIndexToMultiplier (DlgAcquireGetField(CFG_DLGACQUIRE_SPLITFILEUNIT)->pComboBox->currentIndex());
-         #if (LIBEWF_VERSION != 20100226)
+         #if ((LIBEWF_VERSION != 20100226) && (LIBEWF_VERSION != 20080501) && (LIBEWF_VERSION != 20111015))
             #error "Please check EWF documentation for newer Encase formats and adjust following code"
          #endif
          if (pOwn->pRadioButtonFormatEWF->isChecked())
          {
-            if (CONFIG(EwfFormat) == LIBEWF_FORMAT_ENCASE6)
+            if ((CONFIG(EwfFormat) == LIBEWF_FORMAT_ENCASE6) ||
+                (CONFIG(EwfFormat) == t_File::AEWF))
             {
                if ((SplitSize > EWF_MAX_SEGMENT_SIZE_EXT) || (SplitSize < EWF_MIN_SEGMENT_SIZE))
                {
@@ -1138,10 +1142,10 @@ void t_DlgAcquire::SlotAccept (void)
             }
             else
             {
-               if ((NumValue > EWF_MAX_SEGMENT_SIZE) || (NumValue < EWF_MIN_SEGMENT_SIZE))
+               if ((SplitSize > EWF_MAX_SEGMENT_SIZE) || (SplitSize < EWF_MIN_SEGMENT_SIZE))
                {
                   QMessageBox::information (this, tr ("Incorrect value", "Dialog title"),
-                                                  tr ("The split size for the configured EWF format must be in the range %1 - %2 MiB."
+                                                  tr ("The split size for the configured EWF format must be in the range %1 - %2 MiB. "
                                                       "For bigger files, switch to ""Encase6"" format or later (see Guymager configuration file, parameter EwfFormat).")
                                                   .arg(EWF_MIN_SEGMENT_SIZE/(1024*1024))
                                                   .arg(EWF_MAX_SEGMENT_SIZE/(1024*1024)), QMessageBox::Ok);
@@ -1272,7 +1276,7 @@ APIRET t_DlgAcquire::GetParameters (t_Device::t_Acquisition &Acquisition, bool R
    {
       if      (pOwn->pRadioButtonFormatDD ->isChecked()) Acquisition.Format = t_File::DD;
       else if (pOwn->pRadioButtonFormatEWF->isChecked()) Acquisition.Format = t_File::EWF;
-      else                                               Acquisition.Format = t_File::AFF;
+      else                                               Acquisition.Format = t_File::AAFF;
       if (RememberLastUsedValues)
          DlgAcquireLastUsedFormat = Acquisition.Format;
    }
@@ -1285,11 +1289,11 @@ APIRET t_DlgAcquire::GetParameters (t_Device::t_Acquisition &Acquisition, bool R
          pDlgAcquireField->LastEnteredValue = Acq;       \
    }
 
-   #define COPY_CHECKBOX(Acq, FieldName)                 \
+   #define COPY_CHECKBOX(Acq, FieldName, Remember)       \
    {                                                     \
       pDlgAcquireField = DlgAcquireGetField (FieldName); \
       Acq = pDlgAcquireField->pCheckBox->isChecked();    \
-      if (RememberLastUsedValues)                        \
+      if (Remember)                                      \
          pDlgAcquireField->LastEnteredValue = Acq  ? "1" : "0"; \
    }
 
@@ -1303,13 +1307,12 @@ APIRET t_DlgAcquire::GetParameters (t_Device::t_Acquisition &Acquisition, bool R
 
    if (!pOwn->Clone)
    {
-      Acquisition.SplitFileSize = 0;
       COPY_LINEENTRY (Acquisition.CaseNumber    , CFG_DLGACQUIRE_EWF_CASENUMBER     , RememberLastUsedValues)
       COPY_LINEENTRY (Acquisition.EvidenceNumber, CFG_DLGACQUIRE_EWF_EVIDENCENUMBER , RememberLastUsedValues)
       COPY_LINEENTRY (Acquisition.Examiner      , CFG_DLGACQUIRE_EWF_EXAMINER       , RememberLastUsedValues)
       COPY_LINEENTRY (Acquisition.Description   , CFG_DLGACQUIRE_EWF_DESCRIPTION    , RememberLastUsedValues)
       COPY_LINEENTRY (Acquisition.Notes         , CFG_DLGACQUIRE_EWF_NOTES          , RememberLastUsedValues)
-      COPY_CHECKBOX (SplitFileSwitch, CFG_DLGACQUIRE_SPLITFILESWITCH )
+      COPY_CHECKBOX  (SplitFileSwitch           , CFG_DLGACQUIRE_SPLITFILESWITCH    , RememberLastUsedValues)
       if (SplitFileSwitch)
       {
          int UnitIndex;
@@ -1317,16 +1320,20 @@ APIRET t_DlgAcquire::GetParameters (t_Device::t_Acquisition &Acquisition, bool R
          COPY_COMBOBOX  (UnitIndex    , CFG_DLGACQUIRE_SPLITFILEUNIT, RememberLastUsedValues)
          Acquisition.SplitFileSize = SplitFileSize.toULongLong() * UnitIndexToMultiplier(UnitIndex);
       }
+      else
+      {
+         Acquisition.SplitFileSize = 0;
+      }
    }
    COPY_LINEENTRY (Acquisition.ImagePath     , CFG_DLGACQUIRE_DEST_IMAGEDIRECTORY, pOwn->Clone ? false : RememberLastUsedValues)
    COPY_LINEENTRY (Acquisition.ImageFilename , CFG_DLGACQUIRE_DEST_IMAGEFILENAME , pOwn->Clone ? false : RememberLastUsedValues)
    COPY_LINEENTRY (Acquisition.InfoPath      , CFG_DLGACQUIRE_DEST_INFODIRECTORY , RememberLastUsedValues)
    COPY_LINEENTRY (Acquisition.InfoFilename  , CFG_DLGACQUIRE_DEST_INFOFILENAME  , RememberLastUsedValues)
 
-   COPY_CHECKBOX (Acquisition.CalcMD5   , CFG_DLGACQUIRE_HASH_CALC_MD5   )
-   COPY_CHECKBOX (Acquisition.CalcSHA256, CFG_DLGACQUIRE_HASH_CALC_SHA256)
-   COPY_CHECKBOX (Acquisition.VerifySrc , CFG_DLGACQUIRE_HASH_VERIFY_SRC )
-   COPY_CHECKBOX (Acquisition.VerifyDst , CFG_DLGACQUIRE_HASH_VERIFY_DST )
+   COPY_CHECKBOX (Acquisition.CalcMD5   , CFG_DLGACQUIRE_HASH_CALC_MD5   , RememberLastUsedValues)
+   COPY_CHECKBOX (Acquisition.CalcSHA256, CFG_DLGACQUIRE_HASH_CALC_SHA256, RememberLastUsedValues)
+   COPY_CHECKBOX (Acquisition.VerifySrc , CFG_DLGACQUIRE_HASH_VERIFY_SRC , RememberLastUsedValues)
+   COPY_CHECKBOX (Acquisition.VerifyDst , CFG_DLGACQUIRE_HASH_VERIFY_DST , RememberLastUsedValues)
 
    #undef COPY_LINEENTRY
    #undef COPY_CHECKBOX
diff --git a/dlgacquire.h b/dlgacquire.h
index 9cf334b..5b0996d 100644
--- a/dlgacquire.h
+++ b/dlgacquire.h
@@ -9,7 +9,7 @@
 //  Module:         Acquisition dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgacquire_private.h b/dlgacquire_private.h
index 5d92b3c..c94b86f 100755
--- a/dlgacquire_private.h
+++ b/dlgacquire_private.h
@@ -9,7 +9,7 @@
 //  Module:         Private definitions of acquisition dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgautoexit.cpp b/dlgautoexit.cpp
index 4dc97ad..6cc3be0 100644
--- a/dlgautoexit.cpp
+++ b/dlgautoexit.cpp
@@ -9,7 +9,7 @@
 //  Module:         Auto exit dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgautoexit.h b/dlgautoexit.h
index 0d12c32..dca5412 100644
--- a/dlgautoexit.h
+++ b/dlgautoexit.h
@@ -9,7 +9,7 @@
 //  Module:         Auto exit dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgdirsel.cpp b/dlgdirsel.cpp
index 35b5d2a..f46c931 100644
--- a/dlgdirsel.cpp
+++ b/dlgdirsel.cpp
@@ -9,7 +9,7 @@
 //  Module:         Directory selection dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgdirsel.h b/dlgdirsel.h
index 3cb7246..ffb251b 100644
--- a/dlgdirsel.h
+++ b/dlgdirsel.h
@@ -9,7 +9,7 @@
 //  Module:         Directory selection dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgdirsel_private.h b/dlgdirsel_private.h
index 2a38900..7192775 100644
--- a/dlgdirsel_private.h
+++ b/dlgdirsel_private.h
@@ -9,7 +9,7 @@
 //  Module:         Private definitions of directory selection dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgmessage.cpp b/dlgmessage.cpp
index 4962c3c..1b0821d 100644
--- a/dlgmessage.cpp
+++ b/dlgmessage.cpp
@@ -9,7 +9,7 @@
 //  Module:         Different message boxes we need all the time
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -88,6 +88,8 @@ void t_DlgMessage::AdjustGeometry (void)
    int X, Y;
    int Dx, Dy;
 
+   // Adjust size
+   // -----------
    // Trying to adjust the size of the dialog to size of the text inside. Not easy, as Qt doesn't provide the right functions for
    // doing so. Important: AdjustSize must be called after the dialog has been showed in order have QTextBox calculated all scroll
    // bar values.
@@ -103,8 +105,26 @@ void t_DlgMessage::AdjustGeometry (void)
    Dx = GETMIN (Dx, (DLGMESSAGE_MAX_SCREEN_PERCENTAGE * QApplication::desktop()->width ()) / 100);  // Limit to a certain amount
    Dy = GETMIN (Dy, (DLGMESSAGE_MAX_SCREEN_PERCENTAGE * QApplication::desktop()->height()) / 100);  // of the available screen space
 
-   X = (QApplication::desktop()->width  () - Dx) / 2;
-   Y = (QApplication::desktop()->height () - Dy) / 2;
+
+   // Adjust position
+   // ---------------
+   // Try to center relative to the parent if available, relative to srceen otherwise
+
+   QWidget *pParent = parentWidget();
+   if (pParent)
+   {
+      QPoint PosRel (pParent->x(), pParent->y());
+      QPoint PosAbs = pParent->mapToGlobal(PosRel);
+
+      X = PosAbs.x() + pParent->width ()/2 - Dx/2;
+      Y = PosAbs.y() + pParent->height()/2 - Dy/2;
+   }
+   else
+   {
+      X = (QApplication::desktop()->width  () - Dx) / 2;
+      Y = (QApplication::desktop()->height () - Dy) / 2;
+   }
+
    setGeometry (X, Y, Dx, Dy);
 }
 
@@ -113,11 +133,11 @@ t_DlgMessage::~t_DlgMessage ()
    delete pOwn;
 }
 
-APIRET t_DlgMessage::Show (const QString &Title, const QString &Message, bool Monospaced)
+APIRET t_DlgMessage::Show (const QString &Title, const QString &Message, bool Monospaced, QWidget *pParent, Qt::WFlags Flags)
 {
    t_DlgMessage *pDlg;
 
-   pDlg = new t_DlgMessage (Title, Message, Monospaced);
+   pDlg = new t_DlgMessage (Title, Message, Monospaced, pParent, Flags);
    pDlg->setModal      (true);
    pDlg->show          ();
    pDlg->AdjustGeometry();
diff --git a/dlgmessage.h b/dlgmessage.h
index d5797d1..9c8058e 100644
--- a/dlgmessage.h
+++ b/dlgmessage.h
@@ -9,7 +9,7 @@
 //  Module:         Different message boxes we need all the time
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -48,7 +48,7 @@ class t_DlgMessage: public QDialog
 
       void AdjustGeometry (void);
 
-      static APIRET Show (const QString &Title, const QString &Message, bool Monospaced=false);
+      static APIRET Show (const QString &Title, const QString &Message, bool Monospaced=false, QWidget *pParent=NULL, Qt::WFlags Flags=0);
 
    private:
       t_DlgMessageLocal *pOwn;
diff --git a/dlgwait.cpp b/dlgwait.cpp
index 599bb0e..a23eb1f 100644
--- a/dlgwait.cpp
+++ b/dlgwait.cpp
@@ -9,7 +9,7 @@
 //  Module:         Wait dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/dlgwait.h b/dlgwait.h
index c0b375d..b181c90 100644
--- a/dlgwait.h
+++ b/dlgwait.h
@@ -9,7 +9,7 @@
 //  Module:         Wait dialog
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/error.cpp b/error.cpp
index 420e6e8..d3a44a9 100644
--- a/error.cpp
+++ b/error.cpp
@@ -9,7 +9,7 @@
 //  Module:         Error handling utilities
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/error.h b/error.h
index 805320d..229fbe5 100644
--- a/error.h
+++ b/error.h
@@ -9,7 +9,7 @@
 //  Module:         Error handling utilities
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/fifo.cpp b/fifo.cpp
index 1203f64..8073721 100644
--- a/fifo.cpp
+++ b/fifo.cpp
@@ -9,7 +9,7 @@
 //  Module:         The central queues for pipelined data processing
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/fifo.h b/fifo.h
index ec14ab1..86136ae 100644
--- a/fifo.h
+++ b/fifo.h
@@ -9,7 +9,7 @@
 //  Module:         The central queues for pipelined data processing
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/file.cpp b/file.cpp
index f333b4b..3cff3d3 100644
--- a/file.cpp
+++ b/file.cpp
@@ -9,7 +9,7 @@
 //  Module:         Everything related to file names, extension names, paths...
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -69,21 +69,22 @@ APIRET t_File::GetFormatDescription (t_Format Format, bool Clone, int DdSplitDec
       case EWF:
          switch (CONFIG(EwfFormat))
          {
-            case LIBEWF_FORMAT_ENCASE1: SubFormat="Encase1"; break;
-            case LIBEWF_FORMAT_ENCASE2: SubFormat="Encase2"; break;
-            case LIBEWF_FORMAT_ENCASE3: SubFormat="Encase3"; break;
-            case LIBEWF_FORMAT_ENCASE4: SubFormat="Encase4"; break;
-            case LIBEWF_FORMAT_ENCASE5: SubFormat="Encase5"; break;
-            case LIBEWF_FORMAT_ENCASE6: SubFormat="Encase6"; break;
-            case LIBEWF_FORMAT_FTK    : SubFormat="FTK"    ; break;
-            case LIBEWF_FORMAT_SMART  : SubFormat="Smart"  ; break;
-            case LIBEWF_FORMAT_LVF    : SubFormat="LVF"    ; break;
-            case LIBEWF_FORMAT_LINEN5 : SubFormat="Linen5" ; break;
+            case LIBEWF_FORMAT_ENCASE1: SubFormat="Encase1" ; break;
+            case LIBEWF_FORMAT_ENCASE2: SubFormat="Encase2" ; break;
+            case LIBEWF_FORMAT_ENCASE3: SubFormat="Encase3" ; break;
+            case LIBEWF_FORMAT_ENCASE4: SubFormat="Encase4" ; break;
+            case LIBEWF_FORMAT_ENCASE5: SubFormat="Encase5" ; break;
+            case LIBEWF_FORMAT_ENCASE6: SubFormat="Encase6" ; break;
+            case LIBEWF_FORMAT_FTK    : SubFormat="FTK"     ; break;
+            case LIBEWF_FORMAT_SMART  : SubFormat="Smart"   ; break;
+            case LIBEWF_FORMAT_LVF    : SubFormat="LVF"     ; break;
+            case LIBEWF_FORMAT_LINEN5 : SubFormat="Linen5"  ; break;
+            case AEWF                 : SubFormat="Guymager"; break;
             default                   : CHK (ERROR_FILE_INVALID_EWF_FORMAT)
          }
          Str = QObject::tr("Expert Witness Format, sub-format %1") .arg(SubFormat);
          break;
-      case AFF:
+      case AAFF:
          Str = QObject::tr("Advanced forensic image");
          break;
       default:  CHK (ERROR_FILE_INVALID_FORMAT)
@@ -125,13 +126,14 @@ APIRET t_File::GetFormatExtension (t_Format Format, bool Clone, int DdSplitDecim
             case LIBEWF_FORMAT_ENCASE5:
             case LIBEWF_FORMAT_ENCASE6:
             case LIBEWF_FORMAT_LINEN5 :
-            case LIBEWF_FORMAT_FTK    : Wild=".E??"; Human=".Exx"; break;
+            case LIBEWF_FORMAT_FTK    :
+            case AEWF                 : Wild=".E??"; Human=".Exx"; break;
             case LIBEWF_FORMAT_SMART  : Wild=".s??"; Human=".sxx"; break;
             case LIBEWF_FORMAT_LVF    : Wild=".l??"; Human=".lxx"; break;
             default                   : CHK (ERROR_FILE_INVALID_EWF_FORMAT)
          }
          break;
-      case AFF:
+      case AAFF:
          Wild = ".aff";
          Human = Wild;
          break;
diff --git a/file.h b/file.h
index 351f373..07b2412 100644
--- a/file.h
+++ b/file.h
@@ -10,7 +10,7 @@
 //                  etc
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -43,7 +43,8 @@ namespace t_File
       NotSet,
       DD,
       EWF,
-      AFF
+      AAFF,
+      AEWF = 0xAEF   // Take care not to collide with LIBEWF definitions (see also SetArrEwfFormat in config.cpp)
    } Format, t_Format;
 
    extern const char *pExtensionInfo;
diff --git a/guymager.cfg b/guymager.cfg
index 0487f20..2f27232 100644
--- a/guymager.cfg
+++ b/guymager.cfg
@@ -110,6 +110,9 @@ REM The table contains color settings for different items on the screen:
 REM    LocalDevices        Color to be used for marking local devices (i.e. devices with serial numbers found in
 REM                        configuration table LocalDevices, see above) in the user interface. The whole row gets
 REM                        this color.
+REM    AdditionalStateX    Devices maybe marked by this color depending on the values in the additional state info.
+REM                        See description of configuration parameter CommandGetAddStateInfo for more information.
+REM 
 REM All other entries refer to the colored dot of the acquisition state field for reflecting the current state:
 REM    StateIdle              Nothing has been done with this device yet.
 REM    StateAcquire           Acquisition running
@@ -128,6 +131,10 @@ TABLE Colors None
    REM Color                   R   G   B
    REM -----------------------------------
        LocalDevices           255 197 189
+       AdditionalState1       186 255 174
+       AdditionalState2       255 254 137
+       AdditionalState3       255 213  66
+       AdditionalState4       255 126 126
        StateIdle              255 255 255
        StateAcquire           78  132 255
        StateAcquirePaused     255 174   0
@@ -147,8 +154,11 @@ REM
 REM EwfFormat             The EWF format (alias E01 format) differs depending on which software created
 REM                       it. With this parameter, you can control which style guymager should follow.
 REM                       Possible values are: Encase1, Encase2, Encase3, Encase4, Encase5, Encase6, Smart,
-REM                       FTK, Linen5, Linen6 and LVF. See libewf for more information.
-REM                       Select Encase6 in order to be able to produce segment files bigger than 2GiB.
+REM                       FTK, Linen5, Linen6 and Guymager. See libewf for more information.
+REM                       When chosing "Guymager", the program uses its own EWF generation functions, which
+REM                       require only very little RAM and still are as fast as libewf. With any other setting,
+REM                       the program uses libewf i order to create the EWF images.
+REM                       Select Guymager or Encase6 in order to be able to produce segment files bigger than 2GiB.
 REM
 REM EwfCompression        The compression level for EWF images. Possible values are: None, Fast, Best.
 REM                       See ewflib for more information.
@@ -168,12 +178,26 @@ REM                       in the image filenames. If you wannt to allow special
 REM                       that your destination file system can handle them, you might add them to
 REM                       the parameter SpecialFilenameChars. Example: SpecialFilenameChars = '.- '
 REM                       would allow you to use the characters . and - as well as spaces.
+REM
+REM CalcImageFileMD5      Switch the parameter on in order to have Guymager calculate the MD5 hashes of the image
+REM                       file(s). The calculation is done over the whole file(s), not just the contents.
+REM                       NOTE: The MD5 hashes are calculated during image verification and therefore, it only
+REM                       is done if the checkbox for image verification is set in the acquisition dialog window.
+REM
+REM AvoidEncaseProblems   Encase produces strange error messages if the EWF internal fields "Imager Version" and
+REM                       "OS Version" contain more than 11 or 23 chracters, respectively. Leave this flag off
+REM                       if you don't work wth Encase (default setting). Set it to 1 if ever you work with
+REM                       Encase and want to avoid the Encase problems.
+
 
-EwfFormat             = Encase6
+
+EwfFormat             = Guymager
 EwfCompression        = FAST
 AffCompression        = 1
 AffMarkBadSectors     = TRUE
 SpecialFilenameChars  = ''
+CalcImageFileMD5      = off
+AvoidEncaseProblems   = off
 
 REM Acquisition dialog
 REM ------------------
@@ -417,14 +441,39 @@ REM                         (/dev/hda or /dev/sdc for instance). Examples:
 REM                            CommandGetSerialNumber = 'bash -c "smartctl -i %dev | grep -i serial | awk ''{print $3 $4 $5 $6 $7 $8 $9}'' "'
 REM                            CommandGetSerialNumber = 'bash -c "hdparm -I %dev | grep -i ''Serial Number'' | awk ''{print $3 $4 $5 $6 $7 $8 $9}'' "'
 REM
-REM ScanInterval            [s] Speficies how often an automatic device scan (for detecting newly connected devices)
-REM                         should launched. Keep in mind, that the device scan can be launched as well manually.
-REM
+REM CommandGetAddStateInfo  contains the command to be executed in order to gather additional state information. See 
+REM                         CommandGetSerialNumber in order to see how to use the %dev placeholder. By default, the command is 
+REM                         empty and no additional information is read nor displayed. If set, the command executed is expected 
+REM                         to return its information in three separate lines (separated by \n):
+REM                            1st line: Information text. This text is displayed in the device specific screen area of Guymager 
+REM                                      (bottom area of the main window).
+REM                            2nd line: A value of 0 tells Guymager that the device cannot be acquired. Guymager forbids the
+REM                                      acquisition of the device in that case. Any other value enables device acquisition.
+REM                                      If this parameter is missing, the device can be acquired.
+REM                            3rd line: An integer number indicating the color to be used for marking the device. The number
+REM                                      refers to the colors named AdditionalStateX in the configuration table Colors (see 
+REM                                      above), where X corresponds to the color returned by the command. If this parameter 
+REM                                      is missing, the default color (wite) is used.
+REM                         If you plan to use this feature, you may do a first test with the configuration setting
+REM                             CommandGetAddStateInfo='bash -c "/usr/share/guymager/stateinfo.sh %dev"'
+REM                         where the file /usr/share/guymager/stateinfo.sh is executable and contains the lines
+REM                            echo "Moie Welt! - $1"
+REM                            echo "0"
+REM                            echo "2"
+REM                         
+REM ScanInterval            Speficies how often an automatic device scan (for detecting newly connected devices)
+REM                         should launched. Unit: Seconds. Keep in mind, that the device scan can be launched as well manually.
+REM
+REM DirectIO                Decides whether Guymager reads data in direct IO mode or not. Normally, direct mode should be a little
+REM                         faster, but it was observed that reading from SSDSs may be much slower in direct mode. The default
+REM                         setting therefore is "off".
+REM                         Note that direct IO only can be switched on if parameter FifoMemoryManager is also on.
 
 DeviceScanMethod       = UDisks
 CommandGetSerialNumber = 'bash -c "smartctl -i %dev | grep -i serial | awk ''{print $3 $4 $5 $6 $7 $8 $9}'' "'
+CommandGetAddStateInfo = ''
 ScanInterval           = 6000
-
+DirectIO               = off
 
 REM Other settings
 REM --------------
@@ -449,8 +498,8 @@ REM                         256 and 4 acquisitions running in parallel, a total
 REM                         the FIFOs, not counting the overhead required by Guymager and the libs it uses (Qt, libewf, ...).
 REM                         The recommended value is 0 (automatic memory usage calculation).
 REM
-REM FifoMemoryManager       Set to on to use the internal FIFO memory manager. if set to off, the classical C functions mallox and
-REM                         free are used.
+REM FifoMemoryManager       Set to on to use the internal FIFO memory manager. If switched off, the classical C functions malloc and
+REM                         free are used. FifoMemoryManager must be switched on in order to use direct IO (see parameter DirectIO).
 REM
 REM UseSeparatehashThread   The hash calculation can be done in a separate thread or in the read thread (i.e. the thread reading
 REM                         the data from the source). Using a separate thread led to a slight performance advantage on the
diff --git a/guymager.pro b/guymager.pro
index 569b512..d4b9628 100644
--- a/guymager.pro
+++ b/guymager.pro
@@ -9,6 +9,24 @@
 #  Qt project file
 # ****************************************************************************
 
+# Copyright 2008, 2009, 2010, 2011 Guy Voncken
+#
+# This file is part of guymager.
+#
+# guymager is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# guymager 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with guymager. If not, see <http://www.gnu.org/licenses/>.
+
+
 # Command line configuration options
 # ----------------------------------
 # These options are thought to behave like the classical ./configure options, i.e. they
@@ -38,10 +56,6 @@ MOC_DIR  = ./moc
 
 INCLUDEPATH += /usr/include/libguytools2
 
-# LIBEWF_VERSION only must be defined for compiling with libewf before 20080309
-# Newer libewf version already include this macro in file definitions.h.
-# DEFINES += LIBEWF_VERSION=20071111
-
 # Add compile time information
 # ----------------------------
 # Compile time information is written to compileinfo.cpp by means of the date command. The command in QMAKE_PRE_LINK ensures that
@@ -83,6 +97,7 @@ SOURCES += media.cpp
 SOURCES += qtutil.cpp
 #SOURCES += sha256.cpp
 SOURCES += table.cpp
+SOURCES += thread.cpp
 SOURCES += threadcompress.cpp
 SOURCES += threadhash.cpp
 SOURCES += threadread.cpp
@@ -105,6 +120,7 @@ HEADERS += itemdelegate.h
 HEADERS += mainwindow.h
 HEADERS += media.h
 HEADERS += table.h
+HEADERS += thread.h
 HEADERS += threadcompress.h
 HEADERS += threadhash.h
 HEADERS += threadread.h
@@ -148,9 +164,15 @@ LIBS += /usr/lib/libguytools.a
 LIBS += -lz
 LIBS += -ldl
 
+#xou may use any of the 3 following line for the libssl hash functions
+#LIBS += -lssl  # See also macro definitions in common.h
+#LIBS += -lcrypto  # See also macro definitions in common.h
+LIBS += /usr/lib/libcrypto.a
+
+
 TRANSLATIONS  = guymager_en.ts
 TRANSLATIONS += guymager_de.ts
 TRANSLATIONS += guymager_fr.ts
 TRANSLATIONS += guymager_it.ts
 TRANSLATIONS += guymager_nl.ts
-
+TRANSLATIONS += guymager_cn.ts
diff --git a/guymager_en.ts b/guymager_cn.ts
similarity index 69%
copy from guymager_en.ts
copy to guymager_cn.ts
index 979bf37..de5d1a8 100644
--- a/guymager_en.ts
+++ b/guymager_cn.ts
@@ -6,24 +6,24 @@
     <message>
         <source>Guymager needs to be started with root rights in order to perform acquisitions. You are not root and thus won't be able to acquire devices.
 Continue anyway?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">GUYMAGER需要以管理员的身份运行,你目前不是管理员权限,确定继续吗?</translation>
     </message>
     <message>
         <source>Deleting %1</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">删除 %1</translation>
     </message>
     <message>
         <source>Missing root rights</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">非管理员权限</translation>
     </message>
     <message>
         <source>Ok</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">确定</translation>
     </message>
     <message>
         <source>Cancel</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">取消</translation>
     </message>
     <message>
         <source>Linux dd raw image</source>
@@ -35,11 +35,11 @@ Continue anyway?</source>
     </message>
     <message>
         <source>Advanced forensic image</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">A高级司法镜像</translation>
     </message>
     <message>
         <source>Guymager cannot scan the devices connected to this computer.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">GUYMAGER 无法扫描到设备</translation>
     </message>
     <message>
         <source>The selected scan method ("%1") is not available. Do you want to try another scan method?</source>
@@ -47,7 +47,7 @@ Continue anyway?</source>
     </message>
     <message>
         <source>Abort</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">中止</translation>
     </message>
     <message>
         <source>Try method "%1"</source>
@@ -55,7 +55,7 @@ Continue anyway?</source>
     </message>
     <message>
         <source>Creation of a clone</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">创建一个克隆</translation>
     </message>
     <message>
         <source>Linux split dd raw image</source>
@@ -68,28 +68,28 @@ Continue anyway?</source>
         <source>Linux
 device</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">挂载</translation>
     </message>
     <message>
         <source>Model</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">设备名</translation>
     </message>
     <message>
         <source>Serial
 nr.</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">序列号</translation>
     </message>
     <message>
         <source>Size</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">大小</translation>
     </message>
     <message>
         <source>Remarks</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">备注</translation>
     </message>
     <message>
         <source>State</source>
@@ -100,31 +100,33 @@ nr.</source>
         <source>Hidden
 Areas</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">隐藏区</translation>
     </message>
     <message>
         <source>Bad
 sectors</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">坏道</translation>
     </message>
     <message>
         <source>Progress</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">进度</translation>
     </message>
     <message>
         <source>Average
 Speed
 [MB/s]</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">平均
+速度
+[MB/s]</translation>
     </message>
     <message>
         <source>Time
 remaining</source>
         <comment>Column of device table</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">剩余时间</translation>
     </message>
     <message>
         <source>FIFO queues
@@ -138,31 +140,31 @@ usage
     <name>t_DlgAbort</name>
     <message>
         <source>Do you want to abort the acquisition of %1?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">你确定终止%1吗?</translation>
     </message>
     <message>
         <source>Delete partial image files</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">删除部分镜像文件</translation>
     </message>
     <message>
         <source>Do you want to abort the verification of %1?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">你确定终止%1验证吗</translation>
     </message>
     <message>
         <source>Abort?</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">终止?</translation>
     </message>
 </context>
 <context>
     <name>t_DlgAcquire</name>
     <message>
         <source>File format</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">格式化文件</translation>
     </message>
     <message>
         <source>Destination</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">目标</translation>
     </message>
     <message>
         <source>Configuration flag WriteToDevNull is set!</source>
@@ -173,57 +175,60 @@ usage
 	Image filename: %1
 	Info filename: %2
 Do you accept these changes?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">文件名不允许包含特殊字符
+图像文件名:%1
+信息文件名:%2
+是否同意此项变化</translation>
     </message>
     <message>
         <source>EwfCaseNumber</source>
-        <translation>Case number</translation>
+        <translation type="unfinished">案件序列号</translation>
     </message>
     <message>
         <source>EwfEvidenceNumber</source>
-        <translation>Evidence number</translation>
+        <translation type="unfinished">证据号码</translation>
     </message>
     <message>
         <source>EwfExaminer</source>
-        <translation>Examiner</translation>
+        <translation type="unfinished">调查员</translation>
     </message>
     <message>
         <source>EwfDescription</source>
-        <translation>Description</translation>
+        <translation type="unfinished">说明</translation>
     </message>
     <message>
         <source>EwfNotes</source>
-        <translation>Notes</translation>
+        <translation type="unfinished">记录</translation>
     </message>
     <message>
         <source>DestImageFilename</source>
-        <translation>Image filename (without extension)</translation>
+        <translation type="unfinished">镜像名(除扩展名)</translation>
     </message>
     <message>
         <source>DestInfoFilename</source>
-        <translation>Info filename (without extension)</translation>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">选择目标目录</translation>
     </message>
     <message>
         <source>(file extension %1)</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">文件扩展名%1</translation>
     </message>
     <message>
         <source>Special characters</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">特殊字符</translation>
     </message>
     <message>
         <source>DestImageDirectory</source>
-        <translation>Image directory</translation>
+        <translation type="unfinished">镜像目录</translation>
     </message>
     <message>
         <source>DestInfoDirectory</source>
-        <translation>Info directory</translation>
+        <translation type="unfinished">信息目录</translation>
     </message>
     <message>
         <source>...</source>
@@ -233,27 +238,27 @@ Do you accept these changes?</source>
     <message>
         <source>Access denied</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">访问被拒绝</translation>
     </message>
     <message>
         <source>HashCalcMD5</source>
-        <translation>Calculate MD5</translation>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <source>HashCalcSHA256</source>
-        <translation>Calculate SHA-256</translation>
+        <translation type="unfinished">SHA-256校验</translation>
     </message>
     <message>
         <source>HashVerifySrc</source>
-        <translation>Re-read source after acquisition for verification (takes twice as long)</translation>
+        <translation type="unfinished">验证源盘哈希值(需要两倍长度)</translation>
     </message>
     <message>
         <source>HashVerifyDst</source>
-        <translation>Verify image after acquisition (takes twice as long)</translation>
+        <translation type="unfinished">验证目标盘哈希值</translation>
     </message>
     <message>
         <source>Hash calculation / verification</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">哈希值计算/校验</translation>
     </message>
     <message>
         <source>Guymager cannot write to the directory
@@ -263,88 +268,94 @@ This may be due to insufficient access rights or unsupported filename characters
     </message>
     <message>
         <source>Local device, cannot be written</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">本地设备,不能写入</translation>
     </message>
     <message>
         <source>Too small</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">太小</translation>
     </message>
     <message>
         <source>In use</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">使用中</translation>
     </message>
     <message>
         <source>Ok for cloning</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">可以进行拷贝</translation>
     </message>
     <message>
         <source>The info filename contains special characters which are not allowed. Guymager suggests the following changes:
 	%1
 Do you accept these changes?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">文件名中不允许包含特殊字符。
+	%1
+确定接受吗?</translation>
     </message>
     <message>
         <source>Files exist</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">文件已存在</translation>
     </message>
     <message>
         <source>The image or info files already exist. Do you want to overwrite them?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">图像或信息文件已存在,确定覆盖吗?</translation>
     </message>
     <message>
         <source>Clone %1</source>
         <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">拷贝%1</translation>
     </message>
     <message>
         <source>Acquire image of %1</source>
         <comment>Dialog title, %1 is the device (for instance /dev/hdc)</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">采集%1图像</translation>
     </message>
     <message>
         <source>Device to be cloned</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">被拷贝的设备</translation>
     </message>
     <message>
         <source>Used in another clone operation</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">用于另一个拷贝操作</translation>
     </message>
     <message>
         <source>SplitFileSize</source>
-        <translation>Split size</translation>
+        <translation type="unfinished">分卷大小</translation>
     </message>
     <message>
         <source>SplitFileSwitch</source>
-        <translation>Split image files</translation>
+        <translation type="unfinished">分卷镜像文件</translation>
     </message>
     <message>
         <source>(file extension %1 or %2)</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">(文件扩展名%1或%2)</translation>
     </message>
     <message>
         <source>Incorrect value</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">错误的值</translation>
     </message>
     <message>
         <source>The split file size "%1" is not valid. Only positive numbers can be entered.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">分卷大小“%1”是无效的。只能输入一个正数。</translation>
     </message>
     <message>
         <source>The info file already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">信息文件已存在。确定覆盖吗?</translation>
     </message>
     <message>
         <source>SplitFileUnit</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">拆分文件单位</translation>
     </message>
     <message>
         <source>The split size for the selected image format must be in the range %1MiB - %2EiB.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">为选定的镜像格式拆分大小,必须在%1Mib - %2EiB 范围内。</translation>
     </message>
     <message>
         <source>The split size for the configured EWF format must be in the range %1 - %2 MiB.For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
+        <translation type="obsolete">EWF格式的拆分大小必须在%1 - %2 MiB范围内。如果需要支持更大的文件,使用Encase6 格式或更高版本(参考配置文件,参数EwfFormat)</translation>
+    </message>
+    <message>
+        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB. For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -352,130 +363,135 @@ Do you accept these changes?</source>
     <name>t_DlgAutoExit</name>
     <message>
         <source>Abort</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">终止</translation>
     </message>
     <message>
         <source>Exit now</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">退出</translation>
     </message>
     <message>
         <source>All acquisitions have ended.
 Guymager will exit automatically in %1 seconds.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">已完成
+程序将在%1秒后自动退出</translation>
     </message>
 </context>
 <context>
     <name>t_DlgDirSel</name>
     <message>
         <source>New directory</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">新目录</translation>
     </message>
     <message>
         <source>Remove directory</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">删除目录</translation>
     </message>
     <message>
         <source>Select destination directory</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">选择目标目录</translation>
     </message>
     <message>
         <source>NewDirectory</source>
         <comment>Name of the new directory that will be created</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">新目录</translation>
     </message>
 </context>
 <context>
     <name>t_DlgMessage</name>
     <message>
         <source>Close</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">关闭</translation>
     </message>
 </context>
 <context>
     <name>t_Info</name>
     <message>
         <source>Command executed: %1</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">执行命令:%1</translation>
     </message>
     <message>
         <source>No information can be displayed as a timeout occured while executing the command.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">无信息,命令执行超时</translation>
     </message>
     <message>
         <source>Information returned:</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">返回的信息:</translation>
     </message>
 </context>
 <context>
     <name>t_InfoField</name>
     <message>
         <source>Size</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">大小</translation>
     </message>
     <message>
         <source>Sector size</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">扇区大小</translation>
     </message>
     <message>
         <source>Image file</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">镜像文件</translation>
     </message>
     <message>
         <source>Info file</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">文件信息</translation>
     </message>
     <message>
         <source>Current speed</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">当前速度</translation>
     </message>
     <message>
         <source>bytes</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">字节</translation>
     </message>
     <message>
         <source>Hash calculation</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">哈希计算</translation>
     </message>
     <message>
         <source>Source verification</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">源盘校验</translation>
     </message>
     <message>
         <source>Started</source>
         <comment>Start timestamp and running time</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">开始</translation>
     </message>
     <message>
         <source>MD5 and SHA-256</source>
         <comment>Both hashes are calculated</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">MD5和SHA-256</translation>
     </message>
     <message>
         <source>MD5</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">MD5</translation>
     </message>
     <message>
         <source>SHA-256</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">SHA-256</translation>
     </message>
     <message>
         <source>off</source>
         <comment>Hash calculation is off</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">关闭</translation>
     </message>
     <message>
         <source>Image verification</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">镜像校验</translation>
     </message>
     <message>
         <source>on</source>
         <comment>Display that verification is on</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">开启</translation>
     </message>
     <message>
         <source>off</source>
         <comment>Display that verification is off</comment>
+        <translation type="unfinished">关闭</translation>
+    </message>
+    <message>
+        <source>Additional state info</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -483,11 +499,11 @@ Guymager will exit automatically in %1 seconds.</source>
     <name>t_MainWindow</name>
     <message>
         <source>Local device</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">本地设备</translation>
     </message>
     <message>
         <source>Idle</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">闲置</translation>
     </message>
     <message>
         <source>Cleanup</source>
@@ -495,27 +511,27 @@ Guymager will exit automatically in %1 seconds.</source>
     </message>
     <message>
         <source>Finished</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">完成</translation>
     </message>
     <message>
         <source>Aborted - Error: Reason is 'none'</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">中止-错误:原因“none”</translation>
     </message>
     <message>
         <source>Aborted by user</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">用户中断</translation>
     </message>
     <message>
         <source>Aborted - Image file write error</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">中止 - 镜像文件写入错误</translation>
     </message>
     <message>
         <source>Aborted - Device read error</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">中止 - 硬盘读取错误</translation>
     </message>
     <message>
         <source>&Rescan</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">&R重新扫描</translation>
     </message>
     <message>
         <source>F5</source>
@@ -523,11 +539,11 @@ Guymager will exit automatically in %1 seconds.</source>
     </message>
     <message>
         <source>There are active acquisitions. Do you really want to abort them and quit?</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">There are active acquisitions. 你确定放弃并退出?</translation>
     </message>
     <message>
         <source>Debug information</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">调试信息</translation>
     </message>
     <message>
         <source>GUYMAGER is a Linux-based forensic imaging tool
@@ -537,84 +553,86 @@ Compilation timestamp: %2
 Compiled with gcc %3
 Using libewf %4
 Using libguytools %5</source>
-        <translation type="unfinished"></translation>
+        <translation type="obsolete">司法拷贝工具
+
+版本:1.0</translation>
     </message>
     <message>
         <source>About GUYMAGER</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">关于GUYMAGER</translation>
     </message>
     <message>
         <source>About Qt</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">关于QT</translation>
     </message>
     <message>
         <source>Exit GUYMAGER</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">退出</translation>
     </message>
     <message>
         <source>&Devices</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">&D设备</translation>
     </message>
     <message>
         <source>&Misc</source>
         <comment>Menu entry</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">&M其他</translation>
     </message>
     <message>
         <source>Debug</source>
         <comment>Menu entry</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">调试</translation>
     </message>
     <message>
         <source>&Help</source>
         <comment>Menu entry</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">&H帮助</translation>
     </message>
     <message>
         <source>About &GUYMAGER</source>
         <comment>Menu entry</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">关于&GUYMAGER</translation>
     </message>
     <message>
         <source>About &Qt</source>
         <comment>Menu entry</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">关于&QT</translation>
     </message>
     <message>
         <source>Acquisition running</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">正在获取中</translation>
     </message>
     <message>
         <source>Verification running</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">正在验证中</translation>
     </message>
     <message>
         <source>Device disconnected, acquisition paused</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">设备断开,暂停获取</translation>
     </message>
     <message>
         <source>Device disconnected, verification paused</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">设备断开,暂停验证</translation>
     </message>
     <message>
         <source>Finished - Verified & ok</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">验证完成</translation>
     </message>
     <message>
         <source>Finished - Verification failed</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">验证失败</translation>
     </message>
     <message>
         <source>Aborted - Image file verify error</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">中止 - 镜像文件验证错误</translation>
     </message>
     <message>
         <source>Unknown</source>
         <comment>Media info string for informing about hidden areas (HPA/DCO)</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">未知</translation>
     </message>
     <message>
         <source>No</source>
@@ -628,50 +646,50 @@ Using libguytools %5</source>
     </message>
     <message>
         <source>Rescan devices and update table</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">扫描设备和更新档</translation>
     </message>
     <message>
         <source>Add special device</source>
         <comment>Menu entry</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">添加特殊设备</translation>
     </message>
     <message>
         <source>Open File</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">打开文件</translation>
     </message>
     <message>
         <source>Invalid device</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">无效的设备</translation>
     </message>
     <message>
         <source>Manually added special device</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">手动添加特殊设备</translation>
     </message>
     <message>
         <source>Device alrady contained</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">载入设备准备完成</translation>
     </message>
     <message>
         <source>The selected file or device already is contained in the table.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">选定的文件或设备已经加载到列表中</translation>
     </message>
     <message>
         <source>The device or file cannot be selected because its size is unknown.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">无法选择设备或文件。因为大小未知。</translation>
     </message>
     <message>
         <source>The device or file cannot be selected because it contains 0 bytes.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">无法选择设备或文件。因为大小为0字节。</translation>
     </message>
     <message>
         <source>Used in clone operation</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">用于拷贝操作</translation>
     </message>
     <message>
         <source>Aborting...</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">取消中 ...</translation>
     </message>
     <message>
         <source>none</source>
@@ -681,10 +699,32 @@ Using libguytools %5</source>
     <message>
         <source>unknown</source>
         <comment>column hidden areas</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">未知</translation>
     </message>
     <message>
         <source>Exit after acquisitions completed</source>
+        <translation type="unfinished">在获取完成后退出</translation>
+    </message>
+    <message>
+        <source>Aborted - Info file write error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborted - Acquisition start failure</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>(not used as Guymager currently is configured to use its own EWF module)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>GUYMAGER is a Linux-based forensic imaging tool
+
+Version: %1
+Compilation timestamp: %2
+Compiled with gcc %3
+Linked with libewf %4 %5
+Linked with libguytools %6</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -697,32 +737,32 @@ Using libguytools %5</source>
     <message>
         <source>Info</source>
         <comment>Context menu</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">信息</translation>
     </message>
     <message>
         <source>Device info</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">设备信息</translation>
     </message>
     <message>
         <source>GUYMAGER ACQUISITION INFO FILE</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">GUYMAGER取信息文件</translation>
     </message>
     <message>
         <source>Guymager</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">GUYMAGER</translation>
     </message>
     <message>
         <source>Device information</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">设备信息</translation>
     </message>
     <message>
         <source>Finished successfully</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">成功完成</translation>
     </message>
     <message>
         <source>(with %1 bad sectors)</source>
@@ -732,7 +772,7 @@ Using libguytools %5</source>
     <message>
         <source>Aborted by user</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">用户中止</translation>
     </message>
     <message>
         <source>Aborted because of image write error</source>
@@ -742,12 +782,12 @@ Using libguytools %5</source>
     <message>
         <source>Aborted, strange reason (%1)</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">中止 - 原因(%1)</translation>
     </message>
     <message>
         <source>Strange state (%1)</source>
         <comment>Info file</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">状态(%1)</translation>
     </message>
     <message>
         <source>State: %1</source>
@@ -952,7 +992,7 @@ Using libguytools %5</source>
     </message>
     <message>
         <source>Image verification OK. The image contains exactely the data that was written.</source>
-        <translation>Image verification OK. The image contains exactly the data that was written.</translation>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Image verification FAILED. The data in the image is different from what was written.</source>
@@ -1006,17 +1046,38 @@ Using libguytools %5</source>
         <source>Device used for cloning - cannot be acquired</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Generated image files and their MD5 hashes</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (the select EWF format does not support image file hashes)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (image verification checkbox was switched off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot be acquired - see additional state info field</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_ThreadScan</name>
     <message>
         <source>Cannot scan devices</source>
         <comment>Dialog title</comment>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">无法扫描设备</translation>
     </message>
     <message>
         <source>None of the device scan methods worked. Exiting now.</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">扫描设备方法无效。退出。</translation>
     </message>
 </context>
 </TS>
diff --git a/guymager_de.ts b/guymager_de.ts
index 6a0912d..c7f24e8 100644
--- a/guymager_de.ts
+++ b/guymager_de.ts
@@ -362,6 +362,10 @@ Sind Sie mit diesen Änderungen einverstanden?</translation>
     </message>
     <message>
         <source>The split size for the configured EWF format must be in the range %1 - %2 MiB.For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
+        <translation type="obsolete">Die Split-Grösse für das konfigurierte EWF-Format muss im Bereich %1 MiB - %2 MiB liegen. Grössere Dateien sind ab dem Format Encase6 möglich (siehe Guymager Konfigurationsdatei, Parameter EwfFormat).</translation>
+    </message>
+    <message>
+        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB. For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
         <translation>Die Split-Grösse für das konfigurierte EWF-Format muss im Bereich %1 MiB - %2 MiB liegen. Grössere Dateien sind ab dem Format Encase6 möglich (siehe Guymager Konfigurationsdatei, Parameter EwfFormat).</translation>
     </message>
 </context>
@@ -496,6 +500,10 @@ Guymager beendet sich automatisch in %1 Sekunden.</translation>
         <comment>Display that verification is off</comment>
         <translation>aus</translation>
     </message>
+    <message>
+        <source>Additional state info</source>
+        <translation>Status-Zusatzinformation</translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -560,7 +568,7 @@ Compilation timestamp: %2
 Compiled with gcc %3
 Using libewf %4
 Using libguytools %5</source>
-        <translation>GUYMAGER ist ein Linux-basierter, forensischer Imager
+        <translation type="obsolete">GUYMAGER ist ein Linux-basierter, forensischer Imager
 
 Version: %1
 Zeitstempel der Kompilation: %2
@@ -711,6 +719,34 @@ Benutzt libguytools %5</translation>
         <source>Exit after acquisitions completed</source>
         <translation>Guymager nach Abschluss aller Akquisitionen beenden</translation>
     </message>
+    <message>
+        <source>Aborted - Info file write error</source>
+        <translation>Abbruch - Schreibfehler Info-Datei</translation>
+    </message>
+    <message>
+        <source>Aborted - Acquisition start failure</source>
+        <translation>Abbruch - Startfehler Akquisition</translation>
+    </message>
+    <message>
+        <source>(not used as Guymager currently is configured to use its own EWF module)</source>
+        <translation>(inaktiv, da das Guymager-interne EWF-Modul konfiguriert ist)</translation>
+    </message>
+    <message>
+        <source>GUYMAGER is a Linux-based forensic imaging tool
+
+Version: %1
+Compilation timestamp: %2
+Compiled with gcc %3
+Linked with libewf %4 %5
+Linked with libguytools %6</source>
+        <translation>GUYMAGER ist ein Linux-basierter, forensischer Imager
+
+Version: %1
+Zeitstempel der Kompilation: %2
+Kompiliert mit gcc %3
+Benutzt libewf %4 %5
+Benutzt libguytools %6</translation>
+    </message>
 </context>
 <context>
     <name>t_Table</name>
@@ -1030,6 +1066,27 @@ Benutzt libguytools %5</translation>
         <source>Device used for cloning - cannot be acquired</source>
         <translation>Gerät durch Klon-Operation belegt - kann nicht akquiriert werden</translation>
     </message>
+    <message>
+        <source>Generated image files and their MD5 hashes</source>
+        <comment>Info file</comment>
+        <translation>Erezugte Image-Dateien und ihre MD5-Hashwerte</translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (the select EWF format does not support image file hashes)</source>
+        <translation>Keine MD5-Hashes verfügbar (das ausgewählte EWF-Format unterstützt das Hashen der Image-Dateien nicht)</translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (image verification checkbox was switched off)</source>
+        <translation>Keine MD5-Hashes verfügbar (das Häkchen zur Image-Verifikation war nicht gesetzt)</translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)</source>
+        <translation>Keine MD5-Hashes verfügbar (der Konfigurationsparameter CalcImageFileMD5 ist abgeschaltet)</translation>
+    </message>
+    <message>
+        <source>Cannot be acquired - see additional state info field</source>
+        <translation>Kann nicht akquiriert werden - siehe Status-Zusatzinformation</translation>
+    </message>
 </context>
 <context>
     <name>t_ThreadScan</name>
diff --git a/guymager_en.ts b/guymager_en.ts
index 979bf37..49ec28e 100644
--- a/guymager_en.ts
+++ b/guymager_en.ts
@@ -344,7 +344,7 @@ Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB.For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
+        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB. For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -478,6 +478,10 @@ Guymager will exit automatically in %1 seconds.</source>
         <comment>Display that verification is off</comment>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Additional state info</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -530,16 +534,6 @@ Guymager will exit automatically in %1 seconds.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GUYMAGER is a Linux-based forensic imaging tool
-
-Version: %1
-Compilation timestamp: %2
-Compiled with gcc %3
-Using libewf %4
-Using libguytools %5</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>About GUYMAGER</source>
         <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
@@ -687,6 +681,28 @@ Using libguytools %5</source>
         <source>Exit after acquisitions completed</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Aborted - Info file write error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborted - Acquisition start failure</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>(not used as Guymager currently is configured to use its own EWF module)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>GUYMAGER is a Linux-based forensic imaging tool
+
+Version: %1
+Compilation timestamp: %2
+Compiled with gcc %3
+Linked with libewf %4 %5
+Linked with libguytools %6</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_Table</name>
@@ -1006,6 +1022,27 @@ Using libguytools %5</source>
         <source>Device used for cloning - cannot be acquired</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Generated image files and their MD5 hashes</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (the select EWF format does not support image file hashes)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (image verification checkbox was switched off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot be acquired - see additional state info field</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_ThreadScan</name>
diff --git a/guymager_fr.ts b/guymager_fr.ts
index 9bea00f..d595db3 100644
--- a/guymager_fr.ts
+++ b/guymager_fr.ts
@@ -267,7 +267,7 @@ Acceptez-vous ces changement?</translation>
     </message>
     <message>
         <source>Hash calculation / verification</source>
-        <translation>Calcul / vérification de valuers hash</translation>
+        <translation>Calcul / vérification de valeurs hash</translation>
     </message>
     <message>
         <source>Guymager cannot write to the directory
@@ -366,7 +366,11 @@ Acceptez-vous ces changement?</translation>
     </message>
     <message>
         <source>The split size for the configured EWF format must be in the range %1 - %2 MiB.For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
-        <translation>La taille des fragments pour le format EWF configuré doit être comprise entre %1 - %2 MiB. Des fichiers plus grands sont possibles à partir du format Encase6 (voir fichier de configuration, paramètre EwfFormat).</translation>
+        <translation type="obsolete">La taille des fragments pour le format EWF configuré doit être comprise entre %1 - %2 MiB. Des fichiers plus grands sont possibles à partir du format Encase6 (voir fichier de configuration, paramètre EwfFormat).</translation>
+    </message>
+    <message>
+        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB. For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
+        <translation>La taille des fragments pour le format EWF configuré doit être comprise entre %1 et %2 MiB. Des fichiers plus grands sont possibles à partir du format Encase6 (voir fichier de configuration, paramètre EwfFormat).</translation>
     </message>
 </context>
 <context>
@@ -500,6 +504,10 @@ Guymager set terminera automatiquement dans %1 secondes.</translation>
         <comment>Display that verification is off</comment>
         <translation>non</translation>
     </message>
+    <message>
+        <source>Additional state info</source>
+        <translation>Informations d'état suppl.</translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -598,7 +606,7 @@ Compilation timestamp: %2
 Compiled with gcc %3
 Using libewf %4
 Using libguytools %5</source>
-        <translation>GUYMAGER est un outil d'acquisition forensique basé sur Linux
+        <translation type="obsolete">GUYMAGER est un outil d'acquisition forensique basé sur Linux
 
 Version: %1
 Date et heure de compilation: %2
@@ -715,6 +723,34 @@ Utilise libguytools %5</translation>
         <source>Exit after acquisitions completed</source>
         <translation>Terminer Guymager à la fin des acquisitions</translation>
     </message>
+    <message>
+        <source>Aborted - Info file write error</source>
+        <translation>Abandon - accès fichier info échoué</translation>
+    </message>
+    <message>
+        <source>Aborted - Acquisition start failure</source>
+        <translation>Abandon - Démarrage échoué</translation>
+    </message>
+    <message>
+        <source>(not used as Guymager currently is configured to use its own EWF module)</source>
+        <translation>(inactif, Guymager est configuré d'utiliser son propre module EWF)</translation>
+    </message>
+    <message>
+        <source>GUYMAGER is a Linux-based forensic imaging tool
+
+Version: %1
+Compilation timestamp: %2
+Compiled with gcc %3
+Linked with libewf %4 %5
+Linked with libguytools %6</source>
+        <translation>GUYMAGER est un outil d'acquisition forensique basé sur Linux
+
+Version: %1
+Date et heure de compilation: %2
+Compilé avec gcc %3
+Utilise libewf %4 %5
+Utilise libguytools %6</translation>
+    </message>
 </context>
 <context>
     <name>t_Table</name>
@@ -1034,6 +1070,27 @@ Utilise libguytools %5</translation>
         <source>Device used for cloning - cannot be acquired</source>
         <translation>Occupé par opération de clonage - ne peut être  acquéré</translation>
     </message>
+    <message>
+        <source>Generated image files and their MD5 hashes</source>
+        <comment>Info file</comment>
+        <translation>Fichiers image et leur valeurs hash MD5</translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (the select EWF format does not support image file hashes)</source>
+        <translation>Valeurs hashs MD5 non disponibles (le format EWF choisi ne supporte pas le calcul des valeurs hash des fichiers image)</translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (image verification checkbox was switched off)</source>
+        <translation>Valeurs hashs MD5 non disponibles (l'option pour la vérification de l'image n'était pas activée)</translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)</source>
+        <translation>Valeurs hashs MD5 non disponibles (le paramètre de configuration CalcImageFileMD5 est désactivé)</translation>
+    </message>
+    <message>
+        <source>Cannot be acquired - see additional state info field</source>
+        <translation>Ne peut être acquéré - voir informations d'état suppl.</translation>
+    </message>
 </context>
 <context>
     <name>t_ThreadScan</name>
diff --git a/guymager_it.ts b/guymager_it.ts
index aa94654..eae8e41 100644
--- a/guymager_it.ts
+++ b/guymager_it.ts
@@ -344,7 +344,7 @@ Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB.For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
+        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB. For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -478,6 +478,10 @@ Guymager will exit automatically in %1 seconds.</source>
         <comment>Display that verification is off</comment>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Additional state info</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -569,16 +573,6 @@ Guymager will exit automatically in %1 seconds.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GUYMAGER is a Linux-based forensic imaging tool
-
-Version: %1
-Compilation timestamp: %2
-Compiled with gcc %3
-Using libewf %4
-Using libguytools %5</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>About Qt</source>
         <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
@@ -687,6 +681,28 @@ Using libguytools %5</source>
         <source>Exit after acquisitions completed</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Aborted - Info file write error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborted - Acquisition start failure</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>(not used as Guymager currently is configured to use its own EWF module)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>GUYMAGER is a Linux-based forensic imaging tool
+
+Version: %1
+Compilation timestamp: %2
+Compiled with gcc %3
+Linked with libewf %4 %5
+Linked with libguytools %6</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_Table</name>
@@ -1006,6 +1022,27 @@ Using libguytools %5</source>
         <source>Device used for cloning - cannot be acquired</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Generated image files and their MD5 hashes</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (the select EWF format does not support image file hashes)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (image verification checkbox was switched off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot be acquired - see additional state info field</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_ThreadScan</name>
diff --git a/guymager_nl.ts b/guymager_nl.ts
index f5ab2cf..6077c76 100644
--- a/guymager_nl.ts
+++ b/guymager_nl.ts
@@ -344,7 +344,7 @@ Do you accept these changes?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB.For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
+        <source>The split size for the configured EWF format must be in the range %1 - %2 MiB. For bigger files, switch to Encase6 format or later (see Guymager configuration file, parameter EwfFormat).</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -478,6 +478,10 @@ Guymager will exit automatically in %1 seconds.</source>
         <comment>Display that verification is off</comment>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Additional state info</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_MainWindow</name>
@@ -585,16 +589,6 @@ Guymager will exit automatically in %1 seconds.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GUYMAGER is a Linux-based forensic imaging tool
-
-Version: %1
-Compilation timestamp: %2
-Compiled with gcc %3
-Using libewf %4
-Using libguytools %5</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>About Qt</source>
         <comment>Dialog title</comment>
         <translation type="unfinished"></translation>
@@ -687,6 +681,28 @@ Using libguytools %5</source>
         <source>Exit after acquisitions completed</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Aborted - Info file write error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Aborted - Acquisition start failure</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>(not used as Guymager currently is configured to use its own EWF module)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>GUYMAGER is a Linux-based forensic imaging tool
+
+Version: %1
+Compilation timestamp: %2
+Compiled with gcc %3
+Linked with libewf %4 %5
+Linked with libguytools %6</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_Table</name>
@@ -1006,6 +1022,27 @@ Using libguytools %5</source>
         <source>Device used for cloning - cannot be acquired</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Generated image files and their MD5 hashes</source>
+        <comment>Info file</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (the select EWF format does not support image file hashes)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (image verification checkbox was switched off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot be acquired - see additional state info field</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>t_ThreadScan</name>
diff --git a/hash.cpp b/hash.cpp
index 2050f8c..b9fcfad 100644
--- a/hash.cpp
+++ b/hash.cpp
@@ -9,7 +9,7 @@
 //  Module:         Hash wrapper functions for uniform hash interface
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -31,10 +31,24 @@
 #include <QtCore>
 #include "hash.h"
 
+#ifdef USE_MD5_FROM_OPENSSL
+#include <openssl/md5.h>
+#endif
+
+#ifdef USE_SHA256_FROM_OPENSSL
+#include <openssl/sha.h>
+#endif
+
 // ------------------------------------
 //             MD5 Functions
 // ------------------------------------
 
+APIRET HashMD5Clear (t_pHashContextMD5 pContext)
+{
+   memset (pContext, 0, sizeof(t_HashContextMD5));
+   return NO_ERROR;
+}
+
 APIRET HashMD5Init (t_pHashContextMD5 pContext)
 {
    #ifdef USE_MD5_FROM_OPENSSL
@@ -85,21 +99,39 @@ bool HashMD5Match (t_pHashMD5Digest pDigest1, t_pHashMD5Digest pDigest2)
 //           SHA256 Functions
 // ------------------------------------
 
+APIRET HashSHA256Clear (t_pHashContextSHA256 pContext)
+{
+   memset (pContext, 0, sizeof(t_HashContextSHA256));
+   return NO_ERROR;
+}
+
 APIRET HashSHA256Init (t_pHashContextSHA256 pContext)
 {
-   sha256_starts (pContext);
+   #ifdef USE_SHA256_FROM_OPENSSL
+      (void) SHA256_Init (pContext);
+   #else
+      sha256_starts (pContext);
+   #endif
    return NO_ERROR;
 }
 
 APIRET HashSHA256Append (t_pHashContextSHA256 pContext, void *pData, int DataLen)
 {
-   sha256_update (pContext, (unsigned char *)pData, DataLen);
+   #ifdef USE_SHA256_FROM_OPENSSL
+      (void) SHA256_Update (pContext, pData, (unsigned long) DataLen);
+   #else
+      sha256_update (pContext, (unsigned char *)pData, DataLen);
+   #endif
    return NO_ERROR;
 }
 
 APIRET HashSHA256Digest (t_pHashContextSHA256 pContext, t_pHashSHA256Digest pDigest)
 {
-   sha256_finish (pContext, (unsigned char *)pDigest);
+   #ifdef USE_SHA256_FROM_OPENSSL
+      (void) SHA256_Final (&pDigest->Buff[0], pContext);
+   #else
+      sha256_finish (pContext, (unsigned char *)pDigest);
+   #endif
    return NO_ERROR;
 }
 
diff --git a/hash.h b/hash.h
index a12db1e..077ace1 100644
--- a/hash.h
+++ b/hash.h
@@ -9,7 +9,7 @@
 //  Module:         Hash wrapper functions for uniform hash interface
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -33,18 +33,24 @@
    #include "common.h"
 #endif
 
-#ifdef USE_MD5_FROM_OPENSSL   // Only for test purposes; It is strongly recommended to use the local md5 functions in order to avoid an OpenSSL dependency
+#ifdef USE_MD5_FROM_OPENSSL
    #include <openssl/md5.h>
    typedef MD5_CTX t_HashContextMD5;
 #else
    #include "md5.h"
    typedef md5_state_t t_HashContextMD5;
 #endif
-typedef t_HashContextMD5 *t_pHashContextMD5;
 
-#include "sha256.h"
-typedef sha256_context  t_HashContextSHA256;
-typedef sha256_context *t_pHashContextSHA256;
+#ifdef USE_SHA256_FROM_OPENSSL
+   #include <openssl/sha.h>
+   typedef SHA256_CTX t_HashContextSHA256;
+#else
+   #include "sha256.h"
+   typedef sha256_context  t_HashContextSHA256;
+#endif
+
+typedef t_HashContextMD5    *t_pHashContextMD5;
+typedef t_HashContextSHA256 *t_pHashContextSHA256;
 
 
 
@@ -63,12 +69,14 @@ typedef struct
    unsigned char Buff[HASH_SHA256_DIGEST_LENGTH];
 } t_HashSHA256Digest, *t_pHashSHA256Digest;
 
+APIRET HashMD5Clear     (t_pHashContextMD5 pContext);
 APIRET HashMD5Init      (t_pHashContextMD5 pContext);
 APIRET HashMD5Append    (t_pHashContextMD5 pContext, const void *pData, int DataLen);
 APIRET HashMD5Digest    (t_pHashContextMD5 pContext, t_pHashMD5Digest pDigest);
 APIRET HashMD5DigestStr (t_pHashMD5Digest pDigest, QString &Str);
 bool   HashMD5Match     (t_pHashMD5Digest pDigest1, t_pHashMD5Digest pDigest2);
 
+APIRET HashSHA256Clear     (t_pHashContextSHA256 pContext);
 APIRET HashSHA256Init      (t_pHashContextSHA256 pContext);
 APIRET HashSHA256Append    (t_pHashContextSHA256 pContext, void *pData, int DataLen);
 APIRET HashSHA256Digest    (t_pHashContextSHA256 pContext, t_pHashSHA256Digest pDigest);
diff --git a/info.cpp b/info.cpp
index ac14722..5dbb4f1 100644
--- a/info.cpp
+++ b/info.cpp
@@ -9,7 +9,7 @@
 //  Module:         Information about the acquisition, creates the info file
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/info.h b/info.h
index ee52350..8053c86 100644
--- a/info.h
+++ b/info.h
@@ -9,7 +9,7 @@
 //  Module:         Information about the acquisition, creates the info file
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/infofield.cpp b/infofield.cpp
index cc8407b..9d37918 100644
--- a/infofield.cpp
+++ b/infofield.cpp
@@ -9,7 +9,7 @@
 //  Module:         The info field area
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -49,6 +49,8 @@ t_InfoField::t_InfoField ()
 t_InfoField::t_InfoField (QWidget *pParent)
    :QFrame (pParent)
 {
+   QString LabelParams;
+   
    CHK_EXIT (TOOL_ERROR_REGISTER_CODE (ERROR_INFOFIELD_CONSTRUCTOR_NOT_SUPPORTED))
 
    setFrameStyle ((int)QFrame::Panel | (int)QFrame::Sunken);
@@ -60,16 +62,20 @@ t_InfoField::t_InfoField (QWidget *pParent)
    pLayout->addWidget (pOwn->pLabelParams);
    pLayout->addWidget (pOwn->pLabelValues);
    pLayout->addStretch();
-
-   pOwn->pLabelParams->setText (         tr("Size")
-                                + "\n" + tr("Sector size")
-                                + "\n" + tr("Image file")
-                                + "\n" + tr("Info file")
-                                + "\n" + tr("Current speed")
-                                + "\n" + tr("Started", "Start timestamp and running time")
-                                + "\n" + tr("Hash calculation")
-                                + "\n" + tr("Source verification")
-                                + "\n" + tr("Image verification"));
+   
+   if (CONFIG (CommandGetAddStateInfo)[0])
+      LabelParams = tr("Additional state info") + "\n";
+      
+   LabelParams +=       tr("Size")
+               + "\n" + tr("Sector size")
+               + "\n" + tr("Image file")
+               + "\n" + tr("Info file")
+               + "\n" + tr("Current speed")
+               + "\n" + tr("Started", "Start timestamp and running time")
+               + "\n" + tr("Hash calculation")
+               + "\n" + tr("Source verification")
+               + "\n" + tr("Image verification");
+   pOwn->pLabelParams->setText (LabelParams);
 }
 
 t_InfoField::~t_InfoField ()
@@ -86,10 +92,15 @@ void t_InfoField::SlotShowInfo (t_pDevice pDevice)
 
    if (pDevice)
    {
+      // Additional state info
+      // ---------------------
+      if (CONFIG (CommandGetAddStateInfo)[0])
+         StrValue = pDevice->AddStateInfo.Info + "\n";
+         
       // Size
       // ----
       Size = t_Device::GetSize (pDevice).toULongLong();
-      StrValue = MainGetpNumberLocale()->toString(Size) + " " + tr("bytes");
+      StrValue += MainGetpNumberLocale()->toString(Size) + " " + tr("bytes");
       StrValue += " ("  + t_Device::GetSizeHumanFrac (pDevice, false).toString();
       StrValue += " / " + t_Device::GetSizeHumanFrac (pDevice, true ).toString() + ")";
 
@@ -109,7 +120,7 @@ void t_InfoField::SlotShowInfo (t_pDevice pDevice)
       }
       else
       {
-         CHK_EXIT (t_File::GetFormatExtension   (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, NULL, &Format))
+         CHK_EXIT (t_File::GetFormatExtension   (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, 0, NULL, &Format))
          StrValue += "\n" + pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename + QSTR_TO_PSZ(Format);
          StrValue += "\n" + pDevice->Acquisition.InfoPath  + pDevice->Acquisition.InfoFilename  + t_File::pExtensionInfo;
       }
diff --git a/infofield.h b/infofield.h
index 6e552f6..0d0f4b3 100644
--- a/infofield.h
+++ b/infofield.h
@@ -9,7 +9,7 @@
 //  Module:         The info field area 
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/itemdelegate.cpp b/itemdelegate.cpp
index 5a6510d..17e7ce3 100644
--- a/itemdelegate.cpp
+++ b/itemdelegate.cpp
@@ -10,7 +10,7 @@
 //                  in t_Table.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/itemdelegate.h b/itemdelegate.h
index 02ee379..5a33977 100644
--- a/itemdelegate.h
+++ b/itemdelegate.h
@@ -10,7 +10,7 @@
 //                  in t_Table.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/macros_for_lint.h b/macros_for_lint.h
new file mode 100644
index 0000000..0f44585
--- /dev/null
+++ b/macros_for_lint.h
@@ -0,0 +1,139 @@
+// The following macros have generated with the command
+//      echo | g++ -dM -E - | sort
+// in order wto have lint work with the same settings then g++. However, some defintions
+// need to be switched off (see below)
+
+#define __amd64 1
+#define __amd64__ 1
+#define __BIGGEST_ALIGNMENT__ 16
+#define __CHAR16_TYPE__ short unsigned int
+#define __CHAR32_TYPE__ unsigned int
+#define __CHAR_BIT__ 8
+#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+#define __DBL_DIG__ 15
+#define __DBL_EPSILON__ 2.2204460492503131e-16
+#define __DBL_HAS_DENORM__ 1
+#define __DBL_HAS_INFINITY__ 1
+#define __DBL_HAS_QUIET_NAN__ 1
+#define __DBL_MANT_DIG__ 53
+#define __DBL_MAX_10_EXP__ 308
+#define __DBL_MAX__ 1.7976931348623157e+308
+#define __DBL_MAX_EXP__ 1024
+#define __DBL_MIN_10_EXP__ (-307)
+#define __DBL_MIN__ 2.2250738585072014e-308
+#define __DBL_MIN_EXP__ (-1021)
+#define __DEC128_EPSILON__ 1E-33DL
+#define __DEC128_MANT_DIG__ 34
+#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
+#define __DEC128_MAX_EXP__ 6145
+#define __DEC128_MIN__ 1E-6143DL
+#define __DEC128_MIN_EXP__ (-6142)
+#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL
+#define __DEC32_EPSILON__ 1E-6DF
+#define __DEC32_MANT_DIG__ 7
+#define __DEC32_MAX__ 9.999999E96DF
+#define __DEC32_MAX_EXP__ 97
+#define __DEC32_MIN__ 1E-95DF
+#define __DEC32_MIN_EXP__ (-94)
+#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF
+#define __DEC64_EPSILON__ 1E-15DD
+#define __DEC64_MANT_DIG__ 16
+#define __DEC64_MAX__ 9.999999999999999E384DD
+#define __DEC64_MAX_EXP__ 385
+#define __DEC64_MIN__ 1E-383DD
+#define __DEC64_MIN_EXP__ (-382)
+#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD
+#define __DEC_EVAL_METHOD__ 2
+#define __DECIMAL_BID_FORMAT__ 1
+#define __DECIMAL_DIG__ 21
+#define __ELF__ 1
+#define __FINITE_MATH_ONLY__ 0
+#define __FLT_DENORM_MIN__ 1.40129846e-45F
+#define __FLT_DIG__ 6
+#define __FLT_EPSILON__ 1.19209290e-7F
+#define __FLT_EVAL_METHOD__ 0
+#define __FLT_HAS_DENORM__ 1
+#define __FLT_HAS_INFINITY__ 1
+#define __FLT_HAS_QUIET_NAN__ 1
+#define __FLT_MANT_DIG__ 24
+#define __FLT_MAX_10_EXP__ 38
+#define __FLT_MAX__ 3.40282347e+38F
+#define __FLT_MAX_EXP__ 128
+#define __FLT_MIN_10_EXP__ (-37)
+#define __FLT_MIN__ 1.17549435e-38F
+#define __FLT_MIN_EXP__ (-125)
+#define __FLT_RADIX__ 2
+#define _FORTIFY_SOURCE 2
+#define __GCC_HAVE_DWARF2_CFI_ASM 1
+#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
+#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
+#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
+#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1
+//#define __GNUC__ 4
+#define __GNUC_GNU_INLINE__ 1
+//#define __GNUC_MINOR__ 4
+//#define __GNUC_PATCHLEVEL__ 5
+#define __gnu_linux__ 1
+#define __GXX_ABI_VERSION 1002
+#define __INT_MAX__ 2147483647
+#define __INTMAX_MAX__ 9223372036854775807L
+#define __INTMAX_TYPE__ long int
+#define __k8 1
+#define __k8__ 1
+#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
+#define __LDBL_DIG__ 18
+#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
+#define __LDBL_HAS_DENORM__ 1
+#define __LDBL_HAS_INFINITY__ 1
+#define __LDBL_HAS_QUIET_NAN__ 1
+#define __LDBL_MANT_DIG__ 64
+#define __LDBL_MAX_10_EXP__ 4932
+#define __LDBL_MAX__ 1.18973149535723176502e+4932L
+#define __LDBL_MAX_EXP__ 16384
+#define __LDBL_MIN_10_EXP__ (-4931)
+#define __LDBL_MIN__ 3.36210314311209350626e-4932L
+#define __LDBL_MIN_EXP__ (-16381)
+#define __linux 1
+#define __linux__ 1
+#define linux 1
+#define __LONG_LONG_MAX__ 9223372036854775807LL
+#define __LONG_MAX__ 9223372036854775807L
+#define __LP64__ 1
+#define _LP64 1
+#define __MMX__ 1
+#define __NO_INLINE__ 1
+#define __PTRDIFF_TYPE__ long int
+#define __REGISTER_PREFIX__
+#define __SCHAR_MAX__ 127
+#define __SHRT_MAX__ 32767
+#define __SIZEOF_DOUBLE__ 8
+#define __SIZEOF_FLOAT__ 4
+#define __SIZEOF_INT__ 4
+#define __SIZEOF_LONG__ 8
+#define __SIZEOF_LONG_DOUBLE__ 16
+#define __SIZEOF_LONG_LONG__ 8
+#define __SIZEOF_POINTER__ 8
+#define __SIZEOF_PTRDIFF_T__ 8
+#define __SIZEOF_SHORT__ 2
+#define __SIZEOF_SIZE_T__ 8
+#define __SIZEOF_WCHAR_T__ 4
+#define __SIZEOF_WINT_T__ 4
+#define __SIZE_TYPE__ long unsigned int
+#define __SSE__ 1
+#define __SSE2__ 1
+#define __SSE2_MATH__ 1
+#define __SSE_MATH__ 1
+#define __SSP__ 1
+#define __STDC__ 1
+#define __STDC_HOSTED__ 1
+#define __UINTMAX_TYPE__ long unsigned int
+#define __unix 1
+#define __unix__ 1
+#define unix 1
+#define __USER_LABEL_PREFIX__
+#define __VERSION__ "4.4.5"
+#define __WCHAR_MAX__ 2147483647
+#define __WCHAR_TYPE__ int
+#define __WINT_TYPE__ unsigned int
+#define __x86_64 1
+#define __x86_64__ 1
diff --git a/main.cpp b/main.cpp
index 9a60413..0d122c0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -11,7 +11,7 @@
 //                  deinitialisation.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -51,6 +51,7 @@
 #include "config.h"
 #include "device.h"
 #include "qtutil.h"
+#include "util.h"
 #include "hash.h"
 #include "aaff.h"
 #include "aewf.h"
@@ -441,6 +442,7 @@ static APIRET MainGo (int argc, char *argv[], bool *pAutoExit)
    // ----------------------------------------------------------------------
    MainLocal.CriticalInitDone = true;
 
+   CHK (UtilInit    ())
    CHK (HashInit    ())
    CHK (QtUtilInit  ())
    CHK (t_File::Init())
@@ -497,6 +499,7 @@ static APIRET MainGo (int argc, char *argv[], bool *pAutoExit)
    CHK (AaffDeInit  ())
    CHK (QtUtilDeInit())
    CHK (HashDeInit  ())
+   CHK (UtilDeInit  ())
    CHK (CfgDeInit   ())
 
    delete MainLocal.pApp;
diff --git a/main.h b/main.h
index 96d0385..90d8ae8 100644
--- a/main.h
+++ b/main.h
@@ -9,7 +9,7 @@
 //  Module:         Main
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 030dd6a..a1e66d8 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -10,7 +10,7 @@
 //                  widget
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -44,6 +44,10 @@
 #include "table.h"
 #include "dlgmessage.h"
 #include "dlgautoexit.h"
+#include "threadread.h"
+#include "threadhash.h"
+#include "threadcompress.h"
+#include "threadwrite.h"
 
 
 // -----------------------------
@@ -83,6 +87,7 @@ t_DeviceListModel::t_DeviceListModel (t_pDeviceList pDeviceList)
       COL_ASSOC (tr("Linux\ndevice"          , "Column of device table"), t_Device::GetLinuxDevice   , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
       COL_ASSOC (tr("Model"                  , "Column of device table"), t_Device::GetModel         , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
       COL_ASSOC (tr("State"                  , "Column of device table"), t_Device::GetState         , t_ItemDelegate::DISPLAYTYPE_STATE   , LEFT  , 200)
+//    COL_ASSOC (tr("Additional\nstate info" , "Column of device table"), t_Device::GetAddStateInfo  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
       COL_ASSOC (tr("Size"                   , "Column of device table"), t_Device::GetSizeHuman     , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
       COL_ASSOC (tr("Hidden\nAreas"          , "Column of device table"), t_Device::GetHiddenAreas   , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
       COL_ASSOC (tr("Bad\nsectors"           , "Column of device table"), t_Device::GetBadSectorCount, t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
@@ -90,9 +95,9 @@ t_DeviceListModel::t_DeviceListModel (t_pDeviceList pDeviceList)
       COL_ASSOC (tr("Average\nSpeed\n[MB/s]" , "Column of device table"), t_Device::GetAverageSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, RIGHT ,   0)
       COL_ASSOC (tr("Time\nremaining"        , "Column of device table"), t_Device::GetRemaining     , t_ItemDelegate::DISPLAYTYPE_STANDARD, CENTER,   0)
       COL_ASSOC (tr("FIFO queues\nusage\n[%]", "Column of device table"), t_Device::GetFifoStatus    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
-//    COL_ASSOC (tr("Sector\nsize\nlog."     , "Column of device table"), t_Device::GetSectorSize    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
-//    COL_ASSOC (tr("Sector\nsize\nphys."    , "Column of device table"), t_Device::GetSectorSizePhys, t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
-//    COL_ASSOC (tr("Current\nSpeed\n[MB/s]" , "Column of device table"), t_Device::GetCurrentSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT, 0      )
+//    COL_ASSOC (tr("Sector\nsize\nlog."     , "Column of device table"), t_Device::GetSectorSize    , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
+//    COL_ASSOC (tr("Sector\nsize\nphys."    , "Column of device table"), t_Device::GetSectorSizePhys, t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
+//    COL_ASSOC (tr("Current\nSpeed\n[MB/s]" , "Column of device table"), t_Device::GetCurrentSpeed  , t_ItemDelegate::DISPLAYTYPE_STANDARD, LEFT  ,   0)
    #undef COL_ASSOC
    #undef LEFT
    #undef RIGHT
@@ -157,7 +162,14 @@ QVariant t_DeviceListModel::data(const QModelIndex &Index, int Role) const
             pDev = poDeviceList->at(Index.row());
             if (pDev->Local)
                  Value = QBrush (CONFIG_COLOR(COLOR_LOCALDEVICES));
-            else Value = QVariant();
+            else switch (pDev->AddStateInfo.Color)
+                 {
+                    case 1 : Value = QBrush (CONFIG_COLOR(COLOR_ADDITIONALSTATE1)); break;
+                    case 2 : Value = QBrush (CONFIG_COLOR(COLOR_ADDITIONALSTATE2)); break;
+                    case 3 : Value = QBrush (CONFIG_COLOR(COLOR_ADDITIONALSTATE3)); break;
+                    case 4 : Value = QBrush (CONFIG_COLOR(COLOR_ADDITIONALSTATE4)); break;
+                    default: Value = QVariant();
+                 }
             break;
          case Qt::DisplayRole:
             if (Index.column() >= ColAssocList.count())
@@ -279,6 +291,7 @@ t_MainWindow::t_MainWindow (t_pDeviceList pDeviceList, QWidget *pParent, Qt::WFl
 
    CHK_EXIT (CreateMenu ())
    setWindowTitle ("GUYMAGER");
+//   setSizeGripEnabled (true);
 
    // Create models and view according do the following layering:
    //    TableView        -> GUI
@@ -424,6 +437,7 @@ void t_MainWindow::SlotScanFinished (t_pDeviceList pNewDeviceList)
 {
    t_pDeviceList pDeviceList;
    t_pDevice     pDev, pNewDev;
+   bool           NewDevice;
    int            i;
 
 //   LOG_INFO ("%d devices found", pNewDeviceList->count())
@@ -433,7 +447,8 @@ void t_MainWindow::SlotScanFinished (t_pDeviceList pNewDeviceList)
       pDev = pDeviceList->at (i);
       if (pDev->SpecialDevice)
            pDev->Checked = true;   // Checked is used to remember which devices we have seen and which ones not. Treat
-      else pDev->Checked = false;  // special devices as already seen, thus, they are going to be removed from the list.
+      else pDev->Checked = false;  // special devices as already seen, thus, they are not going to be removed from the list.
+      pDev->AddedNow=false;
    }
 
    for (i=0; i<pNewDeviceList->count(); i++)
@@ -451,14 +466,19 @@ void t_MainWindow::SlotScanFinished (t_pDeviceList pNewDeviceList)
 //         LOG_INFO ("No match for device %s %s %s %llu", QSTR_TO_PSZ (pNewDev->LinuxDevice), QSTR_TO_PSZ (pNewDev->Model), QSTR_TO_PSZ (pNewDev->SerialNumber), pNewDev->Size)
 //      }
 
-      if (pDev)
+      if (pDev)                           // Normally, if pDev has been found, it means that pNewDev already is known and should not be added another time. However,
+           NewDevice = (pDev->AddedNow);  // function t_DeviceList::MatchDevice might be wrong in some cases and finds devices it shouldn't. This might happen
+      else NewDevice = true;              // for devices of the same size and not having serial numbers. In order to prevent from these cases, we say that one device scan
+                                          // very unlikely returns 2 entries for the same device (nobody unplugs and replugs a device that fast). So, if t_DeviceList::MatchDevice
+                                          // returns a match with a device that has been added while we are processing this loop, we simply ignore the match and add the device anyway.
+      if (!NewDevice)
       {
          pDev->Checked = true;
          if ((pDev->State == t_Device::AcquirePaused) ||
              (pDev->State == t_Device::VerifyPaused))
          {
             LOG_INFO ("Switching %s to connected again", QSTR_TO_PSZ(pNewDev->LinuxDevice))
-            pDev->LinuxDevice = pNewDev->LinuxDevice;    // Linux may choose a new path when reconnecting the device
+               pDev->LinuxDevice = pNewDev->LinuxDevice;    // Linux may choose a new path when reconnecting the device
             if (pDev->State == t_Device::AcquirePaused)  // (1)
                  pDev->State = t_Device::Acquire;
             else pDev->State = t_Device::Verify;
@@ -466,7 +486,8 @@ void t_MainWindow::SlotScanFinished (t_pDeviceList pNewDeviceList)
       }
       else
       {
-         pNewDev->Checked = true;
+         pNewDev->Checked  = true;
+         pNewDev->AddedNow = true;
          pNewDeviceList->removeAt (i--);                 // (3)
          pDeviceList->append (pNewDev);
       }
@@ -536,11 +557,14 @@ void t_MainWindow::closeEvent (QCloseEvent *pEvent)
 
 void t_MainWindow::SlotDebug (void)
 {
-   QString DebugInfo;
-   quint64 FifoAllocs, FifoFrees;
-   qint64  FifoRemaining;
-   qint64  FifoAllocated;
+   t_pDevice pDevice;
+   QString    DebugInfo;
+   quint64    FifoAllocs, FifoFrees;
+   qint64     FifoRemaining;
+   qint64     FifoAllocated;
 
+   // FIFO memory statistics
+   // ----------------------
    CHK_EXIT (FifoGetStatistics (FifoAllocs, FifoFrees, FifoAllocated))
    FifoRemaining = FifoAllocs - FifoFrees;
    DebugInfo  = "FIFO Buffers";
@@ -549,6 +573,22 @@ void t_MainWindow::SlotDebug (void)
    DebugInfo += QString ("\n   %1 remaining") .arg(FifoRemaining, 10);
    DebugInfo += QString ("\n   %1 MB"       ) .arg((double)FifoAllocated / (1024.0*1024.0), 10, 'f', 1);
 
+   // Thread messages
+   // ---------------
+   #define ADD_MESSAGE(pThread, Name) if (pDevice->pThread) DebugInfo += QString ("\n   %1: %2") .arg(Name, -13) .arg(pDevice->pThread->GetDebugMessage());
+
+   for (int i=0; i<pOwn->pDeviceList->count(); i++)
+   {
+      pDevice = pOwn->pDeviceList->at(i);
+      DebugInfo += QString ("\nThread messages for %1") .arg(pDevice->LinuxDevice);
+      ADD_MESSAGE (pThreadRead, "Read")
+      ADD_MESSAGE (pThreadHash, "Hash")
+      for (int j=0; j<pDevice->ThreadCompressList.count(); j++)
+         ADD_MESSAGE (ThreadCompressList.at(j), QString("Compress %1").arg(j))
+      ADD_MESSAGE (pThreadWrite, "Write")
+   }
+   DebugInfo += QString ("\nThreadScan: %1") .arg(pOwn->pThreadScan->GetDebugMessage());
+
    CHK_EXIT (t_DlgMessage::Show (tr("Debug information"), DebugInfo, true))
 }
 
@@ -556,22 +596,26 @@ void t_MainWindow::SlotAboutGuymager (void)
 {
    const char *pLibGuyToolsVersionInstalled;
    const char *pLibEwfVersionInstalled;
+   QString      EwfRemark;
 
    t_Log::GetLibGuyToolsVersion (&pLibGuyToolsVersionInstalled);
 
    pLibEwfVersionInstalled = (const char *) libewf_get_version ();
 
+   if (CONFIG(EwfFormat) == t_File::AEWF)
+        EwfRemark = tr("(not used as Guymager currently is configured to use its own EWF module)");
+   else EwfRemark = "";
    QMessageBox::about(this, tr("About GUYMAGER", "Dialog title"),
                             tr("GUYMAGER is a Linux-based forensic imaging tool\n\n"
                                "Version: %1\n"
                                "Compilation timestamp: %2\n"
                                "Compiled with gcc %3\n"
-                               "Using libewf %4\n"
-                               "Using libguytools %5")
+                               "Linked with libewf %4 %5\n"
+                               "Linked with libguytools %6")
                                .arg(pCompileInfoVersion)
                                .arg(pCompileInfoTimestamp)
                                .arg(__VERSION__)
-                               .arg(pLibEwfVersionInstalled)
+                               .arg(pLibEwfVersionInstalled) .arg(EwfRemark)
                                .arg(pLibGuyToolsVersionInstalled));
 }
 
diff --git a/mainwindow.h b/mainwindow.h
index f8f1a3a..44999e9 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -7,7 +7,7 @@
 //                  Section Nouvelles Technologies
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/media.cpp b/media.cpp
index 36ff087..ab77529 100644
--- a/media.cpp
+++ b/media.cpp
@@ -790,7 +790,10 @@ APIRET t_MediaInfo::QueryDevice (const char *pLinuxDevice)
 
       CHK (MediaGetSectorCount (File, pLinuxDevice, SupportsLBA48, &SectorCountDeviceConfigIdentify, &SectorCountReadNativeMax))
 
-      LOG_INFO ("Identification of %s: [%s] [%s] %llu / %llu / %llu", pLinuxDevice, QSTR_TO_PSZ(Model), QSTR_TO_PSZ(SerialNumber), SectorCountIdentifyDevice, SectorCountReadNativeMax, SectorCountDeviceConfigIdentify)
+      LOG_INFO ("%s model and serial number: [%s] [%s]", pLinuxDevice, QSTR_TO_PSZ(Model), QSTR_TO_PSZ(SerialNumber))
+      LOG_INFO ("%s sectors->IdentifyDevice: %llu"     , pLinuxDevice, SectorCountIdentifyDevice      )
+      LOG_INFO ("%s sectors->ReadNativeMax : %llu"     , pLinuxDevice, SectorCountReadNativeMax       )
+      LOG_INFO ("%s sectors->ConfigIdentify: %llu"     , pLinuxDevice, SectorCountDeviceConfigIdentify)
 //      printf ("\n[%s] [%s] [%s]", pLinuxDevice, QSTR_TO_PSZ(Model), QSTR_TO_PSZ(SerialNumber));
 //      printf ("\nIdentify       %16llu %16llX", SectorCountIdentifyDevice      , SectorCountIdentifyDevice      );
 //      printf ("\nNative         %16llu %16llX", SectorCountReadNativeMax       , SectorCountReadNativeMax       );
diff --git a/media.h b/media.h
index eb8bba1..1c53d68 100644
--- a/media.h
+++ b/media.h
@@ -9,7 +9,7 @@
 //  Module:         Module for special media function, like HPA/DCO and others
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/memwatch.c b/memwatch.c
deleted file mode 100644
index 08c5f39..0000000
--- a/memwatch.c
+++ /dev/null
@@ -1,2664 +0,0 @@
-/*
-** MEMWATCH.C
-** Nonintrusive ANSI C memory leak / overwrite detection
-** Copyright (C) 1992-2003 Johan Lindh
-** All rights reserved.
-** Version 2.71
-
-	This file is part of MEMWATCH.
-
-    MEMWATCH is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    MEMWATCH 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 General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with MEMWATCH; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-**
-** 920810 JLI   [1.00]
-** 920830 JLI   [1.10 double-free detection]
-** 920912 JLI   [1.15 mwPuts, mwGrab/Drop, mwLimit]
-** 921022 JLI   [1.20 ASSERT and VERIFY]
-** 921105 JLI   [1.30 C++ support and TRACE]
-** 921116 JLI   [1.40 mwSetOutFunc]
-** 930215 JLI   [1.50 modified ASSERT/VERIFY]
-** 930327 JLI   [1.51 better auto-init & PC-lint support]
-** 930506 JLI   [1.55 MemWatch class, improved C++ support]
-** 930507 JLI   [1.60 mwTest & CHECK()]
-** 930809 JLI   [1.65 Abort/Retry/Ignore]
-** 930820 JLI   [1.70 data dump when unfreed]
-** 931016 JLI   [1.72 modified C++ new/delete handling]
-** 931108 JLI   [1.77 mwSetAssertAction() & some small changes]
-** 940110 JLI   [1.80 no-mans-land alloc/checking]
-** 940328 JLI   [2.00 version 2.0 rewrite]
-**              Improved NML (no-mans-land) support.
-**              Improved performance (especially for free()ing!).
-**              Support for 'read-only' buffers (checksums)
-**              ^^ NOTE: I never did this... maybe I should?
-**              FBI (free'd block info) tagged before freed blocks
-**              Exporting of the mwCounter variable
-**              mwBreakOut() localizes debugger support
-**              Allocation statistics (global, per-module, per-line)
-**              Self-repair ability with relinking
-** 950913 JLI   [2.10 improved garbage handling]
-** 951201 JLI   [2.11 improved auto-free in emergencies]
-** 960125 JLI   [X.01 implemented auto-checking using mwAutoCheck()]
-** 960514 JLI   [2.12 undefining of existing macros]
-** 960515 JLI   [2.13 possibility to use default new() & delete()]
-** 960516 JLI   [2.20 suppression of file flushing on unfreed msgs]
-** 960516 JLI   [2.21 better support for using MEMWATCH with DLL's]
-** 960710 JLI   [X.02 multiple logs and mwFlushNow()]
-** 960801 JLI   [2.22 merged X.01 version with current]
-** 960805 JLI   [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
-** 960805 JLI   [2.31 merged X.02 version with current]
-** 961002 JLI   [2.32 support for realloc() + fixed STDERR bug]
-** 961222 JLI   [2.40 added mwMark() & mwUnmark()]
-** 970101 JLI   [2.41 added over/underflow checking after failed ASSERT/VERIFY]
-** 970113 JLI   [2.42 added support for PC-Lint 7.00g]
-** 970207 JLI   [2.43 added support for strdup()]
-** 970209 JLI   [2.44 changed default filename to lowercase]
-** 970405 JLI   [2.45 fixed bug related with atexit() and some C++ compilers]
-** 970723 JLI   [2.46 added MW_ARI_NULLREAD flag]
-** 970813 JLI   [2.47 stabilized marker handling]
-** 980317 JLI   [2.48 ripped out C++ support; wasn't working good anyway]
-** 980318 JLI   [2.50 improved self-repair facilities & SIGSEGV support]
-** 980417 JLI	[2.51 more checks for invalid addresses]
-** 980512 JLI	[2.52 moved MW_ARI_NULLREAD to occur before aborting]
-** 990112 JLI	[2.53 added check for empty heap to mwIsOwned]
-** 990217 JLI	[2.55 improved the emergency repairs diagnostics and NML]
-** 990224 JLI	[2.56 changed ordering of members in structures]
-** 990303 JLI	[2.57 first maybe-fixit-for-hpux test]
-** 990516 JLI	[2.58 added 'static' to the definition of mwAutoInit]
-** 990517 JLI	[2.59 fixed some high-sensitivity warnings]
-** 990610 JLI	[2.60 fixed some more high-sensitivity warnings]
-** 990715 JLI	[2.61 changed TRACE/ASSERT/VERIFY macro names]
-** 991001 JLI	[2.62 added CHECK_BUFFER() and mwTestBuffer()]
-** 991007 JLI	[2.63 first shot at a 64-bit compatible version]
-** 991009 JLI	[2.64 undef's strdup() if defined, mwStrdup made const]
-** 000704 JLI	[2.65 added some more detection for 64-bits]
-** 010502 JLI   [2.66 incorporated some user fixes]
-**              [mwRelink() could print out garbage pointer (thanks mac at phobos.ca)]
-**				[added array destructor for C++ (thanks rdasilva at connecttel.com)]
-**				[added mutex support (thanks rdasilva at connecttel.com)]
-** 010531 JLI	[2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
-** 010619 JLI	[2.68 fix: mwRealloc() could leave the mutex locked]
-** 020918 JLI	[2.69 changed to GPL, added C++ array allocation by Howard Cohen]
-** 030212 JLI	[2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
-** 030520 JLI	[2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
-*/
-
-#define __MEMWATCH_C 1
-
-#ifdef MW_NOCPP
-#define MEMWATCH_NOCPP
-#endif
-#ifdef MW_STDIO
-#define MEMWATCH_STDIO
-#endif
-
-/***********************************************************************
-** Include files
-***********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <time.h>
-#include <limits.h>
-#include "memwatch.h"
-
-#ifndef toupper
-#include <ctype.h>
-#endif
-
-#if defined(WIN32) || defined(__WIN32__)
-#define MW_HAVE_MUTEX 1
-#include <windows.h>
-#endif
-
-#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
-#define MW_HAVE_MUTEX 1
-#include <pthread.h>
-#endif
-
-/***********************************************************************
-** Defines & other weird stuff
-***********************************************************************/
-
-/*lint -save -e767 */
-#define VERSION     "2.71"         /* the current version number */
-#define CHKVAL(mw)  (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)
-#define FLUSH()     mwFlush()
-#define TESTS(f,l)  if(mwTestAlways) (void)mwTestNow(f,l,1)
-#define PRECHK      0x01234567L
-#define POSTCHK     0x76543210L
-#define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )
-/*lint -restore */
-
-#define MW_NML      0x0001
-
-#ifdef _MSC_VER
-#define COMMIT "c"  /* Microsoft C requires the 'c' to perform as desired */
-#else
-#define COMMIT ""   /* Normal ANSI */
-#endif /* _MSC_VER */
-
-#ifdef __cplusplus
-#define CPPTEXT "++"
-#else
-#define CPPTEXT ""
-#endif /* __cplusplus */
-
-#ifdef MEMWATCH_STDIO
-#define mwSTDERR stderr
-#else
-#define mwSTDERR mwLog
-#endif
-
-#ifdef MW_HAVE_MUTEX
-#define MW_MUTEX_INIT()		mwMutexInit()
-#define MW_MUTEX_TERM()		mwMutexTerm()
-#define MW_MUTEX_LOCK()		mwMutexLock()
-#define MW_MUTEX_UNLOCK()	mwMutexUnlock()
-#else
-#define MW_MUTEX_INIT()
-#define MW_MUTEX_TERM()
-#define MW_MUTEX_LOCK()
-#define MW_MUTEX_UNLOCK()
-#endif
-
-/***********************************************************************
-** If you really, really know what you're doing,
-** you can predefine these things yourself.
-***********************************************************************/
-
-#ifndef mwBYTE_DEFINED
-# if CHAR_BIT != 8
-#  error need CHAR_BIT to be 8!
-# else
-typedef unsigned char mwBYTE;
-#  define mwBYTE_DEFINED 1
-# endif
-#endif
-
-#if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)
-# define mw64BIT 1
-# define mwROUNDALLOC_DEFAULT 8
-#else
-# if UINT_MAX <= 0xFFFFUL
-#  define mw16BIT 1
-#  define mwROUNDALLOC_DEFAULT	2
-# else
-#  if ULONG_MAX > 0xFFFFFFFFUL
-#   define mw64BIT 1
-#   define mwROUNDALLOC_DEFAULT	8
-#  else
-#   define mw32BIT 1
-#   define mwROUNDALLOC_DEFAULT	4
-#  endif
-# endif
-#endif
-
-/* mwROUNDALLOC is the number of bytes to */
-/* round up to, to ensure that the end of */
-/* the buffer is suitable for storage of */
-/* any kind of object */
-#ifndef mwROUNDALLOC
-# define mwROUNDALLOC mwROUNDALLOC_DEFAULT
-#endif
-
-#ifndef mwDWORD_DEFINED
-#if ULONG_MAX == 0xFFFFFFFFUL
-typedef unsigned long mwDWORD;
-#define mwDWORD_DEFINED "unsigned long"
-#endif
-#endif
-
-#ifndef mwDWORD_DEFINED
-#if UINT_MAX == 0xFFFFFFFFUL
-typedef unsigned int mwDWORD;
-#define mwDWORD_DEFINED "unsigned int"
-#endif
-#endif
-
-#ifndef mwDWORD_DEFINED
-#if USHRT_MAX == 0xFFFFFFFFUL
-typedef unsigned short mwDWORD;
-#define mwDWORD_DEFINED "unsigned short"
-#endif
-#endif
-
-#ifndef mwBYTE_DEFINED
-#error "can't find out the correct type for a 8 bit scalar"
-#endif
-
-#ifndef mwDWORD_DEFINED
-#error "can't find out the correct type for a 32 bit scalar"
-#endif
-
-/***********************************************************************
-** Typedefs & structures
-***********************************************************************/
-
-/* main data holding area, precedes actual allocation */
-typedef struct mwData_ mwData;
-struct mwData_ {
-    mwData*     prev;   /* previous allocation in chain */
-    mwData*     next;   /* next allocation in chain */
-    const char* file;   /* file name where allocated */
-    long        count;  /* action count */
-    long        check;  /* integrity check value */
-#if 0
-    long        crc;    /* data crc value */
-#endif
-    size_t      size;   /* size of allocation */
-    int         line;   /* line number where allocated */
-    unsigned    flag;   /* flag word */
-    };
-
-/* statistics structure */
-typedef struct mwStat_ mwStat;
-struct mwStat_ {
-    mwStat*     next;   /* next statistic buffer */
-    const char* file;
-    long        total;  /* total bytes allocated */
-    long        num;    /* total number of allocations */
-    long        max;    /* max allocated at one time */
-    long        curr;   /* current allocations */
-    int         line;
-    };
-
-/* grabbing structure, 1K in size */
-typedef struct mwGrabData_ mwGrabData;
-struct mwGrabData_ {
-    mwGrabData* next;
-    int         type;
-    char        blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ];
-    };
-
-typedef struct mwMarker_ mwMarker;
-struct mwMarker_ {
-    void *host;
-    char *text;
-    mwMarker *next;
-    int level;
-    };
-
-#if defined(WIN32) || defined(__WIN32__)
-typedef HANDLE          mwMutex;
-#endif
-
-#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
-typedef pthread_mutex_t mwMutex;
-#endif
-
-/***********************************************************************
-** Static variables
-***********************************************************************/
-
-static int      mwInited =      0;
-static int      mwInfoWritten = 0;
-static int      mwUseAtexit =   0;
-static FILE*    mwLog =         NULL;
-static int      mwFlushing =    0;
-static int      mwStatLevel =   MW_STAT_DEFAULT;
-static int      mwNML =         MW_NML_DEFAULT;
-static int      mwFBI =         0;
-static long     mwAllocLimit =  0L;
-static int      mwUseLimit =    0;
-
-static long     mwNumCurAlloc = 0L;
-static mwData*  mwHead = 		NULL;
-static mwData*  mwTail = 		NULL;
-static int		mwDataSize =	0;
-static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";
-static int		mwOverflowZoneSize = mwROUNDALLOC;
-
-static void     (*mwOutFunction)(int) = NULL;
-static int      (*mwAriFunction)(const char*) = NULL;
-static int      mwAriAction = MW_ARI_ABORT;
-
-static char     mwPrintBuf[MW_TRACE_BUFFER+8];
-
-static unsigned long mwCounter = 0L;
-static long     mwErrors =      0L;
-
-static int      mwTestFlags =   0;
-static int      mwTestAlways =  0;
-
-static FILE*    mwLogB1 =       NULL;
-static int      mwFlushingB1 =  0;
-
-static mwStat*  mwStatList = NULL;
-static long     mwStatTotAlloc = 0L;
-static long     mwStatMaxAlloc = 0L;
-static long     mwStatNumAlloc = 0L;
-static long     mwStatCurAlloc = 0L;
-static long     mwNmlNumAlloc = 0L;
-static long     mwNmlCurAlloc = 0L;
-
-static mwGrabData* mwGrabList = NULL;
-static long     mwGrabSize = 0L;
-
-static void *   mwLastFree[MW_FREE_LIST];
-static const char *mwLFfile[MW_FREE_LIST];
-static int      mwLFline[MW_FREE_LIST];
-static int      mwLFcur = 0;
-
-static mwMarker* mwFirstMark = NULL;
-
-static FILE*    mwLogB2 =       NULL;
-static int      mwFlushingB2 =  0;
-
-#ifdef MW_HAVE_MUTEX
-static mwMutex	mwGlobalMutex;
-#endif
-
-/***********************************************************************
-** Static function declarations
-***********************************************************************/
-
-static void     mwAutoInit( void );
-static FILE*    mwLogR( void );
-static void     mwLogW( FILE* );
-static int      mwFlushR( void );
-static void     mwFlushW( int );
-static void     mwFlush( void );
-static void     mwIncErr( void );
-static void     mwUnlink( mwData*, const char* file, int line );
-static int      mwRelink( mwData*, const char* file, int line );
-static int      mwIsHeapOK( mwData *mw );
-static int      mwIsOwned( mwData* mw, const char* file, int line );
-static int      mwTestBuf( mwData* mw, const char* file, int line );
-static void     mwDefaultOutFunc( int );
-static void     mwWrite( const char* format, ... );
-static void     mwLogFile( const char* name );
-static size_t   mwFreeUp( size_t, int );
-static const void *mwTestMem( const void *, unsigned, int );
-static int      mwStrCmpI( const char *s1, const char *s2 );
-static int      mwTestNow( const char *file, int line, int always_invoked );
-static void     mwDropAll( void );
-static const char *mwGrabType( int type );
-static unsigned mwGrab_( unsigned kb, int type, int silent );
-static unsigned mwDrop_( unsigned kb, int type, int silent );
-static int      mwARI( const char* text );
-static void     mwStatReport( void );
-static mwStat*  mwStatGet( const char*, int, int );
-static void     mwStatAlloc( size_t, const char*, int );
-static void     mwStatFree( size_t, const char*, int );
-static int		mwCheckOF( const void * p );
-static void		mwWriteOF( void * p );
-static char		mwDummy( char c );
-#ifdef MW_HAVE_MUTEX
-static void		mwMutexInit( void );
-static void		mwMutexTerm( void );
-static void		mwMutexLock( void );
-static void		mwMutexUnlock( void );
-#endif
-
-/***********************************************************************
-** System functions
-***********************************************************************/
-
-void mwInit( void ) {
-    time_t tid;
-
-    if( mwInited++ > 0 ) return;
-
-	MW_MUTEX_INIT();
-
-    /* start a log if none is running */
-    if( mwLogR() == NULL ) mwLogFile( "memwatch.log" );
-    if( mwLogR() == NULL ) {
-        int i;
-        char buf[32];
-        /* oops, could not open it! */
-        /* probably because it's already open */
-        /* so we try some other names */
-        for( i=1; i<100; i++ ) {
-            sprintf( buf, "memwat%02d.log", i );
-            mwLogFile( buf );
-            if( mwLogR() != NULL ) break;
-            }
-        }
-
-    /* initialize the statistics */
-    mwStatList = NULL;
-    mwStatTotAlloc = 0L;
-    mwStatCurAlloc = 0L;
-    mwStatMaxAlloc = 0L;
-    mwStatNumAlloc = 0L;
-	mwNmlCurAlloc = 0L;
-	mwNmlNumAlloc = 0L;
-
-	/* calculate the buffer size to use for a mwData */
-	mwDataSize = sizeof(mwData);
-	while( mwDataSize % mwROUNDALLOC ) mwDataSize ++;
-
-    /* write informational header if needed */
-    if( !mwInfoWritten ) {
-        mwInfoWritten = 1;
-        (void) time( &tid );
-        mwWrite(
-            "\n============="
-            " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
-            "=============\n");
-        mwWrite( "\nStarted at %s\n", ctime( &tid ) );
-
-/**************************************************************** Generic */
-		mwWrite( "Modes: " );
-#ifdef mwNew
-        mwWrite( "C++ " );
-#endif /* mwNew */
-#ifdef __STDC__
-        mwWrite( "__STDC__ " );
-#endif /* __STDC__ */
-#ifdef mw16BIT
-		mwWrite( "16-bit " );
-#endif
-#ifdef mw32BIT
-		mwWrite( "32-bit " );
-#endif
-#ifdef mw64BIT
-		mwWrite( "64-bit " );
-#endif
-		mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
-		mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
-			mwROUNDALLOC, sizeof(mwData), mwDataSize );
-/**************************************************************** Generic */
-
-/************************************************************ Microsoft C */
-#ifdef _MSC_VER
-        mwWrite( "Compiled using Microsoft C" CPPTEXT
-            " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
-#endif /* _MSC_VER */
-/************************************************************ Microsoft C */
-
-/************************************************************** Borland C */
-#ifdef __BORLANDC__
-        mwWrite( "Compiled using Borland C"
-#ifdef __cplusplus
-            "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
-#else
-            " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
-#endif /* __cplusplus */
-#endif /* __BORLANDC__ */
-/************************************************************** Borland C */
-
-/************************************************************** Watcom C */
-#ifdef __WATCOMC__
-        mwWrite( "Compiled using Watcom C %d.%02d ",
-            __WATCOMC__/100, __WATCOMC__%100 );
-#ifdef __FLAT__
-        mwWrite( "(32-bit flat model)" );
-#endif /* __FLAT__ */
-        mwWrite( "\n" );
-#endif /* __WATCOMC__ */
-/************************************************************** Watcom C */
-
-        mwWrite( "\n" );
-        FLUSH();
-        }
-
-    if( mwUseAtexit ) (void) atexit( mwAbort );
-    return;
-    }
-
-void mwAbort( void ) {
-    mwData *mw;
-    mwMarker *mrk;
-    char *data;
-    time_t tid;
-    int c, i, j;
-	int errors;
-
-    tid = time( NULL );
-    mwWrite( "\nStopped at %s\n", ctime( &tid) );
-
-    if( !mwInited )
-        mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
-
-    /* release the grab list */
-    mwDropAll();
-
-    /* report mwMarked items */
-    while( mwFirstMark ) {
-        mrk = mwFirstMark->next;
-        mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
-        free( mwFirstMark->text );
-        free( mwFirstMark );
-        mwFirstMark = mrk;
-        mwErrors ++;
-        }
-
-    /* release all still allocated memory */
-	errors = 0;
-    while( mwHead != NULL && errors < 3 ) {
-		if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
-			if( errors < 3 )
-			{
-				errors ++;
-				mwWrite( "internal: NML/unfreed scan restarting\n" );
-				FLUSH();
-				mwHead = mwHead;
-				continue;
-			}
-			mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
-			FLUSH();
-			break;
-			}
-        mwFlushW(0);
-        if( !(mwHead->flag & MW_NML) ) {
-            mwErrors++;
-            data = ((char*)mwHead)+mwDataSize;
-            mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ",
-                mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize );
-            if( mwCheckOF( data ) ) {
-                mwWrite( "[underflowed] ");
-                FLUSH();
-                }
-            if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) {
-                mwWrite( "[overflowed] ");
-                FLUSH();
-                }
-            mwWrite( " \t{" );
-            j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size;
-            for( i=0;i<16;i++ ) {
-                if( i<j ) mwWrite( "%02X ",
-                    (unsigned char) *(data+mwOverflowZoneSize+i) );
-                else mwWrite( ".. " );
-                }
-            for( i=0;i<j;i++ ) {
-                c = *(data+mwOverflowZoneSize+i);
-                if( c < 32 || c > 126 ) c = '.';
-                mwWrite( "%c", c );
-                }
-            mwWrite( "}\n" );
-			mw = mwHead;
-			mwUnlink( mw, __FILE__, __LINE__ );
-            free( mw );
-            }
-        else {
-            data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize;
-            if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) {
-                mwErrors++;
-                mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
-                    mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line );
-                FLUSH();
-                }
-			mwNmlNumAlloc --;
-			mwNmlCurAlloc -= mwHead->size;
-			mw = mwHead;
-			mwUnlink( mw, __FILE__, __LINE__ );
-            free( mw );
-            }
-        }
-
-	if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
-	if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
-
-    /* report statistics */
-    mwStatReport();
-    FLUSH();
-
-    mwInited = 0;
-    mwHead = mwTail = NULL;
-    if( mwErrors )
-        fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors);
-    mwLogFile( NULL );
-    mwErrors = 0;
-
-    MW_MUTEX_TERM();
-
-    }
-
-void mwTerm( void ) {
-    if( mwInited == 1 )
-    {
-        mwAbort();
-        return;
-    }
-    if( !mwInited )
-        mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n");
-    else
-        mwInited --;
-    }
-
-void mwStatistics( int level )
-{
-    mwAutoInit();
-    if( level<0 ) level=0;
-    if( mwStatLevel != level )
-    {
-		mwWrite( "statistics: now collecting on a %s basis\n",
-			level<1?"global":(level<2?"module":"line") );
-	    mwStatLevel = level;
-	}
-}
-
-void mwAutoCheck( int onoff ) {
-    mwAutoInit();
-    mwTestAlways = onoff;
-    if( onoff ) mwTestFlags = MW_TEST_ALL;
-    }
-
-void mwSetOutFunc( void (*func)(int) ) {
-    mwAutoInit();
-    mwOutFunction = func;
-    }
-
-static void mwWriteOF( void *p )
-{
-	int i;
-	unsigned char *ptr;
-	ptr = (unsigned char*) p;
-	for( i=0; i<mwOverflowZoneSize; i++ )
-	{
-		*(ptr+i) = mwOverflowZoneTemplate[i%8];
-	}
-	return;
-}
-
-static int mwCheckOF( const void *p )
-{
-	int i;
-	const unsigned char *ptr;
-	ptr = (const unsigned char *) p;
-	for( i=0; i<mwOverflowZoneSize; i++ )
-	{
-		if( *(ptr+i) != mwOverflowZoneTemplate[i%8] )
-			return 1; /* errors found */
-	}
-	return 0; /* no errors */
-}
-
-int mwTest( const char *file, int line, int items ) {
-    mwAutoInit();
-    mwTestFlags = items;
-    return mwTestNow( file, line, 0 );
-    }
-
-/*
-** Returns zero if there are no errors.
-** Returns nonzero if there are errors.
-*/
-int mwTestBuffer( const char *file, int line, void *p ) {
-    mwData* mw;
-
-    mwAutoInit();
-
-    /* do the quick ownership test */
-    mw = (mwData*) mwBUFFER_TO_MW( p );
-
-    if( mwIsOwned( mw, file, line ) ) {
-        return mwTestBuf( mw, file, line );
-		}
-	return 1;
-	}
-
-void mwBreakOut( const char* cause ) {
-    fprintf(mwSTDERR, "breakout: %s\n", cause);
-    mwWrite("breakout: %s\n", cause );
-    return;
-    }
-
-/*
-** 981217 JLI: is it possible that ->next is not always set?
-*/
-void * mwMark( void *p, const char *desc, const char *file, unsigned line ) {
-    mwMarker *mrk;
-    unsigned n, isnew;
-    char *buf;
-    int tot, oflow = 0;
-    char wherebuf[128];
-
-    mwAutoInit();
-    TESTS(NULL,0);
-
-    if( desc == NULL ) desc = "unknown";
-    if( file == NULL ) file = "unknown";
-
-    tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line );
-    if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; }
-
-    if( p == NULL ) {
-        mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc );
-        return p;
-        }
-
-	if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) )
-	{
-		mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n",
-			file, line, mwFirstMark, desc );
-		return p;
-	}
-
-    for( mrk=mwFirstMark; mrk; mrk=mrk->next )
-	{
-		if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) )
-		{
-			mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n",
-				file, line, mrk, mrk->next, desc );
-			return p;
-		}
-		if( mrk->host == p ) break;
-	}
-
-    if( mrk == NULL ) {
-        isnew = 1;
-        mrk = (mwMarker*) malloc( sizeof( mwMarker ) );
-        if( mrk == NULL ) {
-            mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
-            return p;
-            }
-		mrk->next = NULL;
-        n = 0;
-        }
-    else {
-        isnew = 0;
-        n = strlen( mrk->text );
-        }
-
-    n += strlen( wherebuf );
-    buf = (char*) malloc( n+3 );
-    if( buf == NULL ) {
-        if( isnew ) free( mrk );
-        mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
-        return p;
-        }
-
-    if( isnew ) {
-        memcpy( buf, wherebuf, n+1 );
-        mrk->next = mwFirstMark;
-        mrk->host = p;
-        mrk->text = buf;
-        mrk->level = 1;
-        mwFirstMark = mrk;
-        }
-    else {
-        strcpy( buf, mrk->text );
-        strcat( buf, ", " );
-        strcat( buf, wherebuf );
-        free( mrk->text );
-        mrk->text = buf;
-        mrk->level ++;
-        }
-
-    if( oflow ) {
-        mwIncErr();
-        mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
-        }
-    return p;
-    }
-
-void* mwUnmark( void *p, const char *file, unsigned line ) {
-    mwMarker *mrk, *prv;
-    mrk = mwFirstMark;
-    prv = NULL;
-    while( mrk ) {
-        if( mrk->host == p ) {
-            if( mrk->level < 2 ) {
-                if( prv ) prv->next = mrk->next;
-                else mwFirstMark = mrk->next;
-                free( mrk->text );
-                free( mrk );
-                return p;
-                }
-            mrk->level --;
-            return p;
-            }
-        prv = mrk;
-        mrk = mrk->next;
-        }
-    mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p );
-    return p;
-    }
-
-
-/***********************************************************************
-** Abort/Retry/Ignore handlers
-***********************************************************************/
-
-static int mwARI( const char *estr ) {
-    char inbuf[81];
-    int c;
-    fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr);
-    (void) fgets(inbuf,sizeof(inbuf),stdin);
-	for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ;
-    c = inbuf[c];
-    if( c == 'R' || c == 'r' ) {
-        mwBreakOut( estr );
-        return MW_ARI_RETRY;
-        }
-    if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE;
-    return MW_ARI_ABORT;
-    }
-
-/* standard ARI handler (exported) */
-int mwAriHandler( const char *estr ) {
-    mwAutoInit();
-    return mwARI( estr );
-    }
-
-/* used to set the ARI function */
-void mwSetAriFunc( int (*func)(const char *) ) {
-    mwAutoInit();
-    mwAriFunction = func;
-    }
-
-/***********************************************************************
-** Allocation handlers
-***********************************************************************/
-
-void* mwMalloc( size_t size, const char* file, int line) {
-    size_t needed;
-    mwData *mw;
-    char *ptr;
-    void *p;
-
-    mwAutoInit();
-
-	MW_MUTEX_LOCK();
-
-    TESTS(file,line);
-
-    mwCounter ++;
-    needed = mwDataSize + mwOverflowZoneSize*2 + size;
-    if( needed < size )
-    {
-    	/* theoretical case: req size + mw overhead exceeded size_t limits */
-    	return NULL;
-    }
-
-    /* if this allocation would violate the limit, fail it */
-    if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) {
-        mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
-            mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc );
-        mwIncErr();
-        FLUSH();
-		MW_MUTEX_UNLOCK();
-        return NULL;
-        }
-
-    mw = (mwData*) malloc( needed );
-    if( mw == NULL ) {
-        if( mwFreeUp(needed,0) >= needed ) {
-            mw = (mwData*) malloc(needed);
-            if( mw == NULL ) {
-                mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
-                mwIncErr();
-                FLUSH();
-                }
-            }
-        if( mw == NULL ) {
-            mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n",
-                mwCounter, file, line, (long)size, mwStatCurAlloc );
-            mwIncErr();
-            FLUSH();
-			MW_MUTEX_UNLOCK();
-            return NULL;
-            }
-        }
-
-    mw->count = mwCounter;
-    mw->prev = NULL;
-    mw->next = mwHead;
-    mw->file = file;
-    mw->size = size;
-    mw->line = line;
-    mw->flag = 0;
-    mw->check = CHKVAL(mw);
-
-    if( mwHead ) mwHead->prev = mw;
-    mwHead = mw;
-    if( mwTail == NULL ) mwTail = mw;
-
-    ptr = ((char*)mw) + mwDataSize;
-	mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */
-    ptr += mwOverflowZoneSize;
-    p = ptr;
-    memset( ptr, MW_VAL_NEW, size );
-    ptr += size;
-    mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */
-
-    mwNumCurAlloc ++;
-    mwStatCurAlloc += (long) size;
-    mwStatTotAlloc += (long) size;
-    if( mwStatCurAlloc > mwStatMaxAlloc )
-        mwStatMaxAlloc = mwStatCurAlloc;
-    mwStatNumAlloc ++;
-
-    if( mwStatLevel ) mwStatAlloc( size, file, line );
-
-	MW_MUTEX_UNLOCK();
-    return p;
-    }
-
-void* mwRealloc( void *p, size_t size, const char* file, int line) {
-    int oldUseLimit, i;
-    mwData *mw;
-    char *ptr;
-
-    mwAutoInit();
-
-    if( p == NULL ) return mwMalloc( size, file, line );
-    if( size == 0 ) { mwFree( p, file, line ); return NULL; }
-
-	MW_MUTEX_LOCK();
-
-    /* do the quick ownership test */
-    mw = (mwData*) mwBUFFER_TO_MW( p );
-    if( mwIsOwned( mw, file, line ) ) {
-
-		/* if the buffer is an NML, treat this as a double-free */
-		if( mw->flag & MW_NML )
-		{
-            mwIncErr();
-			if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
-			{
-				mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
-					mwCounter, file, line, mw );
-			}
-			goto check_dbl_free;
-		}
-
-        /* if this allocation would violate the limit, fail it */
-        if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) {
-            TESTS(file,line);
-            mwCounter ++;
-            mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
-                mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc );
-            mwIncErr();
-            FLUSH();
-			MW_MUTEX_UNLOCK();
-            return NULL;
-            }
-
-        /* fake realloc operation */
-        oldUseLimit = mwUseLimit;
-        mwUseLimit = 0;
-        ptr = (char*) mwMalloc( size, file, line );
-        if( ptr != NULL ) {
-            if( size < mw->size )
-                memcpy( ptr, p, size );
-            else
-                memcpy( ptr, p, mw->size );
-            mwFree( p, file, line );
-            }
-        mwUseLimit = oldUseLimit;
-		MW_MUTEX_UNLOCK();
-        return (void*) ptr;
-        }
-
-    /* Unknown pointer! */
-
-    /* using free'd pointer? */
-check_dbl_free:
-    for(i=0;i<MW_FREE_LIST;i++) {
-        if( mwLastFree[i] == p ) {
-            mwIncErr();
-            mwWrite( "realloc: <%ld> %s(%d), %p was"
-                " freed from %s(%d)\n",
-                mwCounter, file, line, p,
-                mwLFfile[i], mwLFline[i] );
-            FLUSH();
-			MW_MUTEX_UNLOCK();
-            return NULL;
-            }
-        }
-
-    /* some weird pointer */
-    mwIncErr();
-    mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n",
-        mwCounter, file, line, p );
-    FLUSH();
-	MW_MUTEX_UNLOCK();
-    return NULL;
-    }
-
-char *mwStrdup( const char* str, const char* file, int line ) {
-    size_t len;
-    char *newstring;
-
-	MW_MUTEX_LOCK();
-
-    if( str == NULL ) {
-        mwIncErr();
-        mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n",
-            mwCounter, file, line );
-        FLUSH();
-		MW_MUTEX_UNLOCK();
-        return NULL;
-        }
-
-    len = strlen( str ) + 1;
-    newstring = (char*) mwMalloc( len, file, line );
-    if( newstring != NULL ) memcpy( newstring, str, len );
-	MW_MUTEX_UNLOCK();
-    return newstring;
-    }
-
-void mwFree( void* p, const char* file, int line ) {
-    int i;
-    mwData* mw;
-    char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ];
-
-    /* this code is in support of C++ delete */
-    if( file == NULL ) {
-        mwFree_( p );
-		MW_MUTEX_UNLOCK();
-        return;
-        }
-
-    mwAutoInit();
-
-	MW_MUTEX_LOCK();
-    TESTS(file,line);
-    mwCounter ++;
-
-    /* on NULL free, write a warning and return */
-    if( p == NULL ) {
-        mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n",
-            mwCounter, file, line );
-        FLUSH();
-		MW_MUTEX_UNLOCK();
-        return;
-        }
-
-    /* do the quick ownership test */
-    mw = (mwData*) mwBUFFER_TO_MW( p );
-
-    if( mwIsOwned( mw, file, line ) ) {
-        (void) mwTestBuf( mw, file, line );
-
-		/* if the buffer is an NML, treat this as a double-free */
-		if( mw->flag & MW_NML )
-		{
-			if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
-			{
-				mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
-					mwCounter, file, line, mw );
-			}
-			goto check_dbl_free;
-		}
-
-        /* update the statistics */
-        mwNumCurAlloc --;
-        mwStatCurAlloc -= (long) mw->size;
-        if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line );
-
-        /* we should either free the allocation or keep it as NML */
-        if( mwNML ) {
-            mw->flag |= MW_NML;
-			mwNmlNumAlloc ++;
-			mwNmlCurAlloc += (long) mw->size;
-            memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size );
-            }
-        else {
-            /* unlink the allocation, and enter the post-free data */
-            mwUnlink( mw, file, line );
-            memset( mw, MW_VAL_DEL,
-                mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize );
-            if( mwFBI ) {
-                memset( mw, '.', mwDataSize + mwOverflowZoneSize );
-                sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line );
-                strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
-                }
-            free( mw );
-            }
-
-        /* add the pointer to the last-free track */
-        mwLFfile[ mwLFcur ] = file;
-        mwLFline[ mwLFcur ] = line;
-        mwLastFree[ mwLFcur++ ] = p;
-        if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0;
-
-		MW_MUTEX_UNLOCK();
-        return;
-        }
-
-    /* check for double-freeing */
-check_dbl_free:
-    for(i=0;i<MW_FREE_LIST;i++) {
-        if( mwLastFree[i] == p ) {
-            mwIncErr();
-            mwWrite( "double-free: <%ld> %s(%d), %p was"
-                " freed from %s(%d)\n",
-                mwCounter, file, line, p,
-                mwLFfile[i], mwLFline[i] );
-            FLUSH();
-			MW_MUTEX_UNLOCK();
-            return;
-            }
-        }
-
-    /* some weird pointer... block the free */
-    mwIncErr();
-    mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n",
-        mwCounter, file, line, p );
-    FLUSH();
-	MW_MUTEX_UNLOCK();
-    return;
-    }
-
-void* mwCalloc( size_t a, size_t b, const char *file, int line ) {
-    void *p;
-    size_t size = a * b;
-    p = mwMalloc( size, file, line );
-    if( p == NULL ) return NULL;
-    memset( p, 0, size );
-    return p;
-    }
-
-void mwFree_( void *p ) {
-	MW_MUTEX_LOCK();
-    TESTS(NULL,0);
-	MW_MUTEX_UNLOCK();
-    free(p);
-    }
-
-void* mwMalloc_( size_t size ) {
-	MW_MUTEX_LOCK();
-    TESTS(NULL,0);
-	MW_MUTEX_UNLOCK();
-    return malloc( size );
-    }
-
-void* mwRealloc_( void *p, size_t size ) {
-	MW_MUTEX_LOCK();
-    TESTS(NULL,0);
-	MW_MUTEX_UNLOCK();
-    return realloc( p, size );
-    }
-
-void* mwCalloc_( size_t a, size_t b ) {
-	MW_MUTEX_LOCK();
-    TESTS(NULL,0);
-	MW_MUTEX_UNLOCK();
-    return calloc( a, b );
-    }
-
-void mwFlushNow( void ) {
-    if( mwLogR() ) fflush( mwLogR() );
-    return;
-    }
-
-void mwDoFlush( int onoff ) {
-    mwFlushW( onoff<1?0:onoff );
-    if( onoff ) if( mwLogR() ) fflush( mwLogR() );
-    return;
-    }
-
-void mwLimit( long lim ) {
-    TESTS(NULL,0);
-    mwWrite("limit: old limit = ");
-    if( !mwAllocLimit ) mwWrite( "none" );
-    else mwWrite( "%ld bytes", mwAllocLimit );
-    mwWrite( ", new limit = ");
-    if( !lim ) {
-        mwWrite( "none\n" );
-        mwUseLimit = 0;
-        }
-    else {
-        mwWrite( "%ld bytes\n", lim );
-        mwUseLimit = 1;
-        }
-    mwAllocLimit = lim;
-    FLUSH();
-    }
-
-void mwSetAriAction( int action ) {
-	MW_MUTEX_LOCK();
-    TESTS(NULL,0);
-    mwAriAction = action;
-	MW_MUTEX_UNLOCK();
-    return;
-    }
-
-int mwAssert( int exp, const char *exps, const char *fn, int ln ) {
-    int i;
-    char buffer[MW_TRACE_BUFFER+8];
-    if( exp ) {
-    	return 0;
-    	}
-    mwAutoInit();
-	MW_MUTEX_LOCK();
-    TESTS(fn,ln);
-    mwIncErr();
-    mwCounter++;
-    mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
-    if( mwAriFunction != NULL ) {
-        sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
-        i = (*mwAriFunction)(buffer);
-		switch( i ) {
-			case MW_ARI_IGNORE:
-	           	mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter );
-				MW_MUTEX_UNLOCK();
-    	        return 0;
-			case MW_ARI_RETRY:
-            	mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter );
-				MW_MUTEX_UNLOCK();
-            	return 1;
-			}
-        }
-    else {
-        if( mwAriAction & MW_ARI_IGNORE ) {
-            mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
-			MW_MUTEX_UNLOCK();
-            return 0;
-            }
-        fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
-        }
-
-    FLUSH();
-    (void) mwTestNow( fn, ln, 1 );
-    FLUSH();
-
-	if( mwAriAction & MW_ARI_NULLREAD ) {
-		/* This is made in an attempt to kick in */
-		/* any debuggers or OS stack traces */
-	    FLUSH();
-		/*lint -save -e413 */
-		i = *((int*)NULL);
-		mwDummy( (char)i );
-		/*lint -restore */
-		}
-
-	MW_MUTEX_UNLOCK();
-    exit(255);
-    /* NOT REACHED - the return statement is in to keep */
-    /* stupid compilers from squeaking about differing return modes. */
-    /* Smart compilers instead say 'code unreachable...' */
-    /*lint -save -e527 */
-    return 0;
-    /*lint -restore */
-    }
-
-int mwVerify( int exp, const char *exps, const char *fn, int ln ) {
-    int i;
-    char buffer[MW_TRACE_BUFFER+8];
-    if( exp ) {
-    	return 0;
-    	}
-    mwAutoInit();
-	MW_MUTEX_LOCK();
-    TESTS(fn,ln);
-    mwIncErr();
-    mwCounter++;
-    mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
-    if( mwAriFunction != NULL ) {
-        sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
-        i = (*mwAriFunction)(buffer);
-        if( i == 0 ) {
-            mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter );
-			MW_MUTEX_UNLOCK();
-            return 0;
-            }
-        if( i == 1 ) {
-            mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter );
-			MW_MUTEX_UNLOCK();
-            return 1;
-            }
-        }
-    else {
-        if( mwAriAction & MW_ARI_NULLREAD ) {
-            /* This is made in an attempt to kick in */
-            /* any debuggers or OS stack traces */
-		    FLUSH();
-            /*lint -save -e413 */
-            i = *((int*)NULL);
-			mwDummy( (char)i );
-            /*lint -restore */
-            }
-        if( mwAriAction & MW_ARI_IGNORE ) {
-            mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
-			MW_MUTEX_UNLOCK();
-            return 0;
-            }
-        fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
-        }
-    FLUSH();
-    (void) mwTestNow( fn, ln, 1 );
-    FLUSH();
-	MW_MUTEX_UNLOCK();
-	exit(255);
-    /* NOT REACHED - the return statement is in to keep */
-    /* stupid compilers from squeaking about differing return modes. */
-    /* Smart compilers instead say 'code unreachable...' */
-    /*lint -save -e527 */
-    return 0;
-    /*lint -restore */
-    }
-
-void mwTrace( const char *format, ... ) {
-    int tot, oflow = 0;
-    va_list mark;
-
-    mwAutoInit();
-	MW_MUTEX_LOCK();
-    TESTS(NULL,0);
-    if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
-
-    va_start( mark, format );
-    tot = vsprintf( mwPrintBuf, format, mark );
-    va_end( mark );
-    if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
-    for(tot=0;mwPrintBuf[tot];tot++)
-        (*mwOutFunction)( mwPrintBuf[tot] );
-    if( oflow ) {
-        mwIncErr();
-        mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
-        }
-
-    FLUSH();
-	MW_MUTEX_UNLOCK();
-    }
-
-
-/***********************************************************************
-** Grab & Drop
-***********************************************************************/
-
-unsigned mwGrab( unsigned kb ) {
-    TESTS(NULL,0);
-    return mwGrab_( kb, MW_VAL_GRB, 0 );
-    }
-
-unsigned mwDrop( unsigned kb ) {
-    TESTS(NULL,0);
-    return mwDrop_( kb, MW_VAL_GRB, 0 );
-    }
-
-static void mwDropAll() {
-    TESTS(NULL,0);
-    (void) mwDrop_( 0, MW_VAL_GRB, 0 );
-    (void) mwDrop_( 0, MW_VAL_NML, 0 );
-    if( mwGrabList != NULL )
-        mwWrite( "internal: the grab list is not empty after mwDropAll()\n");
-    }
-
-static const char *mwGrabType( int type ) {
-    switch( type ) {
-        case MW_VAL_GRB:
-            return "grabbed";
-        case MW_VAL_NML:
-            return "no-mans-land";
-        default:
-            /* do nothing */
-            ;
-        }
-    return "<unknown type>";
-    }
-
-static unsigned mwGrab_( unsigned kb, int type, int silent ) {
-    unsigned i = kb;
-    mwGrabData *gd;
-    if( !kb ) i = kb = 65000U;
-
-    for(;kb;kb--) {
-        if( mwUseLimit &&
-            (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) {
-            if( !silent ) {
-                mwWrite("grabbed: all allowed memory to %s (%u kb)\n",
-                    mwGrabType(type), i-kb);
-                FLUSH();
-                }
-            return i-kb;
-            }
-        gd = (mwGrabData*) malloc( sizeof(mwGrabData) );
-        if( gd == NULL ) {
-            if( !silent ) {
-                mwWrite("grabbed: all available memory to %s (%u kb)\n",
-                    mwGrabType(type), i-kb);
-                FLUSH();
-                }
-            return i-kb;
-            }
-        mwGrabSize += (long) sizeof(mwGrabData);
-        gd->next = mwGrabList;
-        memset( gd->blob, type, sizeof(gd->blob) );
-        gd->type = type;
-        mwGrabList = gd;
-        }
-    if( !silent ) {
-        mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) );
-        FLUSH();
-        }
-    return i;
-    }
-
-static unsigned mwDrop_( unsigned kb, int type, int silent ) {
-    unsigned i = kb;
-    mwGrabData *gd,*tmp,*pr;
-    const void *p;
-
-    if( mwGrabList == NULL && kb == 0 ) return 0;
-    if( !kb ) i = kb = 60000U;
-
-    pr = NULL;
-    gd = mwGrabList;
-    for(;kb;) {
-        if( gd == NULL ) {
-            if( i-kb > 0 && !silent ) {
-                mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb);
-                FLUSH();
-                }
-            return i-kb;
-            }
-        if( gd->type == type ) {
-            if( pr ) pr->next = gd->next;
-            kb --;
-            tmp = gd;
-            if( mwGrabList == gd ) mwGrabList = gd->next;
-            gd = gd->next;
-            p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type );
-            if( p != NULL ) {
-                mwWrite( "wild pointer: <%ld> %s memory hit at %p\n",
-                    mwCounter, mwGrabType(type), p );
-                FLUSH();
-                }
-            mwGrabSize -= (long) sizeof(mwGrabData);
-            free( tmp );
-            }
-        else {
-            pr = gd;
-            gd = gd->next;
-            }
-        }
-    if( !silent ) {
-        mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) );
-        FLUSH();
-        }
-    return i;
-    }
-
-/***********************************************************************
-** No-Mans-Land
-***********************************************************************/
-
-void mwNoMansLand( int level ) {
-    mwAutoInit();
-    TESTS(NULL,0);
-    switch( level ) {
-        case MW_NML_NONE:
-            (void) mwDrop_( 0, MW_VAL_NML, 0 );
-            break;
-        case MW_NML_FREE:
-            break;
-        case MW_NML_ALL:
-            (void) mwGrab_( 0, MW_VAL_NML, 0 );
-            break;
-        default:
-            return;
-        }
-    mwNML = level;
-    }
-
-/***********************************************************************
-** Static functions
-***********************************************************************/
-
-static void mwAutoInit( void )
-{
-    if( mwInited ) return;
-    mwUseAtexit = 1;
-    mwInit();
-    return;
-}
-
-static FILE *mwLogR() {
-    if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog;
-    if( mwLog == mwLogB1 ) mwLogB2 = mwLog;
-    if( mwLog == mwLogB2 ) mwLogB1 = mwLog;
-    if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
-    if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) {
-        mwWrite("internal: log file handle damaged and recovered\n");
-        FLUSH();
-        return mwLog;
-        }
-    fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
-    mwLog = mwLogB1 = mwLogB2 = mwSTDERR;
-    return mwSTDERR;
-    }
-
-static void mwLogW( FILE *p ) {
-    mwLog = mwLogB1 = mwLogB2 = p;
-    }
-
-static int mwFlushR() {
-    if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing;
-    if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
-    if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
-    if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
-    if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) {
-        mwWrite("internal: flushing flag damaged and recovered\n");
-        FLUSH();
-        return mwFlushing;
-        }
-    mwWrite("internal: flushing flag destroyed, so set to true\n");
-    mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
-    return 1;
-    }
-
-static void mwFlushW( int n ) {
-    mwFlushing = mwFlushingB1 = mwFlushingB2 = n;
-    }
-
-static void mwIncErr() {
-    mwErrors++;
-    mwFlushW( mwFlushR()+1 );
-    FLUSH();
-    }
-
-static void mwFlush() {
-    if( mwLogR() == NULL ) return;
-#ifdef MW_FLUSH
-    fflush( mwLogR() );
-#else
-    if( mwFlushR() ) fflush( mwLogR() );
-#endif
-    return;
-    }
-
-static void mwUnlink( mwData* mw, const char* file, int line ) {
-    if( mw->prev == NULL ) {
-        if( mwHead != mw )
-            mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n",
-                mwCounter, file, line, mw );
-        mwHead = mw->next;
-        }
-    else {
-        if( mw->prev->next != mw )
-            mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n",
-                mwCounter, file, line, mw );
-        else mw->prev->next = mw->next;
-        }
-    if( mw->next == NULL ) {
-        if( mwTail != mw )
-            mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n",
-                mwCounter, file, line, mw );
-        mwTail = mw->prev;
-        }
-    else {
-        if( mw->next->prev != mw )
-            mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n",
-                mwCounter, file, line, mw );
-        else mw->next->prev = mw->prev;
-        }
-    }
-
-/*
-** Relinking tries to repair a damaged mw block.
-** Returns nonzero if it thinks it successfully
-** repaired the heap chain.
-*/
-static int mwRelink( mwData* mw, const char* file, int line ) {
-    int fails;
-    mwData *mw1, *mw2;
-    long count, size;
-    mwStat *ms;
-
-	if( file == NULL ) file = "unknown";
-
-    if( mw == NULL ) {
-        mwWrite("relink: cannot repair MW at NULL\n");
-        FLUSH();
-        goto emergency;
-        }
-
-    if( !mwIsSafeAddr(mw, mwDataSize) ) {
-        mwWrite("relink: MW-%p is a garbage pointer\n", mw);
-        FLUSH();
-        goto emergency;
-        }
-
-    mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw );
-    FLUSH();
-    fails = 0;
-
-    /* Repair from head */
-    if( mwHead != mw ) {
-        if( !mwIsSafeAddr( mwHead, mwDataSize ) ) {
-            mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw );
-            FLUSH();
-            goto emergency;
-            }
-        for( mw1=mwHead; mw1; mw1=mw1->next ) {
-            if( mw1->next == mw ) {
-                mw->prev = mw1;
-                break;
-                }
-            if( mw1->next &&
-                ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) {
-                mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next );
-                FLUSH();
-                goto emergency;
-                }
-            }
-        if( mw1 == NULL ) {
-            mwWrite("relink: MW-%p not found in forward chain search\n", mw );
-            FLUSH();
-            fails ++;
-            }
-        }
-	else
-	{
-		mwWrite( "relink: MW-%p is the head (first) allocation\n", mw );
-		if( mw->prev != NULL )
-		{
-			mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
-			mw->prev = NULL;
-		}
-	}
-
-    /* Repair from tail */
-    if( mwTail != mw ) {
-        if( !mwIsSafeAddr( mwTail, mwDataSize ) ) {
-            mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw );
-            FLUSH();
-            goto emergency;
-            }
-        for( mw1=mwTail; mw1; mw1=mw1->prev ) {
-            if( mw1->prev == mw ) {
-                mw->next = mw1;
-                break;
-                }
-            if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) {
-                mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev );
-                FLUSH();
-                goto emergency;
-                }
-            }
-        if( mw1 == NULL ) {
-            mwWrite("relink: MW-%p not found in reverse chain search\n", mw );
-            FLUSH();
-            fails ++;
-            }
-        }
-	else
-	{
-		mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw );
-		if( mw->next != NULL )
-		{
-			mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
-			mw->next = NULL;
-		}
-	}
-
-    if( fails > 1 ) {
-        mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
-        FLUSH();
-        goto verifyok;
-        }
-
-    /* restore MW info where possible */
-    if( mwIsReadAddr( mw->file, 1 ) ) {
-        ms = mwStatGet( mw->file, -1, 0 );
-        if( ms == NULL ) mw->file = "<relinked>";
-        }
-    mw->check = CHKVAL(mw);
-    goto verifyok;
-
-    /* Emergency repair */
-    emergency:
-
-    if( mwHead == NULL && mwTail == NULL )
-    {
-        if( mwStatCurAlloc == 0 )
-            mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line );
-        else
-            mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line );
-        FLUSH();
-        return 0;
-    }
-
-    mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line );
-    FLUSH();
-
-	if( mwHead == NULL || mwTail == NULL )
-	{
-		if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail );
-		else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead );
-	}
-
-    mw1=NULL;
-    if( mwHead != NULL )
-	{
-		if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) )
-		{
-			mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
-			mwHead = NULL;
-			goto scan_reverse;
-		}
-		if( mwHead->prev != NULL )
-		{
-			mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev );
-		}
-        for( mw1=mwHead; mw1; mw1=mw1->next )
-		{
-			if( mw1->next )
-			{
-				if( !mwIsReadAddr(mw1->next,mwDataSize) ||
-					!mw1->next->check != CHKVAL(mw1) ||
-					mw1->next->prev != mw1 )
-				{
-					mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
-						mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line );
-					if( mwIsReadAddr(mw1->next,mwDataSize ) )
-					{
-						mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
-							mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"",
-							mwIsReadAddr(mw1->file,16)?mw1->file:"<garbage-pointer>", mw1->line );
-					}
-					else
-					{
-						mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n",
-							mw1->next );
-					}
-					break;
-				}
-			}
-        }
-	}
-
-
-scan_reverse:
-    mw2=NULL;
-    if( mwTail != NULL )
-	{
-		if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) )
-		{
-			mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
-			mwTail = NULL;
-			goto analyze;
-		}
-		if( mwTail->next != NULL )
-		{
-			mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next );
-		}
-        for( mw2=mwTail; mw2; mw2=mw2->prev )
-		{
-            if( mw2->prev )
-			{
-				if( !mwIsReadAddr(mw2->prev,mwDataSize) ||
-					!mw2->prev->check != CHKVAL(mw2) ||
-					mw2->prev->next != mw2 )
-				{
-					mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
-						mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line );
-					if( mwIsReadAddr(mw2->prev,mwDataSize ) )
-					{
-						mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
-							mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"",
-							mwIsReadAddr(mw2->file,16)?mw2->file:"<garbage-pointer>", mw2->line );
-					}
-					else
-					{
-						mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n",
-							mw2->prev );
-					}
-					break;
-				}
-			}
-        }
-	}
-
-analyze:
-	if( mwHead == NULL && mwTail == NULL )
-	{
-        mwWrite("relink: both head and tail pointers damaged, aborting program\n");
-        mwFlushW(1);
-        FLUSH();
-        abort();
-	}
-	if( mwHead == NULL )
-	{
-		mwHead = mw2;
-		mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
-		mw2->prev = NULL;
-		mw1 = mw2 = NULL;
-	}
-	if( mwTail == NULL )
-	{
-		mwTail = mw1;
-		mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
-		mw1->next = NULL;
-		mw1 = mw2 = NULL;
-	}
-    if( mw1 == NULL && mw2 == NULL &&
-        mwHead->prev == NULL && mwTail->next == NULL ) {
-        mwWrite("relink: verifying heap integrity...\n" );
-        FLUSH();
-        goto verifyok;
-        }
-    if( mw1 && mw2 && mw1 != mw2 ) {
-        mw1->next = mw2;
-        mw2->prev = mw1;
-        mwWrite("relink: emergency repairs successful, assessing damage...\n");
-        FLUSH();
-        }
-    else {
-        mwWrite("relink: heap totally destroyed, aborting program\n");
-        mwFlushW(1);
-        FLUSH();
-        abort();
-        }
-
-    /* Verify by checking that the number of active allocations */
-    /* match the number of entries in the chain */
-verifyok:
-    if( !mwIsHeapOK( NULL ) ) {
-        mwWrite("relink: heap verification FAILS - aborting program\n");
-        mwFlushW(1);
-        FLUSH();
-        abort();
-        }
-    for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) {
-        count ++;
-        size += (long) mw1->size;
-        }
-    if( count == mwNumCurAlloc ) {
-        mwWrite("relink: successful, ");
-        if( size == mwStatCurAlloc ) {
-            mwWrite("no allocations lost\n");
-            }
-        else {
-            if( mw != NULL ) {
-                mwWrite("size information lost for MW-%p\n", mw);
-                mw->size = 0;
-                }
-            }
-        }
-    else {
-        mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n",
-			mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size );
-        return 0;
-        }
-
-    return 1;
-    }
-
-/*
-**  If mwData* is NULL:
-**      Returns 0 if heap chain is broken.
-**      Returns 1 if heap chain is intact.
-**  If mwData* is not NULL:
-**      Returns 0 if mwData* is missing or if chain is broken.
-**      Returns 1 if chain is intact and mwData* is found.
-*/
-static int mwIsHeapOK( mwData *includes_mw ) {
-    int found = 0;
-    mwData *mw;
-
-    for( mw = mwHead; mw; mw=mw->next ) {
-        if( includes_mw == mw ) found++;
-        if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
-        if( mw->prev ) {
-            if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0;
-            if( mw==mwHead || mw->prev->next != mw ) return 0;
-            }
-        if( mw->next ) {
-            if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0;
-            if( mw==mwTail || mw->next->prev != mw ) return 0;
-            }
-        else if( mw!=mwTail ) return 0;
-        }
-
-    if( includes_mw != NULL && !found ) return 0;
-
-    return 1;
-    }
-
-static int mwIsOwned( mwData* mw, const char *file, int line ) {
-    int retv;
-    mwStat *ms;
-
-    /* see if the address is legal according to OS */
-    if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
-
-    /* make sure we have _anything_ allocated */
-    if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 )
-        return 0;
-
-    /* calculate checksum */
-    if( mw->check != CHKVAL(mw) ) {
-        /* may be damaged checksum, see if block is in heap */
-        if( mwIsHeapOK( mw ) ) {
-            /* damaged checksum, repair it */
-            mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n",
-                mwCounter, file, line, mw );
-            mwIncErr();
-            if( mwIsReadAddr( mw->file, 1 ) ) {
-                ms = mwStatGet( mw->file, -1, 0 );
-                if( ms == NULL ) mw->file = "<relinked>";
-                }
-            else mw->file = "<unknown>";
-            mw->size = 0;
-            mw->check = CHKVAL(mw);
-            return 1;
-            }
-        /* no, it's just some garbage data */
-        return 0;
-        }
-
-	/* check that the non-NULL pointers are safe */
-	if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line );
-	if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line );
-
-    /* safe address, checksum OK, proceed with heap checks */
-
-    /* see if the block is in the heap */
-    retv = 0;
-    if( mw->prev ) { if( mw->prev->next == mw ) retv ++; }
-    else { if( mwHead == mw ) retv++; }
-    if( mw->next ) { if( mw->next->prev == mw ) retv ++; }
-    else { if( mwTail == mw ) retv++; }
-    if( mw->check == CHKVAL(mw) ) retv ++;
-    if( retv > 2 ) return 1;
-
-    /* block not in heap, check heap for corruption */
-
-    if( !mwIsHeapOK( mw ) ) {
-        if( mwRelink( mw, file, line ) )
-            return 1;
-        }
-
-    /* unable to repair */
-    mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n",
-       mwCounter, file, line, mw );
-    mwIncErr();
-
-    return 0;
-    }
-
-/*
-** mwTestBuf:
-**  Checks a buffers links and pre/postfixes.
-**  Writes errors found to the log.
-**  Returns zero if no errors found.
-*/
-static int mwTestBuf( mwData* mw, const char* file, int line ) {
-    int retv = 0;
-    char *p;
-
-    if( file == NULL ) file = "unknown";
-
-    if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) {
-        mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n",
-            mwCounter, file, line, mw );
-        mwIncErr();
-        return 2;
-        }
-
-    if( mw->check != CHKVAL(mw) ) {
-        mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n",
-            mwCounter, file, line );
-        mwIncErr();
-        if( !mwRelink( mw, file, line ) ) return 2;
-        }
-
-    if( mw->prev && mw->prev->next != mw ) {
-        mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n",
-            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
-        mwIncErr();
-        if( !mwRelink( mw, file, line ) ) retv = 2;
-        }
-    if( mw->next && mw->next->prev != mw ) {
-        mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n",
-            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
-        mwIncErr();
-        if( !mwRelink( mw, file, line ) ) retv = 2;
-        }
-
-    p = ((char*)mw) + mwDataSize;
-    if( mwCheckOF( p ) ) {
-        mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
-            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
-        mwIncErr();
-        retv = 1;
-        }
-    p += mwOverflowZoneSize + mw->size;
-    if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) {
-        mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
-            mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
-        mwIncErr();
-        retv = 1;
-        }
-
-    return retv;
-    }
-
-static void mwDefaultOutFunc( int c ) {
-    if( mwLogR() ) fputc( c, mwLogR() );
-    }
-
-static void mwWrite( const char *format, ... ) {
-    int tot, oflow = 0;
-    va_list mark;
-    mwAutoInit();
-    if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
-    va_start( mark, format );
-    tot = vsprintf( mwPrintBuf, format, mark );
-    va_end( mark );
-    if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
-    for(tot=0;mwPrintBuf[tot];tot++)
-        (*mwOutFunction)( mwPrintBuf[tot] );
-    if( oflow ) {
-        mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 );
-        FLUSH();
-        }
-    return;
-    }
-
-static void mwLogFile( const char *name ) {
-    time_t tid;
-    (void) time( &tid );
-    if( mwLogR() != NULL ) {
-        fclose( mwLogR() );
-        mwLogW( NULL );
-        }
-    if( name == NULL ) return;
-    mwLogW( fopen( name, "a" COMMIT ) );
-    if( mwLogR() == NULL )
-        mwWrite( "logfile: failed to open/create file '%s'\n", name );
-    }
-
-/*
-** Try to free NML memory until a contiguous allocation of
-** 'needed' bytes can be satisfied. If this is not enough
-** and the 'urgent' parameter is nonzero, grabbed memory is
-** also freed.
-*/
-static size_t mwFreeUp( size_t needed, int urgent ) {
-    void *p;
-    mwData *mw, *mw2;
-    char *data;
-
-    /* free grabbed NML memory */
-    for(;;) {
-        if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break;
-        p = malloc( needed );
-        if( p == NULL ) continue;
-        free( p );
-        return needed;
-        }
-
-    /* free normal NML memory */
-    mw = mwHead;
-    while( mw != NULL ) {
-        if( !(mw->flag & MW_NML) ) mw = mw->next;
-        else {
-            data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
-            if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
-                mwIncErr();
-                mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
-                    mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
-                }
-            mw2 = mw->next;
-            mwUnlink( mw, "mwFreeUp", 0 );
-            free( mw );
-            mw = mw2;
-            p = malloc( needed );
-            if( p == NULL ) continue;
-            free( p );
-            return needed;
-            }
-        }
-
-    /* if not urgent (for internal purposes), fail */
-    if( !urgent ) return 0;
-
-    /* free grabbed memory */
-    for(;;) {
-        if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break;
-        p = malloc( needed );
-        if( p == NULL ) continue;
-        free( p );
-        return needed;
-        }
-
-    return 0;
-    }
-
-static const void * mwTestMem( const void *p, unsigned len, int c ) {
-    const unsigned char *ptr;
-    ptr = (const unsigned char *) p;
-    while( len-- ) {
-        if( *ptr != (unsigned char)c ) return (const void*)ptr;
-        ptr ++;
-        }
-    return NULL;
-    }
-
-static int mwStrCmpI( const char *s1, const char *s2 ) {
-    if( s1 == NULL || s2 == NULL ) return 0;
-    while( *s1 ) {
-        if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; }
-        return 1;
-        }
-    return 0;
-    }
-
-#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }
-
-static int mwTestNow( const char *file, int line, int always_invoked ) {
-    int retv = 0;
-    mwData *mw;
-    char *data;
-
-    if( file && !always_invoked )
-        mwWrite("check: <%ld> %s(%d), checking %s%s%s\n",
-            mwCounter, file, line,
-			(mwTestFlags & MW_TEST_CHAIN) ? "chain ": "",
-		    (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "",
-		    (mwTestFlags & MW_TEST_NML) ? "nomansland ": ""
-			);
-
-    if( mwTestFlags & MW_TEST_CHAIN ) {
-        for( mw = mwHead; mw; mw=mw->next ) {
-			if( !mwIsSafeAddr(mw, mwDataSize) ) {
-				AIPH();
-				mwWrite("check: heap corruption detected\n");
-				mwIncErr();
-				return retv + 1;
-				}
-			if( mw->prev ) {
-				if( !mwIsSafeAddr(mw->prev, mwDataSize) ) {
-					AIPH();
-					mwWrite("check: heap corruption detected\n");
-					mwIncErr();
-					return retv + 1;
-					}
-				if( mw==mwHead || mw->prev->next != mw ) {
-					AIPH();
-					mwWrite("check: heap chain broken, prev link incorrect\n");
-					mwIncErr();
-					retv ++;
-					}
-				}
-			if( mw->next ) {
-				if( !mwIsSafeAddr(mw->next, mwDataSize) ) {
-					AIPH();
-					mwWrite("check: heap corruption detected\n");
-					mwIncErr();
-					return retv + 1;
-					}
-				if( mw==mwTail || mw->next->prev != mw ) {
-					AIPH();
-					mwWrite("check: heap chain broken, next link incorrect\n");
-					mwIncErr();
-					retv ++;
-					}
-				}
-			else if( mw!=mwTail ) {
-				AIPH();
-				mwWrite("check: heap chain broken, tail incorrect\n");
-				mwIncErr();
-				retv ++;
-				}
-            }
-        }
-    if( mwTestFlags & MW_TEST_ALLOC ) {
-        for( mw = mwHead; mw; mw=mw->next ) {
-            if( mwTestBuf( mw, file, line ) ) retv ++;
-            }
-        }
-    if( mwTestFlags & MW_TEST_NML ) {
-        for( mw = mwHead; mw; mw=mw->next ) {
-            if( (mw->flag & MW_NML) ) {
-                data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
-                if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
-                    mwIncErr();
-                    mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
-                        mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
-                    }
-                }
-            }
-        }
-
-
-	if( file && !always_invoked && !retv )
-        mwWrite("check: <%ld> %s(%d), complete; no errors\n",
-            mwCounter, file, line );
-    return retv;
-    }
-
-/**********************************************************************
-** Statistics
-**********************************************************************/
-
-static void mwStatReport()
-{
-    mwStat* ms, *ms2;
-    const char *modname;
-    int modnamelen;
-
-    /* global statistics report */
-    mwWrite( "\nMemory usage statistics (global):\n" );
-    mwWrite( " N)amber of allocations made: %ld\n", mwStatNumAlloc );
-    mwWrite( " L)argest memory usage      : %ld\n", mwStatMaxAlloc );
-    mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
-    mwWrite( " U)nfreed bytes totals      : %ld\n", mwStatCurAlloc );
-    FLUSH();
-
-    if( mwStatLevel < 1 ) return;
-
-    /* on a per-module basis */
-    mwWrite( "\nMemory usage statistics (detailed):\n");
-    mwWrite( " Module/Line                                Number   Largest  Total    Unfreed \n");
-    for( ms=mwStatList; ms; ms=ms->next )
-    {
-        if( ms->line == -1 )
-        {
-			if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = "<unknown>";
-			else modname = ms->file;
-			modnamelen = strlen(modname);
-			if( modnamelen > 42 )
-			{
-				modname = modname + modnamelen - 42;
-			}
-
-            mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n",
-            	modname, ms->num, ms->max, ms->total, ms->curr );
-            if( ms->file && mwStatLevel > 1 )
-            {
-                for( ms2=mwStatList; ms2; ms2=ms2->next )
-                {
-                    if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) )
-					{
-					mwWrite( "  %-8d                                  %-8ld %-8ld %-8ld %-8ld\n",
-						ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr );
-					}
-				}
-			}
-		}
-	}
-}
-
-static mwStat* mwStatGet( const char *file, int line, int makenew ) {
-    mwStat* ms;
-
-    if( mwStatLevel < 2 ) line = -1;
-
-    for( ms=mwStatList; ms!=NULL; ms=ms->next ) {
-        if( line != ms->line ) continue;
-        if( file==NULL ) {
-            if( ms->file == NULL ) break;
-            continue;
-            }
-        if( ms->file == NULL ) continue;
-        if( !strcmp( ms->file, file ) ) break;
-        }
-
-    if( ms != NULL ) return ms;
-
-    if( !makenew ) return NULL;
-
-    ms = (mwStat*) malloc( sizeof(mwStat) );
-    if( ms == NULL ) {
-        if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) ||
-            (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) {
-            mwWrite("internal: memory low, statistics incomplete for '%s'\n", file );
-            return NULL;
-            }
-        }
-    ms->file = file;
-    ms->line = line;
-    ms->total = 0L;
-    ms->max = 0L;
-    ms->num = 0L;
-    ms->curr = 0L;
-    ms->next = mwStatList;
-    mwStatList = ms;
-    return ms;
-    }
-
-static void mwStatAlloc( size_t size, const char* file, int line ) {
-    mwStat* ms;
-
-    /* update the module statistics */
-    ms = mwStatGet( file, -1, 1 );
-    if( ms != NULL ) {
-        ms->total += (long) size;
-        ms->curr += (long) size;
-        ms->num ++;
-        if( ms->curr > ms->max ) ms->max = ms->curr;
-        }
-
-    /* update the line statistics */
-    if( mwStatLevel > 1 && line != -1 && file ) {
-        ms = mwStatGet( file, line, 1 );
-        if( ms != NULL ) {
-            ms->total += (long) size;
-            ms->curr += (long) size;
-            ms->num ++;
-            if( ms->curr > ms->max ) ms->max = ms->curr;
-            }
-        }
-
-    }
-
-static void mwStatFree( size_t size, const char* file, int line ) {
-    mwStat* ms;
-
-    /* update the module statistics */
-    ms = mwStatGet( file, -1, 1 );
-    if( ms != NULL ) ms->curr -= (long) size;
-
-    /* update the line statistics */
-    if( mwStatLevel > 1 && line != -1 && file ) {
-        ms = mwStatGet( file, line, 1 );
-        if( ms != NULL ) ms->curr -= (long) size;
-        }
-    }
-
-/***********************************************************************
-** Safe memory checkers
-**
-** Using ifdefs, implement the operating-system specific mechanism
-** of identifying a piece of memory as legal to access with read
-** and write priviliges. Default: return nonzero for non-NULL pointers.
-***********************************************************************/
-
-static char mwDummy( char c )
-{
-	return c;
-}
-
-#ifndef MW_SAFEADDR
-#ifdef WIN32
-#define MW_SAFEADDR
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-int mwIsReadAddr( const void *p, unsigned len )
-{
-    if( p == NULL ) return 0;
-    if( IsBadReadPtr(p,len) ) return 0;
-    return 1;
-}
-int mwIsSafeAddr( void *p, unsigned len )
-{
-    /* NOTE: For some reason, under Win95 the IsBad... */
-    /* can return false for invalid pointers. */
-    if( p == NULL ) return 0;
-    if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0;
-    return 1;
-}
-#endif /* WIN32 */
-#endif /* MW_SAFEADDR */
-
-#ifndef MW_SAFEADDR
-#ifdef SIGSEGV
-#define MW_SAFEADDR
-
-typedef void (*mwSignalHandlerPtr)( int );
-mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0;
-jmp_buf mwSIGSEGVjump;
-static void mwSIGSEGV( int n );
-
-static void mwSIGSEGV( int n )
-{
-	n = n;
-	longjmp( mwSIGSEGVjump, 1 );
-}
-
-int mwIsReadAddr( const void *p, unsigned len )
-{
-	const char *ptr;
-
-    if( p == NULL ) return 0;
-	if( !len ) return 1;
-
-	/* set up to catch the SIGSEGV signal */
-	mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
-
-	if( setjmp( mwSIGSEGVjump ) )
-	{
-		signal( SIGSEGV, mwOldSIGSEGV );
-		return 0;
-	}
-
-	/* read all the bytes in the range */
-	ptr = (const char *)p;
-	ptr += len;
-
-	/* the reason for this rather strange construct is that */
-	/* we want to keep the number of used parameters and locals */
-	/* to a minimum. if we use len for a counter gcc will complain */
-	/* it may get clobbered by longjmp() at high warning levels. */
-	/* it's a harmless warning, but this way we don't have to see it. */
-	do
-	{
-		ptr --;
-		if( *ptr == 0x7C ) (void) mwDummy( (char)0 );
-	} while( (const void*) ptr != p );
-
-	/* remove the handler */
-	signal( SIGSEGV, mwOldSIGSEGV );
-
-    return 1;
-}
-int mwIsSafeAddr( void *p, unsigned len )
-{
-	char *ptr;
-
-	if( p == NULL ) return 0;
-	if( !len ) return 1;
-
-	/* set up to catch the SIGSEGV signal */
-	mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
-
-	if( setjmp( mwSIGSEGVjump ) )
-	{
-		signal( SIGSEGV, mwOldSIGSEGV );
-		return 0;
-	}
-
-	/* read and write-back all the bytes in the range */
-	ptr = (char *)p;
-	ptr += len;
-
-	/* the reason for this rather strange construct is that */
-	/* we want to keep the number of used parameters and locals */
-	/* to a minimum. if we use len for a counter gcc will complain */
-	/* it may get clobbered by longjmp() at high warning levels. */
-	/* it's a harmless warning, but this way we don't have to see it. */
-	do
-	{
-		ptr --;
-		*ptr = mwDummy( *ptr );
-	} while( (void*) ptr != p );
-
-	/* remove the handler */
-	signal( SIGSEGV, mwOldSIGSEGV );
-
-    return 1;
-}
-#endif /* SIGSEGV */
-#endif /* MW_SAFEADDR */
-
-#ifndef MW_SAFEADDR
-int mwIsReadAddr( const void *p, unsigned len )
-{
-    if( p == NULL ) return 0;
-    if( len == 0 ) return 1;
-    return 1;
-}
-int mwIsSafeAddr( void *p, unsigned len )
-{
-    if( p == NULL ) return 0;
-    if( len == 0 ) return 1;
-    return 1;
-}
-#endif
-
-/**********************************************************************
-** Mutex handling
-**********************************************************************/
-
-#if defined(WIN32) || defined(__WIN32__)
-
-static void	mwMutexInit( void )
-{
-	mwGlobalMutex = CreateMutex( NULL, FALSE, NULL);
-	return;
-}
-
-static void	mwMutexTerm( void )
-{
-	CloseHandle( mwGlobalMutex );
-	return;
-}
-
-static void	mwMutexLock( void )
-{
-	if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
-	{
-		mwWrite( "mwMutexLock: timed out, possible deadlock\n" );
-	}
-	return;
-}
-
-static void	mwMutexUnlock( void )
-{
-	ReleaseMutex( mwGlobalMutex );
-	return;
-}
-
-#endif
-
-#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
-
-static void	mwMutexInit( void )
-{
-	pthread_mutex_init( &mwGlobalMutex, NULL );
-	return;
-}
-
-static void	mwMutexTerm( void )
-{
-	pthread_mutex_destroy( &mwGlobalMutex );
-	return;
-}
-
-static void	mwMutexLock( void )
-{
-	pthread_mutex_lock(&mwGlobalMutex);
-	return;
-}
-
-static void	mwMutexUnlock( void )
-{
-	pthread_mutex_unlock(&mwGlobalMutex);
-	return;
-}
-
-#endif
-
-/**********************************************************************
-** C++ new & delete
-**********************************************************************/
-
-#if 0 /* 980317: disabled C++ */
-
-#ifdef __cplusplus
-#ifndef MEMWATCH_NOCPP
-
-int mwNCur = 0;
-const char *mwNFile = NULL;
-int mwNLine = 0;
-
-class MemWatch {
-public:
-    MemWatch();
-    ~MemWatch();
-    };
-
-MemWatch::MemWatch() {
-    if( mwInited ) return;
-    mwUseAtexit = 0;
-    mwInit();
-    }
-
-MemWatch::~MemWatch() {
-    if( mwUseAtexit ) return;
-    mwTerm();
-    }
-
-/*
-** This global new will catch all 'new' calls where MEMWATCH is
-** not active.
-*/
-void* operator new( unsigned size ) {
-    mwNCur = 0;
-    return mwMalloc( size, "<unknown>", 0 );
-    }
-
-/*
-** This is the new operator that's called when a module uses mwNew.
-*/
-void* operator new( unsigned size, const char *file, int line ) {
-    mwNCur = 0;
-    return mwMalloc( size, file, line );
-    }
-
-/*
-** This is the new operator that's called when a module uses mwNew[].
-** -- hjc 07/16/02
-*/
-void* operator new[] ( unsigned size, const char *file, int line ) {
-    mwNCur = 0;
-    return mwMalloc( size, file, line );
-    }
-
-/*
-** Since this delete operator will recieve ALL delete's
-** even those from within libraries, we must accept
-** delete's before we've been initialized. Nor can we
-** reliably check for wild free's if the mwNCur variable
-** is not set.
-*/
-void operator delete( void *p ) {
-    if( p == NULL ) return;
-    if( !mwInited ) {
-        free( p );
-        return;
-        }
-    if( mwNCur ) {
-        mwFree( p, mwNFile, mwNLine );
-        mwNCur = 0;
-        return;
-        }
-    mwFree_( p );
-    }
-
-void operator delete[]( void *p ) {
-    if( p == NULL ) return;
-    if( !mwInited ) {
-        free( p );
-        return;
-        }
-    if( mwNCur ) {
-        mwFree( p, mwNFile, mwNLine );
-        mwNCur = 0;
-        return;
-        }
-    mwFree_( p );
-    }
-
-#endif /* MEMWATCH_NOCPP */
-#endif /* __cplusplus */
-
-#endif /* 980317: disabled C++ */
-
-/* MEMWATCH.C */
diff --git a/memwatch.h b/memwatch.h
deleted file mode 100644
index d63fd76..0000000
--- a/memwatch.h
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
-** MEMWATCH.H
-** Nonintrusive ANSI C memory leak / overwrite detection
-** Copyright (C) 1992-2002 Johan Lindh
-** All rights reserved.
-** Version 2.71
-**
-************************************************************************
-**
-** PURPOSE:
-**
-**  MEMWATCH has been written to allow guys and gals that like to
-**  program in C a public-domain memory error control product.
-**  I hope you'll find it's as advanced as most commercial packages.
-**  The idea is that you use it during the development phase and
-**  then remove the MEMWATCH define to produce your final product.
-**  MEMWATCH is distributed in source code form in order to allow
-**  you to compile it for your platform with your own compiler.
-**  It's aim is to be 100% ANSI C, but some compilers are more stingy
-**  than others. If it doesn't compile without warnings, please mail
-**  me the configuration of operating system and compiler you are using
-**  along with a description of how to modify the source, and the version
-**  number of MEMWATCH that you are using.
-**
-************************************************************************
-
-	This file is part of MEMWATCH.
-
-    MEMWATCH is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    MEMWATCH 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 General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with MEMWATCH; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-************************************************************************
-**
-** REVISION HISTORY:
-**
-** 920810 JLI   [1.00]
-** 920830 JLI   [1.10 double-free detection]
-** 920912 JLI   [1.15 mwPuts, mwGrab/Drop, mwLimit]
-** 921022 JLI   [1.20 ASSERT and VERIFY]
-** 921105 JLI   [1.30 C++ support and TRACE]
-** 921116 JLI   [1.40 mwSetOutFunc]
-** 930215 JLI   [1.50 modified ASSERT/VERIFY]
-** 930327 JLI   [1.51 better auto-init & PC-lint support]
-** 930506 JLI   [1.55 MemWatch class, improved C++ support]
-** 930507 JLI   [1.60 mwTest & CHECK()]
-** 930809 JLI   [1.65 Abort/Retry/Ignore]
-** 930820 JLI   [1.70 data dump when unfreed]
-** 931016 JLI   [1.72 modified C++ new/delete handling]
-** 931108 JLI   [1.77 mwSetAssertAction() & some small changes]
-** 940110 JLI   [1.80 no-mans-land alloc/checking]
-** 940328 JLI   [2.00 version 2.0 rewrite]
-**              Improved NML (no-mans-land) support.
-**              Improved performance (especially for free()ing!).
-**              Support for 'read-only' buffers (checksums)
-**              ^^ NOTE: I never did this... maybe I should?
-**              FBI (free'd block info) tagged before freed blocks
-**              Exporting of the mwCounter variable
-**              mwBreakOut() localizes debugger support
-**              Allocation statistics (global, per-module, per-line)
-**              Self-repair ability with relinking
-** 950913 JLI   [2.10 improved garbage handling]
-** 951201 JLI   [2.11 improved auto-free in emergencies]
-** 960125 JLI   [X.01 implemented auto-checking using mwAutoCheck()]
-** 960514 JLI   [2.12 undefining of existing macros]
-** 960515 JLI   [2.13 possibility to use default new() & delete()]
-** 960516 JLI   [2.20 suppression of file flushing on unfreed msgs]
-** 960516 JLI   [2.21 better support for using MEMWATCH with DLL's]
-** 960710 JLI   [X.02 multiple logs and mwFlushNow()]
-** 960801 JLI   [2.22 merged X.01 version with current]
-** 960805 JLI   [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
-** 960805 JLI   [2.31 merged X.02 version with current]
-** 961002 JLI   [2.32 support for realloc() + fixed STDERR bug]
-** 961222 JLI   [2.40 added mwMark() & mwUnmark()]
-** 970101 JLI   [2.41 added over/underflow checking after failed ASSERT/VERIFY]
-** 970113 JLI   [2.42 added support for PC-Lint 7.00g]
-** 970207 JLI   [2.43 added support for strdup()]
-** 970209 JLI   [2.44 changed default filename to lowercase]
-** 970405 JLI   [2.45 fixed bug related with atexit() and some C++ compilers]
-** 970723 JLI   [2.46 added MW_ARI_NULLREAD flag]
-** 970813 JLI   [2.47 stabilized marker handling]
-** 980317 JLI   [2.48 ripped out C++ support; wasn't working good anyway]
-** 980318 JLI   [2.50 improved self-repair facilities & SIGSEGV support]
-** 980417 JLI	[2.51 more checks for invalid addresses]
-** 980512 JLI	[2.52 moved MW_ARI_NULLREAD to occur before aborting]
-** 990112 JLI	[2.53 added check for empty heap to mwIsOwned]
-** 990217 JLI	[2.55 improved the emergency repairs diagnostics and NML]
-** 990224 JLI	[2.56 changed ordering of members in structures]
-** 990303 JLI	[2.57 first maybe-fixit-for-hpux test]
-** 990516 JLI	[2.58 added 'static' to the definition of mwAutoInit]
-** 990517 JLI	[2.59 fixed some high-sensitivity warnings]
-** 990610 JLI	[2.60 fixed some more high-sensitivity warnings]
-** 990715 JLI	[2.61 changed TRACE/ASSERT/VERIFY macro names]
-** 991001 JLI	[2.62 added CHECK_BUFFER() and mwTestBuffer()]
-** 991007 JLI	[2.63 first shot at a 64-bit compatible version]
-** 991009 JLI	[2.64 undef's strdup() if defined, mwStrdup made const]
-** 000704 JLI	[2.65 added some more detection for 64-bits]
-** 010502 JLI   [2.66 incorporated some user fixes]
-**              [mwRelink() could print out garbage pointer (thanks mac at phobos.ca)]
-**				[added array destructor for C++ (thanks rdasilva at connecttel.com)]
-**				[added mutex support (thanks rdasilva at connecttel.com)]
-** 010531 JLI	[2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
-** 010619 JLI	[2.68 fix: mwRealloc() could leave the mutex locked]
-** 020918 JLI	[2.69 changed to GPL, added C++ array allocation by Howard Cohen]
-** 030212 JLI	[2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
-** 030520 JLI	[2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
-**
-** To use, simply include 'MEMWATCH.H' as a header file,
-** and add MEMWATCH.C to your list of files, and define the macro
-** 'MEMWATCH'. If this is not defined, MEMWATCH will disable itself.
-**
-** To call the standard C malloc / realloc / calloc / free; use mwMalloc_(),
-** mwCalloc_() and mwFree_(). Note that mwFree_() will correctly
-** free both malloc()'d memory as well as mwMalloc()'d.
-**
-** 980317: C++ support has been disabled.
-**         The code remains, but is not compiled.
-**
-**         For use with C++, which allows use of inlining in header files
-**         and class specific new/delete, you must also define 'new' as
-**         'mwNew' and 'delete' as 'mwDelete'. Do this *after* you include
-**         C++ header files from libraries, otherwise you can mess up their
-**         class definitions. If you don't define these, the C++ allocations
-**         will not have source file and line number information. Also note,
-**         most C++ class libraries implement their own C++ memory management,
-**         and don't allow anyone to override them. MFC belongs to this crew.
-**         In these cases, the only thing to do is to use MEMWATCH_NOCPP.
-**
-** You can capture output from MEMWATCH using mwSetOutFunc().
-** Just give it the adress of a "void myOutFunc(int c)" function,
-** and all characters to be output will be redirected there.
-**
-** A failing ASSERT() or VERIFY() will normally always abort your
-** program. This can be changed using mwSetAriFunc(). Give it a
-** pointer to a "int myAriFunc(const char *)" function. Your function
-** must ask the user whether to Abort, Retry or Ignore the trap.
-** Return 2 to Abort, 1 to Retry or 0 to Ignore. Beware retry; it
-** causes the expression to be evaluated again! MEMWATCH has a
-** default ARI handler. It's disabled by default, but you can enable
-** it by calling 'mwDefaultAri()'. Note that this will STILL abort
-** your program unless you define MEMWATCH_STDIO to allow MEMWATCH
-** to use the standard C I/O streams. Also, setting the ARI function
-** will cause MEMWATCH *NOT* to write the ARI error to stderr. The
-** error string is passed to the ARI function instead, as the
-** 'const char *' parameter.
-**
-** You can disable MEMWATCH's ASSERT/VERIFY and/or TRACE implementations.
-** This can be useful if you're using a debug terminal or smart debugger.
-** Disable them by defining MW_NOASSERT, MW_NOVERIFY or MW_NOTRACE.
-**
-** MEMWATCH fills all allocated memory with the byte 0xFE, so if
-** you're looking at erroneous data which are all 0xFE:s, the
-** data probably was not initialized by you. The exception is
-** calloc(), which will fill with zero's. All freed buffers are
-** zapped with 0xFD. If this is what you look at, you're using
-** data that has been freed. If this is the case, be aware that
-** MEMWATCH places a 'free'd block info' structure immediately
-** before the freed data. This block contains info about where
-** the block was freed. The information is in readable text,
-** in the format "FBI<counter>filename(line)", for example:
-** "FBI<267>test.c(12)". Using FBI's slows down free(), so it's
-** disabled by default. Use mwFreeBufferInfo(1) to enable it.
-**
-** To aid in tracking down wild pointer writes, MEMWATCH can perform
-** no-mans-land allocations. No-mans-land will contain the byte 0xFC.
-** MEMWATCH will, when this is enabled, convert recently free'd memory
-** into NML allocations.
-**
-** MEMWATCH protects it's own data buffers with checksums. If you
-** get an internal error, it means you're overwriting wildly,
-** or using an uninitialized pointer.
-**
-************************************************************************
-**
-** Note when compiling with Microsoft C:
-**  -   MSC ignores fflush() by default. This is overridden, so that
-**      the disk log will always be current.
-**
-** This utility has been tested with:
-**  PC-lint 7.0k, passed as 100% ANSI C compatible
-**  Microsoft Visual C++ on Win16 and Win32
-**  Microsoft C on DOS
-**  SAS C on an Amiga 500
-**  Gnu C on a PC running Red Hat Linux
-**  ...and using an (to me) unknown compiler on an Atari machine.
-**
-************************************************************************
-**
-** Format of error messages in MEMWATCH.LOG:
-**  message: <sequence-number> filename(linenumber), information
-**
-** Errors caught by MemWatch, when they are detected, and any
-** actions taken besides writing to the log file MEMWATCH.LOG:
-**
-**  Double-freeing:
-**      A pointer that was recently freed and has not since been
-**      reused was freed again. The place where the previous free()
-**      was executed is displayed.
-**      Detect: delete or free() using the offending pointer.
-**      Action: The delete or free() is cancelled, execution continues.
-**  Underflow:
-**      You have written just ahead of the allocated memory.
-**      The size and place of the allocation is displayed.
-**      Detect: delete or free() of the damaged buffer.
-**      Action: The buffer is freed, but there may be secondary damage.
-**  Overflow:
-**      Like underflow, but you've written after the end of the buffer.
-**      Detect: see Underflow.
-**      Action: see Underflow.
-**  WILD free:
-**      An unrecognized pointer was passed to delete or free().
-**      The pointer may have been returned from a library function;
-**      in that case, use mwFree_() to force free() of it.
-**      Also, this may be a double-free, but the previous free was
-**      too long ago, causing MEMWATCH to 'forget' it.
-**      Detect: delete or free() of the offending pointer.
-**      Action: The delete or free() is cancelled, execution continues.
-**  NULL free:
-**      It's unclear to me whether or not freeing of NULL pointers
-**      is legal in ANSI C, therefore a warning is written to the log file,
-**      but the error counter remains the same. This is legal using C++,
-**      so the warning does not appear with delete.
-**      Detect: When you free(NULL).
-**      Action: The free() is cancelled.
-**  Failed:
-**      A request to allocate memory failed. If the allocation is
-**      small, this may be due to memory depletion, but is more likely
-**      to be memory fragmentation problems. The amount of memory
-**      allocated so far is displayed also.
-**      Detect: When you new, malloc(), realloc() or calloc() memory.
-**      Action: NULL is returned.
-**  Realloc:
-**      A request to re-allocate a memory buffer failed for reasons
-**      other than out-of-memory. The specific reason is shown.
-**      Detect: When you realloc()
-**      Action: realloc() is cancelled, NULL is returned
-**  Limit fail:
-**      A request to allocate memory failed since it would violate
-**      the limit set using mwLimit(). mwLimit() is used to stress-test
-**      your code under simulated low memory conditions.
-**      Detect: At new, malloc(), realloc() or calloc().
-**      Action: NULL is returned.
-**  Assert trap:
-**      An ASSERT() failed. The ASSERT() macro works like C's assert()
-**      macro/function, except that it's interactive. See your C manual.
-**      Detect: On the ASSERT().
-**      Action: Program ends with an advisory message to stderr, OR
-**              Program writes the ASSERT to the log and continues, OR
-**              Program asks Abort/Retry/Ignore? and takes that action.
-**  Verify trap:
-**      A VERIFY() failed. The VERIFY() macro works like ASSERT(),
-**      but if MEMWATCH is not defined, it still evaluates the
-**      expression, but it does not act upon the result.
-**      Detect: On the VERIFY().
-**      Action: Program ends with an advisory message to stderr, OR
-**              Program writes the VERIFY to the log and continues, OR
-**              Program asks Abort/Retry/Ignore? and takes that action.
-**  Wild pointer:
-**      A no-mans-land buffer has been written into. MEMWATCH can
-**      allocate and distribute chunks of memory solely for the
-**      purpose of trying to catch random writes into memory.
-**      Detect: Always on CHECK(), but can be detected in several places.
-**      Action: The error is logged, and if an ARI handler is installed,
-**              it is executed, otherwise, execution continues.
-**  Unfreed:
-**      A memory buffer you allocated has not been freed.
-**      You are informed where it was allocated, and whether any
-**      over or underflow has occured. MemWatch also displays up to
-**      16 bytes of the data, as much as it can, in hex and text.
-**      Detect: When MemWatch terminates.
-**      Action: The buffer is freed.
-**  Check:
-**      An error was detected during a CHECK() operation.
-**      The associated pointer is displayed along with
-**      the file and line where the CHECK() was executed.
-**      Followed immediately by a normal error message.
-**      Detect: When you CHECK()
-**      Action: Depends on the error
-**  Relink:
-**      After a MEMWATCH internal control block has been trashed,
-**      MEMWATCH tries to repair the damage. If successful, program
-**      execution will continue instead of aborting. Some information
-**      about the block may be gone permanently, though.
-**      Detect: N/A
-**      Action: Relink successful: program continues.
-**              Relink fails: program aborts.
-**  Internal:
-**      An internal error is flagged by MEMWATCH when it's control
-**      structures have been damaged. You are likely using an uninitialized
-**      pointer somewhere in your program, or are zapping memory all over.
-**      The message may give you additional diagnostic information.
-**      If possible, MEMWATCH will recover and continue execution.
-**      Detect: Various actions.
-**      Action: Whatever is needed
-**  Mark:
-**      The program terminated without umarking all marked pointers. Marking
-**      can be used to track resources other than memory. mwMark(pointer,text,...)
-**      when the resource is allocated, and mwUnmark(pointer) when it's freed.
-**      The 'text' is displayed for still marked pointers when the program
-**      ends.
-**      Detect: When MemWatch terminates.
-**      Action: The error is logged.
-**
-**
-************************************************************************
-**
-**  The author may be reached by e-mail at the address below. If you
-**  mail me about source code changes in MEMWATCH, remember to include
-**  MW's version number.
-**
-**      Johan Lindh
-**      johan at linkdata.se
-**
-** The latest version of MEMWATCH may be downloaded from
-** http://www.linkdata.se/
-*/
-
-#ifndef __MEMWATCH_H
-#define __MEMWATCH_H
-
-/* Make sure that malloc(), realloc(), calloc() and free() are declared. */
-/*lint -save -e537 */
-#include <stdlib.h>
-/*lint -restore */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
-** Constants used
-**  All MEMWATCH constants start with the prefix MW_, followed by
-**  a short mnemonic which indicates where the constant is used,
-**  followed by a descriptive text about it.
-*/
-
-#define MW_ARI_NULLREAD 0x10    /* Null read (to start debugger) */
-#define MW_ARI_ABORT    0x04    /* ARI handler says: abort program! */
-#define MW_ARI_RETRY    0x02    /* ARI handler says: retry action! */
-#define MW_ARI_IGNORE   0x01    /* ARI handler says: ignore error! */
-
-#define MW_VAL_NEW      0xFE    /* value in newly allocated memory */
-#define MW_VAL_DEL      0xFD    /* value in newly deleted memory */
-#define MW_VAL_NML      0xFC    /* value in no-mans-land */
-#define MW_VAL_GRB      0xFB    /* value in grabbed memory */
-
-#define MW_TEST_ALL     0xFFFF  /* perform all tests */
-#define MW_TEST_CHAIN   0x0001  /* walk the heap chain */
-#define MW_TEST_ALLOC   0x0002  /* test allocations & NML guards */
-#define MW_TEST_NML     0x0004  /* test all-NML areas for modifications */
-
-#define MW_NML_NONE     0       /* no NML */
-#define MW_NML_FREE     1       /* turn FREE'd memory into NML */
-#define MW_NML_ALL      2       /* all unused memory is NML */
-#define MW_NML_DEFAULT  0       /* the default NML setting */
-
-#define MW_STAT_GLOBAL  0       /* only global statistics collected */
-#define MW_STAT_MODULE  1       /* collect statistics on a module basis */
-#define MW_STAT_LINE    2       /* collect statistics on a line basis */
-#define MW_STAT_DEFAULT 0       /* the default statistics setting */
-
-/*
-** MemWatch internal constants
-**  You may change these and recompile MemWatch to change the limits
-**  of some parameters. Respect the recommended minimums!
-*/
-#define MW_TRACE_BUFFER 2048    /* (min 160) size of TRACE()'s output buffer */
-#define MW_FREE_LIST    64      /* (min 4) number of free()'s to track */
-
-/*
-** Exported variables
-**  In case you have to remove the 'const' keyword because your compiler
-**  doesn't support it, be aware that changing the values may cause
-**  unpredictable behaviour.
-**  - mwCounter contains the current action count. You can use this to
-**      place breakpoints using a debugger, if you want.
-*/
-#ifndef __MEMWATCH_C
-extern const unsigned long mwCounter;
-#endif
-
-/*
-** System functions
-**  Normally, it is not nessecary to call any of these. MEMWATCH will
-**  automatically initialize itself on the first MEMWATCH function call,
-**  and set up a call to mwAbort() using atexit(). Some C++ implementations
-**  run the atexit() chain before the program has terminated, so you
-**  may have to use mwInit() or the MemWatch C++ class to get good
-**  behaviour.
-**  - mwInit() can be called to disable the atexit() usage. If mwInit()
-**      is called directly, you must call mwTerm() to end MemWatch, or
-**      mwAbort().
-**  - mwTerm() is usually not nessecary to call; but if called, it will
-**      call mwAbort() if it finds that it is cancelling the 'topmost'
-**      mwInit() call.
-**  - mwAbort() cleans up after MEMWATCH, reports unfreed buffers, etc.
-*/
-void  mwInit( void );
-void  mwTerm( void );
-void  mwAbort( void );
-
-/*
-** Setup functions
-**  These functions control the operation of MEMWATCH's protective features.
-**  - mwFlushNow() causes MEMWATCH to flush it's buffers.
-**  - mwDoFlush() controls whether MEMWATCH flushes the disk buffers after
-**      writes. The default is smart flushing: MEMWATCH will not flush buffers
-**      explicitly until memory errors are detected. Then, all writes are
-**      flushed until program end or mwDoFlush(0) is called.
-**  - mwLimit() sets the allocation limit, an arbitrary limit on how much
-**      memory your program may allocate in bytes. Used to stress-test app.
-**      Also, in virtual-memory or multitasking environs, puts a limit on
-**      how much MW_NML_ALL can eat up.
-**  - mwGrab() grabs up X kilobytes of memory. Allocates actual memory,
-**      can be used to stress test app & OS both.
-**  - mwDrop() drops X kilobytes of grabbed memory.
-**  - mwNoMansLand() sets the behaviour of the NML logic. See the
-**      MW_NML_xxx for more information. The default is MW_NML_DEFAULT.
-**  - mwStatistics() sets the behaviour of the statistics collector. See
-**      the MW_STAT_xxx defines for more information. Default MW_STAT_DEFAULT.
-**  - mwFreeBufferInfo() enables or disables the tagging of free'd buffers
-**      with freeing information. This information is written in text form,
-**      using sprintf(), so it's pretty slow. Disabled by default.
-**  - mwAutoCheck() performs a CHECK() operation whenever a MemWatch function
-**      is used. Slows down performance, of course.
-**  - mwCalcCheck() calculates checksums for all data buffers. Slow!
-**  - mwDumpCheck() logs buffers where stored & calc'd checksums differ. Slow!!
-**  - mwMark() sets a generic marker. Returns the pointer given.
-**  - mwUnmark() removes a generic marker. If, at the end of execution, some
-**      markers are still in existence, these will be reported as leakage.
-**      returns the pointer given.
-*/
-void        mwFlushNow( void );
-void        mwDoFlush( int onoff );
-void        mwLimit( long bytes );
-unsigned    mwGrab( unsigned kilobytes );
-unsigned    mwDrop( unsigned kilobytes );
-void        mwNoMansLand( int mw_nml_level );
-void        mwStatistics( int level );
-void        mwFreeBufferInfo( int onoff );
-void        mwAutoCheck( int onoff );
-void        mwCalcCheck( void );
-void        mwDumpCheck( void );
-void *      mwMark( void *p, const char *description, const char *file, unsigned line );
-void *      mwUnmark( void *p, const char *file, unsigned line );
-
-/*
-** Testing/verification/tracing
-**  All of these macros except VERIFY() evaluates to a null statement
-**  if MEMWATCH is not defined during compilation.
-**  - mwIsReadAddr() checks a memory area for read privilige.
-**  - mwIsSafeAddr() checks a memory area for both read & write privilige.
-**      This function and mwIsReadAddr() is highly system-specific and
-**      may not be implemented. If this is the case, they will default
-**      to returning nonzero for any non-NULL pointer.
-**  - CHECK() does a complete memory integrity test. Slow!
-**  - CHECK_THIS() checks only selected components.
-**  - CHECK_BUFFER() checks the indicated buffer for errors.
-**  - mwASSERT() or ASSERT() If the expression evaluates to nonzero, execution continues.
-**      Otherwise, the ARI handler is called, if present. If not present,
-**      the default ARI action is taken (set with mwSetAriAction()).
-**      ASSERT() can be disabled by defining MW_NOASSERT.
-**  - mwVERIFY() or VERIFY() works just like ASSERT(), but when compiling without
-**      MEMWATCH the macro evaluates to the expression.
-**      VERIFY() can be disabled by defining MW_NOVERIFY.
-**  - mwTRACE() or TRACE() writes some text and data to the log. Use like printf().
-**      TRACE() can be disabled by defining MW_NOTRACE.
-*/
-int   mwIsReadAddr( const void *p, unsigned len );
-int   mwIsSafeAddr( void *p, unsigned len );
-int   mwTest( const char *file, int line, int mw_test_flags );
-int   mwTestBuffer( const char *file, int line, void *p );
-int   mwAssert( int, const char*, const char*, int );
-int   mwVerify( int, const char*, const char*, int );
-
-/*
-** User I/O functions
-**  - mwTrace() works like printf(), but dumps output either to the
-**      function specified with mwSetOutFunc(), or the log file.
-**  - mwPuts() works like puts(), dumps output like mwTrace().
-**  - mwSetOutFunc() allows you to give the adress of a function
-**      where all user output will go. (exeption: see mwSetAriFunc)
-**      Specifying NULL will direct output to the log file.
-**  - mwSetAriFunc() gives MEMWATCH the adress of a function to call
-**      when an 'Abort, Retry, Ignore' question is called for. The
-**      actual error message is NOT printed when you've set this adress,
-**      but instead it is passed as an argument. If you call with NULL
-**      for an argument, the ARI handler is disabled again. When the
-**      handler is disabled, MEMWATCH will automatically take the
-**      action specified by mwSetAriAction().
-**  - mwSetAriAction() sets the default ARI return value MEMWATCH should
-**      use if no ARI handler is specified. Defaults to MW_ARI_ABORT.
-**  - mwAriHandler() is an ANSI ARI handler you can use if you like. It
-**      dumps output to stderr, and expects input from stdin.
-**  - mwBreakOut() is called in certain cases when MEMWATCH feels it would
-**      be nice to break into a debugger. If you feel like MEMWATCH, place
-**      an execution breakpoint on this function.
-*/
-void  mwTrace( const char* format_string, ... );
-void  mwPuts( const char* text );
-void  mwSetOutFunc( void (*func)(int) );
-void  mwSetAriFunc( int (*func)(const char*) );
-void  mwSetAriAction( int mw_ari_value );
-int   mwAriHandler( const char* cause );
-void  mwBreakOut( const char* cause );
-
-/*
-** Allocation/deallocation functions
-**  These functions are the ones actually to perform allocations
-**  when running MEMWATCH, for both C and C++ calls.
-**  - mwMalloc() debugging allocator
-**  - mwMalloc_() always resolves to a clean call of malloc()
-**  - mwRealloc() debugging re-allocator
-**  - mwRealloc_() always resolves to a clean call of realloc()
-**  - mwCalloc() debugging allocator, fills with zeros
-**  - mwCalloc_() always resolves to a clean call of calloc()
-**  - mwFree() debugging free. Can only free memory which has
-**      been allocated by MEMWATCH.
-**  - mwFree_() resolves to a) normal free() or b) debugging free.
-**      Can free memory allocated by MEMWATCH and malloc() both.
-**      Does not generate any runtime errors.
-*/
-void* mwMalloc( size_t, const char*, int );
-void* mwMalloc_( size_t );
-void* mwRealloc( void *, size_t, const char*, int );
-void* mwRealloc_( void *, size_t );
-void* mwCalloc( size_t, size_t, const char*, int );
-void* mwCalloc_( size_t, size_t );
-void  mwFree( void*, const char*, int );
-void  mwFree_( void* );
-char* mwStrdup( const char *, const char*, int );
-
-/*
-** Enable/disable precompiler block
-**  This block of defines and if(n)defs make sure that references
-**  to MEMWATCH is completely removed from the code if the MEMWATCH
-**  manifest constant is not defined.
-*/
-#ifndef __MEMWATCH_C
-#ifdef MEMWATCH
-
-#define mwASSERT(exp)   while(mwAssert((int)(exp),#exp,__FILE__,__LINE__))
-#ifndef MW_NOASSERT
-#ifndef ASSERT
-#define ASSERT          mwASSERT
-#endif /* !ASSERT */
-#endif /* !MW_NOASSERT */
-#define mwVERIFY(exp)   while(mwVerify((int)(exp),#exp,__FILE__,__LINE__))
-#ifndef MW_NOVERIFY
-#ifndef VERIFY
-#define VERIFY          mwVERIFY
-#endif /* !VERIFY */
-#endif /* !MW_NOVERIFY */
-#define mwTRACE         mwTrace
-#ifndef MW_NOTRACE
-#ifndef TRACE
-#define TRACE           mwTRACE
-#endif /* !TRACE */
-#endif /* !MW_NOTRACE */
-
-/* some compilers use a define and not a function */
-/* for strdup(). */
-#ifdef strdup
-#undef strdup
-#endif
-
-#define malloc(n)       mwMalloc(n,__FILE__,__LINE__)
-#define strdup(p)       mwStrdup(p,__FILE__,__LINE__)
-#define realloc(p,n)    mwRealloc(p,n,__FILE__,__LINE__)
-#define calloc(n,m)     mwCalloc(n,m,__FILE__,__LINE__)
-#define free(p)         mwFree(p,__FILE__,__LINE__)
-#define CHECK()         mwTest(__FILE__,__LINE__,MW_TEST_ALL)
-#define CHECK_THIS(n)   mwTest(__FILE__,__LINE__,n)
-#define CHECK_BUFFER(b) mwTestBuffer(__FILE__,__LINE__,b)
-#define MARK(p)         mwMark(p,#p,__FILE__,__LINE__)
-#define UNMARK(p)       mwUnmark(p,__FILE__,__LINE__)
-
-#else /* MEMWATCH */
-
-#define mwASSERT(exp)
-#ifndef MW_NOASSERT
-#ifndef ASSERT
-#define ASSERT          mwASSERT
-#endif /* !ASSERT */
-#endif /* !MW_NOASSERT */
-
-#define mwVERIFY(exp)    exp
-#ifndef MW_NOVERIFY
-#ifndef VERIFY
-#define VERIFY          mwVERIFY
-#endif /* !VERIFY */
-#endif /* !MW_NOVERIFY */
-
-/*lint -esym(773,mwTRACE) */
-#define mwTRACE         /*lint -save -e506 */ 1?(void)0:mwDummyTraceFunction /*lint -restore */
-#ifndef MW_NOTRACE
-#ifndef TRACE
-/*lint -esym(773,TRACE) */
-#define TRACE           mwTRACE
-#endif /* !TRACE */
-#endif /* !MW_NOTRACE */
-
-extern void mwDummyTraceFunction(const char *,...);
-/*lint -save -e652 */
-#define mwDoFlush(n)
-#define mwPuts(s)
-#define mwInit()
-#define mwGrab(n)
-#define mwDrop(n)
-#define mwLimit(n)
-#define mwTest(f,l)
-#define mwSetOutFunc(f)
-#define mwSetAriFunc(f)
-#define mwDefaultAri()
-#define mwNomansland()
-#define mwStatistics(f)
-#define mwMark(p,t,f,n)     (p)
-#define mwUnmark(p,f,n)     (p)
-#define mwMalloc(n,f,l)     malloc(n)
-#define mwStrdup(p,f,l)     strdup(p)
-#define mwRealloc(p,n,f,l)  realloc(p,n)
-#define mwCalloc(n,m,f,l)   calloc(n,m)
-#define mwFree(p)           free(p)
-#define mwMalloc_(n)        malloc(n)
-#define mwRealloc_(p,n)     realloc(p,n)
-#define mwCalloc_(n,m)      calloc(n,m)
-#define mwFree_(p)          free(p)
-#define mwAssert(e,es,f,l)
-#define mwVerify(e,es,f,l)  (e)
-#define mwTrace             mwDummyTrace
-#define mwTestBuffer(f,l,b) (0)
-#define CHECK()
-#define CHECK_THIS(n)
-#define CHECK_BUFFER(b)
-#define MARK(p)             (p)
-#define UNMARK(p)           (p)
-/*lint -restore */
-
-#endif /* MEMWATCH */
-#endif /* !__MEMWATCH_C */
-
-#ifdef __cplusplus
-    }
-#endif
-
-#if 0 /* 980317: disabled C++ */
-
-/*
-** C++ support section
-**  Implements the C++ support. Please note that in order to avoid
-**  messing up library classes, C++ support is disabled by default.
-**  You must NOT enable it until AFTER the inclusion of all header
-**  files belonging to code that are not compiled with MEMWATCH, and
-**  possibly for some that are! The reason for this is that a C++
-**  class may implement it's own new() function, and the preprocessor
-**  would substitute this crucial declaration for MEMWATCH new().
-**  You can forcibly deny C++ support by defining MEMWATCH_NOCPP.
-**  To enble C++ support, you must be compiling C++, MEMWATCH must
-**  be defined, MEMWATCH_NOCPP must not be defined, and finally,
-**  you must define 'new' to be 'mwNew', and 'delete' to be 'mwDelete'.
-**  Unlike C, C++ code can begin executing *way* before main(), for
-**  example if a global variable is created. For this reason, you can
-**  declare a global variable of the class 'MemWatch'. If this is
-**  is the first variable created, it will then check ALL C++ allocations
-**  and deallocations. Unfortunately, this evaluation order is not
-**  guaranteed by C++, though the compilers I've tried evaluates them
-**  in the order encountered.
-*/
-#ifdef __cplusplus
-#ifndef __MEMWATCH_C
-#ifdef MEMWATCH
-#ifndef MEMWATCH_NOCPP
-extern int mwNCur;
-extern const char *mwNFile;
-extern int mwNLine;
-class MemWatch {
-public:
-    MemWatch();
-    ~MemWatch();
-    };
-void * operator new(size_t);
-void * operator new(size_t,const char *,int);
-void * operator new[] (size_t,const char *,int);	// hjc 07/16/02
-void operator delete(void *);
-#define mwNew new(__FILE__,__LINE__)
-#define mwDelete (mwNCur=1,mwNFile=__FILE__,mwNLine=__LINE__),delete
-#endif /* MEMWATCH_NOCPP */
-#endif /* MEMWATCH */
-#endif /* !__MEMWATCH_C */
-#endif /* __cplusplus */
-
-#endif /* 980317: disabled C++ */
-
-#endif /* __MEMWATCH_H */
-
-/* EOF MEMWATCH.H */
diff --git a/modules.h b/modules.h
index 7829704..85ac380 100644
--- a/modules.h
+++ b/modules.h
@@ -9,7 +9,7 @@
 //  Module:         Central application error code managment
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -30,7 +30,9 @@
 #define __MODULES_H__
 
 #define CREATE_MODULE_IDS(ModulName, x) \
-   const int ERROR_BASE_ ## ModulName = ERROR_BASE_GUYMAGER_MAIN +  x * ID_OFFSET_SUBSUBPROJECT;
+   /*lint -save -e835 -e845*/           \
+   const unsigned int ERROR_BASE_ ## ModulName = ERROR_BASE_GUYMAGER_MAIN +  x * ID_OFFSET_SUBSUBPROJECT; \
+   /*lint -restore*/
 
 
 CREATE_MODULE_IDS (MAIN           ,  0)
@@ -68,8 +70,8 @@ CREATE_MODULE_IDS (QT             , 99)
 
 enum
 {
-   ERROR_QT_UNSUCCESSFUL = ERROR_BASE_QT + 1
-};
+   ERROR_QT_UNSUCCESSFUL = (ERROR_BASE_QT + 1)
+}; //lint !e30
 
 
 #endif
diff --git a/package.sh b/package.sh
deleted file mode 100755
index 48b5d1e..0000000
--- a/package.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-#
-# package.sh - automated packaging in Guy's developer environment.
-#
-# You may use a command like
-#   dpkg-buildpackage -B -uc -rfakeroot
-# or similar instead
-
-if [ -e ../../scripts/package.sh ]; then
-   ../../scripts/package.sh guymager-beta
-else
-   ../../../scripts/package.sh guymager-beta # when called from the branches or tags directories
-fi
-
-./compileinfo.sh | grep Version | awk -F\" ' { print "Version "$2 } '
-
diff --git a/qtutil.cpp b/qtutil.cpp
index 2545ac8..56fdef6 100644
--- a/qtutil.cpp
+++ b/qtutil.cpp
@@ -9,7 +9,7 @@
 //  Module:         Different Qt utility functions
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -356,13 +356,15 @@ APIRET QtUtilProcessCommand (const QString &Command, QString &StandardOutput)
    }
    if (qtrc)
    {
-//      StandardOutput  = Process.readAllStandardOutput();
-      StandardOutput  = Process.readAll();
+//    StandardOutput  = Process.readAllStandardOutput();
+//    StandardOutput  = Process.readAll();
+      StandardOutput  = QString::fromUtf8 (Process.readAll().constData());
+      
       StrState = "Done";
    }
    else
    {
-      LOG_INFO ("Killing command because of timeout [%s] in state %s", QSTR_TO_PSZ(Command), QSTR_TO_PSZ(StrState))
+      LOG_INFO ("Killing command because of timeout or non-existence [%s] in state %s", QSTR_TO_PSZ(Command), QSTR_TO_PSZ(StrState))
       Process.kill();
       return ERROR_QTUTIL_COMMAND_TIMEOUT;
    }
diff --git a/qtutil.h b/qtutil.h
index deb1284..64ed966 100644
--- a/qtutil.h
+++ b/qtutil.h
@@ -9,7 +9,7 @@
 //  Module:         Different Qt utility functions
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/table.cpp b/table.cpp
index f2bb881..99b6f58 100644
--- a/table.cpp
+++ b/table.cpp
@@ -9,7 +9,7 @@
 //  Module:         The table widget (central widget of the application)
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -135,8 +135,9 @@ APIRET t_Table::GetDeviceUnderCursor (t_pDevice &pDevice)
 void t_Table::contextMenuEvent (QContextMenuEvent *pEvent)
 {
    QAction     *pAction;
-   QAction       LocalIndicator (tr("Local Device - cannot be acquired"           ), this);
-   QAction       CloneIndicator (tr("Device used for cloning - cannot be acquired"), this);
+   QAction       LocalIndicator        (tr("Local Device - cannot be acquired"                   ), this);
+   QAction       CloneIndicator        (tr("Device used for cloning - cannot be acquired"        ), this);
+   QAction       AddStateInfoIndicator (tr("Cannot be acquired - see additional state info field"), this);
    QMenu         Menu;
    QPoint        Pos;
    t_pDevice    pDevice;
@@ -177,6 +178,12 @@ void t_Table::contextMenuEvent (QContextMenuEvent *pEvent)
       Menu.addAction (&CloneIndicator);
       Menu.addSeparator ();
    }
+   else if (!pDevice->AddStateInfo.CanBeAcquired)
+   {
+      AddStateInfoIndicator.setEnabled (false);
+      Menu.addAction (&AddStateInfoIndicator);
+      Menu.addSeparator ();
+   }
    else
    {
       Menu.addAction (pOwn->pActionAcquire);
@@ -219,7 +226,7 @@ APIRET t_Table::ShowDeviceInfo (t_pcDevice pDevice)
 {
    QString Info;
 
-   LOG_INFO ("Info for %s requested", QSTR_TO_PSZ(pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Info for requested", QSTR_TO_PSZ(pDevice->LinuxDevice))
    pOwn->SlowDownAcquisitions = true;
    CHK (t_Info::GetDeviceInfo (pDevice, true, Info))
    pOwn->SlowDownAcquisitions = false;
@@ -314,19 +321,20 @@ APIRET TableFifoCalcSizeAndAlloc (t_pDevice pDevice, unsigned int Fifos, unsigne
 {
    const unsigned int PageSize = getpagesize();
    unsigned int       MaxBlocksInUse;
+   unsigned int       ExtraSpace;
 
    // Set the data block size
    // -----------------------
    switch (pDevice->Acquisition.Format)
    {
-      case t_File::DD : pDevice->FifoBlockSize = CONFIG(FifoBlockSizeDD );   break;
-      case t_File::AFF: pDevice->FifoBlockSize = CONFIG(FifoBlockSizeAFF);   break;
+      case t_File::DD  : pDevice->FifoBlockSize = CONFIG(FifoBlockSizeDD );   break;
+      case t_File::AAFF: pDevice->FifoBlockSize = CONFIG(FifoBlockSizeAFF);   break;
       case t_File::EWF:
-         if (pDevice->HasCompressionThreads())
+         if (pDevice->HasCompressionThreads() && (CONFIG(EwfFormat) != t_File::AEWF))
               pDevice->FifoBlockSize = EWF_MULTITHREADED_COMPRESSION_CHUNK_SIZE;
          else pDevice->FifoBlockSize = CONFIG(FifoBlockSizeEWF);
          if (pDevice->FifoBlockSize != (unsigned int) CONFIG(FifoBlockSizeEWF))
-            LOG_INFO ("Running with FifoBlockSize of %d (no other size supported when running with multithreaded EWF compression)", pDevice->FifoBlockSize)
+            LOG_INFO ("[%s] Running with FifoBlockSize of %d (no other size supported when using libewf with multithreaded compression)", QSTR_TO_PSZ (pDevice->LinuxDevice), pDevice->FifoBlockSize)
          break;
       default:  CHK (ERROR_TABLE_INVALID_FORMAT)
    }
@@ -335,8 +343,8 @@ APIRET TableFifoCalcSizeAndAlloc (t_pDevice pDevice, unsigned int Fifos, unsigne
    // ---------------------------------------------------
    pDevice->FifoAllocBlockSize = pDevice->FifoBlockSize;    // Start with the standard data size
 
-   if (pDevice->HasCompressionThreads())                    // Add what might be necessary for compressed  data
-      pDevice->FifoAllocBlockSize += (int)(pDevice->FifoBlockSize * 0.001) + 12;  // Reserve enough room so that compressed data its in the block.
+   CHK (t_ThreadCompress::GetFifoExtraSpace (pDevice, &ExtraSpace))
+   pDevice->FifoAllocBlockSize += ExtraSpace;
 
    pDevice->FifoAllocBlockSize += sizeof (t_FifoBlock);     // Add the structure overhead
 
@@ -356,7 +364,7 @@ APIRET TableFifoCalcSizeAndAlloc (t_pDevice pDevice, unsigned int Fifos, unsigne
    // --------------------------------------------------------
    MaxBlocksInUse = pDevice->FifoMaxBlocks * Fifos;  // Data in the FIFOs
    MaxBlocksInUse += 1;                              // ThreadRead might allocate an additional block that can't yet be written to the full FIFO
-   if ((pDevice->Acquisition.Format == t_File::AFF) && !pDevice->HasCompressionThreads())
+   if ((pDevice->Acquisition.Format == t_File::AAFF) && !pDevice->HasCompressionThreads())
       MaxBlocksInUse += 1;                           // ThreadWrite might use an additional buffer if it does the AFF preprocessing
    if (pDevice->HasCompressionThreads())
       MaxBlocksInUse += CONFIG(CompressionThreads);  // Each compression thread might have one additional block for writing the compressed data
@@ -379,13 +387,13 @@ APIRET t_Table::StartAcquisition (t_pDevice pDevice, bool Clone)
       return NO_ERROR;
 
    pOwn->SlowDownAcquisitions = true;
-   LOG_INFO ("Starting acquisition (%s) for %s", Clone ? "clone":"image", QSTR_TO_PSZ(pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Starting acquisition (%s)", QSTR_TO_PSZ (pDevice->LinuxDevice), Clone ? "clone":"image")
    CHK (Dlg.GetParameters (pDevice->Acquisition))
-   CHK (t_File::GetFormatExtension  (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, NULL, &Format))
+   CHK (t_File::GetFormatExtension  (pDevice->Acquisition.Format, pDevice->Acquisition.Clone, 0, NULL, &Format))
    if (Clone)
       Format = " (clone)";
-   LOG_INFO ("Image %s%s%s", QSTR_TO_PSZ(pDevice->Acquisition.ImagePath), QSTR_TO_PSZ(pDevice->Acquisition.ImageFilename), QSTR_TO_PSZ(Format))
-   LOG_INFO ("Info  %s%s%s", QSTR_TO_PSZ(pDevice->Acquisition.InfoPath ), QSTR_TO_PSZ(pDevice->Acquisition.InfoFilename ), t_File::pExtensionInfo)
+   LOG_INFO ("[%s] Image %s%s%s", QSTR_TO_PSZ (pDevice->LinuxDevice), QSTR_TO_PSZ(pDevice->Acquisition.ImagePath), QSTR_TO_PSZ(pDevice->Acquisition.ImageFilename), QSTR_TO_PSZ(Format))
+   LOG_INFO ("[%s] Info  %s%s%s", QSTR_TO_PSZ (pDevice->LinuxDevice), QSTR_TO_PSZ(pDevice->Acquisition.InfoPath ), QSTR_TO_PSZ(pDevice->Acquisition.InfoFilename ), t_File::pExtensionInfo)
 
    CHK (pDevice->SetMessage (QString()))
    pDevice->State               = t_Device::Acquire;
@@ -409,6 +417,7 @@ APIRET t_Table::StartAcquisition (t_pDevice pDevice, bool Clone)
    memset (&pDevice->SHA256Digest         , 0, sizeof(pDevice->SHA256Digest         ));
    memset (&pDevice->SHA256DigestVerifySrc, 0, sizeof(pDevice->SHA256DigestVerifySrc));
    memset (&pDevice->SHA256DigestVerifyDst, 0, sizeof(pDevice->SHA256DigestVerifyDst));
+   pDevice->ImageFileHashList.clear();
    pDevice->StartTimestamp = QDateTime::currentDateTime();
    CHK (InfoAcquisitionStart (pDevice))
 
@@ -490,10 +499,12 @@ APIRET t_Table::StartAcquisition (t_pDevice pDevice, bool Clone)
       pDevice->pFifoWrite       = pDevice->pFifoCompressOut;
    }
 
-   LOG_INFO ("Acquisition runs with %d fifos, each one with space for %d blocks of %d bytes (%0.1f MB FIFO space)",
+   LOG_INFO ("[%s] Acquisition runs with %d fifos, each one with space for %d blocks of %d bytes (%0.1f MB FIFO space)",
+             QSTR_TO_PSZ (pDevice->LinuxDevice),
              Fifos, pDevice->FifoMaxBlocks, pDevice->FifoBlockSize,
              ((double)Fifos * pDevice->FifoMaxBlocks * pDevice->FifoBlockSize) / BYTES_PER_MEGABYTE)
-   LOG_INFO ("Including the overhead, %u blocks of %d bytes have been allocated (%0.1f MB)",
+   LOG_INFO ("[%s] Including the overhead, %u blocks of %d bytes have been allocated (%0.1f MB)",
+             QSTR_TO_PSZ (pDevice->LinuxDevice),
              MaxBlocksInUse, pDevice->FifoAllocBlockSize,
              ((double)MaxBlocksInUse * pDevice->FifoAllocBlockSize) / BYTES_PER_MEGABYTE)
 
@@ -532,8 +543,8 @@ APIRET t_Table::InfoAcquisitionBadSectors (t_pDevice pDevice, bool Verify)
    if (Count)
    {
       if (Verify)
-           LOG_INFO ("During verification, %lld bad sectors have been encountered", Count)
-      else LOG_INFO ("During acquisition, %lld bad sectors have been encountered", Count)
+           LOG_INFO ("[%s] During verification, %lld bad sectors have been encountered", QSTR_TO_PSZ (pDevice->LinuxDevice), Count)
+      else LOG_INFO ("[%s] During acquisition, %lld bad sectors have been encountered", QSTR_TO_PSZ (pDevice->LinuxDevice), Count)
 
       if (Verify)
            CHK (pDevice->Info.WriteLn (tr("During verification, %1 bad sectors have been encountered. The sector numbers are:", "Info file") .arg(Count)))
@@ -582,12 +593,12 @@ APIRET t_Table::InfoAcquisitionBadSectors (t_pDevice pDevice, bool Verify)
    {
       if (Verify)
       {
-         LOG_INFO ("No bad sectors encountered during verification.")
+         LOG_INFO ("[%s] No bad sectors encountered during verification.", QSTR_TO_PSZ (pDevice->LinuxDevice))
          CHK (pDevice->Info.WriteLn (tr("No bad sectors encountered during verification.", "Info file")))
       }
       else
       {
-         LOG_INFO ("No bad sectors encountered during acquisition.")
+         LOG_INFO ("[%s] No bad sectors encountered during acquisition.", QSTR_TO_PSZ (pDevice->LinuxDevice))
          CHK (pDevice->Info.WriteLn (tr("No bad sectors encountered during acquisition.", "Info file")))
       }
    }
@@ -604,19 +615,20 @@ static APIRET TableTimestampToISO (const QDateTime &Timestamp, QString &Str)
 
 APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
 {
-   QString    MD5;
-   QString    MD5VerifySrc;
-   QString    MD5VerifyDst;
-   QString    SHA256;
-   QString    SHA256VerifySrc;
-   QString    SHA256VerifyDst;
-   QString    StateStr;
-   quint64    BadSectors;
-   QString    StartStr, StopStr, VerifyStr;
-   int        Hours, Minutes, Seconds;
-   double     Speed;
-   bool       MatchSrc = true;
-   bool       MatchDst = true;
+   QString MD5;
+   QString MD5VerifySrc;
+   QString MD5VerifyDst;
+   QString SHA256;
+   QString SHA256VerifySrc;
+   QString SHA256VerifyDst;
+   QString StateStr;
+   quint64 BadSectors;
+   QString StartStr, StopStr, VerifyStr;
+   QString Filename;
+   int     Hours, Minutes, Seconds;
+   double  Speed;
+   bool    MatchSrc = true;
+   bool    MatchDst = true;
 
    CHK (pDevice->Info.WriteLn ())
    CHK (InfoAcquisitionBadSectors (pDevice, false))
@@ -666,8 +678,12 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
                   if (pDevice->Acquisition.CalcSHA256) CHK (HashSHA256DigestStr (&pDevice->SHA256Digest, SHA256)) // acquisition), we can calculate the acquisition hash.
                }
                break;
+            case t_Device::ThreadWriteVerifyError:
+               StateStr = tr("Aborted because of image read error during verification", "Info file");
+               if (pDevice->Acquisition.CalcMD5   ) CHK (HashMD5DigestStr    (&pDevice->MD5Digest   , MD5   ))
+               if (pDevice->Acquisition.CalcSHA256) CHK (HashSHA256DigestStr (&pDevice->SHA256Digest, SHA256))
+               break;
             case t_Device::ThreadWriteWriteError : StateStr = tr("Aborted because of image write error"                   , "Info file"); break;
-            case t_Device::ThreadWriteVerifyError: StateStr = tr("Aborted because of image read error during verification", "Info file"); break;
             default:                               StateStr = tr("Aborted, strange reason (%1)"                           , "Info file") .arg(pDevice->AbortReason); break;
          }
          break;
@@ -757,6 +773,44 @@ APIRET t_Table::InfoAcquisitionEnd (t_pDevice pDevice)
       CHK (pDevice->Info.AddRow (tr("Acquisition speed:: %1 MByte/s (%2 hours, %3 minutes and %4 seconds)", "Info file").arg(Speed, 0, 'f', 2) .arg(Hours) .arg(Minutes) .arg(Seconds)))
       CHK (pDevice->Info.WriteTable ());
    }
+
+   // Images files and hashes
+   // -----------------------
+   t_Device::t_ImageFileHash *pFileHash;
+
+   CHK (pDevice->Info.WriteLn ())
+   CHK (pDevice->Info.WriteLn ())
+   CHK (pDevice->Info.Title   (tr("Generated image files and their MD5 hashes", "Info file")))
+   CHK (pDevice->Info.WriteLn ())
+   if (CONFIG(CalcImageFileMD5))
+   {
+      if (pDevice->Acquisition.VerifyDst)
+      {
+         if (pDevice->Acquisition.Format == t_File::EWF)
+            CHK (pDevice->Info.WriteLn (tr("No MD5 hashes available (the select EWF format does not support image file hashes)")))
+      }
+      else
+      {
+         CHK (pDevice->Info.WriteLn (tr("No MD5 hashes available (image verification checkbox was switched off)")))
+      }
+   }
+   else
+   {
+      CHK (pDevice->Info.WriteLn (tr("No MD5 hashes available (configuration parameter CalcImageFileMD5 is off)")))
+   }
+   CHK (pDevice->Info.WriteLn ("MD5                               Image file"))
+   for (int i=0; i<pDevice->ImageFileHashList.count(); i++)
+   {
+      pFileHash = pDevice->ImageFileHashList[i];
+      if (pFileHash->MD5Valid)
+           CHK (HashMD5DigestStr(&pFileHash->MD5Digest, MD5))
+      else MD5 = "n/a                             ";
+      Filename = QFileInfo(pFileHash->Filename).fileName();
+      CHK (pDevice->Info.WriteLn (QString("%1  %2") .arg(MD5) .arg(Filename)))
+   }
+
+
+
    CHK (pDevice->Info.WriteLn ());
    CHK (pDevice->Info.WriteLn ());
 
@@ -807,7 +861,6 @@ APIRET t_Table::FinaliseThreadStructs (t_pDevice pDevice)
 //      LibEwfGetMemStats (&LibEwfAllocs, &LibEwfFrees);
 //      LOG_INFO ("LIBEWF mem  statistics: %d allocated - %d freed = %d remaining", LibEwfAllocs, LibEwfFrees, LibEwfAllocs - LibEwfFrees)
 
-      LOG_INFO ("Acquisition of %s: All structures cleaned.", QSTR_TO_PSZ (pDevice->LinuxDevice))
 
       if (pDevice->AbortRequest)
            pDevice->State = t_Device::Aborted;
@@ -816,6 +869,11 @@ APIRET t_Table::FinaliseThreadStructs (t_pDevice pDevice)
       if (!pDevice->DeleteAfterAbort)
          CHK_EXIT (InfoAcquisitionEnd (pDevice))
 
+      while (!pDevice->ImageFileHashList.isEmpty())
+         delete pDevice->ImageFileHashList.takeFirst();
+
+      LOG_INFO ("[%s] All structures cleaned.", QSTR_TO_PSZ (pDevice->LinuxDevice))
+
       // Check if all acqusitions have completed now (for AutoExit)
       // ----------------------------------------------------------
       t_Device::t_State State;
@@ -838,7 +896,7 @@ APIRET t_Table::FinaliseThreadStructs (t_pDevice pDevice)
 
 void t_Table::SlotThreadReadFinished (t_pDevice pDevice)
 {
-   LOG_INFO ("Acquisition of %s: Read thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Read thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
    pDevice->pThreadRead->deleteLater();
    pDevice->pThreadRead = NULL;
 
@@ -850,7 +908,7 @@ void t_Table::SlotThreadReadFinished (t_pDevice pDevice)
 
 void t_Table::SlotThreadHashFinished (t_pDevice pDevice)
 {
-   LOG_INFO ("Acquisition of %s: Hash thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Hash thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
    pDevice->pThreadHash->deleteLater();
    pDevice->pThreadHash = NULL;
 
@@ -864,7 +922,7 @@ void t_Table::SlotThreadCompressFinished (t_pDevice pDevice, int ThreadNr)
 {
    bool NoMoreThreads = true;
 
-   LOG_INFO ("Acquisition of %s: Compression thread #%d finished", QSTR_TO_PSZ (pDevice->LinuxDevice), ThreadNr)
+   LOG_INFO ("[%s] Compression thread #%d finished", QSTR_TO_PSZ (pDevice->LinuxDevice), ThreadNr)
 
    pDevice->ThreadCompressList[ThreadNr]->deleteLater();
    pDevice->ThreadCompressList[ThreadNr] = NULL;
@@ -876,7 +934,7 @@ void t_Table::SlotThreadCompressFinished (t_pDevice pDevice, int ThreadNr)
 
    if (NoMoreThreads)
    {
-       LOG_INFO ("All %d compression threads finished", pDevice->ThreadCompressList.count())
+       LOG_INFO ("[%s] All %d compression threads finished", QSTR_TO_PSZ (pDevice->LinuxDevice), pDevice->ThreadCompressList.count())
        pDevice->ThreadCompressList.clear();
    }
 
@@ -889,7 +947,7 @@ void t_Table::SlotThreadCompressFinished (t_pDevice pDevice, int ThreadNr)
 
 void t_Table::SlotThreadWriteFinished (t_pDevice pDevice)
 {
-   LOG_INFO ("Acquisition of %s: Write thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Write thread finished", QSTR_TO_PSZ (pDevice->LinuxDevice))
 
    pDevice->pThreadWrite->deleteLater();
    pDevice->pThreadWrite = NULL;
@@ -902,11 +960,11 @@ void t_Table::SlotThreadWriteFinished (t_pDevice pDevice)
 
 void t_Table::SlotThreadWriteWakeThreads (t_pDevice pDevice)
 {
-   LOG_INFO ("Acquisition of %s: Write thread asks other threads for releasing its handle", QSTR_TO_PSZ (pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Write thread asks other threads for releasing its handle", QSTR_TO_PSZ (pDevice->LinuxDevice))
 
    if (pDevice->AbortRequest)
    {
-      LOG_INFO ("Acquisition of %s: Calling WakeWaitingThreads", QSTR_TO_PSZ (pDevice->LinuxDevice))
+      LOG_INFO ("[%s] Calling WakeWaitingThreads", QSTR_TO_PSZ (pDevice->LinuxDevice))
       CHK_EXIT (WakeWaitingThreads(pDevice))
    }
 }
@@ -915,11 +973,11 @@ APIRET t_Table::AbortAcquisition0 (t_pDevice pDevice)
 {
    if (pDevice->AbortRequest)
    {
-      LOG_INFO ("User pressed abort, but abort flag for acquisition on %s is already set.", QSTR_TO_PSZ(pDevice->LinuxDevice))
+      LOG_INFO ("[%s] User pressed abort, but abort flag is already set.", QSTR_TO_PSZ(pDevice->LinuxDevice))
       return NO_ERROR;
    }
 
-   LOG_INFO ("User aborts acquisition on %s", QSTR_TO_PSZ(pDevice->LinuxDevice))
+   LOG_INFO ("[%s] User aborts acquisition", QSTR_TO_PSZ(pDevice->LinuxDevice))
    pDevice->AbortReason  = t_Device::UserRequest;
    pDevice->AbortRequest = true;
 
@@ -989,4 +1047,3 @@ APIRET t_Table::WakeWaitingThreads (t_pDevice pDevice)
 
    return NO_ERROR;
 }
-
diff --git a/table.h b/table.h
index 10143cc..bbd3569 100644
--- a/table.h
+++ b/table.h
@@ -9,7 +9,7 @@
 //  Module:         The table widget (central widget of the application)
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
diff --git a/main.h b/thread.cpp
similarity index 75%
copy from main.h
copy to thread.cpp
index 96d0385..d37e075 100644
--- a/main.h
+++ b/thread.cpp
@@ -6,10 +6,10 @@
 //                  Service de Police Judiciaire
 //                  Section Nouvelles Technologies
 // ****************************************************************************
-//  Module:         Main
+//  Module:         Thread bas class
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -26,11 +26,24 @@
 // You should have received a copy of the GNU General Public License
 // along with guymager. If not, see <http://www.gnu.org/licenses/>.
 
-APIRET        MainPocessEvents     (void);
-APIRET        MainGetCommandLine   (char **ppCommandLine);
-QLocale      *MainGetpNumberLocale (void);
+#include <QtCore>
 
-#ifdef __DEVICE_H__
-   t_pDeviceList MainGetDeviceList (void);
-#endif
+#include "common.h"
+#include "thread.h"
+
+
+t_Thread::t_Thread()
+{
+   pDebugMessage="Thread started";
+}
+
+const char *t_Thread::GetDebugMessage (void)
+{
+   return pDebugMessage;
+}
+
+APIRET t_Thread::SetDebugMessage (const char *pMessage)
+{
+   pDebugMessage = pMessage; return NO_ERROR;
+}
 
diff --git a/main.h b/thread.h
similarity index 74%
copy from main.h
copy to thread.h
index 96d0385..0eda047 100644
--- a/main.h
+++ b/thread.h
@@ -6,10 +6,10 @@
 //                  Service de Police Judiciaire
 //                  Section Nouvelles Technologies
 // ****************************************************************************
-//  Module:         Main
+//  Module:         Thread bas class
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -26,11 +26,28 @@
 // You should have received a copy of the GNU General Public License
 // along with guymager. If not, see <http://www.gnu.org/licenses/>.
 
-APIRET        MainPocessEvents     (void);
-APIRET        MainGetCommandLine   (char **ppCommandLine);
-QLocale      *MainGetpNumberLocale (void);
+#ifndef __THREAD_H__
+#define __THREAD_H__
 
-#ifdef __DEVICE_H__
-   t_pDeviceList MainGetDeviceList (void);
+#ifndef __COMMON_H__
+   #include "common.h"
 #endif
 
+#include <QThread>
+
+class t_Thread: public QThread
+{
+   Q_OBJECT
+
+   public:
+      t_Thread ();
+
+      const char *GetDebugMessage (void);
+
+      APIRET SetDebugMessage (const char *pMessage);
+
+   private:
+      const char *pDebugMessage;
+};
+
+#endif
diff --git a/threadcompress.cpp b/threadcompress.cpp
index f4f009d..f08676f 100644
--- a/threadcompress.cpp
+++ b/threadcompress.cpp
@@ -9,7 +9,7 @@
 //  Module:         Multi-threaded compression
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -36,6 +36,7 @@
 #include "threadwrite.h"
 #include "config.h"
 #include "aaff.h"
+#include "util.h"
 
 class t_ThreadCompressLocal
 {
@@ -77,6 +78,28 @@ t_ThreadCompress::~t_ThreadCompress (void)
    delete pOwn;
 }
 
+APIRET t_ThreadCompress::GetFifoExtraSpace (t_pDevice pDevice, unsigned int *pExtraSpace)
+{
+   unsigned int ExtraSpace;
+   unsigned int ExtraZ;
+
+   ExtraZ = UtilGetMaxZcompressedBufferSize (pDevice->FifoBlockSize) - pDevice->FifoBlockSize;
+
+   switch (pDevice->Acquisition.Format)
+   {
+      case t_File::DD  : ExtraSpace = 0;   break;
+      case t_File::AAFF: ExtraSpace = AaffPreprocessExtraSpace(pDevice->FifoBlockSize);  break;
+      case t_File::EWF:
+         if (CONFIG(EwfFormat) == t_File::AEWF)
+              ExtraSpace = AewfPreprocessExtraSpace(pDevice->FifoBlockSize);
+         else ExtraSpace = ExtraZ;
+         break;
+      default:  CHK (ERROR_THREADCOMPRESS_INVALID_FORMAT)
+   }
+   *pExtraSpace = ExtraSpace;
+   return NO_ERROR;
+}
+
 
 void t_ThreadCompress::run (void)
 {
@@ -90,72 +113,102 @@ void t_ThreadCompress::run (void)
    const int       SubFifoNr = pOwn->ThreadNr;
    size_t          CompressedMaxSize = 0;
    size_t          CompressedSize    = 0;
-   LIBEWF_HANDLE *pEwfHandle;
+   void          *pHandle;
+   LIBEWF_HANDLE *pEwfHandle  = NULL;
+   t_Aewf        *pAewfHandle = NULL;
+// t_Aaff        *pAaffHandle = NULL;
    ssize_t         rc;
 
-   LOG_INFO ("Acquisition of %s: Compression thread #%d started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), pOwn->ThreadNr)
+   LOG_INFO ("[%s] Compression thread #%d started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), pOwn->ThreadNr)
+   CHK_EXIT (SetDebugMessage ("Start run function"))
 
    pDevice  = pOwn->pDevice;
 
    if (pDevice->Acquisition.Format == t_File::EWF)
       CompressedMaxSize = (size_t) (pDevice->FifoBlockSize * 1.001) + 12; // see zlib documentation
 
-   CHK_EXIT (pDevice->pThreadWrite->GetpFileHandle ((void **)&pEwfHandle))
+   CHK_EXIT (pDevice->pThreadWrite->GetpFileHandle (&pHandle))
+   switch (pDevice->Acquisition.Format)
+   {
+      case t_File::EWF:  if (CONFIG(EwfFormat) == t_File::AEWF)
+                              pAewfHandle = (t_Aewf *)        pHandle;
+                         else pEwfHandle  = (LIBEWF_HANDLE *) pHandle;
+                         break;
+      case t_File::AAFF: // pAawfHandle = (t_Aawf *) pHandle;
+                         break;
+      default:           CHK_EXIT (ERROR_THREADCOMPRESS_INVALID_FORMAT)
+   }
+
    CHK_EXIT (pDevice->pFifoCompressIn ->GetSubFifo (SubFifoNr, pFifoIn ))
    CHK_EXIT (pDevice->pFifoCompressOut->GetSubFifo (SubFifoNr, pFifoOut))
 
    while (!Finished && !pDevice->AbortRequest)
    {
+      CHK_EXIT (SetDebugMessage ("Wait for block"))
       CHK_EXIT (pFifoIn->Get (pFifoBlockIn))
+      CHK_EXIT (SetDebugMessage ("Process block"))
       if (pFifoBlockIn)
       {
          Blocks++;
+         CHK_EXIT (t_Fifo::Create (pDevice->pFifoMemory, pFifoBlockOut, pDevice->FifoAllocBlockSize))
+         pFifoBlockOut->Nr       = pFifoBlockIn->Nr;
+         pFifoBlockOut->DataSize = pFifoBlockIn->DataSize;
+
          switch (pDevice->Acquisition.Format)
          {
             case t_File::EWF:
-               CHK_EXIT (t_Fifo::Create (pDevice->pFifoMemory, pFifoBlockOut, pDevice->FifoAllocBlockSize))
-
-               CompressedSize          = CompressedMaxSize;   // Must be initialised with the max buffer size (we use this one instead of MULTITHREADED_COMPRESSION_FIFO_BLOCK_SIZE in order to check if ti works as tols in the zlib docu)
-               pFifoBlockOut->Nr       = pFifoBlockIn->Nr;
-               pFifoBlockOut->DataSize = pFifoBlockIn->DataSize;
-
-               rc = libewf_raw_write_prepare_buffer (pEwfHandle, pFifoBlockIn ->Buffer, pFifoBlockIn->DataSize,
-                                                                 pFifoBlockOut->Buffer, &CompressedSize,
-                                                                &pFifoBlockOut->EwfCompressionUsed,
-                                                                &pFifoBlockOut->EwfChunkCRC,
-                                                                &pFifoBlockOut->EwfWriteCRC);
-               if (pFifoBlockOut->EwfCompressionUsed)
+               if (CONFIG(EwfFormat) == t_File::AEWF)
                {
-                  pFifoBlockOut->EwfDataSize = CompressedSize;   // Data to be forwarded is contained in
-                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockIn))     // pFifoBlockOut, pFifoBlockIn no longer needed.
+                  CHK_EXIT (AewfPreprocess (pAewfHandle, &pFifoBlockOut->pAewfPreprocess, pFifoBlockIn ->Buffer, pFifoBlockIn ->DataSize,
+                                                                                          pFifoBlockOut->Buffer, pFifoBlockOut->BufferSize))
+                  if (pFifoBlockOut->pAewfPreprocess->Compressed)
+                  {
+                     CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockIn))
+                  }
+                  else
+                  {
+                     pFifoBlockIn->pAewfPreprocess = pFifoBlockOut->pAewfPreprocess;
+                     CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockOut))
+                     pFifoBlockOut = pFifoBlockIn;
+                  }
+                  break;
                }
                else
                {
-                  pFifoBlockIn->EwfDataSize        = pFifoBlockIn ->DataSize;
-                  pFifoBlockIn->EwfCompressionUsed = pFifoBlockOut->EwfCompressionUsed;
-                  pFifoBlockIn->EwfChunkCRC        = pFifoBlockOut->EwfChunkCRC;
-                  pFifoBlockIn->EwfWriteCRC        = pFifoBlockOut->EwfWriteCRC;
-                  CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockOut))    // No compression, we'll forward the
-                  pFifoBlockOut = pFifoBlockIn;                                       // original block we received
-               }
-
-               if (rc != (ssize_t) pFifoBlockOut->EwfDataSize)
-               {
-                  LOG_INFO ("libewf_raw_write_prepare_buffer returned %d. DataSize=%u, CompressedMaxSize=%zd, CompressedSize=%zd, EwfCompressionUsed=%d", (int)rc,
-                            pFifoBlockOut->DataSize, CompressedMaxSize, CompressedSize, pFifoBlockOut->EwfCompressionUsed)
-                  CHK_EXIT (ERROR_THREADCOMPRESS_LIBEWF_FAILED)
+                  CompressedSize = CompressedMaxSize;   // Must be initialised with the max buffer size (we use this one instead of MULTITHREADED_COMPRESSION_FIFO_BLOCK_SIZE in order to check if ti works as tols in the zlib docu)
+                  rc = libewf_raw_write_prepare_buffer (pEwfHandle, pFifoBlockIn ->Buffer, pFifoBlockIn->DataSize,
+                                                                    pFifoBlockOut->Buffer, &CompressedSize,
+                                                                   &pFifoBlockOut->EwfCompressionUsed,
+                                                                   &pFifoBlockOut->EwfChunkCRC,
+                                                                   &pFifoBlockOut->EwfWriteCRC);
+                  if (pFifoBlockOut->EwfCompressionUsed)
+                  {
+                     pFifoBlockOut->EwfDataSize = CompressedSize;                        // Data to be forwarded is contained in
+                     CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockIn))     // pFifoBlockOut, pFifoBlockIn no longer needed.
+                  }
+                  else
+                  {
+                     pFifoBlockIn->EwfDataSize        = pFifoBlockIn ->DataSize;
+                     pFifoBlockIn->EwfCompressionUsed = pFifoBlockOut->EwfCompressionUsed;
+                     pFifoBlockIn->EwfChunkCRC        = pFifoBlockOut->EwfChunkCRC;
+                     pFifoBlockIn->EwfWriteCRC        = pFifoBlockOut->EwfWriteCRC;
+                     CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockOut))    // No compression, we'll forward the
+                     pFifoBlockOut = pFifoBlockIn;                                       // original block we received
+                  }
+
+                  if (rc != (ssize_t) pFifoBlockOut->EwfDataSize)
+                  {
+                     LOG_INFO ("[%s] libewf_raw_write_prepare_buffer returned %d. DataSize=%u, CompressedMaxSize=%zd, CompressedSize=%zd, EwfCompressionUsed=%d",
+                               QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), (int)rc,
+                               pFifoBlockOut->DataSize, CompressedMaxSize, CompressedSize, pFifoBlockOut->EwfCompressionUsed)
+                     CHK_EXIT (ERROR_THREADCOMPRESS_LIBEWF_FAILED)
+                  }
+                  pFifoBlockOut->EwfPreprocessed = true;
                }
-               pFifoBlockOut->EwfPreprocessed = true;
                break;
 
-            case t_File::AFF:
-//               LOG_ERROR ("AaffPreprocess")
-               CHK_EXIT (t_Fifo::Create (pDevice->pFifoMemory, pFifoBlockOut, pDevice->FifoAllocBlockSize))
-               pFifoBlockOut->Nr       = pFifoBlockIn->Nr;
-               pFifoBlockOut->DataSize = pFifoBlockIn->DataSize;
-
+            case t_File::AAFF:
                CHK_EXIT (AaffPreprocess (&pFifoBlockOut->pAaffPreprocess, pFifoBlockIn->Buffer, pFifoBlockIn->DataSize, pFifoBlockOut->Buffer, pFifoBlockOut->BufferSize))
-
                if (pFifoBlockOut->pAaffPreprocess->Compressed)
                {
                   CHK_EXIT (t_Fifo::Destroy (pDevice->pFifoMemory, pFifoBlockIn))
@@ -175,13 +228,14 @@ void t_ThreadCompress::run (void)
       }
       else
       {
-         LOG_INFO ("Dummy block")
+         LOG_INFO ("[%s] Dummy block", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
          Finished = true;
       }
    }
    CHK_EXIT (pDevice->pThreadWrite->ReleaseFileHandle ())
 
-   LOG_INFO ("Compression thread #%d exits now (device %s, %Ld blocks processed)", pOwn->ThreadNr, QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks)
+   LOG_INFO ("[%s] Compression thread #%d exits now - %Ld blocks processed", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), pOwn->ThreadNr, Blocks)
+   CHK_EXIT (SetDebugMessage ("Exit run function"))
 }
 
 
diff --git a/threadcompress.h b/threadcompress.h
index ac124a0..efe30bf 100644
--- a/threadcompress.h
+++ b/threadcompress.h
@@ -9,7 +9,7 @@
 //  Module:         Multi-threaded compression
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -29,7 +29,7 @@
 #ifndef __THREADCOMPRESS_H__
 #define __THREADCOMPRESS_H__
 
-#include <QThread>   //lint !e537 Repeated include
+#include "thread.h"
 
 #ifndef __DEVICE_H__
   #include "device.h"
@@ -37,7 +37,7 @@
 
 class t_ThreadCompressLocal;
 
-class t_ThreadCompress: public QThread
+class t_ThreadCompress: public t_Thread
 {
    Q_OBJECT
 
@@ -46,6 +46,8 @@ class t_ThreadCompress: public QThread
       t_ThreadCompress (t_pDevice pDevice, int ThreadNr);
      ~t_ThreadCompress ();
 
+      static APIRET GetFifoExtraSpace (t_pDevice pDevice, unsigned int *pExtraSpace);
+
    protected:
       void run (void);
 
diff --git a/threadhash.cpp b/threadhash.cpp
index 0bc0137..de9abf8 100644
--- a/threadhash.cpp
+++ b/threadhash.cpp
@@ -9,7 +9,7 @@
 //  Module:         Thread for calculating hashes
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -80,7 +80,8 @@ void t_ThreadHash::run (void)
    t_HashContextSHA256 HashContextSHA256;
    bool                VerifyLoop = false;
 
-   LOG_INFO ("Acquisition of %s: Hash thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Hash thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   CHK_EXIT (SetDebugMessage ("Start run function"))
    pDevice = pOwn->pDevice;
    pBlocks = &BlocksCalculated;
    for (;;)  // The whole loop is done 2 times if the user chose to do a source verification, 1 time otherwise.
@@ -91,7 +92,9 @@ void t_ThreadHash::run (void)
       if (pDevice->Acquisition.CalcSHA256) CHK_EXIT (HashSHA256Init (&HashContextSHA256))
       do
       {
+         CHK_EXIT (SetDebugMessage ("Wait for block"))
          CHK_EXIT (pDevice->pFifoHashIn->Get (pFifoBlock))
+         CHK_EXIT (SetDebugMessage ("Process block"))
          if (pFifoBlock)
          {
             (*pBlocks)++;
@@ -109,7 +112,7 @@ void t_ThreadHash::run (void)
          }
          else
          {
-            LOG_INFO ("Dummy block")
+            LOG_INFO ("[%s] Dummy block", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
             Finished = true;
          }
       } while (!Finished && !pDevice->AbortRequest);
@@ -141,8 +144,9 @@ void t_ThreadHash::run (void)
    }
 
    if (pDevice->Acquisition.VerifySrc)
-        LOG_INFO ("Hash thread exits now (device %s, %Ld blocks processed, %Ld blocks verified)", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), BlocksCalculated, BlocksVerified)
-   else LOG_INFO ("Hash thread exits now (device %s, %Ld blocks processed)"                     , QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), BlocksCalculated)
+        LOG_INFO ("[%s] Hash thread exits now - %Ld blocks processed, %Ld blocks verified", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), BlocksCalculated, BlocksVerified)
+   else LOG_INFO ("[%s] Hash thread exits now - %Ld blocks processed"                     , QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), BlocksCalculated)
+   CHK_EXIT (SetDebugMessage ("Exit run function"))
 }
 
 
diff --git a/threadhash.h b/threadhash.h
index b589c02..1545128 100644
--- a/threadhash.h
+++ b/threadhash.h
@@ -9,7 +9,7 @@
 //  Module:         Thread for calculating hashes
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -29,7 +29,7 @@
 #ifndef __THREADHASH_H__
 #define __THREADHASH_H__
 
-#include <QThread>   //lint !e537 Repeated include
+#include "thread.h"
 
 #ifndef __DEVICE_H__
   #include "device.h"
@@ -37,7 +37,7 @@
 
 class t_ThreadHashLocal;
 
-class t_ThreadHash: public QThread
+class t_ThreadHash: public t_Thread
 {
    Q_OBJECT
 
diff --git a/threadread.cpp b/threadread.cpp
index 8651e57..6ccc275 100644
--- a/threadread.cpp
+++ b/threadread.cpp
@@ -9,7 +9,7 @@
 //  Module:         Thread for reading data.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -113,7 +113,7 @@ static APIRET ThreadReadDeviceDisconnected (t_pDevice pDevice, const char* pStrA
    if (pDevice->State == t_Device::Acquire)
         pDevice->State = t_Device::AcquirePaused;
    else pDevice->State = t_Device::VerifyPaused;
-   LOG_INFO ("Device %s disconnected (%s, %d, %s), switching device state to %s", QSTR_TO_PSZ(pDevice->LinuxDevice), pStrAction, errno, strerror(errno), pDevice->StateStr())
+   LOG_INFO ("[%s] Device disconnected (%s, %d, %s), switching device state to %s", QSTR_TO_PSZ(pDevice->LinuxDevice), pStrAction, errno, strerror(errno), pDevice->StateStr())
 
    return ERROR_THREADREAD_DEVICE_DISCONNECTED;
 }
@@ -146,9 +146,9 @@ static APIRET ThreadReadBlock0 (t_pDevice pDevice, unsigned char *pBuffer, unsig
    if (pDevice->FileDescSrc == t_Device::FileDescEmpty)
    {
       OpenFlags = O_RDONLY | O_NOATIME;
-      if (CONFIG (FifoMemoryManager))     // We need the buffers to be located on page size (4K) boundaries; this only
-      {                                   // is guaranteed when working with Guymager's internal memory manager (see t_FifoMemory::t_FifoMemory)
-         LOG_INFO ("Trying direct mode for %s", QSTR_TO_PSZ(pDevice->LinuxDevice))
+      if (CONFIG (FifoMemoryManager) && CONFIG (DirectIO))  // We need the buffers to be located on page size (4K) boundaries; this only
+      {                                                     // is guaranteed when working with Guymager's internal memory manager (see t_FifoMemory::t_FifoMemory)
+         LOG_INFO ("[%s] Trying direct mode", QSTR_TO_PSZ(pDevice->LinuxDevice))
          OpenFlags |= O_DIRECT;
       }
       pDevice->FileDescSrc = open64 (QSTR_TO_PSZ(pDevice->LinuxDevice), OpenFlags);
@@ -157,7 +157,7 @@ static APIRET ThreadReadBlock0 (t_pDevice pDevice, unsigned char *pBuffer, unsig
          OpenFlags &= ~O_DIRECT;                                                       // (added as special device) on the cases server (dd reported
          pDevice->FileDescSrc = open64 (QSTR_TO_PSZ(pDevice->LinuxDevice), OpenFlags); // the same error with iflag=direct). Try again without it.
       }
-      LOG_INFO ("Direct mode for %s switched %s", QSTR_TO_PSZ(pDevice->LinuxDevice), (OpenFlags & O_DIRECT) ? "on":"off")
+      LOG_INFO ("[%s] Direct mode switched %s", QSTR_TO_PSZ(pDevice->LinuxDevice), (OpenFlags & O_DIRECT) ? "on":"off")
       if (pDevice->FileDescSrc < 0)
          CHK_RET (ThreadReadDeviceDisconnected (pDevice, "open"))
       CHK_RET (ThreadReadAdjustSeek (pDevice))
@@ -241,7 +241,7 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
                pDevice->FallbackMode = true;
 //               ReadTry = (int) GETMIN (pDevice->SectorSize, pDevice->SectorSizePhys);
                ReadTry = pDevice->SectorSize;
-               LOG_INFO ("Device read error, switching %s to slow fallback mode. Reading sectors individually from now on.", QSTR_TO_PSZ(pDevice->LinuxDevice))
+               LOG_INFO ("[%s] Device read error, switching to slow fallback mode. Reading sectors individually from now on.", QSTR_TO_PSZ(pDevice->LinuxDevice))
             }
             else
             {
@@ -251,12 +251,12 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
                switch (RcSeek)                          // the source device, let's replace it by a zero sector.
                {
                   case NO_ERROR:
-                     if ((pDevice->Acquisition.Format == t_File::AFF) && (CONFIG (AffMarkBadSectors)))
+                     if ((pDevice->Acquisition.Format == t_File::AAFF) && (CONFIG (AffMarkBadSectors)))
                           CHK (AaffCopyBadSectorMarker (pBuffer, ReadTry))
                      else memset (pBuffer, 0, ReadTry);
                      BytesRead += ReadTry;
                      pBuffer   += ReadTry;
-                     LOG_INFO ("Read error on %s, sector %Ld, bad data replaced by zero block", QSTR_TO_PSZ(pDevice->LinuxDevice), Sector)
+                     LOG_INFO ("[%s] Read error on sector %Ld, bad data replaced by zero block", QSTR_TO_PSZ(pDevice->LinuxDevice), Sector)
                      pDevice->AddBadSector (Sector);
                      break;
                   case ERROR_THREADREAD_DEVICE_DISCONNECTED:
@@ -294,7 +294,7 @@ APIRET t_ThreadRead::ThreadReadBlock (t_pFifoBlock &pFifoBlock)
    else if ((pDevice->FallbackMode) && (RcRead == NO_ERROR))
    {
       pDevice->FallbackMode = false;  // Switch to fast reading mode if last read was good
-      LOG_INFO ("Device read ok again. Switching %s to fast block read.", QSTR_TO_PSZ(pDevice->LinuxDevice))
+      LOG_INFO ("[%s] Device read ok again, switching to fast block read.", QSTR_TO_PSZ(pDevice->LinuxDevice))
    }
 
    pFifoBlock->LastBlock = ThreadReadEOF (pDevice);
@@ -318,12 +318,19 @@ void t_ThreadRead::run (void)
    t_HashContextMD5    HashContextMD5;
    t_HashContextSHA256 HashContextSHA256;
 
-   LOG_INFO ("Acquisition of %s: Read thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Read thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   CHK_EXIT (SetDebugMessage ("Start run function"))
    pDevice = pOwn->pDevice;
    CalcHashMD5    = pDevice->Acquisition.CalcMD5    && !CONFIG (UseSeparateHashThread);
    CalcHashSHA256 = pDevice->Acquisition.CalcSHA256 && !CONFIG (UseSeparateHashThread);
 
    pBlocks = &BlocksRead;
+
+//   pDevice->AddBadSector (3);   // Simulate bad sectors
+//   pDevice->AddBadSector (4);
+//   pDevice->AddBadSector (5);
+//   pDevice->AddBadSector (122);
+
    pDevice->State = t_Device::Acquire;
    for (;;)
    {
@@ -338,7 +345,9 @@ void t_ThreadRead::run (void)
          if (*(pOwn->pSlowDownRequest))
             msleep (THREADREAD_SLOWDOWN_SLEEP);
 
+         CHK_EXIT (SetDebugMessage ("Calling ThreadReadBlock"))
          rc = ThreadReadBlock (pFifoBlock);
+         CHK_EXIT (SetDebugMessage ("ThreadReadBlock returned"))
          switch (rc)
          {
             case NO_ERROR:
@@ -368,7 +377,7 @@ void t_ThreadRead::run (void)
             case ERROR_THREADREAD_DEVICE_ABORTED:
                break;
             default:
-               LOG_ERROR ("Unexpected return code ThreadReadBlock")
+               LOG_ERROR ("[%s] Unexpected return code from ThreadReadBlock", QSTR_TO_PSZ(pDevice->LinuxDevice))
                CHK_EXIT (rc)
          }
       } while (!ThreadReadEOF(pDevice) && !pDevice->AbortRequest);
@@ -384,7 +393,7 @@ void t_ThreadRead::run (void)
       {
          if (CalcHashMD5)    CHK_EXIT (HashMD5Digest    (&HashContextMD5   , &pDevice->MD5DigestVerifySrc   ))
          if (CalcHashSHA256) CHK_EXIT (HashSHA256Digest (&HashContextSHA256, &pDevice->SHA256DigestVerifySrc))
-         LOG_INFO ("Source verification completed (device %s)", QSTR_TO_PSZ (pDevice->LinuxDevice))
+         LOG_INFO ("[%s] Source verification completed", QSTR_TO_PSZ (pDevice->LinuxDevice))
          break;
       }
 
@@ -401,14 +410,14 @@ void t_ThreadRead::run (void)
       if (pDevice->Acquisition.VerifySrc)
       {
          (void) close (pDevice->FileDescSrc);
-         LOG_INFO ("All data has been read (device %s), now re-reading for source verification", QSTR_TO_PSZ (pDevice->LinuxDevice))
+         LOG_INFO ("[%s] All data has been read, now re-reading for source verification", QSTR_TO_PSZ (pDevice->LinuxDevice))
          pBlocks = &BlocksVerified;
 //         if (CONFIG (UseSeparateHashThread))
          CHK_EXIT (pDevice->pFifoRead->InsertDummy ())
       }
       else
       {
-         LOG_INFO ("All data has been read (device %s)", QSTR_TO_PSZ (pDevice->LinuxDevice))
+         LOG_INFO ("[%s] All data has been read", QSTR_TO_PSZ (pDevice->LinuxDevice))
          break;
       }
    }
@@ -419,15 +428,16 @@ void t_ThreadRead::run (void)
       pDevice->FileDescSrc = t_Device::FileDescEmpty;
       if (rcf)
       {
-         LOG_INFO ("Unexpected error on close, errno = %d", errno)
+         LOG_INFO ("[%s] Unexpected error on close, errno = %d", QSTR_TO_PSZ(pDevice->LinuxDevice), errno)
          pDevice->AbortReason  = t_Device::ThreadReadFileError;
          pDevice->AbortRequest = true;
       }
    }
 
-   LOG_INFO ("Read thread exits now (device %s, %Ld blocks read, %llu bytes)", QSTR_TO_PSZ (pDevice->LinuxDevice), BlocksRead, BytesRead)
+   LOG_INFO ("[%s] Read thread exits now (%Ld blocks read, %llu bytes)", QSTR_TO_PSZ (pDevice->LinuxDevice), BlocksRead, BytesRead)
    if (pDevice->Acquisition.VerifySrc)
-   LOG_INFO ("             (for the source verification: %Ld blocks read, %llu bytes)", BlocksVerified, BytesVerified)
+   LOG_INFO ("[%s]   Source verification: %Ld blocks read, %llu bytes)", QSTR_TO_PSZ(pDevice->LinuxDevice), BlocksVerified, BytesVerified)
+   CHK_EXIT (SetDebugMessage ("Exit run function"))
 }
 
 void t_ThreadRead::SlotFinished (void)
diff --git a/threadread.h b/threadread.h
index 4f56ced..59c3587 100644
--- a/threadread.h
+++ b/threadread.h
@@ -9,7 +9,7 @@
 //  Module:         Thread for reading data.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -29,7 +29,7 @@
 #ifndef __THREADREAD_H__
 #define __THREADREAD_H__
 
-#include <QThread>
+#include "thread.h"
 
 #ifndef __DEVICE_H__
    #include "device.h"
@@ -37,7 +37,7 @@
 
 class t_ThreadReadLocal;
 
-class t_ThreadRead: public QThread
+class t_ThreadRead: public t_Thread
 {
    Q_OBJECT
 
diff --git a/threadscan.cpp b/threadscan.cpp
index 7b992b2..ee47889 100644
--- a/threadscan.cpp
+++ b/threadscan.cpp
@@ -9,7 +9,7 @@
 //  Module:         Thread for scanning the connected devices
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -44,7 +44,11 @@
 //         Constants
 // --------------------------
 
-// #define DEBUG_SERNR
+//#define DEBUG_SERNR
+
+#ifdef DEBUG_SERNR
+   #warning "DEBUG_SERNR must be switched off for final release"
+#endif
 
 const int THREADSCAN_WAIT_MAX         = 10000;
 const int THREADSCAN_WAIT_GRANULARITY = 100;
@@ -52,6 +56,16 @@ const int THREADSCAN_WAIT_GRANULARITY = 100;
 const QString ThreadScanLibPartedSearchDirs    = "/lib,/usr/lib,/usr/local/lib";       // Separate directories by commas
 const QString ThreadScanLibPartedSearchPattern = "libparted*.so*";
 
+
+// -----------------------------------
+//        Worker base class
+// -----------------------------------
+
+t_ThreadScanWorker::t_ThreadScanWorker (t_ThreadScan *pThreadScan)
+{
+   poThreadScan = pThreadScan;
+}
+
 // -----------------------------------
 //  Utility functions used by workers
 // -----------------------------------
@@ -73,6 +87,33 @@ static APIRET ThreadScanMarkLocalDevices (const t_pDeviceList pDeviceList)
    return NO_ERROR;
 }
 
+static APIRET ThreadScanGetAddStateInfo (t_pDevice pDevice)
+{
+   QString     Command;
+   APIRET      rc;
+   QString     StateInfo;
+   QStringList StateInfoList;
+
+   Command = CONFIG (CommandGetAddStateInfo);
+   if (!Command.isEmpty())
+   {
+      Command.replace ("%dev", pDevice->LinuxDevice, Qt::CaseInsensitive);
+   
+      rc = QtUtilProcessCommand (Command, StateInfo);
+      if (rc == ERROR_QTUTIL_COMMAND_TIMEOUT)
+      {
+         LOG_INFO ("Timeout while trying to get additional state information for %s, additional state info will be ignored", QSTR_TO_PSZ(pDevice->LinuxDevice))
+         return NO_ERROR;
+      }
+      CHK(rc)
+      StateInfoList = StateInfo.split("\n");
+      if (StateInfoList.count() > 0) pDevice->AddStateInfo.Info          =  StateInfoList[0].trimmed();
+      if (StateInfoList.count() > 1) pDevice->AddStateInfo.CanBeAcquired = (StateInfoList[1].trimmed() != "0");
+      if (StateInfoList.count() > 2) pDevice->AddStateInfo.Color         =  StateInfoList[2].trimmed().toInt();
+   }
+   return NO_ERROR;
+}
+
 // --------------------------
 //  t_ThreadScanWorkerParted
 // --------------------------
@@ -152,7 +193,8 @@ static APIRET ThreadScanFindLibparted (QStringList &Files)
 }
 
 
-t_ThreadScanWorkerParted::t_ThreadScanWorkerParted (APIRET &rc)
+t_ThreadScanWorkerParted::t_ThreadScanWorkerParted (t_ThreadScan *pThreadScan, APIRET &rc)
+   :t_ThreadScanWorker (pThreadScan)
 {
    QStringList   FilenameList;
    QString       Filename;
@@ -232,6 +274,7 @@ void t_ThreadScanWorkerParted::SlotRescan (void)
 
    emit (SignalScanStarted ());
    LOG_INFO ("Rescanning devices")
+   CHK_EXIT (poThreadScan->SetDebugMessage ("SlotRescan called (parted)"))
 
    pOwn->pFnLibPartedProbeAll ();
 
@@ -260,11 +303,13 @@ void t_ThreadScanWorkerParted::SlotRescan (void)
       pDevice = pDeviceList->AppendNew (SerialNumber, pPedDev);
       if (pDevice->LinuxDevice.startsWith ("/dev/fd",  Qt::CaseSensitive)) // Not a good way for checking this, but I don't know how to extract the information from
          pDevice->Removable = true;                                        // PedDevice. BTW, this won't work with other removable devices, for instance memory sticks.
+      CHK_EXIT (ThreadScanGetAddStateInfo (pDevice));
    }
    pOwn->pFnLibPartedFreeAll ();
    CHK_EXIT (ThreadScanMarkLocalDevices (pDeviceList))
 
    emit (SignalScanFinished (pDeviceList));
+   CHK_EXIT (poThreadScan->SetDebugMessage ("Leaving SlotRescan (parted)"))
 }
 
 // --------------------------
@@ -301,7 +346,8 @@ class t_ThreadScanWorkerHALLocal
 };
 
 
-t_ThreadScanWorkerHAL::t_ThreadScanWorkerHAL (APIRET &rc)
+t_ThreadScanWorkerHAL::t_ThreadScanWorkerHAL (t_ThreadScan *pThreadScan, APIRET &rc)
+   :t_ThreadScanWorker (pThreadScan)
 {
    pOwn = new t_ThreadScanWorkerHALLocal;
    if (!pOwn->pDBusConnection->isConnected())
@@ -421,6 +467,8 @@ void t_ThreadScanWorkerHAL::SlotRescan (void)
    QVariant         RemovableAvailable;
    QString          Model;
 
+   CHK_EXIT (poThreadScan->SetDebugMessage ("SlotRescan called (HAL)"))
+
    if (thread() != QThread::currentThread())
       CHK_EXIT (ERROR_THREADSCAN_CALLED_FROM_WRONG_THREAD) // As Qt's DBus system is quite sensible to this kind of
                                                            // mistake (resulting in many QTimer "cannot be stopped/started
@@ -506,11 +554,13 @@ void t_ThreadScanWorkerHAL::SlotRescan (void)
          pDevice->Removable = Removable.toBool();
 
          CHK_EXIT (pDevice->MediaInfo.QueryDevice(QSTR_TO_PSZ(LinuxDevice.toString())))
+         CHK_EXIT (ThreadScanGetAddStateInfo (pDevice));
       }
    }
    CHK_EXIT (ThreadScanMarkLocalDevices (pDeviceList))
    LOG_INFO ("Device scan finished")
 
+   CHK_EXIT (poThreadScan->SetDebugMessage ("Leaving SlotRescan (HAL)"))
    emit (SignalScanFinished (pDeviceList));
 }
 
@@ -566,7 +616,8 @@ class t_ThreadScanWorkerDevKitLocal
 };
 
 
-t_ThreadScanWorkerDevKit::t_ThreadScanWorkerDevKit (APIRET &rc)
+t_ThreadScanWorkerDevKit::t_ThreadScanWorkerDevKit (t_ThreadScan *pThreadScan, APIRET &rc)
+   :t_ThreadScanWorker (pThreadScan)
 {
    QDBusMessage Message;
 
@@ -688,6 +739,8 @@ void t_ThreadScanWorkerDevKit::SlotRescan (void)
    QVariant        RemovableAvailable;
    QString         Model;
 
+   CHK_EXIT (poThreadScan->SetDebugMessage ("SlotRescan called (DevKit)"))
+
    if (thread() != QThread::currentThread())
       CHK_EXIT (ERROR_THREADSCAN_CALLED_FROM_WRONG_THREAD) // As Qt's DBus system is quite sensible to this kind of
                                                            // mistake (resulting in many QTimer "cannot be stopped/started
@@ -763,11 +816,14 @@ void t_ThreadScanWorkerDevKit::SlotRescan (void)
          pDevice = pDeviceList->AppendNew (SerialNumber.toString(), LinuxDevice.toString(), Model,
                                            BlockSize.toULongLong(), BlockSize.toULongLong(), Size.toULongLong());
          pDevice->Removable = Removable.toBool();
+         CHK_EXIT (pDevice->MediaInfo.QueryDevice(QSTR_TO_PSZ(LinuxDevice.toString())))
+         CHK_EXIT (ThreadScanGetAddStateInfo (pDevice));
       }
    }
    CHK_EXIT (ThreadScanMarkLocalDevices (pDeviceList))
    LOG_INFO ("Device scan finished")
 
+   CHK_EXIT (poThreadScan->SetDebugMessage ("Leaving SlotRescan (DevKit)"))
    emit (SignalScanFinished (pDeviceList));
 }
 
@@ -871,6 +927,8 @@ APIRET t_ThreadScan::Start (t_ThreadScanWorker **ppWorker)
    int  Tries;
    bool Ok;
 
+   CHK_EXIT (SetDebugMessage ("Launch thread"))
+
    #define LAUNCH_WORKER                                                                    \
    {                                                                                        \
       *ppWorker   = NULL;                                                                   \
@@ -912,6 +970,8 @@ APIRET t_ThreadScan::Start (t_ThreadScanWorker **ppWorker)
    if (*ppWorker == NULL)
       CHK (ERROR_THREADSCAN_NOT_STARTED)
 
+   CHK_EXIT (SetDebugMessage ("Thread launched"))
+
    return NO_ERROR;
 }
 
@@ -943,14 +1003,15 @@ void t_ThreadScan::run (void)
    int      rc;
 
    LOG_INFO ("Thread Scan started")
+   CHK_EXIT (SetDebugMessage ("Start run function"))
 
    switch (CONFIG(DeviceScanMethod))
    {
       // We have to create the following object as we want to work with signals and slots in this new thread.
       // t_ThreadScan itself belongs to the main thread and thus can't be used for signals and slots.
-      case SCANMETHOD_DBUSDEVKIT: *ppoWorker = new t_ThreadScanWorkerDevKit (oWorkerRc); break;
-      case SCANMETHOD_DBUSHAL:    *ppoWorker = new t_ThreadScanWorkerHAL    (oWorkerRc); break;
-      case SCANMETHOD_LIBPARTED:  *ppoWorker = new t_ThreadScanWorkerParted (oWorkerRc); break;
+      case SCANMETHOD_DBUSDEVKIT: *ppoWorker = new t_ThreadScanWorkerDevKit (this, oWorkerRc); break;
+      case SCANMETHOD_DBUSHAL:    *ppoWorker = new t_ThreadScanWorkerHAL    (this, oWorkerRc); break;
+      case SCANMETHOD_LIBPARTED:  *ppoWorker = new t_ThreadScanWorkerParted (this, oWorkerRc); break;
       default: CHK_EXIT (ERROR_THREADSCAN_INVALID_SCAN_METHOD)
    }
    if (oWorkerRc)
@@ -968,6 +1029,7 @@ void t_ThreadScan::run (void)
       CHK_EXIT (ERROR_THREADSCAN_EXITCODE_NONZERO)
    }
    LOG_INFO ("Thread Scan ended")
+   CHK_EXIT (SetDebugMessage ("Exit run function"))
    delete pTimer;
    delete *ppoWorker;
    *ppoWorker = NULL;
diff --git a/threadscan.h b/threadscan.h
index ce7f1a3..4d3a026 100644
--- a/threadscan.h
+++ b/threadscan.h
@@ -7,7 +7,7 @@
 //                  Section Nouvelles Technologies
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -25,7 +25,8 @@
 // along with guymager. If not, see <http://www.gnu.org/licenses/>.
 
 #include <QObject>  //lint !e537 Repeated include
-#include <QThread>
+
+#include "thread.h"
 
 #ifndef __DEVICE_H__
    #include "device.h"
@@ -35,16 +36,24 @@
    #include "common.h"
 #endif
 
+class t_ThreadScan;
+
 class t_ThreadScanWorker: public QObject
 {
    Q_OBJECT
 
+   public:
+      t_ThreadScanWorker (t_ThreadScan *pThreadScan);
+
    public slots:
       virtual void SlotRescan (void) = 0;
 
    signals:
       void SignalScanFinished (t_pDeviceList);
-      void SignalScanStarted  (void)         ;
+      void SignalScanStarted  (void);
+
+   protected:
+      t_ThreadScan *poThreadScan;
 };
 
 class t_ThreadScanWorkerPartedLocal;
@@ -53,7 +62,7 @@ class t_ThreadScanWorkerParted: public t_ThreadScanWorker
    Q_OBJECT
 
    public:
-      t_ThreadScanWorkerParted (APIRET &rc);
+      t_ThreadScanWorkerParted (t_ThreadScan *pThreadScan, APIRET &rc);
      ~t_ThreadScanWorkerParted (void);
 
    public slots:
@@ -70,7 +79,7 @@ class t_ThreadScanWorkerHAL: public t_ThreadScanWorker
    Q_OBJECT
 
    public:
-      t_ThreadScanWorkerHAL (APIRET &rc);
+      t_ThreadScanWorkerHAL (t_ThreadScan *pThreadScan, APIRET &rc);
      ~t_ThreadScanWorkerHAL (void);
 
    private:
@@ -93,7 +102,7 @@ class t_ThreadScanWorkerDevKit: public t_ThreadScanWorker
    Q_OBJECT
 
    public:
-      t_ThreadScanWorkerDevKit (APIRET &rc);
+      t_ThreadScanWorkerDevKit (t_ThreadScan *pThreadScan, APIRET &rc);
      ~t_ThreadScanWorkerDevKit (void);
 
    private:
@@ -108,7 +117,7 @@ class t_ThreadScanWorkerDevKit: public t_ThreadScanWorker
 };
 
 
-class t_ThreadScan: public QThread
+class t_ThreadScan: public t_Thread
 {
    Q_OBJECT
 
diff --git a/threadwrite.cpp b/threadwrite.cpp
index 6c96756..11917fb 100644
--- a/threadwrite.cpp
+++ b/threadwrite.cpp
@@ -9,7 +9,7 @@
 //  Module:         Thread for writing data.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -46,26 +46,38 @@
 #include "threadwrite.h"
 
 
-const unsigned long THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY =   100; // ms
+const unsigned long THREADWRITE_WAIT_FOR_HANDLE_GRANULARITY =   500; // ms
 const unsigned long THREADWRITE_WAIT_FOR_HANDLE             = 30000; // ms
 const unsigned long THREADWRITE_SLOWDOWN_SLEEP              =   700; // ms
 
+const unsigned long THREADWRITE_ENCASE_MAXLEN_IMAGERVERSION = 11;
+const unsigned long THREADWRITE_ENCASE_MAXLEN_OSVERSION     = 23;
+
+
 class t_OutputFile
 {
    public:
-      virtual        ~t_OutputFile  (void) {};
+                      t_OutputFile  (t_ThreadWrite *pThreadWrite) :poThreadWrite(pThreadWrite) {}
+      virtual        ~t_OutputFile  () {}
       virtual APIRET  Open          (t_pDevice pDevice, bool Verify) = 0;
       virtual APIRET  Write         (t_pFifoBlock pFifoBlock)        = 0;
-      virtual APIRET  Verify        (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos) = 0;
+      virtual APIRET  Verify        (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, t_Device::t_ImageFileHashList &ImageFileHashList, quint64 *pPos) = 0;
       virtual APIRET  Close         (void)                           = 0;
       virtual bool    Opened        (void)                           = 0;
       virtual void *  GetFileHandle (void)                           = 0;
+
+      t_ThreadWrite *poThreadWrite;
 };
 
+// ------------------------------------------------------------------------------------------------
+//                                            DD FORMAT
+// ------------------------------------------------------------------------------------------------
+
 class t_OutputFileDD: public t_OutputFile
 {
    public:
-      t_OutputFileDD (void) :
+      t_OutputFileDD (t_ThreadWrite *pThreadWrite) :
+          t_OutputFile         (pThreadWrite),
           oFile                (-1),
           oLastCheckT          (0),
          poVerifyBuff          (NULL),
@@ -137,7 +149,7 @@ class t_OutputFileDD: public t_OutputFile
                oFile = open64 (QSTR_TO_PSZ (Filename), oFileFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
                if (oFile < 0)
                {
-                  LOG_ERROR ("open64 on %s failed, errno=%d '%s'", QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
+                  LOG_ERROR ("[%s] open64 on %s failed, errno=%d '%s'", QSTR_TO_PSZ (poDevice->LinuxDevice), QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
                   return ERROR_THREADWRITE_OPEN_FAILED;
                }
             }
@@ -145,7 +157,7 @@ class t_OutputFileDD: public t_OutputFile
             Written = write (oFile, &pFifoBlock->Buffer[Offset], GETMIN(RemainingData, oRemainingFileSize));
             if (Written < 0)
             {
-               LOG_ERROR ("write failed, oFile %d, errno=%d '%s'", oFile, errno, ToolErrorTranslateErrno (errno))
+               LOG_ERROR ("[%s] Write failed, oFile %d, errno=%d '%s'", QSTR_TO_PSZ (poDevice->LinuxDevice), oFile, errno, ToolErrorTranslateErrno (errno))
                return ERROR_THREADWRITE_WRITE_FAILED;
             }
             RemainingData      -= Written;
@@ -169,7 +181,7 @@ class t_OutputFileDD: public t_OutputFile
                   Error = (fclose (pFile) != 0);
                if (Error)
                {
-                  LOG_ERROR ("Check for destination clone %s failed (%d '%s')", QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
+                  LOG_ERROR ("[%s] Check for destination clone %s failed (%d '%s')", QSTR_TO_PSZ (poDevice->LinuxDevice), QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
                   return ERROR_THREADWRITE_WRITE_FAILED;
                }
                oLastCheckT = NowT;
@@ -179,9 +191,10 @@ class t_OutputFileDD: public t_OutputFile
          return NO_ERROR;
       }
 
-      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos)
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, t_Device::t_ImageFileHashList &ImageFileHashList, quint64 *pPos)
       {
-         ssize_t Read;
+         t_HashMD5Digest MD5Digest;
+         ssize_t         Read;
 
          if (*pPos == 0)       // First call of this function?
          {
@@ -200,23 +213,36 @@ class t_OutputFileDD: public t_OutputFile
             if (!Err) Err = (lseek64 (oFile, 0, SEEK_SET) != 0);
             if (Err)
             {
-               LOG_ERROR ("Opening %s failed, errno=%d '%s'", QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
+               LOG_ERROR ("[%s] Opening %s failed, errno=%d '%s'", QSTR_TO_PSZ (poDevice->LinuxDevice), QSTR_TO_PSZ (oFilename), errno, ToolErrorTranslateErrno (errno))
                return ERROR_THREADWRITE_OPEN_FAILED;
             }
             oRemainingFileSize = (t_uint64) FileSize;
+            if (CONFIG(CalcImageFileMD5))
+               CHK (HashMD5Init (&oCurrentHashContextMD5))
          }
 
          Read = read (oFile, (char*)poVerifyBuff, GETMIN(poDevice->FifoBlockSize, oRemainingFileSize));
          if (Read < 0)
          {
             QString Filename = oFilenameList[oCurrentVerifyFileNr-1];
-            LOG_ERROR ("read failed, oFile %d [%s], seek pos %llu, errno %d '%s'", oFile, QSTR_TO_PSZ (Filename), *pPos, errno, ToolErrorTranslateErrno (errno))
+            LOG_ERROR ("[%s] Read failed, oFile %d [%s], seek pos %llu, errno %d '%s'", QSTR_TO_PSZ (poDevice->LinuxDevice), oFile, QSTR_TO_PSZ (Filename), *pPos, errno, ToolErrorTranslateErrno (errno))
             return ERROR_THREADWRITE_VERIFY_FAILED;
          }
          oRemainingFileSize -= Read;
+         if (CONFIG(CalcImageFileMD5))
+            CHK_EXIT (HashMD5Append (&oCurrentHashContextMD5, poVerifyBuff, Read))
 
          if (oRemainingFileSize == 0)
+         {
+            bool MD5Valid = false;
+            if (CONFIG(CalcImageFileMD5))
+            {
+               CHK (HashMD5Digest (&oCurrentHashContextMD5, &MD5Digest))
+               MD5Valid = true;
+            }
+            ImageFileHashList.append (new t_Device::t_ImageFileHash (oFilenameList[oCurrentVerifyFileNr-1], &MD5Digest, MD5Valid));
             Close0 (false);
+         }
 
          if (pHashContextMD5)    CHK_EXIT (HashMD5Append    (pHashContextMD5   , poVerifyBuff, Read))
          if (pHashContextSHA256) CHK_EXIT (HashSHA256Append (pHashContextSHA256, poVerifyBuff, Read))
@@ -237,7 +263,7 @@ class t_OutputFileDD: public t_OutputFile
          oFile = -1;
          if (Res != 0)
          {
-            LOG_ERROR ("close failed, errno=%d '%s'", errno, ToolErrorTranslateErrno (errno))
+            LOG_ERROR ("[%s] Close failed, errno=%d '%s'", QSTR_TO_PSZ (poDevice->LinuxDevice), errno, ToolErrorTranslateErrno (errno))
             return ERROR_THREADWRITE_CLOSE_FAILED;
          }
 
@@ -267,25 +293,30 @@ class t_OutputFileDD: public t_OutputFile
       }
 
    private:
-      QStringList oFilenameList;
-      int         oFile;
-      time_t      oLastCheckT; // Only used when cloning, see above
-      QString     oFilename;
-      void      *poVerifyBuff;
-      t_pDevice  poDevice;
-      int         oSplitNr;
-      int         oSplitNrDecimals;
-      int         oFileFlags;
-      t_uint64    oRemainingFileSize;
-      int         oCurrentVerifyFileNr;
+      QStringList       oFilenameList;
+      int               oFile;
+      time_t            oLastCheckT; // Only used when cloning, see above
+      QString           oFilename;
+      void            *poVerifyBuff;
+      t_pDevice        poDevice;
+      int               oSplitNr;
+      int               oSplitNrDecimals;
+      int               oFileFlags;
+      t_uint64          oRemainingFileSize;
+      int               oCurrentVerifyFileNr;
+      t_HashContextMD5  oCurrentHashContextMD5;
 };
 
+// ------------------------------------------------------------------------------------------------
+//                                           EWF FORMAT
+// ------------------------------------------------------------------------------------------------
+
 #define CHK_LIBEWF(Fn)                                                 \
 {                                                                      \
    int rclibewf = (Fn);                                                \
    if (rclibewf != 1)                                                  \
    {                                                                   \
-      LOG_ERROR ("Error in libewf function: %s, rc=%d", #Fn, rclibewf) \
+      LOG_ERROR ("[%s] Error in libewf function: %s, rc=%d", QSTR_TO_PSZ (poDevice->LinuxDevice), #Fn, rclibewf) \
       return ERROR_THREADWRITE_LIBEWF_FAILED;                          \
    }                                                                   \
 }
@@ -293,7 +324,8 @@ class t_OutputFileDD: public t_OutputFile
 class t_OutputFileEWF: public t_OutputFile
 {
    public:
-      t_OutputFileEWF (void)
+      t_OutputFileEWF (t_ThreadWrite *pThreadWrite):
+          t_OutputFile (pThreadWrite)
       {
          poFile                  = NULL;
          poDevice                = NULL;   //lint -esym(613,t_OutputFileEWF::poDevice)  Prevent lint from telling us about possible null pointers in the following code
@@ -342,10 +374,13 @@ class t_OutputFileEWF: public t_OutputFile
                poImageFilenameArr[i] = (char *) malloc (strlen(pAsciiFileName)+1);
                strcpy (poImageFilenameArr[i], pAsciiFileName);
             }
+
+            CHK_EXIT (poThreadWrite->SetDebugMessage ("Verification: Calling libewf_open"))
             pFile = libewf_open (poImageFilenameArr, oImageFileCount, libewf_get_flags_read());
+            CHK_EXIT (poThreadWrite->SetDebugMessage ("Verification: Returning from libewf_open"))
             if (pFile == NULL)
             {
-               LOG_INFO ("Error while reopening EWF for verification. The files are:")
+               LOG_INFO ("[%s] Error while reopening EWF for verification. The files are:", QSTR_TO_PSZ (poDevice->LinuxDevice))
                for (i=0; i<oImageFileCount; i++)
                   LOG_INFO ("%s", poImageFilenameArr[i])
                return ERROR_THREADWRITE_OPEN_FAILED;
@@ -360,16 +395,16 @@ class t_OutputFileEWF: public t_OutputFile
                return ERROR_THREADWRITE_OPEN_FAILED;
 
             #define STR_AND_LEN(QStr) QStr.toAscii().data(), strlen(QStr.toAscii().data())
-            libewf_set_notify_values(stderr, 1);
 
             CHK_LIBEWF (libewf_set_format             (pFile, (uint8_t) CONFIG (EwfFormat)))
             CHK_LIBEWF (libewf_set_media_size         (pFile, pDevice->Size))
             CHK_LIBEWF (libewf_set_bytes_per_sector   (pFile, (unsigned int) pDevice->SectorSize))
-            CHK_LIBEWF (libewf_set_sectors_per_chunk  (pFile, 64))
+            CHK_LIBEWF (libewf_set_sectors_per_chunk  (pFile, pDevice->FifoBlockSize / pDevice->SectorSize))
             CHK_LIBEWF (libewf_set_segment_file_size  (pFile, pDevice->Acquisition.SplitFileSize))
-            CHK_LIBEWF (libewf_set_compression_values (pFile, CONFIG (EwfCompression), 1))
+            CHK_LIBEWF (libewf_set_compression_values (pFile, CONFIG (EwfCompression), 0)) // last parameter must be set to 0, else, only empty-block compression is done
             CHK_LIBEWF (libewf_set_media_type         (pFile, pDevice->Removable ? LIBEWF_MEDIA_TYPE_REMOVABLE : LIBEWF_MEDIA_TYPE_FIXED))
             CHK_LIBEWF (libewf_set_volume_type        (pFile, LIBEWF_VOLUME_TYPE_PHYSICAL))
+            CHK_LIBEWF (libewf_set_error_granularity  (pFile, 1))
 
             CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"case_number"    , STR_AND_LEN(pDevice->Acquisition.CaseNumber    )))
             CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"description"    , STR_AND_LEN(pDevice->Acquisition.Description   )))
@@ -379,6 +414,12 @@ class t_OutputFileEWF: public t_OutputFile
 
             CHK (ToolSysInfoUname (Uname))
             GuymagerVersion = QString("guymager ") + QString(pCompileInfoVersion);
+            if (CONFIG (AvoidEncaseProblems))
+            {
+               GuymagerVersion = GuymagerVersion.left (THREADWRITE_ENCASE_MAXLEN_IMAGERVERSION);
+               Uname           = Uname          .left (THREADWRITE_ENCASE_MAXLEN_OSVERSION    );
+            }
+
             CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"acquiry_operating_system", STR_AND_LEN(Uname)))
             CHK_LIBEWF (libewf_set_header_value (pFile, (char *)"acquiry_software_version", STR_AND_LEN(GuymagerVersion)))
 
@@ -413,14 +454,14 @@ class t_OutputFileEWF: public t_OutputFile
 
          if (Written != Size)
          {
-            LOG_ERROR ("Written %d/%d bytes", Written, Size)
+            LOG_ERROR ("[%s] Written %d/%d bytes", QSTR_TO_PSZ (poDevice->LinuxDevice), Written, Size)
             return ERROR_THREADWRITE_WRITE_FAILED;
          }
 
          return NO_ERROR;
       }
 
-      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos)
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, t_Device::t_ImageFileHashList &ImageFileHashList, quint64 *pPos)
       {
          quint64      Remaining;
          unsigned int ToRead;
@@ -432,13 +473,20 @@ class t_OutputFileEWF: public t_OutputFile
             poVerifyBuff = UTIL_MEM_ALLOC (poDevice->FifoBlockSize);
             if (poVerifyBuff == NULL)
                CHK (ERROR_THREADWRITE_MALLOC_FAILED);
+
+            for (int i=0; i<oImageFileCount; i++)
+               ImageFileHashList.append (new t_Device::t_ImageFileHash (poImageFilenameArr[i], NULL));  // No MD5 files hashes for EWF files generated by libewf
          }
          Remaining = poDevice->Size - *pPos;
          ToRead = GETMIN (Remaining, poDevice->FifoBlockSize);
+
+         CHK_EXIT (poThreadWrite->SetDebugMessage ("Verification: Calling libewf_read_buffer"))
          Read = libewf_read_buffer (poFile, poVerifyBuff, ToRead);
+         CHK_EXIT (poThreadWrite->SetDebugMessage ("Verification: Returning from libewf_read_buffer"))
+
          if (Read != (ssize_t)ToRead)
          {
-            LOG_INFO ("Reading from EWF file failed (%zu)", Read);
+            LOG_INFO ("[%s] Reading from EWF file failed (%zu)", QSTR_TO_PSZ (poDevice->LinuxDevice), Read);
             return ERROR_THREADWRITE_VERIFY_FAILED;
          }
          if (pHashContextMD5)    CHK_EXIT (HashMD5Append    (pHashContextMD5   , poVerifyBuff, ToRead))
@@ -451,19 +499,52 @@ class t_OutputFileEWF: public t_OutputFile
 
       APIRET Close (void)
       {
-         int rc;
-         int i;
+         QList<quint64> BadSectors;
+         quint64        i, Count;
+         quint64        From, To, Next;
+         int            rc;
+         int            j;
 
          if (poFile == NULL)
             CHK (ERROR_THREADWRITE_NOT_OPENED)
 
+         // Write bad sector list
+         // ---------------------
+         if (!oVerification)
+         {
+            CHK (poDevice->GetBadSectors (BadSectors, false))
+            Count = BadSectors.count();
+            if (Count)
+            {
+               i = 0;
+               while (i<Count)
+               {
+                  From = BadSectors.at(i++);
+                  To   = From;
+                  while (i < Count)
+                  {
+                     Next = BadSectors.at(i);
+                     if (Next != To+1)
+                         break;
+                     To = Next;
+                     i++;
+                  }
+                  CHK_LIBEWF (libewf_add_acquiry_error(poFile, From, To - From + 1))
+               }
+            }
+         }
+
+         // Write hash
+         // ----------
          if (!oVerification && poDevice->HasCompressionThreads() && poDevice->Acquisition.CalcMD5)
             CHK_LIBEWF (libewf_set_md5_hash (poFile, (uint8_t*)&poDevice->MD5Digest, HASH_MD5_DIGEST_LENGTH))
 
+         // Close and cleanup
+         // -----------------
          rc = libewf_close (poFile);
          if (rc != 0)
          {
-            LOG_ERROR ("Error in libewf function: libewf_close, rc=%d", rc)
+            LOG_ERROR ("[%s] Error in libewf function: libewf_close, rc=%d", QSTR_TO_PSZ (poDevice->LinuxDevice), rc)
             return ERROR_THREADWRITE_LIBEWF_FAILED;
          }
 
@@ -473,8 +554,8 @@ class t_OutputFileEWF: public t_OutputFile
             poVerifyBuff = NULL;
          }
 
-         for (i=0; i<oImageFileCount; i++)
-            free (poImageFilenameArr[i]);
+         for (j=0; j<oImageFileCount; j++)
+            free (poImageFilenameArr[j]);
          free (poImageFilenameArr);
 
          poFile = NULL;
@@ -501,11 +582,15 @@ class t_OutputFileEWF: public t_OutputFile
       bool            oHasCompressionThreads;
 };
 
+// ------------------------------------------------------------------------------------------------
+//                                           AAFF FORMAT
+// ------------------------------------------------------------------------------------------------
 
-class t_OutputFileAFF: public t_OutputFile
+class t_OutputFileAAFF: public t_OutputFile
 {
    public:
-      t_OutputFileAFF (void) :
+      t_OutputFileAAFF (t_ThreadWrite *pThreadWrite) :
+         t_OutputFile          (pThreadWrite),
          poFile                (NULL ),
          poDevice              (NULL ),
          poVerifyBuff          (NULL ),
@@ -514,10 +599,10 @@ class t_OutputFileAFF: public t_OutputFile
       {
       }
 
-      ~t_OutputFileAFF (void)
+      ~t_OutputFileAAFF (void)
       {
-         if (t_OutputFileAFF::Opened())
-            (void) t_OutputFileAFF::Close();
+         if (t_OutputFileAAFF::Opened())
+            (void) t_OutputFileAAFF::Close();
       } //lint !e1740
 
       APIRET Open (t_pDevice pDevice, bool Verify)
@@ -540,16 +625,21 @@ class t_OutputFileAFF: public t_OutputFile
 
          if (oVerification)
          {
-            rc = AaffOpen (&pFile, QSTR_TO_PSZ(FileName));
+            rc = AaffOpen (&pFile, QSTR_TO_PSZ(FileName), pDevice->Size);
             if (rc)
             {
-               LOG_INFO ("AFF image verification failed: %s", ToolErrorMessage (rc))
+               LOG_INFO ("[%s] AFF image verification failed: %s", QSTR_TO_PSZ (poDevice->LinuxDevice), ToolErrorMessage (rc))
                return ERROR_THREADWRITE_VERIFY_FAILED;
             }
          }
          else
          {
-            CHK (AaffOpen (&pFile, QSTR_TO_PSZ(FileName), pDevice->Size, pDevice->SectorSize, pDevice->FifoBlockSize))
+            rc = AaffOpen (&pFile, QSTR_TO_PSZ(FileName), pDevice->Size, pDevice->SectorSize, pDevice->FifoBlockSize);
+            if (rc)
+            {
+               LOG_INFO ("[%s] Opening AFF image for writing failed: %s", QSTR_TO_PSZ (poDevice->LinuxDevice), ToolErrorMessage (rc))
+               return ERROR_THREADWRITE_OPEN_FAILED;
+            }
 
             rc = ToolSysInfoGetMacAddr (&MacAddr);
             if (rc == TOOLSYSINFO_ERROR_NO_ADDR)
@@ -586,6 +676,7 @@ class t_OutputFileAFF: public t_OutputFile
       //lint -save -esym(613,t_OutputFileAFF::poDevice)   Possible use of null pointer
       APIRET Write (t_pFifoBlock pFifoBlock)
       {
+         APIRET rc;
          if (!oHasCompressionThreads) // Do preprocessing if not already done in compression threads
          {
             t_pFifoBlock pPreprocessBlock;
@@ -605,16 +696,21 @@ class t_OutputFileAFF: public t_OutputFile
             }
          }
 
-         CHK (AaffWrite (poFile, pFifoBlock->pAaffPreprocess, pFifoBlock->Buffer, pFifoBlock->DataSize))
+         rc = AaffWrite (poFile, pFifoBlock->pAaffPreprocess, pFifoBlock->Buffer, pFifoBlock->DataSize);
+         if (rc != NO_ERROR)
+            CHK (ERROR_THREADWRITE_WRITE_FAILED)
 
          return NO_ERROR;
       }
       //lint -restore
 
-      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, quint64 *pPos)
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, t_Device::t_ImageFileHashList &ImageFileHashList, quint64 *pPos)
       {
-         unsigned int DataLen = poDevice->FifoBlockSize;
-         APIRET       rc;
+         unsigned int    DataLen = poDevice->FifoBlockSize;
+         APIRET          rc;
+         QString         ImageFilename;
+         t_HashMD5Digest MD5Digest;
+         bool            MD5Valid;
 
          if (*pPos == 0)
          {
@@ -622,10 +718,10 @@ class t_OutputFileAFF: public t_OutputFile
             if (poVerifyBuff == NULL)
                CHK (ERROR_THREADWRITE_MALLOC_FAILED);
          }
-         rc = AaffReadNextPage (poFile, (unsigned char *) poVerifyBuff, &DataLen);
+         rc = AaffReadNextPage (poFile, (unsigned char *) poVerifyBuff, &DataLen, &ImageFilename, &MD5Digest, &MD5Valid);
          if (rc)
          {
-            LOG_INFO ("AFF image verification failed: %s", ToolErrorMessage (rc))
+            LOG_INFO ("[%s] AFF image verification failed: %s", QSTR_TO_PSZ (poDevice->LinuxDevice), ToolErrorMessage (rc))
             return ERROR_THREADWRITE_VERIFY_FAILED;
          }
 
@@ -634,6 +730,14 @@ class t_OutputFileAFF: public t_OutputFile
 
          *pPos += DataLen;
 
+         if (!ImageFilename.isEmpty())
+         {
+            QString MD5Str;
+
+            CHK (HashMD5DigestStr (&MD5Digest, MD5Str))
+            ImageFileHashList.append (new t_Device::t_ImageFileHash (ImageFilename, &MD5Digest, MD5Valid));
+         }
+
          return NO_ERROR;
       }
 
@@ -687,6 +791,194 @@ class t_OutputFileAFF: public t_OutputFile
       bool        oVerification;
 };
 
+// ------------------------------------------------------------------------------------------------
+//                                           AEWF FORMAT
+// ------------------------------------------------------------------------------------------------
+
+class t_OutputFileAEWF: public t_OutputFile
+{
+   public:
+      t_OutputFileAEWF (t_ThreadWrite *pThreadWrite) :
+         t_OutputFile           (pThreadWrite),
+         poFile                 (NULL ),
+         poDevice               (NULL ),
+         poVerifyBuff           (NULL ),
+          oHasCompressionThreads(false),
+          oVerification         (false)
+      {
+      }
+
+      ~t_OutputFileAEWF (void)
+      {
+         if (t_OutputFileAEWF::Opened())
+            (void) t_OutputFileAEWF::Close();
+      } //lint !e1740
+
+      APIRET Open (t_pDevice pDevice, bool Verify)
+      {
+         t_pAewf pFile = NULL;
+         QString  FileName;
+         QString  GuymagerVersion;
+         QString  Uname;
+
+         poDevice      = pDevice;
+         oVerification =  Verify;
+         oHasCompressionThreads = pDevice->HasCompressionThreads();
+
+         FileName = pDevice->Acquisition.ImagePath + pDevice->Acquisition.ImageFilename;
+         if (oVerification)
+         {
+            CHK (AewfOpen (&pFile, QSTR_TO_PSZ(FileName)))
+         }
+         else
+         {
+            CHK (ToolSysInfoUname (Uname))
+            GuymagerVersion = QString("guymager ") + QString(pCompileInfoVersion);
+            if (CONFIG (AvoidEncaseProblems))
+            {
+               GuymagerVersion = GuymagerVersion.left (THREADWRITE_ENCASE_MAXLEN_IMAGERVERSION);
+               Uname           = Uname          .left (THREADWRITE_ENCASE_MAXLEN_OSVERSION    );
+            }
+            CHK (AewfOpen (&pFile, QSTR_TO_PSZ(FileName), pDevice->Size, pDevice->Acquisition.SplitFileSize, pDevice->FifoBlockSize, pDevice->SectorSize,
+                                   pDevice->Removable ? AEWF_MEDIATYPE_REMOVABLE : AEWF_MEDIATYPE_FIXED,
+                                   AEWF_MEDIAFLAGS_PHYSICAL,
+                                   pDevice->Acquisition.Description, pDevice->Acquisition.CaseNumber, pDevice->Acquisition.EvidenceNumber,
+                                   pDevice->Acquisition.Examiner   , pDevice->Acquisition.Notes     , pDevice->Model                     ,
+                                   pDevice->SerialNumber           , GuymagerVersion                , Uname))
+         }
+         poFile = pFile; // Only set poFile at the very end, so the CompressionThreads won't use it until everything is initialised
+         return NO_ERROR;
+      }
+
+      APIRET Write (t_pFifoBlock pFifoBlock)
+      {
+         APIRET rc;
+
+         if (!oHasCompressionThreads) // Do preprocessing if not already done in compression threads
+         {
+            t_pFifoBlock pPreprocessBlock;
+
+            CHK_EXIT (t_Fifo::Create (poDevice->pFifoMemory, pPreprocessBlock, poDevice->FifoAllocBlockSize))
+            pPreprocessBlock->DataSize = pFifoBlock->DataSize;
+            CHK_EXIT (AewfPreprocess (poFile, &pPreprocessBlock->pAewfPreprocess, pFifoBlock      ->Buffer, pFifoBlock      ->DataSize,
+                                                                                  pPreprocessBlock->Buffer, pPreprocessBlock->BufferSize))
+            if (pPreprocessBlock->pAewfPreprocess->Compressed)
+            {
+               CHK_EXIT (t_Fifo::Destroy (poDevice->pFifoMemory, pFifoBlock))
+               pFifoBlock = pPreprocessBlock;
+            }
+            else
+            {
+               pFifoBlock->pAewfPreprocess = pPreprocessBlock->pAewfPreprocess;
+               CHK_EXIT (t_Fifo::Destroy (poDevice->pFifoMemory, pPreprocessBlock))
+            }
+         }
+         rc = AewfWrite (poFile, pFifoBlock->pAewfPreprocess, pFifoBlock->Buffer, pFifoBlock->pAewfPreprocess->DataLenOut);
+         if (rc != NO_ERROR)
+            CHK (ERROR_THREADWRITE_WRITE_FAILED)
+
+         return NO_ERROR;
+      }
+      //lint -restore
+
+   private:
+      APIRET ProcessUnit (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, t_Device::t_ImageFileHashList &ImageFileHashList, quint64 *pPos, bool *pFinished)
+      {
+         QString         SegmentFilename;
+         QString         MD5Str;
+         t_HashMD5Digest MD5Digest;
+         bool            MD5Valid;
+         unsigned int    DataLen;
+         APIRET          rc;
+
+         DataLen = poDevice->FifoAllocBlockSize;
+         rc = AewfReadNextChunk (poFile, (unsigned char *) poVerifyBuff, &DataLen, &SegmentFilename, &MD5Digest, &MD5Valid, pFinished);
+         if (rc)
+         {
+            LOG_INFO ("[%s] AEF image verification failed: %s", QSTR_TO_PSZ (poDevice->LinuxDevice), ToolErrorMessage (rc))
+            return ERROR_THREADWRITE_VERIFY_FAILED;
+         }
+
+         if (DataLen)
+         {
+            if (pHashContextMD5)    CHK_EXIT (HashMD5Append    (pHashContextMD5   , poVerifyBuff, DataLen))
+            if (pHashContextSHA256) CHK_EXIT (HashSHA256Append (pHashContextSHA256, poVerifyBuff, DataLen))
+            *pPos += DataLen;
+         }
+
+         if (!SegmentFilename.isEmpty())
+         {
+            CHK (HashMD5DigestStr (&MD5Digest, MD5Str))
+            ImageFileHashList.append (new t_Device::t_ImageFileHash (SegmentFilename, &MD5Digest, MD5Valid));
+         }
+         return NO_ERROR;
+      }
+
+   public:
+      APIRET Verify (t_pHashContextMD5 pHashContextMD5, t_pHashContextSHA256 pHashContextSHA256, t_Device::t_ImageFileHashList &ImageFileHashList, quint64 *pPos)
+      {
+         bool Finished;
+
+         if (*pPos == 0)
+         {
+            poVerifyBuff = UTIL_MEM_ALLOC (poDevice->FifoAllocBlockSize);
+            if (poVerifyBuff == NULL)
+               CHK (ERROR_THREADWRITE_MALLOC_FAILED);
+         }
+         CHK (ProcessUnit (pHashContextMD5, pHashContextSHA256, ImageFileHashList, pPos, &Finished))
+
+         if (*pPos >= poDevice->Size)  // If all data has been read keep calling
+         {                             // the processing function until it says it
+            while (!Finished)          // finished (see AewfReadNextChunk)
+               CHK (ProcessUnit (pHashContextMD5, pHashContextSHA256, ImageFileHashList, pPos, &Finished))
+         }
+         return NO_ERROR;
+      }
+
+      APIRET Close (void)
+      {
+         QList<quint64> BadSectors;
+
+         if (poFile == NULL)
+            CHK (ERROR_THREADWRITE_NOT_OPENED)
+
+         if (oVerification)
+         {
+            CHK (AewfClose (&poFile))
+         }
+         else
+         {
+            CHK (poDevice->GetBadSectors (BadSectors, false))
+            CHK (AewfClose (&poFile, BadSectors, (unsigned char*)&poDevice->MD5Digest, (unsigned char*)&poDevice->SHA256Digest))
+         }
+         poFile = NULL;
+
+         return NO_ERROR;
+      }
+      //lint -restore
+
+      void *GetFileHandle (void)
+      {
+         return poFile;
+      }
+
+      bool Opened (void)
+      {
+         return (poFile != NULL);
+      }
+
+   private:
+      t_pAewf    poFile;
+      t_pDevice  poDevice;
+      void      *poVerifyBuff;
+      bool        oHasCompressionThreads;
+      bool        oVerification;
+};
+
+
+// ------------------------------------------------------------------------------------------------
+//                                           WRITE THREAD
+// ------------------------------------------------------------------------------------------------
 
 class t_ThreadWriteLocal
 {
@@ -823,7 +1115,8 @@ void t_ThreadWrite::run (void)
    quint64        Written   = 0;
    APIRET         rc;
 
-   LOG_INFO ("Acquisition of %s: Write thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   LOG_INFO ("[%s] Write thread started", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+   CHK_EXIT (SetDebugMessage ("Start run function"))
 
    pDevice = pOwn->pDevice;
    pDevice->SetCurrentWritePos (0LL);
@@ -832,16 +1125,18 @@ void t_ThreadWrite::run (void)
 
    switch (pDevice->Acquisition.Format)
    {
-      case t_File::DD:  pOutputFile = new t_OutputFileDD;  break;
-      case t_File::EWF: pOutputFile = new t_OutputFileEWF; break;
-      case t_File::AFF: pOutputFile = new t_OutputFileAFF; break;
+      case t_File::EWF : if (CONFIG(EwfFormat) == t_File::AEWF)
+                              pOutputFile = new t_OutputFileAEWF(this);
+                         else pOutputFile = new t_OutputFileEWF (this); break;
+      case t_File::DD  :      pOutputFile = new t_OutputFileDD  (this); break;
+      case t_File::AAFF:      pOutputFile = new t_OutputFileAAFF(this); break;
       default: CHK_EXIT (ERROR_THREADWRITE_INVALID_FORMAT)
    }
 
    rc = pOutputFile->Open (pDevice, false);
    if (rc == ERROR_THREADWRITE_OPEN_FAILED)
    {
-      LOG_INFO ("Could not open destination file %s", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
+      LOG_INFO ("[%s] Could not open destination file %s", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
       pDevice->AbortReason  = t_Device::ThreadWriteWriteError;
       pDevice->AbortRequest = true;
    }
@@ -859,13 +1154,15 @@ void t_ThreadWrite::run (void)
       if (*(pOwn->pSlowDownRequest))
          msleep (THREADWRITE_SLOWDOWN_SLEEP);
 
+      CHK_EXIT (SetDebugMessage ("Wait for block"))
       CHK_EXIT (pDevice->pFifoWrite->Get (pFifoBlock))
+      CHK_EXIT (SetDebugMessage ("Process block"))
       if (pFifoBlock)
       {
 //         t_Fifo::LogBlock (pDevice->pFifoMemory, pFifoBlock, 'w');
          if (pFifoBlock->Nr != Blocks)
          {
-            LOG_ERROR ("Fifo block number out of sequence. Expected: %Ld Received: %Ld", Blocks, pFifoBlock->Nr)
+            LOG_ERROR ("[%s] Fifo block number out of sequence. Expected: %Ld Received: %Ld", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks, pFifoBlock->Nr)
 //            t_Fifo::LogBlock (pDevice->pFifoMemory, pFifoBlock, 'e');
             CHK_EXIT (ERROR_THREADWRITE_OUT_OF_SEQUENCE_BLOCK)
         }
@@ -877,8 +1174,8 @@ void t_ThreadWrite::run (void)
              (rc == ERROR_THREADWRITE_OPEN_FAILED))
          {
             const char *pAction = (rc == ERROR_THREADWRITE_WRITE_FAILED) ? "write to" : "open";
-            LOG_ERROR ("Could not %s destination file %s", pAction, QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
-            LOG_INFO ("Last block sizes: %d - %d - %zd ", pFifoBlock->BufferSize, pFifoBlock->DataSize, pFifoBlock->EwfDataSize)
+            LOG_ERROR ("[%s] Could not %s destination file %s", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), pAction, QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
+            LOG_INFO  ("[%s] Last block sizes: %d - %d - %zd ", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), pFifoBlock->BufferSize, pFifoBlock->DataSize, pFifoBlock->EwfDataSize)
             pDevice->AbortReason  = t_Device::ThreadWriteWriteError;
             pDevice->AbortRequest = true;
          }
@@ -896,14 +1193,14 @@ void t_ThreadWrite::run (void)
       }
       else
       {
-         LOG_INFO ("Dummy block")
+         LOG_INFO ("[%s] Dummy block", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
          Finished = true;
       }
    }
 
    // Wait until file handle released and close it
    // --------------------------------------------
-   LOG_INFO ("Waiting for all other threads using the file handle to finish")
+   LOG_INFO ("[%s] Waiting for all other threads using the file handle to finish", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
    do
    {
       bool AskedForRelease = false;
@@ -922,7 +1219,7 @@ void t_ThreadWrite::run (void)
       }
    } while (!FileHandleReleased);
 
-   LOG_INFO ("Closing output file")
+   LOG_INFO ("[%s] Closing output file", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
    if (pOwn->pOutputFile->Opened())
    {
       rc = pOwn->pOutputFile->Close ();
@@ -951,12 +1248,13 @@ void t_ThreadWrite::run (void)
            CHK_EXIT (HashSHA256Init (pHashContextSHA256))
       else pHashContextSHA256 = NULL;
 
-      LOG_INFO ("Reopening output file for verification")
-
+      LOG_INFO ("[%s] Reopening image file for verification", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
+      CHK_EXIT (SetDebugMessage ("pOutputFile->Open verification"))      
       rc = pOutputFile->Open (pDevice, true);
+      CHK_EXIT (SetDebugMessage ("Returning from pOutputFile->Open"))
       if (rc == ERROR_THREADWRITE_OPEN_FAILED)
       {
-         LOG_INFO ("Could not open destination file %s for verification", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
+         LOG_INFO ("[%s] Could not open image file %s for verification", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
          pDevice->AbortReason  = t_Device::ThreadWriteVerifyError;
          pDevice->AbortRequest = true;
       }
@@ -968,10 +1266,10 @@ void t_ThreadWrite::run (void)
       Finished = false;
       while (!Finished && !pDevice->AbortRequest)
       {
-         rc = pOwn->pOutputFile->Verify (pHashContextMD5, pHashContextSHA256, &Pos);
+         rc = pOwn->pOutputFile->Verify (pHashContextMD5, pHashContextSHA256, pDevice->ImageFileHashList, &Pos);
          if (rc == ERROR_THREADWRITE_VERIFY_FAILED)
          {
-            LOG_ERROR ("Could not verify image %s", QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
+            LOG_ERROR ("[%s] Could not verify image %s", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), QSTR_TO_PSZ (pOwn->pDevice->Acquisition.ImageFilename))
             pDevice->AbortReason  = t_Device::ThreadWriteVerifyError;
             pDevice->AbortRequest = true;
          }
@@ -987,7 +1285,7 @@ void t_ThreadWrite::run (void)
             }
          }
       }
-      LOG_INFO ("Verification finished, closing output file")
+      LOG_INFO ("[%s] Verification finished, closing output file", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
       if (pOwn->pOutputFile->Opened())
       {
          rc = pOwn->pOutputFile->Close ();
@@ -1010,7 +1308,8 @@ void t_ThreadWrite::run (void)
       CHK_EXIT (DeleteImageFiles (true))
    }
 
-   LOG_INFO ("Write thread exits now (device %s, %Ld blocks processed, %Ld bytes written to output file)", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks, pDevice->GetCurrentWritePos ())
+   LOG_INFO ("[%s] Write thread exits now (%Ld blocks processed, %Ld bytes written to output file)", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice), Blocks, pDevice->GetCurrentWritePos ())
+   CHK_EXIT (SetDebugMessage ("Exit run function"))
 }
 //lint -restore
 
@@ -1032,7 +1331,7 @@ static APIRET DeleteImageFiles0 (t_pDevice pDevice, const QDir &Dir, const QStri
       if (Success)
            Info += "successfull";
       else Info += "could not be deleted";
-      LOG_INFO ("%s", QSTR_TO_PSZ(Info))
+      LOG_INFO ("[%s] %s", QSTR_TO_PSZ (pDevice->LinuxDevice), QSTR_TO_PSZ(Info))
    }
 
    return NO_ERROR;
@@ -1047,13 +1346,13 @@ APIRET t_ThreadWrite::DeleteImageFiles (bool AlsoDeleteInfoFile)
 
    if (!pDevice->Acquisition.Clone)
    {
-      LOG_INFO ("Deleting existing image files of the same name")
+      LOG_INFO ("[%s] Deleting existing image files of the same name", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
       CHK (t_File::GetFormatExtension (pDevice, &ExtensionImage))
       CHK (DeleteImageFiles0 (pDevice, DirImage, QStringList(pDevice->Acquisition.ImageFilename + ExtensionImage)))
    }
    if (AlsoDeleteInfoFile)
    {
-      LOG_INFO ("Deleting existing info file of the same name")
+      LOG_INFO ("[%s] Deleting existing info file of the same name", QSTR_TO_PSZ (pOwn->pDevice->LinuxDevice))
       CHK (DeleteImageFiles0 (pDevice, DirImage, QStringList(pDevice->Acquisition.InfoFilename + t_File::pExtensionInfo)))
    }
    CHK (pDevice->SetMessage (QString()))
diff --git a/threadwrite.h b/threadwrite.h
index 4c43e94..1d63f23 100644
--- a/threadwrite.h
+++ b/threadwrite.h
@@ -9,7 +9,7 @@
 //  Module:         Thread for writing data.
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -29,7 +29,7 @@
 #ifndef __THREADWRITE_H__
 #define __THREADWRITE_H__
 
-#include <QThread>   //lint !e537 Repeated include
+#include "thread.h"
 
 #ifndef __DEVICE_H__
   #include "device.h"
@@ -38,7 +38,7 @@
 
 class t_ThreadWriteLocal;
 
-class t_ThreadWrite: public QThread
+class t_ThreadWrite: public t_Thread
 {
    Q_OBJECT
 
diff --git a/util.cpp b/util.cpp
index fd7acb6..2dd893e 100644
--- a/util.cpp
+++ b/util.cpp
@@ -9,7 +9,7 @@
 //  Module:         Different utility functions
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -33,6 +33,19 @@
 #include "config.h"
 #include "util.h"
 
+// ----------------
+//   Global vars
+// ----------------
+
+#define UTIL_ZEROBLOCK_MAXSIZE 65536
+
+char         *pUtilZeroBlock     = NULL;
+unsigned int   UtilZeroBlockSize = 0;
+
+// ----------------
+//     Functions
+// ----------------
+
 void *UtilMemAlloc (size_t Size, const char */*pFile*/, int /*Line*/)
 {
    return malloc(Size);
@@ -51,5 +64,67 @@ int UtilCalcDecimals (t_uint64 Value)
    return Str.length();
 }
 
+bool UtilIsZeroOld (unsigned char *pData, unsigned int DataLen)
+{
+   long long          *pBuff    = (long long *)pData;   //lint !e826   Suspicious pointer-to-pointer conversion
+   const unsigned int   CmpSize = sizeof (long long);   // 64 bit operations for optimal performance on amd64 processors
+
+   while (DataLen >= CmpSize)
+   {
+      if (*pBuff++)
+        return false;
+      DataLen -= CmpSize;
+   }
+
+   pData = (unsigned char *) pBuff;
+   while (DataLen--)
+   {
+      if (*pData++)
+         return false;
+   }
+
+   return true;
+}
+
+bool UtilIsZero (unsigned char *pData, unsigned int DataLen)
+{
+   unsigned int ToCompare;
+   unsigned int Remaining = DataLen;
+   bool         IsZero    = true;
+   
+   while (Remaining)
+   { 
+      ToCompare = GETMIN(Remaining, UtilZeroBlockSize);
+      IsZero = (memcmp (pData, pUtilZeroBlock, ToCompare) == 0);
+      if (!IsZero)
+         break;
+      Remaining -= ToCompare;
+   }
+   return IsZero;
+}
+
+unsigned int UtilGetMaxZcompressedBufferSize (unsigned int UncompressedBufferSize)
+{
+   return (UncompressedBufferSize * 1.001) + 12;
+}
 
 
+APIRET UtilInit (void)
+{   
+   int MaxFifoBockSize;
+   
+   MaxFifoBockSize = GETMAX(CONFIG(FifoBlockSizeEWF), CONFIG(FifoBlockSizeAFF));
+   
+   UtilZeroBlockSize = GETMIN(UTIL_ZEROBLOCK_MAXSIZE, MaxFifoBockSize);
+
+   pUtilZeroBlock = (char *) malloc (UtilZeroBlockSize);
+   memset(pUtilZeroBlock, 0, UtilZeroBlockSize);
+   
+   return NO_ERROR;
+}
+
+APIRET UtilDeInit (void)
+{
+   free (pUtilZeroBlock);
+   return NO_ERROR;
+}
diff --git a/util.h b/util.h
index b74b794..a2d7f71 100644
--- a/util.h
+++ b/util.h
@@ -9,7 +9,7 @@
 //  Module:         Different utility functions
 // ****************************************************************************
 
-// Copyright 2008, 2009, 2010 Guy Voncken
+// Copyright 2008, 2009, 2010, 2011 Guy Voncken
 //
 // This file is part of guymager.
 //
@@ -32,11 +32,17 @@
 void *UtilMemAlloc (size_t Size, const char *pFile, int Line);
 void  UtilMemFree  (void *pMem , const char *pFile, int Line);
 
-int UtilCalcDecimals (t_uint64 Value);
+int          UtilCalcDecimals (t_uint64 Value);
+bool         UtilIsZero       (unsigned char *pData, unsigned int DataLen);
+unsigned int UtilGetMaxZcompressedBufferSize (unsigned int UncompressedBufferSize);
 
 #define UTIL_MEM_ALLOC(Size) UtilMemAlloc (Size, __FILE__, __LINE__)
 #define UTIL_MEM_FREE(pMem)  UtilMemFree  (pMem, __FILE__, __LINE__)
 
+
+APIRET UtilInit   (void);
+APIRET UtilDeInit (void);
+
 #endif
 
 

-- 
debian-forensics/guymager



More information about the forensics-changes mailing list