Thread: ofstream and FILE behaviour

  1. #1
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39

    ofstream and FILE behaviour

    I'm modiefing the source of an application which was originally written in C, to a more C++ (object oriented) code.

    The application uses a FILE struct, and I want to use an ofstream object. But I have a question about the behaviour of FILE and ofstream.


    The original C code:
    Code:
    	// appFile is a FILE struct
    
    	// Set the pointer to the right position
    	fseek (appFile, patchOffset, SEEK_SET);
    	// Write the patch
    	fwrite (pAH, 1, ddmemSize, appFile);
    	fclose (appFile);
    My first question:
    What exactly does fwrite do? Just put the contents at the pointer, overwriting any data, what on that place exists, or does it append the data there, and move back any data that exists on that place?

    My C++ code:
    Code:
    	ofstream file(this -> filename.c_str(), ios::out | ios::binary | ios::app);
    
    	if(!file.is_open())
    	{
    		throw std::runtime_error("Could not open file for writing");
    	}
    
    	file.seekp(this -> patch_offset);
    	file.write(reinterpret_cast<char *>(this -> dldi_section), dldi_mem_size);
    	file.close();
    My second question:
    How exactly does ofstream write to the file?

    I've experimented a bit with it, and when I don't use the ios::app flag, it looks like everything beyond the put pointer is truncated. (the patched file gets a very small filesize, which doesn't happen with the original code).

    But when I do use the ios::app flag, the patched file filesize is always a few KB's bigger then when I patch it with the original app. And everytime I patch it again, it gets a few KB's bigger. So it's clear that when using the ios:app flag, all data after the put pointer is moved, and not overwritten.

    So can anybody answer my questions?

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    What are the arguments passed to fopen() when appFile is opened? I'd guess "Xb+", but what's the X?

    My only suggestion is to try googling for "fstream ios flags" or something. Perhaps you can find a list, or an equivalent fopen()-to-fstream modes list.

    [edit] 4,500th post! [/edit]
    Last edited by dwks; 06-16-2007 at 02:40 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39
    fopen mode is "rb+"

    I've found this table on the inet:

    Code:
    // Table 92 File Open modes
    //+------------------------------------------------------------+
    //| ios_base Flag combination            stdio equivalent      |
    //|binary  in  out  trunc  app                                 |
    //+------------------------------------------------------------+
    //|             +                        "w"                   |
    //|             +           +            "a"                   |
    //|             +     +                  "w"                   |
    //|         +                            "r"                   |
    //|         +   +                        "r+"                  |
    //|         +   +     +                  "w+"                  |
    //+------------------------------------------------------------+
    //|   +         +                        "wb"                  |
    //|   +         +           +            "ab"                  |
    //|   +         +     +                  "wb"                  |
    //|   +     +                            "rb"                  |
    //|   +     +   +                        "r+b"                 |
    //|   +     +   +     +                  "w+b"                 |
    //+------------------------------------------------------------+
    So if I look at it rb+ should be the same as ios:ut | ios::in | ios::binary, I only need the oustream so then it would be ios:ut | ios::binary.

    Well, I'm gonna try somethings, thanks and congratulations

  4. #4
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    app stands for append. It opens the file so that you start writing at the end of the file. it's what the a is for in fopen.

  5. #5
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39
    Well, I have viewed the application with a hex viewer, before the patch and after the patch.

    Short description on how the patching works:
    To patch an application, you need a patch file. The data of the patch file is read into memory. Also the data of the application file is read into memory, then the patch data is copied into the application data, and then de application data is saved back to the application file.

    I discovered that, the application file after the patch, only exists of zero's, except for the data from the patch, copied into the application data. But the application data before the patch exists of a lot of non meaning characters (it's binary, doh).

    So where does it go wrong? On reading the application data, or writing it back?

    This is the way I open the application file:
    data_t is an unsigned char
    Code:
    /**
     * Opens the .nds file
     *
     * This method opens the .nds file, so the data can be read in memory and modified.
     * If anything goes wrong, an runtime_error is thrown
     */
    void NdsFile::open()
    {
    	// Try to open the file, and put the pointer at the end
    	ifstream nds_file(this -> filename.c_str(), ios::in | ios::binary | ios::ate);
    
    	if(nds_file.is_open() == false)
    	{
    		throw std::runtime_error("Could not open NDS File file");
    	}
    
    	// Get filesize
    	this -> filesize = nds_file.tellg();
    
    	// Initialize member
    	this -> app_file_data = new data_t[this -> filesize];
    	char * buffer = new char[this -> filesize];
    
    	// Put the pointer back at the beginning
    	nds_file.seekg(0, ios::beg);
    
    	// Read it into memory
    	nds_file.read(buffer, this -> filesize);
    
    	this -> app_file_data = reinterpret_cast<data_t *>(buffer);
    
    	if(buffer)
    	{
    		//delete[] buffer;
    		buffer = 0;
    	}
    
    	// And close the file
    	nds_file.close();
    
    	this -> parse_info();
    }
    
    void NdsFile::parse_info()
    {
    	// First, find the reserved DLDI space in the app file
    	this -> patch_offset = this -> quick_find (dldiMagicString, sizeof(dldiMagicString) / sizeof(char));
    
    	if(this -> patch_offset < 0)
    	{
    		throw std::runtime_error("File does not have a DLDI section");
    	}
    
    	this -> dldi_section = &(this -> app_file_data[patch_offset]);
    	this -> driver_name = string(reinterpret_cast<const char*>(&this -> dldi_section[DO_friendlyName]));
    }
    I read the patch file data on almost the same way.

    I have a subversion repo @ sourceforge, so if you want to view the whole code:
    http://dldigui.svn.sourceforge.net/v...dldigui/trunk/

    The original C code can be found in this file:
    http://dldigui.svn.sourceforge.net/v...=4&view=markup

    Reading/patching the application file happens in src/ndsfile.cpp
    Reading the patch file happens in src/dldifile.cpp
    Last edited by MrLucky; 06-17-2007 at 09:03 AM. Reason: typos

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I would think that with the ios::ate flag you'd also need the ios:ut flag, or that it only applied to writing, but I could be wrong.

    Why not just open the file in an ordinary reading mode, seek to the end, call tellg(), then seek to the beginning again?

    Google found this, I'm not sure if it will be useful to you: http://www.linuxquestions.org/questi...d.php?t=431582

    I'm sorry, but I don't have time right now to investigate this further. I may have a look at your code later.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    So, if I'm understanding you correctly, you're trying to do something like this:
    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib>
    
    void write(const char *filename, const char *message) {
        std::ofstream out(filename);
        
        out << message;
        
        out.close();
    }
    
    void modify(const char *filename, int pos, const char *change) {
        std::ofstream file(filename, std::ios::in | std::ios::out);
        
        file.seekp(pos);
        file << change;
        
        file.close();
    }
    
    void dump(const char *filename) {
        std::ifstream file(filename);
        std::string line;
        
        while(std::getline(file, line)) {
            std::cout << line << std::endl;
        }
        
        file.close();
    }
    
    int main() {
        const char *filename = "rewritetest.txt";
        const char *message = "Hello, World! Nice to meet you.\n";
        
        write(filename, message);
        modify(filename, 7, "Steve");
        dump(filename);
        std::remove(filename);
        
        std::cin.get();
        return 0;
    }
    That program outputs
    Code:
    Hello, Steve! Nice to meet you.
    Of course, I don't seek to the end of the file to determine its size, nor do I use binary mode, but it seems to indicate that what you are attempting is possible.

    I suggest trying different combinations of flags (I'm sure you're already doing that!) and simple programs like the one above to figure out what is happening.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Code:
    >	// Read it into memory
    >	nds_file.read(buffer, this -> filesize);
    I would check here to see how much data was read into buffer:
    Code:
    	std::cout << "bytes read: " << nds_file.gcount() << endl;
    If that prints zero by chance, then maybe you need to clear the input file stream before seeking to the beginning:
    Code:
    	// Put the pointer back at the beginning
    	nds_file.clear();
    	nds_file.seekg(0, ios::beg);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. I'm not THAT good am I?
    By indigo0086 in forum A Brief History of Cprogramming.com
    Replies: 2
    Last Post: 10-19-2006, 10:08 AM
  2. Automatically dating an output file created by ofstream
    By Jeff21 in forum C++ Programming
    Replies: 8
    Last Post: 08-01-2005, 09:31 AM
  3. Outputting to a File Modified Text
    By alpha in forum C++ Programming
    Replies: 8
    Last Post: 11-24-2003, 08:39 PM
  4. Replies: 9
    Last Post: 06-06-2002, 07:03 PM
  5. Removing *Unchanged* Output File (ofstream) :: C++
    By kuphryn in forum C++ Programming
    Replies: 2
    Last Post: 01-05-2002, 07:47 PM