Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include <stdarg.h>
6 :
7 : #include "mozilla/Assertions.h"
8 : #include "cpr_types.h"
9 : #include "cpr_string.h"
10 : #include "cpr_strings.h"
11 :
12 : /* From cpr_stdlib.h */
13 : #ifdef CPR_STRING_USE_FALLIBLE_MALLOC
14 : #define cpr_malloc(a) malloc(a)
15 : #define cpr_calloc(a, b) calloc(a, b)
16 : #define cpr_realloc(a, b) realloc(a, b)
17 : #define cpr_free(a) free(a)
18 : #else
19 : #include "mozilla/mozalloc.h"
20 :
21 : #define cpr_malloc(a) moz_xmalloc(a)
22 : #define cpr_calloc(a, b) moz_xcalloc(a, b)
23 : #define cpr_realloc(a, b) moz_xrealloc(a, b)
24 : #define cpr_free(a) free(a)
25 : #endif
26 :
27 : /**
28 : * sstrncpy
29 : *
30 : * This is Cisco's *safe* version of strncpy. The string will always
31 : * be NUL terminated (which is not ANSI compliant).
32 : *
33 : * Parameters: s1 - first string
34 : * s2 - second string
35 : * max - maximum length in octets to concat.
36 : *
37 : * Return: Pointer to the *end* of the string
38 : *
39 : * Remarks: Modified to be explicitly safe for all inputs.
40 : * Also return the number of characters copied excluding the
41 : * NUL terminator vs. the original string s1. This simplifies
42 : * code where sstrncat functions follow.
43 : */
44 : unsigned long
45 0 : sstrncpy (char *dst, const char *src, unsigned long max)
46 : {
47 0 : unsigned long cnt = 0;
48 :
49 0 : if (dst == NULL) {
50 0 : return 0;
51 : }
52 :
53 0 : if (src) {
54 0 : while ((max-- > 1) && (*src)) {
55 0 : *dst = *src;
56 0 : dst++;
57 0 : src++;
58 0 : cnt++;
59 : }
60 : }
61 :
62 : #if defined(CPR_SSTRNCPY_PAD)
63 : /*
64 : * To be equivalent to the TI compiler version
65 : * v2.01, SSTRNCPY_PAD needs to be defined
66 : */
67 : while (max-- > 1) {
68 : *dst = '\0';
69 : dst++;
70 : }
71 : #endif
72 0 : *dst = '\0';
73 :
74 0 : return cnt;
75 : }
76 :
77 : /**
78 : * sstrncat
79 : *
80 : * This is Cisco's *safe* version of strncat. The string will always
81 : * be NUL terminated (which is not ANSI compliant).
82 : *
83 : * Parameters: s1 - first string
84 : * s2 - second string
85 : * max - maximum length in octets to concatenate
86 : *
87 : * Return: Pointer to the *end* of the string
88 : *
89 : * Remarks: Modified to be explicitly safe for all inputs.
90 : * Also return the end vs. the beginning of the string s1
91 : * which is useful for multiple sstrncat calls.
92 : */
93 : char *
94 0 : sstrncat (char *s1, const char *s2, unsigned long max)
95 : {
96 0 : if (s1 == NULL)
97 0 : return (char *) NULL;
98 :
99 0 : while (*s1)
100 0 : s1++;
101 :
102 0 : if (s2) {
103 0 : while ((max-- > 1) && (*s2)) {
104 0 : *s1 = *s2;
105 0 : s1++;
106 0 : s2++;
107 : }
108 : }
109 0 : *s1 = '\0';
110 :
111 0 : return s1;
112 : }
113 :
114 : /*
115 : * flex_string
116 : */
117 :
118 : /*
119 : * flex_string_init
120 : *
121 : * Not thread-safe
122 : */
123 0 : void flex_string_init(flex_string *fs) {
124 0 : fs->buffer_length = FLEX_STRING_CHUNK_SIZE;
125 0 : fs->string_length = 0;
126 0 : fs->buffer = cpr_malloc(fs->buffer_length);
127 0 : fs->buffer[0] = '\0';
128 0 : }
129 :
130 : /*
131 : * flex_string_free
132 : *
133 : * Not thread-safe
134 : */
135 0 : void flex_string_free(flex_string *fs) {
136 0 : fs->buffer_length = 0;
137 0 : fs->string_length = 0;
138 0 : cpr_free(fs->buffer);
139 0 : fs->buffer = NULL;
140 0 : }
141 :
142 : /* For sanity check before alloc */
143 : #define FLEX_STRING_MAX_SIZE (10 * 1024 * 1024) /* 10MB */
144 :
145 : /*
146 : * flex_string_check_alloc
147 : *
148 : * Allocate enough chunks to hold the new minimum size.
149 : *
150 : * Not thread-safe
151 : */
152 0 : void flex_string_check_alloc(flex_string *fs, size_t new_min_length) {
153 0 : if (new_min_length > fs->buffer_length) {
154 : /* Oversize, allocate more */
155 :
156 : /* Sanity check on allocation size */
157 0 : if (new_min_length > FLEX_STRING_MAX_SIZE) {
158 0 : MOZ_CRASH();
159 : }
160 :
161 : /* Alloc to nearest chunk */
162 0 : fs->buffer_length = (((new_min_length - 1) / FLEX_STRING_CHUNK_SIZE) + 1) * FLEX_STRING_CHUNK_SIZE;
163 :
164 0 : fs->buffer = cpr_realloc(fs->buffer, fs->buffer_length);
165 : }
166 0 : }
167 :
168 : /*
169 : * flex_string_append
170 : *
171 : * Not thread-safe
172 : */
173 0 : void flex_string_append(flex_string *fs, const char *more) {
174 0 : fs->string_length += strlen(more);
175 :
176 0 : flex_string_check_alloc(fs, fs->string_length + 1);
177 :
178 0 : sstrncat(fs->buffer, more, fs->buffer_length - strlen(fs->buffer));
179 0 : }
180 :
181 : /*
182 : * va_copy is part of the C99 spec but MSVC doesn't have it.
183 : */
184 : #ifndef va_copy
185 : #define va_copy(d,s) ((d) = (s))
186 : #endif
187 :
188 : /*
189 : * flex_string_vsprintf
190 : *
191 : * Not thread-safe
192 : */
193 0 : void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap) {
194 : va_list ap;
195 : int vsnprintf_result;
196 :
197 0 : va_copy(ap, original_ap);
198 0 : vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap);
199 0 : va_end(ap);
200 :
201 : /* Special case just for Windows where vsnprintf is broken
202 : and returns -1 if buffer too large unless you size it 0. */
203 0 : if (vsnprintf_result < 0) {
204 0 : va_copy(ap, original_ap);
205 0 : vsnprintf_result = vsnprintf(NULL, 0, format, ap);
206 0 : va_end(ap);
207 : }
208 :
209 0 : if (fs->string_length + vsnprintf_result >= fs->buffer_length) {
210 : /* Buffer overflow, resize */
211 0 : flex_string_check_alloc(fs, fs->string_length + vsnprintf_result + 1);
212 :
213 : /* Try again with new buffer */
214 0 : va_copy(ap, original_ap);
215 0 : vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap);
216 0 : va_end(ap);
217 0 : MOZ_ASSERT(vsnprintf_result > 0 &&
218 : (size_t)vsnprintf_result < (fs->buffer_length - fs->string_length));
219 : }
220 :
221 0 : if (vsnprintf_result > 0) {
222 0 : fs->string_length += vsnprintf_result;
223 : }
224 0 : }
225 :
226 : /*
227 : * flex_string_sprintf
228 : *
229 : * Not thread-safe
230 : */
231 0 : void flex_string_sprintf(flex_string *fs, const char *format, ...) {
232 : va_list ap;
233 :
234 0 : va_start(ap, format);
235 0 : flex_string_vsprintf(fs, format, ap);
236 0 : va_end(ap);
237 0 : }
238 :
239 :
240 :
241 : /* From cpr_linux_string.c */
242 : /**
243 : * cpr_strdup
244 : *
245 : * @brief The CPR wrapper for strdup
246 :
247 : * The cpr_strdup shall return a pointer to a new string, which is a duplicate
248 : * of the string pointed to by "str" argument. A null pointer is returned if the
249 : * new string cannot be created.
250 : *
251 : * @param[in] str - The string that needs to be duplicated
252 : *
253 : * @return The duplicated string or NULL in case of no memory
254 : *
255 : */
256 : char *
257 0 : cpr_strdup (const char *str)
258 : {
259 : char *dup;
260 : size_t len;
261 :
262 0 : if (!str) {
263 0 : return (char *) NULL;
264 : }
265 :
266 0 : len = strlen(str);
267 0 : if (len == 0) {
268 0 : return (char *) NULL;
269 : }
270 0 : len++;
271 :
272 0 : dup = cpr_malloc(len * sizeof(char));
273 0 : if (!dup) {
274 0 : return (char *) NULL;
275 : }
276 0 : (void) memcpy(dup, str, len);
277 0 : return dup;
278 : }
|