buffer.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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, size_t capacity)
  32. {
  33. /* Buffer should be zero-initialized */
  34. GNUNET_assert (0 == buf->mem);
  35. GNUNET_assert (0 == buf->capacity);
  36. GNUNET_assert (0 == buf->position);
  37. buf->mem = GNUNET_malloc (capacity);
  38. buf->capacity = capacity;
  39. buf->warn_grow = GNUNET_YES;
  40. }
  41. /**
  42. * Make sure that at least @a n bytes remaining in the buffer.
  43. *
  44. * @param buf buffer to potentially grow
  45. * @param n number of bytes that should be available to write
  46. */
  47. void
  48. GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf,
  49. size_t n)
  50. {
  51. size_t new_capacity = buf->position + n;
  52. /* guard against overflow */
  53. GNUNET_assert (new_capacity >= buf->position);
  54. if (new_capacity <= buf->capacity)
  55. return;
  56. /* warn if calculation of expected size was wrong */
  57. GNUNET_break (GNUNET_YES != buf->warn_grow);
  58. if (new_capacity < buf->capacity * 2)
  59. new_capacity = buf->capacity * 2;
  60. buf->capacity = new_capacity;
  61. if (NULL != buf->mem)
  62. buf->mem = GNUNET_realloc (buf->mem, new_capacity);
  63. else
  64. buf->mem = GNUNET_malloc (new_capacity);
  65. }
  66. /**
  67. * Write bytes to the buffer.
  68. *
  69. * Grows the buffer if necessary.
  70. *
  71. * @param buf buffer to write to
  72. * @param data data to read from
  73. * @param len number of bytes to copy from @a data to @a buf
  74. */
  75. void
  76. GNUNET_buffer_write (struct GNUNET_Buffer *buf,
  77. const char *data,
  78. size_t len)
  79. {
  80. GNUNET_buffer_ensure_remaining (buf, len);
  81. memcpy (buf->mem + buf->position, data, len);
  82. buf->position += len;
  83. }
  84. /**
  85. * Write a 0-terminated string to a buffer, excluding the 0-terminator.
  86. *
  87. * @param buf the buffer to write to
  88. * @param str the string to write to @a buf
  89. */
  90. void
  91. GNUNET_buffer_write_str (struct GNUNET_Buffer *buf,
  92. const char *str)
  93. {
  94. size_t len = strlen (str);
  95. GNUNET_buffer_write (buf, str, len);
  96. }
  97. /**
  98. * Clear the buffer and return the string it contained.
  99. * The caller is responsible to eventually #GNUNET_free
  100. * the returned string.
  101. *
  102. * The returned string is always 0-terminated.
  103. *
  104. * @param buf the buffer to reap the string from
  105. * @returns the buffer contained in the string
  106. */
  107. char *
  108. GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf)
  109. {
  110. char *res;
  111. /* ensure 0-termination */
  112. if ( (0 == buf->position) || ('\0' != buf->mem[buf->position - 1]))
  113. {
  114. GNUNET_buffer_ensure_remaining (buf, 1);
  115. buf->mem[buf->position++] = '\0';
  116. }
  117. res = buf->mem;
  118. memset (buf, 0, sizeof (struct GNUNET_Buffer));
  119. return res;
  120. }
  121. /**
  122. * Clear the buffer and return its contents.
  123. * The caller is responsible to eventually #GNUNET_free
  124. * the returned data.
  125. *
  126. * @param buf the buffer to reap the contents from
  127. * @param size where to store the size of the returned data
  128. * @returns the data contained in the string
  129. */
  130. void *
  131. GNUNET_buffer_reap (struct GNUNET_Buffer *buf, size_t *size)
  132. {
  133. *size = buf->position;
  134. void *res = buf->mem;
  135. memset (buf, 0, sizeof (struct GNUNET_Buffer));
  136. return res;
  137. }
  138. /**
  139. * Free the backing memory of the given buffer.
  140. * Does not free the memory of the buffer control structure,
  141. * which is typically stack-allocated.
  142. */
  143. void
  144. GNUNET_buffer_clear (struct GNUNET_Buffer *buf)
  145. {
  146. GNUNET_free_non_null (buf->mem);
  147. memset (buf, 0, sizeof (struct GNUNET_Buffer));
  148. }
  149. /**
  150. * Write a path component to a buffer, ensuring that
  151. * there is exactly one slash between the previous contents
  152. * of the buffer and the new string.
  153. *
  154. * @param buf buffer to write to
  155. * @param str string containing the new path component
  156. */
  157. void
  158. GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str)
  159. {
  160. size_t len = strlen (str);
  161. while ( (0 != len) && ('/' == str[0]) )
  162. {
  163. str++;
  164. len--;
  165. }
  166. if ( (0 == buf->position) || ('/' != buf->mem[buf->position - 1]) )
  167. {
  168. GNUNET_buffer_ensure_remaining (buf, 1);
  169. buf->mem[buf->position++] = '/';
  170. }
  171. GNUNET_buffer_write (buf, str, len);
  172. }
  173. /**
  174. * Write a 0-terminated formatted string to a buffer, excluding the
  175. * 0-terminator.
  176. *
  177. * Grows the buffer if necessary.
  178. *
  179. * @param buf the buffer to write to
  180. * @param fmt format string
  181. * @param ... format arguments
  182. */
  183. void
  184. GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...)
  185. {
  186. va_list args;
  187. va_start (args, fmt);
  188. GNUNET_buffer_write_vfstr (buf, fmt, args);
  189. va_end (args);
  190. }
  191. /**
  192. * Write a 0-terminated formatted string to a buffer, excluding the
  193. * 0-terminator.
  194. *
  195. * Grows the buffer if necessary.
  196. *
  197. * @param buf the buffer to write to
  198. * @param fmt format string
  199. * @param args format argument list
  200. */
  201. void
  202. GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf,
  203. const char *fmt,
  204. va_list args)
  205. {
  206. int res;
  207. va_list args2;
  208. va_copy (args2, args);
  209. res = vsnprintf (NULL, 0, fmt, args2);
  210. va_end (args2);
  211. GNUNET_assert (res >= 0);
  212. GNUNET_buffer_ensure_remaining (buf, res + 1);
  213. va_copy (args2, args);
  214. res = vsnprintf (buf->mem + buf->position, res + 1, fmt, args2);
  215. va_end (args2);
  216. GNUNET_assert (res >= 0);
  217. buf->position += res;
  218. GNUNET_assert (buf->position <= buf->capacity);
  219. }