diff options
Diffstat (limited to 'third_party/sipcc/cpr_string.c')
-rw-r--r-- | third_party/sipcc/cpr_string.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/third_party/sipcc/cpr_string.c b/third_party/sipcc/cpr_string.c new file mode 100644 index 0000000000..1e97c186ae --- /dev/null +++ b/third_party/sipcc/cpr_string.c @@ -0,0 +1,278 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <stdarg.h> + +#include "mozilla/Assertions.h" +#include "cpr_types.h" +#include "cpr_string.h" +#include "cpr_strings.h" + +/* From cpr_stdlib.h */ +#ifdef CPR_STRING_USE_FALLIBLE_MALLOC +#define cpr_malloc(a) malloc(a) +#define cpr_calloc(a, b) calloc(a, b) +#define cpr_realloc(a, b) realloc(a, b) +#define cpr_free(a) free(a) +#else +#include "mozilla/mozalloc.h" + +#define cpr_malloc(a) moz_xmalloc(a) +#define cpr_calloc(a, b) moz_xcalloc(a, b) +#define cpr_realloc(a, b) moz_xrealloc(a, b) +#define cpr_free(a) free(a) +#endif + +/** + * sstrncpy + * + * This is Cisco's *safe* version of strncpy. The string will always + * be NUL terminated (which is not ANSI compliant). + * + * Parameters: s1 - first string + * s2 - second string + * max - maximum length in octets to concat. + * + * Return: Pointer to the *end* of the string + * + * Remarks: Modified to be explicitly safe for all inputs. + * Also return the number of characters copied excluding the + * NUL terminator vs. the original string s1. This simplifies + * code where sstrncat functions follow. + */ +unsigned long +sstrncpy (char *dst, const char *src, unsigned long max) +{ + unsigned long cnt = 0; + + if (dst == NULL) { + return 0; + } + + if (src) { + while ((max-- > 1) && (*src)) { + *dst = *src; + dst++; + src++; + cnt++; + } + } + +#if defined(CPR_SSTRNCPY_PAD) + /* + * To be equivalent to the TI compiler version + * v2.01, SSTRNCPY_PAD needs to be defined + */ + while (max-- > 1) { + *dst = '\0'; + dst++; + } +#endif + *dst = '\0'; + + return cnt; +} + +/** + * sstrncat + * + * This is Cisco's *safe* version of strncat. The string will always + * be NUL terminated (which is not ANSI compliant). + * + * Parameters: s1 - first string + * s2 - second string + * max - maximum length in octets to concatenate + * + * Return: Pointer to the *end* of the string + * + * Remarks: Modified to be explicitly safe for all inputs. + * Also return the end vs. the beginning of the string s1 + * which is useful for multiple sstrncat calls. + */ +char * +sstrncat (char *s1, const char *s2, unsigned long max) +{ + if (s1 == NULL) + return (char *) NULL; + + while (*s1) + s1++; + + if (s2) { + while ((max-- > 1) && (*s2)) { + *s1 = *s2; + s1++; + s2++; + } + } + *s1 = '\0'; + + return s1; +} + +/* + * flex_string + */ + +/* + * flex_string_init + * + * Not thread-safe + */ +void flex_string_init(flex_string *fs) { + fs->buffer_length = FLEX_STRING_CHUNK_SIZE; + fs->string_length = 0; + fs->buffer = cpr_malloc(fs->buffer_length); + fs->buffer[0] = '\0'; +} + +/* + * flex_string_free + * + * Not thread-safe + */ +void flex_string_free(flex_string *fs) { + fs->buffer_length = 0; + fs->string_length = 0; + cpr_free(fs->buffer); + fs->buffer = NULL; +} + +/* For sanity check before alloc */ +#define FLEX_STRING_MAX_SIZE (10 * 1024 * 1024) /* 10MB */ + +/* + * flex_string_check_alloc + * + * Allocate enough chunks to hold the new minimum size. + * + * Not thread-safe + */ +void flex_string_check_alloc(flex_string *fs, size_t new_min_length) { + if (new_min_length > fs->buffer_length) { + /* Oversize, allocate more */ + + /* Sanity check on allocation size */ + if (new_min_length > FLEX_STRING_MAX_SIZE) { + MOZ_CRASH(); + } + + /* Alloc to nearest chunk */ + fs->buffer_length = (((new_min_length - 1) / FLEX_STRING_CHUNK_SIZE) + 1) * FLEX_STRING_CHUNK_SIZE; + + fs->buffer = cpr_realloc(fs->buffer, fs->buffer_length); + } +} + +/* + * flex_string_append + * + * Not thread-safe + */ +void flex_string_append(flex_string *fs, const char *more) { + fs->string_length += strlen(more); + + flex_string_check_alloc(fs, fs->string_length + 1); + + sstrncat(fs->buffer, more, fs->buffer_length - strlen(fs->buffer)); +} + +/* + * va_copy is part of the C99 spec but MSVC doesn't have it. + */ +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +/* + * flex_string_vsprintf + * + * Not thread-safe + */ +void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap) { + va_list ap; + int vsnprintf_result; + + va_copy(ap, original_ap); + vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap); + va_end(ap); + + /* Special case just for Windows where vsnprintf is broken + and returns -1 if buffer too large unless you size it 0. */ + if (vsnprintf_result < 0) { + va_copy(ap, original_ap); + vsnprintf_result = vsnprintf(NULL, 0, format, ap); + va_end(ap); + } + + if (fs->string_length + vsnprintf_result >= fs->buffer_length) { + /* Buffer overflow, resize */ + flex_string_check_alloc(fs, fs->string_length + vsnprintf_result + 1); + + /* Try again with new buffer */ + va_copy(ap, original_ap); + vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap); + va_end(ap); + MOZ_ASSERT(vsnprintf_result > 0 && + (size_t)vsnprintf_result < (fs->buffer_length - fs->string_length)); + } + + if (vsnprintf_result > 0) { + fs->string_length += vsnprintf_result; + } +} + +/* + * flex_string_sprintf + * + * Not thread-safe + */ +void flex_string_sprintf(flex_string *fs, const char *format, ...) { + va_list ap; + + va_start(ap, format); + flex_string_vsprintf(fs, format, ap); + va_end(ap); +} + + + +/* From cpr_linux_string.c */ +/** + * cpr_strdup + * + * @brief The CPR wrapper for strdup + + * The cpr_strdup shall return a pointer to a new string, which is a duplicate + * of the string pointed to by "str" argument. A null pointer is returned if the + * new string cannot be created. + * + * @param[in] str - The string that needs to be duplicated + * + * @return The duplicated string or NULL in case of no memory + * + */ +char * +cpr_strdup (const char *str) +{ + char *dup; + size_t len; + + if (!str) { + return (char *) NULL; + } + + len = strlen(str); + if (len == 0) { + return (char *) NULL; + } + len++; + + dup = cpr_malloc(len * sizeof(char)); + if (!dup) { + return (char *) NULL; + } + (void) memcpy(dup, str, len); + return dup; +} |