Oppure

Loading
26/12/14 14:33
TheDarkJuster
Sto scrivendo un virtual file manager che immagazzina diversi file (compressi) dentro un unico file, ogni file ha un header (vedrete come è fatto nel file in .h) è seguito da X caratteri che formano il suo nome (senza terminatore di stringa), con X che è scritto nell'header. header+nome è seguito dal contenuto compresso, la cui lunghezza è salvata nell'header.

VirtualFileSystem.h
#ifndef __LZMAFILE__
#define __LZMAFILE__

#include <string>
#include <vector>
#include <assert.h>
#include <math.h>
#include <inttypes.h>

#include "Quasar.h"
#include "../RawLZMA/RawLZMA.h"
#include "MD5.h"
#include "CRC.h"

using namespace std;

#define __LZMA_BAD_MEMORY_ALLOC__ 0

//read errors
#define __LZMA_INVALID_HEADER__ 1

//write errors
#define __LZMA_CANNOT_WRITE_FILE__ -1
#define __LZMA_CANNOT_OPEN_ORIGIN__ -2
#define __LZMA_NOTHING_TO_COMPRESS__ -3
#define __LZMA_FILE_ALREADY_EXISTS__ -4

typedef struct cfile {
	CRC32 CRC;
	size_t FileNameLength;
	size_t RawDataLength;
	size_t CompressedDataLength;
	Digest MD5UncompressedData;
	Digest MD5CompressedData;
} LZMAFileHeader;


class QUASAR_API VirtualFileSystem {
public:
	//class constructor: initialize the current archive
	VirtualFileSystem(string);

	//class destructor: release the used memory
	~VirtualFileSystem(void);

	//Write a file to the current LZMA archive
	void WriteFile(string, string);

	char* ReadFile(string);

private:
	//Does the current archive exists?
	bool Exists;

	//the path to the archive
	string LZMAFilePath;

	//list of stored files (by name)
	vector<string> StoredFiles;
	vector<size_t> PositionOfFiles;
};
#endif // __LZMAFILE__


VirtualFileSystem.cpp
#include "stdafx.h"

#include "VirtualFileSystem.h"

VirtualFileSystem::VirtualFileSystem(string path)
{
	//save important data
	this->Exists = true;
	this->LZMAFilePath = path;

	//try to open the file, create it if it doesn't exists
	FILE* RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	if (RawData == (FILE*)NULL)
	{
		this->Exists = false;
		RawData = fopen(this->LZMAFilePath.c_str(), "w");
		fclose(RawData);
		RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	}

	//if the file does exists
	if (this->Exists)
	{
		//get its length
		fseek(RawData, 0, SEEK_END);
		size_t fileLength = ftell(RawData);
		rewind(RawData);

		//check the file length
		if (fileLength > 0)
		{
			do {
				//check if the header is corrupted
				if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
				{
					//save the position inside the file of the current header
					this->PositionOfFiles.emplace_back(ftell(RawData));

					//get the header of the file
					LZMAFileHeader currentHeader;
					fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);

					//create the space used to hold the name of the file
					char* currentFileName = new char[currentHeader.FileNameLength + 1];

					//check for a bad memory allocation
					if (currentFileName == (char*)NULL)
						throw __LZMA_BAD_MEMORY_ALLOC__;

					//get the name of the file
					fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
					currentFileName[currentHeader.FileNameLength] = 'Sto scrivendo un virtual file manager che immagazzina diversi file (compressi) dentro un unico file, ogni file ha un header (vedrete come è fatto nel file in .h) è seguito da X caratteri che formano il suo nome (senza terminatore di stringa), con X che è scritto nell'header. header+nome è seguito dal contenuto compresso, la cui lunghezza è salvata nell'header.


VirtualFileSystem.h
#ifndef __LZMAFILE__
#define __LZMAFILE__

#include <string>
#include <vector>
#include <assert.h>
#include <math.h>
#include <inttypes.h>

#include "Quasar.h"
#include "../RawLZMA/RawLZMA.h"
#include "MD5.h"
#include "CRC.h"

using namespace std;

#define __LZMA_BAD_MEMORY_ALLOC__ 0

//read errors
#define __LZMA_INVALID_HEADER__ 1

//write errors
#define __LZMA_CANNOT_WRITE_FILE__ -1
#define __LZMA_CANNOT_OPEN_ORIGIN__ -2
#define __LZMA_NOTHING_TO_COMPRESS__ -3
#define __LZMA_FILE_ALREADY_EXISTS__ -4

typedef struct cfile {
	CRC32 CRC;
	size_t FileNameLength;
	size_t RawDataLength;
	size_t CompressedDataLength;
	Digest MD5UncompressedData;
	Digest MD5CompressedData;
} LZMAFileHeader;


class QUASAR_API VirtualFileSystem {
public:
	//class constructor: initialize the current archive
	VirtualFileSystem(string);

	//class destructor: release the used memory
	~VirtualFileSystem(void);

	//Write a file to the current LZMA archive
	void WriteFile(string, string);

	char* ReadFile(string);

private:
	//Does the current archive exists?
	bool Exists;

	//the path to the archive
	string LZMAFilePath;

	//list of stored files (by name)
	vector<string> StoredFiles;
	vector<size_t> PositionOfFiles;
};
#endif // __LZMAFILE__


VirtualFileSystem.cpp
#include "stdafx.h"

#include "VirtualFileSystem.h"

VirtualFileSystem::VirtualFileSystem(string path)
{
	//save important data
	this->Exists = true;
	this->LZMAFilePath = path;

	//try to open the file, create it if it doesn't exists
	FILE* RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	if (RawData == (FILE*)NULL)
	{
		this->Exists = false;
		RawData = fopen(this->LZMAFilePath.c_str(), "w");
		fclose(RawData);
		RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	}

	//if the file does exists
	if (this->Exists)
	{
		//get its length
		fseek(RawData, 0, SEEK_END);
		size_t fileLength = ftell(RawData);
		rewind(RawData);

		//check the file length
		if (fileLength > 0)
		{
			do {
				//check if the header is corrupted
				if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
				{
					//save the position inside the file of the current header
					this->PositionOfFiles.emplace_back(ftell(RawData));

					//get the header of the file
					LZMAFileHeader currentHeader;
					fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);

					//create the space used to hold the name of the file
					char* currentFileName = new char[currentHeader.FileNameLength + 1];

					//check for a bad memory allocation
					if (currentFileName == (char*)NULL)
						throw __LZMA_BAD_MEMORY_ALLOC__;

					//get the name of the file
					fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
					currentFileName[currentHeader.FileNameLength] = '{parsed_message}';

					//store the file name
					string fileNameToStore = string(currentFileName);
					this->StoredFiles.emplace_back(fileNameToStore);

					//release the memory used to store a copy of the current file name
					delete currentFileName;

					//jump to the next header
					fseek(RawData, currentHeader.CompressedDataLength, SEEK_CUR);
				}
				else
				{
					throw __LZMA_INVALID_HEADER__;
				}
			} while (!feof(RawData));
		}
		else
		{
			this->Exists = false;
		}
	}

	//close the file
	fclose(RawData);
}

VirtualFileSystem::~VirtualFileSystem(void)
{
	//release the memory used to store the name of files inside the current lzma file
	this->StoredFiles.clear();
	this->StoredFiles.resize(0);
}

void VirtualFileSystem::WriteFile(string realPath, string fakeName)
{
	//check if a file with the same name already exists
	bool found = false;

	for each (string var in this->StoredFiles)
	{
		if (var.compare(fakeName) == 0)
			found = true;
	}

	//throw an exception if so
	if (found == true)
		throw __LZMA_FILE_ALREADY_EXISTS__;

	//try to open the file
	FILE* RawData;
	
	//check if the file exists
	if (this->Exists)
		RawData = fopen(this->LZMAFilePath.c_str(), "a+");
	else
		RawData = fopen(this->LZMAFilePath.c_str(), "wb");

	//check errors
	if (RawData == (FILE*)NULL)
		throw __LZMA_CANNOT_WRITE_FILE__;

	//try to open the file to compress
	FILE* FileToCompress = fopen(realPath.c_str(), "rb");

	//check if the operation successed
	if (FileToCompress == (FILE*)NULL)
		throw __LZMA_CANNOT_OPEN_ORIGIN__;

	//get the length of the file to compress
	fseek(FileToCompress, 0, SEEK_END);
	size_t OriginalLength = ftell(FileToCompress);
	rewind(FileToCompress);

	//check the length of the file
	if (OriginalLength > 0)
	{
		//read the data that will be compressed
		char* buffer = new char[OriginalLength + 1];
		fread(buffer, sizeof(char), OriginalLength, FileToCompress);
		buffer[OriginalLength] = '{parsed_message}';

		//prepare structures that will be used to hold compressed and uncompressed data
		vector<unsigned char> DataToCompress(buffer, buffer + OriginalLength);
		vector<unsigned char> CompressedData;

		//clean the buffer used to read the file to compress
		delete buffer;

		//compress data
		RawCompress(CompressedData, DataToCompress);

		//get the MD5 of both rappresentation of the same data: compressed and uncompressed:

		//prepare two digest holders
		Digest MD5OfCompressedData, MD5OfUncompressedData;
		//compute the digest of the compressed data
		Digest* temp = MD5Vector(CompressedData);
		memcpy(&MD5OfCompressedData, temp, sizeof(Digest));
		//release the memory used to hold a copy of the digest of the compressed data
		delete temp;
		//compute the digest of the uncompressed data
		temp = MD5Vector(DataToCompress);
		memcpy(&MD5OfUncompressedData, temp, sizeof(Digest));
		//release the memory used to hold a copy of the digest of the uncompressed data
		delete temp;

		//calculate the CRC of compressed data
		CRC32 CRCOfCompressedData = CRCVector(CompressedData);

		//build the header of the current compressed file
		LZMAFileHeader header;
		header.CompressedDataLength = CompressedData.size();
		header.RawDataLength = DataToCompress.size();
		header.FileNameLength = fakeName.length();
		memcpy(&header.CRC, &CRCOfCompressedData, sizeof(CRC32));
		memcpy(&header.MD5CompressedData, &MD5OfCompressedData, sizeof(Digest));
		memcpy(&header.MD5UncompressedData, &MD5OfUncompressedData, sizeof(Digest));

		//release the memory used to store the uncompressed data
		DataToCompress.clear();
		DataToCompress.resize(0);

		//prepare the name of the file
		char* nameOfCompressedFile = new char[fakeName.length() + 1];
		memcpy(nameOfCompressedFile, fakeName.c_str(), fakeName.length());
		nameOfCompressedFile[fakeName.length()] = '{parsed_message}';

		//write everything to file
		fwrite(&header, sizeof(LZMAFileHeader), 1, RawData);
		fwrite(nameOfCompressedFile, sizeof(char), strlen(nameOfCompressedFile), RawData);
		for (size_t j = 0; j < CompressedData.size(); j++)
		{
			char ch = (char)CompressedData[j];
			fwrite(&ch, sizeof(char), 1, RawData);
		}

		//track the new added file 
		this->StoredFiles.emplace_back(fakeName);

		//the file exists now
		this->Exists = true;
	}
	else
	{
		throw __LZMA_NOTHING_TO_COMPRESS__;
	}

	//close files
	fclose(RawData);
	fclose(FileToCompress);
}


Il problema è nel costruttore: ovvero: nel ciclo do-while controllo se sono arrivato alla fine del file e il controllo fallisce: anche se DOVREI e MI ASPETTO di essere alla fine del file non lo sono, infatti il programma fa la lettura del file successivo, che, per inciso non c'è.
Ciò di cui sono certo è che:
-gli header e i nomi dei files vengono letti CORRETTAMENTE e i vettori membri di classe vengono popolati correttamente (quindi presumo che anche il vettore che contiene le posizioni di inizio dei files sia corretto)
-gli hash MD5 e CRC sono corretti
-ho provato a sostituire (!feof(RawData)) in modo da ottenere il risultato sperato, ma c'era sempre quel problema

Ora vi chiedo: a cosa è dovuta l'ultima lettura "fantasma"?'; //store the file name string fileNameToStore = string(currentFileName); this->StoredFiles.emplace_back(fileNameToStore); //release the memory used to store a copy of the current file name delete currentFileName; //jump to the next header fseek(RawData, currentHeader.CompressedDataLength, SEEK_CUR); } else { throw __LZMA_INVALID_HEADER__; } } while (!feof(RawData)); } else { this->Exists = false; } } //close the file fclose(RawData); } VirtualFileSystem::~VirtualFileSystem(void) { //release the memory used to store the name of files inside the current lzma file this->StoredFiles.clear(); this->StoredFiles.resize(0); } void VirtualFileSystem::WriteFile(string realPath, string fakeName) { //check if a file with the same name already exists bool found = false; for each (string var in this->StoredFiles) { if (var.compare(fakeName) == 0) found = true; } //throw an exception if so if (found == true) throw __LZMA_FILE_ALREADY_EXISTS__; //try to open the file FILE* RawData; //check if the file exists if (this->Exists) RawData = fopen(this->LZMAFilePath.c_str(), "a+"); else RawData = fopen(this->LZMAFilePath.c_str(), "wb"); //check errors if (RawData == (FILE*)NULL) throw __LZMA_CANNOT_WRITE_FILE__; //try to open the file to compress FILE* FileToCompress = fopen(realPath.c_str(), "rb"); //check if the operation successed if (FileToCompress == (FILE*)NULL) throw __LZMA_CANNOT_OPEN_ORIGIN__; //get the length of the file to compress fseek(FileToCompress, 0, SEEK_END); size_t OriginalLength = ftell(FileToCompress); rewind(FileToCompress); //check the length of the file if (OriginalLength > 0) { //read the data that will be compressed char* buffer = new char[OriginalLength + 1]; fread(buffer, sizeof(char), OriginalLength, FileToCompress); buffer[OriginalLength] = 'Sto scrivendo un virtual file manager che immagazzina diversi file (compressi) dentro un unico file, ogni file ha un header (vedrete come è fatto nel file in .h) è seguito da X caratteri che formano il suo nome (senza terminatore di stringa), con X che è scritto nell'header. header+nome è seguito dal contenuto compresso, la cui lunghezza è salvata nell'header.

VirtualFileSystem.h
#ifndef __LZMAFILE__
#define __LZMAFILE__

#include <string>
#include <vector>
#include <assert.h>
#include <math.h>
#include <inttypes.h>

#include "Quasar.h"
#include "../RawLZMA/RawLZMA.h"
#include "MD5.h"
#include "CRC.h"

using namespace std;

#define __LZMA_BAD_MEMORY_ALLOC__ 0

//read errors
#define __LZMA_INVALID_HEADER__ 1

//write errors
#define __LZMA_CANNOT_WRITE_FILE__ -1
#define __LZMA_CANNOT_OPEN_ORIGIN__ -2
#define __LZMA_NOTHING_TO_COMPRESS__ -3
#define __LZMA_FILE_ALREADY_EXISTS__ -4

typedef struct cfile {
	CRC32 CRC;
	size_t FileNameLength;
	size_t RawDataLength;
	size_t CompressedDataLength;
	Digest MD5UncompressedData;
	Digest MD5CompressedData;
} LZMAFileHeader;


class QUASAR_API VirtualFileSystem {
public:
	//class constructor: initialize the current archive
	VirtualFileSystem(string);

	//class destructor: release the used memory
	~VirtualFileSystem(void);

	//Write a file to the current LZMA archive
	void WriteFile(string, string);

	char* ReadFile(string);

private:
	//Does the current archive exists?
	bool Exists;

	//the path to the archive
	string LZMAFilePath;

	//list of stored files (by name)
	vector<string> StoredFiles;
	vector<size_t> PositionOfFiles;
};
#endif // __LZMAFILE__


VirtualFileSystem.cpp
#include "stdafx.h"

#include "VirtualFileSystem.h"

VirtualFileSystem::VirtualFileSystem(string path)
{
	//save important data
	this->Exists = true;
	this->LZMAFilePath = path;

	//try to open the file, create it if it doesn't exists
	FILE* RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	if (RawData == (FILE*)NULL)
	{
		this->Exists = false;
		RawData = fopen(this->LZMAFilePath.c_str(), "w");
		fclose(RawData);
		RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	}

	//if the file does exists
	if (this->Exists)
	{
		//get its length
		fseek(RawData, 0, SEEK_END);
		size_t fileLength = ftell(RawData);
		rewind(RawData);

		//check the file length
		if (fileLength > 0)
		{
			do {
				//check if the header is corrupted
				if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
				{
					//save the position inside the file of the current header
					this->PositionOfFiles.emplace_back(ftell(RawData));

					//get the header of the file
					LZMAFileHeader currentHeader;
					fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);

					//create the space used to hold the name of the file
					char* currentFileName = new char[currentHeader.FileNameLength + 1];

					//check for a bad memory allocation
					if (currentFileName == (char*)NULL)
						throw __LZMA_BAD_MEMORY_ALLOC__;

					//get the name of the file
					fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
					currentFileName[currentHeader.FileNameLength] = '{parsed_message}';

					//store the file name
					string fileNameToStore = string(currentFileName);
					this->StoredFiles.emplace_back(fileNameToStore);

					//release the memory used to store a copy of the current file name
					delete currentFileName;

					//jump to the next header
					fseek(RawData, currentHeader.CompressedDataLength, SEEK_CUR);
				}
				else
				{
					throw __LZMA_INVALID_HEADER__;
				}
			} while (!feof(RawData));
		}
		else
		{
			this->Exists = false;
		}
	}

	//close the file
	fclose(RawData);
}

VirtualFileSystem::~VirtualFileSystem(void)
{
	//release the memory used to store the name of files inside the current lzma file
	this->StoredFiles.clear();
	this->StoredFiles.resize(0);
}

void VirtualFileSystem::WriteFile(string realPath, string fakeName)
{
	//check if a file with the same name already exists
	bool found = false;

	for each (string var in this->StoredFiles)
	{
		if (var.compare(fakeName) == 0)
			found = true;
	}

	//throw an exception if so
	if (found == true)
		throw __LZMA_FILE_ALREADY_EXISTS__;

	//try to open the file
	FILE* RawData;
	
	//check if the file exists
	if (this->Exists)
		RawData = fopen(this->LZMAFilePath.c_str(), "a+");
	else
		RawData = fopen(this->LZMAFilePath.c_str(), "wb");

	//check errors
	if (RawData == (FILE*)NULL)
		throw __LZMA_CANNOT_WRITE_FILE__;

	//try to open the file to compress
	FILE* FileToCompress = fopen(realPath.c_str(), "rb");

	//check if the operation successed
	if (FileToCompress == (FILE*)NULL)
		throw __LZMA_CANNOT_OPEN_ORIGIN__;

	//get the length of the file to compress
	fseek(FileToCompress, 0, SEEK_END);
	size_t OriginalLength = ftell(FileToCompress);
	rewind(FileToCompress);

	//check the length of the file
	if (OriginalLength > 0)
	{
		//read the data that will be compressed
		char* buffer = new char[OriginalLength + 1];
		fread(buffer, sizeof(char), OriginalLength, FileToCompress);
		buffer[OriginalLength] = '{parsed_message}';

		//prepare structures that will be used to hold compressed and uncompressed data
		vector<unsigned char> DataToCompress(buffer, buffer + OriginalLength);
		vector<unsigned char> CompressedData;

		//clean the buffer used to read the file to compress
		delete buffer;

		//compress data
		RawCompress(CompressedData, DataToCompress);

		//get the MD5 of both rappresentation of the same data: compressed and uncompressed:

		//prepare two digest holders
		Digest MD5OfCompressedData, MD5OfUncompressedData;
		//compute the digest of the compressed data
		Digest* temp = MD5Vector(CompressedData);
		memcpy(&MD5OfCompressedData, temp, sizeof(Digest));
		//release the memory used to hold a copy of the digest of the compressed data
		delete temp;
		//compute the digest of the uncompressed data
		temp = MD5Vector(DataToCompress);
		memcpy(&MD5OfUncompressedData, temp, sizeof(Digest));
		//release the memory used to hold a copy of the digest of the uncompressed data
		delete temp;

		//calculate the CRC of compressed data
		CRC32 CRCOfCompressedData = CRCVector(CompressedData);

		//build the header of the current compressed file
		LZMAFileHeader header;
		header.CompressedDataLength = CompressedData.size();
		header.RawDataLength = DataToCompress.size();
		header.FileNameLength = fakeName.length();
		memcpy(&header.CRC, &CRCOfCompressedData, sizeof(CRC32));
		memcpy(&header.MD5CompressedData, &MD5OfCompressedData, sizeof(Digest));
		memcpy(&header.MD5UncompressedData, &MD5OfUncompressedData, sizeof(Digest));

		//release the memory used to store the uncompressed data
		DataToCompress.clear();
		DataToCompress.resize(0);

		//prepare the name of the file
		char* nameOfCompressedFile = new char[fakeName.length() + 1];
		memcpy(nameOfCompressedFile, fakeName.c_str(), fakeName.length());
		nameOfCompressedFile[fakeName.length()] = '{parsed_message}';

		//write everything to file
		fwrite(&header, sizeof(LZMAFileHeader), 1, RawData);
		fwrite(nameOfCompressedFile, sizeof(char), strlen(nameOfCompressedFile), RawData);
		for (size_t j = 0; j < CompressedData.size(); j++)
		{
			char ch = (char)CompressedData[j];
			fwrite(&ch, sizeof(char), 1, RawData);
		}

		//track the new added file 
		this->StoredFiles.emplace_back(fakeName);

		//the file exists now
		this->Exists = true;
	}
	else
	{
		throw __LZMA_NOTHING_TO_COMPRESS__;
	}

	//close files
	fclose(RawData);
	fclose(FileToCompress);
}


Il problema è nel costruttore: ovvero: nel ciclo do-while controllo se sono arrivato alla fine del file e il controllo fallisce: anche se DOVREI e MI ASPETTO di essere alla fine del file non lo sono, infatti il programma fa la lettura del file successivo, che, per inciso non c'è.
Ciò di cui sono certo è che:
-gli header e i nomi dei files vengono letti CORRETTAMENTE e i vettori membri di classe vengono popolati correttamente (quindi presumo che anche il vettore che contiene le posizioni di inizio dei files sia corretto)
-gli hash MD5 e CRC sono corretti
-ho provato a sostituire (!feof(RawData)) in modo da ottenere il risultato sperato, ma c'era sempre quel problema

Ora vi chiedo: a cosa è dovuta l'ultima lettura "fantasma"?'; //prepare structures that will be used to hold compressed and uncompressed data vector<unsigned char> DataToCompress(buffer, buffer + OriginalLength); vector<unsigned char> CompressedData; //clean the buffer used to read the file to compress delete buffer; //compress data RawCompress(CompressedData, DataToCompress); //get the MD5 of both rappresentation of the same data: compressed and uncompressed: //prepare two digest holders Digest MD5OfCompressedData, MD5OfUncompressedData; //compute the digest of the compressed data Digest* temp = MD5Vector(CompressedData); memcpy(&MD5OfCompressedData, temp, sizeof(Digest)); //release the memory used to hold a copy of the digest of the compressed data delete temp; //compute the digest of the uncompressed data temp = MD5Vector(DataToCompress); memcpy(&MD5OfUncompressedData, temp, sizeof(Digest)); //release the memory used to hold a copy of the digest of the uncompressed data delete temp; //calculate the CRC of compressed data CRC32 CRCOfCompressedData = CRCVector(CompressedData); //build the header of the current compressed file LZMAFileHeader header; header.CompressedDataLength = CompressedData.size(); header.RawDataLength = DataToCompress.size(); header.FileNameLength = fakeName.length(); memcpy(&header.CRC, &CRCOfCompressedData, sizeof(CRC32)); memcpy(&header.MD5CompressedData, &MD5OfCompressedData, sizeof(Digest)); memcpy(&header.MD5UncompressedData, &MD5OfUncompressedData, sizeof(Digest)); //release the memory used to store the uncompressed data DataToCompress.clear(); DataToCompress.resize(0); //prepare the name of the file char* nameOfCompressedFile = new char[fakeName.length() + 1]; memcpy(nameOfCompressedFile, fakeName.c_str(), fakeName.length()); nameOfCompressedFile[fakeName.length()] = 'Sto scrivendo un virtual file manager che immagazzina diversi file (compressi) dentro un unico file, ogni file ha un header (vedrete come è fatto nel file in .h) è seguito da X caratteri che formano il suo nome (senza terminatore di stringa), con X che è scritto nell'header. header+nome è seguito dal contenuto compresso, la cui lunghezza è salvata nell'header.

VirtualFileSystem.h
#ifndef __LZMAFILE__
#define __LZMAFILE__

#include <string>
#include <vector>
#include <assert.h>
#include <math.h>
#include <inttypes.h>

#include "Quasar.h"
#include "../RawLZMA/RawLZMA.h"
#include "MD5.h"
#include "CRC.h"

using namespace std;

#define __LZMA_BAD_MEMORY_ALLOC__ 0

//read errors
#define __LZMA_INVALID_HEADER__ 1

//write errors
#define __LZMA_CANNOT_WRITE_FILE__ -1
#define __LZMA_CANNOT_OPEN_ORIGIN__ -2
#define __LZMA_NOTHING_TO_COMPRESS__ -3
#define __LZMA_FILE_ALREADY_EXISTS__ -4

typedef struct cfile {
	CRC32 CRC;
	size_t FileNameLength;
	size_t RawDataLength;
	size_t CompressedDataLength;
	Digest MD5UncompressedData;
	Digest MD5CompressedData;
} LZMAFileHeader;


class QUASAR_API VirtualFileSystem {
public:
	//class constructor: initialize the current archive
	VirtualFileSystem(string);

	//class destructor: release the used memory
	~VirtualFileSystem(void);

	//Write a file to the current LZMA archive
	void WriteFile(string, string);

	char* ReadFile(string);

private:
	//Does the current archive exists?
	bool Exists;

	//the path to the archive
	string LZMAFilePath;

	//list of stored files (by name)
	vector<string> StoredFiles;
	vector<size_t> PositionOfFiles;
};
#endif // __LZMAFILE__


VirtualFileSystem.cpp
#include "stdafx.h"

#include "VirtualFileSystem.h"

VirtualFileSystem::VirtualFileSystem(string path)
{
	//save important data
	this->Exists = true;
	this->LZMAFilePath = path;

	//try to open the file, create it if it doesn't exists
	FILE* RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	if (RawData == (FILE*)NULL)
	{
		this->Exists = false;
		RawData = fopen(this->LZMAFilePath.c_str(), "w");
		fclose(RawData);
		RawData = fopen(this->LZMAFilePath.c_str(), "rb");
	}

	//if the file does exists
	if (this->Exists)
	{
		//get its length
		fseek(RawData, 0, SEEK_END);
		size_t fileLength = ftell(RawData);
		rewind(RawData);

		//check the file length
		if (fileLength > 0)
		{
			do {
				//check if the header is corrupted
				if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
				{
					//save the position inside the file of the current header
					this->PositionOfFiles.emplace_back(ftell(RawData));

					//get the header of the file
					LZMAFileHeader currentHeader;
					fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);

					//create the space used to hold the name of the file
					char* currentFileName = new char[currentHeader.FileNameLength + 1];

					//check for a bad memory allocation
					if (currentFileName == (char*)NULL)
						throw __LZMA_BAD_MEMORY_ALLOC__;

					//get the name of the file
					fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
					currentFileName[currentHeader.FileNameLength] = '{parsed_message}';

					//store the file name
					string fileNameToStore = string(currentFileName);
					this->StoredFiles.emplace_back(fileNameToStore);

					//release the memory used to store a copy of the current file name
					delete currentFileName;

					//jump to the next header
					fseek(RawData, currentHeader.CompressedDataLength, SEEK_CUR);
				}
				else
				{
					throw __LZMA_INVALID_HEADER__;
				}
			} while (!feof(RawData));
		}
		else
		{
			this->Exists = false;
		}
	}

	//close the file
	fclose(RawData);
}

VirtualFileSystem::~VirtualFileSystem(void)
{
	//release the memory used to store the name of files inside the current lzma file
	this->StoredFiles.clear();
	this->StoredFiles.resize(0);
}

void VirtualFileSystem::WriteFile(string realPath, string fakeName)
{
	//check if a file with the same name already exists
	bool found = false;

	for each (string var in this->StoredFiles)
	{
		if (var.compare(fakeName) == 0)
			found = true;
	}

	//throw an exception if so
	if (found == true)
		throw __LZMA_FILE_ALREADY_EXISTS__;

	//try to open the file
	FILE* RawData;
	
	//check if the file exists
	if (this->Exists)
		RawData = fopen(this->LZMAFilePath.c_str(), "a+");
	else
		RawData = fopen(this->LZMAFilePath.c_str(), "wb");

	//check errors
	if (RawData == (FILE*)NULL)
		throw __LZMA_CANNOT_WRITE_FILE__;

	//try to open the file to compress
	FILE* FileToCompress = fopen(realPath.c_str(), "rb");

	//check if the operation successed
	if (FileToCompress == (FILE*)NULL)
		throw __LZMA_CANNOT_OPEN_ORIGIN__;

	//get the length of the file to compress
	fseek(FileToCompress, 0, SEEK_END);
	size_t OriginalLength = ftell(FileToCompress);
	rewind(FileToCompress);

	//check the length of the file
	if (OriginalLength > 0)
	{
		//read the data that will be compressed
		char* buffer = new char[OriginalLength + 1];
		fread(buffer, sizeof(char), OriginalLength, FileToCompress);
		buffer[OriginalLength] = '{parsed_message}';

		//prepare structures that will be used to hold compressed and uncompressed data
		vector<unsigned char> DataToCompress(buffer, buffer + OriginalLength);
		vector<unsigned char> CompressedData;

		//clean the buffer used to read the file to compress
		delete buffer;

		//compress data
		RawCompress(CompressedData, DataToCompress);

		//get the MD5 of both rappresentation of the same data: compressed and uncompressed:

		//prepare two digest holders
		Digest MD5OfCompressedData, MD5OfUncompressedData;
		//compute the digest of the compressed data
		Digest* temp = MD5Vector(CompressedData);
		memcpy(&MD5OfCompressedData, temp, sizeof(Digest));
		//release the memory used to hold a copy of the digest of the compressed data
		delete temp;
		//compute the digest of the uncompressed data
		temp = MD5Vector(DataToCompress);
		memcpy(&MD5OfUncompressedData, temp, sizeof(Digest));
		//release the memory used to hold a copy of the digest of the uncompressed data
		delete temp;

		//calculate the CRC of compressed data
		CRC32 CRCOfCompressedData = CRCVector(CompressedData);

		//build the header of the current compressed file
		LZMAFileHeader header;
		header.CompressedDataLength = CompressedData.size();
		header.RawDataLength = DataToCompress.size();
		header.FileNameLength = fakeName.length();
		memcpy(&header.CRC, &CRCOfCompressedData, sizeof(CRC32));
		memcpy(&header.MD5CompressedData, &MD5OfCompressedData, sizeof(Digest));
		memcpy(&header.MD5UncompressedData, &MD5OfUncompressedData, sizeof(Digest));

		//release the memory used to store the uncompressed data
		DataToCompress.clear();
		DataToCompress.resize(0);

		//prepare the name of the file
		char* nameOfCompressedFile = new char[fakeName.length() + 1];
		memcpy(nameOfCompressedFile, fakeName.c_str(), fakeName.length());
		nameOfCompressedFile[fakeName.length()] = '{parsed_message}';

		//write everything to file
		fwrite(&header, sizeof(LZMAFileHeader), 1, RawData);
		fwrite(nameOfCompressedFile, sizeof(char), strlen(nameOfCompressedFile), RawData);
		for (size_t j = 0; j < CompressedData.size(); j++)
		{
			char ch = (char)CompressedData[j];
			fwrite(&ch, sizeof(char), 1, RawData);
		}

		//track the new added file 
		this->StoredFiles.emplace_back(fakeName);

		//the file exists now
		this->Exists = true;
	}
	else
	{
		throw __LZMA_NOTHING_TO_COMPRESS__;
	}

	//close files
	fclose(RawData);
	fclose(FileToCompress);
}


Il problema è nel costruttore: ovvero: nel ciclo do-while controllo se sono arrivato alla fine del file e il controllo fallisce: anche se DOVREI e MI ASPETTO di essere alla fine del file non lo sono, infatti il programma fa la lettura del file successivo, che, per inciso non c'è.
Ciò di cui sono certo è che:
-gli header e i nomi dei files vengono letti CORRETTAMENTE e i vettori membri di classe vengono popolati correttamente (quindi presumo che anche il vettore che contiene le posizioni di inizio dei files sia corretto)
-gli hash MD5 e CRC sono corretti
-ho provato a sostituire (!feof(RawData)) in modo da ottenere il risultato sperato, ma c'era sempre quel problema

Ora vi chiedo: a cosa è dovuta l'ultima lettura "fantasma"?'; //write everything to file fwrite(&header, sizeof(LZMAFileHeader), 1, RawData); fwrite(nameOfCompressedFile, sizeof(char), strlen(nameOfCompressedFile), RawData); for (size_t j = 0; j < CompressedData.size(); j++) { char ch = (char)CompressedData[j]; fwrite(&ch, sizeof(char), 1, RawData); } //track the new added file this->StoredFiles.emplace_back(fakeName); //the file exists now this->Exists = true; } else { throw __LZMA_NOTHING_TO_COMPRESS__; } //close files fclose(RawData); fclose(FileToCompress); }


Il problema è nel costruttore: ovvero: nel ciclo do-while controllo se sono arrivato alla fine del file e il controllo fallisce: anche se DOVREI e MI ASPETTO di essere alla fine del file non lo sono, infatti il programma fa la lettura del file successivo, che, per inciso non c'è.
Ciò di cui sono certo è che:
-gli header e i nomi dei files vengono letti CORRETTAMENTE e i vettori membri di classe vengono popolati correttamente (quindi presumo che anche il vettore che contiene le posizioni di inizio dei files sia corretto)
-gli hash MD5 e CRC sono corretti
-ho provato a sostituire (!feof(RawData)) in modo da ottenere il risultato sperato, ma c'era sempre quel problema

Ora vi chiedo: a cosa è dovuta l'ultima lettura "fantasma"?
aaa
26/12/14 15:10
pierotofy
Invece di usare un do-while, cosa succede se lo sostituisci con un semplice while?
Il mio blog: piero.dev
26/12/14 15:30
TheDarkJuster
Succede la stessa cosa, non cambia nulla
aaa
26/12/14 15:46
pierotofy
Penso il problema sia causato dal fatto che chiami fseek prima di invocare foef.

The end-of-file internal indicator of the stream is cleared after a successful call to this function


cplusplus.com/reference/cstdio/fseek/

Il mio blog: piero.dev
26/12/14 16:34
TheDarkJuster
Questo non lo sapevo, grazie per avermelo detto, ma ora come risolvo? (possibilmente senza leggere il contenuto compresso visto che potrebbe essere una operazione lunga e in quel momento non necessaria?)
aaa
26/12/14 18:35
pierotofy
Potresti calcolare all'inizio (prima del do-while) la grandezza del file, dopodichè ad ogni read potresti tenere traccia di quanti bytes hai letto e sostituire feof con un (bytesRead < totalBytes).
Il mio blog: piero.dev
26/12/14 21:12
TheDarkJuster
già pensato, ma dovrei leggere i bytes relativi al file compresso
aaa
27/12/14 13:49
TheDarkJuster
do {
				//check if the header is corrupted
				if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
				{
					//save the position inside the file of the current header
					this->PositionOfFiles.emplace_back(ftell(RawData));

					//get the header of the file
					LZMAFileHeader currentHeader;
					fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);

					//create the space used to hold the name of the file
					char* currentFileName = new char[currentHeader.FileNameLength + 1];

					//check for a bad memory allocation
					if (currentFileName == (char*)NULL)
						throw __LZMA_BAD_MEMORY_ALLOC__;

					//get the name of the file
					fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
					currentFileName[currentHeader.FileNameLength] = '
do {
				//check if the header is corrupted
				if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
				{
					//save the position inside the file of the current header
					this->PositionOfFiles.emplace_back(ftell(RawData));

					//get the header of the file
					LZMAFileHeader currentHeader;
					fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);

					//create the space used to hold the name of the file
					char* currentFileName = new char[currentHeader.FileNameLength + 1];

					//check for a bad memory allocation
					if (currentFileName == (char*)NULL)
						throw __LZMA_BAD_MEMORY_ALLOC__;

					//get the name of the file
					fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
					currentFileName[currentHeader.FileNameLength] = '{parsed_message}';

					//store the file name
					string fileNameToStore = string(currentFileName);
					this->StoredFiles.emplace_back(fileNameToStore);

					//release the memory used to store a copy of the current file name
					delete currentFileName;

					//jump to the next header
					char* data = new char[currentHeader.CompressedDataLength];
					fread(data, sizeof(char), currentHeader.CompressedDataLength, RawData);
				}
				else
				{
					throw __LZMA_INVALID_HEADER__;
				}
			} while (!feof(RawData));


il codice è così ora, ma non è cambiato nulla'; //store the file name string fileNameToStore = string(currentFileName); this->StoredFiles.emplace_back(fileNameToStore); //release the memory used to store a copy of the current file name delete currentFileName; //jump to the next header char* data = new char[currentHeader.CompressedDataLength]; fread(data, sizeof(char), currentHeader.CompressedDataLength, RawData); } else { throw __LZMA_INVALID_HEADER__; } } while (!feof(RawData));


il codice è così ora, ma non è cambiato nulla
aaa