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