1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef BUFFER_H
21 #define BUFFER_H
22 
23 #include "SMTask.h"
24 #include "Filter.h"
25 #include "Timer.h"
26 #include "fg.h"
27 #include "xstring.h"
28 #include "Speedometer.h"
29 
30 #include <stdarg.h>
31 
32 #ifdef HAVE_ICONV
33 CDECL_BEGIN
34 # include <iconv.h>
35 CDECL_END
36 #endif
37 
38 class Buffer
39 {
40 protected:
41    xstring error_text;
42    int  saved_errno;
43    bool error_fatal;
44 
45    xstring buffer;
46    int buffer_ptr;
47    bool eof;	  // no reads possible (except from mem buffer)
48    bool broken;	  // no writes possible
49 
50    bool save;  // save skipped data
51    int save_max;
52 
53    off_t pos;
54 
55    Ref<Speedometer> rate;
56    void RateAdd(int n);
57 
58    void Allocate(int size);
59 
60    void SaveMaxCheck(int addsize);
61 
62 public:
Error()63    bool Error() const { return error_text!=0; }
ErrorFatal()64    bool ErrorFatal() const { return error_fatal; }
65    void SetError(const char *e,bool fatal=false);
66    void SetErrorCached(const char *e);
ErrorText()67    const char *ErrorText() const { return error_text; }
Size()68    int Size() const { return buffer.length()-buffer_ptr; }
Eof()69    bool Eof() const { return eof; }
Broken()70    bool Broken() const { return broken; }
71 
72    const char *Get() const;
73    void Get(const char **buf,int *size) const;
74    void Skip(int len); // Get(); consume; Skip()
75    void UnSkip(int len); // this only works if there were no Put's.
76    void Append(const char *buf,int size);
Append(const xstring & s)77    void Append(const xstring& s) { Append(s.get(),s.length()); }
78    void Put(const char *buf,int size);
Put(const char * buf)79    void Put(const char *buf) { Put(buf,strlen(buf)); }
Put(const xstring & s)80    void Put(const xstring &s) { Put(s.get(),s.length()); }
Put(char c)81    void Put(char c) { Put(&c,1); }
82    void Format(const char *f,...) PRINTF_LIKE(2,3);
83    void vFormat(const char *f, va_list v);
PutEOF()84    void PutEOF() { eof=true; }
GetSpace(int size)85    char *GetSpace(int size) {
86       Allocate(size);
87       return buffer.get_non_const()+buffer.length();
88    }
SpaceAdd(int size)89    void SpaceAdd(int size) {
90       buffer.set_length(buffer.length()+size);
91    }
92    void Prepend(const char *buf,int size);
Prepend(const char * buf)93    void Prepend(const char *buf) { Prepend(buf,strlen(buf)); }
94    int MoveDataHere(Buffer *o,int len);
MoveDataHere(const Ref<BUF> & o,int len)95    template<class BUF> int MoveDataHere(const Ref<BUF>& o,int len) { return MoveDataHere(o.get_non_const(),len); }
MoveDataHere(const SMTaskRef<BUF> & o,int len)96    template<class BUF> int MoveDataHere(const SMTaskRef<BUF>& o,int len) { return MoveDataHere(o.get_non_const(),len); }
97 
98    unsigned long long UnpackUINT64BE(int offset=0) const;
99    unsigned UnpackUINT32BE(int offset=0) const;
100    unsigned UnpackUINT16BE(int offset=0) const;
101    unsigned UnpackUINT8(int offset=0) const;
102    void PackUINT64BE(unsigned long long data);
103    void PackUINT32BE(unsigned data);
104    void PackUINT16BE(unsigned data);
105    void PackUINT8(unsigned data);
106 
107    long long UnpackINT64BE(int offset=0) const;
108    int UnpackINT32BE(int offset=0) const;
109    int UnpackINT16BE(int offset=0) const;
110    int UnpackINT8(int offset=0) const;
111    void PackINT64BE(long long data);
112    void PackINT32BE(int data);
113    void PackINT16BE(int data);
114    void PackINT8(int data);
115 
116    // useful for cache.
Save(int m)117    void Save(int m) { save=true; save_max=m; }
IsSaving()118    bool IsSaving() const { return save; }
119    void GetSaved(const char **buf,int *size) const;
120    void SaveRollback(off_t p);
121 
SetPos(off_t p)122    void SetPos(off_t p) { pos=p; }
GetPos()123    off_t GetPos() const { return pos; }
124 
SetSpeedometer(Speedometer * s)125    void SetSpeedometer(Speedometer *s) { rate=s; }
126    const char *GetRateStrS();
127 
128    void Empty();
129 
130    Buffer();
131    ~Buffer();
132 
133    const char *Dump() const;
134 };
135 
136 class DataTranslator : public Buffer
137 {
138 public:
139    virtual void PutTranslated(Buffer *dst,const char *buf,int size)=0;
ResetTranslation()140    virtual void ResetTranslation() { Empty(); }
~DataTranslator()141    virtual ~DataTranslator() {}
142 
143    // same as PutTranslated, but does not advance pos.
144    void AppendTranslated(Buffer *dst,const char *buf,int size);
145 };
146 
147 #ifdef HAVE_ICONV
148 class DataRecoder : public DataTranslator
149 {
150    iconv_t backend_translate;
151 public:
152    void PutTranslated(Buffer *dst,const char *buf,int size);
153    void ResetTranslation();
154    DataRecoder(const char *from_code,const char *to_code,bool translit=true);
155    ~DataRecoder();
156 };
157 #endif //HAVE_ICONV
158 
159 class DirectedBuffer : public Buffer
160 {
161 public:
162    enum dir_t { GET, PUT };
163 
164 protected:
165    Ref<DataTranslator> translator;
166    dir_t mode;
167    void EmbraceNewData(int len);
168 
169 public:
DirectedBuffer(dir_t m)170    DirectedBuffer(dir_t m) : mode(m) {}
171    void SetTranslator(DataTranslator *t);
GetTranslator()172    const Ref<DataTranslator>& GetTranslator() const { return translator; }
173    void SetTranslation(const char *be_encoding,bool translit=true)
174 #ifdef HAVE_ICONV
175       ;
176 #else
177       {}
178 #endif //HAVE_ICONV
179    void PutTranslated(const char *buf,int size);
PutTranslated(const char * buf)180    void PutTranslated(const char *buf) { PutTranslated(buf,strlen(buf)); }
PutTranslated(const xstring & s)181    void PutTranslated(const xstring& s) { PutTranslated(s.get(),s.length()); }
182    void ResetTranslation();
PutRaw(const char * buf,int size)183    void PutRaw(const char *buf,int size) { Buffer::Put(buf,size); }
PutRaw(const char * buf)184    void PutRaw(const char *buf) { Buffer::Put(buf); }
185    void Put(const char *buf,int size);
Put(const char * buf)186    void Put(const char *buf) { Put(buf,strlen(buf)); }
187    void PutEOF(); // set eof, flush translator
188    int MoveDataHere(Buffer *o,int len);
MoveDataHere(const SMTaskRef<BUF> & o,int len)189    template<class BUF> int MoveDataHere(const SMTaskRef<BUF>& o,int len) { return MoveDataHere(o.get_non_const(),len); }
GetDirection()190    dir_t GetDirection() { return mode; }
191 };
192 
193 class IOBuffer : public DirectedBuffer, public SMTask
194 {
195 protected:
196    // low-level for derived classes
Get_LL(int size)197    virtual int Get_LL(int size) { return 0; }
Put_LL(const char * buf,int size)198    virtual int Put_LL(const char *buf,int size) { return 0; }
PutEOF_LL()199    virtual int PutEOF_LL() { return 0; }
200 
201    Time event_time; // used to detect timeouts
202    int max_buf;
203    int get_size;
204    int TuneGetSize(int res);
205 
206    enum {
207       GET_BUFSIZE=0x10000,
208       PUT_LL_MIN=0x2000,
209    };
210 
211    virtual ~IOBuffer();
212 
213 public:
214    IOBuffer(dir_t m);
EventTime()215    virtual const Time& EventTime()
216       {
217 	 if(IsSuspended())
218 	    return now;
219 	 return event_time;
220       }
Done()221    virtual bool Done()
222       {
223 	 return(broken || Error() || (eof && (mode==GET || Size()==0)));
224       }
225    virtual int Do();
226 
GetFgData(bool)227    virtual FgData *GetFgData(bool) { return 0; }
Status()228    virtual const char *Status() { return ""; }
Buffered()229    virtual int Buffered() { return Size(); }
TranslationEOF()230    virtual bool TranslationEOF() const { return translator?translator->Eof():false; }
231 
232    // Put method with Put_LL shortcut
233    void Put(const char *,int);
234    void Put(const char *buf);
Put(const xstring & s)235    void Put(const xstring &s) { Put(s.get(),s.length()); }
Put(char c)236    void Put(char c) { Put(&c,1); }
237    // anchor to PutEOF_LL
PutEOF()238    void PutEOF() { DirectedBuffer::PutEOF(); PutEOF_LL(); }
239 
SetMaxBuffered(int m)240    void SetMaxBuffered(int m) { max_buf=m; }
IsFull()241    bool IsFull() { return Size()+(translator?translator->Size():0) >= max_buf; }
242 };
243 
244 class IOBufferStacked : public IOBuffer
245 {
246    SMTaskRef<IOBuffer> down;
247 
248    int Get_LL(int size);
249    int Put_LL(const char *buf,int size);
250 
251    void SuspendInternal();
252    void ResumeInternal();
253 
254 public:
IOBufferStacked(IOBuffer * b)255    IOBufferStacked(IOBuffer *b) : IOBuffer(b->GetDirection()), down(b) {}
TranslationEOF()256    bool TranslationEOF() const { return down->TranslationEOF()||IOBuffer::TranslationEOF(); }
PrepareToDie()257    void PrepareToDie() { down=0; }
EventTime()258    const Time& EventTime() { return down->EventTime(); }
259    int Do();
260    bool Done();
261 };
262 
263 class IOBufferFDStream : public IOBuffer
264 {
265    Ref<FDStream> my_stream;
266    const Ref<FDStream>& stream;
267    Ref<Timer> put_ll_timer;
268 
269    int Get_LL(int size);
270    int Put_LL(const char *buf,int size);
271 
272 public:
IOBufferFDStream(FDStream * o,dir_t m)273    IOBufferFDStream(FDStream *o,dir_t m)
274       : IOBuffer(m), my_stream(o), stream(my_stream) {}
IOBufferFDStream(const Ref<FDStream> & o,dir_t m)275    IOBufferFDStream(const Ref<FDStream>& o,dir_t m)
276       : IOBuffer(m), stream(o) {}
IOBufferFDStream(FDStream * o,dir_t m,Timer * t)277    IOBufferFDStream(FDStream *o,dir_t m,Timer *t)
278       : IOBuffer(m), my_stream(o), stream(my_stream), put_ll_timer(t) {}
IOBufferFDStream(const Ref<FDStream> & o,dir_t m,Timer * t)279    IOBufferFDStream(const Ref<FDStream>& o,dir_t m,Timer *t)
280       : IOBuffer(m), stream(o), put_ll_timer(t) {}
281    ~IOBufferFDStream();
282    bool Done();
283    FgData *GetFgData(bool fg);
Status()284    const char *Status() { return stream->status; }
285 };
286 
287 #include <FileAccess.h>
288 
289 class IOBufferFileAccess : public IOBuffer
290 {
291    const FileAccessRef& session;
292    FileAccessRef session_ref;
293 
294    int Get_LL(int size);
295 
296    void SuspendInternal();
297    void ResumeInternal();
298 
299 public:
IOBufferFileAccess(const FileAccessRef & i)300    IOBufferFileAccess(const FileAccessRef& i) : IOBuffer(GET), session(i) {}
IOBufferFileAccess(FileAccess * fa)301    IOBufferFileAccess(FileAccess *fa) : IOBuffer(GET), session(session_ref), session_ref(fa) {}
~IOBufferFileAccess()302    ~IOBufferFileAccess() {
303       // we don't want to delete the session
304       (void)session_ref.borrow();
305    }
306 
307    const char *Status();
308 };
309 
310 #endif // BUFFER_H
311