Hi all. I have just done a class called VirtualFileSystem, but it is a problem, it is too fast in my opinion so can anyone make a fast check and see if anything looks wrong:
Code:
class VirtualFileSystem
{
private:
mutable std::ifstream infilestream;
mutable std::ofstream outfilestream;
mutable std::multimap<MD5String, std::map<unsigned long long int, unsigned short int>::iterator> hashdata;
mutable std::map<unsigned long long int, unsigned short int> numberdata;
std::vector<unsigned long long int> remove;
std::size_t blocksize;
char* block;
std::string filename;
public:
VirtualFileSystem(const std::string &,unsigned short int,bool);
~VirtualFileSystem();
void init(const std::string&);
void shutdown(const std::string&) const;
unsigned long long int add(const char*,unsigned short int);
unsigned long long int get(const char*, unsigned short int) const;
std::vector<unsigned char> get(const unsigned long long int&) const;
std::size_t GetSize() const;
};
VirtualFileSystem::VirtualFileSystem(const std::string & f, unsigned short int bsize = 8192, bool i = true)
: filename(f), outfilestream(f.c_str(),std::ios::binary | std::ios::app), infilestream(f.c_str(),std::ios::binary), blocksize(1024*8)
{
block = new char[bsize];
if(i)
{
init(f + ".ini");
}
}
VirtualFileSystem::~VirtualFileSystem()
{
delete [] block;
shutdown((filename + ".ini").c_str());
}
void VirtualFileSystem::init(const std::string& f)
{
hashdata.clear();
std::ifstream stream(f.c_str(),std::ios::binary);
MD5String md5;
unsigned long long int num;
unsigned short int length;
std::multimap<unsigned long long int, unsigned short int>::iterator it;
while(stream >> md5 >> num >> length)
{
numberdata[num] = length;
hashdata.insert(std::make_pair(md5,numberdata.find(num)));
}
}
void VirtualFileSystem::shutdown(const std::string& f) const
{
std::ofstream stream(f.c_str(),std::ios::binary | std::ios::trunc);
std::multimap<MD5String, std::map<unsigned long long int, unsigned short int>::iterator>::iterator it;
std::map<unsigned long long int, unsigned short int>::iterator it2;
for(it = hashdata.begin(); it != hashdata.end(); it++)
{
it2 = (*it).second;
stream << (*it).first << " " << (*it2).first << " " << (*it2).second;
}
outfilestream << std::flush;
}
unsigned long long int VirtualFileSystem::get(const char* data, unsigned short int size) const
{
if(size > blocksize)
{
return 0;
}
std::multimap<MD5String, std::map<unsigned long long int, unsigned short int>::iterator>::iterator it;
std::map<unsigned long long int, unsigned short int>::iterator it2;
MD5String md5(data,size);
for(it = hashdata.find(md5); it != hashdata.end(); it++)
{
it2 = (*it).second;
if(size != (*it2).second)
{
continue;
}
infilestream.seekg(blocksize*((*it2).first-1));
infilestream.read(block,size);
if(std::memcmp(block,data,size) == 0)
{
return (*it2).first;
}
}
return 0;
}
unsigned long long int VirtualFileSystem::add(const char* data,unsigned short int size)
{
unsigned long long int ret = get(data,size);
if(ret > 0)
{
return ret;
}
bool usedremove = false;
if(remove.size() > 0)
{
ret = remove[0];
usedremove = true;
}
else
{
infilestream.seekg(0,std::ios::end);
ret = (float)(infilestream.tellg())/(float)blocksize + 1;
}
if(outfilestream.seekp(blocksize*(ret-1)) && outfilestream.write(data,size))
{
outfilestream.write(block,blocksize-size);
numberdata[ret] = size;
hashdata.insert(std::make_pair(MD5String(data,size),numberdata.find(ret)));
if(usedremove)
{
remove.erase(remove.begin());
}
}
outfilestream << std::flush;
return ret;
}
std::vector<unsigned char> VirtualFileSystem::get(const unsigned long long int &pos) const
{
std::map<unsigned long long int, unsigned short int>::iterator it(numberdata.find(pos));
if(it == numberdata.end())
{
return std::vector<unsigned char>();
}
infilestream.seekg(blocksize*(pos-1));
infilestream.read(block,(*it).second);
std::vector<unsigned char> ret(block,block + (*it).second);
return ret;
}
inline std::size_t VirtualFileSystem::GetSize() const
{
return hashdata.size();
}
The MD5String class look like this if anyone really want to now:
Code:
/*
uses http://www.md5hashing.com/c++/
*/
class MD5String
{
private:
unsigned char md5str[16];
static MD5 md5_po;
public:
MD5String(const char*, std::size_t);
MD5String(const MD5String &);
~MD5String();
void Update(const char*, std::size_t);
MD5String & operator=(const MD5String&);
friend std::ostream & operator<<(std::ostream &, const MD5String&);
friend std::istream & operator>>(std::istream &, MD5String&);
friend bool operator==(const MD5String &, const MD5String&);
friend bool operator<(const MD5String &, const MD5String&);
friend bool operator>(const MD5String &, const MD5String&);
};
MD5 MD5String::md5_po = MD5();
MD5String::MD5String(const MD5String & str)
{
std::memcpy(md5str,str.md5str,16);
}
MD5String::MD5String(const char* data = 0, std::size_t size = 0)
{
if(data != 0)
{
Update(data,size);
}
}
MD5String::~MD5String()
{
}
MD5String & MD5String::operator=(const MD5String& str)
{
if(this == &str)
{
return *this;
}
std::memcpy(md5str,str.md5str,16);
return *this;
}
std::ostream & operator<<(std::ostream & stream, const MD5String& str)
{
stream.write((char*)str.md5str,16);
return stream;
}
std::istream & operator>>(std::istream & stream, MD5String& str)
{
stream.read((char*)str.md5str,16);
return stream;
}
bool operator==(const MD5String & str1, const MD5String& str2)
{
return memcmp(str1.md5str,str2.md5str,16) == 0;
}
bool operator<(const MD5String & str1, const MD5String& str2)
{
return memcmp(str1.md5str,str2.md5str,16) == 1;
}
bool operator>(const MD5String & str1, const MD5String& str2)
{
return memcmp(str1.md5str,str2.md5str,16) == -1;
}
void MD5String::Update(const char* data, std::size_t size)
{
MD5_CTX ctx;
md5_po.MD5Init(&ctx);
md5_po.MD5Update(&ctx,(unsigned char*)data,size);
md5_po.MD5Final(md5str,&ctx);
}
And besides, is this the "right" way to build anything like this? Is there anyway I can make this class even faster which is not so hard to implement?
Thanks in advance.