Stream - wie lese ich aus ? (istream)



  • Hallo, ich versuche n eigenen Stream zu basteln.
    Ich kann auch schon wunderbar damit schreiben,
    also das ist die Klasse womit ich dies tue:

    template<typename c>
    class cryptbuf : private c, public streambuf
    {
    protected:
    	streambuf *buf;
    public:
    	ios::int_type overflow(ios::int_type c)
    	{
    		if(!traits_type::eq_int_type(c, traits_type::eof())) 
            { 
    			if(traits_type::eq_int_type(buf->sputc(crypt(c)), traits_type::eof())) 
    				return traits_type::eof(); 
            } 
            return traits_type::not_eof(c); 
    	}
    	cryptbuf<c>(streambuf *buffer):buf(buffer){}
    	int sync()
    	{
    		return buf->pubsync();
    	}
    private:
    
    template <typename c, typename stream>
    class cryptstream :private c,  public stream  
    {
    public:
    	cryptstream(streambuf *buffer):c(buffer),stream(this) {}
    };
    

    Das klappt auch schon perfekt...

    Nu will ich das auch wieder auslesen, und hab schon so ziemlich
    alles mal testweise überschrieben, und eigentlich nur festgestellt,
    das ich in underflow den ersten character gekomme, mehr nicht:

    template<typename c>
    class encryptbuf : private c, public streambuf
    {
    protected:
    	streambuf *buf;
    public:
    	ios::int_type underflow()
    	{
    		int c =buf->sgetc();
    		cout <<c  << "underflow" << endl;
    		if(!traits_type::eq_int_type(c, traits_type::eof())) 
            { 
    			if(traits_type::eq_int_type(buf->sputc(encrypt(c)), traits_type::eof())) 
    				return traits_type::eof(); 
            } 
            return traits_type::not_eof(c); 
    	}
    	encryptbuf<c>(streambuf *buffer):buf(buffer){}
    	int sync()
    	{
    		return buf->pubsync();
    	}
    private:
    
    };
    

    Wie müsste ich Underflow korrekt überladen, oder muss ich dies überhaupt ?

    Devil



  • Hm, hat niemand ne idee ?
    Mir gehts eigenltich nur darum, wie kann ich
    das in einem streambuffer wieder auslesen,
    was ich vorher dort reingeschrieben habe...

    Devil



  • while(!humeSikkins->isAvailable())
    {
        noHelp();
    }
    


  • n1, supercode ^^



  • Hallo,
    zum Lesen aus einem Stream musst du mindestens zwei Dinge tun:
    1. underflow überschreiben und einen eigenen Lesepuffer bereitstellen
    oder
    2. underflow und uflow überschreiben. Hier ist ein Lesepuffer dann optional.

    Die Methode underflow wird aufgerufen (von Methoden wie sgetc oder sbumpc), falls kein Zeichen mehr im Lesepuffer ist (sofern vorhanden). underflow muss also Zeichen bereitstellen (sprich: Mit der eigentlichen Datenquelle kommunizieren). underflow selbst sollte natürlich nicht solche Methoden wie sgetc benutzen.

    uflow wird normalerweise von der Methode sbumpc (liest ein Zeichen und setzt danach den Lesezeiger um eins weiter) aufgerufen. uflow selbst ruft erst underflow auf (um ein Zeichen zu bekommen) und setzt dann den Lesezeiger eins weiter (also entweder hat man einen Lesepuffer oder man muss auf diese Defaultimplementation verzichten).

    Ein Lesepuffer wird durch drei Zeiger beschrieben:
    1. end back - eback(): Dieser Zeiger markiert das Ende der Putbackarea. Bis hierhin können also zuvor gelesene Zeichen in den Stream zurückgepackt werden.

    2. get pointer - gptr(): Markiert die aktuelle Leseposition

    3. end get pointer - egptr(): Markiert das Ende des Puffers im STL-typischen Stil (eins hinter das letzte Element).

    Die einfachste Form einer Streambuffer-Klasse stellt im Konstruktor einen Lesepuffer bereit (über setg) und überschreibt underflow.
    Ein Beispiel frei nach Josuttis' "The C++ Standard Library:"

    class InBuf : public std::streambuf
    {
    public:
        InBuf()
        {
            // Lesepuffer bekanntmachen.
            // setg erwartet: eback, gptr gefolgt von egptr
            // Unsere putback-Area erfüllt die Minimalanforderungen: 1 Zeichen
            // Da wir am Anfang noch keine Zeichen haben, setzen wir alle drei Zeiger
            // an die selbe Stelle -> beim ersten Leseversuch wird garantiert 
            // underflow aufgerufen
            setg(readBuf_ + 1, readBuf_ + 1, readBuf_ + 1);
        }
    
    protected:
         int_type underflow() 
         {
             // Wir haben noch ungelesene Zeichen in unserem Puffer
             if (gptr() < egptr())
             {
             	// aktuelles Zeichen zurückliefern.
             	// Die Leseposition wird *nicht* verändert. Dies ist die 
             	// Aufgabe anderer Methoden wie z.B. uflow
             	return *gptr();
             }
    
             // Keine ungelesenen Zeichen mehr im Puffer
             int putBack = gptr() != eback() ? 1 : 0;
    
             // Zeichen in die Putback-Area kopieren...
             memcpy(
             		readBuf_ + (1 - putBack)	// Beginn der Putback-Area
             		, readBuf_ + 1 				// Eigentlicher Beginn unseres Puffers
             		, putBack
             );
    
             // ...und neue Zeichen lesen
             int num = read(your_device, readBuf_ + 1, 10 - 1);
             if (num <= 0)
             	return EOF;	// keine Zeichen mehr vorhanden
    
    		// Puffer aktualisieren...
    		setg(
    			readBuf_ + (1 - putBack)	// Beginn der Putback-Area
    			, readBuf_ + 1				// aktuelle Leseposition
    			, readBuf_ + 1 + num		// Ende des Puffers
    		);
    
    		// ...und aktuelles Zeichen liefern
    		return *gptr();
         }
    private:
        // Lesepuffer für maximal 10 Zeichen
        char readBuf_[10];
    };
    

    Genauere Informationen zu diesem Thema (z.B. wann und warum du pbackfail überschreiben musst) findest du hier:

    http://www.langer.camelot.de/IOStreams/Excerpt/excerpt.htm



  • Hm, also ich hab bei deinem Code jetzt nur noch 1 Problem:

    bei der funktion read über gibtst du your_device, wo wird diese definiert,
    bzw. was müsste ich übergeben? ?

    Devil



  • Hallo,
    sowohl your_device, als auch read sind fiktiv (your_device könnte hier z.B. ein File-Descriptor und read die C-Funktion sein). Hiermit sollte nur angedeuted werden, dass an dieser Stelle tatsächliche Zeichen gelesen werden müssen, und zwar von der Quelle, die du abstrahierst.
    Was du hier also konkret machen musst, hängt von deiner Situation ab.

    Hätte ich wohl besser kommentieren müssen.



  • sprich ich musslediglich noch open überschreiben, und dafür sorgen
    das die Datei geöffnet wird. Und das ganze Auslesen dann auf Lowlevel basis
    machen.

    Gibts ne Möglichkeit sich nur in den Zeichenstrom einzuhängen, zwecks manipulation ?
    Ich mein beim Schreiben geht das ja auch. 🙄

    Devil



  • Gibts ne Möglichkeit sich nur in den Zeichenstrom einzuhängen, zwecks manipulation ?

    Lies dir mal diesen Artikel durch:
    http://www.gabi-soft.fr/articles/fltrsbf1.html

    Und danach schau dir mal die noch nicht offizielle boost::Streambuf Library an.
    Die ist meiner Meinung nach sehr gut gelungen.

    Selbige findest du in der boost-File-Sektion (streambuf_lib.tar.gz):

    http://groups.yahoo.com/group/boost/files/


Log in to reply