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