Commits

Anonymous committed ee2bc2a

The file slice/splice project.
Unfortunately, this code base is full of bugs.

Comments (0)

Files changed (222)

+Bugs on 29th February (just before missed deadline on
+1st March).  The Slice program STILL isn't right!!!
+Arghhhhhh!
+
+-----------------------------------------------------
+Program is working safely for one disk, but that
+eliminates the point of the program doesn't it!
+
+Bug 0: Restart wizard should be automatically disabled
+when clicked. - FIXED: Added code in CEBackAndNextProcess()
+
+Bug 1: Page indicator is not updated when slice progress
+begins, because slice process begins when the page is
+switched it always says 3/4 not 4/4 for this page unless
+it fails.  - FIXED: Moved up call of UpdatePageStats()
+from after the code in SetWizPage() to the top (before
+the code for that change), therefore the call to
+SlicinigStatusController.Start() does not take control
+away from the page switcher until it's job is complete.
+
+Bug 2: Page four only seems to work properly when
+switched to the first time in each program execution,
+if done again the Splice copier works but the slicing
+doesn't happen. - FIXED: An obscure error which was a
+result of the drive letter component handing out 'A'
+once which was used to start a pathname and then using
+the number 1 the next time!
+
+Bug 3: Gauges (progress meters) don't work
+
+Bug 4: Hint mechanism sticks while slicing - FIXED:
+While the hint special effect is in operation (extending
+or retracting) it the messages are not processed, there
+is now no time delay in the height changes of the form,
+it still seems to move to the caller, I didn't think
+think it would but it still seems to work with less code
+and less chance for error.
+
+Bug 5: When doing two (or more disks) the second disk
+(or possibly the last, I don't know) writes past the
+end of the source file and eventually causes an access
+violation with a read of address 0xFFFFFFFF (or -1)
+at which point the window has to be closed to get out as
+the cancel button still works as a cancel and not a
+close, it keeps on prompting the user if they are sure.
+
+Bug 6: Prompt asking for disk displays scroll bars on
+the crappy system at the training center, I think I
+shall disable V.C.L.'s automatic scrolling support and
+do some maths to ensure that all components are on the
+prompt.
+
+Bug 7: Hint on cancel button stays the same even when it
+becomes close, shall I split them up and hide one and
+shoe the other to prevent these type of problems of one
+thinking it's the other?
+
+ - Overlord David Duncan Ross Palmer
+Part file format revisions
+--------------------------
+0 - Original as decided by Daybo Logic (Overlord David Duncan Ross
+Palmer)
+
+1 - Eliminated packets as thay were causing too many problems and had
+delayed the initial released (Overlord missed the March 1st 2000
+deadline).

Private/Bitmaps/DLogic/SmlLgo.bmp

Added
New image

Private/Bitmaps/PartDisk.bmp

Added
New image

Private/Bitmaps/SliDiag.bmp

Added
New image

Private/Bug list at pater's.txt

+Bug list - things found while at pater's place
+----------------------------------------------
+
+Two mistakes in the registry, firstly if the AppRootStr value is not set when the app starts
+then slice corrupts it. - FIXED
+
+Secondly, slice's root string should be kept as HKEY_LOCAL_MACHINE not HKEY_CURRENT_USER
+because the harddisk is a machine thing not a user thing and the app would have to
+be installed for every user (madness), must extant the class TSettingsStorage or
+whatever it's called to support user / machine difference.
+- FIXED

Private/CoreLib/BuffCpy.C

+/*
+Project: Slice/Splice
+Programmer: Overlord David Duncan Ross Palmer
+Date: 18th January 2000
+Last modified: 18th January 2000
+File: CoreLib\BuffCpy.C
+Description: Buffered copying (between part files and whole files)
+Language: ANSI C (1990)
+*/
+
+#include <Assert.H>
+#include <StdLib.H> /* for realloc() - (re)allocation of buffer) */
+#include <String.H> /* for memset() - Init of buffer */
+#include "Stds\DLStdInc.H" /* Daybo Logic standard inclusions */
+/* Pay special attention! Never include the Daybo Logic utilities because certain
+macros come into play which mean that malloc() might not act as it should and
+will terminate the program if it fails and that type of thing. */
+#ifdef __INC_DLUTILS_SDYNMEM_H
+#  error ("Never include Daybo Logic utilities in CoreLib\BuffCpy")
+#endif /*__INC_DLUTILS_SDYNMEM_H*/
+#pragma hdrstop
+
+#include "CoreLib\BuffCpy.H"
+
+/*------------------------------ PRIVATE DATA -----------------------------*/
+static struct
+{
+  size_t size; /* Size in bytes of copy buffer */
+  BYTE* PdynBuff; /* Pointer to dynamically allocated buffer */
+} CopyBuffer;
+/*-------------------------- PRIVATE FUNCTIONS ----------------------------*/
+static BOOL PossibleReAllocation(const size_t SuggestedBufferSize);
+static void File2Buffer(FILE* HFile, const BOOL ResetFilePos); /* Reads from the file into the buffer, if it hits the EOF in the file the buffer size is reduced to the size used, possibly released if nothing can be read */
+static BOOL Buffer2File(FILE* HFile, const BOOL ResetFilePos); /* Reads from the buffer into the file, if EOF is hit in target (probable disk full) the function returns TRUE meaning (EOF hit) */
+/*-------------------------------------------------------------------------*/
+short int corelib_BufferedCopy(FILE* HSource, FILE* HTarget, const size_t CopyBufferSize, const BOOL ResetFilePos[2])
+{
+  /* locals */
+  size_t sizeOfBuffer;
+  short int status = CORELIB_BUFFCPY_NORMAL; /* Status is return of function */
+
+  if (!PossibleReAllocation(CopyBufferSize)) return CORELIB_BUFFCPY_MALLOC; /* Ensure we have a copy buffer of at least 1Kb */
+  sizeOfBuffer = corelib_GetCurrentCopyBufferSize(); /* Get actual size of copy buffer */
+  while (1) /* Semi-premanent loop (must be broken from the inside) */
+  {
+    File2Buffer(HSource, ResetFilePos[0]); /* Read data into buffer */
+    if ( corelib_GetCurrentCopyBufferSize() < sizeOfBuffer ) /* Buffer size reduced? */
+      status = CORELIB_BUFFCPY_HITEOFSOURCE; /* Hit EOF in source */
+    Buffer2File(HTarget, ResetFilePos[1]); /* Write data to output file */
+    if ( feof(HTarget) )
+      status = CORELIB_BUFFCPY_HITEOFTARGET; /* Hit EOF in target (disk full?) */
+
+    if (status) /* A status level was set? */
+      break; /* Get out of the loop */
+  }
+
+  return status; /* Tell caller status */
+}
+/*-------------------------------------------------------------------------*/
+size_t corelib_AllocCopyBuffer(size_t RequestedSize)
+{
+  do
+  {
+    CopyBuffer.PdynBuff = (BYTE*)realloc( CopyBuffer.PdynBuff, RequestedSize ); /* Attempt to allocate the buffer or resize one which is previously allocated */
+    if (!CopyBuffer.PdynBuff) /* Failed to allocated the buffer as requested? */
+    {
+      size_t R = (RequestedSize % 1024); /* Remainder of RequestedSize modulus 1 Kb */
+      if ( R != 0 ) /* Not a multiple of K requested! */
+      {
+        if (RequestedSize >= R) RequestedSize -= R; /* Round down to nearest Kb */
+      }
+      if ( RequestedSize >= (size_t)1024 ) /* Over a K left? (make sure it doesn't underrun) */
+        RequestedSize -= (size_t)1024; /* Decrease request by 1 Kb */
+    }
+  } while (!CopyBuffer.PdynBuff && RequestedSize); /* Continue until allocated or no request left */
+
+  if (CopyBuffer.PdynBuff) /* Allocation / reallocation OK? */
+  {
+    CopyBuffer.size = RequestedSize; /* Record size in buffer information */
+  }
+  else /* The allocation failed due to memory shortage */
+  {
+    CopyBuffer.size ^= CopyBuffer.size; /* Record size as zero */
+  }
+  return CopyBuffer.size; /* Tell caller size of buffer */
+}
+/*-------------------------------------------------------------------------*/
+size_t corelib_GetCurrentCopyBufferSize()
+{
+  return CopyBuffer.size;
+}
+/*-------------------------------------------------------------------------*/
+BOOL corelib_ReleaseCopyBuffer()
+{
+  if (corelib_GetCurrentCopyBufferSize()) /* Buffer allocated? */
+  {
+    assert(CopyBuffer.PdynBuff); /* DEBUG: There must be a pointer to memoy to free! */
+    free(CopyBuffer.PdynBuff); /* Release the buffer */
+    CopyBuffer.PdynBuff = NULL; /* Delete pointer (probally just paranoia) */
+    CopyBuffer.size ^= CopyBuffer.size; /* Record no size of no buffer, nice */
+    return TRUE; /* Done */
+  }
+  assert(!CopyBuffer.PdynBuff); /* DEBUG: There should be no buffer if there was no size */
+  return FALSE; /* There was no buffer to free */
+}
+/*-------------------------------------------------------------------------*/
+BOOL corelib_WipeCopyBuffer()
+{
+  size_t bufferSize = corelib_GetCurrentCopyBufferSize(); /* Get the size of the current copy buffer */
+
+  if (bufferSize) /* There is a copy buffer? */
+  {
+    memset(CopyBuffer.PdynBuff, 0, bufferSize); /* Init the buffer */
+    return TRUE; /* Yes, me olde son! */
+  }
+  return FALSE; /* No, there was no buffer to work on */
+}
+/*-------------------------------------------------------------------------*/
+static BOOL PossibleReAllocation(const size_t SuggestedBufferSize)
+{
+  if (corelib_GetCurrentCopyBufferSize() && !SuggestedBufferSize) /* Current buffer and no suggestion */
+    return TRUE;
+  if (!SuggestedBufferSize) return FALSE; /* No buffer and no suggestion? */
+  if (corelib_AllocCopyBuffer(SuggestedBufferSize)) /* Allocate buffer */
+    return TRUE; /* Done */
+  return FALSE; /* Real memory shortage (couldn't even allocate minimum buffer) */
+}
+/*-------------------------------------------------------------------------*/
+static void File2Buffer(FILE* HFile, const BOOL ResetFilePos)
+{
+  if (HFile && corelib_GetCurrentCopyBufferSize())
+  {
+    size_t currentBuffPos = 0; /* Current position reading buffer */
+    long origPos; /* Original file pointer position */
+
+    if (ResetFilePos) /* Should the file position be saved so that it may be restored later */
+      origPos = ftell(HFile); /* Save current file position */
+
+    corelib_WipeCopyBuffer();
+    while (1) /* Semi-permanent loop */
+    {
+      BYTE* targetByte = CopyBuffer.PdynBuff + currentBuffPos; /* Calculate pointer to buffer position */
+      if ( fread(&targetByte, sizeof(BYTE), 1, HFile) < 1) /* Read from file into buffer, one byte */
+      {
+        /* Hit EOF in the file to read from,
+        /* The buffer must be truncated */
+        corelib_AllocCopyBuffer(currentBuffPos); /* Truncate the buffer to this position */
+        break; /* Get out here */
+      }
+      /* Test if reached end of buffer */
+      if (currentBuffPos == CopyBuffer.size - 1) /* End of buffer position! */
+        break; /* Don't try to copy any more into the buffer */
+    }
+
+    if (ResetFilePos && origPos >= 0) /* Should the old file position be restored? */
+    {
+      rewind(HFile);
+      fseek(HFile, origPos, SEEK_SET); /* Restore file pointer */
+    }
+  }
+}
+/*-------------------------------------------------------------------------*/
+static BOOL Buffer2File(FILE* HFile, const BOOL ResetFilePos)
+{
+  if ( corelib_GetCurrentCopyBufferSize() && HFile )
+  {
+    long origPos; /* Stores original position of file pointer */
+    size_t currentBuffPos = 0; /* Current position in copy buffer */
+
+    if (ResetFilePos) /* Should store file position so that it may be restored later? */
+      origPos = ftell(HFile); /* Store file pos before we move it */
+
+    while (1) /* Semi-permanent loop */
+    {
+      BYTE* sourceByte = CopyBuffer.PdynBuff + currentBuffPos; /* Calculate pointer to buffer position */
+      if ( fwrite(&sourceByte, sizeof(BYTE), 1, HFile) < 1) /* Write one byte from the buffer to the file */
+      {
+        /* Hit EOF in the file to write to, return TRUE (hit EOF) to caller */
+        return TRUE;
+      }
+      /* Test if reached end of buffer */
+      if (currentBuffPos == CopyBuffer.size - 1) /* End of buffer position! */
+        break; /* Don't try to read any further from the buffer */
+    }
+
+    if (ResetFilePos && origPos >= 0) /* Should the old file position be restored? */
+    {
+      rewind(HFile);
+      fseek(HFile, origPos, SEEK_SET); /* Restore file pointer */
+    }
+  }
+
+  return FALSE; /* EOF has not yet been reached in target file */
+}
+/*-------------------------------------------------------------------------*/

Private/CoreLib/BuffCpy.h

+#ifndef __INC_CORELIB_BUFFCPY_H
+#define __INC_CORELIB_BUFFCPY_H
+#include "Headers\BeginCH.H"
+/*-------------------------------------------------------------------------*/
+/* Possible status returns (or errors): */
+#define CORELIB_BUFFCPY_NORMAL        (0) /* Normal result, ignore */
+#define CORELIB_BUFFCPY_HITEOFSOURCE  (1) /* Hit EOF in source, normal ending */
+#define CORELIB_BUFFCPY_HITEOFTARGET  (2) /* Hit EOF in target, disk full? */
+#define CORELIB_BUFFCPY_MALLOC        (3) /* Memory allocation error (copy buffer), free up some memory or decrease buffer size) */
+short int corelib_BufferedCopy(FILE* HSource, FILE* HTarget, const size_t CopyBufferSize, const BOOL ResetFilePos[2]);
+/* Description of parameters for corelib_BufferedCopy() :
+HSource - Handle to source file (starts copy from this at the current position)
+HTarget - Handle to target file (starts copying to this at the current position)
+CopyBufferSize - Size of the buffer to copy with (should be reasonable and certainly never exceed the physical memory size, if too small copying becomes slow though
+ResetFilePos[0] - Should the file pointer be restored for the source file?
+ResetFilePos[1] - Should the file pointer be restored for the target file?
+
+This function automatically deals with the copy buffer and always releases
+the buffer after it has been called.  If the caller did allocate the
+buffer CopyBufferSize may be zero, normally CopyBufferSize being zero
+would cause CORELIB_BUFFCPY_MALLOC */
+
+size_t corelib_AllocCopyBuffer(size_t RequestedSize);
+/* Allocates the copy buffer, returns zero if the copy buffer could not
+be allocated, the function is start and if the allocation fails it reduces
+the request until the allocation is successful.  The true size of the copy
+buffer (usually RequestedSize unless low on heap) is returned to the caller.
+The copy buffer's true address is held internally in this module and is
+never disclosed to callers.  Calling this function is not required, if the
+caller has not done it it will automatically be handled by BufferedCopy(), the
+only reason it is here is so that callers may know the size of the copy
+buffer before calling BufferedCopy().  If the buffer was already allocated
+it is reallocated and possibly relocated.  By never disclosing the true
+address of the buffer to the caller the reallocation may lead to relocation
+which the caller need never worry about.  If allocations fail and the smart
+functionallity kicks in the buffer will be a multiple of 1Kb */
+
+size_t corelib_GetCurrentCopyBufferSize(void);
+/* Returns the size of the currently allocated internal copy buffer,
+or zero if there is no copy buffer allocated. */
+
+BOOL corelib_ReleaseCopyBuffer(void);
+/* If the copy buffer was allocated it will be released with a call to
+this function.  The function BufferedCopy() can do this automatically,
+but if a request to allocate a buffer by the caller succeeded and nobody
+called BufferedCopy() the caller must call this function themselves to
+ensure no memory leakage.  FALSE is returned if there was no buffer */
+
+BOOL corelib_WipeCopyBuffer(void);
+/* Initialization of a fresh buffer or wiping to reuse an old buffer,
+this sets all bytes in the buffer to zero , it fails if there was no buffer
+*/
+/*-------------------------------------------------------------------------*/
+#include "Headers\EndCH.H"
+#endif /*!__INC_CORELIB_BUFFCPY_H*/

Private/CoreLib/BuffCpy.~C

+/*
+Project: Slice/Splice
+Programmer: Overlord David Duncan Ross Palmer
+Date: 18th January 2000
+Last modified: 18th January 2000
+File: CoreLib\BuffCpy.C
+Description: Buffered copying (between part files and whole files)
+Language: ANSI C (1990)
+*/
+
+#include <Assert.H>
+#include <StdLib.H> /* for realloc() - (re)allocation of buffer) */
+#include <String.H> /* for memset() - Init of buffer */
+#include "Stds\DLStdInc.H" /* Daybo Logic standard inclusions */
+/* Pay special attention! Never include the Daybo Logic utilities because certain
+macros come into play which mean that malloc() might not act as it should and
+will terminate the program if it fails and that type of thing. */
+#ifdef __INC_DLUTILS_SDYNMEM_H
+#  error ("Never include Daybo Logic utilities in CoreLib\BuffCpy")
+#endif /*__INC_DLUTILS_SDYNMEM_H*/
+#pragma hdrstop
+
+#include "CoreLib\BuffCpy.H"
+
+/*------------------------------ PRIVATE DATA -----------------------------*/
+static struct
+{
+  size_t size; /* Size in bytes of copy buffer */
+  BYTE* PdynBuff; /* Pointer to dynamically allocated buffer */
+} CopyBuffer;
+/*-------------------------- PRIVATE FUNCTIONS ----------------------------*/
+static BOOL PossibleReAllocation(const size_t SuggestedBufferSize);
+static void File2Buffer(FILE* HFile, const BOOL ResetFilePos); /* Reads from the file into the buffer, if it hits the EOF in the file the buffer size is reduced to the size used, possibly released if nothing can be read */
+static BOOL Buffer2File(FILE* HFile, const BOOL ResetFilePos); /* Reads from the buffer into the file, if EOF is hit in target (probable disk full) the function returns TRUE meaning (EOF hit) */
+/*-------------------------------------------------------------------------*/
+short int corelib_BufferedCopy(FILE* HSource, FILE* HTarget, const size_t CopyBufferSize, const BOOL ResetFilePos[2])
+{
+  /* locals */
+  size_t sizeOfBuffer;
+  short int status = CORELIB_BUFFCPY_NORMAL; /* Status is return of function */
+
+  if (!PossibleReAllocation(CopyBufferSize)) return CORELIB_BUFFCPY_MALLOC; /* Ensure we have a copy buffer of at least 1Kb */
+  sizeOfBuffer = corelib_GetCurrentCopyBufferSize(); /* Get actual size of copy buffer */
+  while (1) /* Semi-premanent loop (must be broken from the inside) */
+  {
+    File2Buffer(HSource, ResetFilePos[0]); /* Read data into buffer */
+    if ( corelib_GetCurrentCopyBufferSize() < sizeOfBuffer ) /* Buffer size reduced? */
+      status = CORELIB_BUFFCPY_HITEOFSOURCE; /* Hit EOF in source */
+    Buffer2File(HTarget, ResetFilePos[1]); /* Write data to output file */
+    if ( feof(HTarget) )
+      status = CORELIB_BUFFCPY_HITEOFTARGET; /* Hit EOF in target (disk full?) */
+
+    if (status) /* A status level was set? */
+      break; /* Get out of the loop */
+  }
+}
+/*-------------------------------------------------------------------------*/
+size_t corelib_AllocCopyBuffer(size_t RequestedSize)
+{
+  do
+  {
+    CopyBuffer.PdynBuff = (BYTE*)realloc( CopyBuffer.PdynBuff, RequestedSize ); /* Attempt to allocate the buffer or resize one which is previously allocated */
+    if (!CopyBuffer.PdynBuff) /* Failed to allocated the buffer as requested? */
+    {
+      size_t R = (RequestedSize % 1024); /* Remainder of RequestedSize modulus 1 Kb */
+      if ( R != 0 ) /* Not a multiple of K requested! */
+      {
+        if (RequestedSize >= R) RequestedSize -= R; /* Round down to nearest Kb */
+      }
+      if ( RequestedSize >= (size_t)1024 ) /* Over a K left? (make sure it doesn't underrun) */
+        RequestedSize -= (size_t)1024; /* Decrease request by 1 Kb */
+    }
+  } while (!CopyBuffer.PdynBuff && RequestedSize); /* Continue until allocated or no request left */
+
+  if (CopyBuffer.PdynBuff) /* Allocation / reallocation OK? */
+  {
+    CopyBuffer.size = RequestedSize; /* Record size in buffer information */
+  }
+  else /* The allocation failed due to memory shortage */
+  {
+    CopyBuffer.size ^= CopyBuffer.size; /* Record size as zero */
+  }
+  return CopyBuffer.size; /* Tell caller size of buffer */
+}
+/*-------------------------------------------------------------------------*/
+size_t corelib_GetCurrentCopyBufferSize()
+{
+  return CopyBuffer.size;
+}
+/*-------------------------------------------------------------------------*/
+BOOL corelib_ReleaseCopyBuffer()
+{
+  if (corelib_GetCurrentCopyBufferSize()) /* Buffer allocated? */
+  {
+    assert(CopyBuffer.PdynBuff); /* DEBUG: There must be a pointer to memoy to free! */
+    free(CopyBuffer.PdynBuff); /* Release the buffer */
+    CopyBuffer.PdynBuff = NULL; /* Delete pointer (probally just paranoia) */
+    CopyBuffer.size ^= CopyBuffer.size; /* Record no size of no buffer, nice */
+    return TRUE; /* Done */
+  }
+  assert(!CopyBuffer.PdynBuff); /* DEBUG: There should be no buffer if there was no size */
+  return FALSE; /* There was no buffer to free */
+}
+/*-------------------------------------------------------------------------*/
+BOOL corelib_WipeCopyBuffer()
+{
+  size_t bufferSize = corelib_GetCurrentCopyBufferSize(); /* Get the size of the current copy buffer */
+
+  if (bufferSize) /* There is a copy buffer? */
+  {
+    memset(CopyBuffer.PdynBuff, 0, bufferSize); /* Init the buffer */
+    return TRUE; /* Yes, me olde son! */
+  }
+  return FALSE; /* No, there was no buffer to work on */
+}
+/*-------------------------------------------------------------------------*/
+static BOOL PossibleReAllocation(const size_t SuggestedBufferSize)
+{
+  if (corelib_GetCurrentCopyBufferSize() && !SuggestedBufferSize) /* Current buffer and no suggestion */
+    return TRUE;
+  if (!SuggestedBufferSize) return FALSE; /* No buffer and no suggestion? */
+  if (corelib_AllocCopyBuffer(SuggestedBufferSize)) /* Allocate buffer */
+    return TRUE; /* Done */
+  return FALSE; /* Real memory shortage (couldn't even allocate minimum buffer) */
+}
+/*-------------------------------------------------------------------------*/
+static void File2Buffer(FILE* HFile, const BOOL ResetFilePos)
+{
+  if (HFile && corelib_GetCurrentCopyBufferSize())
+  {
+    size_t currentBuffPos = 0; /* Current position reading buffer */
+    long origPos; /* Original file pointer position */
+
+    if (ResetFilePos) /* Should the file position be saved so that it may be restored later */
+      origPos = ftell(HFile); /* Save current file position */
+
+    corelib_WipeCopyBuffer();
+    while (1) /* Semi-permanent loop */
+    {
+      BYTE* targetByte = CopyBuffer.PdynBuff + currentBuffPos; /* Calculate pointer to buffer position */
+      if ( fread(&targetByte, sizeof(BYTE), 1, HFile) < 1) /* Read from file into buffer, one byte */
+      {
+        /* Hit EOF in the file to read from,
+        /* The buffer must be truncated */
+        corelib_AllocCopyBuffer(currentBuffPos); /* Truncate the buffer to this position */
+        break; /* Get out here */
+      }
+      /* Test if reached end of buffer */
+      if (currentBuffPos == CopyBuffer.size - 1) /* End of buffer position! */
+        break; /* Don't try to copy any more into the buffer */
+    }
+
+    if (ResetFilePos && origPos >= 0) /* Should the old file position be restored? */
+    {
+      rewind(HFile);
+      fseek(HFile, origPos, SEEK_SET); /* Restore file pointer */
+    }
+  }
+}
+/*-------------------------------------------------------------------------*/
+static BOOL Buffer2File(FILE* HFile, const BOOL ResetFilePos)
+{
+  if ( corelib_GetCurrentCopyBufferSize() && HFile )
+  {
+    long origPos; /* Stores original position of file pointer */
+    size_t currentBuffPos = 0; /* Current position in copy buffer */
+
+    if (ResetFilePos) /* Should store file position so that it may be restored later? */
+      origPos = ftell(HFile); /* Store file pos before we move it */
+
+    while (1) /* Semi-permanent loop */
+    {
+      BYTE* sourceByte = CopyBuffer.PdynBuff + currentBuffPos; /* Calculate pointer to buffer position */
+      if ( fwrite(&sourceByte, sizeof(BYTE), 1, HFile) < 1) /* Write one byte from the buffer to the file */
+      {
+        /* Hit EOF in the file to write to, return TRUE (hit EOF) to caller */
+        return TRUE;
+      }
+      /* Test if reached end of buffer */
+      if (currentBuffPos == CopyBuffer.size - 1) /* End of buffer position! */
+        break; /* Don't try to read any further from the buffer */
+    }
+
+    if (ResetFilePos && origPos >= 0) /* Should the old file position be restored? */
+    {
+      rewind(HFile);
+      fseek(HFile, origPos, SEEK_SET); /* Restore file pointer */
+    }
+  }
+
+  return FALSE; /* EOF has not yet been reached in target file */
+}
+/*-------------------------------------------------------------------------*/

Private/CoreLib/BuffCpy.~h

+#ifndef __INC_CORELIB_BUFFCPY_H
+#define __INC_CORELIB_BUFFCPY_H
+#include "Headers\BeginCH.H"
+/*-------------------------------------------------------------------------*/
+/* Possible status returns (or errors): */
+#define CORELIB_BUFFCPY_NORMAL        (0) /* Normal result, ignore */
+#define CORELIB_BUFFCPY_HITEOFSOURCE  (1) /* Hit EOF in source, normal ending */
+#define CORELIB_BUFFCPY_HITEOFTARGET  (2) /* Hit EOF in target, disk full? */
+#define CORELIB_BUFFCPY_MALLOC        (3) /* Memory allocation error (copy buffer), free up some memory or decrease buffer size) */
+short int corelib_BufferedCopy(FILE* HSource, FILE* HTarget, const size_t CopyBufferSize, const BOOL ResetFilePos[2]);
+/* Description of parameters for corelib_BufferedCopy() :
+HSource - Handle to source file (starts copy from this at the current position)
+HTarget - Handle to target file (starts copying to this at the current position)
+CopyBufferSize - Size of the buffer to copy with (should be reasonable and certainly never exceed the physical memory size, if too small copying becomes slow though
+ResetFilePos[0] - Should the file pointer be restored for the source file?
+ResetFilePos[1] - Should the file pointer be restored for the target file?
+
+This function automatically deals with the copy buffer and always releases
+the buffer after it has been called. */
+
+size_t corelib_AllocCopyBuffer(size_t RequestedSize);
+/* Allocates the copy buffer, returns zero if the copy buffer could not
+be allocated, the function is start and if the allocation fails it reduces
+the request until the allocation is successful.  The true size of the copy
+buffer (usually RequestedSize unless low on heap) is returned to the caller.
+The copy buffer's true address is held internally in this module and is
+never disclosed to callers.  Calling this function is not required, if the
+caller has not done it it will automatically be handled by BufferedCopy(), the
+only reason it is here is so that callers may know the size of the copy
+buffer before calling BufferedCopy().  If the buffer was already allocated
+it is reallocated and possibly relocated.  By never disclosing the true
+address of the buffer to the caller the reallocation may lead to relocation
+which the caller need never worry about.  If allocations fail and the smart
+functionallity kicks in the buffer will be a multiple of 1Kb */
+
+size_t corelib_GetCurrentCopyBufferSize(void);
+/* Returns the size of the currently allocated internal copy buffer,
+or zero if there is no copy buffer allocated. */
+
+BOOL corelib_ReleaseCopyBuffer(void);
+/* If the copy buffer was allocated it will be released with a call to
+this function.  The function BufferedCopy() can do this automatically,
+but if a request to allocate a buffer by the caller succeeded and nobody
+called BufferedCopy() the caller must call this function themselves to
+ensure no memory leakage.  FALSE is returned if there was no buffer */
+
+BOOL corelib_WipeCopyBuffer(void);
+/* Initialization of a fresh buffer or wiping to reuse an old buffer,
+this sets all bytes in the buffer to zero , it fails if there was no buffer
+*/
+/*-------------------------------------------------------------------------*/
+#include "Headers\EndCH.H"
+#endif /*!__INC_CORELIB_BUFFCPY_H*/

Private/CoreLib/CoreInit.C

+#include <Time.H>
+#include "Stds\DLStdInc.H" /* Daybo Logic standards */
+#pragma hdrstop
+
+#include "CoreLib\FtlStrHa.H"
+#include "CoreLib\FDKO.H"
+#include "CoreLib\namefile.H" /* Naming file code */
+#include "Slice\CSCC.H"
+#include "CoreLib\CoreInit.H" /* Our header */
+/*-------------------------------------------------------------------*/
+void corelib_CClassGlobalConstruct()
+{
+  static BOOL doneOnce;
+  if (!doneOnce) /* Only do this once... */
+  {
+    doneOnce = TRUE; /* Never call us again (this exec) */
+
+    S_CORELIB_FTLSTRHA_Construct(&_FatalStr);
+    S_CORELIB_ConfigSettingsCache_Construct(&_CSCC); /* Construct the C to C++ settings cache object (deals with requests from C for the C++ settings cache) */
+    S_CORELIB_FDKO_Construct(&_FileDetails); /* Construct the file details keeper which is used during the slice process to prevent direct file handle access */
+    corelib_namefile_Startup(); /* Start the NAMING.FIL module which deals with the loading and saving of naming files on the first disk of sets */
+  }
+  return;
+}
+/*-------------------------------------------------------------------*/
+void corelib_CClassGlobalDestruct()
+{
+  static BOOL doneOnce;
+  if (!doneOnce) /* Only do this once... */
+  {
+    doneOnce = TRUE; /* Never call us again (this exec) */
+
+    corelib_namefile_Shutdown(); /* Shutdown the NAMING.FIL code */
+    S_CORELIB_FDKO_Destruct(&_FileDetails); /* Destruct the file details keeper */
+    S_CORELIB_ConfigSettingsCache_Destruct(&_CSCC); /* Destruct the C to C++ cache converter */
+    S_CORELIB_FTLSTRHA_Destruct(&_FatalStr);
+  }
+  return;
+}
+/*-------------------------------------------------------------------*/

Private/CoreLib/CoreInit.H

+/* Deals with the core library initialization and cleanup tasks, should
+be called from the main module of the program. */
+
+#ifndef __INC_WSLICE_CORELIB_INIT_H
+#define __INC_WSLICE_CORELIB_INIT_H
+#include "Headers\BeginCH.H"
+/*--------------------------------------------------------------*/
+void corelib_CClassGlobalConstruct(void); /* CALL ONCE PER RUN */
+void corelib_CClassGlobalDestruct(void); /* CALL ONCE PER RUN */
+/*--------------------------------------------------------------*/
+#include "Headers\EndCH.H"
+#endif /*!__INC_WSLICE_CORELIB_INIT_H*/

Private/CoreLib/CoreInit.~C

+#include "Stds\DLStdInc.H" /* Daybo Logic standards */
+#pragma hdrstop
+
+#include "CoreLib\FtlStrHa.H"
+#include "CoreLib\FDKO.H"
+#include "CoreLib\namefile.H" /* Naming file code */
+#include "Slice\CSCC.H"
+#include "CoreLib\CoreInit.H" /* Our header */
+/*-------------------------------------------------------------------*/
+void corelib_CClassGlobalConstruct()
+{
+  static BOOL doneOnce;
+  if (!doneOnce) /* Only do this once... */
+  {
+    doneOnce = TRUE; /* Never call us again (this exec) */
+
+    S_CORELIB_FTLSTRHA_Construct(&_FatalStr);
+    S_CORELIB_ConfigSettingsCache_Construct(&_CSCC); /* Construct the C to C++ settings cache object (deals with requests from C for the C++ settings cache) */
+    S_CORELIB_FDKO_Construct(&_FileDetails); /* Construct the file details keeper which is used during the slice process to prevent direct file handle access */
+    corelib_namefile_Startup(); /* Start the NAMING.FIL module which deals with the loading and saving of naming files on the first disk of sets */
+  }
+  return;
+}
+/*-------------------------------------------------------------------*/
+void corelib_CClassGlobalDestruct()
+{
+  static BOOL doneOnce;
+  if (!doneOnce) /* Only do this once... */
+  {
+    doneOnce = TRUE; /* Never call us again (this exec) */
+
+    corelib_namefile_Shutdown(); /* Shutdown the NAMING.FIL code */
+    S_CORELIB_FDKO_Destruct(&_FileDetails); /* Destruct the file details keeper */
+    S_CORELIB_ConfigSettingsCache_Destruct(&_CSCC); /* Destruct the C to C++ cache converter */
+    S_CORELIB_FTLSTRHA_Destruct(&_FatalStr);
+  }
+  return;
+}
+/*-------------------------------------------------------------------*/

Private/CoreLib/CoreLib.H

+#ifndef __INC_CORELIB_CORELIB_H
+#define __INC_CORELIB_CORELIB_H
+
+/* Master include file for the Slice/Splice core library, should list
+all headers for CoreLib - OVERLORD DDRP 10th Jan 2000 */
+
+#include "CoreLib\CoreInit.H"
+#include "CoreLib\CpyRcrPr.H"
+#include "CoreLib\FtlStrHa.H"
+#include "CoreLib\SliceFmt.H"
+#include "CoreLib\Slicer.H"
+#include "CoreLib\SplFN.H"
+
+#endif /*!__INC_CORELIB_CORELIB_H*/

Private/CoreLib/CpyRcrPr.C

+/* Copies the recovery program to the first target diskette,
+what I mean by the recovery program is the program called
+Splice which makes parts of files back into a real file again
+
+Language: ANSI C (1990)
+Created: 2nd December 1999
+Last modified: 4rd January Y2K
+Author: David Duncan Ross Palmer (Overlord @ Daybo Logic)
+Last modified by: ME (DDRP)
+
+*/
+
+#ifdef _Windows
+#include <Windows.H>
+#endif
+#include <StdIO.H>
+#include <StdLib.H>
+#include <IO.H>
+#include <Signal.H> /* raise() & args */
+#include <StdLib.H> /* abort() */
+#include "Stds\DLStdInc.H" /* The Daybo Logic standard inclusions header */
+#include "DLUtils\DLUtils.H" /* The Daybo Logic utilities (for MALLOC()) */
+#include "DLStrLib\DLStrLib.H" /* Daybo Logic string library */
+#include "Math\Headers\DLMath.H" // The Daybo Logic maths library header
+#pragma hdrstop
+
+#define copysplice_USINGNAMESPACE
+#include "CpyRcrPr.H"
+#include "SplFN.H" /* Contains filename of the Splice program */
+#include "Headers\AnsiSfnc.H"
+#include "Replace\DskSpace.H" /* dskSpace_????? functions */
+#include "Math\Headers\DLMath.H"
+#include "Stds\FileLine.H" /* __LINE__ file __FILE__ fail safe support */
+#include "Slice\CSCC.H" /* _CSCC - Settings cache */
+#include "CoreLib\FtlStrHa.H" /* Fatal string handler */
+
+static char* GetSpliceFilename(void); /* Used to get the filename of the Splice program, includes the path (information from the registry put there when the application was installed).  The pointer returned was dynamically allocated with MALLOC and should be freed by the caller */
+#define GAUGE_UPDATE_INTERVAL (1024) /* Every X bytes the gauge is updated on the callback if installed (increase if WSplice is large */
+/*-------------------------------------------------------------------------*/
+int copysplice_Copy(
+                    const BYTE TargetDrive,
+                    DWORD (*PCopyProgressRoutine)(
+                                                  MONSTERLONG64 TotalFileSize, /* total file size, in bytes */
+                                                  MONSTERLONG64 TotalBytesTransferred, /* total number of bytes tranferred */
+                                                  DWORD dwCallbackReason, /* reason for callback */
+                                                  LPVOID lpData /* data passed by copier */
+                    ),
+                    const BOOL Restart /* Normally FALSE, used when copying is stopped and restarted */
+)
+{
+  /* locals */
+  FILE* Hsplice; /* Handle to the WSplice.exe file */
+  int errorStatus = COPYSPLICE_NOERRORS; /* Return value for the caller */
+  static long int origFilePosResume = 0L; /* Holds file position in original so that it may be stopped and resumed later */
+  char* dpsplfn; /* Dynamic pointer to a copy of the Splice program filename */
+  struct ftime ft; /* Used to hold a file's time and date (to change copy's) */
+
+  if (!Restart) /* Starting a new attempt? */
+    origFilePosResume = 0UL; /* Reset starting position */
+
+  /* See if certain errors can occur before we do the copy */
+  if ( copysplice_AreThereAnyErrors(TargetDrive, &errorStatus, NULL) ) /* Any errors are automated test list can pick up */
+    return errorStatus; /* Gotcha - ABORT, ABORT, ABORT! */
+
+  dpsplfn = GetSpliceFilename(); /* Get a copy of the Splice filename */
+  if (dpsplfn) /* Copied safe? */
+  {
+    Hsplice = fopen(dpsplfn, "rb"); /* Open original */
+    free(dpsplfn); /* Release copy of the Splice program name */
+  }
+  if (Hsplice) /* Opened original successfully? */
+  {
+    FILE* Hcopy; /* Handle to the copy */
+    char* copyFn; /* Dynamically holds fully qualified DOS name for the copy */
+
+    if (Restart && origFilePosResume) /* Want to resume from part way through the original? */
+      fseek(Hsplice, origFilePosResume, SEEK_SET); /* Do so by pre-offsetting */
+
+    /* WARNING! Incompatibilities may arise in the naming convention for other platforms! */
+    copyFn = (char*)MALLOC( 3 + strlen(_SPLICEFILENAME) + 1 ); /* Allocate space to build a name of the copy */
+    copyFn[0] = (char)(TargetDrive + 65); /* Starts with drive designator (convert to character (0 to A etc.) */
+    copyFn[1] = ':'; copyFn[2] = '\\'; /* Continue building */
+    strcpy(copyFn+3, _SPLICEFILENAME); /* Copy filename of original */
+
+    if (Restart) /* Restarting a previously stopped copy */
+      Hcopy = fopen(copyFn, "ab"); /* Open the file where we were in append mode */
+    else
+      Hcopy = fopen(copyFn, "wb"); /* Create copy of Splice on target disk (empty file) */
+
+    if (Hcopy) /* Providing the copy was created successfully... */
+    {
+      /* CAUTION! Some of this code has trouble working with 64-bit values, a 64-bit capable file handling library will have to be made later! */
+      unsigned short copyProgressRoutineControlVar = 0UL;
+      BOOL firstLoop = TRUE;
+      BOOL delTarget = FALSE; /* Copy should be/not be deleted after creation (only used for cancellations) */
+
+      while (!feof(Hsplice)) /* More to copy? */
+      {
+        BOOL breakOut = FALSE; /* Break out of the while loop (used for cancellations only) */
+        BYTE currentByte; /* Used for copying, hardly buffered, but I'm not bothered */
+
+        fread(&currentByte, sizeof(currentByte), 1, Hsplice); /* Read from source */
+        if (feof(Hsplice)) break;
+        fwrite(&currentByte, sizeof(currentByte), 1, Hcopy); /* Write to copy */
+
+        /* Now to call the copy progress routine to allow the caller to update a gauge */
+        if (PCopyProgressRoutine) /* Pointer to the routine was sent by the caller? */
+        {
+          if ((copyProgressRoutineControlVar % GAUGE_UPDATE_INTERVAL) == 0) /* Only call every so often otherwise copying is slow */
+          {
+            MONSTERLONG64 ml64TotSpaceBytes, ml64BytesDone;
+            DWORD request; /* Last request by gauge routine */
+
+            ml64TotSpaceBytes.hi = 0UL;     ml64TotSpaceBytes.lo = subst_filelength(Hsplice);
+            ml64BytesDone.hi = 0UL;         ml64BytesDone.lo = ftell(Hcopy);
+            request = PCopyProgressRoutine( ml64TotSpaceBytes, ml64BytesDone,
+                                                 ( (firstLoop) ? (COPYSPLICE_CALLBACK_STREAM_SWITCH) : (COPYSPLICE_CALLBACK_CHUNK_FINISHED) ),
+                                                 NULL /* Don't allow access to the block to outsiders as we don't actually have the copy process buffered yet (add buffering later if things are slow) */
+                            );
+            /* Now to handle any requests by the progress routine, COPYSPLICE_PROGRESS_CONTINUE
+            is normal.  Invalid requests cause the program to crash! */
+            switch (request)
+            {
+              case COPYSPLICE_PROGRESS_CONTINUE :
+              {
+                /* (do nothing) */
+                break;
+              }
+              case COPYSPLICE_PROGRESS_CANCEL :
+              {
+                breakOut = TRUE; /* Break out of copy loop at next chance */
+                delTarget = TRUE; /* Delete the file afterwards */
+                break;
+              }
+              case COPYSPLICE_PROGRESS_STOP :
+              {
+                origFilePosResume = ftell(Hsplice); /* Get how far we were */
+                breakOut = TRUE; /* Break out of copy loop at next chance */
+                break;
+              }
+              case COPYSPLICE_PROGRESS_QUIET : /* Don't want to be called again? */
+              {
+                PCopyProgressRoutine = NULL; /* Erase pointer to progress routine so that it is not called */
+                break;
+              }
+              default : /* Invalid request? */
+              {
+                #ifdef __DAYBO_DEBUGGING__
+                char errmsg[1024]; /* Space for error message */
+                sprintf(errmsg, "Invalid request from progress routine\nrequest: %lu, file: \"%s\", line: %u.\nThe program terminated abnormally, call Daybo Logic.", request, __FILE__, __LINE__); /* Create error message */
+                fprintf(stderr, errmsg); /* Output it to the error stream */
+                _FatalStr.Set(&_FatalStr, errmsg); /* Set the global error string in Slice */
+                raise(SIGABRT); /* Warn handlers prior to termination */
+                #endif
+                exit(EXIT_FAILURE); /* Terminate! */
+              }
+            }
+
+            firstLoop = FALSE;
+          }
+          copyProgressRoutineControlVar++; /* Increment control variable, gauge won't happen again for a while now if one steps through all this */
+        }
+        if (breakOut) break; /* Chance for cancelling */
+      }
+
+      getftime((int)Hsplice->fd, &ft); /* Get time from source file */
+      setftime((int)Hcopy->fd, &ft); /* Set time for source file, same as time for source */
+      fclose(Hcopy);
+
+      if (delTarget) /* Target (copy) should be deleted? */
+        remove(copyFn);
+
+      free(copyFn); /* The name of the newly created file is no longer required now */
+    }
+    else /* The copy could not be created! */
+    {
+      errorStatus = COPYSPLICE_CREATIONERROR; /* Set error status */
+    }
+
+    fclose(Hsplice); /* Close the original */
+  }
+  else /* Failed to open the original! */
+  {
+    /* Since AreThereAnyErrors was already called I cannot eloborate further as to the
+       cause of this error. */
+    errorStatus = COPYSPLICE_UNKNOWNERROR; /* Set emergency use only error number */
+  }
+  return errorStatus; /* Give error condition to caller */
+}
+/*-------------------------------------------------------------------------*/
+static char* GetSpliceFilename()
+{
+  /* locals */
+  static const char fn[] = _SPLICEFILENAME; /* Fixed string of Splice program */
+  char* dynPtr; /* Dynamic pointer of filename including path (returned to the caller) */
+
+  if (_CSCC.IsItemInStorage(csAppRootStr)) /* Is the app root string in the settings storage? */
+  {
+    size_t l;
+    char* pathInSto; /* Path in storage (dynamic) */
+    size_t dynPtrSize;
+
+    l = _CSCC.GetStringItem(csAppRootStr, NULL, (size_t)0U); /* Get length of string in storage */
+    if (l)
+    {
+      pathInSto = (char*)MALLOC( ++l ); /* Allocate space for path */
+      if (pathInSto)
+      {
+        memset(pathInSto, 0, l); /* Init new block (in case strcat() is used on it before strcpy()) */
+        _CSCC.GetStringItem(csAppRootStr, pathInSto, l); /* Copy us the path from the settings, thanks */
+      }
+      dynPtrSize = l + 1 + strlen(fn) +1;
+      dynPtr = (char*)MALLOC( dynPtrSize ); /* Allocate memory on behalf of the caller */
+      if (dynPtr)
+      {
+        char lastChar;
+        memset(dynPtr, 0, dynPtrSize); /* Init new block */
+        if (pathInSto) strcpy(dynPtr, pathInSto); /* Copy the app base path to the name */
+        dynPtr = dlstrlib_strrev(dynPtr); /* Reverse the string (to make life simpler) */
+        lastChar = dynPtr[0]; /* Save first (last) char */
+        dynPtr = dlstrlib_strrev(dynPtr); /* Re-reverse the string (put it the right way around) */
+        if (lastChar != '\\') /* String does NOT end with a path separator? */
+        {
+          strcat(dynPtr, "\\"); /* Add a sep. to the string */
+        }
+        strcat(dynPtr, fn); /* Add filename! */
+      }
+      if (pathInSto) free(pathInSto);
+      return dynPtr;
+    }
+  }
+
+  dynPtr = (char*)MALLOC( strlen(fn)+1 ); /* Allocate space on behalf of the caller */
+  strcpy(dynPtr, fn); /* Copy string into new block of memory */
+
+  return dynPtr; /* Give the dynamic pointer to the caller (they must free it) */
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_IsTargetTooSmall(const BYTE TargetDrive, FILE* _Hfile)
+{
+  /* locals */
+  MONSTERLONG64 tarSpace; /* Holds space on target drive */
+  BOOL dontClose; /* Whether to close the handle at the end */
+  FILE* Hfile;
+  BOOL result; /* Result for caller */
+  long int fz; /* File size of file to copy */
+  BOOL bisBigger; /* An argument to an ml64 function */
+
+  if (IsBadDriveLetter(TargetDrive)) return FALSE;
+
+  dskSpace_GetTotalSpace(&tarSpace, TargetDrive);
+  if (!tarSpace.lo && !tarSpace.hi) /* No space? */
+    return TRUE; /* No space on target, don't waste more time */
+
+  if (_Hfile) /* Handle was sent be caller? */
+  {
+    Hfile = _Hfile; /* Copy caller's handle */
+    dontClose = TRUE; /* Never close the caller's handle */
+  }
+  else /* Caller did not bother to sent the handle */
+  {
+    Hfile = fopen(GetSpliceFilename(), "rb"); /* Open file and get handle */
+    if (!Hfile) /* Could not open the file */
+      return TRUE; /* Say target too small */
+    dontClose = FALSE; /* Closing our own handle is a good idea */
+  }
+  /* Handle to file is now VALID! */
+  fz = subst_filelength(Hfile); /* Get length of file */
+  if ( ml64CompDWORD( &tarSpace, fz, &bisBigger ) != 0 ) /* Compare size on disk to program size */
+  {
+    if (bisBigger) /* Size bigger than space on disk? */
+    {
+      result = TRUE; /* To small! */
+      goto normalReturn;
+    }
+  }
+
+  result = FALSE; /* Target is NOT to small */
+normalReturn:
+  if (!dontClose) /* Allowed to close the handle? */
+    fclose(Hfile); /* Close the handle */
+  return result;
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_IsThereEnoughFreeSpace(const BYTE TargetDrive, FILE* _Hfile)
+{
+  /* locals */
+  MONSTERLONG64 tarFree; /* Holds free space on target drive */
+  BOOL dontClose; /* Whether to close the handle at the end */
+  FILE* Hfile;
+  BOOL result; /* Result for caller */
+  long int fz; /* File size of file to copy */
+  BOOL bisBigger; /* An argument in the call to an ml64 function */
+
+  if (IsBadDriveLetter(TargetDrive)) return FALSE;
+
+  dskSpace_GetFreeSpace(&tarFree, TargetDrive);
+  if (!tarFree.lo && !tarFree.hi) /* No free space? */
+    return FALSE; /* No free space on target, don't waste more time */
+
+  if (_Hfile) /* Handle was sent be caller? */
+  {
+    Hfile = _Hfile; /* Copy caller's handle */
+    dontClose = TRUE; /* Never close the caller's handle */
+  }
+  else /* Caller did not bother to sent the handle */
+  {
+    Hfile = fopen(GetSpliceFilename(), "rb"); /* Open file and get handle */
+    if (!Hfile) /* Could not open the file */
+      return TRUE; /* Say target too small */
+    dontClose = FALSE; /* Closing our own handle is a good idea */
+  }
+  /* Handle to file is now VALID! */
+  fz = subst_filelength(Hfile); /* Get length of file */
+  if ( ml64CompDWORD( &tarFree, fz, &bisBigger ) != 0 )
+  {
+    if (bisBigger) /* File size greater than free space on target drive? */
+    {
+      result = FALSE; /* To little free space! */
+      goto normalReturn;
+    }
+  }
+
+  result = TRUE; /* Target has enough free space */
+normalReturn:
+  if (!dontClose) /* Allowed to close the handle? */
+    fclose(Hfile); /* Close the handle */
+  return result;
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_IsBadDriveLetter(const BYTE TargetDrive)
+{
+  if (TargetDrive > 25) return TRUE; /* Out of range! */
+  return FALSE; /* Safe */
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_CanYouSeeTheFile()
+{
+  return CheckFileExistance(GetSpliceFilename());
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_AreThereAnyErrors(const BYTE TargetDrive, int* PerrorNumber, FILE* _Hfile)
+{
+  /* locals */
+  BOOL status; /* Safe... */
+  FILE* Hfile; /* Handle to the file to copy */
+  BOOL CloseHfile = FALSE;
+
+  if (PerrorNumber) *PerrorNumber = COPYSPLICE_NOERRORS; /* Reset caller's error number */
+
+  status = IsBadDriveLetter(TargetDrive);
+  if (status) /* Bad drive? */
+  {
+    status = FALSE;
+    if (PerrorNumber) *PerrorNumber = COPYSPLICE_BADDRIVELETTER;
+    goto giveStat;
+  }
+
+  if (_Hfile) /* Handle for file sent by caller? */
+  {
+    Hfile = _Hfile; /* Copy handle */
+    CloseHfile = FALSE; /* Don't close caller's handle */
+  }
+  else /* Handle was not sent by the caller? */
+  {
+    char* dpspfn = GetSpliceFilename(); // Get a copy of the splice filename (with path)
+    if (dpspfn) /* Allocated sucessfully? */
+    {
+      Hfile = fopen( dpspfn, "rb" ); // Attempt to open the file Splice
+      free(dpspfn); /* Release dynamic string of filename */
+    }
+    if (!Hfile)
+    {
+      if (PerrorNumber) *PerrorNumber = COPYSPLICE_SPLICEPROGNOTFOUND;
+      goto giveStat;
+    }
+    CloseHfile = TRUE; /* Close our own handle */
+  }
+
+  status = IsTargetTooSmall(TargetDrive, Hfile);
+  if (status) /* Target to small? */
+  {
+    status = FALSE;
+    if (PerrorNumber) *PerrorNumber = COPYSPLICE_TARGETTOOSMALL;
+    goto giveStat;
+  }
+  status = IsThereEnoughFreeSpace(TargetDrive, Hfile);
+  if (!status) /* Not enough free space? */
+  {
+    if (PerrorNumber) *PerrorNumber = COPYSPLICE_NOTENOUGHFREESPACE;
+    goto giveStat;
+  }
+
+giveStat: /* Time to give the status to the caller */
+  if (CloseHfile) /* Permitted to close file handle? */
+    fclose(Hfile); /* Do it! */
+  return !status; // Not status : Why? Because we return TRUE there are errors as opposed to TRUE everything is safe
+}
+/*-------------------------------------------------------------------------*/
+const char* copysplice_GetErrorMessageA(const int ErrorNumber)
+{
+  static const char msgs[][128] = {
+    "The copy was completed successfully",
+    "The total size of the target disk was to small for the recovery program\n(which can't be cut into slices!)",
+    "There is not enough free space left on the drive",
+    "The file system is corrupt or there may be a physical defect on the surface",
+    "The drive letter is not valid",
+    "The Splice program was not found",
+    "An unknown error happened while copying the file, call Daybo Logic",
+    "Drive not ready\n\nor\nReadonly filesystem\n\nor\nPermission denied."
+  };
+
+  if (ErrorNumber < sizeof(msgs)/sizeof(msgs[0])) /* Error number safe? */
+    return msgs[ErrorNumber]; /* Give pointer to requested message */
+
+  return NULL; /* The number was out of range */
+}
+/*-------------------------------------------------------------------------*/

Private/CoreLib/CpyRcrPr.h

+#ifndef __INC_WSLICE_CPYRCRPR_H
+#define __INC_WSLICE_CPYRCRPR_H
+#include "Headers\BeginCH.H"
+/*-------------------------------------------------------------------------*/
+/* Header for C file which copies the Splice program to the first
+target floppy, there is no way for this to know that the disk in
+the drive is the first disk, the caller should try to make sure
+that the user has the correct disk in the drive. */
+
+/* These values are things that can go wrong */
+#define COPYSPLICE_NOERRORS           (0) /* The copy was completed successfully */
+#define COPYSPLICE_TARGETTOOSMALL     (1) /* The total size of the target disk was to small for the recovery program (which can't be cut into slices!) */
+#define COPYSPLICE_NOTENOUGHFREESPACE (2) /* There is not enough free space left on the drive */
+#define COPYSPLICE_PHYSICALDEFECT     (3) /* Suspect only: A physical defect on the surface (writing failed even though there was enough space), another reason might be a corrupted file system */
+#define COPYSPLICE_BADDRIVELETTER     (4) /* A very simple filter, it does not yet have the ability to detect if the drive is on the system but returns this if the drive letter is > 25 */
+#define COPYSPLICE_SPLICEPROGNOTFOUND (5) /* The Splice program was not found to copy */
+#define COPYSPLICE_UNKNOWNERROR       (6) /* I hope this doesn't happen! */
+#define COPYSPLICE_CREATIONERROR      (7) /* Creation error ocours while copying usually if there is no disk in the drive, the drive is readonly or permission is denied for sharing or security reasons */
+/* Some of these errors may be avoided by calling the detection functions separately
+before calling the copy function.  Note that any 'Drive' is always zero based (0=A, 1=B, 25=Z),
+when copying, to allow a gauge to work pass a pointer to a CopyProgressRoutine!
+These defs are used for the callback: (firstly return value from the callback
+(set by the user (the programmer who makes the callback function)) */
+
+#define COPYSPLICE_PROGRESS_CONTINUE (0) /* Continue the copy operation. */
+#define COPYSPLICE_PROGRESS_CANCEL   (1) /* Cancel the copy operation and delete the destination file. */
+#define COPYSPLICE_PROGRESS_STOP     (2) /* Stop the copy operation. It can be restarted at a later time. */
+#define COPYSPLICE_PROGRESS_QUIET    (3) /* Continue the copy operation, but stop invoking CopyProgressRoutine to report progress. */
+
+/* Now reasons for the callback (set by the copy routine and processed
+by the programmer of the progress routine), these are actually bits
+set in a DWORD (32-bit) and may be used at the same time by use of the
+bitwise or operation dw |= bit */
+
+#define COPYSPLICE_CALLBACK_CHUNK_FINISHED (1) /* Bit 0 - Set every other call, another part of the file will have been copied */
+#define COPYSPLICE_CALLBACK_STREAM_SWITCH  (2) /* Bit 1 - Set only on first call */
+
+int copysplice_Copy(
+                    const BYTE TargetDrive,
+                    DWORD (*PCopyProgressRoutine)(
+                                                  MONSTERLONG64 TotalFileSize, /* total file size, in bytes */
+                                                  MONSTERLONG64 TotalBytesTransferred, /* total number of bytes tranferred */
+                                                  DWORD dwCallbackReason, /* reason for callback */
+                                                  LPVOID lpData /* data passed by copier */
+                    ),
+                    const BOOL Restart /* Normally FALSE, used when copying is stopped and restarted */
+);
+
+BOOL copysplice_IsBadDriveLetter(const BYTE TargetDrive); /* Is drive letter > 25? I know it would be simpler for the caller to do this, but it's better to call this because it's functionality may be expanded later */
+BOOL copysplice_CanYouSeeTheFile(void); /* If FALSE means the file cannot be found, it will be looked for in the current directory only */
+BOOL copysplice_IsTargetTooSmall(const BYTE TargetDrive, FILE* _Hfile); /* Returns TRUE if target is too small for the WSplice program.  Send handle to file or NULL if one can't be bothered to */
+BOOL copysplice_IsThereEnoughFreeSpace(const BYTE TargetDrive, FILE* _Hfile); /* Returns FALSE if there is not enough free space for the WSplice program */
+/* The order of these tests are important! */
+BOOL copysplice_AreThereAnyErrors(const BYTE TargetDrive, int* PerrorNumber, FILE* _Hfile); /* Does all above tests, PerrorNumber is optional, return value is TRUE only if all tests return the desired result.  The error number is for the first error, the tests are executed in the order above */
+const char* copysplice_GetErrorMessageA(const int ErrorNumber); /* Gets a pointer to an error message for the error number */
+
+/* Shortcuts, make the copysplice prefix obsolete, off by default to avoid
+conflict, to access them define copysplice_USINGNAMESPACE before including
+this header */
+#ifdef copysplice_USINGNAMESPACE
+#  define Copy                        copysplice_Copy
+#  define IsTargetTooSmall            copysplice_IsTargetTooSmall
+#  define IsThereEnoughFreeSpace      copysplice_IsThereEnoughFreeSpace
+#  define IsBadDriveLetter            copysplice_IsBadDriveLetter
+#  define CanYouSeeTheFile            copysplice_CanYouSeeTheFile
+#  define AreThereAnyErrors           copysplice_AreThereAnyErrors
+#  define GetErrorMessageA            copysplice_GetErrorMessageA
+#  define GetErrorMessageW            copysplice_GetErrorMessageW
+#  ifdef UNICODE
+#    define GetErrorMessage  copysplice_GetErrorMessageW
+#  else
+#    define GetErrorMessage  copysplice_GetErrorMessageA
+#  endif /*UNICODE*/
+#endif /*copysplice_USINGNAMESPACE*/
+
+#ifdef UNICODE
+#  define copysplice_GetErrorMessage             copysplice_GetErrorMessageW
+#else
+#  define copysplice_GetErrorMessage             copysplice_GetErrorMessageA
+#endif /*UNICODE*/
+/*-------------------------------------------------------------------------*/
+#include "Headers\EndCH.H"
+#endif /*__INC_WSLICE_CPYRCRPR_H*/

Private/CoreLib/CpyRcrPr.~C

+/* Copies the recovery program to the first target diskette,
+what I mean by the recovery program is the program called
+Splice which makes parts of files back into a real file again
+
+Language: ANSI C (1990)
+Created: 2nd December 1999
+Last modified: 4rd January Y2K
+Author: David Duncan Ross Palmer (Overlord @ Daybo Logic)
+Last modified by: ME (DDRP)
+
+*/
+
+#ifdef _Windows
+#include <Windows.H>
+#endif
+#include <StdIO.H>
+#include <StdLib.H>
+#include <IO.H>
+#include <Signal.H> /* raise() & args */
+#include <StdLib.H> /* abort() */
+#include "Stds\DLStdInc.H" /* The Daybo Logic standard inclusions header */
+#include "DLUtils\DLUtils.H" /* The Daybo Logic utilities (for MALLOC()) */
+#include "DLStrLib\DLStrLib.H" /* Daybo Logic string library */
+#include "Math\Headers\DLMath.H" // The Daybo Logic maths library header
+#pragma hdrstop
+
+#define copysplice_USINGNAMESPACE
+#include "CpyRcrPr.H"
+#include "SplFN.H" /* Contains filename of the Splice program */
+#include "Headers\AnsiSfnc.H"
+#include "Replace\DskSpace.H" /* dskSpace_????? functions */
+#include "Math\Headers\DLMath.H"
+#include "Stds\FileLine.H" /* __LINE__ file __FILE__ fail safe support */
+#include "Slice\CSCC.H" /* _CSCC - Settings cache */
+#include "CoreLib\FtlStrHa.H" /* Fatal string handler */
+
+static char* GetSpliceFilename(void); /* Used to get the filename of the Splice program, includes the path (information from the registry put there when the application was installed).  The pointer returned was dynamically allocated with MALLOC and should be freed by the caller */
+#define GAUGE_UPDATE_INTERVAL (1024) /* Every X bytes the gauge is updated on the callback if installed (increase if WSplice is large */
+/*-------------------------------------------------------------------------*/
+int copysplice_Copy(
+                    const BYTE TargetDrive,
+                    DWORD (*PCopyProgressRoutine)(
+                                                  MONSTERLONG64 TotalFileSize, /* total file size, in bytes */
+                                                  MONSTERLONG64 TotalBytesTransferred, /* total number of bytes tranferred */
+                                                  DWORD dwCallbackReason, /* reason for callback */
+                                                  LPVOID lpData /* data passed by copier */
+                    ),
+                    const BOOL Restart /* Normally FALSE, used when copying is stopped and restarted */
+)
+{
+  /* locals */
+  FILE* Hsplice; /* Handle to the WSplice.exe file */
+  int errorStatus = COPYSPLICE_NOERRORS; /* Return value for the caller */
+  static long int origFilePosResume = 0L; /* Holds file position in original so that it may be stopped and resumed later */
+  char* dpsplfn; /* Dynamic pointer to a copy of the Splice program filename */
+  struct ftime ft; /* Used to hold a file's time and date (to change copy's) */
+
+  if (!Restart) /* Starting a new attempt? */
+    origFilePosResume = 0UL; /* Reset starting position */
+
+  /* See if certain errors can occur before we do the copy */
+  if ( copysplice_AreThereAnyErrors(TargetDrive, &errorStatus, NULL) ) /* Any errors are automated test list can pick up */
+    return errorStatus; /* Gotcha - ABORT, ABORT, ABORT! */
+
+  dpsplfn = GetSpliceFilename(); /* Get a copy of the Splice filename */
+  if (dpsplfn) /* Copied safe? */
+  {
+    Hsplice = fopen(dpsplfn, "rb"); /* Open original */
+    free(dpsplfn); /* Release copy of the Splice program name */
+  }
+  if (Hsplice) /* Opened original successfully? */
+  {
+    FILE* Hcopy; /* Handle to the copy */
+    char* copyFn; /* Dynamically holds fully qualified DOS name for the copy */
+
+    if (Restart && origFilePosResume) /* Want to resume from part way through the original? */
+      fseek(Hsplice, origFilePosResume, SEEK_SET); /* Do so by pre-offsetting */
+
+    /* WARNING! Incompatibilities may arise in the naming convention for other platforms! */
+    copyFn = (char*)MALLOC( 3 + strlen(_SPLICEFILENAME) + 1 ); /* Allocate space to build a name of the copy */
+    copyFn[0] = (char)(TargetDrive + 65); /* Starts with drive designator (convert to character (0 to A etc.) */
+    copyFn[1] = ':'; copyFn[2] = '\\'; /* Continue building */
+    strcpy(copyFn+3, _SPLICEFILENAME); /* Copy filename of original */
+
+    if (Restart) /* Restarting a previously stopped copy */
+      Hcopy = fopen(copyFn, "ab"); /* Open the file where we were in append mode */
+    else
+      Hcopy = fopen(copyFn, "wb"); /* Create copy of Splice on target disk (empty file) */
+
+    if (Hcopy) /* Providing the copy was created successfully... */
+    {
+      /* CAUTION! Some of this code has trouble working with 64-bit values, a 64-bit capable file handling library will have to be made later! */
+      unsigned short copyProgressRoutineControlVar = 0UL;
+      BOOL firstLoop = TRUE;
+      BOOL delTarget = FALSE; /* Copy should be/not be deleted after creation (only used for cancellations) */
+
+      while (!feof(Hsplice)) /* More to copy? */
+      {
+        BOOL breakOut = FALSE; /* Break out of the while loop (used for cancellations only) */
+        BYTE currentByte; /* Used for copying, hardly buffered, but I'm not bothered */
+
+        fread(&currentByte, sizeof(currentByte), 1, Hsplice); /* Read from source */
+        if (feof(Hsplice)) break;
+        fwrite(&currentByte, sizeof(currentByte), 1, Hcopy); /* Write to copy */
+
+        /* Now to call the copy progress routine to allow the caller to update a gauge */
+        if (PCopyProgressRoutine) /* Pointer to the routine was sent by the caller? */
+        {
+          if ((copyProgressRoutineControlVar % GAUGE_UPDATE_INTERVAL) == 0) /* Only call every so often otherwise copying is slow */
+          {
+            MONSTERLONG64 ml64TotSpaceBytes, ml64BytesDone;
+            DWORD request; /* Last request by gauge routine */
+
+            ml64TotSpaceBytes.hi = 0UL;     ml64TotSpaceBytes.lo = subst_filelength(Hsplice);
+            ml64BytesDone.hi = 0UL;         ml64BytesDone.lo = ftell(Hcopy);
+            request = PCopyProgressRoutine( ml64TotSpaceBytes, ml64BytesDone,
+                                                 ( (firstLoop) ? (COPYSPLICE_CALLBACK_STREAM_SWITCH) : (COPYSPLICE_CALLBACK_CHUNK_FINISHED) ),
+                                                 NULL /* Don't allow access to the block to outsiders as we don't actually have the copy process buffered yet (add buffering later if things are slow) */
+                            );
+            /* Now to handle any requests by the progress routine, COPYSPLICE_PROGRESS_CONTINUE
+            is normal.  Invalid requests cause the program to crash! */
+            switch (request)
+            {
+              case COPYSPLICE_PROGRESS_CONTINUE :
+              {
+                /* (do nothing) */
+                break;
+              }
+              case COPYSPLICE_PROGRESS_CANCEL :
+              {
+                breakOut = TRUE; /* Break out of copy loop at next chance */
+                delTarget = TRUE; /* Delete the file afterwards */
+                break;
+              }
+              case COPYSPLICE_PROGRESS_STOP :
+              {
+                origFilePosResume = ftell(Hsplice); /* Get how far we were */
+                breakOut = TRUE; /* Break out of copy loop at next chance */
+                break;
+              }
+              case COPYSPLICE_PROGRESS_QUIET : /* Don't want to be called again? */
+              {
+                PCopyProgressRoutine = NULL; /* Erase pointer to progress routine so that it is not called */
+                break;
+              }
+              default : /* Invalid request? */
+              {
+                #ifdef __DAYBO_DEBUGGING__
+                char errmsg[1024]; /* Space for error message */
+                sprintf(errmsg, "Invalid request from progress routine\nrequest: %lu, file: \"%s\", line: %u.\nThe program terminated abnormally, call Daybo Logic.", request, __FILE__, __LINE__); /* Create error message */
+                fprintf(stderr, errmsg); /* Output it to the error stream */
+                _FatalStr.Set(&_FatalStr, errmsg); /* Set the global error string in Slice */
+                raise(SIGABRT); /* Warn handlers prior to termination */
+                #endif
+                exit(EXIT_FAILURE); /* Terminate! */
+              }
+            }
+
+            firstLoop = FALSE;
+          }
+          copyProgressRoutineControlVar++; /* Increment control variable, gauge won't happen again for a while now if one steps through all this */
+        }
+        if (breakOut) break; /* Chance for cancelling */
+      }
+
+      getftime((int)Hsplice->fd, &ft); /* Get time from source file */
+      setftime((int)Hcopy->fd, &ft); /* Set time for source file, same as time for source */
+      fclose(Hcopy);
+
+      if (delTarget) /* Target (copy) should be deleted? */
+        remove(copyFn);
+
+      free(copyFn); /* The name of the newly created file is no longer required now */
+    }
+    else /* The copy could not be created! */
+    {
+      errorStatus = COPYSPLICE_CREATIONERROR; /* Set error status */
+    }
+
+    fclose(Hsplice); /* Close the original */
+  }
+  else /* Failed to open the original! */
+  {
+    /* Since AreThereAnyErrors was already called I cannot eloborate further as to the
+       cause of this error. */
+    errorStatus = COPYSPLICE_UNKNOWNERROR; /* Set emergency use only error number */
+  }
+  return errorStatus; /* Give error condition to caller */
+}
+/*-------------------------------------------------------------------------*/
+static char* GetSpliceFilename()
+{
+  /* locals */
+  static const char fn[] = _SPLICEFILENAME; /* Fixed string of Splice program */
+  char* dynPtr; /* Dynamic pointer of filename including path (returned to the caller) */
+
+  if (_CSCC.IsItemInStorage(csAppRootStr)) /* Is the app root string in the settings storage? */
+  {
+    size_t l;
+    char* pathInSto; /* Path in storage (dynamic) */
+    size_t dynPtrSize;
+
+    l = _CSCC.GetStringItem(csAppRootStr, NULL, (size_t)0U); /* Get length of string in storage */
+    if (l)
+    {
+      pathInSto = (char*)MALLOC( ++l ); /* Allocate space for path */
+      if (pathInSto)
+      {
+        memset(pathInSto, 0, l); /* Init new block (in case strcat() is used on it before strcpy()) */
+        _CSCC.GetStringItem(csAppRootStr, pathInSto, l); /* Copy us the path from the settings, thanks */
+      }
+    }/*(l)*/
+    dynPtrSize = l + 1 + strlen(fn) +1;
+    dynPtr = (char*)MALLOC( dynPtrSize ); /* Allocate memory on behalf of the caller */
+    if (dynPtr)
+    {
+      char lastChar;
+      memset(dynPtr, 0, dynPtrSize); /* Init new block */
+      if (pathInSto) strcpy(dynPtr, pathInSto); /* Copy the app base path to the name */
+      dynPtr = dlstrlib_strrev(dynPtr); /* Reverse the string (to make life simpler) */
+      lastChar = dynPtr[0]; /* Save first (last) char */
+      dynPtr = dlstrlib_strrev(dynPtr); /* Re-reverse the string (put it the right way around) */
+      if (lastChar != '\\') /* String does NOT end with a path separator? */
+      {
+        strcat(dynPtr, "\\"); /* Add a sep. to the string */
+      }
+      strcat(dynPtr, fn); /* Add filename! */
+    }
+
+    if (pathInSto) free(pathInSto);
+  }
+  else /* No, the app root string is not stored in the settings */
+  {
+    /* We don't acually need to dynamically allocate a string for this, but not doing
+    so would confuse the caller unless we complicated the function call which really
+    just causes more work for a very small inefficiency */
+    dynPtr = (char*)MALLOC( strlen(fn)+1 ); /* Allocate space on behalf of the caller */
+    strcpy(dynPtr, fn); /* Copy string into new block of memory */
+  }
+
+  return dynPtr; /* Give the dynamic pointer to the caller (they must free it) */
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_IsTargetTooSmall(const BYTE TargetDrive, FILE* _Hfile)
+{
+  /* locals */
+  MONSTERLONG64 tarSpace; /* Holds space on target drive */
+  BOOL dontClose; /* Whether to close the handle at the end */
+  FILE* Hfile;
+  BOOL result; /* Result for caller */
+  long int fz; /* File size of file to copy */
+  BOOL bisBigger; /* An argument to an ml64 function */
+
+  if (IsBadDriveLetter(TargetDrive)) return FALSE;
+
+  dskSpace_GetTotalSpace(&tarSpace, TargetDrive);
+  if (!tarSpace.lo && !tarSpace.hi) /* No space? */
+    return TRUE; /* No space on target, don't waste more time */
+
+  if (_Hfile) /* Handle was sent be caller? */
+  {
+    Hfile = _Hfile; /* Copy caller's handle */
+    dontClose = TRUE; /* Never close the caller's handle */
+  }
+  else /* Caller did not bother to sent the handle */
+  {
+    Hfile = fopen(GetSpliceFilename(), "rb"); /* Open file and get handle */
+    if (!Hfile) /* Could not open the file */
+      return TRUE; /* Say target too small */
+    dontClose = FALSE; /* Closing our own handle is a good idea */
+  }
+  /* Handle to file is now VALID! */
+  fz = subst_filelength(Hfile); /* Get length of file */
+  if ( ml64CompDWORD( &tarSpace, fz, &bisBigger ) != 0 ) /* Compare size on disk to program size */
+  {
+    if (bisBigger) /* Size bigger than space on disk? */
+    {
+      result = TRUE; /* To small! */
+      goto normalReturn;
+    }
+  }
+
+  result = FALSE; /* Target is NOT to small */
+normalReturn:
+  if (!dontClose) /* Allowed to close the handle? */
+    fclose(Hfile); /* Close the handle */
+  return result;
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_IsThereEnoughFreeSpace(const BYTE TargetDrive, FILE* _Hfile)
+{
+  /* locals */
+  MONSTERLONG64 tarFree; /* Holds free space on target drive */
+  BOOL dontClose; /* Whether to close the handle at the end */
+  FILE* Hfile;
+  BOOL result; /* Result for caller */
+  long int fz; /* File size of file to copy */
+  BOOL bisBigger; /* An argument in the call to an ml64 function */
+
+  if (IsBadDriveLetter(TargetDrive)) return FALSE;
+
+  dskSpace_GetFreeSpace(&tarFree, TargetDrive);
+  if (!tarFree.lo && !tarFree.hi) /* No free space? */
+    return FALSE; /* No free space on target, don't waste more time */
+
+  if (_Hfile) /* Handle was sent be caller? */
+  {
+    Hfile = _Hfile; /* Copy caller's handle */
+    dontClose = TRUE; /* Never close the caller's handle */
+  }
+  else /* Caller did not bother to sent the handle */
+  {
+    Hfile = fopen(GetSpliceFilename(), "rb"); /* Open file and get handle */
+    if (!Hfile) /* Could not open the file */
+      return TRUE; /* Say target too small */
+    dontClose = FALSE; /* Closing our own handle is a good idea */
+  }
+  /* Handle to file is now VALID! */
+  fz = subst_filelength(Hfile); /* Get length of file */
+  if ( ml64CompDWORD( &tarFree, fz, &bisBigger ) != 0 )
+  {
+    if (bisBigger) /* File size greater than free space on target drive? */
+    {
+      result = FALSE; /* To little free space! */
+      goto normalReturn;
+    }
+  }
+
+  result = TRUE; /* Target has enough free space */
+normalReturn:
+  if (!dontClose) /* Allowed to close the handle? */
+    fclose(Hfile); /* Close the handle */
+  return result;
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_IsBadDriveLetter(const BYTE TargetDrive)
+{
+  if (TargetDrive > 25) return TRUE; /* Out of range! */
+  return FALSE; /* Safe */
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_CanYouSeeTheFile()
+{
+  return CheckFileExistance(GetSpliceFilename());
+}
+/*-------------------------------------------------------------------------*/
+BOOL copysplice_AreThereAnyErrors(const BYTE TargetDrive, int* PerrorNumber, FILE* _Hfile)
+{
+  /* locals */
+  BOOL status; /* Safe... */
+  FILE* Hfile; /* Handle to the file to copy */
+  BOOL CloseHfile = FALSE;
+
+  if (PerrorNumber) *PerrorNumber = COPYSPLICE_NOERRORS; /* Reset caller's error number */
+
+  status = IsBadDriveLetter(TargetDrive);
+  if (status) /* Bad drive? */
+  {
+    status = FALSE;
+    if (PerrorNumber) *PerrorNumber = COPYSPLICE_BADDRIVELETTER;
+    goto giveStat;
+  }
+
+  if (_Hfile) /* Handle for file sent by caller? */
+  {
+    Hfile = _Hfile; /* Copy handle */
+    CloseHfile = FALSE; /* Don't close caller's handle */
+  }
+  else /* Handle was not sent by the caller? */
+  {
+    char* dpspfn = GetSpliceFilename(); // Get a copy of the splice filename (with path)
+    if (dpspfn) /* Allocated sucessfully? */
+    {
+      Hfile = fopen( dpspfn, "rb" ); // Attempt to open the file Splice
+      free(dpspfn); /* Release dynamic string of filename */
+    }
+    if (!Hfile)
+    {
+      if (PerrorNumber) *PerrorNumber = COPYSPLICE_SPLICEPROGNOTFOUND;
+      goto giveStat;
+    }
+    CloseHfile = TRUE; /* Close our own handle */
+  }
+
+  status = IsTargetTooSmall(TargetDrive, Hfile);
+  if (status) /* Target to small? */
+  {
+    status = FALSE;
+    if (PerrorNumber) *PerrorNumber = COPYSPLICE_TARGETTOOSMALL;
+    goto giveStat;
+  }
+  status = IsThereEnoughFreeSpace(TargetDrive, Hfile);
+  if (!status) /* Not enough free space? */
+  {
+    if (PerrorNumber) *PerrorNumber = COPYSPLICE_NOTENOUGHFREESPACE;
+    goto giveStat;
+  }
+
+giveStat: /* Time to give the status to the caller */
+  if (CloseHfile) /* Permitted to close file handle? */
+    fclose(Hfile); /* Do it! */
+  return !status; // Not status : Why? Because we return TRUE there are errors as opposed to TRUE everything is safe
+}
+/*-------------------------------------------------------------------------*/
+const char* copysplice_GetErrorMessageA(const int ErrorNumber)
+{
+  static const char msgs[][128] = {
+    "The copy was completed successfully",
+    "The total size of the target disk was to small for the recovery program\n(which can't be cut into slices!)",
+    "There is not enough free space left on the drive",
+    "The file system is corrupt or there may be a physical defect on the surface",
+    "The drive letter is not valid",
+    "The Splice program was not found",
+    "An unknown error happened while copying the file, call Daybo Logic",
+    "Drive not ready\n\nor\nReadonly filesystem\n\nor\nPermission denied."
+  };
+
+  if (ErrorNumber < sizeof(msgs)/sizeof(msgs[0])) /* Error number safe? */
+    return msgs[ErrorNumber]; /* Give pointer to requested message */
+
+  return NULL; /* The number was out of range */
+}
+/*-------------------------------------------------------------------------*/

Private/CoreLib/Fdko.c

+/* File Details Keeper Object designed for WSlice! by Overlord! */
+
+#include <Assert.H>
+#include <StdIO.H>
+#include <StdLib.H>
+#include <String.H>
+#include "Stds\DLStdInc.H" /* The Daybo Logic standard inclusions header */
+#include "DLUtils\DLUtils.H" /* The Daybo Logic utilities */
+#pragma hdrstop
+
+#include "Headers\AnsiSfnc.H" /* Daybo Logic ANSI replacements */
+#include "CoreLib\FDKO.H" /* My header */
+
+/* Definition of ASSERTRANGE macro */
+#ifdef ASSERTRANGE /* Someone else using this macro? */
+#  undef ASSERTRANGE /* We will delete their version from the private compilation of this module (it won't effect the person who uses it elsewhere) */
+#endif
+#define ASSERTRANGE(EntryIndex) ( assert( (EntryIndex) < CORELIB_FDKO_ENTRYCOUNT ) )
+/*-------------------------------------------------------------------------*/
+/* Internal functions which are never exposed to the user of the object */
+static void S_CORELIB_FDKO_Link(PS_CORELIB_FDKO PObject);
+static void S_CORELIB_FDKO_Init(PS_CORELIB_FDKO PObject);
+static BOOL S_CORELIB_FDKO_Open(PS_CORELIB_FDKO PObject, const unsigned int EntryIndex, const char* AccessString); /* Used internally by the more specific open functions */
+/* Internal functions exposed through pointers in the object */
+static BOOL S_CORELIB_FDKO_SetName(void*, const unsigned int EntryIndex, const char* NewFN);
+static BOOL S_CORELIB_FDKO_GetName(void*, const unsigned int EntryIndex, char* YourFN, const size_t YourSize);
+static size_t S_CORELIB_FDKO_GetNameLength(void*, const unsigned int EntryIndex);
+static void S_CORELIB_FDKO_ClearName(void*, const unsigned int EntryIndex);
+static BOOL S_CORELIB_FDKO_Create(void*, const unsigned int EntryIndex);
+static BOOL S_CORELIB_FDKO_ReadOpen(void*, const unsigned int EntryIndex);
+static BOOL S_CORELIB_FDKO_Close(void*, const unsigned int EntryIndex);
+static size_t S_CORELIB_FDKO_Read(void*, const unsigned int EntryIndex, void* ptr, size_t size, size_t n);
+static size_t S_CORELIB_FDKO_Write(void*, const unsigned int EntryIndex, const void* ptr, size_t size, size_t n);
+static const long S_CORELIB_FDKO_GetFileLength(void*, const unsigned int EntryIndex);
+static void S_CORELIB_FDKO_InvalidateLenCache(void*, const unsigned int EntryIndex);
+static int S_CORELIB_FDKO_Seek(void*, const unsigned int EntryIndex, const long offset, int whence);
+static BOOL S_CORELIB_FDKO_IsOpen(void* PObject, const unsigned int EntryIndex);
+static BOOL S_CORELIB_FDKO_IsEOF(void* PObject, const unsigned int EntryIndex);
+static long int S_CORELIB_FDKO_Tell(void* PObject, const unsigned int EntryIndex);
+static BOOL S_CORELIB_FDKO_Rewind(void* PObject, const unsigned int EntryIndex);
+static FILE* S_CORELIB_FDKO_GetHandle(void* PObject, const unsigned int EntryIndex);
+/* Global objects */
+S_CORELIB_FDKO _FileDetails;
+/*-------------------------------------------------------------------------*/
+void S_CORELIB_FDKO_Construct(PS_CORELIB_FDKO PObject)
+{
+  assert(PObject);
+  S_CORELIB_FDKO_Link(PObject);
+  S_CORELIB_FDKO_Init(PObject);
+}
+/*-------------------------------------------------------------------------*/
+void S_CORELIB_FDKO_Destruct(PS_CORELIB_FDKO PObject)
+{
+  unsigned int i;
+
+  assert(PObject);
+
+  for (i = 0; i < CORELIB_FDKO_ENTRYCOUNT; i++) /* All entries */
+  {
+    PObject->Close(PObject, i); /* Close file */
+    PObject->ClearName(PObject, i); /* Clear the file's name */
+  }
+  return;
+}
+/*-------------------------------------------------------------------------*/
+static void S_CORELIB_FDKO_Link(PS_CORELIB_FDKO PObject)
+{
+  /* Link member function using pointers in the object */
+  PObject->SetName             = S_CORELIB_FDKO_SetName;
+  PObject->GetName             = S_CORELIB_FDKO_GetName;
+  PObject->GetNameLength       = S_CORELIB_FDKO_GetNameLength;
+  PObject->ClearName           = S_CORELIB_FDKO_ClearName;
+  PObject->Create              = S_CORELIB_FDKO_Create;
+  PObject->ReadOpen            = S_CORELIB_FDKO_ReadOpen;
+  PObject->Close               = S_CORELIB_FDKO_Close;
+  PObject->Read                = S_CORELIB_FDKO_Read;
+  PObject->Write               = S_CORELIB_FDKO_Write;
+  PObject->GetFileLength       = S_CORELIB_FDKO_GetFileLength;
+  PObject->InvalidateLenCache  = S_CORELIB_FDKO_InvalidateLenCache;
+  PObject->Seek                = S_CORELIB_FDKO_Seek;
+  PObject->IsOpen              = S_CORELIB_FDKO_IsOpen;
+  PObject->IsEOF               = S_CORELIB_FDKO_IsEOF;
+  PObject->Tell                = S_CORELIB_FDKO_Tell;
+  PObject->Rewind              = S_CORELIB_FDKO_Rewind;
+  PObject->GetHandle           = S_CORELIB_FDKO_GetHandle;
+}
+/*-------------------------------------------------------------------------*/
+static void S_CORELIB_FDKO_Init(PS_CORELIB_FDKO PObject)
+{
+  unsigned int i;
+
+  for (i = 0; i < CORELIB_FDKO_ENTRYCOUNT; i++)
+  {
+    PObject->_name[i] = NULL;
+    PObject->_H[i] = NULL;
+    PObject->_lenCache[i] = 0L;
+    PObject->_lenCacheValid[i] = FALSE;
+  }
+}
+/*-------------------------------------------------------------------------*/
+static BOOL S_CORELIB_FDKO_Open(PS_CORELIB_FDKO PObject, const unsigned int EntryIndex, const char* AccessString)
+{
+  ASSERTRANGE(EntryIndex);
+  if (PObject->_H[EntryIndex]) /* Already got an open file? */
+  {
+    #ifdef __DAYBO_DEBUGGING__
+      assert(PObject->_H[EntryIndex]);
+    #endif /*__DAYBO_DEBUGGING__*/
+    return FALSE; /* Fail! */
+  }
+  if (!PObject->_name[EntryIndex]) /* No filename? */
+  {
+    #ifdef __DAYBO_DEBUGGING__
+      assert(!PObject->_name[EntryIndex]);
+    #endif /*__DAYBO_DEBUGGING__*/
+    return FALSE; /* Fail! */
+  }
+
+  PObject->_H[EntryIndex] = fopen(PObject->_name[EntryIndex], AccessString); /* Open filename and get handle in the access mode specified */
+  if (!PObject->_H[EntryIndex]) /* Failed to obtain a handle? */
+    return FALSE; /* Damn! */
+
+  PObject->InvalidateLenCache(PObject, EntryIndex); /* We don't know the length of this file yet */
+  return TRUE; /* Yeah! */
+}
+/*-------------------------------------------------------------------------*/
+static BOOL S_CORELIB_FDKO_SetName(void* PObject, const unsigned int EntryIndex, const char* NewFN)
+{
+  PS_CORELIB_FDKO this = (S_CORELIB_FDKO*)PObject; /* Cast pointer to an unknown type into object pointer */
+
+  ASSERTRANGE(EntryIndex);
+  assert(this);
+  if (this->_name[EntryIndex]) /* Already got a name? */
+  {
+    this->ClearName(this, EntryIndex); /* Clear the current name */
+    if (this->_name[EntryIndex]) /* Failed to clear name? */
+      return FALSE; /* Do not proceed */
+  }
+  if (NewFN && NewFN[0])
+  {
+    if (this->_H[EntryIndex]) /* File open? */
+      return FALSE; /* Fail! */
+
+    this->_name[EntryIndex] = (char*)MALLOC( strlen(NewFN) + 1 ); /* Allocate space to store filename */
+    if (!this->_name[EntryIndex]) /* Failed to allocate copy! */
+      return FALSE; /* Fail! */
+
+    strcpy(this->_name[EntryIndex], NewFN); /* Store the new filename */
+  }
+
+  return TRUE; /* Success */
+}
+/*-------------------------------------------------------------------------*/
+static BOOL S_CORELIB_FDKO_GetName(void* PObject, const unsigned int EntryIndex, char* YourFN, const size_t YourSize)
+{
+  PS_CORELIB_FDKO this = (S_CORELIB_FDKO*)PObject; /* Cast pointer to an unknown type into object pointer */
+
+  ASSERTRANGE(EntryIndex);
+  assert(this);
+  if (!this->_name[EntryIndex]) /* Filename missing! */
+  {
+    if (YourFN)
+      memset(YourFN, 0, YourSize); /* Zero the caller's buffer */