Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Lettura da file: aspettata fine del file non raggiunta
Forum - C/C++ - Lettura da file: aspettata fine del file non raggiunta

Pagine: [ 1 2 3 ] Precedente | Prossimo
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 15:33
Venerdì, 26/12/2014
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
Codice sorgente - presumibilmente C++

  1. #ifndef __LZMAFILE__
  2. #define __LZMAFILE__
  3.  
  4. #include <string>
  5. #include <vector>
  6. #include <assert.h>
  7. #include <math.h>
  8. #include <inttypes.h>
  9.  
  10. #include "Quasar.h"
  11. #include "../RawLZMA/RawLZMA.h"
  12. #include "MD5.h"
  13. #include "CRC.h"
  14.  
  15. using namespace std;
  16.  
  17. #define __LZMA_BAD_MEMORY_ALLOC__ 0
  18.  
  19. //read errors
  20. #define __LZMA_INVALID_HEADER__ 1
  21.  
  22. //write errors
  23. #define __LZMA_CANNOT_WRITE_FILE__ -1
  24. #define __LZMA_CANNOT_OPEN_ORIGIN__ -2
  25. #define __LZMA_NOTHING_TO_COMPRESS__ -3
  26. #define __LZMA_FILE_ALREADY_EXISTS__ -4
  27.  
  28. typedef struct cfile {
  29.         CRC32 CRC;
  30.         size_t FileNameLength;
  31.         size_t RawDataLength;
  32.         size_t CompressedDataLength;
  33.         Digest MD5UncompressedData;
  34.         Digest MD5CompressedData;
  35. } LZMAFileHeader;
  36.  
  37.  
  38. class QUASAR_API VirtualFileSystem {
  39. public:
  40.         //class constructor: initialize the current archive
  41.         VirtualFileSystem(string);
  42.  
  43.         //class destructor: release the used memory
  44.         ~VirtualFileSystem(void);
  45.  
  46.         //Write a file to the current LZMA archive
  47.         void WriteFile(string, string);
  48.  
  49.         char* ReadFile(string);
  50.  
  51. private:
  52.         //Does the current archive exists?
  53.         bool Exists;
  54.  
  55.         //the path to the archive
  56.         string LZMAFilePath;
  57.  
  58.         //list of stored files (by name)
  59.         vector<string> StoredFiles;
  60.         vector<size_t> PositionOfFiles;
  61. };
  62. #endif // __LZMAFILE__



VirtualFileSystem.cpp
Codice sorgente - presumibilmente Delphi

  1. #include "stdafx.h"
  2.  
  3. #include "VirtualFileSystem.h"
  4.  
  5. VirtualFileSystem::VirtualFileSystem(string path)
  6. {
  7.         //save important data
  8.         this->Exists = true;
  9.         this->LZMAFilePath = path;
  10.  
  11.         //try to open the file, create it if it doesn't exists
  12.         FILE* RawData = fopen(this->LZMAFilePath.c_str(), "rb");
  13.         if (RawData == (FILE*)NULL)
  14.         {
  15.                 this->Exists = false;
  16.                 RawData = fopen(this->LZMAFilePath.c_str(), "w");
  17.                 fclose(RawData);
  18.                 RawData = fopen(this->LZMAFilePath.c_str(), "rb");
  19.         }
  20.  
  21.         //if the file does exists
  22.         if (this->Exists)
  23.         {
  24.                 //get its length
  25.                 fseek(RawData, 0, SEEK_END);
  26.                 size_t fileLength = ftell(RawData);
  27.                 rewind(RawData);
  28.  
  29.                 //check the file length
  30.                 if (fileLength > 0)
  31.                 {
  32.                         do {
  33.                                 //check if the header is corrupted
  34.                                 if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
  35.                                 {
  36.                                         //save the position inside the file of the current header
  37.                                         this->PositionOfFiles.emplace_back(ftell(RawData));
  38.  
  39.                                         //get the header of the file
  40.                                         LZMAFileHeader currentHeader;
  41.                                         fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);
  42.  
  43.                                         //create the space used to hold the name of the file
  44.                                         char* currentFileName = new char[currentHeader.FileNameLength + 1];
  45.  
  46.                                         //check for a bad memory allocation
  47.                                         if (currentFileName == (char*)NULL)
  48.                                                 throw __LZMA_BAD_MEMORY_ALLOC__;
  49.  
  50.                                         //get the name of the file
  51.                                         fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
  52.                                         currentFileName[currentHeader.FileNameLength] = '\0';
  53.  
  54.                                         //store the file name
  55.                                         string fileNameToStore = string(currentFileName);
  56.                                         this->StoredFiles.emplace_back(fileNameToStore);
  57.  
  58.                                         //release the memory used to store a copy of the current file name
  59.                                         delete currentFileName;
  60.  
  61.                                         //jump to the next header
  62.                                         fseek(RawData, currentHeader.CompressedDataLength, SEEK_CUR);
  63.                                 }
  64.                                 else
  65.                                 {
  66.                                         throw __LZMA_INVALID_HEADER__;
  67.                                 }
  68.                         } while (!feof(RawData));
  69.                 }
  70.                 else
  71.                 {
  72.                         this->Exists = false;
  73.                 }
  74.         }
  75.  
  76.         //close the file
  77.         fclose(RawData);
  78. }
  79.  
  80. VirtualFileSystem::~VirtualFileSystem(void)
  81. {
  82.         //release the memory used to store the name of files inside the current lzma file
  83.         this->StoredFiles.clear();
  84.         this->StoredFiles.resize(0);
  85. }
  86.  
  87. void VirtualFileSystem::WriteFile(string realPath, string fakeName)
  88. {
  89.         //check if a file with the same name already exists
  90.         bool found = false;
  91.  
  92.         for each (string var in this->StoredFiles)
  93.         {
  94.                 if (var.compare(fakeName) == 0)
  95.                         found = true;
  96.         }
  97.  
  98.         //throw an exception if so
  99.         if (found == true)
  100.                 throw __LZMA_FILE_ALREADY_EXISTS__;
  101.  
  102.         //try to open the file
  103.         FILE* RawData;
  104.        
  105.         //check if the file exists
  106.         if (this->Exists)
  107.                 RawData = fopen(this->LZMAFilePath.c_str(), "a+");
  108.         else
  109.                 RawData = fopen(this->LZMAFilePath.c_str(), "wb");
  110.  
  111.         //check errors
  112.         if (RawData == (FILE*)NULL)
  113.                 throw __LZMA_CANNOT_WRITE_FILE__;
  114.  
  115.         //try to open the file to compress
  116.         FILE* FileToCompress = fopen(realPath.c_str(), "rb");
  117.  
  118.         //check if the operation successed
  119.         if (FileToCompress == (FILE*)NULL)
  120.                 throw __LZMA_CANNOT_OPEN_ORIGIN__;
  121.  
  122.         //get the length of the file to compress
  123.         fseek(FileToCompress, 0, SEEK_END);
  124.         size_t OriginalLength = ftell(FileToCompress);
  125.         rewind(FileToCompress);
  126.  
  127.         //check the length of the file
  128.         if (OriginalLength > 0)
  129.         {
  130.                 //read the data that will be compressed
  131.                 char* buffer = new char[OriginalLength + 1];
  132.                 fread(buffer, sizeof(char), OriginalLength, FileToCompress);
  133.                 buffer[OriginalLength] = '\0';
  134.  
  135.                 //prepare structures that will be used to hold compressed and uncompressed data
  136.                 vector<unsigned char> DataToCompress(buffer, buffer + OriginalLength);
  137.                 vector<unsigned char> CompressedData;
  138.  
  139.                 //clean the buffer used to read the file to compress
  140.                 delete buffer;
  141.  
  142.                 //compress data
  143.                 RawCompress(CompressedData, DataToCompress);
  144.  
  145.                 //get the MD5 of both rappresentation of the same data: compressed and uncompressed:
  146.  
  147.                 //prepare two digest holders
  148.                 Digest MD5OfCompressedData, MD5OfUncompressedData;
  149.                 //compute the digest of the compressed data
  150.                 Digest* temp = MD5Vector(CompressedData);
  151.                 memcpy(&MD5OfCompressedData, temp, sizeof(Digest));
  152.                 //release the memory used to hold a copy of the digest of the compressed data
  153.                 delete temp;
  154.                 //compute the digest of the uncompressed data
  155.                 temp = MD5Vector(DataToCompress);
  156.                 memcpy(&MD5OfUncompressedData, temp, sizeof(Digest));
  157.                 //release the memory used to hold a copy of the digest of the uncompressed data
  158.                 delete temp;
  159.  
  160.                 //calculate the CRC of compressed data
  161.                 CRC32 CRCOfCompressedData = CRCVector(CompressedData);
  162.  
  163.                 //build the header of the current compressed file
  164.                 LZMAFileHeader header;
  165.                 header.CompressedDataLength = CompressedData.size();
  166.                 header.RawDataLength = DataToCompress.size();
  167.                 header.FileNameLength = fakeName.length();
  168.                 memcpy(&header.CRC, &CRCOfCompressedData, sizeof(CRC32));
  169.                 memcpy(&header.MD5CompressedData, &MD5OfCompressedData, sizeof(Digest));
  170.                 memcpy(&header.MD5UncompressedData, &MD5OfUncompressedData, sizeof(Digest));
  171.  
  172.                 //release the memory used to store the uncompressed data
  173.                 DataToCompress.clear();
  174.                 DataToCompress.resize(0);
  175.  
  176.                 //prepare the name of the file
  177.                 char* nameOfCompressedFile = new char[fakeName.length() + 1];
  178.                 memcpy(nameOfCompressedFile, fakeName.c_str(), fakeName.length());
  179.                 nameOfCompressedFile[fakeName.length()] = '\0';
  180.  
  181.                 //write everything to file
  182.                 fwrite(&header, sizeof(LZMAFileHeader), 1, RawData);
  183.                 fwrite(nameOfCompressedFile, sizeof(char), strlen(nameOfCompressedFile), RawData);
  184.                 for (size_t j = 0; j < CompressedData.size(); j++)
  185.                 {
  186.                         char ch = (char)CompressedData[j];
  187.                         fwrite(&ch, sizeof(char), 1, RawData);
  188.                 }
  189.  
  190.                 //track the new added file
  191.                 this->StoredFiles.emplace_back(fakeName);
  192.  
  193.                 //the file exists now
  194.                 this->Exists = true;
  195.         }
  196.         else
  197.         {
  198.                 throw __LZMA_NOTHING_TO_COMPRESS__;
  199.         }
  200.  
  201.         //close files
  202.         fclose(RawData);
  203.         fclose(FileToCompress);
  204. }



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"?

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 16:10
Venerdì, 26/12/2014
Invece di usare un do-while, cosa succede se lo sostituisci con un semplice while?


Il mio blog: https://piero.dev
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 16:30
Venerdì, 26/12/2014
Succede la stessa cosa, non cambia nulla

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 16:46
Venerdì, 26/12/2014
Penso il problema sia causato dal fatto che chiami fseek prima di invocare foef.

Testo quotato


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



Il mio blog: https://piero.dev
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 17:34
Venerdì, 26/12/2014
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?)

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 19:35
Venerdì, 26/12/2014
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: https://piero.dev
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 22:12
Venerdì, 26/12/2014
già pensato, ma dovrei leggere i bytes relativi al file compresso

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 14:49
Sabato, 27/12/2014
Codice sorgente - presumibilmente Delphi

  1. do {
  2.                                 //check if the header is corrupted
  3.                                 if ((fileLength - ftell(RawData)) > sizeof(LZMAFileHeader))
  4.                                 {
  5.                                         //save the position inside the file of the current header
  6.                                         this->PositionOfFiles.emplace_back(ftell(RawData));
  7.  
  8.                                         //get the header of the file
  9.                                         LZMAFileHeader currentHeader;
  10.                                         fread(&currentHeader, sizeof(LZMAFileHeader), 1, RawData);
  11.  
  12.                                         //create the space used to hold the name of the file
  13.                                         char* currentFileName = new char[currentHeader.FileNameLength + 1];
  14.  
  15.                                         //check for a bad memory allocation
  16.                                         if (currentFileName == (char*)NULL)
  17.                                                 throw __LZMA_BAD_MEMORY_ALLOC__;
  18.  
  19.                                         //get the name of the file
  20.                                         fread((void*)currentFileName, sizeof(char), currentHeader.FileNameLength, RawData);
  21.                                         currentFileName[currentHeader.FileNameLength] = '\0';
  22.  
  23.                                         //store the file name
  24.                                         string fileNameToStore = string(currentFileName);
  25.                                         this->StoredFiles.emplace_back(fileNameToStore);
  26.  
  27.                                         //release the memory used to store a copy of the current file name
  28.                                         delete currentFileName;
  29.  
  30.                                         //jump to the next header
  31.                                         char* data = new char[currentHeader.CompressedDataLength];
  32.                                         fread(data, sizeof(char), currentHeader.CompressedDataLength, RawData);
  33.                                 }
  34.                                 else
  35.                                 {
  36.                                         throw __LZMA_INVALID_HEADER__;
  37.                                 }
  38.                         } while (!feof(RawData));



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

PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6230
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 17:19
Sabato, 27/12/2014
Testo quotato

Postato originariamente da TheDarkJuster:

già pensato, ma dovrei leggere i bytes relativi al file compresso



Non riesco a capire... perchè non puoi usare fileLength?


Il mio blog: https://piero.dev
PM Quote
Pagine: [ 1 2 3 ] Precedente | Prossimo