reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Data.cxx
Go to the documentation of this file.
1#include <algorithm>
2#include "rutil/ResipAssert.h"
3#include <chrono>
4#include <ctype.h>
5#include <fstream>
6#include <math.h>
7#include <limits>
8#include <limits.h>
9#include <random>
10#include <stdexcept>
11
12#if defined(HAVE_CONFIG_H)
13#include "config.h"
14#endif
15
16#include "rutil/Data.hxx"
18#include "rutil/ParseBuffer.hxx"
19#include "rutil/vmd5.hxx"
20#include "rutil/Coders.hxx"
22
23#ifdef WIN32
24#include "Winsock2.h"
25#endif
26
27using namespace resip;
28using namespace std;
29
30const Data Data::Empty("", 0);
31const Data::size_type Data::npos = std::string::npos;
32
33Data::PreallocateType::PreallocateType(int)
34{}
35
37
38const bool DataHelper::isCharHex[256] =
39{
40// 0 1 2 3 4 5 6 7 8 9 a b c d e f
41 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //0
42 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //1
43 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //2
44 true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, //3
45 false, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, //4
46 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //5
47 false, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, //6
48 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //8
49 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //9
50 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //a
51 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //b
52 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //c
53 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //d
54 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, //e
55 false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false //f
56};
57
58//must be lowercase for MD5
59static const char hexmap[] = "0123456789abcdef";
60
61static const signed char inversehexmap[] = {
62 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0 -
63 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
65 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
66 -1, -1, -1, -1, -1, -1, -1, -1, // - 47
67
68 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 48 ...
69
70 -1, -1, // 58 -
71 -1, -1, -1, -1, -1, // -64
72
73 10, 11, 12, 13, 14, 15, // 65 ...
74
75 -1, -1, -1, -1, -1, -1, -1, -1, -1, // 71 ...
76 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, -1, -1, -1, // - 96
78
79 10, 11, 12, 13, 14, 15 // 97 ...
80};
81
82int
83hexpair2int(char high, char low)
84{
85 int val;
86
87 switch(high)
88 {
89 case '0':
90 val = 0x00;
91 break;
92 case '1':
93 val = 0x10;
94 break;
95 case '2':
96 val = 0x20;
97 break;
98 case '3':
99 val = 0x30;
100 break;
101 case '4':
102 val = 0x40;
103 break;
104 case '5':
105 val = 0x50;
106 break;
107 case '6':
108 val = 0x60;
109 break;
110 case '7':
111 val = 0x70;
112 break;
113 case '8':
114 val = 0x80;
115 break;
116 case '9':
117 val = 0x90;
118 break;
119 case 'A':
120 case 'a':
121 val = 0xA0;
122 break;
123 case 'B':
124 case 'b':
125 val = 0xB0;
126 break;
127 case 'C':
128 case 'c':
129 val = 0xC0;
130 break;
131 case 'D':
132 case 'd':
133 val = 0xD0;
134 break;
135 case 'E':
136 case 'e':
137 val = 0xE0;
138 break;
139 case 'F':
140 case 'f':
141 val = 0xF0;
142 break;
143 default:
144 return '?';
145 break;
146 }
147
148 switch(low)
149 {
150 case '0':
151 if (!val)
152 {
153 return '?';
154 }
155 break;
156 case '1':
157 val += 0x01;
158 break;
159 case '2':
160 val += 0x02;
161 break;
162 case '3':
163 val += 0x03;
164 break;
165 case '4':
166 val += 0x04;
167 break;
168 case '5':
169 val += 0x05;
170 break;
171 case '6':
172 val += 0x06;
173 break;
174 case '7':
175 val += 0x07;
176 break;
177 case '8':
178 val += 0x08;
179 break;
180 case '9':
181 val += 0x09;
182 break;
183 case 'A':
184 case 'a':
185 val += 0x0A;
186 break;
187 case 'B':
188 case 'b':
189 val += 0x0B;
190 break;
191 case 'C':
192 case 'c':
193 val += 0x0C;
194 break;
195 case 'D':
196 case 'd':
197 val += 0x0D;
198 break;
199 case 'E':
200 case 'e':
201 val += 0x0E;
202 break;
203 case 'F':
204 case 'f':
205 val += 0x0F;
206 break;
207 default:
208 return '?';
209 break;
210 }
211 return val;
212}
213
214bool
216{
217 return true;
218}
219
221 const Data::PreallocateType&)
222 : mBuf(capacity > LocalAlloc
223 ? new char[capacity + 1]
224 : mPreBuffer),
225 mSize(0),
226 mCapacity(capacity > LocalAlloc
227 ? capacity
228 : LocalAlloc),
229 mShareEnum(capacity > LocalAlloc ? Take : Borrow)
230{
231 resip_assert( capacity >= 0 );
232 mBuf[mSize] = 0;
233}
234
235#ifdef DEPRECATED_PREALLOC
236// pre-allocate capacity
237Data::Data(size_type capacity, bool)
238 : mBuf(capacity > LocalAlloc
239 ? new char[capacity + 1]
240 : mPreBuffer),
241 mSize(0),
242 mCapacity(capacity > LocalAlloc
243 ? capacity
244 : LocalAlloc),
245 mShareEnum(capacity > LocalAlloc ? Take : Borrow)
246{
247 resip_assert( capacity >= 0 );
248 mBuf[mSize] = 0;
249}
250#endif
251
252Data::Data(const char* str, size_type length)
253{
254 initFromString(str, length);
255}
256
257Data::Data(const unsigned char* str, size_type length)
258{
259 initFromString((const char*)str, length);
260}
261
262// share memory KNOWN to be in a surrounding scope
263// wears off on, c_str, operator=, operator+=, non-const
264// operator[], append, reserve
265Data::Data(const char* str, size_type length, bool)
266 : mBuf(const_cast<char*>(str)),
267 mSize(length),
268 mCapacity(mSize),
269 mShareEnum(Share)
270{
271 resip_assert(str);
272}
273
274void
275Data::initFromString(const char* str, size_type len)
276{
277 mSize = len;
278 if(len > 0)
279 {
280 resip_assert(str);
281 }
282 size_t bytes = len + 1;
283 if(bytes <= len)
284 {
285 // integer overflow
286 throw std::bad_alloc();
287 }
288 if(bytes > LocalAlloc)
289 {
290 mBuf = new char[bytes];
291 mCapacity = mSize;
292 mShareEnum = Take;
293 }
294 else
295 {
296 mBuf = mPreBuffer;
297 mCapacity = LocalAlloc;
298 mShareEnum = Borrow;
299 }
300 if(str)
301 {
302 memcpy(mBuf, str, len);
303 }
304 mBuf[mSize] = 0;
305}
306
307Data::Data(ShareEnum se, const char* buffer, size_type length)
308 : mBuf(const_cast<char*>(buffer)),
309 mSize(length),
310 mCapacity(mSize),
311 mShareEnum(se)
312{
313 resip_assert(buffer);
314}
315
316Data::Data(ShareEnum se, const char* buffer, size_type length, size_type capacity)
317 : mBuf(const_cast<char*>(buffer)),
318 mSize(length),
319 mCapacity(capacity),
320 mShareEnum(se)
321{
322 resip_assert(buffer);
323}
324
325Data::Data(ShareEnum se, const char* buffer)
326 : mBuf(const_cast<char*>(buffer)),
327 mSize((Data::size_type)strlen(buffer)),
328 mCapacity(mSize),
329 mShareEnum(se)
330{
331 resip_assert(buffer);
332}
333
334Data::Data(ShareEnum se, const Data& staticData)
335 : mBuf(staticData.mBuf),
336 mSize(staticData.mSize),
337 mCapacity(mSize),
338 mShareEnum(Share)
339{
340 // !dlb! maybe:
341 // if you are trying to use Take, but make sure that you unset the mShareEnum on
342 // the staticData
343 resip_assert(se == Share); // makes no sense to call this with 'Take'.
344}
345//=============================================================================
346
347Data::Data(const char* str)
348{
349 initFromString(str, str ? (Data::size_type)strlen(str) : 0);
350}
351
352Data::Data(const string& str)
353{
354 initFromString(str.c_str(), (Data::size_type)str.size());
355}
356
357#if RESIP_HAVE_STRING_VIEW
361 Data::Data(const std::string_view sv)
362{
363 initFromString(sv.data(), (Data::size_type)sv.size());
364}
365#endif
366
367Data::Data(const Data& data)
368{
369 initFromString(data.mBuf, data.mSize);
370}
371
372Data::Data(Data &&data) noexcept
373 : mBuf(mPreBuffer),mSize(0),mCapacity(LocalAlloc),mShareEnum(Borrow)
374{
375 *this = std::move(data);
376}
377
378// -2147483646
379static const int Int32MaxSize = 11;
380
381// 18446744073709551615
382static const int UInt64MaxSize = 20;
383
385 : mBuf(Int32MaxSize > LocalAlloc
386 ? new char[Int32MaxSize + 1]
387 : mPreBuffer),
388 mSize(0),
389 mCapacity(Int32MaxSize > LocalAlloc
391 : LocalAlloc),
392 mShareEnum(Int32MaxSize > LocalAlloc ? Take : Borrow)
393{
394 if (val == 0)
395 {
396 mBuf[0] = '0';
397 mBuf[1] = 0;
398 mSize = 1;
399 return;
400 }
401
402 bool neg = false;
403
404 int32_t value = val;
405 if (value < 0)
406 {
407 value = -value;
408 neg = true;
409 }
410
411 int c = 0;
412 int32_t v = value;
413 while (v /= 10)
414 {
415 ++c;
416 }
417
418 if (neg)
419 {
420 ++c;
421 }
422
423 mSize = c+1;
424 mBuf[c+1] = 0;
425
426 v = value;
427 while (v)
428 {
429 mBuf[c--] = '0' + v%10;
430 v /= 10;
431 }
432
433 if (neg)
434 {
435 mBuf[0] = '-';
436 }
437}
438
439#ifndef RESIP_FIXED_POINT
441Data::Data(double value,
443 : mBuf(DoubleMaxSize + precision > LocalAlloc
444 ? new char[DoubleMaxSize + precision + 1]
445 : mPreBuffer),
446 mSize(0),
447 mCapacity(DoubleMaxSize + precision > LocalAlloc
448 ? DoubleMaxSize + precision
449 : LocalAlloc),
450 mShareEnum(DoubleMaxSize + precision > LocalAlloc ? Take : Borrow)
451{
452 resip_assert(precision >= 0);
453 resip_assert(precision < MaxDigitPrecision);
454
455 double v = value;
456 bool neg = (value < 0.0);
457
458 if (neg)
459 {
460 v = -v;
461 }
462
463 Data m((uint64_t)v);
464
465 // remainder
466 v = v - floor(v);
467
468 int p = precision;
469 while (p--)
470 {
471 v *= 10;
472 }
473
474 int dec = (int)floor(v+0.5);
475 Data d(precision, Data::Preallocate);
476
477 if (dec == 0)
478 {
479 d = "0";
480 }
481 else
482 {
483 d.mBuf[precision] = 0;
484 p = precision;
485 // neglect trailing zeros
486 bool significant = false;
487 while (p--)
488 {
489 if (dec % 10 || significant)
490 {
491 significant = true;
492 ++d.mSize;
493 d.mBuf[p] = '0' + (dec % 10);
494 }
495 else
496 {
497 d.mBuf[p] = 0;
498 }
499
500 dec /= 10;
501 }
502 }
503
504 if (neg)
505 {
506 mBuf[0] = '-';
507 memcpy(mBuf+1, m.mBuf, m.size());
508 mBuf[1+m.size()] = '.';
509 memcpy(mBuf+1+m.size()+1, d.mBuf, d.size()+1);
510 mSize = m.size() + d.size() + 2;
511 }
512 else
513 {
514 if (mCapacity < m.size() + d.size() + 1)
515 {
516 resize(m.size() + d.size() + 1, false);
517 }
518 memcpy(mBuf, m.mBuf, m.size());
519 mBuf[m.size()] = '.';
520 memcpy(mBuf+m.size()+1, d.mBuf, d.size()+1);
521 mSize = m.size() + d.size() + 1;
522 }
523
524 resip_assert(mBuf[mSize] == 0);
525}
526#endif
527
529 : mBuf(Int32MaxSize > LocalAlloc
530 ? new char[Int32MaxSize + 1]
531 : mPreBuffer),
532 mSize(0),
533 mCapacity(Int32MaxSize > LocalAlloc
535 : LocalAlloc),
536 mShareEnum(Int32MaxSize > LocalAlloc ? Take : Borrow)
537{
538 if (value == 0)
539 {
540 mBuf[0] = '0';
541 mBuf[1] = 0;
542 mSize = 1;
543 return;
544 }
545
546 int c = 0;
547 uint32_t v = value;
548 while (v /= 10)
549 {
550 ++c;
551 }
552
553 mSize = c+1;
554 mBuf[c+1] = 0;
555
556 v = value;
557 while (v)
558 {
559 unsigned int digit = v%10;
560 unsigned char d = (char)digit;
561 mBuf[c--] = '0' + d;
562 v /= 10;
563 }
564}
565
567 : mBuf(UInt64MaxSize > LocalAlloc
568 ? new char[UInt64MaxSize + 1]
569 : mPreBuffer),
570 mSize(0),
571 mCapacity(UInt64MaxSize > LocalAlloc
573 : LocalAlloc),
574 mShareEnum(UInt64MaxSize > LocalAlloc ? Take : Borrow)
575{
576 if (value == 0)
577 {
578 mBuf[0] = '0';
579 mBuf[1] = 0;
580 mSize = 1;
581 return;
582 }
583
584 int c = 0;
585 uint64_t v = value;
586 while (v /= 10)
587 {
588 ++c;
589 }
590
591 mSize = c+1;
592 mBuf[c+1] = 0;
593
594 v = value;
595 while (v)
596 {
597 uint64_t digit = v%10;
598 unsigned char d = (char)digit;
599 mBuf[c--] = '0' + d;
600 v /= 10;
601 }
602}
603
604static const int CharMaxSize = 1;
606 : mBuf(CharMaxSize > LocalAlloc
607 ? new char[CharMaxSize + 1]
608 : mPreBuffer),
609 mSize(1),
610 mCapacity(CharMaxSize > LocalAlloc
612 : LocalAlloc),
613 mShareEnum(CharMaxSize > LocalAlloc ? Take : Borrow)
614{
615 mBuf[0] = c;
616 mBuf[1] = 0;
617}
618
619Data::Data(bool value)
620 : mBuf(value ? const_cast<char*>("true") : const_cast<char*>("false")),
621 mSize(value ? 4 : 5),
622 mCapacity(value ? 4 : 5),
623 mShareEnum(Borrow)
624{}
625
626Data&
627Data::setBuf(ShareEnum se, const char* buffer, size_type length)
628{
629 resip_assert(buffer);
630 if (mShareEnum == Take)
631 {
632 delete[] mBuf;
633 }
634 mBuf = const_cast<char*>(buffer);
635 mCapacity = mSize = length;
636 mShareEnum = se;
637 return *this;
638}
639
640Data&
641Data::takeBuf(Data& other) noexcept
642{
643 if ( &other == this )
644 return *this;
645
646 if (mShareEnum == Data::Take)
647 delete[] mBuf;
648
649 if ( other.mBuf == other.mPreBuffer )
650 {
651 // plus one picks up the terminating safety NULL
652 memcpy( mPreBuffer, other.mPreBuffer, other.mSize+1);
653 mBuf = mPreBuffer;
654 }
655 else
656 {
657 mBuf = other.mBuf;
658 other.mBuf = other.mPreBuffer;
659 }
660 mSize = other.mSize;
661 mCapacity = other.mCapacity;
662 mShareEnum = other.mShareEnum;
663
664 // reset {other} to same state as the default Data() constructor
665 // note that other.mBuf is set above
666 other.mSize = 0;
667 other.mCapacity = LocalAlloc;
668 other.mShareEnum = Data::Borrow;
669 other.mPreBuffer[0] = 0;
670
671 return *this;
672}
673
674Data&
676{
677 if (&other == this)
678 return *this;
679
680 if (mShareEnum == Data::Take)
681 delete[] mBuf;
682
683 if (other.mBuf == other.mPreBuffer)
684 {
685 // plus one picks up the terminating safety NULL
686 memcpy(mPreBuffer, other.mPreBuffer, other.mSize + 1);
687 mBuf = mPreBuffer;
688 }
689 else
690 {
691 mBuf = other.mBuf;
692 }
693 mSize = other.mSize;
694 mCapacity = other.mCapacity;
695 mShareEnum = other.mShareEnum;
696
697 return *this;
698}
699
700Data&
701Data::copy(const char *buf, size_type length)
702{
703 if (mShareEnum == Data::Share || mCapacity < length+1)
704 {
705 // will alloc length+1, so the term NULL below is safe
706 resize(length, false);
707 }
708 // {buf} might be part of ourselves already, in which case {length}
709 // is smaller than our capacity, so resize above won't happen, so
710 // just memmove (not memcpy) and everything good
711 mSize = length;
712 if (mSize>0)
713 {
714 memmove(mBuf, buf, mSize);
715 }
716 // DONT do term NULL until after copy, because may be shifting contents
717 // down and don't want to put NULL in middle of it
718 mBuf[mSize] = 0;
719 return *this;
720}
721
722char*
724{
725 if (mShareEnum == Data::Share || mCapacity < length)
726 {
727 // will alloc length+1, so the term NULL below is safe
728 resize(length, false);
729 mBuf[length] = 0;
730 }
731 else if ( mCapacity != length )
732 {
733 mBuf[length] = 0;
734 }
735 // even if we don't NULL-term it, it may have NULL term from before.
736 // But if external buffer (taken or borrow'd) then don't know if it
737 // has a NULL or not.
738 mSize = length;
739 return mBuf;
740}
741
742bool
743resip::operator==(const Data& lhs, const Data& rhs)
744{
745 if (lhs.mSize != rhs.mSize)
746 {
747 return false;
748 }
749 return memcmp(lhs.mBuf, rhs.mBuf, lhs.mSize) == 0;
750}
751
752bool
753resip::operator==(const Data& lhs, const char* rhs)
754{
755 resip_assert(rhs); // .dlb. not consistent with constructor
756 if (strncmp(lhs.mBuf, rhs, lhs.mSize) != 0)
757 {
758 return false;
759 }
760 return strlen(rhs) == lhs.mSize;
761}
762
763bool
764resip::operator==(const Data& lhs, const std::string& rhs) noexcept
765{
766 return lhs.size() == rhs.size() && std::memcmp(lhs.data(), rhs.c_str(), rhs.size()) == 0;
767}
768
769#if RESIP_HAVE_STRING_VIEW
770bool
771resip::operator==(const Data& lhs, const std::string_view rhs) noexcept
772{
773 return lhs.size() == rhs.size() && std::memcmp(lhs.data(), rhs.data(), rhs.size()) == 0;
774}
775#endif
776
777bool
778resip::operator<(const Data& lhs, const Data& rhs)
779{
780 int res = memcmp(lhs.mBuf, rhs.mBuf, resipMin(lhs.mSize, rhs.mSize));
781
782 if (res < 0)
783 {
784 return true;
785 }
786 else if (res > 0)
787 {
788 return false;
789 }
790 else
791 {
792 return (lhs.mSize < rhs.mSize);
793 }
794}
795
796bool
797resip::operator<(const Data& lhs, const char* rhs)
798{
799 resip_assert(rhs);
800 Data::size_type l = (Data::size_type)strlen(rhs);
801 int res = memcmp(lhs.mBuf, rhs, resipMin(lhs.mSize, l));
802
803 if (res < 0)
804 {
805 return true;
806 }
807 else if (res > 0)
808 {
809 return false;
810 }
811 else
812 {
813 return (lhs.mSize < l);
814 }
815}
816
817bool
818resip::operator<(const char* lhs, const Data& rhs)
819{
820 resip_assert(lhs);
821 Data::size_type l = (Data::size_type)strlen(lhs);
822 int res = memcmp(lhs, rhs.mBuf, resipMin(l, rhs.mSize));
823
824 if (res < 0)
825 {
826 return true;
827 }
828 else if (res > 0)
829 {
830 return false;
831 }
832 else
833 {
834 return (l < rhs.mSize);
835 }
836}
837
838bool
839resip::operator<(const Data& lhs, const std::string& rhs) noexcept
840{
841 const Data::size_type l = rhs.size();
842 if (lhs.mSize != l)
843 {
844 return lhs.mSize < l;
845 }
846 return memcmp(lhs.mBuf, rhs.c_str(), lhs.mSize) < 0;
847}
848
849bool
850resip::operator<(const std::string& lhs, const Data& rhs) noexcept
851{
852 const Data::size_type lhsSize = lhs.size();
853 if (lhsSize != rhs.mSize)
854 {
855 return lhsSize < rhs.mSize;
856 }
857 return memcmp(lhs.c_str(), rhs.mBuf, lhsSize) < 0;
858}
859
860#if RESIP_HAVE_STRING_VIEW
861bool
862resip::operator<(const Data& lhs, const std::string_view rhs) noexcept
863{
864 const Data::size_type rhsSize = rhs.size();
865 if (lhs.mSize != rhsSize)
866 {
867 return lhs.mSize < rhsSize;
868 }
869 return memcmp(lhs.mBuf, rhs.data(), lhs.mSize) < 0;
870}
871
872bool
873resip::operator<(const std::string_view lhs, const Data& rhs) noexcept
874{
875 const Data::size_type lhsSize = lhs.size();
876 if (lhsSize != rhs.mSize)
877 {
878 return lhsSize < rhs.mSize;
879 }
880 return memcmp(lhs.data(), rhs.mBuf, lhsSize) < 0;
881}
882#endif
883
884
885#if 0
886// Moved to inline header as special case of copy()
887Data&
888Data::operator=(const Data& data)
889{
890 resip_assert(mBuf);
891
892 if (&data != this)
893 {
894 if (mShareEnum == Share)
895 {
896 resize(data.mSize, false);
897 }
898 else
899 {
900 if (data.mSize > mCapacity)
901 {
902 resize(data.mSize, false);
903 }
904 }
905
906 mSize = data.mSize;
907 // could overlap!
908 if (mSize > 0)
909 {
910 memmove(mBuf, data.mBuf, mSize);
911 }
912 mBuf[mSize] = 0;
913 }
914 return *this;
915}
916#endif
917
918Data& Data::operator=(Data &&data) noexcept
919{
920 // Delegate to takeBuf(), which releases any buffer currently owned by *this,
921 // steals data's buffer (or copies when data uses its local buffer), and
922 // leaves data in a valid empty state. The earlier hand-rolled implementation
923 // leaked *this's heap buffer and left data aliasing the stolen buffer.
924 return takeBuf(data);
925}
926
929{
930 if (len < mSize)
931 {
932 (*this)[len] = 0;
933 mSize = len;
934 }
935
936 return mSize;
937}
938
939Data&
941{
942 if (len < mSize)
943 {
944 // NOTE: Do not write terminating NULL, to avoid un-doing Share
945 mSize = len;
946 }
947 return *this;
948}
949
950Data
951Data::operator+(const Data& data) const
952{
953 Data tmp(mSize + (int)data.mSize, Data::Preallocate);
954 tmp.mSize = mSize + data.mSize;
955 tmp.mCapacity = tmp.mSize;
956 memcpy(tmp.mBuf, mBuf, mSize);
957 memcpy(tmp.mBuf + mSize, data.mBuf, data.mSize);
958 tmp.mBuf[tmp.mSize] = 0;
959
960 return tmp;
961}
962
963Data&
965{
966 if (mCapacity < rhs.mSize)
967 {
968 resize(rhs.mSize, true);
969 }
970 if (mSize < rhs.mSize)
971 {
972 memset(mBuf+mSize, 0, mCapacity - mSize);
973 }
974
975 char* c1 = mBuf;
976 char* c2 = rhs.mBuf;
977 char* end = c2 + rhs.mSize;
978 while (c2 != end)
979 {
980 *c1++ ^= *c2++;
981 }
982 mSize = resipMax(mSize, rhs.mSize);
983
984 return *this;
985}
986
987char&
989{
990 if (p >= mCapacity)
991 {
992 resize(p+1, true);
993 }
994 else
995 {
996 own();
997 if (p > mSize)
998 {
999 mSize = p + 1;
1000 mBuf[mSize] = 0;
1001 }
1002 }
1003 return mBuf[p];
1004}
1005
1006#if 0
1007// Moved to inline header as special case of copy()
1008Data&
1009Data::operator=(const char* str)
1010{
1011 resip_assert(str);
1012 size_type l = strlen(str);
1013
1014 if (mShareEnum == Share)
1015 {
1016 resize(l, false);
1017 }
1018 else
1019 {
1020 if (l > mCapacity)
1021 {
1022 resize(l, false);
1023 }
1024 }
1025
1026 mSize = l;
1027 // could conceivably overlap
1028 memmove(mBuf, str, mSize+1);
1029
1030 return *this;
1031}
1032#endif
1033
1034Data
1035Data::operator+(const char* str) const
1036{
1037 resip_assert(str);
1038 Data::size_type l = (Data::size_type)strlen(str);
1039 Data tmp(mSize + l, Data::Preallocate);
1040 tmp.mSize = mSize + l;
1041 tmp.mCapacity = tmp.mSize;
1042 memcpy(tmp.mBuf, mBuf, mSize);
1043 memcpy(tmp.mBuf + mSize, str, l+1);
1044
1045 return tmp;
1046}
1047
1048void
1050{
1051 if (len > mCapacity)
1052 {
1053 resize(len, true);
1054 }
1055}
1056
1057Data&
1058Data::append(const char* str, size_type len)
1059{
1060 resip_assert(str);
1061 if (mCapacity <= mSize + len) // append null terminates, thus the equality
1062 {
1063 // .dlb. pad for future growth?
1064 resize(((mSize + len +16)*3)/2, true);
1065 }
1066 else
1067 {
1068 if (mShareEnum == Share)
1069 {
1070 resize(mSize + len, true);
1071 }
1072 }
1073
1074 // could conceivably overlap
1075 memmove(mBuf + mSize, str, len);
1076 mSize += len;
1077 mBuf[mSize] = 0;
1078
1079 return *this;
1080}
1081
1082
1083Data
1084Data::operator+(char c) const
1085{
1086 Data tmp(mSize + 1, Data::Preallocate);
1087 tmp.mSize = mSize + 1;
1088 tmp.mCapacity = tmp.mSize;
1089 memcpy(tmp.mBuf, mBuf, mSize);
1090 tmp.mBuf[mSize] = c;
1091 tmp.mBuf[mSize+1] = 0;
1092
1093 return tmp;
1094}
1095
1096const char*
1098{
1099 if (mShareEnum == Data::Share || mSize == mCapacity)
1100 {
1101 const_cast<Data*>(this)->resize(mSize+1,true);
1102 }
1103 // mostly is zero terminated, but not by DataStream
1104 mBuf[mSize] = 0;
1105 return mBuf;
1106}
1107
1108std::string
1110{
1111 return std::string(c_str(), size());
1112}
1113
1114#if RESIP_HAVE_STRING_VIEW
1115std::string_view
1116Data::toStringView() const
1117{
1118 return std::string_view(c_str(), size());
1119}
1120#endif
1121
1122void
1123Data::own() const
1124{
1125 if (mShareEnum == Share)
1126 {
1127 const_cast<Data*>(this)->resize(mSize, true);
1128 }
1129}
1130
1131// generate additional capacity
1132void
1133Data::resize(size_type newCapacity,
1134 bool copy)
1135{
1136 resip_assert(newCapacity >= mCapacity || mShareEnum == Data::Share);
1137
1138 char *oldBuf = mBuf;
1139 bool needToDelete=(mShareEnum==Take);
1140
1141 size_t newBytes = newCapacity + 1;
1142 if(newBytes <= newCapacity)
1143 {
1144 // integer overflow
1145 throw std::range_error("newCapacity too big");
1146 }
1147
1148 if(newCapacity > LocalAlloc)
1149 {
1150 mBuf = new char[newBytes];
1151 mShareEnum = Take;
1152 }
1153 else
1154 {
1155 mBuf = mPreBuffer;
1156 mShareEnum = Borrow;
1157 }
1158
1159 if (copy)
1160 {
1161 memcpy(mBuf, oldBuf, mSize);
1162 mBuf[mSize] = 0;
1163 }
1164
1165 if (needToDelete)
1166 {
1167 delete[] oldBuf;
1168 }
1169
1170 mCapacity = newCapacity;
1171}
1172
1173Data
1175{
1176 MD5Context context;
1177 MD5Init(&context);
1178 MD5Update(&context, reinterpret_cast < unsigned const char* > (mBuf), (unsigned int)mSize);
1179
1180 unsigned char digestBuf[16];
1181 MD5Final(digestBuf, &context);
1182 Data digest(digestBuf,16);
1183
1184 switch(type)
1185 {
1186 case BINARY:
1187 return digest;
1188 case BASE64:
1189 return digest.base64encode(true);
1190 case HEX:
1191 default:
1192 return digest.hex();
1193 }
1194 resip_assert(0);
1195 return digest.hex();
1196}
1197
1198Data
1200{
1201 Data ret((int)((size()*11)/10), Data::Preallocate);
1202
1203 const char* p = data();
1204 for (size_type i=0; i < size(); ++i)
1205 {
1206 unsigned char c = *p++;
1207
1208 if ( c == 0x0d )
1209 {
1210 if ( i+1 < size() )
1211 {
1212 if ( *p == 0x0a )
1213 {
1214 // found a CRLF sequence
1215 ret += c;
1216 c = *p++; i++;
1217 ret += c;
1218 continue;
1219 }
1220 }
1221 }
1222
1223 if ( !isprint(c) )
1224 {
1225 ret +='%';
1226
1227 int hi = (c & 0xF0)>>4;
1228 int low = (c & 0x0F);
1229
1230 ret += hexmap[hi];
1231 ret += hexmap[low];
1232 }
1233 else
1234 {
1235 ret += c;
1236 }
1237 }
1238
1239 return ret;
1240}
1241
1242Data
1244{
1245 Data ret((int)((size()*11)/10), Data::Preallocate);
1246
1247 const char* p = data();
1248 for (size_type i=0; i < size(); ++i)
1249 {
1250 unsigned char c = *p++;
1251
1252 if ( c == 0x0d )
1253 {
1254 if ( i+1 < size() )
1255 {
1256 if ( *p == 0x0a )
1257 {
1258 // found a CRLF sequence
1259 ret += c;
1260 c = *p++; i++;
1261 ret += c;
1262 continue;
1263 }
1264 }
1265 }
1266
1267 if ( !isprint(c) ||
1268 // rfc 3261 reserved + mark + space + tab
1269 strchr(" \";/?:@&=+%$,\t-_.!~*'()", c))
1270 {
1271 ret +='%';
1272
1273 int hi = (c & 0xF0)>>4;
1274 int low = (c & 0x0F);
1275
1276 ret += hexmap[hi];
1277 ret += hexmap[low];
1278 }
1279 else
1280 {
1281 ret += c;
1282 }
1283 }
1284
1285 return ret;
1286}
1287
1288Data
1290{
1291 Data ret(size(), Data::Preallocate);
1292
1293 const char* p = data();
1294 for (size_type i = 0; i < size(); ++i)
1295 {
1296 unsigned char c = *p++;
1297 if (c == '%')
1298 {
1299 if ( i+2 < size())
1300 {
1301 const char* high = strchr(hexmap, tolower(static_cast< unsigned char >(*p++)));
1302 const char* low = strchr(hexmap, tolower(static_cast< unsigned char >(*p++)));
1303
1304 // !rwm! changed from high==0 || low==0
1305 if (high == 0 && low == 0)
1306 {
1307 resip_assert(0);
1308 // ugh
1309 return ret;
1310 }
1311
1312 int highInt = int(high - hexmap);
1313 int lowInt = int(low - hexmap);
1314 ret += char(highInt<<4 | lowInt);
1315 i += 2;
1316 }
1317 else
1318 {
1319 break;
1320 }
1321 }
1322 else
1323 {
1324 ret += c;
1325 }
1326 }
1327 return ret;
1328}
1329
1330Data
1332{
1333 Data buffer;
1334 DataStream strm(buffer);
1335 urlEncode(strm);
1336 strm.flush();
1337 return buffer;
1338}
1339
1340Data
1342{
1343 Data buffer;
1344 DataStream strm(buffer);
1345 urlDecode(strm);
1346 strm.flush();
1347 return buffer;
1348}
1349
1351Data::urlDecode(EncodeStream& s) const
1352{
1353 unsigned int i = 0;
1354 for (const char* p = data(); p != data()+size(); ++p, ++i)
1355 {
1356 unsigned char c = *p;
1357 if (c == '%')
1358 {
1359 if (i+2 < size())
1360 {
1361 s << (char) hexpair2int( *(p+1), *(p+2));
1362 p += 2;
1363 }
1364 else
1365 {
1366 break;
1367 }
1368 }
1369 else if (c == '+')
1370 {
1371 s << ' ';
1372 }
1373 else
1374 {
1375 s << c;
1376 }
1377 }
1378 return s;
1379}
1380
1381bool urlNonEncodedChars[256] = {false};
1382bool
1384{
1385 // query part of HTTP URL can be a pchar, slash, or question
1386 // pchar is unreserved, subdelims, colon, at-sign
1387
1388 for (int i = 0; i < 256; ++i)
1389 {
1390 unsigned char c(i);
1391 urlNonEncodedChars[c] = (isalpha(c) || // unreserved
1392 isdigit(c) || // unreserved
1393 c == '-' || // these first 4 are unreserved
1394 c == '_' ||
1395 c == '.' ||
1396 c == '~' ||
1397 c == '!' || // these are subdelims (allowed in pchars)
1398 c == '$' ||
1399// c == '&' || // while these are allowed subdelims, this is an error
1400// c == '+' || // I believe this is an error as well.
1401 c == '\'' ||
1402 c == '(' ||
1403 c == ')' ||
1404 c == '*' ||
1405 c == ',' ||
1406 c == ';' ||
1407 c == '=' ||
1408 c == ':' || // next two explicitly allowed in pchar
1409 c == '@' ||
1410 c == '/' || // next two explicitly allowed in query in addition to pchar
1411 c == '?');
1412 }
1413
1414 return false;
1415}
1416
1418
1419// e.g. http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
1421Data::urlEncode(EncodeStream& s) const
1422{
1423 for (const char* p = data(); p != data() + size(); ++p)
1424 {
1425 unsigned char c = *p;
1426
1427 // pchar, slash, questionmark
1428 // pchar = unreserved, sub-delims, colon, at-sign
1429 // unreserved = alphanum, hyphen, underscore, period, tilde
1430 // subdelims = bang (!), dollar, ampersand (oops!), plus, single-quote, lparen, rparen, asterisk, comma, semicolon, equal
1431 //if (isalpha(c) || isdigit(c) || strchr("-_.~!$+'()*,;=:@/?", c)) //
1432 // strchr is inefficient and wrong
1433 if (urlNonEncodedChars[c])
1434 {
1435 s << c;
1436 }
1437 else
1438 {
1439 if (c == 0x20)
1440 {
1441 s << '+';
1442 }
1443 else
1444 {
1445 s << '%' << (hexmap[(c & 0xF0)>>4]) << (hexmap[(c & 0x0F)]);
1446 }
1447 }
1448 }
1449
1450 return s;
1451}
1452
1453Data
1455{
1456 Data buffer;
1457 DataStream strm(buffer);
1458 xmlCharDataEncode(strm);
1459 strm.flush();
1460 return buffer;
1461}
1462
1463Data
1465{
1466 Data buffer;
1467 DataStream strm(buffer);
1468 xmlCharDataDecode(strm);
1469 strm.flush();
1470 return buffer;
1471}
1472
1473// http://www.w3.org/TR/REC-xml/#syntax
1475Data::xmlCharDataEncode(EncodeStream& s) const
1476{
1477 for (const char* p = data(); p != data() + size(); ++p)
1478 {
1479 unsigned char c = *p;
1480
1481 switch(c)
1482 {
1483 case '&':
1484 s << "&amp;";
1485 break;
1486 case '<':
1487 s << "&lt;";
1488 break;
1489 case '>':
1490 s << "&gt;";
1491 break;
1492 case '\'':
1493 s << "&apos;";
1494 break;
1495 case '\"':
1496 s << "&quot;";
1497 break;
1498 default:
1499 s << c;
1500 }
1501 }
1502
1503 return s;
1504}
1505
1507Data::xmlCharDataDecode(EncodeStream& s) const
1508{
1509 unsigned int i = 0;
1510 for (const char* p = data(); p != data()+size(); ++p, ++i)
1511 {
1512 unsigned char c = *p;
1513 if (c == '&')
1514 {
1515 // look for amp;
1516 if(i+4 < size() &&
1517 *(p+1) == 'a' && *(p+2) == 'm' && *(p+3) == 'p' && *(p+4) == ';')
1518 {
1519 s << '&';
1520 p += 4;
1521 }
1522 // look for lt;
1523 else if(i+3 < size() &&
1524 *(p+1) == 'l' && *(p+2) == 't' && *(p+3) == ';')
1525 {
1526 s << '<';
1527 p += 3;
1528 }
1529 // look for gt;
1530 else if(i+3 < size() &&
1531 *(p+1) == 'g' && *(p+2) == 't' && *(p+3) == ';')
1532 {
1533 s << '>';
1534 p += 3;
1535 }
1536 // look for apos;
1537 else if(i+5 < size() &&
1538 *(p+1) == 'a' && *(p+2) == 'p' && *(p+3) == 'o' && *(p+4) == 's' && *(p+5) == ';')
1539 {
1540 s << '\'';
1541 p += 5;
1542 }
1543 // look for quot;
1544 else if(i+5 < size() &&
1545 *(p+1) == 'q' && *(p+2) == 'u' && *(p+3) == 'o' && *(p+4) == 't' && *(p+5) == ';')
1546 {
1547 s << '\"';
1548 p += 5;
1549 }
1550 else // if no conversion found - just leave characters in data
1551 {
1552 s << c;
1553 }
1554 }
1555 else
1556 {
1557 s << c;
1558 }
1559 }
1560 return s;
1561}
1562
1563Data
1565{
1566 if (size() <= s)
1567 {
1568 return *this;
1569 }
1570 else
1571 {
1572 return Data(data(), s) + "..";
1573 }
1574}
1575
1576Data
1578{
1579 Data ret( 2*mSize, Data::Preallocate);
1580
1581 const char* p = mBuf;
1582 char* r = ret.mBuf;
1583 for (size_type i=0; i < mSize; ++i)
1584 {
1585 unsigned char temp = *p++;
1586
1587 int hi = (temp & 0xf0)>>4;
1588 int low = (temp & 0xf);
1589
1590 *r++ = hexmap[hi];
1591 *r++ = hexmap[low];
1592 }
1593 *r = 0;
1594 ret.mSize = 2*mSize;
1595 return ret;
1596}
1597
1598Data
1600{
1601 bool oddSize = mSize & 1;
1602 size_type resultSize = (mSize + (mSize & 1)) / 2;
1603 Data ret(resultSize, Data::Preallocate);
1604
1605 const unsigned char* p = (unsigned char*)mBuf;
1606 char* r = ret.mBuf;
1607 size_type i = 0;
1608 if(oddSize)
1609 {
1610 if(!isHex(*p))
1611 {
1612 throw DataException("Encountered non-hex digit",
1613 __FILE__,__LINE__);
1614 }
1615 *r++ = inversehexmap[*p++];
1616 i++;
1617 }
1618 for ( ; i < mSize; i+=2)
1619 {
1620 const unsigned char high = *p++;
1621 const unsigned char low = *p++;
1622 if(!isHex(high) || !isHex(low))
1623 {
1624 throw DataException("Encountered non-hex digit",
1625 __FILE__,__LINE__);
1626 }
1627
1628 *r++ = (inversehexmap[high] << 4) + inversehexmap[low];
1629 }
1630 ret.mSize = resultSize;
1631 return ret;
1632}
1633
1634Data&
1636{
1637 own();
1638 char* p = mBuf;
1639 for (size_type i=0; i < mSize; ++i)
1640 {
1641 *p = tolower(static_cast< unsigned char >(*p));
1642 ++p;
1643 }
1644 return *this;
1645}
1646
1647Data&
1649{
1650 own();
1651 char* p = mBuf;
1652 for (size_type i=0; i < mSize; ++i)
1653 {
1654 *p = toupper(static_cast< unsigned char >(*p));
1655 ++p;
1656 }
1657 return *this;
1658}
1659
1660Data&
1662{
1663 own();
1664 char* p = mBuf;
1665 for (size_type i=0; i < mSize; ++i)
1666 {
1667 *p |= ' ';
1668 ++p;
1669 }
1670 return *this;
1671}
1672
1673#if 0
1674// in-lined into header as special case of truncate2()
1675Data&
1677{
1678 mSize = 0;
1679 return *this;
1680}
1681#endif
1682
1683int
1685{
1686 int val = 0;
1687 char* p = mBuf;
1688 const char* const end = mBuf + mSize;
1689 int s = 1;
1690
1691 for (; p != end; ++p)
1692 {
1693 if (!isspace(static_cast< unsigned char >(*p)))
1694 {
1695 goto sign_char;
1696 }
1697 }
1698 return val;
1699sign_char:
1700
1701 if (*p == '-')
1702 {
1703 s = -1;
1704 ++p;
1705 }
1706 else if (*p == '+')
1707 {
1708 ++p;
1709 }
1710
1711 for(; p != end; ++p)
1712 {
1713 if (!isdigit(static_cast< unsigned char >(*p)))
1714 {
1715 break;
1716 }
1717 val *= 10;
1718 val += (*p) - '0';
1719 }
1720 return s*val;
1721}
1722
1723unsigned long
1725{
1726 unsigned long val = 0;
1727 char* p = mBuf;
1728 const char* const end = mBuf + mSize;
1729
1730 for (; p != end; ++p)
1731 {
1732 if (!isspace(static_cast< unsigned char >(*p)))
1733 {
1734 goto sign_char;
1735 }
1736 }
1737 return val;
1738sign_char:
1739
1740 if (*p == '+')
1741 {
1742 ++p;
1743 }
1744
1745 for(; p != end; ++p)
1746 {
1747 if (!isdigit(static_cast< unsigned char >(*p)))
1748 {
1749 break;
1750 }
1751 val *= 10;
1752 val += (*p) - '0';
1753 }
1754 return val;
1755}
1756
1759{
1760 uint64_t val = 0;
1761 char* p = mBuf;
1762 const char* const end = mBuf + mSize;
1763
1764 for (; p != end; ++p)
1765 {
1766 if (!isspace(static_cast< unsigned char >(*p)))
1767 {
1768 goto sign_char;
1769 }
1770 }
1771 return val;
1772sign_char:
1773
1774 if (*p == '+')
1775 {
1776 ++p;
1777 }
1778
1779 for(; p != end; ++p)
1780 {
1781 if (!isdigit(static_cast< unsigned char >(*p)))
1782 {
1783 break;
1784 }
1785 val *= 10;
1786 val += (*p) - '0';
1787 }
1788 return val;
1789}
1790
1791size_t
1793{
1794 size_t val = 0;
1795 char* p = mBuf;
1796 const char* const end = mBuf + mSize;
1797
1798 for (; p != end; ++p)
1799 {
1800 if (!isspace(static_cast< unsigned char >(*p)))
1801 {
1802 goto sign_char;
1803 }
1804 }
1805 return val;
1806sign_char:
1807
1808 if (*p == '+')
1809 {
1810 ++p;
1811 }
1812
1813 for(; p != end; ++p)
1814 {
1815 if (!isdigit(static_cast< unsigned char >(*p)))
1816 {
1817 break;
1818 }
1819 val *= 10;
1820 val += (*p) - '0';
1821 }
1822 return val;
1823}
1824
1825#ifndef RESIP_FIXED_POINT
1826double
1828{
1829 long val = 0;
1830 char* p = mBuf;
1831 const char* const end = p + mSize;
1832 int s = 1;
1833
1834 for (; p != end; ++p)
1835 {
1836 if (!isspace(static_cast< unsigned char >(*p)))
1837 {
1838 goto sign_char;
1839 }
1840 }
1841 return val;
1842sign_char:
1843
1844 if (*p == '-')
1845 {
1846 s = -1;
1847 ++p;
1848 }
1849 else if (*p == '+')
1850 {
1851 ++p;
1852 }
1853
1854 for(; p != end; ++p)
1855 {
1856 if (*p == '.')
1857 {
1858 goto decimals;
1859 }
1860 if (!isdigit(static_cast< unsigned char >(*p)))
1861 {
1862 return s*val;
1863 }
1864 val *= 10;
1865 val += (*p) - '0';
1866 }
1867 return s*val;
1868
1869decimals:
1870 ++p;
1871 long d = 0;
1872 double div = 1.0;
1873 for(; p != end; ++p)
1874 {
1875 if (!isdigit(static_cast< unsigned char >(*p)))
1876 {
1877 break;
1878 }
1879 d *= 10;
1880 d += *p - '0';
1881 div *= 10;
1882 }
1883 return s*(val + d/div);
1884}
1885#endif
1886
1887bool
1888Data::prefix(const Data& pre) const noexcept
1889{
1890 if (pre.size() > size())
1891 {
1892 return false;
1893 }
1894
1895 return memcmp(data(), pre.data(), pre.size()) == 0;
1896}
1897
1898bool
1899Data::prefixNoCase(const Data& pre) const noexcept
1900{
1901 if (pre.size() > size())
1902 {
1903 return false;
1904 }
1905
1906 return strncasecmp(data(), pre.data(), pre.size()) == 0;
1907}
1908
1909bool
1910Data::postfix(const Data& post) const noexcept
1911{
1912 if (post.size() > size())
1913 {
1914 return false;
1915 }
1916
1917 return memcmp(data() + (size()-post.size()), post.data(), post.size()) == 0;
1918}
1919
1920bool
1921Data::postfixNoCase(const Data& post) const noexcept
1922{
1923 if (post.size() > size())
1924 {
1925 return false;
1926 }
1927
1928 return strncasecmp(data() + (size() - post.size()), post.data(), post.size()) == 0;
1929}
1930
1931Data
1933{
1934 resip_assert(first <= mSize);
1935 if ( count == Data::npos)
1936 {
1937 return Data(mBuf+first, mSize-first);
1938 }
1939 else
1940 {
1941 resip_assert(first + count <= mSize);
1942 return Data(mBuf+first, count);
1943 }
1944}
1945
1947Data::find(const Data& match,
1948 size_type start) const
1949{
1950 if (start < mSize)
1951 {
1952 ParseBuffer pb(mBuf + start, mSize - start);
1953 pb.skipToChars(match);
1954 if (!pb.eof())
1955 {
1956 return (Data::size_type)(pb.position() - pb.start() + start);
1957 }
1958 }
1959
1960 return Data::npos;
1961}
1962
1963int
1964Data::replace(const Data& match,
1965 const Data& replaceWith,
1966 int max)
1967{
1968 resip_assert(!match.empty());
1969
1970 int count = 0;
1971
1972 const int incr = int(replaceWith.size() - match.size());
1973 for (size_type offset = find(match, 0);
1974 count < max && offset != Data::npos;
1975 offset = find(match, offset+replaceWith.size()))
1976 {
1977 if (mSize + incr >= mCapacity)
1978 {
1979 resize((mCapacity + incr) * 3 / 2, true);
1980 }
1981 else
1982 {
1983 own();
1984 }
1985
1986 // move the memory forward (or backward)
1987 memmove(mBuf + offset + replaceWith.size(), mBuf + offset + match.size(), mSize - offset - match.size());
1988 memcpy(mBuf + offset, replaceWith.data(), replaceWith.size());
1989 mSize += incr;
1990
1991 ++count;
1992 }
1993
1994 return count;
1995}
1996
1997#ifndef RESIP_USE_STL_STREAMS
1999resip::operator<<(EncodeStream& strm, const Data& d)
2000{
2001 return strm.write(d.mBuf, d.mSize);
2002}
2003#endif
2004
2005// random permutation of 0..255
2006static const unsigned char randomPermutation[256] =
2007{
2008 44, 9, 46, 184, 21, 30, 92, 231, 79, 7, 166, 237, 173, 72, 91, 123,
2009 212, 183, 16, 99, 85, 45, 190, 130, 118, 107, 169, 119, 100, 179, 251, 177,
2010 23, 125, 12, 101, 121, 246, 61, 38, 156, 114, 159, 57, 181, 145, 198, 182,
2011 58, 215, 174, 225, 82, 178, 150, 161, 63, 103, 32, 203, 68, 151, 139, 55,
2012 143, 2, 36, 110, 209, 154, 204, 89, 62, 17, 187, 226, 31, 105, 195, 208,
2013 49, 56, 238, 172, 37, 3, 234, 206, 134, 233, 19, 148, 64, 4, 10, 224,
2014 144, 88, 93, 191, 20, 131, 138, 199, 243, 244, 39, 50, 214, 87, 6, 84,
2015 185, 112, 171, 75, 192, 193, 239, 69, 106, 43, 194, 1, 78, 67, 116, 200,
2016 83, 70, 213, 25, 59, 137, 52, 13, 153, 42, 232, 0, 133, 210, 76, 33,
2017 255, 236, 124, 104, 65, 201, 53, 155, 140, 254, 54, 196, 120, 146, 216, 29,
2018 28, 86, 245, 90, 98, 26, 81, 115, 180, 66, 102, 136, 167, 51, 109, 132,
2019 77, 175, 14, 202, 222, 48, 223, 188, 40, 242, 157, 5, 128, 229, 71, 127,
2020 164, 207, 247, 8, 80, 149, 94, 160, 47, 117, 135, 176, 129, 142, 189, 97,
2021 11, 250, 221, 218, 96, 220, 35, 197, 152, 126, 219, 74, 170, 252, 163, 41,
2022 95, 27, 34, 22, 205, 230, 241, 186, 168, 228, 253, 249, 113, 108, 111, 211,
2023 235, 217, 165, 122, 15, 141, 158, 147, 240, 24, 162, 18, 60, 73, 227, 248
2024};
2025
2026size_t
2027Data::rawHash(const unsigned char* c, size_t size)
2028{
2029 // 4 byte Pearson's hash
2030 // essentially random hashing
2031
2032 union
2033 {
2034 size_t st;
2035 unsigned char bytes[4];
2036 };
2037 st = 0; // suppresses warnings about unused st
2038 bytes[0] = randomPermutation[0];
2039 bytes[1] = randomPermutation[1];
2040 bytes[2] = randomPermutation[2];
2041 bytes[3] = randomPermutation[3];
2042
2043 const unsigned char* end = c + size;
2044 for ( ; c != end; ++c)
2045 {
2046 bytes[0] = randomPermutation[*c ^ bytes[0]];
2047 bytes[1] = randomPermutation[*c ^ bytes[1]];
2048 bytes[2] = randomPermutation[*c ^ bytes[2]];
2049 bytes[3] = randomPermutation[*c ^ bytes[3]];
2050 }
2051
2052 // convert from network to host byte order
2053 return ntohl((u_long)st);
2054}
2055
2056// use only for ascii characters!
2057size_t
2058Data::rawCaseInsensitiveHash(const unsigned char* c, size_t size)
2059{
2060
2061 union
2062 {
2063 size_t st;
2064 unsigned char bytes[4];
2065 };
2066 st = 0; // suppresses warnings about unused st
2067 bytes[0] = randomPermutation[0];
2068 bytes[1] = randomPermutation[1];
2069 bytes[2] = randomPermutation[2];
2070 bytes[3] = randomPermutation[3];
2071
2072 const unsigned char* end = c + size;
2073 for ( ; c != end; ++c)
2074 {
2075 unsigned char cc = tolower(*c);
2076 bytes[0] = randomPermutation[cc ^ bytes[0]];
2077 bytes[1] = randomPermutation[cc ^ bytes[1]];
2078 bytes[2] = randomPermutation[cc ^ bytes[2]];
2079 bytes[3] = randomPermutation[cc ^ bytes[3]];
2080 }
2081
2082 // convert from network to host byte order
2083 return ntohl((u_long)st);
2084}
2085
2086// SipHash-1-3 (Aumasson and Bernstein), the keyed hash Python and Rust use for
2087// their hash tables. The key is chosen randomly once per process, so remote
2088// peers cannot precompute keys that collide (hash flooding). See KeyedDataHash
2089// in Data.hxx for why containers keyed by network data need this.
2090namespace
2091{
2092
2093struct SipHashKey
2094{
2095 uint64_t k0;
2096 uint64_t k1;
2097};
2098
2099const SipHashKey&
2100sipHashKey()
2101{
2102 static const SipHashKey key = []()
2103 {
2104 // Mix in the clock and an address as well, in case random_device is weak
2105 // or unavailable on this platform.
2106 uint64_t seed[4] = { (uint64_t)std::chrono::high_resolution_clock::now().time_since_epoch().count(),
2107 (uint64_t)(uintptr_t)&seed,
2108 0, 0 };
2109 try
2110 {
2111 std::random_device rd;
2112 for (uint64_t& s : seed)
2113 {
2114 s ^= ((uint64_t)rd() << 32) ^ rd();
2115 }
2116 }
2117 catch (const std::exception&)
2118 {
2119 }
2120 SipHashKey k = { seed[0] ^ seed[2], seed[1] ^ seed[3] };
2121 return k;
2122 }();
2123 return key;
2124}
2125
2126inline uint64_t
2127rotl64(uint64_t x, int b)
2128{
2129 return (x << b) | (x >> (64 - b));
2130}
2131
2132inline void
2133sipRound(uint64_t& v0, uint64_t& v1, uint64_t& v2, uint64_t& v3)
2134{
2135 v0 += v1; v1 = rotl64(v1, 13); v1 ^= v0; v0 = rotl64(v0, 32);
2136 v2 += v3; v3 = rotl64(v3, 16); v3 ^= v2;
2137 v0 += v3; v3 = rotl64(v3, 21); v3 ^= v0;
2138 v2 += v1; v1 = rotl64(v1, 17); v1 ^= v2; v2 = rotl64(v2, 32);
2139}
2140
2141template <bool NoCase>
2142inline uint64_t
2143sipByte(unsigned char c)
2144{
2145 // ASCII-only folding, to agree with strncasecmp in the C locale
2146 if (NoCase && (unsigned char)(c - 'A') < 26)
2147 {
2148 c |= 0x20;
2149 }
2150 return c;
2151}
2152
2153template <bool NoCase>
2154size_t
2155sipHash13(const unsigned char* c, size_t size)
2156{
2157 const SipHashKey& key = sipHashKey();
2158 uint64_t v0 = 0x736f6d6570736575ULL ^ key.k0;
2159 uint64_t v1 = 0x646f72616e646f6dULL ^ key.k1;
2160 uint64_t v2 = 0x6c7967656e657261ULL ^ key.k0;
2161 uint64_t v3 = 0x7465646279746573ULL ^ key.k1;
2162
2163 const unsigned char* end = c + (size & ~(size_t)7);
2164 for ( ; c != end; c += 8)
2165 {
2166 uint64_t m = 0;
2167 for (int i = 7; i >= 0; --i)
2168 {
2169 m = (m << 8) | sipByte<NoCase>(c[i]); // little-endian load
2170 }
2171 v3 ^= m;
2172 sipRound(v0, v1, v2, v3);
2173 v0 ^= m;
2174 }
2175
2176 uint64_t b = (uint64_t)size << 56;
2177 for (int i = (int)(size & 7) - 1; i >= 0; --i)
2178 {
2179 b |= sipByte<NoCase>(c[i]) << (8 * i);
2180 }
2181 v3 ^= b;
2182 sipRound(v0, v1, v2, v3);
2183 v0 ^= b;
2184
2185 v2 ^= 0xff;
2186 sipRound(v0, v1, v2, v3);
2187 sipRound(v0, v1, v2, v3);
2188 sipRound(v0, v1, v2, v3);
2189
2190 return (size_t)(v0 ^ v1 ^ v2 ^ v3);
2191}
2192
2193}
2194
2195size_t
2196Data::rawKeyedHash(const unsigned char* c, size_t size)
2197{
2198 return sipHash13<false>(c, size);
2199}
2200
2201size_t
2202Data::rawKeyedCaseInsensitiveHash(const unsigned char* c, size_t size)
2203{
2204 return sipHash13<true>(c, size);
2205}
2206
2207#if defined(RESIP_BIG_ENDIAN) || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
2208
2209#if !defined (get16bits)
2210#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[0])) << 8)\
2211 +(uint32_t)(((const uint8_t *)(d))[1]) )
2212#endif
2213
2214#if !defined (get32bits)
2215#define get32bits(d) ((get16bits(d) << 16) + get16bits(d+2))
2216#endif
2217
2218#else // little endian:
2219
2220#undef get16bits
2221#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
2222 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
2223#define get16bits(d) (*((const uint16_t *) (d)))
2224#endif
2225
2226#if !defined (get16bits)
2227#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
2228 +(uint32_t)(((const uint8_t *)(d))[0]) )
2229#endif
2230
2231#undef get32bits
2232#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
2233 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
2234#define get32bits(d) (*((const uint32_t *) (d)))
2235#endif
2236
2237#if !defined (get32bits)
2238#define get32bits(d) ((get16bits(d+2) << 16) + get16bits(d))
2239#endif
2240#endif
2241
2242// This is intended to be a faster case-insensitive hash function that works
2243// well when the buffer is a RFC 3261 token.
2244// Having non-token characters will not prevent the hash from working, but it
2245// will increase the number of cases where a single char difference will result
2246// in a hash collision. The pairs of _printable_ characters that this hash will
2247// not distinguish between are @`, [{, \|, ]} and ^~
2248// (Note that, for RFC 3261 tokens, this will not be a problem since @, [, {, \,
2249// |, ], } and ^ are not allowed in a token.)
2250size_t
2251Data::rawCaseInsensitiveTokenHash(const unsigned char* data, size_t len)
2252{
2253 // .bwc. Hsieh hash, with some bitmasking to get the case-insensitive
2254 // property (this is what all the "0x2020 |" business is about.)
2255 uint32_t hash = (uint32_t)len, tmp;
2256 int rem;
2257
2258 if (len <= 0 || data == NULL) return 0;
2259
2260 rem = len & 3;
2261 len >>= 2;
2262
2263 union
2264 {
2265 uint32_t masked;
2266 uint16_t ui16[2];
2267 };
2268
2269 /* Main loop */
2270 for (;len > 0; len--)
2271 {
2272 // mask out bit 6 for case-insensitivity
2273 masked = (0x20202020 | get32bits(data));
2274 hash += ui16[0];
2275 tmp = ((uint32_t)ui16[1] << 11) ^ hash;
2276 hash = (hash << 16) ^ tmp;
2277 data += 2*sizeof (uint16_t);
2278 hash += hash >> 11;
2279 }
2280
2281 /* Handle end cases */
2282 switch (rem)
2283 {
2284 case 3: hash += (0x2020 | get16bits (data));
2285 hash ^= hash << 16;
2286 hash ^= (0x20 | data[sizeof (uint16_t)]) << 18;
2287 hash += hash >> 11;
2288 break;
2289 case 2: hash += (0x2020 | get16bits (data));
2290 hash ^= hash << 11;
2291 hash += hash >> 17;
2292 break;
2293 case 1: hash += (0x20 | *data);
2294 hash ^= hash << 10;
2295 hash += hash >> 1;
2296 }
2297
2298 /* Force "avalanching" of final 127 bits */
2299 hash ^= hash << 3;
2300 hash += hash >> 5;
2301 hash ^= hash << 4;
2302 hash += hash >> 17;
2303 hash ^= hash << 25;
2304 hash += hash >> 6;
2305
2306 return hash;
2307
2308// union
2309// {
2310// size_t st;
2311// unsigned char bytes[4];
2312// };
2313// st = 0; // suppresses warnings about unused st
2314// bytes[0] = randomPermutation[0];
2315// bytes[1] = randomPermutation[1];
2316// bytes[2] = randomPermutation[2];
2317// bytes[3] = randomPermutation[3];
2318//
2319// const unsigned char* end = c + size;
2320// for ( ; c != end; ++c)
2321// {
2322// union
2323// {
2324// uint32_t temp;
2325// uint8_t cccc[4];
2326// };
2327// // .bwc. Mask out bit 6, use a multiplication op to write the
2328// // resulting byte to each of the 4 bytes in temp, and xor the whole
2329// // thing with bytes/st.
2330// temp = ( (*c | ' ') * 16843009UL) ^ st;
2331// bytes[0] = randomPermutation[cccc[0]];
2332// bytes[1] = randomPermutation[cccc[1]];
2333// bytes[2] = randomPermutation[cccc[2]];
2334// bytes[3] = randomPermutation[cccc[3]];
2335// }
2336//
2337// // convert from network to host byte order
2338// return ntohl((u_long)st);
2339}
2340
2341Data
2342bits(size_t v)
2343{
2344 Data ret;
2345 for (unsigned int i = 0; i < 8*sizeof(size_t); ++i)
2346 {
2347 ret += ('0' + v%2);
2348 v /= 2;
2349 }
2350
2351 return ret;
2352}
2353
2354size_t
2356{
2357 return rawHash((const unsigned char*)(this->data()), this->size());
2358}
2359
2360size_t
2362{
2363 return rawCaseInsensitiveHash((const unsigned char*)(this->data()), this->size());
2364}
2365
2366size_t
2368{
2369 return rawCaseInsensitiveTokenHash((const unsigned char*)(this->data()), this->size());
2370}
2371
2372size_t
2374{
2375 return rawKeyedHash((const unsigned char*)(this->data()), this->size());
2376}
2377
2378size_t
2380{
2381 return rawKeyedCaseInsensitiveHash((const unsigned char*)(this->data()), this->size());
2382}
2383
2384#define compUnalignedRemainder(d1, d2, size) \
2385switch(size) \
2386{\
2387 case 3: \
2388 if( (*d1 ^ *d2) & 0xDF) \
2389 { \
2390 return false; \
2391 } \
2392 d1++; \
2393 d2++; \
2394 /* fallthrough */ \
2395 case 2: \
2396 if((get16bits(d1) ^ get16bits(d2)) & 0xDFDF) \
2397 { \
2398 return false; \
2399 } \
2400 d1+=2; \
2401 d2+=2; \
2402 break; \
2403 case 1: \
2404 if( (*d1 ^ *d2) & 0xDF) \
2405 { \
2406 return false; \
2407 } \
2408 d1++; \
2409 d2++; \
2410 /* fallthrough */ \
2411 default: \
2412 ; \
2413}\
2414
2415bool
2417{
2418 resip_assert(mSize==rhs.mSize);
2419 const char* d1(mBuf);
2420 const char* d2(rhs.mBuf);
2421
2422 if(mSize < 4)
2423 {
2424 // No point in trying 32-bit ops.
2425 compUnalignedRemainder(d1, d2, mSize);
2426 return true;
2427 }
2428
2429 int unalignedPrefix(4-((ptrdiff_t)d1 & 3));
2430
2431 compUnalignedRemainder(d1, d2, unalignedPrefix);
2432
2433 // We are now on a 32-bit boundary with d1.
2434 uint32_t* wd1((uint32_t*)(d1));
2435 size_t wordLen=(mSize-unalignedPrefix)>>2;
2436 int rem=(mSize-unalignedPrefix)&3;
2437
2438 if((ptrdiff_t)(d2)%4==0)
2439 {
2440 // d2 is aligned too. Happy day!
2441 uint32_t* wd2((uint32_t*)(d2));
2442 for (;wordLen > 0; wordLen--)
2443 {
2444 // bitwise xor is zero iff equal, but we only really care about bits
2445 // other than bit 6, so we mask out bit 6 after the xor.
2446 if( (*wd1 ^ *wd2) & 0xDFDFDFDF)
2447 {
2448 return false;
2449 }
2450 wd1++;
2451 wd2++;
2452 }
2453 d2=(const char*)wd2;
2454 }
2455 else
2456 {
2457 for (;wordLen > 0; wordLen--)
2458 {
2459 // bitwise xor is zero iff equal, but we only really care about bits
2460 // other than bit 6, so we mask out bit 6 after the xor.
2461 uint32_t test=get32bits(d2);
2462 if( (*wd1 ^ test) & 0xDFDFDFDF)
2463 {
2464 return false;
2465 }
2466 wd1++;
2467 d2+=4;
2468 }
2469 }
2470 d1=(const char*)wd1;
2471
2472 compUnalignedRemainder(d1, d2, rem);
2473 return true;
2474}
2475
2476std::bitset<256>
2478{
2479 std::bitset<256> result;
2480 result.reset();
2481 for (unsigned int i=0; i!=chars.mSize;++i)
2482 {
2483 result.set(*(unsigned char*)(chars.mBuf+i));
2484 }
2485 return result;
2486}
2487
2488std::ostream&
2489Data::escapeToStream(std::ostream& str,
2490 const std::bitset<256>& shouldEscape) const
2491{
2492 static char hex[] = "0123456789ABCDEF";
2493
2494 if (empty())
2495 {
2496 return str;
2497 }
2498
2499 const unsigned char* anchor = (unsigned char*)mBuf;
2500 const unsigned char* p = (unsigned char*)mBuf;
2501 const unsigned char* e = (unsigned char*)mBuf + mSize;
2502
2503 while (p < e)
2504 {
2505 // ?abr? Why is this special cased? Removing this code
2506 // does not change the behavior of this method.
2507 if (*p == '%'
2508 && e - p > 2
2509 && isHex(*(p+1))
2510 && isHex(*(p+2)))
2511 {
2512 p+=3;
2513 }
2514 else if (shouldEscape[*p])
2515 {
2516 if(p > anchor)
2517 {
2518 str.write((char*)anchor, p-anchor);
2519 }
2520 int hi = (*p & 0xF0)>>4;
2521 int low = (*p & 0x0F);
2522
2523 str << '%' << hex[hi] << hex[low];
2524 anchor=++p;
2525 }
2526 else
2527 {
2528 ++p;
2529 }
2530 }
2531 if(p > anchor)
2532 {
2533 str.write((char*)anchor, p-anchor);
2534 }
2535 return str;
2536}
2537
2538Data
2539Data::fromFile(const Data& filename)
2540{
2541 ifstream is;
2542 is.open(filename.c_str(), ios::binary );
2543 if ( !is.is_open() )
2544 {
2545 throw DataException("Could not read file " + filename, __FILE__,__LINE__);
2546 }
2547
2548 resip_assert(is.is_open());
2549
2550 int length = 0;
2551
2552 // get length of file:
2553#if !defined(__MSL_CPP__) || (__MSL_CPP_ >= 0x00012000)
2554 is.seekg (0, ios::end);
2555 length = (int)is.tellg();
2556 is.seekg (0, ios::beg);
2557#else
2558 // this is a work around for a bug in CodeWarrior 9's implementation of seekg.
2559 // http://groups.google.ca/group/comp.sys.mac.programmer.codewarrior/browse_frm/thread/a4279eb75f3bd55a
2560 FILE * tmpFile = fopen(filename.c_str(), "r+b");
2561 resip_assert(tmpFile != NULL);
2562 fseek(tmpFile, 0, SEEK_END);
2563 length = ftell(tmpFile);
2564 fseek(tmpFile, 0, SEEK_SET);
2565#endif // __MWERKS__
2566
2567 // tellg/tell will return -1 if the stream is bad
2568 if (length == -1)
2569 {
2570 throw DataException("Could not seek into file ",
2571 __FILE__,__LINE__);
2572 }
2573
2574 // !jf! +1 is a workaround for a bug in Data::c_str() that adds the 0 without
2575 // resizing.
2576 char* buffer = new char [length+1];
2577
2578 // read data as a block:
2579 is.read (buffer,length);
2580
2581 Data target(Data::Take, buffer, length);
2582
2583 is.close();
2584
2585 return target;
2586}
2587
2589
2590static signed char base64Lookup[128] =
2591{
2592 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
2593 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
2594 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
2595 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
2596 -1,-1,-1,62,-1,62,-2,63,52,53,
2597 54,55,56,57,58,59,60,61,-1,-1,
2598 -1,-2,-1,-1,-1,0, 1, 2, 3, 4,
2599 5, 6, 7, 8, 9, 10,11,12,13,14,
2600 15,16,17,18,19,20,21,22,23,24,
2601 25,-1,-1,-1,-1,63,-1,26,27,28,
2602 29,30,31,32,33,34,35,36,37,38,
2603 39,40,41,42,43,44,45,46,47,48,
2604 49,50,51,-1,-1,-1,-1,-1
2605};
2606Data
2608{
2609 // see RFC 3548
2610 // this will decode normal and URL safe alphabet
2611#if 0
2612 return Base64Coder::decode( *this );
2613#else
2614 int wc=0;
2615 int val=0;
2616 Data bin;
2617 bin.reserve( size()*3/4 );
2618
2619 for( unsigned int i=0; i<size(); i++ )
2620 {
2621 unsigned int x = mBuf[i] & 0x7F;
2622 char c1,c2,c3;
2623
2624 int v = base64Lookup[x];
2625
2626 if ( v >= 0 )
2627 {
2628 val = val << 6;
2629 val |= v;
2630 wc++;
2631
2632 if ( wc == 4 )
2633 {
2634 c3 = char( val & 0xFF ); val = val >> 8;
2635 c2 = char( val & 0xFF ); val = val >> 8;
2636 c1 = char( val & 0xFF ); val = val >> 8;
2637
2638 bin += c1;
2639 bin += c2;
2640 bin += c3;
2641
2642 wc=0;
2643 val=0;
2644 }
2645 }
2646 if ( base64Lookup[x] == -2 )
2647 {
2648 if (wc==2) val = val<<12;
2649 if (wc==3) val = val<<6;
2650
2651 c3 = char( val & 0xFF ); val = val >> 8;
2652 c2 = char( val & 0xFF ); val = val >> 8;
2653 c1 = char( val & 0xFF ); val = val >> 8;
2654
2655 unsigned int xNext = mBuf[i] & 0x7F;
2656 if ( (i+1<size() ) && ( base64Lookup[xNext] == -2 ))
2657 {
2658 bin += c1;
2659 i++;
2660 }
2661 else
2662 {
2663 bin += c1;
2664 bin += c2;
2665 }
2666
2667 break;
2668 }
2669 }
2670
2671 return bin;
2672#endif
2673}
2674
2675
2676// see RFC 3548
2677static unsigned char codeCharUnsafe[] =
2678 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
2679static unsigned char codeCharSafe[] =
2680 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
2681Data
2682Data::base64encode(bool useSafeSet) const
2683{
2684 unsigned char* codeChar = useSafeSet ? codeCharSafe : codeCharUnsafe;
2685
2686 int srcLength = (int)this->size();
2687 unsigned int dstLimitLength = 4 * (srcLength / 3 + (srcLength%3==0 ? 0 : 1));
2688 unsigned char * dstData = new unsigned char[dstLimitLength + 1];
2689 unsigned int dstIndex = 0;
2690
2691 const char * p = static_cast<const char *>( this->data() );
2692
2693 for(int index=0;index<srcLength;index+=3)
2694 {
2695 unsigned char codeBits = (p[index] & 0xfc)>>2;
2696
2697 resip_assert(codeBits < 64);
2698 dstData[dstIndex++] = codeChar[codeBits]; // c0 output
2699 resip_assert(dstIndex <= dstLimitLength);
2700
2701 // do second codeBits
2702 codeBits = ((p[index]&0x3)<<4);
2703 if (index+1 < srcLength)
2704 {
2705 codeBits |= ((p[index+1]&0xf0)>>4);
2706 }
2707 resip_assert(codeBits < 64);
2708 dstData[dstIndex++] = codeChar[codeBits]; // c1 output
2709 resip_assert(dstIndex <= dstLimitLength);
2710
2711 if (index+1 >= srcLength)
2712 {
2713 dstData[dstIndex++] = codeChar[64];
2714 resip_assert(dstIndex <= dstLimitLength);
2715 dstData[dstIndex++] = codeChar[64];
2716 resip_assert(dstIndex <= dstLimitLength);
2717 break; // encoded d0 only
2718 }
2719
2720 // do third codeBits
2721 codeBits = ((p[index+1]&0xf)<<2);
2722 if (index+2 < srcLength)
2723 {
2724 codeBits |= ((p[index+2]&0xc0)>>6);
2725 }
2726 resip_assert(codeBits < 64);
2727 dstData[dstIndex++] = codeChar[codeBits]; // c2 output
2728 resip_assert(dstIndex <= dstLimitLength);
2729
2730 if (index+2 >= srcLength)
2731 {
2732 dstData[dstIndex++] = codeChar[64];
2733 resip_assert(dstIndex <= dstLimitLength);
2734 break; // encoded d0 d1 only
2735 }
2736
2737 // do fourth codeBits
2738 codeBits = ((p[index+2]&0x3f));
2739 resip_assert(codeBits < 64);
2740 dstData[dstIndex++] = codeChar[codeBits]; // c3 output
2741 resip_assert(dstIndex <= dstLimitLength);
2742 // outputed all d0,d1, and d2
2743 }
2744
2745 dstData[dstIndex] = 0;
2746 return Data(Data::Take, reinterpret_cast<char*>(dstData),
2747 dstIndex);
2748}
2749
2750
2751/* ====================================================================
2752 * The Vovida Software License, Version 1.0
2753 *
2754 * Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
2755 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
2756 *
2757 * Redistribution and use in source and binary forms, with or without
2758 * modification, are permitted provided that the following conditions
2759 * are met:
2760 *
2761 * 1. Redistributions of source code must retain the above copyright
2762 * notice, this list of conditions and the following disclaimer.
2763 *
2764 * 2. Redistributions in binary form must reproduce the above copyright
2765 * notice, this list of conditions and the following disclaimer in
2766 * the documentation and/or other materials provided with the
2767
2768 * distribution.
2769 *
2770 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2771 * and "Vovida Open Communication Application Library (VOCAL)" must
2772 * not be used to endorse or promote products derived from this
2773 * software without prior written permission. For written
2774 * permission, please contact vocal@vovida.org.
2775 *
2776 * 4. Products derived from this software may not be called "VOCAL", nor
2777 * may "VOCAL" appear in their name, without prior written
2778 * permission of Vovida Networks, Inc.
2779 *
2780 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2781 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2782 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2783 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
2784 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2785 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2786 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2787 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2788 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2789 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2790 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2791 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2792 * DAMAGE.
2793 *
2794 * ====================================================================
2795 *
2796 * This software consists of voluntary contributions made by Vovida
2797 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2798 * Inc. For more information on Vovida Networks, Inc., please see
2799 * <http://www.vovida.org/>.
2800 *
2801 * vi: set shiftwidth=3 expandtab:
2802 */
static unsigned char codeCharUnsafe[]
Definition Data.cxx:2677
static const int Int32MaxSize
Definition Data.cxx:379
static const unsigned char randomPermutation[256]
Definition Data.cxx:2006
static signed char base64Lookup[128]
Definition Data.cxx:2590
Data bits(size_t v)
Definition Data.cxx:2342
int hexpair2int(char high, char low)
Definition Data.cxx:83
bool urlNonEncodedCharsInitFn()
Definition Data.cxx:1383
static bool dummy
Definition Data.cxx:1417
static const int UInt64MaxSize
Definition Data.cxx:382
bool urlNonEncodedChars[256]
Definition Data.cxx:1381
static unsigned char codeCharSafe[]
Definition Data.cxx:2679
#define get16bits(d)
Definition Data.cxx:2227
#define compUnalignedRemainder(d1, d2, size)
Definition Data.cxx:2384
#define get32bits(d)
Definition Data.cxx:2238
static const int CharMaxSize
Definition Data.cxx:604
static const int DoubleMaxSize
Definition Data.cxx:440
static const char hexmap[]
Definition Data.cxx:59
static const signed char inversehexmap[]
Definition Data.cxx:61
#define max(x, y)
#define HashValueImp(type, ret)
Definition HashMap.hxx:24
static Data digest("digest")
#define resip_assert(x)
This file needs to work for both C and C++ code.
static Data decode(const Data &)
Definition Coders.cxx:19
static const bool isCharHex[256]
Definition Data.hxx:1103
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
EncodeStream & escapeToStream(EncodeStream &str, Predicate shouldEscape) const
Performs escaping of this Data according to the indicated Predicate.
Definition Data.hxx:1147
Data xmlCharDataDecode() const
Performs in-place XML Character Data un-escaping of a Data.
Definition Data.cxx:1464
Data & uppercase()
Converts this Data to uppercase.
Definition Data.cxx:1648
Data base64decode() const
Performs RFC 3548 Base 64 decoding of the contents of this data.
Definition Data.cxx:2607
DoubleDigitPrecision
Definition Data.hxx:218
@ MaxDigitPrecision
Definition Data.hxx:224
static size_t rawCaseInsensitiveTokenHash(const unsigned char *c, size_t size)
A faster version of rawCaseInsensitiveHash that has the same collision properties if this Data is mad...
Definition Data.cxx:2251
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
ShareEnum
The various memory management behaviors.
Definition Data.hxx:255
@ Share
The Data instance will use the buffer in a read-only mode.
Definition Data.hxx:266
@ Borrow
The Data instance is borrowing the memory from the passed in buffer.
Definition Data.hxx:260
@ Take
The Data instance takes complete ownership of the buffer.
Definition Data.hxx:272
Data base64encode(bool useUrlSafe=false) const
Performs RFC 3548 Base 64 encoding of the contents of this data.
Definition Data.cxx:2682
static size_t rawKeyedCaseInsensitiveHash(const unsigned char *c, size_t size)
As rawKeyedHash, after normalizing ASCII alphabetic characters to lowercase; consistent with isEqualN...
Definition Data.cxx:2202
char & at(size_type p)
Returns the character at the specified position.
Definition Data.cxx:988
Data & operator^=(const Data &rhs)
Performs an in-place exclusive-or of this buffer buffer with the specified buffer.
Definition Data.cxx:964
int replace(const Data &match, const Data &target, int max=INT_MAX)
Replaces up to max occurrences of the bytes match with target.
Definition Data.cxx:1964
bool postfixNoCase(const Data &post) const noexcept
Definition Data.cxx:1921
const char * end() const noexcept
Returns a pointer to the end of the buffer used by the Data.
Definition Data.hxx:650
static Data fromFile(const Data &filename)
Definition Data.cxx:2539
Data charUnencoded() const
Performs RFC 3261 un-escaping of SIP URIs.
Definition Data.cxx:1289
unsigned long convertUnsignedLong() const
Definition Data.cxx:1724
bool sizeEqualCaseInsensitiveTokenCompare(const Data &rhs) const
Definition Data.cxx:2416
char * getBuf(size_type length)
Set size to be exactly {length}, extending buffer if needed.
Definition Data.cxx:723
Data xmlCharDataEncode() const
Performs in-place XML Character Data escaping of a Data.
Definition Data.cxx:1454
Data & operator=(const Data &data)
Definition Data.hxx:425
size_t keyedCaseInsensitiveHash() const
Creates a keyed hash based on the contents of this Data, after normalizing ASCII alphabetic character...
Definition Data.cxx:2379
uint64_t convertUInt64() const
Takes the contents of the Data and converts them to an unsigned 64-bit integer.
Definition Data.cxx:1758
static const PreallocateType Preallocate
used only to disambiguate constructors
Definition Data.hxx:116
std::string toString() const
Convert to a C++ string.
Definition Data.cxx:1109
bool prefix(const Data &pre) const noexcept
Returns true if this Data starts with the bytes indicated by the passed-in Data.
Definition Data.cxx:1888
Data & append(const char *str, size_type len)
Appends the specified number of bytes to the end of this Data.
Definition Data.cxx:1058
Data & duplicate(const Data &other)
Functional equivalent of: *this = Data(buf, length) and Data& copy(const char *buf,...
Definition Data.cxx:675
size_t caseInsensitivehash() const
Creates a 32-bit hash based on the contents of this Data, after normalizing any alphabetic characters...
Definition Data.cxx:2361
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
Definition Data.cxx:1932
Data & takeBuf(Data &other) noexcept
Take the data from {other}.
Definition Data.cxx:641
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
Data charEncoded() const
Performs RFC 3261 escaping of SIP URIs.
Definition Data.cxx:1243
Data & lowercase()
Converts this Data to lowercase.
Definition Data.cxx:1635
Data urlDecoded() const
Performs in-place HTTP URL un-escaping of a Data.
Definition Data.cxx:1341
size_t size_type
Definition Data.hxx:94
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
EncodeStream & urlEncode(EncodeStream &s) const
Escapes a Data to a stream according to HTTP URL encoding rules.
Definition Data.cxx:1421
static bool init(DataLocalSize< RESIP_DATA_LOCAL_SIZE > arg)
Initializes Data class.
Definition Data.cxx:215
EncodeStream & urlDecode(EncodeStream &s) const
Un-escapes a Data to a stream according to HTTP URL encoding rules.
Definition Data.cxx:1351
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
static const size_type npos
Represents an impossible position; returned to indicate failure to find.
Definition Data.hxx:887
static size_t rawKeyedHash(const unsigned char *c, size_t size)
Creates a hash based on the contents of the indicated buffer, using SipHash-1-3 with a key chosen ran...
Definition Data.cxx:2196
Data operator+(const Data &rhs) const
Concatenates two Data objects.
Definition Data.cxx:951
Data urlEncoded() const
Performs in-place HTTP URL escaping of a Data.
Definition Data.cxx:1331
Data & schemeLowercase()
Converts this Data to lowercase, assuming this Data only consists of scheme characters.
Definition Data.cxx:1661
Data trunc(size_type trunc) const
Shortens the size of this Data.
Definition Data.cxx:1564
Data fromHex() const
Returns the binary form of the hexadecimal string in this Data.
Definition Data.cxx:1599
size_t caseInsensitiveTokenHash() const
A faster version of caseInsensitiveHash that has the same collision properties if this Data is made u...
Definition Data.cxx:2367
size_type truncate(size_type len)
Shortens the size of this Data.
Definition Data.cxx:928
Data & setBuf(ShareEnum se, const char *buf, size_type length)
Set the Data to hold {buf} using share type {se}, which may be any of Share (read-only,...
Definition Data.cxx:627
static size_t rawHash(const unsigned char *c, size_t size)
Creates a 32-bit hash based on the contents of the indicated buffer.
Definition Data.cxx:2027
Data & copy(const char *buf, size_type length)
Functional equivalent of: *this = Data(buf, length) but avoids the intermediate allocation and free.
Definition Data.cxx:701
Data hex() const
Returns a hexadecimal representation of the contents of this Data.
Definition Data.cxx:1577
size_t hash() const
Creates a 32-bit hash based on the contents of this Data.
Definition Data.cxx:2355
double convertDouble() const
Takes the contents of the Data and converts them to a double precision floating point value.
Definition Data.cxx:1827
int convertInt() const
Takes the contents of the Data and converts them to an integer.
Definition Data.cxx:1684
Data escaped() const
Returns a representation of the contents of the data with any non-printable characters escaped.
Definition Data.cxx:1199
bool postfix(const Data &post) const noexcept
Returns true if this Data ends with the bytes indicated by the passed-in Data.
Definition Data.cxx:1910
Data & clear()
Clears the contents of this Data.
Definition Data.hxx:800
static std::bitset< 256 > toBitset(const resip::Data &chars)
Creates a bitset reflecting the contents of this data (as a set) ie.
Definition Data.cxx:2477
size_t keyedHash() const
Creates a keyed hash based on the contents of this Data.
Definition Data.cxx:2373
Data md5(EncodingType type=HEX) const
Computes the MD5 hash of the current data.
Definition Data.cxx:1174
size_t convertSize() const
Takes the contents of the Data and converts them to a size_t.
Definition Data.cxx:1792
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
bool prefixNoCase(const Data &pre) const noexcept
Definition Data.cxx:1899
void reserve(size_type capacity)
Guarantees that the underlying buffer used by the Data is at least the number of bytes specified.
Definition Data.cxx:1049
static size_t rawCaseInsensitiveHash(const unsigned char *c, size_t size)
Creates a 32-bit hash based on the contents of the indicated buffer, after normalizing any alphabetic...
Definition Data.cxx:2058
Data & truncate2(size_type len)
Shortens the size of this Data so length is at most of {len}.
Definition Data.cxx:940
Provides string-parsing functionality with protection from buffer overflow.
Pointer start() const
CurrentPosition skipToChars(const char *cs)
CurrentPosition position() const
dcm! – add UnusedChecking(_enum) below;
const _Tp & resipMin(const _Tp &__a, const _Tp &__b)
Definition compat.hxx:182
void MD5Final(unsigned char digest[16], struct MD5Context *context)
Definition vmd5.cxx:116
unsigned short uint16_t
Definition Stun.hxx:30
void MD5Init(struct MD5Context *context)
Definition vmd5.cxx:58
unsigned long long uint64_t
Definition Stun.hxx:39
unsigned int uint32_t
Definition Stun.hxx:34
bool operator<(const Data &lhs, const Data &rhs)
Definition Data.cxx:778
const _Tp & resipMax(const _Tp &__a, const _Tp &__b)
Definition compat.hxx:194
void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len)
Definition vmd5.cxx:74
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
bool operator==(const char *lhs, const Data &rhs)
Definition Data.hxx:1197
#define EncodeStream
_W64 unsigned int uintptr_t
Definition stdint.h:124
signed int int32_t
Definition stdint.h:82
unsigned __int64 uint64_t
Definition stdint.h:95