quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

dynbuf.c (7016B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "../curl_setup.h"
     26 #include "dynbuf.h"
     27 #include "../curl_printf.h"
     28 #ifdef BUILDING_LIBCURL
     29 #include "../curl_memory.h"
     30 #endif
     31 #include "../memdebug.h"
     32 
     33 #define MIN_FIRST_ALLOC 32
     34 
     35 #ifdef DEBUGBUILD
     36 #define DYNINIT 0xbee51da /* random pattern */
     37 #endif
     38 
     39 /*
     40  * Init a dynbuf struct.
     41  */
     42 void curlx_dyn_init(struct dynbuf *s, size_t toobig)
     43 {
     44   DEBUGASSERT(s);
     45   DEBUGASSERT(toobig);
     46   DEBUGASSERT(toobig <= MAX_DYNBUF_SIZE); /* catch crazy mistakes */
     47   s->bufr = NULL;
     48   s->leng = 0;
     49   s->allc = 0;
     50   s->toobig = toobig;
     51 #ifdef DEBUGBUILD
     52   s->init = DYNINIT;
     53 #endif
     54 }
     55 
     56 /*
     57  * free the buffer and re-init the necessary fields. It does not touch the
     58  * 'init' field and thus this buffer can be reused to add data to again.
     59  */
     60 void curlx_dyn_free(struct dynbuf *s)
     61 {
     62   DEBUGASSERT(s);
     63   DEBUGASSERT(s->init == DYNINIT);
     64   Curl_safefree(s->bufr);
     65   s->leng = s->allc = 0;
     66 }
     67 
     68 /*
     69  * Store/append an chunk of memory to the dynbuf.
     70  */
     71 static CURLcode dyn_nappend(struct dynbuf *s,
     72                             const unsigned char *mem, size_t len)
     73 {
     74   size_t indx = s->leng;
     75   size_t a = s->allc;
     76   size_t fit = len + indx + 1; /* new string + old string + zero byte */
     77 
     78   /* try to detect if there is rubbish in the struct */
     79   DEBUGASSERT(s->init == DYNINIT);
     80   DEBUGASSERT(s->toobig);
     81   DEBUGASSERT(indx < s->toobig);
     82   DEBUGASSERT(!s->leng || s->bufr);
     83   DEBUGASSERT(a <= s->toobig);
     84   DEBUGASSERT(!len || mem);
     85 
     86   if(fit > s->toobig) {
     87     curlx_dyn_free(s);
     88     return CURLE_TOO_LARGE;
     89   }
     90   else if(!a) {
     91     DEBUGASSERT(!indx);
     92     /* first invoke */
     93     if(MIN_FIRST_ALLOC > s->toobig)
     94       a = s->toobig;
     95     else if(fit < MIN_FIRST_ALLOC)
     96       a = MIN_FIRST_ALLOC;
     97     else
     98       a = fit;
     99   }
    100   else {
    101     while(a < fit)
    102       a *= 2;
    103     if(a > s->toobig)
    104       /* no point in allocating a larger buffer than this is allowed to use */
    105       a = s->toobig;
    106   }
    107 
    108   if(a != s->allc) {
    109     /* this logic is not using Curl_saferealloc() to make the tool not have to
    110        include that as well when it uses this code */
    111     void *p = realloc(s->bufr, a);
    112     if(!p) {
    113       curlx_dyn_free(s);
    114       return CURLE_OUT_OF_MEMORY;
    115     }
    116     s->bufr = p;
    117     s->allc = a;
    118   }
    119 
    120   if(len)
    121     memcpy(&s->bufr[indx], mem, len);
    122   s->leng = indx + len;
    123   s->bufr[s->leng] = 0;
    124   return CURLE_OK;
    125 }
    126 
    127 /*
    128  * Clears the string, keeps the allocation. This can also be called on a
    129  * buffer that already was freed.
    130  */
    131 void curlx_dyn_reset(struct dynbuf *s)
    132 {
    133   DEBUGASSERT(s);
    134   DEBUGASSERT(s->init == DYNINIT);
    135   DEBUGASSERT(!s->leng || s->bufr);
    136   if(s->leng)
    137     s->bufr[0] = 0;
    138   s->leng = 0;
    139 }
    140 
    141 /*
    142  * Specify the size of the tail to keep (number of bytes from the end of the
    143  * buffer). The rest will be dropped.
    144  */
    145 CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail)
    146 {
    147   DEBUGASSERT(s);
    148   DEBUGASSERT(s->init == DYNINIT);
    149   DEBUGASSERT(!s->leng || s->bufr);
    150   if(trail > s->leng)
    151     return CURLE_BAD_FUNCTION_ARGUMENT;
    152   else if(trail == s->leng)
    153     return CURLE_OK;
    154   else if(!trail) {
    155     curlx_dyn_reset(s);
    156   }
    157   else {
    158     memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
    159     s->leng = trail;
    160     s->bufr[s->leng] = 0;
    161   }
    162   return CURLE_OK;
    163 
    164 }
    165 
    166 /*
    167  * Appends a buffer with length.
    168  */
    169 CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
    170 {
    171   DEBUGASSERT(s);
    172   DEBUGASSERT(s->init == DYNINIT);
    173   DEBUGASSERT(!s->leng || s->bufr);
    174   return dyn_nappend(s, mem, len);
    175 }
    176 
    177 /*
    178  * Append a null-terminated string at the end.
    179  */
    180 CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
    181 {
    182   size_t n;
    183   DEBUGASSERT(str);
    184   DEBUGASSERT(s);
    185   DEBUGASSERT(s->init == DYNINIT);
    186   DEBUGASSERT(!s->leng || s->bufr);
    187   n = strlen(str);
    188   return dyn_nappend(s, (const unsigned char *)str, n);
    189 }
    190 
    191 /*
    192  * Append a string vprintf()-style
    193  */
    194 CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
    195 {
    196 #ifdef BUILDING_LIBCURL
    197   int rc;
    198   DEBUGASSERT(s);
    199   DEBUGASSERT(s->init == DYNINIT);
    200   DEBUGASSERT(!s->leng || s->bufr);
    201   DEBUGASSERT(fmt);
    202   rc = curlx_dyn_vprintf(s, fmt, ap);
    203 
    204   if(!rc)
    205     return CURLE_OK;
    206   else if(rc == MERR_TOO_LARGE)
    207     return CURLE_TOO_LARGE;
    208   return CURLE_OUT_OF_MEMORY;
    209 #else
    210   char *str;
    211   str = curl_mvaprintf(fmt, ap); /* this allocs a new string to append */
    212 
    213   if(str) {
    214     CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
    215     free(str);
    216     return result;
    217   }
    218   /* If we failed, we cleanup the whole buffer and return error */
    219   curlx_dyn_free(s);
    220   return CURLE_OUT_OF_MEMORY;
    221 #endif
    222 }
    223 
    224 /*
    225  * Append a string printf()-style
    226  */
    227 CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
    228 {
    229   CURLcode result;
    230   va_list ap;
    231   DEBUGASSERT(s);
    232   DEBUGASSERT(s->init == DYNINIT);
    233   DEBUGASSERT(!s->leng || s->bufr);
    234   va_start(ap, fmt);
    235   result = curlx_dyn_vaddf(s, fmt, ap);
    236   va_end(ap);
    237   return result;
    238 }
    239 
    240 /*
    241  * Returns a pointer to the buffer.
    242  */
    243 char *curlx_dyn_ptr(const struct dynbuf *s)
    244 {
    245   DEBUGASSERT(s);
    246   DEBUGASSERT(s->init == DYNINIT);
    247   DEBUGASSERT(!s->leng || s->bufr);
    248   return s->bufr;
    249 }
    250 
    251 char *curlx_dyn_take(struct dynbuf *s, size_t *plen)
    252 {
    253   char *ptr = s->bufr;
    254   DEBUGASSERT(s);
    255   DEBUGASSERT(s->init == DYNINIT);
    256   *plen = s->leng;
    257   s->bufr = NULL;
    258   s->leng = 0;
    259   s->allc = 0;
    260   return ptr;
    261 }
    262 
    263 /*
    264  * Returns an unsigned pointer to the buffer.
    265  */
    266 unsigned char *curlx_dyn_uptr(const struct dynbuf *s)
    267 {
    268   DEBUGASSERT(s);
    269   DEBUGASSERT(s->init == DYNINIT);
    270   DEBUGASSERT(!s->leng || s->bufr);
    271   return (unsigned char *)s->bufr;
    272 }
    273 
    274 /*
    275  * Returns the length of the buffer.
    276  */
    277 size_t curlx_dyn_len(const struct dynbuf *s)
    278 {
    279   DEBUGASSERT(s);
    280   DEBUGASSERT(s->init == DYNINIT);
    281   DEBUGASSERT(!s->leng || s->bufr);
    282   return s->leng;
    283 }
    284 
    285 /*
    286  * Set a new (smaller) length.
    287  */
    288 CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set)
    289 {
    290   DEBUGASSERT(s);
    291   DEBUGASSERT(s->init == DYNINIT);
    292   DEBUGASSERT(!s->leng || s->bufr);
    293   if(set > s->leng)
    294     return CURLE_BAD_FUNCTION_ARGUMENT;
    295   s->leng = set;
    296   s->bufr[s->leng] = 0;
    297   return CURLE_OK;
    298 }