/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BUFFER_H #define BUFFER_H #include "SMTask.h" #include "Filter.h" #include "Timer.h" #include "fg.h" #include "xstring.h" #include "Speedometer.h" #include #ifdef HAVE_ICONV CDECL_BEGIN # include CDECL_END #endif class Buffer { protected: xstring error_text; int saved_errno; bool error_fatal; xstring buffer; int buffer_ptr; bool eof; // no reads possible (except from mem buffer) bool broken; // no writes possible bool save; // save skipped data int save_max; off_t pos; Ref rate; void RateAdd(int n); void Allocate(int size); void SaveMaxCheck(int addsize); public: bool Error() const { return error_text!=0; } bool ErrorFatal() const { return error_fatal; } void SetError(const char *e,bool fatal=false); void SetErrorCached(const char *e); const char *ErrorText() const { return error_text; } int Size() const { return buffer.length()-buffer_ptr; } bool Eof() const { return eof; } bool Broken() const { return broken; } const char *Get() const; void Get(const char **buf,int *size) const; void Skip(int len); // Get(); consume; Skip() void UnSkip(int len); // this only works if there were no Put's. void Append(const char *buf,int size); void Append(const xstring& s) { Append(s.get(),s.length()); } void Put(const char *buf,int size); void Put(const char *buf) { Put(buf,strlen(buf)); } void Put(const xstring &s) { Put(s.get(),s.length()); } void Put(char c) { Put(&c,1); } void Format(const char *f,...) PRINTF_LIKE(2,3); void vFormat(const char *f, va_list v); void PutEOF() { eof=true; } char *GetSpace(int size) { Allocate(size); return buffer.get_non_const()+buffer.length(); } void SpaceAdd(int size) { buffer.set_length(buffer.length()+size); } void Prepend(const char *buf,int size); void Prepend(const char *buf) { Prepend(buf,strlen(buf)); } int MoveDataHere(Buffer *o,int len); template int MoveDataHere(const Ref& o,int len) { return MoveDataHere(o.get_non_const(),len); } template int MoveDataHere(const SMTaskRef& o,int len) { return MoveDataHere(o.get_non_const(),len); } unsigned long long UnpackUINT64BE(int offset=0) const; unsigned UnpackUINT32BE(int offset=0) const; unsigned UnpackUINT16BE(int offset=0) const; unsigned UnpackUINT8(int offset=0) const; void PackUINT64BE(unsigned long long data); void PackUINT32BE(unsigned data); void PackUINT16BE(unsigned data); void PackUINT8(unsigned data); long long UnpackINT64BE(int offset=0) const; int UnpackINT32BE(int offset=0) const; int UnpackINT16BE(int offset=0) const; int UnpackINT8(int offset=0) const; void PackINT64BE(long long data); void PackINT32BE(int data); void PackINT16BE(int data); void PackINT8(int data); // useful for cache. void Save(int m) { save=true; save_max=m; } bool IsSaving() const { return save; } void GetSaved(const char **buf,int *size) const; void SaveRollback(off_t p); void SetPos(off_t p) { pos=p; } off_t GetPos() const { return pos; } void SetSpeedometer(Speedometer *s) { rate=s; } const char *GetRateStrS(); void Empty(); Buffer(); ~Buffer(); const char *Dump() const; }; class DataTranslator : public Buffer { public: virtual void PutTranslated(Buffer *dst,const char *buf,int size)=0; virtual void ResetTranslation() { Empty(); } virtual ~DataTranslator() {} // same as PutTranslated, but does not advance pos. void AppendTranslated(Buffer *dst,const char *buf,int size); }; #ifdef HAVE_ICONV class DataRecoder : public DataTranslator { iconv_t backend_translate; public: void PutTranslated(Buffer *dst,const char *buf,int size); void ResetTranslation(); DataRecoder(const char *from_code,const char *to_code,bool translit=true); ~DataRecoder(); }; #endif //HAVE_ICONV class DirectedBuffer : public Buffer { public: enum dir_t { GET, PUT }; protected: Ref translator; dir_t mode; void EmbraceNewData(int len); public: DirectedBuffer(dir_t m) : mode(m) {} void SetTranslator(DataTranslator *t); const Ref& GetTranslator() const { return translator; } void SetTranslation(const char *be_encoding,bool translit=true) #ifdef HAVE_ICONV ; #else {} #endif //HAVE_ICONV void PutTranslated(const char *buf,int size); void PutTranslated(const char *buf) { PutTranslated(buf,strlen(buf)); } void PutTranslated(const xstring& s) { PutTranslated(s.get(),s.length()); } void ResetTranslation(); void PutRaw(const char *buf,int size) { Buffer::Put(buf,size); } void PutRaw(const char *buf) { Buffer::Put(buf); } void Put(const char *buf,int size); void Put(const char *buf) { Put(buf,strlen(buf)); } void PutEOF(); // set eof, flush translator int MoveDataHere(Buffer *o,int len); template int MoveDataHere(const SMTaskRef& o,int len) { return MoveDataHere(o.get_non_const(),len); } dir_t GetDirection() { return mode; } }; class IOBuffer : public DirectedBuffer, public SMTask { protected: // low-level for derived classes virtual int Get_LL(int size) { return 0; } virtual int Put_LL(const char *buf,int size) { return 0; } virtual int PutEOF_LL() { return 0; } Time event_time; // used to detect timeouts int max_buf; int get_size; int TuneGetSize(int res); enum { GET_BUFSIZE=0x10000, PUT_LL_MIN=0x2000, }; virtual ~IOBuffer(); public: IOBuffer(dir_t m); virtual const Time& EventTime() { if(IsSuspended()) return now; return event_time; } virtual bool Done() { return(broken || Error() || (eof && (mode==GET || Size()==0))); } virtual int Do(); virtual FgData *GetFgData(bool) { return 0; } virtual const char *Status() { return ""; } virtual int Buffered() { return Size(); } virtual bool TranslationEOF() const { return translator?translator->Eof():false; } // Put method with Put_LL shortcut void Put(const char *,int); void Put(const char *buf); void Put(const xstring &s) { Put(s.get(),s.length()); } void Put(char c) { Put(&c,1); } // anchor to PutEOF_LL void PutEOF() { DirectedBuffer::PutEOF(); PutEOF_LL(); } void SetMaxBuffered(int m) { max_buf=m; } bool IsFull() { return Size()+(translator?translator->Size():0) >= max_buf; } }; class IOBufferStacked : public IOBuffer { SMTaskRef down; int Get_LL(int size); int Put_LL(const char *buf,int size); void SuspendInternal(); void ResumeInternal(); public: IOBufferStacked(IOBuffer *b) : IOBuffer(b->GetDirection()), down(b) {} bool TranslationEOF() const { return down->TranslationEOF()||IOBuffer::TranslationEOF(); } void PrepareToDie() { down=0; } const Time& EventTime() { return down->EventTime(); } int Do(); bool Done(); }; class IOBufferFDStream : public IOBuffer { Ref my_stream; const Ref& stream; Ref put_ll_timer; int Get_LL(int size); int Put_LL(const char *buf,int size); public: IOBufferFDStream(FDStream *o,dir_t m) : IOBuffer(m), my_stream(o), stream(my_stream) {} IOBufferFDStream(const Ref& o,dir_t m) : IOBuffer(m), stream(o) {} IOBufferFDStream(FDStream *o,dir_t m,Timer *t) : IOBuffer(m), my_stream(o), stream(my_stream), put_ll_timer(t) {} IOBufferFDStream(const Ref& o,dir_t m,Timer *t) : IOBuffer(m), stream(o), put_ll_timer(t) {} ~IOBufferFDStream(); bool Done(); FgData *GetFgData(bool fg); const char *Status() { return stream->status; } }; #include class IOBufferFileAccess : public IOBuffer { const FileAccessRef& session; FileAccessRef session_ref; int Get_LL(int size); void SuspendInternal(); void ResumeInternal(); public: IOBufferFileAccess(const FileAccessRef& i) : IOBuffer(GET), session(i) {} IOBufferFileAccess(FileAccess *fa) : IOBuffer(GET), session(session_ref), session_ref(fa) {} ~IOBufferFileAccess() { // we don't want to delete the session (void)session_ref.borrow(); } const char *Status(); }; #endif // BUFFER_H