Problem loading file in memory

2

I'm trying to load several files into memory (small files), but the problem is that when I try to load another file soon then all files have the same name as the last file loaded.

I'm using a struct that contains name, size of the name, data and size of the data, to represent the files.

// Cabeçalho
struct AssetHeader
{
    char* version;
    long version_sz;
    int files_num;
};

// Estrutura para representar os arquivos
struct AssetData
{
    char* name;
    char* data;
    long name_sz;
    long data_sz;
};

class AssetManager
{
    protected:
        FILE* m_pFile;
        AssetHeader* m_pHeader;

        std::vector<AssetData*> m_pAssets;
        unsigned int m_FileNum;

    .....
    .....

    public:
        inline std::vector<AssetData*> getFileList() {return m_pAssets;}
        inline int getFileCount() {return (int)m_FileNum;}

        AssetData* getFileByName(std::string name);

        void createAsset(const char* name="DefaultAssetName.asset");
        void loadAsset(const char* filename);

        void addFile(const char* filename);
        void saveFile(AssetData* asset, const char* filename);

        void clear();
        void writeAsset();
        void closeAsset();

    protected:
        void writeAssetHeader();
        void writeAssetBlock(AssetData* asset);

        void readAssetHeader();
        void readAssetBlock();
};


// Carrega um arquivo na memória
void AssetManager::addFile(const char* filename)
{
    AssetData* asset = new AssetData();

    FILE* file = fopen(filename, "rb");

    fseek(file, 0, SEEK_END);
    asset->data_sz = ftell(file);
    fseek(file, 0, SEEK_SET);

    asset->data = new char[asset->data_sz];

    if(fread(&asset->data[0], sizeof(char), asset->data_sz, file) == 0) {
        delete asset;
        asset = NULL;

        fclose(file);
    }

    fclose(file);

    asset->name_sz = strlen(filename);
    asset->name = (char*)filename;

    m_FileNum += 1;
    m_pAssets.push_back(asset);
    m_pHeader->files_num = m_FileNum;
}

// Utilização
int main(int argc, char* argv[])
{
    AssetManager* asset_mgr = new AssetManager();
    asset_mgr->createAsset("asset.txt");

    std::string name;

    name = "1.txt";
    asset_mgr->addFile(name.c_str());

    name = "2.txt";
    asset_mgr->addFile(name.c_str());

    asset_mgr->writeAsset();
    asset_mgr->closeAsset();

    return 0;
}

I do not know what I'm doing wrong. I did a test using a print in each HAssetData stored but the problem is how I was told, the files get the name of the last file loaded.

    
asked by anonymous 17.07.2014 / 00:39

2 answers

3

The problem is that you are saving the pointer received directly into your structure, which means saving the pointer to the string contained in the name variable. Therefore, when the pointed content changes to "2.txt", it is this content pointed to in both instances.

Ideally you should allocate your own area for storing the name and copying the content with strlen :

asset->name = new char[asset->name_sz];
strncpy(asset->name, filename, asset->name_sz);

Note also that in the deletion of your structures you also need to release the memory used by the inner elements. For example, in your current code you have a potential memory leak ( memory leak ) in the handling of fread :

. . .
if(fread(&asset->data[0], sizeof(char), asset->data_sz, file) == 0) {
    delete asset;
    asset = NULL;

    fclose(file);
}
. . .

In the event of a failure, you directly execute the delete on the asset variable but do not delete the allocated memory for asset->data . Since you're using C ++ (at least it's in the question tag), I suggest you use classes instead of structures so you can try to ensure that proper memory releases are made to the destructor.

    
17.07.2014 / 01:08
2

Looking fast at your code, I noticed this:

std::string name;

name = "1.txt";
asset_mgr->addFile(name.c_str());

name = "2.txt";
asset_mgr->addFile(name.c_str());

You only have 1 string called name, which receives "1.txt" and then is overwritten with "2.txt". When passing to addFile, you are using the c_str () method, which takes only the pointer to the beginning of the string.

But if you save only the pointer, this happens, the change in one place affects another (or worse, if the string is relocated, the old pointer becomes invalid and may crash or display invalid data).

If you only use std :: string, each parameter assignment or pass will be copied (which can be avoided with const reference: const std::string & ). If you really want to use pointers, you will have to decide carefully where to make copies, and where to keep pointers (making sure they remain valid for as long as they are needed).

    
17.07.2014 / 01:34