dynbuf.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2020, 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.haxx.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. ***************************************************************************/
  22. #include "curl_setup.h"
  23. #include "strdup.h"
  24. #include "dynbuf.h"
  25. /* The last 3 #include files should be in this order */
  26. #include "curl_printf.h"
  27. #include "curl_memory.h"
  28. #include "memdebug.h"
  29. #define MIN_FIRST_ALLOC 32
  30. #define DYNINIT 0xbee51da /* random pattern */
  31. /*
  32. * Init a dynbuf struct.
  33. */
  34. void Curl_dyn_init(struct dynbuf *s, size_t toobig)
  35. {
  36. DEBUGASSERT(s);
  37. DEBUGASSERT(toobig);
  38. s->bufr = NULL;
  39. s->leng = 0;
  40. s->allc = 0;
  41. s->toobig = toobig;
  42. #ifdef DEBUGBUILD
  43. s->init = DYNINIT;
  44. #endif
  45. }
  46. /*
  47. * free the buffer and re-init the necessary fields. It doesn't touch the
  48. * 'init' field and thus this buffer can be reused to add data to again.
  49. */
  50. void Curl_dyn_free(struct dynbuf *s)
  51. {
  52. DEBUGASSERT(s);
  53. Curl_safefree(s->bufr);
  54. s->leng = s->allc = 0;
  55. }
  56. /*
  57. * Store/append an chunk of memory to the dynbuf.
  58. */
  59. static CURLcode dyn_nappend(struct dynbuf *s,
  60. const unsigned char *mem, size_t len)
  61. {
  62. size_t indx = s->leng;
  63. size_t a = s->allc;
  64. size_t fit = len + indx + 1; /* new string + old string + zero byte */
  65. /* try to detect if there's rubbish in the struct */
  66. DEBUGASSERT(s->init == DYNINIT);
  67. DEBUGASSERT(s->toobig);
  68. DEBUGASSERT(indx < s->toobig);
  69. DEBUGASSERT(!s->leng || s->bufr);
  70. if(fit > s->toobig) {
  71. Curl_dyn_free(s);
  72. return CURLE_OUT_OF_MEMORY;
  73. }
  74. else if(!a) {
  75. DEBUGASSERT(!indx);
  76. /* first invoke */
  77. if(fit < MIN_FIRST_ALLOC)
  78. a = MIN_FIRST_ALLOC;
  79. else
  80. a = fit;
  81. }
  82. else {
  83. while(a < fit)
  84. a *= 2;
  85. }
  86. if(a != s->allc) {
  87. s->bufr = Curl_saferealloc(s->bufr, a);
  88. if(!s->bufr) {
  89. s->leng = s->allc = 0;
  90. return CURLE_OUT_OF_MEMORY;
  91. }
  92. s->allc = a;
  93. }
  94. if(len)
  95. memcpy(&s->bufr[indx], mem, len);
  96. s->leng = indx + len;
  97. s->bufr[s->leng] = 0;
  98. return CURLE_OK;
  99. }
  100. /*
  101. * Clears the string, keeps the allocation. This can also be called on a
  102. * buffer that already was freed.
  103. */
  104. void Curl_dyn_reset(struct dynbuf *s)
  105. {
  106. DEBUGASSERT(s);
  107. DEBUGASSERT(s->init == DYNINIT);
  108. DEBUGASSERT(!s->leng || s->bufr);
  109. if(s->leng)
  110. s->bufr[0] = 0;
  111. s->leng = 0;
  112. }
  113. #ifdef USE_NGTCP2
  114. /*
  115. * Specify the size of the tail to keep (number of bytes from the end of the
  116. * buffer). The rest will be dropped.
  117. */
  118. CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
  119. {
  120. DEBUGASSERT(s);
  121. DEBUGASSERT(s->init == DYNINIT);
  122. DEBUGASSERT(!s->leng || s->bufr);
  123. if(trail > s->leng)
  124. return CURLE_BAD_FUNCTION_ARGUMENT;
  125. else if(trail == s->leng)
  126. return CURLE_OK;
  127. else if(!trail) {
  128. Curl_dyn_reset(s);
  129. }
  130. else {
  131. memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
  132. s->leng = trail;
  133. }
  134. return CURLE_OK;
  135. }
  136. #endif
  137. /*
  138. * Appends a buffer with length.
  139. */
  140. CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
  141. {
  142. DEBUGASSERT(s);
  143. DEBUGASSERT(s->init == DYNINIT);
  144. DEBUGASSERT(!s->leng || s->bufr);
  145. return dyn_nappend(s, mem, len);
  146. }
  147. /*
  148. * Append a zero terminated string at the end.
  149. */
  150. CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
  151. {
  152. size_t n = strlen(str);
  153. DEBUGASSERT(s);
  154. DEBUGASSERT(s->init == DYNINIT);
  155. DEBUGASSERT(!s->leng || s->bufr);
  156. return dyn_nappend(s, (unsigned char *)str, n);
  157. }
  158. /*
  159. * Append a string printf()-style
  160. */
  161. CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
  162. {
  163. char *str;
  164. va_list ap;
  165. va_start(ap, fmt);
  166. str = vaprintf(fmt, ap); /* this allocs a new string to append */
  167. va_end(ap);
  168. if(str) {
  169. CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str));
  170. free(str);
  171. return result;
  172. }
  173. /* If we failed, we cleanup the whole buffer and return error */
  174. Curl_dyn_free(s);
  175. return CURLE_OUT_OF_MEMORY;
  176. }
  177. /*
  178. * Returns a pointer to the buffer.
  179. */
  180. char *Curl_dyn_ptr(const struct dynbuf *s)
  181. {
  182. DEBUGASSERT(s);
  183. DEBUGASSERT(s->init == DYNINIT);
  184. DEBUGASSERT(!s->leng || s->bufr);
  185. return s->leng ? s->bufr : (char *)"";
  186. }
  187. /*
  188. * Returns an unsigned pointer to the buffer.
  189. */
  190. unsigned char *Curl_dyn_uptr(const struct dynbuf *s)
  191. {
  192. DEBUGASSERT(s);
  193. DEBUGASSERT(s->init == DYNINIT);
  194. DEBUGASSERT(!s->leng || s->bufr);
  195. return s->leng ? (unsigned char *)s->bufr : (unsigned char *)"";
  196. }
  197. /*
  198. * Returns the length of the buffer.
  199. */
  200. size_t Curl_dyn_len(const struct dynbuf *s)
  201. {
  202. DEBUGASSERT(s);
  203. DEBUGASSERT(s->init == DYNINIT);
  204. DEBUGASSERT(!s->leng || s->bufr);
  205. return s->leng;
  206. }