113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci#include "dynbuf.h" 2713498266Sopenharmony_ci#include "curl_printf.h" 2813498266Sopenharmony_ci#ifdef BUILDING_LIBCURL 2913498266Sopenharmony_ci#include "curl_memory.h" 3013498266Sopenharmony_ci#endif 3113498266Sopenharmony_ci#include "memdebug.h" 3213498266Sopenharmony_ci 3313498266Sopenharmony_ci#define MIN_FIRST_ALLOC 32 3413498266Sopenharmony_ci 3513498266Sopenharmony_ci#define DYNINIT 0xbee51da /* random pattern */ 3613498266Sopenharmony_ci 3713498266Sopenharmony_ci/* 3813498266Sopenharmony_ci * Init a dynbuf struct. 3913498266Sopenharmony_ci */ 4013498266Sopenharmony_civoid Curl_dyn_init(struct dynbuf *s, size_t toobig) 4113498266Sopenharmony_ci{ 4213498266Sopenharmony_ci DEBUGASSERT(s); 4313498266Sopenharmony_ci DEBUGASSERT(toobig); 4413498266Sopenharmony_ci s->bufr = NULL; 4513498266Sopenharmony_ci s->leng = 0; 4613498266Sopenharmony_ci s->allc = 0; 4713498266Sopenharmony_ci s->toobig = toobig; 4813498266Sopenharmony_ci#ifdef DEBUGBUILD 4913498266Sopenharmony_ci s->init = DYNINIT; 5013498266Sopenharmony_ci#endif 5113498266Sopenharmony_ci} 5213498266Sopenharmony_ci 5313498266Sopenharmony_ci/* 5413498266Sopenharmony_ci * free the buffer and re-init the necessary fields. It doesn't touch the 5513498266Sopenharmony_ci * 'init' field and thus this buffer can be reused to add data to again. 5613498266Sopenharmony_ci */ 5713498266Sopenharmony_civoid Curl_dyn_free(struct dynbuf *s) 5813498266Sopenharmony_ci{ 5913498266Sopenharmony_ci DEBUGASSERT(s); 6013498266Sopenharmony_ci Curl_safefree(s->bufr); 6113498266Sopenharmony_ci s->leng = s->allc = 0; 6213498266Sopenharmony_ci} 6313498266Sopenharmony_ci 6413498266Sopenharmony_ci/* 6513498266Sopenharmony_ci * Store/append an chunk of memory to the dynbuf. 6613498266Sopenharmony_ci */ 6713498266Sopenharmony_cistatic CURLcode dyn_nappend(struct dynbuf *s, 6813498266Sopenharmony_ci const unsigned char *mem, size_t len) 6913498266Sopenharmony_ci{ 7013498266Sopenharmony_ci size_t indx = s->leng; 7113498266Sopenharmony_ci size_t a = s->allc; 7213498266Sopenharmony_ci size_t fit = len + indx + 1; /* new string + old string + zero byte */ 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci /* try to detect if there's rubbish in the struct */ 7513498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 7613498266Sopenharmony_ci DEBUGASSERT(s->toobig); 7713498266Sopenharmony_ci DEBUGASSERT(indx < s->toobig); 7813498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 7913498266Sopenharmony_ci DEBUGASSERT(a <= s->toobig); 8013498266Sopenharmony_ci DEBUGASSERT(!len || mem); 8113498266Sopenharmony_ci 8213498266Sopenharmony_ci if(fit > s->toobig) { 8313498266Sopenharmony_ci Curl_dyn_free(s); 8413498266Sopenharmony_ci return CURLE_TOO_LARGE; 8513498266Sopenharmony_ci } 8613498266Sopenharmony_ci else if(!a) { 8713498266Sopenharmony_ci DEBUGASSERT(!indx); 8813498266Sopenharmony_ci /* first invoke */ 8913498266Sopenharmony_ci if(MIN_FIRST_ALLOC > s->toobig) 9013498266Sopenharmony_ci a = s->toobig; 9113498266Sopenharmony_ci else if(fit < MIN_FIRST_ALLOC) 9213498266Sopenharmony_ci a = MIN_FIRST_ALLOC; 9313498266Sopenharmony_ci else 9413498266Sopenharmony_ci a = fit; 9513498266Sopenharmony_ci } 9613498266Sopenharmony_ci else { 9713498266Sopenharmony_ci while(a < fit) 9813498266Sopenharmony_ci a *= 2; 9913498266Sopenharmony_ci if(a > s->toobig) 10013498266Sopenharmony_ci /* no point in allocating a larger buffer than this is allowed to use */ 10113498266Sopenharmony_ci a = s->toobig; 10213498266Sopenharmony_ci } 10313498266Sopenharmony_ci 10413498266Sopenharmony_ci if(a != s->allc) { 10513498266Sopenharmony_ci /* this logic is not using Curl_saferealloc() to make the tool not have to 10613498266Sopenharmony_ci include that as well when it uses this code */ 10713498266Sopenharmony_ci void *p = realloc(s->bufr, a); 10813498266Sopenharmony_ci if(!p) { 10913498266Sopenharmony_ci Curl_dyn_free(s); 11013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 11113498266Sopenharmony_ci } 11213498266Sopenharmony_ci s->bufr = p; 11313498266Sopenharmony_ci s->allc = a; 11413498266Sopenharmony_ci } 11513498266Sopenharmony_ci 11613498266Sopenharmony_ci if(len) 11713498266Sopenharmony_ci memcpy(&s->bufr[indx], mem, len); 11813498266Sopenharmony_ci s->leng = indx + len; 11913498266Sopenharmony_ci s->bufr[s->leng] = 0; 12013498266Sopenharmony_ci return CURLE_OK; 12113498266Sopenharmony_ci} 12213498266Sopenharmony_ci 12313498266Sopenharmony_ci/* 12413498266Sopenharmony_ci * Clears the string, keeps the allocation. This can also be called on a 12513498266Sopenharmony_ci * buffer that already was freed. 12613498266Sopenharmony_ci */ 12713498266Sopenharmony_civoid Curl_dyn_reset(struct dynbuf *s) 12813498266Sopenharmony_ci{ 12913498266Sopenharmony_ci DEBUGASSERT(s); 13013498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 13113498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 13213498266Sopenharmony_ci if(s->leng) 13313498266Sopenharmony_ci s->bufr[0] = 0; 13413498266Sopenharmony_ci s->leng = 0; 13513498266Sopenharmony_ci} 13613498266Sopenharmony_ci 13713498266Sopenharmony_ci/* 13813498266Sopenharmony_ci * Specify the size of the tail to keep (number of bytes from the end of the 13913498266Sopenharmony_ci * buffer). The rest will be dropped. 14013498266Sopenharmony_ci */ 14113498266Sopenharmony_ciCURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail) 14213498266Sopenharmony_ci{ 14313498266Sopenharmony_ci DEBUGASSERT(s); 14413498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 14513498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 14613498266Sopenharmony_ci if(trail > s->leng) 14713498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 14813498266Sopenharmony_ci else if(trail == s->leng) 14913498266Sopenharmony_ci return CURLE_OK; 15013498266Sopenharmony_ci else if(!trail) { 15113498266Sopenharmony_ci Curl_dyn_reset(s); 15213498266Sopenharmony_ci } 15313498266Sopenharmony_ci else { 15413498266Sopenharmony_ci memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail); 15513498266Sopenharmony_ci s->leng = trail; 15613498266Sopenharmony_ci s->bufr[s->leng] = 0; 15713498266Sopenharmony_ci } 15813498266Sopenharmony_ci return CURLE_OK; 15913498266Sopenharmony_ci 16013498266Sopenharmony_ci} 16113498266Sopenharmony_ci 16213498266Sopenharmony_ci/* 16313498266Sopenharmony_ci * Appends a buffer with length. 16413498266Sopenharmony_ci */ 16513498266Sopenharmony_ciCURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len) 16613498266Sopenharmony_ci{ 16713498266Sopenharmony_ci DEBUGASSERT(s); 16813498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 16913498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 17013498266Sopenharmony_ci return dyn_nappend(s, mem, len); 17113498266Sopenharmony_ci} 17213498266Sopenharmony_ci 17313498266Sopenharmony_ci/* 17413498266Sopenharmony_ci * Append a null-terminated string at the end. 17513498266Sopenharmony_ci */ 17613498266Sopenharmony_ciCURLcode Curl_dyn_add(struct dynbuf *s, const char *str) 17713498266Sopenharmony_ci{ 17813498266Sopenharmony_ci size_t n; 17913498266Sopenharmony_ci DEBUGASSERT(str); 18013498266Sopenharmony_ci DEBUGASSERT(s); 18113498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 18213498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 18313498266Sopenharmony_ci n = strlen(str); 18413498266Sopenharmony_ci return dyn_nappend(s, (unsigned char *)str, n); 18513498266Sopenharmony_ci} 18613498266Sopenharmony_ci 18713498266Sopenharmony_ci/* 18813498266Sopenharmony_ci * Append a string vprintf()-style 18913498266Sopenharmony_ci */ 19013498266Sopenharmony_ciCURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) 19113498266Sopenharmony_ci{ 19213498266Sopenharmony_ci#ifdef BUILDING_LIBCURL 19313498266Sopenharmony_ci int rc; 19413498266Sopenharmony_ci DEBUGASSERT(s); 19513498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 19613498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 19713498266Sopenharmony_ci DEBUGASSERT(fmt); 19813498266Sopenharmony_ci rc = Curl_dyn_vprintf(s, fmt, ap); 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci if(!rc) 20113498266Sopenharmony_ci return CURLE_OK; 20213498266Sopenharmony_ci else if(rc == MERR_TOO_LARGE) 20313498266Sopenharmony_ci return CURLE_TOO_LARGE; 20413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 20513498266Sopenharmony_ci#else 20613498266Sopenharmony_ci char *str; 20713498266Sopenharmony_ci str = vaprintf(fmt, ap); /* this allocs a new string to append */ 20813498266Sopenharmony_ci 20913498266Sopenharmony_ci if(str) { 21013498266Sopenharmony_ci CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str)); 21113498266Sopenharmony_ci free(str); 21213498266Sopenharmony_ci return result; 21313498266Sopenharmony_ci } 21413498266Sopenharmony_ci /* If we failed, we cleanup the whole buffer and return error */ 21513498266Sopenharmony_ci Curl_dyn_free(s); 21613498266Sopenharmony_ci return CURLE_OK; 21713498266Sopenharmony_ci#endif 21813498266Sopenharmony_ci} 21913498266Sopenharmony_ci 22013498266Sopenharmony_ci/* 22113498266Sopenharmony_ci * Append a string printf()-style 22213498266Sopenharmony_ci */ 22313498266Sopenharmony_ciCURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...) 22413498266Sopenharmony_ci{ 22513498266Sopenharmony_ci CURLcode result; 22613498266Sopenharmony_ci va_list ap; 22713498266Sopenharmony_ci DEBUGASSERT(s); 22813498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 22913498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 23013498266Sopenharmony_ci va_start(ap, fmt); 23113498266Sopenharmony_ci result = Curl_dyn_vaddf(s, fmt, ap); 23213498266Sopenharmony_ci va_end(ap); 23313498266Sopenharmony_ci return result; 23413498266Sopenharmony_ci} 23513498266Sopenharmony_ci 23613498266Sopenharmony_ci/* 23713498266Sopenharmony_ci * Returns a pointer to the buffer. 23813498266Sopenharmony_ci */ 23913498266Sopenharmony_cichar *Curl_dyn_ptr(const struct dynbuf *s) 24013498266Sopenharmony_ci{ 24113498266Sopenharmony_ci DEBUGASSERT(s); 24213498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 24313498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 24413498266Sopenharmony_ci return s->bufr; 24513498266Sopenharmony_ci} 24613498266Sopenharmony_ci 24713498266Sopenharmony_ci/* 24813498266Sopenharmony_ci * Returns an unsigned pointer to the buffer. 24913498266Sopenharmony_ci */ 25013498266Sopenharmony_ciunsigned char *Curl_dyn_uptr(const struct dynbuf *s) 25113498266Sopenharmony_ci{ 25213498266Sopenharmony_ci DEBUGASSERT(s); 25313498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 25413498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 25513498266Sopenharmony_ci return (unsigned char *)s->bufr; 25613498266Sopenharmony_ci} 25713498266Sopenharmony_ci 25813498266Sopenharmony_ci/* 25913498266Sopenharmony_ci * Returns the length of the buffer. 26013498266Sopenharmony_ci */ 26113498266Sopenharmony_cisize_t Curl_dyn_len(const struct dynbuf *s) 26213498266Sopenharmony_ci{ 26313498266Sopenharmony_ci DEBUGASSERT(s); 26413498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 26513498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 26613498266Sopenharmony_ci return s->leng; 26713498266Sopenharmony_ci} 26813498266Sopenharmony_ci 26913498266Sopenharmony_ci/* 27013498266Sopenharmony_ci * Set a new (smaller) length. 27113498266Sopenharmony_ci */ 27213498266Sopenharmony_ciCURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set) 27313498266Sopenharmony_ci{ 27413498266Sopenharmony_ci DEBUGASSERT(s); 27513498266Sopenharmony_ci DEBUGASSERT(s->init == DYNINIT); 27613498266Sopenharmony_ci DEBUGASSERT(!s->leng || s->bufr); 27713498266Sopenharmony_ci if(set > s->leng) 27813498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 27913498266Sopenharmony_ci s->leng = set; 28013498266Sopenharmony_ci s->bufr[s->leng] = 0; 28113498266Sopenharmony_ci return CURLE_OK; 28213498266Sopenharmony_ci} 283