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