What's new

Buggy Virtual Array class?

Cyberman

Moderator
Moderator
So I've been pulling my hair out over this particular class I made and it's driving me a bit batty.

I'm not sure if the class is the fault or something else, essentially it takes file and presents it as a virtual array up to as large as the OS can handle (64 bit indexing however iostream->read doesn't support beyond 32 bit indexing I think).

What is it doing wrong? Well with using ISO disk images it seems to end 1 byte prematurely on each sector. I examine the same file using a hex file editor and it appears to be in order. However the Virtual array doesn't give the right data for the right location. It's off by 1 byte per sector.

Of course this sucks if one is going to use such an array to view data in a ISO image (because it's always off).
types.h defines things used by this class and some others it is part of.

This is the current source code:
VirtualArray.h
Code:
//---------------------------------------------------------------------------

#ifndef VirtualArrayH
#define VirtualArrayH
#include <iostream>
#include <fstream>
#include <ios>
#include "types.h"
//---------------------------------------------------------------------------
class VirtDatArray
{
   enum DatArrayConsts {
      CacheEntries = 4096,
      CacheBlockSize = 256,
      CacheEntryNotUsed = 0xFFFF
      };
   private:
      // how big is this file of data?
      uint64            MySize;
      // where is this file located?
      std::string       MyPath;
      // cache Data for array
      // segments are 256 byte chunks
      // cache tag references;
      unsigned __int64  DataCacheTag[CacheEntries];
      // when was this last accessed?
      unsigned short    DataAge[CacheEntries];
      // references to cache data
      uint8            *DataCache[CacheEntries];
      int               LastTag;

      void              Init(void);
      std::string       GetPath(void);
      uint64            GetID(uint64 _value);
      uint64            GetLocation(uint64   _value);
      void              SetPath(std::string);
      void              AgeCache(void);
      int               OldestCache(void);
   public:
      VirtDatArray();
      VirtDatArray(std::string);
      __property std::string Path = { read=GetPath, write=SetPath };
      uint8 operator[](unsigned __int64);
      ~VirtDatArray();
      __property  uint64  PhysicalSize = { read=MySize };
};
//---------------------------------------------------------------------------
#endif
VirtualArray.cpp
Code:
//---------------------------------------------------------------------------

//#include <vcl.h>
//#pragma hdrstop

#include "VirtualArray.h"

//---------------------------------------------------------------------------

//#pragma package(smart_init)
//---------------------------------------------------------------------------
VirtDatArray::VirtDatArray()
{
   MyPath = "";
   Init();
}
//---------------------------------------------------------------------------
VirtDatArray::VirtDatArray(std::string APath)
{
   MyPath = APath;
   Init();
}
//---------------------------------------------------------------------------
VirtDatArray::~VirtDatArray()
{
   for(int Index = 0; Index < CacheEntries; Index++)
   {
      if(DataCache[Index] != NULL)
         delete DataCache[Index];
   }
}
//---------------------------------------------------------------------------
void  VirtDatArray::AgeCache(void)
{
   for(int Index = 0; Index < CacheEntries; Index++)
   {
      if(DataAge[Index] != CacheEntryNotUsed)
      {
         DataAge[Index]++;
      }
   }
}
//---------------------------------------------------------------------------
int   VirtDatArray::OldestCache(void)
{
   int   Index, Oldest;

   Oldest = 0;
   Index = 1;
   while(Index < CacheEntries)
   {
      if(DataAge[Index] >= DataAge[Oldest])
         Oldest = Index;
      Index++;
   }
   return Oldest;
}
//---------------------------------------------------------------------------
void VirtDatArray::Init(void)
{
   std::fstream         File;
   unsigned __int64     Addr;
   int                  Index, ReadSz;

   // for each cache entry
   for( Index = 0; Index < CacheEntries; Index++)
   {
      // set the tag to 0
      DataCacheTag[Index] =   0;
      // if the Datacache entry is not null delete it
      if(DataCache[Index] != NULL)
         delete DataCache[Index];
      // set it to null
      DataCache[Index] =      NULL;
      // this entry is not used at this time
      DataAge[Index] =        CacheEntryNotUsed;
   }
   // we always tagged the first entry right?
   LastTag = 0;
   // now if the path is not empty
   if(!MyPath.empty())
   {
      // open the file
      File.open(MyPath.c_str(), std::fstream::in);
      // if the file isn't a problem
      if(File.is_open())
      {
         // move to it's end
         File.seekg(0, std::fstream::end);
         // our size is it's length
         MySize = (uint32)File.tellg();
         // move to it's begining
         File.seekg(0, std::fstream::beg);
         // for each cache entry
         for(int Index = 0; Index < CacheEntries; Index++)
         {
            // create a new cache block
            DataCache[Index] = new uint8[CacheBlockSize];
            // read into that cache block data from the file
            File.read(DataCache[Index], CacheBlockSize);
            // find out how many bytes were read
            ReadSz = File.gcount();
            if(ReadSz != CacheBlockSize)
            {
               ReadSz = CacheBlockSize;
               Index = Index;
               ReadSz = CacheEntries;
            }
            // store the 64 bit value into the tag array
            DataCacheTag[Index] = (uint64)(Index % CacheEntries);
            // this data is new so tag it new
            DataAge[Index] = 0;
         }
         // close the file
         File.close();
      }
      else
         // there was a problem so we are an empty file
         MySize = 0;
   }
   else
      // we have an empty file name
      MySize = 0;
}
//---------------------------------------------------------------------------
uint64   VirtDatArray::GetID(uint64  _value)
{
   // shift the entire value 8 bits right
   return (_value >> 8);
}
//---------------------------------------------------------------------------
uint64   VirtDatArray::GetLocation(uint64  _value)
{
   // shift the entire value 8 bits right
   return (_value << 8);
}
//---------------------------------------------------------------------------
uint8 VirtDatArray::operator[](uint64 Addr)
{
   uint64      CacheID;
   int         Index, ReadSZ;
   uint8       Return;

   Return = 0xFF;
   if(Addr < MySize)
   {
      CacheID = GetID(Addr);
      // scan from the first cache entry
      Index = 0;
      if((Addr >= 0x92Fl)&&(Addr <= 0x940l))
      {
         Index = Index;
      }
      // check each entry for our chunk of data
      // tell we have no more
      while(
         (Index < CacheEntries)&&
         (DataCacheTag[Index] != CacheID))
      {
         Index++;
      }
      // if we found a matching entry
      if((Index < CacheEntries)&&
         (DataAge[Index] != CacheEntryNotUsed)
         )
      {  // cache hit we just need the lower byte to return the data
         if(DataCache[Index] != NULL)
         {
            Return = DataCache[Index][(Addr & 0x00FF)];
         }
         else
         {  // this is a bad thing
            Return = 0xFF;
         }
         // if we are at a new index
         if(Index != LastTag)
         {  // age the cache
            AgeCache();
         }
         // keep the last accessed data the newest
         DataAge[Index] = 0;
         // new LastTag
         LastTag = Index;
      }
      else
      {  // we have a cache miss
         std::fstream   File;

         // we need to load the data we want
         // age all existing cache entries
         AgeCache();
         // first find the oldest entry
         Index = OldestCache();
         // open the file we are reading our data from
         File.open(MyPath.c_str(), std::fstream::in);
         // if the file exists
         if(File.is_open())
         {
            // seek from the begining to the nearest 256 byte chunk
            File.seekg(GetLocation(CacheID), std::fstream::beg);
            // if the cache entry is NULL
            if(DataCache[Index] == NULL)
            {
               // allocate a block
               DataCache[Index] = new uint8[CacheBlockSize];
            }
            // read in the chunk into the cache
            File.read(DataCache[Index], CacheBlockSize);
            if(File.gcount() != CacheBlockSize)
            {
               Index = Index;
            }
            // close the file
            File.close();
         }
         // set the return information to the location in the data cache
         Return = DataCache[Index][Addr & 0x00FF];
         // age everything
         AgeCache();
         // this is now the latest location accessed
         DataAge[Index] = 0;
         // set the tag for this data block to find it later
         DataCacheTag[Index] = CacheID;
      }
   }
   return Return;
}
//---------------------------------------------------------------------------
void VirtDatArray::SetPath(std::string Path)
{
   // assign a new path
   MyPath = Path;
   // initialize ourselves
   Init();
}
//---------------------------------------------------------------------------
types.h
Code:
//---------------------------------------------------------------------------

#ifndef typesH
#define typesH
//---------------------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <string>
//---------------------------------------------------------------------------
#ifndef  uint64
typedef  unsigned __int64  uint64;
#endif
#ifndef  int64
typedef  __int64           int64;
#endif
typedef  unsigned int      uint32;
typedef  int               int32;
typedef  unsigned short    uint16;
typedef  short             int16;
typedef  unsigned char     uint8;
typedef  char              int8;

extern   uint8    GetUINT8(char *);
extern   int8     GetINT8(char *);
extern   uint16   GetUINT16(char *);
extern   int16    GetINT16(char *);
extern   uint32   GetUINT32(char *);
extern   int32    GetINT32(char *);

extern   uint8    GetUINT8(std::fstream &);
extern   int8     GetINT8(std::fstream &);
extern   uint16   GetUINT16(std::fstream &);
extern   int16    GetINT16(std::fstream &);
extern   uint32   GetUINT32(std::fstream &);
extern   int32    GetINT32(std::fstream &);
extern   std::string  GetStr(char *, int);
//extern   std::string  FF7Chr2String(void *, int);
//---------------------------------------------------------------------------
#endif
Cyb
 

Top