// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- //
// C++ Header File Name: vbdfile.hpp 
// Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
// Produced By: Doug Gaer    
// File Creation Date: 02/04/1997 
// Date Last Modified: 11/05/1998
// Copyright (c) 1997 Douglas M. Gaer
// --------------------------------------------------------- // 
// ---------- Include File Description and Details  ---------- // 
// ----------------------------------------------------------- // 
/*
The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
All those who put this code or its derivatives in a commercial
product MUST mention this copyright in their documentation for
users of the products in which this code or its derivative
classes are used. Otherwise, you have the freedom to redistribute
verbatim copies of this source code, adapt it to your specific
needs, or improve the code and release your improvements to the
public provided that the modified files carry prominent notices
stating that you changed the files and the date of any change.

THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
CORRECTION.

The VBD file manager class is responsible for handling all
low-level file operations through the use of VBDFile objects
or by inheriting the VBDFile class. Low-level file operations
refer to functions such as: Create(), Open(), Read(), Write(),
Alloc(), Delete(), and Close(). These functions contain all the
routines needed to create and maintain VBD files in accordance
with the VBD File Format. VBDFile objects are reference counted
and must be created dynamically due to the way reference
counting is implemented. 

Changes:
================================================================
01/15/1998 - The template implementation in refcount.hpp caused a
linker error when compling under HPUX 10.20 (using HPUX CPP 1024)
in some wxWindows applications.
Changed by: Doug Gaer

01/15/1998 - Added the __USE_VBDREFCOUNT__ macro to enable use of
the non-template version of the Refcount class.
Changed by: Doug Gaer

01/20/1998 - Combined the debug version with this version.
Changed by: Doug Gaer

01/20/1998 - Added BlindOpen() debug function.
Changed by: Doug Gaer

01/20/1998 - Added VBSearch() debug function.
Changed by: Doug Gaer

01/20/1998 - VBDSignature data member changed from private to
public access for compatibility with VB_DEBUG program.
Changed by: Doug Gaer

01/20/1998 - VBDVersion data member changed from private to
public assess for compatibility with VB_DEBUG program.
Changed by: Doug Gaer

02/06/1998 - The ReadVBHdr() function was changed to throw a
CSyncError execption instead of a CFileCorrupt exception for
file synchronization errors.
Changed by: Doug Gaer

03/11/1998 - Modified the Open() function to check the true
end of file and compare it to the VBD file header's end of
file. If the true end of file is greater then VBD file header's
EndOfFile value, the EndOfFile value will be changed to match the
true end of file.
Changed by: Doug Gaer

03/12/1998 -  Changed ReadHdr() function to pubilc access
so that applications can force the VBD file header to reread.
Changed by: Doug Gaer

03/13/1998 - Modified InitHdr() function to write the VBD file
header and flush the disk buffers to maintain file integrity
during multiple file access when a new file has been created.
Changed by: Doug Gaer

03/13/1998 - Modified the Write() function to allow applications 
to flush disk buffers after each write operation to ensure the
file data stays in sync during multiple file access. This approach
was used as opposed to un-buffered read and writes to maintain code
portability between all platforms.  
Changed by: Doug Gaer

03/13/1998 - Modified the Alloc() function to write the VBD file
header to disk after each allocation to ensure that the VBD file
header stays in sync during multiple file access.
Changed by: Doug Gaer

03/13/1998 - Modified the Delete() function to write the VBD file
header to disk after each deletion to ensure that the VBD file
header stays in sync during multiple file access.
Changed by: Doug Gaer

03/13/1998 - Added the TestVBDHeader() function to ensure that
the in memory copy of the VBD file header and the disk copy
stay in sync during multiple file access.
Added by: Doug Gaer

03/13/1998 - Modified the FindFirstVB() function to read the
VBD file from the disk before each search to ensure that the
VBD file header stays in sync during multiple file access.
Changed by: Doug Gaer

03/13/1998 - Modified the VBDeleted() function to read the
VBD file from the disk before each search to ensure that the
VBD file header stays in sync during multiple file access.
Changed by: Doug Gaer

03/13/1998 - Added non-const versions of GetSignature(),
GetVersion(), FileHeaderSize(), VBHeaderSize(), VBDFileName
and GetFileStatus().
Added by: Doug Gaer

03/13/1998 - Removed the const versions of the StaticArea(),
GetFreeSpace(), GetVBDFreeSpace(), GetEOF(), GetHeapStart()
and GetHighestVB() functions.
Changed by: Doug Gaer

03/13/1998 - Modified the StaticArea(), GetFreeSpace(),
GetVBDFreeSpace(), GetEOF(), GetHeapStart() and GetHighestVB()
functions to compare the in memory copy and disk copy of the
VBD file header. If they differ the VBD file header will be
reread from the disk. 
Changed by: Doug Gaer

03/16/1998 - Modified the VBTotal() function to perform its own
independent read operation. Will throw CAccessViolation exception
if an end of file error occurs during multiple file access over
an NFS mount.
Changed by: Doug Gaer

03/16/1998 - Modified the FindFirstVB() function to perform its 
own independent read operation. Will throw CAccessViolation
exception if an end of file error occurs during multiple file
access over an NFS mount.
Changed by: Doug Gaer

03/17/1998: Modified the Read() function to throw CAccessViolation
exception if an end of file error occurs during multiple file
access over an NFS mount.
Changed by: Doug Gaer

07/22/1998: In version 1025 the Open function no longer checks 
the revision letter when opening a file. Also, the last character 
of the VBDSignature member has been changed from a space to a
null byte.
Changed by: Doug Gaer

07/22/1998: Version number changed to 1025, Revsion 0, to reflect
all modifcations made from 01/15/1998 to 07/22/1998. 
Changed by: Doug Gaer

09/03/1998: Added the FSListCorrupt constant to tell the Reclaim(),
UnDelete(), and VBDeleted() functions that the free space list is
corrupt.
Added by: Doug Gaer

09/04/1998: Added two versions of the Reclaim() function, one using
the best-fit method and the other using the first-fit method. Define
the __RECLAIM_BEST_FIT__ macro to use the best-fit routine or the
__RECLAIM_FIRST_FIT__ macro to use the first-fit routine.
Added by: Doug Gaer

09/04/1998: Modifed the Reclaim() and VBDeleted() functions, allowing
them to write the FSListCorrupt constant to the file header and abort
the operation.
Changed by: Doug Gaer

09/08/1998: Changed the UnDelete() function to mange changes to the
free space list independently of the Reclaim() function.
Changed by: Doug Gaer

09/08/1998: By default the file manager will use the first-fit method
to reclaim deleted or removed blocks. The __RECLAIM_BEST_FIT__ macro
must be defined to use the best-fit method.
Changed by: Doug Gaer

09/08/1998: The Remove() function no longer allocates memory for the
length of the entire block. A single byte value, equal to zero, is
written to the file byte by byte for the length of the block.
Changed by: Doug Gaer

09/09/1998: Modified the VBDeleted() function to pass back the
total number of deleted and removed blocks in the __UWORD__ *d,
__UWORD__ *r variables.
Changed by: Doug Gaer

09/11/1998: Added the __DOS_INCLUDES__ macro for compilers that
require the use of DOS path separators in include files.
Added by: Doug Gaer

09/21/1998: Added the CalcChecksum() function. This function will
return a 32-bit CRC checksum for specified number of bytes at a
given file address.
Added by: Doug Gaer

09/24/1998: Added the GetRevLetter() function. This function will
return a single character representing the VBD file's revision
letter.
Added by: Doug Gaer

09/24/1998: Modified the InitHdr() and Open() functions to record
the VBD file's revision letter in the rev_letter variable.
Changed by: Doug Gaer

09/24/1998: Modified the Alloc() function to allocate an additional
4 bytes with each block to allow an application to store a 32-bit
checksum with each block. This changes the VBD revision letter from
zero to rev 'A'.
Changed by: Doug Gaer

09/24/1998: Modified the Write() function to perform a CRC check
with each write operation by default. The CRC check will compare
of the CRC of the buffer to the CRC of the actual bytes written to
disk. If the CRC test fails, the Write() function will throw a
CChecksumError exception.
Changed by: Doug Gaer

09/25/1998: Added the WriteObjectChecksum() function to write
a 32-bit checksum for an object in the pre-allocated space at
the end of the block. This function will return zero for any
file below revision letter 'A'.
Added by: Doug Gaer

09/25/1998: Added the ReadObjectChecksum() function to read
the 32-bit checksum of an object from the pre-allocated space
at the end of the block. This function will always return true
for any file below revision letter 'A'.
Added by: Doug Gaer

09/25/1998: Added the ReOpen() function to reassign the file
pointer to another file.
Added by: Doug Gaer

09/28/1998: Modified the Remove() function to allocate
memory for the length of the object by default. If memory
allocation fails or is disabled a single byte value, equal
to zero, is written to the file byte by byte for the length
of the object. 
Changed by: Doug Gaer

09/30/1998: Added the Rewind() function to reposition the file
pointer to the beginning of a file.
Added by: Doug Gaer

09/30/1998: Added the GetPosition() function to get the current
file position using fpos_t type.
Added by: Doug Gaer

09/30/1998: Added the SetPosition() function to reset the current
file position using fpos_t type.
Added by: Doug Gaer

09/30/1998: Added the SeekTo() function to perform an optimized
seek operation by moving the file position indicator based on the
current stream position.
Added by: Doug Gaer

10/01/1998: Modifed the Alloc() function to reposition the file
pointer to the file address where the next write operation
should take place after allocating space for an object.
Changed by: Doug Gaer
*/
// ----------------------------------------------------------- //  
#ifndef __VBDFILE_HPP
#define __VBDFILE_HPP

#include <stdio.h>

// Enable to use the non-template version of the Refcount class
// #ifndef __USE_VBDREFCOUNT__
// #define __USE_VBDREFCOUNT__
// #endif

#ifdef __USE_VBDREFCOUNT__
#include "vbdref.hpp"
#else
#include "refcount.hpp"
#endif

#include "ehandler.hpp"
#include "dtypes.hpp"
#include "int32.hpp"
#include "uint32.hpp"
#include "crc32.hpp"

// typedefs for file operations and stream position
typedef INT32 FAU; // (F)ile (A)ddress (U)nit, physical file address type
typedef INT32 StreamPos;   // Stream position

// CRC-32 checksum used to detect bit errors (4 bytes)
typedef UINT32 vbChecksum;

// Variable Block Database (F)ile (H)eader
struct FileHeader // VBD file header information (28 bytes total)
{ 
  FAU FreeSpace;      // Address to first block of free heap space (4 bytes)
  FAU EndOfFile;      // Address of byte after end of file (4 bytes)
  FAU HeapStart;      // Address of the start of the heap space (4 bytes)
  FAU HighestVB;      // Highest allocated (V)ariable (B)lock
  __SBYTE__ Signature[8]; // Signature used for every VBD file (8 bytes)
  INT32 Version;      // VBD Version number (4 bytes)
};

// (V)ariable (B)lock (H)eader 
struct VBHeader // Marks each variable data block (16 bytes total)
{
  UINT32 CkWord;      // Check-word used to mark each block (4 bytes)
  UINT32 Length;      // Block Length (Header + Object + CRC) (4 bytes) 
  UINT32 Status;      // Status of the block's dynamic data (4 byte)
  FAU NextDeletedVB;  // Pointer to next deleted block (4 bytes) 
};

// Constants for dynamic data attributes used by the VB Header Status member
const __SBYTE__ NormalVB  = 'N'; // Normal Read/Write attribute 
const __SBYTE__ DeletedVB = 'D'; // Deleted Variable Block 
const __SBYTE__ RemovedVB = 'R'; // Removed Variable Block
const __SBYTE__ BadVB     = 'B'; // Bad Variable Block

// Constants for file operations and stream position 
const int MaxNameLength   = 255;        // Max len of file names
const FAU StartOfFile     = 0;          // First byte in the file
const FAU CurrAddress     = -1;         // Indicates current location
const UINT32 CheckWord    = 0x0000fefe; // 32-bit Check Word
const INT32 FSListCorrupt = -1;         // Free space list is corrupt

class VBDFile : public CountedObject
{
public:
  enum IO_Operation { READ, WRITE, SEEK, REWIND };
  enum AccessMode { READWRITE, READONLY };

public:
  VBDFile();
  virtual ~VBDFile();

public: // Debug VBD File manager: revisions 01/20/1997
  virtual int BlindOpen(const char *FName, AccessMode Mode = READONLY);
  FAU VBSearch(FAU Offset = 0);     // Finds first valid Variable Block
  static __SBYTE__ VBDSignature[8]; // Signature for VBD files
  static __LWORD__ VBDVersion;      // Version number VBD files

public:
  virtual int Create(const char *FName, FAU StaticSize = 0);
  virtual int Open(const char *FName, AccessMode Mode = READWRITE);
  virtual int ReOpen(const char *FName, AccessMode Mode = READWRITE);
  virtual void Close(int flush = 1);
  virtual void Flush();
  FAU Alloc(__UWORD__ Bytes);
  FAU ReAlloc(FAU Address, __UWORD__ Bytes); 
  int Delete(FAU Address); 
  int Remove(FAU Address, int mem_alloc = 1);
  int UnDelete(FAU Address);
  void Read(void *buf, __UWORD__ Bytes, FAU Address = CurrAddress);
  void Write(const void *buf, __UWORD__ Bytes, FAU Address = CurrAddress,
             int flush = 1, int bit_test = 1);
  void Seek(FAU Offset, int SeekMode = SEEK_SET);
  FAU SeekTo(FAU Address);
  void Rewind();
  void SetPosition(const fpos_t fpos);
  fpos_t GetPosition();
  int IsOpen() const { return (Status & 0x02); }
  int ReadOnly() const { return (Status & 0x04) == 0; }
  int ReadyForWriting() const { return (Status & 0x07) == 0x07; }
  void ClearErr() { Error->ClearException(); Status |= 0x01; }
  int IsOK() const { return (Status & 0x03) == 0x03; }
  __UWORD__ ObjectLength(FAU Address = CurrAddress);
  __UWORD__ VBLength(FAU Address = CurrAddress);
  StreamPos FilePosition();

  // 32-bit CRC checksum routines
  __ULWORD__ CalcChecksum(__UWORD__ Bytes, FAU Address, int mem_alloc = 1);
  UINT32 WriteObjectChecksum(FAU Address);
  int ReadObjectChecksum(FAU Address, __ULWORD__ *object_crc = 0,
			 __ULWORD__ *calc_crc = 0);

  // Static file statistics
  const char *GetSignature() const;
  char *GetSignature();
  char GetRevLetter() { return rev_letter; }
  const char GetRevLetter() const { return rev_letter; }
  INT32 GetVersion() const { return Header.Version; }
  INT32 GetVersion() { return Header.Version; }
  size_t FileHeaderSize() const { return sizeof(FileHeader); }
  size_t FileHeaderSize() { return sizeof(FileHeader); }
  size_t VBHeaderSize() const { return sizeof(VBHeader); }
  size_t VBHeaderSize() { return sizeof(VBHeader); }
  const char *VBDFileName() const { return (const char *)FileName; }
  char *VBDFileName() { return FileName; }
  __SBYTE__ GetFileStatus() const { return Status; }
  __SBYTE__ GetFileStatus() { return Status; }
  __LWORD__ StaticArea();

  // Dynamic file statistics
  FAU GetFreeSpace();
  FAU GetVBDFreeSpace(); // Use this version for wxWindows programs
  FAU GetEOF();
  FAU GetHeapStart();
  FAU GetHighestVB();

  // Return total number of removed and deleted VBs
  INT32 VBDeleted(__UWORD__ *d = 0, __UWORD__ *r = 0);
  
  int TestVBDHeader();  // Keeps VBD file header's dynamic data in sync
  __UWORD__ VBTotal();  // Return total number of Variable Blocks
  FAU FindFirstVB(FAU Offset = 0);     // Finds first valid Variable Block
  FAU FindNextVB(FAU Offset = 0);      // Finds next after first 
  FAU FindFirstObject(FAU Offset = 0); // Finds first object
  FAU FindNextObject(FAU Offset = 0);  // Finds next after first 

public: // General purpose file utilities
  static int Exists(const char *FName);
  static __LWORD__ FileSize(const char *FName);

protected:
  FAU Reclaim(__UWORD__ Bytes); 
  void InitHdr();
  void WriteHdr();
  void ReadVBHdr(VBHeader &hdr, FAU Address = CurrAddress);
  void WriteVBHdr(const VBHeader &hdr, FAU Address = CurrAddress);

public: // 03/12/1998: Changed to pubilc access
  void ReadHdr();
  
protected:
  char FileName[MaxNameLength]; // Name of the file
  char rev_letter;              // Revision number
  FileHeader Header;            // File header as stored in memory
  FILE *fp;                     // Stream file handle
  IO_Operation LastOperation;   // Last I/O operation

  __SBYTE__ Status; // File Status bits used in VBD Files:
  // 210
  // |||---- good = 1, bad = 0
  // |+----- open = 1, closed = 0
  // +------ read/write = 1, read/only = 0

public: // Overloaded operators
  int operator!() const { return (Status & 0x03) != 0x03; }
  operator const int () const { return (Status & 0x03) == 0x03; }
};

#ifdef __USE_VBDREFCOUNT__
typedef vbdRefCount VBDFilePtr;
#else
typedef RefCount<VBDFile> VBDFilePtr;
#endif

#endif // __VBDFILE_HPP
// ----------------------------------------------------------- // 
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //
