1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2016 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 #include <config.h>
21 #include <errno.h>
22 #include "buffer.h"
23 #include "FileAccess.h"
24 #include "misc.h"
25 #include "trio.h"
26 #include "Speedometer.h"
27 #include "log.h"
28 
29 #define BUFFER_INC	   (8*1024) // should be power of 2
30 
Get() const31 const char *Buffer::Get() const
32 {
33    if(Size()==0)
34       return eof?0:"";
35    return buffer+buffer_ptr;
36 }
37 
Get(const char ** buf,int * size) const38 void Buffer::Get(const char **buf,int *size) const
39 {
40    *size=Size();
41    *buf=Get();
42 }
43 
GetSaved(const char ** buf,int * size) const44 void Buffer::GetSaved(const char **buf,int *size) const
45 {
46    if(!save)
47    {
48       *size=0;
49       *buf=0;
50       return;
51    }
52    *buf=buffer;
53    *size=buffer.length();
54 }
55 
SaveRollback(off_t p)56 void Buffer::SaveRollback(off_t p)
57 {
58    pos=p;
59    if(buffer_ptr<p)
60       save=false;
61    if(!save)
62       p=0;
63    buffer.truncate(buffer_ptr=p);
64 }
65 
Allocate(int size)66 void Buffer::Allocate(int size)
67 {
68    if(buffer_ptr>0 && Size()==0 && !save)
69    {
70       buffer.truncate(0);
71       buffer_ptr=0;
72    }
73 
74    size_t in_buffer_real=Size();
75    /* disable data movement to beginning of the buffer, if:
76       1. we save the data explicitly;
77       2. we add more data than there is space in the beginning of the buffer
78 	 (because the probability of realloc is high anyway);
79       3. the gap at beginning is smaller than the amount of data in the buffer
80 	 (because the penalty of data movement is high). */
81    if(save || buffer_ptr<size || buffer_ptr<Size())
82       in_buffer_real+=buffer_ptr;
83 
84    // could be round-robin, but this is easier
85    if(buffer.length()>in_buffer_real)
86    {
87       buffer.nset(buffer+buffer_ptr,Size());
88       buffer_ptr=0;
89    }
90 
91    buffer.get_space2(in_buffer_real+size,BUFFER_INC);
92 }
93 
SaveMaxCheck(int size)94 void Buffer::SaveMaxCheck(int size)
95 {
96    if(save && buffer_ptr+size>save_max)
97       save=false;
98 }
99 
Append(const char * buf,int size)100 void Buffer::Append(const char *buf,int size)
101 {
102    if(size==0)
103       return;
104 
105    SaveMaxCheck(size);
106    if(Size()==0 && buffer_ptr>0 && !save)
107    {
108       buffer.truncate(0);
109       buffer_ptr=0;
110    }
111 
112    memmove(GetSpace(size),buf,size);
113    SpaceAdd(size);
114 }
Put(const char * buf,int size)115 void Buffer::Put(const char *buf,int size)
116 {
117    Append(buf,size);
118    pos+=size;
119 }
Prepend(const char * buf,int size)120 void Buffer::Prepend(const char *buf,int size)
121 {
122    if(size==0)
123       return;
124    save=false;
125    if(Size()==0)
126    {
127       memmove(GetSpace(size),buf,size);
128       SpaceAdd(size);
129       return;
130    }
131    if(buffer_ptr<size)
132    {
133       Allocate(size-buffer_ptr);
134       memmove(buffer.get_non_const()+size,buffer+buffer_ptr,Size());
135       SpaceAdd(size-buffer_ptr);
136       buffer_ptr=size;
137    }
138    memmove(buffer.get_non_const()+buffer_ptr-size,buf,size);
139    buffer_ptr-=size;
140 }
141 
Format(const char * f,...)142 void Buffer::Format(const char *f,...)
143 {
144    va_list v;
145    va_start(v,f);
146    vFormat(f, v);
147    va_end(v);
148 }
149 
vFormat(const char * f,va_list v)150 void Buffer::vFormat(const char *f, va_list v)
151 {
152    int size=64;
153    for(;;)
154    {
155       va_list tmp;
156       VA_COPY(tmp,v);
157       int res=vsnprintf(GetSpace(size), size, f, tmp);
158       va_end(tmp);
159       if(res>=0 && res<size)
160       {
161 	 SpaceAdd(res);
162 	 return;
163       }
164       if(res>size)   // some vsnprintf's return desired buffer size.
165 	 size=res+1;
166       else
167 	 size*=2;
168    }
169 }
170 
Skip(int len)171 void Buffer::Skip(int len)
172 {
173    if(len>Size())
174       len=Size();
175    buffer_ptr+=len;
176    pos+=len;
177 }
UnSkip(int len)178 void Buffer::UnSkip(int len)
179 {
180    if(len>buffer_ptr)
181       len=buffer_ptr;
182    buffer_ptr-=len;
183    pos-=len;
184 }
185 
Empty()186 void Buffer::Empty()
187 {
188    buffer.truncate(0);
189    buffer_ptr=0;
190    if(save_max>0)
191       save=true;
192 }
193 
194 // move data from other buffer, prepare for SpaceAdd.
MoveDataHere(Buffer * o,int max_len)195 int Buffer::MoveDataHere(Buffer *o,int max_len)
196 {
197    const char *b;
198    int size;
199    o->Get(&b,&size);
200    if(size>max_len)
201       size=max_len;
202    if(size>0) {
203       if(size>=64 && Size()==0 && o->Size()==size && !save && !o->save) {
204 	 // optimization by swapping buffers
205 	 buffer.swap(o->buffer);
206 	 buffer_ptr=replace_value(o->buffer_ptr,buffer_ptr);
207 	 buffer.set_length_no_z(buffer_ptr);
208 	 o->pos+=size;
209       } else {
210 	 memcpy(GetSpace(size),b,size);
211 	 o->Skip(size);
212       }
213    }
214    return size;
215 }
216 
Buffer()217 Buffer::Buffer()
218 {
219    saved_errno=0;
220    error_fatal=false;
221    buffer_ptr=0;
222    eof=false;
223    broken=false;
224    save=false;
225    save_max=0;
226    pos=0;
227 }
~Buffer()228 Buffer::~Buffer()
229 {
230 }
231 
GetRateStrS()232 const char *Buffer::GetRateStrS()
233 {
234    if(!rate || !rate->Valid())
235       return "";
236    return rate->GetStrS();
237 }
RateAdd(int n)238 void Buffer::RateAdd(int n)
239 {
240    if(!rate)
241       return;
242    rate->Add(n);
243 }
244 
SetError(const char * e,bool fatal)245 void Buffer::SetError(const char *e,bool fatal)
246 {
247    error_text.set(e);
248    error_fatal=fatal;
249 }
SetErrorCached(const char * e)250 void Buffer::SetErrorCached(const char *e)
251 {
252    SetError(e,false);
253    error_text.append(_(" [cached]"));
254 }
Dump() const255 const char *Buffer::Dump() const
256 {
257    if(buffer_ptr==0)
258       return buffer.dump();
259    return xstring::get_tmp(Get(),Size()).dump();
260 }
261 
AppendTranslated(Buffer * target,const char * put_buf,int size)262 void DataTranslator::AppendTranslated(Buffer *target,const char *put_buf,int size)
263 {
264    off_t old_pos=target->GetPos();
265    PutTranslated(target,put_buf,size);
266    target->SetPos(old_pos);
267 }
268 
SetTranslator(DataTranslator * t)269 void DirectedBuffer::SetTranslator(DataTranslator *t)
270 {
271    if(mode==GET && !translator && Size()>0) {
272       // translate unread data
273       const char *data;
274       int len;
275       Get(&data,&len);
276       t->Put(data,len);
277       buffer.truncate(buffer_ptr);
278       t->AppendTranslated(this,0,0);
279    }
280    translator=t;
281 }
282 
283 #ifdef HAVE_ICONV
PutTranslated(Buffer * target,const char * put_buf,int size)284 void DataRecoder::PutTranslated(Buffer *target,const char *put_buf,int size)
285 {
286    bool from_untranslated=false;
287    if(Size()>0)
288    {
289       Put(put_buf,size);
290       Get(&put_buf,&size);
291       from_untranslated=true;
292    }
293    if(size<=0)
294       return;
295    if(!backend_translate)
296    {
297       target->Put(put_buf,size);
298       if(from_untranslated)
299 	 Skip(size);
300       return;
301    }
302    size_t put_size=size;
303 
304    int size_coeff=6;
305 try_again:
306    if(put_size==0)
307       return;
308    size_t store_size=size_coeff*put_size;
309    char *store_space=target->GetSpace(store_size);
310    char *store_buf=store_space;
311    const char *base_buf=put_buf;
312    // do the translation
313    ICONV_CONST char **put_buf_ptr=const_cast<ICONV_CONST char**>(&put_buf);
314    size_t res=iconv(backend_translate,put_buf_ptr,&put_size,&store_buf,&store_size);
315    target->SpaceAdd(store_buf-store_space);
316    if(from_untranslated)
317       Skip(put_buf-base_buf);
318    if(res==(size_t)-1)
319    {
320       switch(errno)
321       {
322       case EINVAL: // incomplete character
323 	 if(!from_untranslated)
324 	    Put(put_buf,put_size);
325 	 break;
326       case EILSEQ: // invalid character
327 	 target->Put("?");
328 	 put_buf++;
329 	 put_size--;
330 	 goto try_again;
331       case E2BIG:  // no room to store result, allocate more.
332 	 size_coeff*=2;
333 	 goto try_again;
334       default:
335 	 break;
336       }
337    }
338    return;
339 }
ResetTranslation()340 void DataRecoder::ResetTranslation()
341 {
342    Empty();
343    if(!backend_translate)
344       return;
345    iconv(backend_translate,0,0,0,0);
346 }
~DataRecoder()347 DataRecoder::~DataRecoder()
348 {
349    if(backend_translate)
350       iconv_close(backend_translate);
351 }
DataRecoder(const char * from_code,const char * to_code,bool translit)352 DataRecoder::DataRecoder(const char *from_code,const char *to_code,bool translit)
353 {
354    backend_translate=0;
355 
356    if(translit) {
357       const char *to_code_translit=xstring::cat(to_code,"//TRANSLIT",NULL);
358       backend_translate=iconv_open(to_code_translit,from_code);
359       if(backend_translate!=(iconv_t)-1) {
360 	 Log::global->Format(9,"initialized translation from %s to %s\n",from_code,to_code_translit);
361 	 return;
362       }
363       backend_translate=0;
364    }
365 
366    backend_translate=iconv_open(to_code,from_code);
367    if(backend_translate!=(iconv_t)-1) {
368       Log::global->Format(9,"initialized translation from %s to %s\n",from_code,to_code);
369       return;
370    }
371 
372    Log::global->Format(0,"iconv_open(%s,%s) failed: %s\n",
373 			      to_code,from_code,strerror(errno));
374    backend_translate=0;
375 }
376 
SetTranslation(const char * enc,bool translit)377 void DirectedBuffer::SetTranslation(const char *enc,bool translit)
378 {
379    if(!enc || !*enc)
380       return;
381    const char *local_code=ResMgr::Query("file:charset",0);
382    if(!local_code || !*local_code)
383       return;
384    const char *from_code=(mode==GET?enc:local_code);
385    const char *to_code  =(mode==GET?local_code:enc);
386    if(!strcasecmp(from_code,to_code))
387       return;
388    SetTranslator(new DataRecoder(from_code,to_code,translit));
389 }
390 #endif //HAVE_ICONV
391 
ResetTranslation()392 void DirectedBuffer::ResetTranslation()
393 {
394    if(translator)
395       translator->ResetTranslation();
396 }
Put(const char * buf,int size)397 void DirectedBuffer::Put(const char *buf,int size)
398 {
399    if(mode==PUT && translator)
400       translator->PutTranslated(this,buf,size);
401    else
402       Buffer::Put(buf,size);
403 }
PutTranslated(const char * buf,int size)404 void DirectedBuffer::PutTranslated(const char *buf,int size)
405 {
406    if(translator)
407       translator->PutTranslated(this,buf,size);
408    else
409       Buffer::Put(buf,size);
410 }
MoveDataHere(Buffer * buf,int size)411 int DirectedBuffer::MoveDataHere(Buffer *buf,int size)
412 {
413    if(size>buf->Size())
414       size=buf->Size();
415    if(mode==PUT && translator)
416       translator->PutTranslated(this,buf->Get(),size);
417    else
418       return Buffer::MoveDataHere(buf,size);
419    return size;
420 }
PutEOF()421 void DirectedBuffer::PutEOF()
422 {
423    if(mode==PUT && translator)
424       translator->PutTranslated(this,0,0);
425    Buffer::PutEOF();
426 }
427 
EmbraceNewData(int len)428 void DirectedBuffer::EmbraceNewData(int len)
429 {
430    if(len<=0)
431       return;
432    RateAdd(len);
433    if(translator)
434    {
435       // copy the data to free room for translated data
436       translator->Put(buffer+buffer.length(),len);
437       translator->AppendTranslated(this,0,0);
438    }
439    else
440       SpaceAdd(len);
441    SaveMaxCheck(0);
442 }
443 
444 
IOBuffer(dir_t m)445 IOBuffer::IOBuffer(dir_t m)
446    : DirectedBuffer(m), event_time(now),
447      max_buf(0), get_size(GET_BUFSIZE)
448 {
449 }
~IOBuffer()450 IOBuffer::~IOBuffer()
451 {
452 }
453 
Put(const char * buf,int size)454 void IOBuffer::Put(const char *buf,int size)
455 {
456    if(size>=PUT_LL_MIN && Size()==0 && mode==PUT && !save && !translator)
457    {
458       int res=Put_LL(buf,size);
459       if(res>=0)
460       {
461 	 buf+=res;
462 	 size-=res;
463 	 pos+=res;
464       }
465    }
466    if(size<=0)
467       return;
468    if(Size()==0)
469       current->Timeout(0);
470    DirectedBuffer::Put(buf,size);
471 }
Put(const char * buf)472 void IOBuffer::Put(const char *buf)
473 {
474    Put(buf,strlen(buf));
475 }
476 
TuneGetSize(int res)477 int IOBuffer::TuneGetSize(int res)
478 {
479    if(res>0)
480    {
481       // buffer size tuning depending on data rate
482       const int max_get_size=(max_buf?max_buf:0x100000);
483       if(res>get_size/2 && Size()+get_size*2<=max_get_size)
484 	 get_size*=2;
485    }
486    return res;
487 }
488 
Do()489 int IOBuffer::Do()
490 {
491    if(Done() || Error())
492       return STALL;
493    int res=0;
494    switch(mode)
495    {
496    case PUT:
497       if(Size()==0)
498 	 return STALL;
499       res=Put_LL(buffer+buffer_ptr,Size());
500       if(res>0)
501       {
502 	 RateAdd(res);
503 	 buffer_ptr+=res;
504 	 event_time=now;
505 	 if(eof)
506 	    PutEOF_LL();
507 	 return MOVED;
508       }
509       break;
510 
511    case GET:
512       if(eof)
513 	 return STALL;
514       res=TuneGetSize(Get_LL(get_size));
515       if(res>0)
516       {
517 	 EmbraceNewData(res);
518 	 event_time=now;
519 	 return MOVED;
520       }
521       if(eof)
522       {
523 	 event_time=now;
524 	 return MOVED;
525       }
526       break;
527    }
528    if(res<0)
529    {
530       event_time=now;
531       return MOVED;
532    }
533    return STALL;
534 }
535 
536 // IOBufferStacked implementation
537 #undef super
538 #define super IOBuffer
Do()539 int IOBufferStacked::Do()
540 {
541    int m=STALL;
542    if(Done() || Error())
543       return m;
544    int res=0;
545    switch(mode)
546    {
547    case PUT:
548       if(down->Broken() && !broken)
549       {
550 	 broken=true;
551 	 return MOVED;
552       }
553       if(down->Error())
554       {
555 	 SetError(down->ErrorText(),down->ErrorFatal());
556 	 m=MOVED;
557       }
558       if(Size()==0)
559 	 return m;
560       res=Put_LL(buffer+buffer_ptr,Size());
561       if(res>0)
562       {
563 	 buffer_ptr+=res;
564 	 m=MOVED;
565       }
566       break;
567 
568    case GET:
569       if(eof)
570 	 return m;
571       res=Get_LL(/*unused*/0);
572       if(res>0)
573       {
574 	 EmbraceNewData(res);
575 	 m=MOVED;
576       }
577       if(eof)
578 	 m=MOVED;
579       if(down->Error())
580       {
581 	 SetError(down->ErrorText(),down->ErrorFatal());
582 	 m=MOVED;
583       }
584       break;
585    }
586    if(res<0)
587       return MOVED;
588    return m;
589 }
Put_LL(const char * buf,int size)590 int IOBufferStacked::Put_LL(const char *buf,int size)
591 {
592    if(down->Broken())
593    {
594       broken=true;
595       return -1;
596    }
597    down->Put(buf,size);
598    return size;
599 }
600 
Get_LL(int)601 int IOBufferStacked::Get_LL(int)
602 {
603    if(max_buf && Size()>=max_buf) {
604       down->SuspendSlave();
605       return 0;
606    }
607    down->ResumeSlave();
608    int size=MoveDataHere(down,down->Size());
609    if(down->Size()==0 && down->Eof())
610       PutEOF();
611    return size;
612 }
613 
Done()614 bool IOBufferStacked::Done()
615 {
616    if(super::Done())
617       return down->Done();
618    return false;
619 }
620 
SuspendInternal()621 void IOBufferStacked::SuspendInternal()
622 {
623    super::SuspendInternal();
624    down->SuspendSlave();
625 }
ResumeInternal()626 void IOBufferStacked::ResumeInternal()
627 {
628    if(!max_buf || Size()<max_buf)
629       down->ResumeSlave();
630    super::ResumeInternal();
631 }
632 
633 // IOBufferFDStream implementation
634 #include <fcntl.h>
635 #include <unistd.h>
636 #undef super
637 #define super IOBuffer
Put_LL(const char * buf,int size)638 int IOBufferFDStream::Put_LL(const char *buf,int size)
639 {
640    if(put_ll_timer && !eof && Size()<PUT_LL_MIN
641    && !put_ll_timer->Stopped())
642       return 0;
643    if(stream->broken())
644    {
645       broken=true;
646       return -1;
647    }
648 
649    int res=0;
650 
651    int fd=stream->getfd();
652    if(fd==-1)
653    {
654       if(stream->error())
655 	 goto stream_err;
656       TimeoutS(1);
657       event_time=now;
658       return 0;
659    }
660 
661    res=write(fd,buf,size);
662    if(res==-1)
663    {
664       saved_errno=errno;
665       if(E_RETRY(saved_errno))
666       {
667 	 Block(fd,POLLOUT);
668 	 return 0;
669       }
670       if(NonFatalError(saved_errno))
671 	 return 0;
672       if(errno==EPIPE)
673       {
674 	 broken=true;
675 	 return -1;
676       }
677       stream->MakeErrorText(saved_errno);
678       goto stream_err;
679    }
680    if(put_ll_timer)
681       put_ll_timer->Reset();
682    return res;
683 
684 stream_err:
685    SetError(stream->error_text,!TemporaryNetworkError(saved_errno));
686    return -1;
687 }
688 
Get_LL(int size)689 int IOBufferFDStream::Get_LL(int size)
690 {
691    if(max_buf && Size()>=max_buf)
692       return 0;
693 
694    int res=0;
695 
696    int fd=stream->getfd();
697    if(fd==-1)
698    {
699       if(stream->error())
700 	 goto stream_err;
701       TimeoutS(1);
702       return 0;
703    }
704 
705    if(!Ready(fd,POLLIN))
706    {
707       Block(fd,POLLIN);
708       return 0;
709    }
710 
711    res=read(fd,GetSpace(size),size);
712    if(res==-1)
713    {
714       saved_errno=errno;
715       if(E_RETRY(saved_errno))
716       {
717 	 SetNotReady(fd,POLLIN);
718 	 Block(fd,POLLIN);
719 	 return 0;
720       }
721       if(NonFatalError(saved_errno))
722 	 return 0;
723       stream->MakeErrorText(saved_errno);
724       goto stream_err;
725    }
726 
727    if(res==0) {
728       Log::global->Format(10,"buffer: EOF on FD %d\n",fd);
729       eof=true;
730    }
731    return res;
732 
733 stream_err:
734    SetError(stream->error_text,!TemporaryNetworkError(saved_errno));
735    return -1;
736 }
737 
GetFgData(bool fg)738 FgData *IOBufferFDStream::GetFgData(bool fg)
739 {
740    if(stream->getfd()!=-1)
741       return new FgData(stream->GetProcGroup(),fg);
742    return 0;
743 }
744 
Done()745 bool IOBufferFDStream::Done()
746 {
747    if(put_ll_timer)
748       put_ll_timer->Stop();
749    if(super::Done())
750       return stream->Done(); // stream->Done indicates if sub-process finished
751    return false;
752 }
753 
~IOBufferFDStream()754 IOBufferFDStream::~IOBufferFDStream() {}
755 
756 
757 // IOBufferFileAccess implementation
758 #undef super
759 #define super IOBuffer
Get_LL(int size)760 int IOBufferFileAccess::Get_LL(int size)
761 {
762    if(max_buf && Size()>=max_buf) {
763       session->SuspendSlave();
764       return 0;
765    }
766    session->ResumeSlave();
767 
768    int res=0;
769 
770    res=session->Read(this,size);
771    if(res<0)
772    {
773       if(res==FA::DO_AGAIN)
774 	 return 0;
775       SetError(session->StrError(res));
776       return -1;
777    }
778    if(res==0)
779       eof=true;
780    return res;
781 }
782 
SuspendInternal()783 void IOBufferFileAccess::SuspendInternal()
784 {
785    super::SuspendInternal();
786    session->SuspendSlave();
787 }
ResumeInternal()788 void IOBufferFileAccess::ResumeInternal()
789 {
790    if(!max_buf || Size()<max_buf)
791       session->ResumeSlave();
792    super::ResumeInternal();
793 }
Status()794 const char *IOBufferFileAccess::Status()
795 {
796    return session->CurrentStatus();
797 }
798 
UnpackUINT64BE(int offset) const799 unsigned long long Buffer::UnpackUINT64BE(int offset) const
800 {
801    if(Size()-offset<8)
802       return 0;
803    unsigned long long res=UnpackUINT32BE(offset);
804    res=(res<<32)|UnpackUINT32BE(offset+4);
805    return res;
806 }
UnpackINT64BE(int offset) const807 long long Buffer::UnpackINT64BE(int offset) const
808 {
809    unsigned long long n=UnpackUINT64BE(offset);
810    if(n&0x8000000000000000ULL)
811       return -(long long)(n^0xFFFFFFFFFFFFFFFFULL)-1;
812    return (long long)n;
813 }
UnpackUINT32BE(int offset) const814 unsigned Buffer::UnpackUINT32BE(int offset) const
815 {
816    if(Size()-offset<4)
817       return 0;
818    unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset;
819    return (b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3];
820 }
UnpackINT32BE(int offset) const821 int Buffer::UnpackINT32BE(int offset) const
822 {
823    unsigned n=UnpackUINT32BE(offset);
824    if(n&0x80000000U)
825       return -(int)(n^0xFFFFFFFFU)-1;
826    return (int)n;
827 }
UnpackUINT16BE(int offset) const828 unsigned Buffer::UnpackUINT16BE(int offset) const
829 {
830    if(Size()-offset<2)
831       return 0;
832    unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset;
833    return (b[0]<<8)|b[1];
834 }
UnpackUINT8(int offset) const835 unsigned Buffer::UnpackUINT8(int offset) const
836 {
837    if(Size()-offset<1)
838       return 0;
839    unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset;
840    return b[0];
841 }
PackUINT64BE(unsigned long long data)842 void Buffer::PackUINT64BE(unsigned long long data)
843 {
844 #ifndef NDEBUG
845    Log::global->Format(11,"PackUINT64BE(0x%016llX)\n",data);
846 #endif
847    Allocate(8);
848    PackUINT32BE((unsigned)(data>>32));
849    PackUINT32BE((unsigned)(data&0xFFFFFFFFU));
850 }
PackINT64BE(long long data)851 void Buffer::PackINT64BE(long long data)
852 {
853    unsigned long long n;
854    if(data<0)
855       n=((unsigned long long)(-data)^0xFFFFFFFFFFFFFFFFULL)+1;
856    else
857       n=(unsigned long long)data;
858    PackUINT64BE(n);
859 }
PackUINT32BE(unsigned data)860 void Buffer::PackUINT32BE(unsigned data)
861 {
862 #ifndef NDEBUG
863    Log::global->Format(11,"PackUINT32BE(0x%08X)\n",data);
864 #endif
865    char *b=GetSpace(4);
866    b[0]=(data>>24)&255;
867    b[1]=(data>>16)&255;
868    b[2]=(data>>8)&255;
869    b[3]=(data)&255;
870    SpaceAdd(4);
871 }
PackINT32BE(int data)872 void Buffer::PackINT32BE(int data)
873 {
874    unsigned n;
875    if(data<0)
876       n=((unsigned)(-data)^0xFFFFFFFFU)+1;
877    else
878       n=(unsigned)data;
879    PackUINT32BE(n);
880 }
PackUINT16BE(unsigned data)881 void Buffer::PackUINT16BE(unsigned data)
882 {
883    char *b=GetSpace(2);
884    b[0]=(data>>8)&255;
885    b[1]=(data)&255;
886    SpaceAdd(2);
887 }
PackUINT8(unsigned data)888 void Buffer::PackUINT8(unsigned data)
889 {
890 #ifndef NDEBUG
891    Log::global->Format(11,"PackUINT8(0x%02X)\n",data);
892 #endif
893    char *b=GetSpace(1);
894    b[0]=(data)&255;
895    SpaceAdd(1);
896 }
897