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
VirtualFileSystem.cpp
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"?
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(¤tHeader, 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(¤tHeader, 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(¤tHeader, 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(¤tHeader, 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