Coverage Report

Created: 2025-06-13 06:12

/src/resiprocate/rutil/Data.hxx
Line
Count
Source (jump to first uncovered line)
1
#ifndef RESIP_Data_hxx
2
#define RESIP_Data_hxx
3
4
#ifdef HAVE_CONFIG_H
5
#include "config.h"
6
#endif
7
8
#include <iostream>
9
#include <string>
10
#include <bitset>
11
#if RESIP_HAVE_STRING_VIEW
12
#include <string_view>
13
#endif
14
#include "rutil/ResipAssert.h"
15
16
#include "rutil/compat.hxx"
17
#include "rutil/DataStream.hxx"
18
#include "rutil/HeapInstanceCounter.hxx"
19
#include "rutil/HashMap.hxx"
20
21
#ifndef RESIP_DATA_LOCAL_SIZE
22
#define RESIP_DATA_LOCAL_SIZE 16
23
#endif
24
25
class TestData;
26
namespace resip
27
{
28
29
/**
30
   @internal
31
   This template is here to help diagnose API/ABI mismatches. Say you build
32
   librutil. A single Data::init(DataLocalSize<RESIP_DATA_LOCAL_SIZE>)
33
   function is implemented in Data.cxx, with the default
34
   value. (Data::init(DataLocalSize<16>) ends up being defined,
35
   Data::init(DataLocalSize<15>) does not) If, later, another build using
36
   that librutil tries to tweak the local alloc size to 24, it will end
37
   up attempting to call Data::init(DataLocalSize<24>); this will result
38
   in a link-time error, that while opaque, is less opaque than the stack
39
   corruption that would result otherwise.
40
**/
41
template <int S>
42
struct DataLocalSize
43
{
44
198
      explicit DataLocalSize(size_t) noexcept {}
45
};
46
47
// .bwc. Pack class Data; has to come before doxygen block though.
48
#pragma pack(push, 4)
49
50
/**
51
  @brief An alternative to std::string, encapsulates an arbitrary buffer of 
52
  bytes.
53
54
  It has a variety of memory management styles that can be
55
  established at contruction time and changed later via setBuf().
56
57
  Three modes of allocation are currently available:
58
59
    @li 'Borrow' - The Data instance is borrowing the memory from the passed
60
                   in buffer. It will modify its contents as necessary,
61
                   but will not deallocate it.
62
            
63
    @li 'Share'  - The Data instance will use the buffer in a read-only mode.
64
                   If any attempt is made to modify the contents of
65
                   the Data, it will copy the buffer and modify it.
66
           
67
    @li 'Take'   - The Data instance takes complete ownership of the
68
                   buffer. The buffer is deallocated using delete[].
69
70
   Additionally, Data has a small locally-allocated buffer (member buffer) that
71
   it will use to hold small amounts of data. By default, this buffer can 
72
   contain 16 bytes, meaning that Data will not use the heap unless it
73
   needs more than 16 bytes of space. The tradeoff here, of course, is that
74
   instances of Data will be larger than instances of std::string. Generally
75
   speaking, if you expect to need more than 16 bytes of room, and you cannot
76
   make good use of the flexible memory management offered by Data, you may want
77
   to use a std::string instead.
78
79
  @see RESIP_HeapCount
80
81
  @todo It might be worthwhile examining the heap usage of this
82
        class in the context of using realloc everywhere appropriate.
83
        (realloc is defined in ANSI C, SVID, and the OpenGroup "Single
84
        Unix Specification").
85
86
   @ingroup text_proc
87
*/
88
89
class Data 
90
{
91
   public:
92
      RESIP_HeapCount(Data);
93
94
      typedef size_t size_type;
95
96
      inline Data()
97
4.33M
         : mBuf(mPreBuffer),
98
4.33M
           mSize(0),
99
4.33M
           mCapacity(LocalAlloc),
100
4.33M
           mShareEnum(Borrow)
101
4.33M
      {
102
4.33M
         mBuf[mSize] = 0;
103
4.33M
      }
104
105
      /**
106
      @internal
107
      */
108
      class PreallocateType
109
      {
110
         friend class Data;
111
         explicit PreallocateType(int);
112
      };
113
      /**
114
      @brief used only to disambiguate constructors
115
      */
116
      static const PreallocateType Preallocate;
117
118
      /**
119
        Creates a data with a specified initial capacity.
120
121
        @param capacity  The initial capacity of the buffer
122
123
        @param foo       This parameter is ignored; it is merely
124
                         used to disambiguate this constructor
125
                         from the constructor that takes a single
126
                         int. Always pass Data::Preallocate.
127
      */
128
      Data(size_type capacity, const PreallocateType&);
129
130
//#define DEPRECATED_PREALLOC
131
#ifdef DEPRECATED_PREALLOC
132
      /**
133
        Creates a data with a specified initial capacity.
134
135
        @deprecated      This constructor shouldn't really exist;
136
                         it would be far better to add a value
137
                         to "ShareEnum" (e.g. "Allocate") which
138
                         indicates that the Data should allocated
139
                         its own buffer.
140
141
        @param capacity  The initial capacity of the buffer
142
143
        @param foo       This parameter is ignored; it is merely
144
                         used to disambiguate this constructor
145
                         from the constructor that takes a single
146
                         int. Yes, it's ugly -- that's why it's
147
                         deprecated.
148
149
        @todo Remove this constructor
150
      */
151
      Data(size_type capacity, bool foo);
152
#endif      
153
154
      /**
155
        Creates a data with a copy of the contents of the
156
        null-terminated string.
157
158
        @warning Passing a non-null-terminated string to this
159
                 method would be a Really Bad Thing.
160
      */
161
      Data(const char* str);
162
163
      /**
164
        Creates a data with the contents of the buffer.
165
166
        @param length Number of bytes in the buffer
167
      */
168
      Data(const char* buffer, size_type length);
169
170
      /**
171
        Creates a data with the contents of the buffer.
172
173
        @param length Number of bytes in the buffer
174
      */
175
      Data(const unsigned char* buffer, size_type length);
176
177
      Data(const Data& data);
178
179
#ifdef RESIP_HAS_RVALUE_REFS
180
      Data(Data &&data);
181
#endif
182
      /**
183
        Creates a data with the contents of the string.
184
      */
185
      Data(const std::string& str);
186
187
#if RESIP_HAVE_STRING_VIEW
188
      /**
189
        Creates a data with the contents of the string_view.
190
      */
191
      Data(const std::string_view sv);
192
#endif
193
194
      /**
195
        Converts the passed in value into ascii-decimal
196
        representation, and then creates a "Data" containing
197
        that value. (E.g. "Data(75)" will create a Data
198
        with length=2, and contents of 0x37 0x35).
199
      */
200
      explicit Data(int32_t value);
201
202
      /**
203
        Converts the passed in value into ascii-decimal
204
        representation, and then creates a "Data" containing
205
        that value. (E.g. "Data(75)" will create a Data
206
        with length=2, and contents of 0x37 0x35).
207
      */
208
      explicit Data(uint32_t value);
209
210
      /**
211
        Converts the passed in value into ascii-decimal
212
        representation, and then creates a "Data" containing
213
        that value. (E.g. "Data(75)" will create a Data
214
        with length=2, and contents of 0x37 0x35).
215
      */
216
      explicit Data(uint64_t value);
217
218
#ifndef RESIP_FIXED_POINT
219
      enum DoubleDigitPrecision 
220
      {
221
         ZeroDigitPrecision = 0, OneDigitPrecision, 
222
         TwoDigitPrecision, ThreeDigitPrecision, 
223
         FourDigitPrecision, FiveDigitPrecision,
224
         SixDigitPrecision, SevenDigitPrecision,
225
         EightDigitPrecision, NineDigitPrecision,
226
         TenDigitPrecision, MaxDigitPrecision
227
      };
228
      /**
229
        Converts the passed in value into ascii-decimal
230
        representation, and then creates a "Data" containing
231
        that value. (E.g. "Data(75.4,2)" will create a Data
232
        with length=4, and contents of 0x37 0x35 0x2E 0x34).
233
234
        @param precision  Number of digits after the decimal point.
235
                          Trailing zeros will be removed.
236
      */
237
      explicit Data(double value, 
238
                    Data::DoubleDigitPrecision precision = FourDigitPrecision);
239
#endif
240
241
      /**
242
        Creates a buffer containing "true" or "false", depending
243
        on the value of "value".
244
      */
245
      explicit Data(bool value);
246
247
      /**
248
        Creates a buffer containing a single character. Is this silly?
249
        Maybe. Perhaps it can be removed.
250
      */
251
      explicit Data(char c);
252
253
      /**
254
        The various memory management behaviors.
255
      */
256
      enum ShareEnum 
257
      {
258
        /** The Data instance is borrowing the memory from the passed
259
            in buffer. It will modify its contents as necessary,
260
            but will not deallocate it.
261
        */
262
        Borrow=0,
263
264
        /** The Data instance will use the buffer in a read-only mode.
265
            If any attempt is made to modify the contents of
266
            the Data, it will copy the buffer and modify it.
267
        */
268
        Share=1,
269
270
        /** The Data instance takes complete ownership of the
271
            buffer. The buffer must have been allocate using
272
            "new char[]" so that it can be freed with "delete char[]".
273
        */
274
        Take=2
275
      };
276
277
      /**
278
        Creates a Data from the passed-in buffer.
279
280
        @see ShareEnum
281
      */
282
283
      Data(ShareEnum, const char* buffer, size_type length);
284
285
      /**
286
        Creates a Data from the passed-in buffer.
287
288
        @see ShareEnum
289
      */
290
291
      Data(ShareEnum, const char* buffer, size_type length, size_type capacity);
292
293
      /**
294
        Takes a null-terminated string and creates a buffer.
295
296
        @see ShareEnum
297
298
        @warning Passing a non-null-terminated string to this
299
                 method would be a Really Bad Thing.
300
      */
301
      Data(ShareEnum, const char* buffer);
302
303
      /**
304
        Lazily creates a Data from the passed-in Data. 
305
306
        @see ShareEnum
307
308
        @warning Calling this with "Take" or "Borrow" is invalid and will
309
                 cause an assertion or crash.
310
311
        @todo This implementation has some confusing and conflicting
312
              comments. (e.g. is Borrow actually okay? Can there be some
313
              way to use it with Take as long as you play with mShareEnum
314
              correctly?)
315
      */
316
      Data(ShareEnum, const Data& staticData); // Cannot call with 'Take'
317
318
      inline ~Data()
319
12.2M
      {
320
12.2M
         if (mShareEnum == Take)
321
583k
         {
322
583k
            delete[] mBuf;
323
583k
         }
324
12.2M
      }
325
326
      /**
327
        Set the Data to hold {buf} using share type {se}, which may be any
328
        of Share (read-only, no-free), Borrow (read-write, no-free)
329
        or Take (read-write, yes-free). Both the capacity
330
        and current length are set to {length}; you can call truncate2()
331
        afterwords to shorten.  The provided buffer (and its current
332
        contents) will be used going forward; any currently owned buffer
333
        will be released.
334
        NOTE: The {buf} param is declared const to support Share type; for
335
        Borrow and Take the buffer may be written (e.g., treated non-const).
336
      **/
337
      Data& setBuf(ShareEnum se, const char *buf, size_type length);
338
339
      /**
340
        Convience function to call setBuf() with a NULL-terminated string.
341
        This is in-lined for case where compiler knows strlen statically.
342
      **/
343
      Data& setBuf(ShareEnum se, const char *str)
344
0
      {
345
0
         return setBuf(se, str, (size_type)strlen(str));
346
0
      };
347
348
349
      /**
350
        Take the data from {other}. Any current buffer is released.
351
        {this} will have the same storage mode as {other} and steal
352
        its buffer. All storage modes of {other} (Share,Borrow,Take)
353
        are legal. When done, {other} will be empty (it will ref its
354
        internal buffer).
355
      **/
356
      Data& takeBuf(Data& other);
357
358
      /**
359
        Functional equivalent of: *this = Data(buf, length)
360
        and Data& copy(const char *buf, size_type length)
361
        but avoids an actual copy of the data if {other} is Shared
362
        or Borrowed.  Will have the same storage mode as {other}.
363
      **/
364
      Data& duplicate(const Data& other);
365
366
      /**
367
        Functional equivalent of: *this = Data(buf, length)
368
        but avoids the intermediate allocation and free. Also,
369
        will never decrease capacity. Safe to call even if {buf}
370
        is part of {this}.
371
372
        @note The result is always NULL terminated. Unfortunately,
373
        this requires a buffer allocation even if capacity exactly
374
        equals length.
375
      **/
376
      Data& copy(const char *buf, size_type length);
377
378
      /**
379
        Set size to be exactly {length}, extending buffer if needed.
380
        Also, reallocate buffer if needed so that it is writable.
381
        Buffer contents is NOT initialized, and existing contents
382
        may or may not be preserved.
383
384
        @note Purpose of this function is to provide a working buffer
385
        of fixed size that the application fills in after this call.
386
387
        @note If you want just the buffer without changing the size,
388
        use data() and cast-away the const-ness.
389
390
        @note The result may or may not be NULL terminated. The buffer
391
        is NULL terminated only when safe to do so without extra reallocation.
392
      **/
393
      char* getBuf(size_type length);
394
395
      /**
396
        Converts from arbitrary other type to Data. Requires the other
397
        type to have an operator<<.
398
      */
399
      template<class T>
400
      static Data from(const T& x)
401
0
      {
402
0
         Data d;
403
0
         {
404
0
            DataStream s(d);
405
0
            s << x;
406
0
         }
407
0
         return d;
408
0
      }
Unexecuted instantiation: resip::Data resip::Data::from<resip::Contents>(resip::Contents const&)
Unexecuted instantiation: resip::Data resip::Data::from<resip::Uri>(resip::Uri const&)
409
410
      friend bool operator==(const Data& lhs, const Data& rhs);
411
      friend bool operator==(const Data& lhs, const char* rhs);
412
      friend bool operator==(const Data& lhs, const std::string& rhs) noexcept;
413
#if RESIP_HAVE_STRING_VIEW
414
      friend bool operator==(const Data& lhs, const std::string_view rhs) noexcept;
415
#endif
416
417
      friend bool operator<(const Data& lhs, const Data& rhs);
418
      friend bool operator<(const Data& lhs, const char* rhs);
419
      friend bool operator<(const char* lhs, const Data& rhs);
420
      friend bool operator<(const Data& lhs, const std::string& rhs) noexcept;
421
      friend bool operator<(const std::string& lhs, const Data& rhs) noexcept;
422
#if RESIP_HAVE_STRING_VIEW
423
      friend bool operator<(const Data& lhs, const std::string_view rhs) noexcept;
424
      friend bool operator<(const std::string_view lhs, const Data& rhs) noexcept;
425
#endif
426
427
      Data& operator=(const Data& data)
428
69.4k
      {
429
69.4k
         if (&data==this)
430
0
             return *this;
431
69.4k
         return copy(data.mBuf,data.mSize);
432
69.4k
      }
433
434
#ifdef RESIP_HAS_RVALUE_REFS
435
      Data& operator=(Data &&data);
436
#endif
437
438
      operator std::string() const 
439
0
      {
440
0
         return std::string(c_str(), size());
441
0
      }
442
443
      /**
444
        Assigns a null-terminated string to the buffer.
445
446
        @warning Passing a non-null-terminated string to this
447
                 method would be a Really Bad Thing.
448
        The strlen() inlined to take advantages of cases where
449
        the compiler knows the length statically.
450
      */
451
      Data& operator=(const char* str)
452
426
      {
453
426
         return copy(str, (size_type)strlen(str));
454
426
      }
455
456
457
      Data& operator=(const std::string& str)
458
0
      {
459
0
         return copy(str.c_str(), static_cast<size_type>(str.size()));
460
0
      }
461
462
#if RESIP_HAVE_STRING_VIEW
463
464
      operator std::string_view() const 
465
0
      {
466
0
         return std::string_view(c_str(), size());
467
0
      }
468
469
      Data& operator=(const std::string_view sv)
470
0
      {
471
0
         return copy(sv.data(), static_cast<size_type>(sv.size()));
472
0
      }
473
#endif
474
475
      /**
476
        Concatenates two Data objects.
477
      */
478
      Data operator+(const Data& rhs) const;
479
480
      /**
481
        Concatenates a null-terminated string after the Data object.
482
483
        @warning Passing a non-null-terminated string to this
484
                 method would be a Really Bad Thing.
485
      */
486
      Data operator+(const char* str) const;
487
488
      /**
489
        Concatenates a single byte after Data object.
490
      */
491
      Data operator+(char c) const;
492
493
      /**
494
        Appends a data object to this one.
495
      */
496
      inline Data& operator+=(const Data& rhs)
497
100k
      {
498
100k
         return append(rhs.data(), rhs.size());
499
100k
      }
500
501
      /**
502
        Appends a null-terminated string to the end of the Data
503
        object.
504
505
        @warning Passing a non-null-terminated string to this
506
                 method would be a Really Bad Thing.
507
      */
508
      inline Data& operator+=(const char* str)
509
200k
      {
510
200k
         resip_assert(str);
511
200k
         return append(str, (size_type)strlen(str));
512
200k
      }
513
514
515
      /**
516
        Appends a single byte to the Data object.
517
      */
518
      inline Data& operator+=(char c)
519
1.45G
      {
520
1.45G
         return append(&c, 1);
521
1.45G
      }
522
523
524
      /**
525
        Performs an in-place exclusive-or of this buffer
526
        buffer with the specified buffer. If the specifed
527
        buffer is longer than this buffer, then this buffer
528
        will first be expanded and zero-padded.
529
      */
530
      Data& operator^=(const Data& rhs);
531
532
      /**
533
        Returns the character at the specified position. Ensures that ownership of
534
        the buffer is taken, since the character could be modified by the caller.
535
      */
536
      inline char& operator[](size_type p)
537
8.37M
      {
538
8.37M
         resip_assert(p < mSize);
539
8.37M
         own();
540
8.37M
         return mBuf[p];
541
8.37M
      }
542
543
      /**
544
        Returns the character at the specified position.
545
      */
546
      inline char operator[](size_type p) const
547
9.26M
      {
548
9.26M
         resip_assert(p < mSize);
549
9.26M
         return mBuf[p];
550
9.26M
      }
551
552
      /**
553
        Returns the character at the specified position.
554
      */
555
      char& at(size_type p);
556
557
      /**
558
        Guarantees that the underlying buffer used by the Data
559
        is at least the number of bytes specified. May cause
560
        reallocation of the buffer.
561
      */
562
      void reserve(size_type capacity);
563
564
      /**
565
        Appends the specified number of bytes to the end of
566
        this Data.
567
      */
568
      Data& append(const char* str, size_type len);
569
570
      /**
571
        Shortens the size of this Data. Does not
572
        impact the size of the allocated buffer.
573
        This owns() the buffer (undoes Share) so as to write
574
        terminating NULL. See truncate2() as alternative.
575
576
        @deprecated dlb says that no one uses this and
577
                    it should be removed.
578
579
        @todo Remove this at some point.
580
      */
581
      size_type truncate(size_type len);
582
583
      /**
584
        Shortens the size of this Data so length is at most of {len}.
585
        (If already shorter, doesn't increase length).
586
        Does not affect buffer allocation, and doesn't impact writing
587
        terminating NULL. Thus is safe to use with Share'd or external
588
        Take'n buffers.
589
      **/
590
      Data& truncate2(size_type len);
591
592
      /**
593
        Checks whether the Data is empty.
594
      */
595
12.6k
      bool empty() const noexcept { return mSize == 0; }
596
597
      /**
598
        Returns the number of bytes in this Data.
599
600
        @note This does NOT indicate the capacity of the
601
              underlying buffer.
602
      */
603
69.5M
      size_type size() const noexcept { return mSize; }
604
605
      /**
606
        Returns a pointer to the contents of this Data. This
607
        is the preferred mechanism for accessing the bytes inside
608
        the Data.
609
610
        @note The value returned is NOT necessarily null-terminated.
611
      */
612
      const char* data() const noexcept
613
24.8M
      {
614
24.8M
         return mBuf;
615
24.8M
      }
616
617
      /**
618
        Returns a null-terminated string representing 
619
620
        @note    Depending on the memory management scheme being used,
621
                 this method often copies the contents of the Data;
622
                 consequently, this method is rather expensive and should
623
                 be avoided when possible.
624
625
        @warning Calling this method is a pretty bad idea if the
626
                 contents of Data are binary (i.e. may contain
627
                 a null in the middle of the Data).
628
      */
629
      const char* c_str() const;
630
631
      /**
632
        Convert to a C++ string.
633
      */
634
      std::string toString() const;
635
636
#if RESIP_HAVE_STRING_VIEW
637
      /**
638
        Creates a c++ string_view.
639
      */
640
      std::string_view toStringView() const;
641
#endif
642
643
      /**
644
        Returns a pointer to the beginning of the buffer used by the Data.
645
      */
646
      const char* begin() const noexcept
647
0
      {
648
0
         return mBuf;
649
0
      }
650
651
      /**
652
        Returns a pointer to the end of the buffer used by the Data.
653
      */
654
      const char* end() const noexcept
655
0
      {
656
0
         return mBuf + mSize;
657
0
      }
658
659
      typedef enum
660
      {
661
         BINARY,
662
         BASE64,
663
         HEX
664
      } EncodingType;
665
666
      /**
667
        Computes the MD5 hash of the current data.
668
        @param type The encoding of the return (default is HEX)
669
        @return The MD5 hash, in the encoding specified by type.
670
      */      
671
      Data md5(EncodingType type=HEX) const;
672
673
      /**
674
        Converts this Data to lowercase.
675
676
        @note This is silly unless the contents are ASCII.
677
      */      
678
      Data& lowercase();
679
680
      /**
681
        Converts this Data to uppercase.
682
683
        @note This is silly unless the contents are ASCII.
684
      */      
685
      Data& uppercase();
686
687
      /**
688
        Converts this Data to lowercase, assuming this Data only consists of 
689
        scheme characters.
690
691
        @note Assuming scheme contents allows the use of a bitmask instead of
692
         tolower(), which is faster. Why, you ask? A bitmask is sufficient to 
693
         perform a lowercase operation on alphabetical data, since 'a' and 'A' 
694
         only differ on bit 6; it is set for 'a', but not for 'A'. Digits always 
695
         have bit 6 set, so setting it is a no-op. The last three characters in 
696
         the scheme character set are '+', '-', and '.'; all of these have bit 6 
697
         set as well. Note that there is no corresponding efficient uppercase 
698
         function; clearing bit 6 on either a digit or the the three remaining 
699
         characters (+=.) will change them.
700
      */
701
      Data& schemeLowercase();
702
703
      /**
704
        Returns a hexadecimal representation of the contents of
705
        this Data.
706
      */
707
      Data hex() const;
708
709
      /**
710
        Returns the binary form of the hexadecimal string in this Data
711
      */
712
      Data fromHex() const;
713
714
      /**
715
        Returns a representation of the contents of the data
716
        with any non-printable characters escaped.
717
718
        @warning This is extremely slow, and should not be called
719
                 except for debugging purposes.
720
      */
721
      Data escaped() const;
722
723
      /**
724
        Performs RFC 3261 escaping of SIP URIs.
725
726
        @note This method is relatively inefficient
727
728
        @deprecated Use escapeToStream instead
729
730
        @todo This method should be removed
731
732
        @see escapeToStream
733
      */
734
      Data charEncoded() const;
735
736
      /**
737
        Performs RFC 3261 un-escaping of SIP URIs.
738
739
        @note This method is relatively inefficient
740
741
        @bug This method can assert if a "%00" comes
742
             in off the wire. That's really bad form.
743
744
        @deprecated Use something more in the spirit of escapeToStream instead
745
746
        @todo This method should be removed
747
748
        @see escapeToStream
749
      */
750
      Data charUnencoded() const;
751
752
      /**
753
        Performs in-place HTTP URL escaping of a Data.
754
      */
755
      Data urlEncoded() const;
756
757
      /**
758
        Performs in-place HTTP URL un-escaping of a Data.
759
      */
760
      Data urlDecoded() const;
761
762
      /**
763
        Escapes a Data to a stream according to HTTP URL encoding rules.
764
      */
765
      EncodeStream& urlEncode(EncodeStream& s) const;
766
767
      /**
768
        Un-escapes a Data to a stream according to HTTP URL encoding rules.
769
      */
770
      EncodeStream& urlDecode(EncodeStream& s) const;
771
772
      /**
773
        Performs in-place XML Character Data escaping of a Data.
774
      */
775
      Data xmlCharDataEncode() const;
776
777
      /**
778
        Performs in-place XML Character Data un-escaping of a Data.
779
      */
780
      Data xmlCharDataDecode() const;
781
782
      /**
783
        Escapes a Data to a stream according to XML Character Data encoding rules.
784
      */
785
      EncodeStream& xmlCharDataEncode(EncodeStream& s) const;
786
787
      /**
788
        Un-escapes a Data to a stream according to XML Character Data encoding rules.
789
      */
790
      EncodeStream& xmlCharDataDecode(EncodeStream& s) const;
791
792
      /**
793
        Shortens the size of this Data. If the contents are truncated,
794
        this method appends two dot ('.') characters to the end.
795
        Presumably, this is used for output purposes.
796
      */
797
      Data trunc(size_type trunc) const;
798
799
      /**
800
        Clears the contents of this Data. This call does not modify
801
        the capacity of the Data. It does not write terminating NULL,
802
        and thus is safe to use with external buffers.
803
      */
804
749
      Data& clear() { return truncate2(0); };
805
806
      /**
807
        Takes the contents of the Data and converts them to an 
808
        integer. Will strip leading whitespace. This method stops
809
        upon encountering the first non-decimal digit (with exceptions
810
        made for leading negative signs).
811
      */ 
812
      int convertInt() const;
813
      unsigned long convertUnsignedLong() const;
814
815
      /**
816
        Takes the contents of the Data and converts them to a 
817
        size_t. Will strip leading whitespace. This method stops
818
        upon encountering the first non-decimal digit.
819
      */ 
820
      size_t convertSize() const;
821
822
#ifndef RESIP_FIXED_POINT
823
      /**
824
        Takes the contents of the Data and converts them to a 
825
        double precision floating point value. Will strip leading
826
        whitespace. This method stops upon encountering the first
827
        non-decimal digit (with exceptions made for decimal points
828
        and leading negative signs).
829
      */ 
830
      double convertDouble() const;
831
#endif
832
833
      /**
834
        Takes the contents of the Data and converts them to an
835
        unsigned 64-bit integer. Will strip leading whitespace.
836
        This method stops upon encountering the first non-decimal digit.
837
      */ 
838
      uint64_t convertUInt64() const;
839
840
      /**
841
        Returns true if this Data starts with the bytes indicated by
842
        the passed-in Data. For example, if this Data is "abc", then
843
        prefix(Data("ab")) would be true; however, prefix(Data("abcd"))
844
        would be false.
845
      */
846
      bool prefix(const Data& pre) const noexcept;
847
848
      /**
849
        Returns true if this Data ends with the bytes indicated by
850
        the passed-in Data. For example, if this Data is "abc", then
851
        postfix(Data("bc")) would be true; however, postfix(Data("ab"))
852
        would be false.
853
      */
854
      bool postfix(const Data& post) const noexcept;
855
856
      /**
857
        Copies a portion of this Data into a new Data.
858
 
859
        @param first Index of the first byte to copy
860
        @param count Number of bytes to copy
861
      */
862
      Data substr(size_type first, size_type count = Data::npos) const; 
863
864
      /**
865
        Finds a specified sequence of bytes in this Data.
866
867
        @param match The bytes to be found
868
869
        @param start Offset into this Data to start the search
870
871
        @returns An index to the start of the found bytes.
872
      */
873
      size_type find(const Data& match, size_type start = 0) const;
874
875
      /** 
876
          Replaces up to max occurrences of the bytes match with
877
          target. Returns the number of matches.
878
      */
879
      int replace(const Data& match, const Data& target, int max=INT_MAX);
880
      
881
      /**
882
        Constant that represents a zero-length data.
883
      */
884
      static const Data Empty;
885
886
      /**
887
         Represents an impossible position; returned to indicate failure to find.
888
      */
889
      static const size_type npos;
890
891
      /**
892
        Initializes Data class.
893
894
        @note This method is a link time constraint. Don't remove it.
895
      */
896
      static bool init(DataLocalSize<RESIP_DATA_LOCAL_SIZE> arg);
897
898
      /**
899
        Performs RFC 3548 Base 64 decoding of the contents of this data.
900
901
        @returns A new buffer containing the unencoded representation
902
      */
903
      Data base64decode() const;
904
905
      /**
906
        Performs RFC 3548 Base 64 encoding of the contents of this data.
907
908
        @returns A new buffer containing the base64 representation
909
      */
910
      Data base64encode(bool useUrlSafe=false) const;
911
912
      /**
913
        Creates a 32-bit hash based on the contents of the indicated
914
        buffer.
915
916
        @param c Pointer to the buffer to hash
917
        @param size Number of bytes to be hashed
918
      */
919
      static size_t rawHash(const unsigned char* c, size_t size);
920
921
      /**
922
        Creates a 32-bit hash based on the contents of this Data.
923
      */
924
      size_t hash() const;
925
926
      /**
927
        Creates a 32-bit hash based on the contents of the indicated
928
        buffer, after normalizing any alphabetic characters to lowercase.
929
930
        @param c Pointer to the buffer to hash
931
        @param size Number of bytes to be hashed
932
      */
933
      static size_t rawCaseInsensitiveHash(const unsigned char* c, size_t size);
934
935
      /**
936
        A faster version of rawCaseInsensitiveHash that has the same collision 
937
        properties if this Data is made up of RFC 3261 token characters.
938
939
        @param c Pointer to the buffer to hash
940
        @param size Number of bytes to be hashed
941
        @note This is not guaranteed to return the same value as 
942
            rawCaseInsensitiveHash.
943
      */
944
      static size_t rawCaseInsensitiveTokenHash(const unsigned char* c, size_t size);
945
946
      /**
947
        Creates a 32-bit hash based on the contents of this Data, after
948
        normalizing any alphabetic characters to lowercase.
949
      */
950
      size_t caseInsensitivehash() const;
951
952
      /**
953
        A faster version of caseInsensitiveHash that has the same collision 
954
        properties if this Data is made up of RFC 3261 token characters.
955
        @note This is not guaranteed to return the same value as 
956
            rawCaseInsensitiveHash.
957
      */
958
      size_t caseInsensitiveTokenHash() const;
959
960
      inline bool caseInsensitiveTokenCompare(const Data& rhs) const
961
0
      {
962
0
         if(mSize==rhs.mSize)
963
0
         {
964
0
            return sizeEqualCaseInsensitiveTokenCompare(rhs);
965
0
         }
966
0
         return false;
967
0
      }
968
969
      bool sizeEqualCaseInsensitiveTokenCompare(const Data& rhs) const;
970
971
      /**
972
         Creates a bitset reflecting the contents of this data (as a set)
973
         ie. "15eo" would have the bits 49, 53, 101, and 111 set to true, and
974
         all others set to false
975
      */
976
      static std::bitset<256> toBitset(const resip::Data& chars);
977
978
      /**
979
        Performs escaping of this Data according to the indicated
980
        Predicate.
981
982
        @param str          A stream to which the escaped representation
983
                            should be added.
984
985
        @param shouldEscape A functor which takes a single character
986
                            as a parameter, and returns true if the
987
                            character should be escaped, false if
988
                            it should not.
989
990
        @deprecated dlb -- pass a 256 array of bits rather than a function.
991
      */      
992
      template<class Predicate> EncodeStream& 
993
          escapeToStream(EncodeStream& str, 
994
                         Predicate shouldEscape) const;
995
996
      /**
997
        Performs escaping of this Data according to a bitset.
998
999
        @param str          A stream to which the escaped representation
1000
                            should be added.
1001
1002
        @param shouldEscape A bitset representing which chars should be escaped.
1003
      */      
1004
      std::ostream& escapeToStream(std::ostream& str, 
1005
                                   const std::bitset<256>& shouldEscape) const;
1006
1007
      static Data fromFile(const Data& filename);
1008
1009
   private:
1010
      /**
1011
        @deprecated use Data(ShareEnum ...)
1012
      */
1013
      Data(const char* buffer, size_type length, bool);
1014
1015
      /**
1016
        Used by string constructors
1017
      */
1018
      inline void initFromString(const char* str, size_type len);
1019
1020
      /**
1021
        Copies the contents of this data to a new buffer if the
1022
        Data does not own the current buffer.
1023
      */
1024
      void own() const;
1025
1026
      /**
1027
        @note Always allocates a new buffer
1028
      */
1029
      void resize(size_type newSize, bool copy);
1030
1031
      static bool isHex(unsigned char c);      
1032
1033
      /** Trade off between in-object and heap allocation
1034
          Larger LocalAlloc makes for larger objects that have Data members but
1035
          bulk allocation/deallocation of Data  members. */
1036
      enum {LocalAlloc = RESIP_DATA_LOCAL_SIZE };
1037
1038
      char* mBuf;
1039
      size_type mSize;
1040
      size_type mCapacity;
1041
      char mPreBuffer[LocalAlloc];
1042
      // Null terminator for mPreBuffer when mSize==LocalAlloc lands here; this
1043
      // is ok, because Borrow==0.
1044
      // Note: we could use a char here, and expand mPreBuffer by 3 bytes, but 
1045
      // this imposes a performance penalty since it requires operating on a 
1046
      // memory location smaller than a word (requires masking and such).
1047
      size_type mShareEnum;
1048
1049
      friend std::ostream& operator<<(std::ostream& strm, const Data& d);
1050
#ifndef RESIP_USE_STL_STREAMS
1051
      friend EncodeStream& operator<<(EncodeStream& strm, const Data& d);
1052
#endif
1053
      friend class ParseBuffer;
1054
      friend class DataBuffer;
1055
      friend class DataStream;
1056
      friend class oDataStream;
1057
      friend class ::TestData;
1058
      friend class MD5Buffer;
1059
};
1060
// reset alignment to previous value
1061
#pragma pack(pop)
1062
1063
1064
class DataHelper {
1065
   public:
1066
      static const bool isCharHex[256];
1067
};
1068
1069
static bool invokeDataInit = Data::init(DataLocalSize<RESIP_DATA_LOCAL_SIZE>(0));
1070
1071
inline bool Data::isHex(unsigned char c)
1072
0
{
1073
   // Shut up the warning about invokeDataInit defined, but not used
1074
0
   if(0){(void) invokeDataInit;}
1075
1076
0
   return DataHelper::isCharHex[c];
1077
0
}
1078
1079
inline bool isEqualNoCase(const Data& left, const Data& right)
1080
10.5M
{
1081
10.5M
   return ( (left.size() == right.size()) &&
1082
10.5M
            (strncasecmp(left.data(), right.data(), left.size()) == 0) );
1083
10.5M
}
1084
1085
inline bool isTokenEqualNoCase(const Data& left, const Data& right)
1086
0
{
1087
0
   return left.caseInsensitiveTokenCompare(right);
1088
0
}
1089
1090
inline bool isLessThanNoCase(const Data& left, const Data& right)
1091
0
{
1092
0
   size_t minsize = resipMin( left.size(), right.size() );
1093
0
   int res = strncasecmp(left.data(), right.data(), minsize);
1094
1095
0
   if (res < 0)
1096
0
   {
1097
0
      return true;
1098
0
   }
1099
0
   else if (res > 0)
1100
0
   {
1101
0
      return false;
1102
0
   }
1103
0
   else
1104
0
   {
1105
0
      return left.size() < right.size();
1106
0
   }
1107
0
}
1108
1109
template<class Predicate> EncodeStream& 
1110
Data::escapeToStream(EncodeStream& str, Predicate shouldEscape) const
1111
{
1112
   constexpr char hex[] = "0123456789ABCDEF";
1113
1114
   if (empty())
1115
   {
1116
      return str;
1117
   }
1118
   
1119
   const unsigned char* p = (unsigned char*)mBuf;
1120
   const unsigned char* e = (unsigned char*)mBuf + mSize;
1121
1122
   while (p < e)
1123
   {
1124
      // ?abr? Why is this special cased? Removing this code
1125
      // does not change the behavior of this method.
1126
      if (*p == '%' 
1127
          && e - p > 2 
1128
          && isHex(*(p+1)) 
1129
          && isHex(*(p+2)))
1130
      {
1131
         str.write((char*)p, 3);
1132
         p+=3;
1133
      }
1134
      else if (shouldEscape[*p])
1135
      {
1136
         int hi = (*p & 0xF0)>>4;
1137
         int low = (*p & 0x0F);
1138
1139
         str << '%' << hex[hi] << hex[low];
1140
         p++;
1141
      }
1142
      else
1143
      {
1144
         str.put(*p++);
1145
      }
1146
   }
1147
   return str;
1148
}
1149
1150
82.2k
inline bool operator!=(const Data& lhs, const Data& rhs) { return !(lhs == rhs); }
1151
0
inline bool operator>(const Data& lhs, const Data& rhs) { return rhs < lhs; }
1152
0
inline bool operator<=(const Data& lhs, const Data& rhs) { return !(rhs < lhs); }
1153
0
inline bool operator>=(const Data& lhs, const Data& rhs) { return !(lhs < rhs); }
1154
1155
0
inline bool operator!=(const Data& lhs, const char* rhs) { return !(lhs == rhs); }
1156
0
inline bool operator>(const Data& lhs, const char* rhs) { return rhs < lhs; }
1157
0
inline bool operator<=(const Data& lhs, const char* rhs) { return !(rhs < lhs); }
1158
0
inline bool operator>=(const Data& lhs, const char* rhs) { return !(lhs < rhs); }
1159
1160
0
inline bool operator==(const char* lhs, const Data& rhs) { return rhs == lhs; }
1161
0
inline bool operator!=(const char* lhs, const Data& rhs) { return !(rhs == lhs); }
1162
0
inline bool operator>(const char* lhs, const Data& rhs) { return rhs < lhs; }
1163
0
inline bool operator<=(const char* lhs, const Data& rhs) { return !(rhs < lhs); }
1164
0
inline bool operator>=(const char* lhs, const Data& rhs) { return !(lhs < rhs); }
1165
1166
0
inline bool operator!=(const Data& lhs, const std::string& rhs) noexcept { return !(lhs == rhs); }
1167
0
inline bool operator>(const Data& lhs, const std::string& rhs) { return rhs < lhs; }
1168
0
inline bool operator<=(const Data& lhs, const std::string& rhs) { return !(rhs < lhs); }
1169
0
inline bool operator>=(const Data& lhs, const std::string& rhs) { return !(lhs < rhs); }
1170
1171
0
inline bool operator==(const std::string& lhs, const Data& rhs) noexcept { return rhs == lhs; }
1172
0
inline bool operator!=(const std::string& lhs, const Data& rhs) noexcept { return !(rhs == lhs); }
1173
0
inline bool operator>(const std::string& lhs, const Data& rhs) { return rhs < lhs; }
1174
0
inline bool operator<=(const std::string& lhs, const Data& rhs) { return !(rhs < lhs); }
1175
0
inline bool operator>=(const std::string& lhs, const Data& rhs) { return !(lhs < rhs); }
1176
1177
#if RESIP_HAVE_STRING_VIEW
1178
0
inline bool operator!=(const Data& lhs, const std::string_view rhs) noexcept { return !(lhs == rhs); }
1179
0
inline bool operator>(const Data& lhs, const std::string_view rhs) { return rhs < lhs; }
1180
0
inline bool operator<=(const Data& lhs, const std::string_view rhs) { return !(rhs < lhs); }
1181
0
inline bool operator>=(const Data& lhs, const std::string_view rhs) { return !(lhs < rhs); }
1182
1183
0
inline bool operator==(const std::string_view lhs, const Data& rhs) noexcept { return rhs == lhs; }
1184
0
inline bool operator!=(const std::string_view lhs, const Data& rhs) noexcept { return !(rhs == lhs); }
1185
0
inline bool operator>(const std::string_view lhs, const Data& rhs) { return rhs < lhs; }
1186
0
inline bool operator<=(const std::string_view lhs, const Data& rhs) { return !(rhs < lhs); }
1187
0
inline bool operator>=(const std::string_view lhs, const Data& rhs) { return !(lhs < rhs); }
1188
#endif
1189
1190
#ifndef  RESIP_USE_STL_STREAMS
1191
EncodeStream& operator<<(EncodeStream& strm, const Data& d);
1192
#endif
1193
inline std::ostream& operator<<(std::ostream& strm, const Data& d)
1194
252k
{
1195
252k
   return strm.write(d.mBuf, d.mSize);
1196
252k
}
1197
1198
1199
inline Data
1200
operator+(const char* c, const Data& d)
1201
0
{
1202
0
   return Data(c) + d;
1203
0
}
1204
1205
bool operator==(const Data& lhs, const Data& rhs);
1206
bool operator==(const Data& lhs, const char* rhs);
1207
bool operator==(const Data& lhs, const std::string& rhs) noexcept;
1208
#if RESIP_HAVE_STRING_VIEW
1209
bool operator==(const Data& lhs, const std::string_view rhs) noexcept;
1210
#endif
1211
1212
bool operator<(const Data& lhs, const Data& rhs);
1213
bool operator<(const Data& lhs, const char* rhs);
1214
bool operator<(const char* lhs, const Data& rhs);
1215
bool operator<(const Data& lhs, const std::string& rhs) noexcept;
1216
bool operator<(const std::string& lhs, const Data& rhs) noexcept;
1217
#if RESIP_HAVE_STRING_VIEW
1218
bool operator<(const Data& lhs, const std::string_view rhs) noexcept;
1219
bool operator<(const std::string_view lhs, const Data& rhs) noexcept;
1220
#endif
1221
}
1222
1223
HashValue(resip::Data);
1224
1225
#endif
1226
1227
/* ====================================================================
1228
 * The Vovida Software License, Version 1.0 
1229
 * 
1230
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
1231
 * 
1232
 * Redistribution and use in source and binary forms, with or without
1233
 * modification, are permitted provided that the following conditions
1234
 * are met:
1235
 * 
1236
 * 1. Redistributions of source code must retain the above copyright
1237
 *    notice, this list of conditions and the following disclaimer.
1238
 * 
1239
 * 2. Redistributions in binary form must reproduce the above copyright
1240
 *    notice, this list of conditions and the following disclaimer in
1241
 *    the documentation and/or other materials provided with the
1242
 *    distribution.
1243
 * 
1244
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1245
 *    and "Vovida Open Communication Application Library (VOCAL)" must
1246
 *    not be used to endorse or promote products derived from this
1247
 *    software without prior written permission. For written
1248
 *    permission, please contact vocal@vovida.org.
1249
 *
1250
 * 4. Products derived from this software may not be called "VOCAL", nor
1251
 *    may "VOCAL" appear in their name, without prior written
1252
 *    permission of Vovida Networks, Inc.
1253
 * 
1254
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1255
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1256
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1257
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1258
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1259
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1260
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1261
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1262
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1263
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1264
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1265
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1266
 * DAMAGE.
1267
 * 
1268
 * ====================================================================
1269
 * 
1270
 * This software consists of voluntary contributions made by Vovida
1271
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1272
 * Inc.  For more information on Vovida Networks, Inc., please see
1273
 * <http://www.vovida.org/>.
1274
 *
1275
 * vi: set shiftwidth=3 expandtab:
1276
 */