/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 | | */ |