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
VirtualArray.cpp
types.h
Cyb
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
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();
}
//---------------------------------------------------------------------------
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