buffer.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2020 GNUnet e.V.
  4. GNUnet is free software; you can redistribute it and/or modify it under the
  5. terms of the GNU Affero General Public License as published by the Free Software
  6. Foundation; either version 3, or (at your option) any later version.
  7. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
  8. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  9. A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
  10. You should have received a copy of the GNU Affero General Public License along with
  11. GNUnet; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
  12. */
  13. /**
  14. * @file buffer.c
  15. * @brief Common buffer management functions.
  16. * @author Florian Dold
  17. */
  18. #include "platform.h"
  19. #include "gnunet_util_lib.h"
  20. #include "gnunet_buffer_lib.h"
  21. /**
  22. * Initialize a buffer with the given capacity.
  23. *
  24. * When a buffer is allocated with this function, a warning is logged
  25. * when the buffer exceeds the initial capacity.
  26. *
  27. * @param buf the buffer to initialize
  28. * @param capacity the capacity (in bytes) to allocate for @a buf
  29. */
  30. void
  31. GNUNET_buffer_prealloc (struct GNUNET_Buffer *buf,
  32. size_t capacity)
  33. {
  34. /* Buffer should be zero-initialized */
  35. GNUNET_assert (0 == buf->mem);
  36. GNUNET_assert (0 == buf->capacity);
  37. GNUNET_assert (0 == buf->position);
  38. buf->mem = GNUNET_malloc (capacity);
  39. buf->capacity = capacity;
  40. buf->warn_grow = GNUNET_YES;
  41. }
  42. /**
  43. * Make sure that at least @a n bytes remaining in the buffer.
  44. *
  45. * @param buf buffer to potentially grow
  46. * @param n number of bytes that should be available to write
  47. */
  48. void
  49. GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf,
  50. size_t n)
  51. {
  52. size_t new_capacity = buf->position + n;
  53. /* guard against overflow */
  54. GNUNET_assert (new_capacity >= buf->position);
  55. if (new_capacity <= buf->capacity)
  56. return;
  57. /* warn if calculation of expected size was wrong */
  58. GNUNET_break (GNUNET_YES != buf->warn_grow);
  59. if (new_capacity < buf->capacity * 2)
  60. new_capacity = buf->capacity * 2;
  61. buf->capacity = new_capacity;
  62. if (NULL != buf->mem)
  63. buf->mem = GNUNET_realloc (buf->mem, new_capacity);
  64. else
  65. buf->mem = GNUNET_malloc (new_capacity);
  66. }
  67. /**
  68. * Write bytes to the buffer.
  69. *
  70. * Grows the buffer if necessary.
  71. *
  72. * @param buf buffer to write to
  73. * @param data data to read from
  74. * @param len number of bytes to copy from @a data to @a buf
  75. */
  76. void
  77. GNUNET_buffer_write (struct GNUNET_Buffer *buf,
  78. const char *data,
  79. size_t len)
  80. {
  81. GNUNET_buffer_ensure_remaining (buf, len);
  82. memcpy (buf->mem + buf->position, data, len);
  83. buf->position += len;
  84. }
  85. /**
  86. * Write a 0-terminated string to a buffer, excluding the 0-terminator.
  87. *
  88. * @param buf the buffer to write to
  89. * @param str the string to write to @a buf
  90. */
  91. void
  92. GNUNET_buffer_write_str (struct GNUNET_Buffer *buf,
  93. const char *str)
  94. {
  95. size_t len = strlen (str);
  96. GNUNET_buffer_write (buf, str, len);
  97. }
  98. /**
  99. * Clear the buffer and return the string it contained.
  100. * The caller is responsible to eventually #GNUNET_free
  101. * the returned string.
  102. *
  103. * The returned string is always 0-terminated.
  104. *
  105. * @param buf the buffer to reap the string from
  106. * @returns the buffer contained in the string
  107. */
  108. char *
  109. GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf)
  110. {
  111. char *res;
  112. /* ensure 0-termination */
  113. if ( (0 == buf->position) || ('\0' != buf->mem[buf->position - 1]))
  114. {
  115. GNUNET_buffer_ensure_remaining (buf, 1);
  116. buf->mem[buf->position++] = '\0';
  117. }
  118. res = buf->mem;
  119. memset (buf, 0, sizeof (struct GNUNET_Buffer));
  120. return res;
  121. }
  122. /**
  123. * Clear the buffer and return its contents.
  124. * The caller is responsible to eventually #GNUNET_free
  125. * the returned data.
  126. *
  127. * @param buf the buffer to reap the contents from
  128. * @param size where to store the size of the returned data
  129. * @returns the data contained in the string
  130. */
  131. void *
  132. GNUNET_buffer_reap (struct GNUNET_Buffer *buf, size_t *size)
  133. {
  134. *size = buf->position;
  135. void *res = buf->mem;
  136. memset (buf, 0, sizeof (struct GNUNET_Buffer));
  137. return res;
  138. }
  139. /**
  140. * Free the backing memory of the given buffer.
  141. * Does not free the memory of the buffer control structure,
  142. * which is typically stack-allocated.
  143. */
  144. void
  145. GNUNET_buffer_clear (struct GNUNET_Buffer *buf)
  146. {
  147. GNUNET_free (buf->mem);
  148. memset (buf, 0, sizeof (struct GNUNET_Buffer));
  149. }
  150. /**
  151. * Write a path component to a buffer, ensuring that
  152. * there is exactly one slash between the previous contents
  153. * of the buffer and the new string.
  154. *
  155. * @param buf buffer to write to
  156. * @param str string containing the new path component
  157. */
  158. void
  159. GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str)
  160. {
  161. size_t len = strlen (str);
  162. while ( (0 != len) && ('/' == str[0]) )
  163. {
  164. str++;
  165. len--;
  166. }
  167. if ( (0 == buf->position) || ('/' != buf->mem[buf->position - 1]) )
  168. {
  169. GNUNET_buffer_ensure_remaining (buf, 1);
  170. buf->mem[buf->position++] = '/';
  171. }
  172. GNUNET_buffer_write (buf, str, len);
  173. }
  174. /**
  175. * Write a 0-terminated formatted string to a buffer, excluding the
  176. * 0-terminator.
  177. *
  178. * Grows the buffer if necessary.
  179. *
  180. * @param buf the buffer to write to
  181. * @param fmt format string
  182. * @param ... format arguments
  183. */
  184. void
  185. GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...)
  186. {
  187. va_list args;
  188. va_start (args, fmt);
  189. GNUNET_buffer_write_vfstr (buf, fmt, args);
  190. va_end (args);
  191. }
  192. /**
  193. * Write a 0-terminated formatted string to a buffer, excluding the
  194. * 0-terminator.
  195. *
  196. * Grows the buffer if necessary.
  197. *
  198. * @param buf the buffer to write to
  199. * @param fmt format string
  200. * @param args format argument list
  201. */
  202. void
  203. GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf,
  204. const char *fmt,
  205. va_list args)
  206. {
  207. int res;
  208. va_list args2;
  209. va_copy (args2, args);
  210. res = vsnprintf (NULL, 0, fmt, args2);
  211. va_end (args2);
  212. GNUNET_assert (res >= 0);
  213. GNUNET_buffer_ensure_remaining (buf, res + 1);
  214. va_copy (args2, args);
  215. res = vsnprintf (buf->mem + buf->position, res + 1, fmt, args2);
  216. va_end (args2);
  217. GNUNET_assert (res >= 0);
  218. buf->position += res;
  219. GNUNET_assert (buf->position <= buf->capacity);
  220. }
  221. /**
  222. * Write data encoded via #GNUNET_STRINGS_data_to_string to the buffer.
  223. *
  224. * Grows the buffer if necessary.
  225. *
  226. * @param buf buffer to write to
  227. * @param data data to read from
  228. * @param data_len number of bytes to copy from @a data to @a buf
  229. */
  230. void
  231. GNUNET_buffer_write_data_encoded (struct GNUNET_Buffer *buf,
  232. const void *data,
  233. size_t data_len)
  234. {
  235. size_t outlen = data_len * 8;
  236. if (outlen % 5 > 0)
  237. outlen += 5 - outlen % 5;
  238. outlen /= 5;
  239. GNUNET_buffer_ensure_remaining (buf,
  240. outlen);
  241. GNUNET_assert (NULL !=
  242. GNUNET_STRINGS_data_to_string (data,
  243. data_len,
  244. (buf->mem
  245. + buf->position),
  246. outlen));
  247. buf->position += outlen;
  248. GNUNET_assert (buf->position <= buf->capacity);
  249. }