PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/google/protobuf-c/protobuf-c-data-buffer.c

http://protobuf-c.googlecode.com/
C | 1126 lines | 813 code | 54 blank | 259 comment | 137 complexity | 4f63614a8fdd8c79617b23ca87793f2c MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /* Free blocks to hold around to avoid repeated mallocs... */
  2. #define MAX_RECYCLED 16
  3. /* Size of allocations to make. */
  4. #define BUF_CHUNK_SIZE 8192
  5. /* Max fragments in the iovector to writev. */
  6. #define MAX_FRAGMENTS_TO_WRITE 16
  7. /* This causes fragments not to be transferred from buffer to buffer,
  8. * and not to be allocated in pools. The result is that stack-trace
  9. * based debug-allocators work much better with this on.
  10. *
  11. * On the other hand, this can mask over some abuses (eg stack-based
  12. * foreign buffer fragment bugs) so we disable it by default.
  13. */
  14. #define GSK_DEBUG_BUFFER_ALLOCATIONS 0
  15. #define BUFFER_RECYCLING 0
  16. #if HAVE_PROTOBUF_C_CONFIG_H
  17. #include "protobuf-c-config.h"
  18. #endif
  19. #include <sys/types.h>
  20. #if HAVE_SYS_UIO_H /* writev function isn't available on Windows */
  21. #include <sys/uio.h>
  22. #endif
  23. #if HAVE_UNISTD_H
  24. #include <unistd.h>
  25. #elif HAVE_IO_H
  26. #include <io.h>
  27. #define read _read
  28. #endif
  29. #include <string.h>
  30. #include <errno.h>
  31. #if HAVE_ALLOCA_H
  32. # include <alloca.h>
  33. #elif HAVE_MALLOC_H
  34. # include <malloc.h>
  35. #endif
  36. #include <stdlib.h>
  37. #include "protobuf-c-data-buffer.h"
  38. #undef TRUE
  39. #define TRUE 1
  40. #undef FALSE
  41. #define FALSE 0
  42. #define PROTOBUF_C_FRAGMENT_DATA_SIZE 4096
  43. #define PROTOBUF_C_FRAGMENT_DATA(frag) ((uint8_t*)(((ProtobufCDataBufferFragment*)(frag))+1))
  44. /* --- ProtobufCDataBufferFragment implementation --- */
  45. static inline int
  46. protobuf_c_data_buffer_fragment_avail (ProtobufCDataBufferFragment *frag)
  47. {
  48. return PROTOBUF_C_FRAGMENT_DATA_SIZE - frag->buf_start - frag->buf_length;
  49. }
  50. static inline uint8_t *
  51. protobuf_c_data_buffer_fragment_start (ProtobufCDataBufferFragment *frag)
  52. {
  53. return PROTOBUF_C_FRAGMENT_DATA(frag) + frag->buf_start;
  54. }
  55. static inline uint8_t *
  56. protobuf_c_data_buffer_fragment_end (ProtobufCDataBufferFragment *frag)
  57. {
  58. return PROTOBUF_C_FRAGMENT_DATA(frag) + frag->buf_start + frag->buf_length;
  59. }
  60. /* --- ProtobufCDataBufferFragment recycling --- */
  61. #if BUFFER_RECYCLING
  62. static int num_recycled = 0;
  63. static ProtobufCDataBufferFragment* recycling_stack = 0;
  64. #endif
  65. static ProtobufCDataBufferFragment *
  66. new_native_fragment(ProtobufCAllocator *allocator)
  67. {
  68. ProtobufCDataBufferFragment *frag;
  69. #if !BUFFER_RECYCLING
  70. frag = (ProtobufCDataBufferFragment *) allocator->alloc (allocator, BUF_CHUNK_SIZE);
  71. #else /* optimized (?) */
  72. if (recycling_stack)
  73. {
  74. frag = recycling_stack;
  75. recycling_stack = recycling_stack->next;
  76. num_recycled--;
  77. }
  78. else
  79. {
  80. frag = (ProtobufCDataBufferFragment *) g_malloc (BUF_CHUNK_SIZE);
  81. }
  82. #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
  83. frag->buf_start = frag->buf_length = 0;
  84. frag->next = 0;
  85. return frag;
  86. }
  87. #if GSK_DEBUG_BUFFER_ALLOCATIONS || !BUFFER_RECYCLING
  88. #define recycle(allocator, frag) allocator->free (allocator, frag)
  89. #else /* optimized (?) */
  90. static void
  91. recycle(ProtobufCDataBufferFragment* frag,
  92. ProtobufCAllocator *allocator)
  93. {
  94. frag->next = recycling_stack;
  95. recycling_stack = frag;
  96. num_recycled++;
  97. }
  98. #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
  99. /* --- Global public methods --- */
  100. /**
  101. * protobuf_c_data_buffer_cleanup_recycling_bin:
  102. *
  103. * Free unused buffer fragments. (Normally some are
  104. * kept around to reduce strain on the global allocator.)
  105. */
  106. void
  107. protobuf_c_data_buffer_cleanup_recycling_bin ()
  108. {
  109. #if !GSK_DEBUG_BUFFER_ALLOCATIONS && BUFFER_RECYCLING
  110. G_LOCK (recycling_stack);
  111. while (recycling_stack != NULL)
  112. {
  113. ProtobufCDataBufferFragment *next;
  114. next = recycling_stack->next;
  115. g_free (recycling_stack);
  116. recycling_stack = next;
  117. }
  118. num_recycled = 0;
  119. G_UNLOCK (recycling_stack);
  120. #endif
  121. }
  122. /* --- Public methods --- */
  123. /**
  124. * protobuf_c_data_buffer_init:
  125. * @buffer: buffer to initialize (as empty).
  126. *
  127. * Construct an empty buffer out of raw memory.
  128. * (This is equivalent to filling the buffer with 0s)
  129. */
  130. void
  131. protobuf_c_data_buffer_init(ProtobufCDataBuffer *buffer,
  132. ProtobufCAllocator *allocator)
  133. {
  134. buffer->first_frag = buffer->last_frag = NULL;
  135. buffer->size = 0;
  136. buffer->allocator = allocator;
  137. }
  138. #if defined(GSK_DEBUG) || GSK_DEBUG_BUFFER_ALLOCATIONS
  139. static inline gboolean
  140. verify_buffer (const ProtobufCDataBuffer *buffer)
  141. {
  142. const ProtobufCDataBufferFragment *frag;
  143. size_t total = 0;
  144. for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
  145. total += frag->buf_length;
  146. return total == buffer->size;
  147. }
  148. #define CHECK_INTEGRITY(buffer) g_assert (verify_buffer (buffer))
  149. #else
  150. #define CHECK_INTEGRITY(buffer)
  151. #endif
  152. /**
  153. * protobuf_c_data_buffer_append:
  154. * @buffer: the buffer to add data to. Data is put at the end of the buffer.
  155. * @data: binary data to add to the buffer.
  156. * @length: length of @data to add to the buffer.
  157. *
  158. * Append data into the buffer.
  159. */
  160. void
  161. protobuf_c_data_buffer_append(ProtobufCDataBuffer *buffer,
  162. const void *data,
  163. size_t length)
  164. {
  165. CHECK_INTEGRITY (buffer);
  166. buffer->size += length;
  167. while (length > 0)
  168. {
  169. size_t avail;
  170. if (!buffer->last_frag)
  171. {
  172. buffer->last_frag = buffer->first_frag = new_native_fragment (buffer->allocator);
  173. avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
  174. }
  175. else
  176. {
  177. avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
  178. if (avail <= 0)
  179. {
  180. buffer->last_frag->next = new_native_fragment (buffer->allocator);
  181. avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
  182. buffer->last_frag = buffer->last_frag->next;
  183. }
  184. }
  185. if (avail > length)
  186. avail = length;
  187. memcpy (protobuf_c_data_buffer_fragment_end (buffer->last_frag), data, avail);
  188. data = (const char *) data + avail;
  189. length -= avail;
  190. buffer->last_frag->buf_length += avail;
  191. }
  192. CHECK_INTEGRITY (buffer);
  193. }
  194. void
  195. protobuf_c_data_buffer_append_repeated_char (ProtobufCDataBuffer *buffer,
  196. char character,
  197. size_t count)
  198. {
  199. CHECK_INTEGRITY (buffer);
  200. buffer->size += count;
  201. while (count > 0)
  202. {
  203. size_t avail;
  204. if (!buffer->last_frag)
  205. {
  206. buffer->last_frag = buffer->first_frag = new_native_fragment (buffer->allocator);
  207. avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
  208. }
  209. else
  210. {
  211. avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
  212. if (avail <= 0)
  213. {
  214. buffer->last_frag->next = new_native_fragment (buffer->allocator);
  215. avail = protobuf_c_data_buffer_fragment_avail (buffer->last_frag);
  216. buffer->last_frag = buffer->last_frag->next;
  217. }
  218. }
  219. if (avail > count)
  220. avail = count;
  221. memset (protobuf_c_data_buffer_fragment_end (buffer->last_frag), character, avail);
  222. count -= avail;
  223. buffer->last_frag->buf_length += avail;
  224. }
  225. CHECK_INTEGRITY (buffer);
  226. }
  227. #if 0
  228. void
  229. protobuf_c_data_buffer_append_repeated_data (ProtobufCDataBuffer *buffer,
  230. gconstpointer data_to_repeat,
  231. gsize data_length,
  232. gsize count)
  233. {
  234. ...
  235. }
  236. #endif
  237. /**
  238. * protobuf_c_data_buffer_append_string:
  239. * @buffer: the buffer to add data to. Data is put at the end of the buffer.
  240. * @string: NUL-terminated string to append to the buffer.
  241. * The NUL is not appended.
  242. *
  243. * Append a string to the buffer.
  244. */
  245. void
  246. protobuf_c_data_buffer_append_string(ProtobufCDataBuffer *buffer,
  247. const char *string)
  248. {
  249. assert (string != NULL);
  250. protobuf_c_data_buffer_append (buffer, string, strlen (string));
  251. }
  252. /**
  253. * protobuf_c_data_buffer_append_char:
  254. * @buffer: the buffer to add the byte to.
  255. * @character: the byte to add to the buffer.
  256. *
  257. * Append a byte to a buffer.
  258. */
  259. void
  260. protobuf_c_data_buffer_append_char(ProtobufCDataBuffer *buffer,
  261. char character)
  262. {
  263. protobuf_c_data_buffer_append (buffer, &character, 1);
  264. }
  265. /**
  266. * protobuf_c_data_buffer_append_string0:
  267. * @buffer: the buffer to add data to. Data is put at the end of the buffer.
  268. * @string: NUL-terminated string to append to the buffer;
  269. * NUL is appended.
  270. *
  271. * Append a NUL-terminated string to the buffer. The NUL is appended.
  272. */
  273. void
  274. protobuf_c_data_buffer_append_string0 (ProtobufCDataBuffer *buffer,
  275. const char *string)
  276. {
  277. protobuf_c_data_buffer_append (buffer, string, strlen (string) + 1);
  278. }
  279. /**
  280. * protobuf_c_data_buffer_read:
  281. * @buffer: the buffer to read data from.
  282. * @data: buffer to fill with up to @max_length bytes of data.
  283. * @max_length: maximum number of bytes to read.
  284. *
  285. * Removes up to @max_length data from the beginning of the buffer,
  286. * and writes it to @data. The number of bytes actually read
  287. * is returned.
  288. *
  289. * returns: number of bytes transferred.
  290. */
  291. size_t
  292. protobuf_c_data_buffer_read(ProtobufCDataBuffer *buffer,
  293. void *data,
  294. size_t max_length)
  295. {
  296. size_t rv = 0;
  297. size_t orig_max_length = max_length;
  298. CHECK_INTEGRITY (buffer);
  299. while (max_length > 0 && buffer->first_frag)
  300. {
  301. ProtobufCDataBufferFragment *first = buffer->first_frag;
  302. if (first->buf_length <= max_length)
  303. {
  304. memcpy (data, protobuf_c_data_buffer_fragment_start (first), first->buf_length);
  305. rv += first->buf_length;
  306. data = (char *) data + first->buf_length;
  307. max_length -= first->buf_length;
  308. buffer->first_frag = first->next;
  309. if (!buffer->first_frag)
  310. buffer->last_frag = NULL;
  311. recycle (buffer->allocator, first);
  312. }
  313. else
  314. {
  315. memcpy (data, protobuf_c_data_buffer_fragment_start (first), max_length);
  316. rv += max_length;
  317. first->buf_length -= max_length;
  318. first->buf_start += max_length;
  319. data = (char *) data + max_length;
  320. max_length = 0;
  321. }
  322. }
  323. buffer->size -= rv;
  324. assert (rv == orig_max_length || buffer->size == 0);
  325. CHECK_INTEGRITY (buffer);
  326. return rv;
  327. }
  328. /**
  329. * protobuf_c_data_buffer_peek:
  330. * @buffer: the buffer to peek data from the front of.
  331. * This buffer is unchanged by the operation.
  332. * @data: buffer to fill with up to @max_length bytes of data.
  333. * @max_length: maximum number of bytes to peek.
  334. *
  335. * Copies up to @max_length data from the beginning of the buffer,
  336. * and writes it to @data. The number of bytes actually copied
  337. * is returned.
  338. *
  339. * This function is just like protobuf_c_data_buffer_read() except that the
  340. * data is not removed from the buffer.
  341. *
  342. * returns: number of bytes copied into data.
  343. */
  344. size_t
  345. protobuf_c_data_buffer_peek (const ProtobufCDataBuffer *buffer,
  346. void *data,
  347. size_t max_length)
  348. {
  349. int rv = 0;
  350. ProtobufCDataBufferFragment *frag = (ProtobufCDataBufferFragment *) buffer->first_frag;
  351. CHECK_INTEGRITY (buffer);
  352. while (max_length > 0 && frag)
  353. {
  354. if (frag->buf_length <= max_length)
  355. {
  356. memcpy (data, protobuf_c_data_buffer_fragment_start (frag), frag->buf_length);
  357. rv += frag->buf_length;
  358. data = (char *) data + frag->buf_length;
  359. max_length -= frag->buf_length;
  360. frag = frag->next;
  361. }
  362. else
  363. {
  364. memcpy (data, protobuf_c_data_buffer_fragment_start (frag), max_length);
  365. rv += max_length;
  366. data = (char *) data + max_length;
  367. max_length = 0;
  368. }
  369. }
  370. return rv;
  371. }
  372. /**
  373. * protobuf_c_data_buffer_read_line:
  374. * @buffer: buffer to read a line from.
  375. *
  376. * Parse a newline (\n) terminated line from
  377. * buffer and return it as a newly allocated string.
  378. * The newline is changed to a NUL character.
  379. *
  380. * If the buffer does not contain a newline, then NULL is returned.
  381. *
  382. * returns: a newly allocated NUL-terminated string, or NULL.
  383. */
  384. char *
  385. protobuf_c_data_buffer_read_line(ProtobufCDataBuffer *buffer)
  386. {
  387. int len = 0;
  388. char *rv;
  389. ProtobufCDataBufferFragment *at;
  390. int newline_length;
  391. CHECK_INTEGRITY (buffer);
  392. for (at = buffer->first_frag; at; at = at->next)
  393. {
  394. uint8_t *start = protobuf_c_data_buffer_fragment_start (at);
  395. uint8_t *got;
  396. got = memchr (start, '\n', at->buf_length);
  397. if (got)
  398. {
  399. len += got - start;
  400. break;
  401. }
  402. len += at->buf_length;
  403. }
  404. if (at == NULL)
  405. return NULL;
  406. rv = buffer->allocator->alloc (buffer->allocator, len + 1);
  407. /* If we found a newline, read it out, truncating
  408. * it with NUL before we return from the function... */
  409. if (at)
  410. newline_length = 1;
  411. else
  412. newline_length = 0;
  413. protobuf_c_data_buffer_read (buffer, rv, len + newline_length);
  414. rv[len] = 0;
  415. CHECK_INTEGRITY (buffer);
  416. return rv;
  417. }
  418. /**
  419. * protobuf_c_data_buffer_parse_string0:
  420. * @buffer: buffer to read a line from.
  421. *
  422. * Parse a NUL-terminated line from
  423. * buffer and return it as a newly allocated string.
  424. *
  425. * If the buffer does not contain a newline, then NULL is returned.
  426. *
  427. * returns: a newly allocated NUL-terminated string, or NULL.
  428. */
  429. char *
  430. protobuf_c_data_buffer_parse_string0(ProtobufCDataBuffer *buffer)
  431. {
  432. int index0 = protobuf_c_data_buffer_index_of (buffer, '\0');
  433. char *rv;
  434. if (index0 < 0)
  435. return NULL;
  436. rv = buffer->allocator->alloc (buffer->allocator, index0 + 1);
  437. protobuf_c_data_buffer_read (buffer, rv, index0 + 1);
  438. return rv;
  439. }
  440. /**
  441. * protobuf_c_data_buffer_peek_char:
  442. * @buffer: buffer to peek a single byte from.
  443. *
  444. * Get the first byte in the buffer as a positive or 0 number.
  445. * If the buffer is empty, -1 is returned.
  446. * The buffer is unchanged.
  447. *
  448. * returns: an unsigned character or -1.
  449. */
  450. int
  451. protobuf_c_data_buffer_peek_char(const ProtobufCDataBuffer *buffer)
  452. {
  453. const ProtobufCDataBufferFragment *frag;
  454. if (buffer->size == 0)
  455. return -1;
  456. for (frag = buffer->first_frag; frag; frag = frag->next)
  457. if (frag->buf_length > 0)
  458. break;
  459. return * protobuf_c_data_buffer_fragment_start ((ProtobufCDataBufferFragment*)frag);
  460. }
  461. /**
  462. * protobuf_c_data_buffer_read_char:
  463. * @buffer: buffer to read a single byte from.
  464. *
  465. * Get the first byte in the buffer as a positive or 0 number,
  466. * and remove the character from the buffer.
  467. * If the buffer is empty, -1 is returned.
  468. *
  469. * returns: an unsigned character or -1.
  470. */
  471. int
  472. protobuf_c_data_buffer_read_char (ProtobufCDataBuffer *buffer)
  473. {
  474. char c;
  475. if (protobuf_c_data_buffer_read (buffer, &c, 1) == 0)
  476. return -1;
  477. return (int) (uint8_t) c;
  478. }
  479. /**
  480. * protobuf_c_data_buffer_discard:
  481. * @buffer: the buffer to discard data from.
  482. * @max_discard: maximum number of bytes to discard.
  483. *
  484. * Removes up to @max_discard data from the beginning of the buffer,
  485. * and returns the number of bytes actually discarded.
  486. *
  487. * returns: number of bytes discarded.
  488. */
  489. size_t
  490. protobuf_c_data_buffer_discard(ProtobufCDataBuffer *buffer,
  491. size_t max_discard)
  492. {
  493. int rv = 0;
  494. CHECK_INTEGRITY (buffer);
  495. while (max_discard > 0 && buffer->first_frag)
  496. {
  497. ProtobufCDataBufferFragment *first = buffer->first_frag;
  498. if (first->buf_length <= max_discard)
  499. {
  500. rv += first->buf_length;
  501. max_discard -= first->buf_length;
  502. buffer->first_frag = first->next;
  503. if (!buffer->first_frag)
  504. buffer->last_frag = NULL;
  505. recycle (buffer->allocator, first);
  506. }
  507. else
  508. {
  509. rv += max_discard;
  510. first->buf_length -= max_discard;
  511. first->buf_start += max_discard;
  512. max_discard = 0;
  513. }
  514. }
  515. buffer->size -= rv;
  516. CHECK_INTEGRITY (buffer);
  517. return rv;
  518. }
  519. static inline protobuf_c_boolean
  520. errno_is_ignorable (int e)
  521. {
  522. #ifdef EWOULDBLOCK /* for windows */
  523. if (e == EWOULDBLOCK)
  524. return 1;
  525. #endif
  526. return e == EINTR || e == EAGAIN;
  527. }
  528. #if HAVE_SYS_UIO_H
  529. /**
  530. * protobuf_c_data_buffer_writev:
  531. * @read_from: buffer to take data from.
  532. * @fd: file-descriptor to write data to.
  533. *
  534. * Writes as much data as possible to the
  535. * given file-descriptor using the writev(2)
  536. * function to deal with multiple fragments
  537. * efficiently, where available.
  538. *
  539. * returns: the number of bytes transferred,
  540. * or -1 on a write error (consult errno).
  541. */
  542. int
  543. protobuf_c_data_buffer_writev (ProtobufCDataBuffer *read_from,
  544. int fd)
  545. {
  546. int rv;
  547. struct iovec *iov;
  548. int nfrag, i;
  549. ProtobufCDataBufferFragment *frag_at = read_from->first_frag;
  550. CHECK_INTEGRITY (read_from);
  551. for (nfrag = 0; frag_at != NULL
  552. #ifdef MAX_FRAGMENTS_TO_WRITE
  553. && nfrag < MAX_FRAGMENTS_TO_WRITE
  554. #endif
  555. ; nfrag++)
  556. frag_at = frag_at->next;
  557. iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
  558. frag_at = read_from->first_frag;
  559. for (i = 0; i < nfrag; i++)
  560. {
  561. iov[i].iov_len = frag_at->buf_length;
  562. iov[i].iov_base = protobuf_c_data_buffer_fragment_start (frag_at);
  563. frag_at = frag_at->next;
  564. }
  565. rv = writev (fd, iov, nfrag);
  566. if (rv < 0 && errno_is_ignorable (errno))
  567. return 0;
  568. if (rv <= 0)
  569. return rv;
  570. protobuf_c_data_buffer_discard (read_from, rv);
  571. return rv;
  572. }
  573. #endif
  574. #if HAVE_SYS_UIO_H
  575. /**
  576. * protobuf_c_data_buffer_writev_len:
  577. * @read_from: buffer to take data from.
  578. * @fd: file-descriptor to write data to.
  579. * @max_bytes: maximum number of bytes to write.
  580. *
  581. * Writes up to max_bytes bytes to the
  582. * given file-descriptor using the writev(2)
  583. * function to deal with multiple fragments
  584. * efficiently, where available.
  585. *
  586. * returns: the number of bytes transferred,
  587. * or -1 on a write error (consult errno).
  588. */
  589. #undef MIN
  590. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  591. int
  592. protobuf_c_data_buffer_writev_len (ProtobufCDataBuffer *read_from,
  593. int fd,
  594. size_t max_bytes)
  595. {
  596. int rv;
  597. struct iovec *iov;
  598. int nfrag, i;
  599. size_t bytes;
  600. ProtobufCDataBufferFragment *frag_at = read_from->first_frag;
  601. CHECK_INTEGRITY (read_from);
  602. for (nfrag = 0, bytes = 0; frag_at != NULL && bytes < max_bytes
  603. #ifdef MAX_FRAGMENTS_TO_WRITE
  604. && nfrag < MAX_FRAGMENTS_TO_WRITE
  605. #endif
  606. ; nfrag++)
  607. {
  608. bytes += frag_at->buf_length;
  609. frag_at = frag_at->next;
  610. }
  611. iov = (struct iovec *) alloca (sizeof (struct iovec) * nfrag);
  612. frag_at = read_from->first_frag;
  613. for (bytes = max_bytes, i = 0; i < nfrag && bytes > 0; i++)
  614. {
  615. size_t frag_bytes = MIN (frag_at->buf_length, bytes);
  616. iov[i].iov_len = frag_bytes;
  617. iov[i].iov_base = protobuf_c_data_buffer_fragment_start (frag_at);
  618. frag_at = frag_at->next;
  619. bytes -= frag_bytes;
  620. }
  621. rv = writev (fd, iov, i);
  622. if (rv < 0 && errno_is_ignorable (errno))
  623. return 0;
  624. if (rv <= 0)
  625. return rv;
  626. protobuf_c_data_buffer_discard (read_from, rv);
  627. return rv;
  628. }
  629. #endif
  630. /**
  631. * protobuf_c_data_buffer_read_in_fd:
  632. * @write_to: buffer to append data to.
  633. * @read_from: file-descriptor to read data from.
  634. *
  635. * Append data into the buffer directly from the
  636. * given file-descriptor.
  637. *
  638. * returns: the number of bytes transferred,
  639. * or -1 on a read error (consult errno).
  640. */
  641. /* TODO: zero-copy! */
  642. int
  643. protobuf_c_data_buffer_read_in_fd(ProtobufCDataBuffer *write_to,
  644. int read_from)
  645. {
  646. char buf[8192];
  647. int rv = read (read_from, buf, sizeof (buf));
  648. if (rv < 0)
  649. return rv;
  650. protobuf_c_data_buffer_append (write_to, buf, rv);
  651. return rv;
  652. }
  653. /**
  654. * protobuf_c_data_buffer_destruct:
  655. * @to_destroy: the buffer to empty.
  656. *
  657. * Remove all fragments from a buffer, leaving it empty.
  658. * The buffer is guaranteed to not to be consuming any resources,
  659. * but it also is allowed to start using it again.
  660. */
  661. void
  662. protobuf_c_data_buffer_reset(ProtobufCDataBuffer *to_destroy)
  663. {
  664. ProtobufCDataBufferFragment *at = to_destroy->first_frag;
  665. CHECK_INTEGRITY (to_destroy);
  666. while (at)
  667. {
  668. ProtobufCDataBufferFragment *next = at->next;
  669. recycle (to_destroy->allocator, at);
  670. at = next;
  671. }
  672. to_destroy->first_frag = to_destroy->last_frag = NULL;
  673. to_destroy->size = 0;
  674. }
  675. void
  676. protobuf_c_data_buffer_clear(ProtobufCDataBuffer *to_destroy)
  677. {
  678. ProtobufCDataBufferFragment *at = to_destroy->first_frag;
  679. CHECK_INTEGRITY (to_destroy);
  680. while (at)
  681. {
  682. ProtobufCDataBufferFragment *next = at->next;
  683. recycle (to_destroy->allocator, at);
  684. at = next;
  685. }
  686. }
  687. /**
  688. * protobuf_c_data_buffer_index_of:
  689. * @buffer: buffer to scan.
  690. * @char_to_find: a byte to look for.
  691. *
  692. * Scans for the first instance of the given character.
  693. * returns: its index in the buffer, or -1 if the character
  694. * is not in the buffer.
  695. */
  696. int
  697. protobuf_c_data_buffer_index_of(ProtobufCDataBuffer *buffer,
  698. char char_to_find)
  699. {
  700. ProtobufCDataBufferFragment *at = buffer->first_frag;
  701. int rv = 0;
  702. while (at)
  703. {
  704. uint8_t *start = protobuf_c_data_buffer_fragment_start (at);
  705. uint8_t *saught = memchr (start, char_to_find, at->buf_length);
  706. if (saught)
  707. return (saught - start) + rv;
  708. else
  709. rv += at->buf_length;
  710. at = at->next;
  711. }
  712. return -1;
  713. }
  714. /**
  715. * protobuf_c_data_buffer_str_index_of:
  716. * @buffer: buffer to scan.
  717. * @str_to_find: a string to look for.
  718. *
  719. * Scans for the first instance of the given string.
  720. * returns: its index in the buffer, or -1 if the string
  721. * is not in the buffer.
  722. */
  723. int
  724. protobuf_c_data_buffer_str_index_of (ProtobufCDataBuffer *buffer,
  725. const char *str_to_find)
  726. {
  727. ProtobufCDataBufferFragment *frag = buffer->first_frag;
  728. size_t rv = 0;
  729. for (frag = buffer->first_frag; frag; frag = frag->next)
  730. {
  731. const uint8_t *frag_at = PROTOBUF_C_FRAGMENT_DATA (frag);
  732. size_t frag_rem = frag->buf_length;
  733. while (frag_rem > 0)
  734. {
  735. ProtobufCDataBufferFragment *subfrag;
  736. const uint8_t *subfrag_at;
  737. size_t subfrag_rem;
  738. const char *str_at;
  739. if (*frag_at != str_to_find[0])
  740. {
  741. frag_at++;
  742. frag_rem--;
  743. rv++;
  744. continue;
  745. }
  746. subfrag = frag;
  747. subfrag_at = frag_at + 1;
  748. subfrag_rem = frag_rem - 1;
  749. str_at = str_to_find + 1;
  750. if (*str_at == '\0')
  751. return rv;
  752. while (subfrag != NULL)
  753. {
  754. while (subfrag_rem == 0)
  755. {
  756. subfrag = subfrag->next;
  757. if (subfrag == NULL)
  758. goto bad_guess;
  759. subfrag_at = protobuf_c_data_buffer_fragment_start (subfrag);
  760. subfrag_rem = subfrag->buf_length;
  761. }
  762. while (*str_at != '\0' && subfrag_rem != 0)
  763. {
  764. if (*str_at++ != *subfrag_at++)
  765. goto bad_guess;
  766. subfrag_rem--;
  767. }
  768. if (*str_at == '\0')
  769. return rv;
  770. }
  771. bad_guess:
  772. frag_at++;
  773. frag_rem--;
  774. rv++;
  775. }
  776. }
  777. return -1;
  778. }
  779. /**
  780. * protobuf_c_data_buffer_drain:
  781. * @dst: buffer to add to.
  782. * @src: buffer to remove from.
  783. *
  784. * Transfer all data from @src to @dst,
  785. * leaving @src empty.
  786. *
  787. * returns: the number of bytes transferred.
  788. */
  789. #if GSK_DEBUG_BUFFER_ALLOCATIONS
  790. size_t
  791. protobuf_c_data_buffer_drain (ProtobufCDataBuffer *dst,
  792. ProtobufCDataBuffer *src)
  793. {
  794. size_t rv = src->size;
  795. ProtobufCDataBufferFragment *frag;
  796. CHECK_INTEGRITY (dst);
  797. CHECK_INTEGRITY (src);
  798. for (frag = src->first_frag; frag; frag = frag->next)
  799. protobuf_c_data_buffer_append (dst,
  800. protobuf_c_data_buffer_fragment_start (frag),
  801. frag->buf_length);
  802. protobuf_c_data_buffer_discard (src, src->size);
  803. CHECK_INTEGRITY (dst);
  804. CHECK_INTEGRITY (src);
  805. return rv;
  806. }
  807. #else /* optimized */
  808. size_t
  809. protobuf_c_data_buffer_drain (ProtobufCDataBuffer *dst,
  810. ProtobufCDataBuffer *src)
  811. {
  812. size_t rv = src->size;
  813. CHECK_INTEGRITY (dst);
  814. CHECK_INTEGRITY (src);
  815. if (src->first_frag == NULL)
  816. return rv;
  817. dst->size += src->size;
  818. if (dst->last_frag != NULL)
  819. {
  820. dst->last_frag->next = src->first_frag;
  821. dst->last_frag = src->last_frag;
  822. }
  823. else
  824. {
  825. dst->first_frag = src->first_frag;
  826. dst->last_frag = src->last_frag;
  827. }
  828. src->size = 0;
  829. src->first_frag = src->last_frag = NULL;
  830. CHECK_INTEGRITY (dst);
  831. return rv;
  832. }
  833. #endif
  834. /**
  835. * protobuf_c_data_buffer_transfer:
  836. * @dst: place to copy data into.
  837. * @src: place to read data from.
  838. * @max_transfer: maximum number of bytes to transfer.
  839. *
  840. * Transfer data out of @src and into @dst.
  841. * Data is removed from @src. The number of bytes
  842. * transferred is returned.
  843. *
  844. * returns: the number of bytes transferred.
  845. */
  846. #if GSK_DEBUG_BUFFER_ALLOCATIONS
  847. size_t
  848. protobuf_c_data_buffer_transfer(ProtobufCDataBuffer *dst,
  849. ProtobufCDataBuffer *src,
  850. size_t max_transfer)
  851. {
  852. size_t rv = 0;
  853. ProtobufCDataBufferFragment *frag;
  854. CHECK_INTEGRITY (dst);
  855. CHECK_INTEGRITY (src);
  856. for (frag = src->first_frag; frag && max_transfer > 0; frag = frag->next)
  857. {
  858. size_t len = frag->buf_length;
  859. if (len >= max_transfer)
  860. {
  861. protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), max_transfer);
  862. rv += max_transfer;
  863. break;
  864. }
  865. else
  866. {
  867. protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), len);
  868. rv += len;
  869. max_transfer -= len;
  870. }
  871. }
  872. protobuf_c_data_buffer_discard (src, rv);
  873. CHECK_INTEGRITY (dst);
  874. CHECK_INTEGRITY (src);
  875. return rv;
  876. }
  877. #else /* optimized */
  878. size_t
  879. protobuf_c_data_buffer_transfer(ProtobufCDataBuffer *dst,
  880. ProtobufCDataBuffer *src,
  881. size_t max_transfer)
  882. {
  883. size_t rv = 0;
  884. CHECK_INTEGRITY (dst);
  885. CHECK_INTEGRITY (src);
  886. while (src->first_frag && max_transfer >= src->first_frag->buf_length)
  887. {
  888. ProtobufCDataBufferFragment *frag = src->first_frag;
  889. src->first_frag = frag->next;
  890. frag->next = NULL;
  891. if (src->first_frag == NULL)
  892. src->last_frag = NULL;
  893. if (dst->last_frag)
  894. dst->last_frag->next = frag;
  895. else
  896. dst->first_frag = frag;
  897. dst->last_frag = frag;
  898. rv += frag->buf_length;
  899. max_transfer -= frag->buf_length;
  900. }
  901. dst->size += rv;
  902. if (src->first_frag && max_transfer)
  903. {
  904. ProtobufCDataBufferFragment *frag = src->first_frag;
  905. protobuf_c_data_buffer_append (dst, protobuf_c_data_buffer_fragment_start (frag), max_transfer);
  906. frag->buf_start += max_transfer;
  907. frag->buf_length -= max_transfer;
  908. rv += max_transfer;
  909. }
  910. src->size -= rv;
  911. CHECK_INTEGRITY (dst);
  912. CHECK_INTEGRITY (src);
  913. return rv;
  914. }
  915. #endif /* !GSK_DEBUG_BUFFER_ALLOCATIONS */
  916. #if 0
  917. /**
  918. * protobuf_c_data_buffer_printf:
  919. * @buffer: the buffer to append to.
  920. * @format: printf-style format string describing what to append to buffer.
  921. * @Varargs: values referenced by @format string.
  922. *
  923. * Append printf-style content to a buffer.
  924. */
  925. void protobuf_c_data_buffer_printf (ProtobufCDataBuffer *buffer,
  926. const char *format,
  927. ...)
  928. {
  929. va_list args;
  930. va_start (args, format);
  931. protobuf_c_data_buffer_vprintf (buffer, format, args);
  932. va_end (args);
  933. }
  934. /**
  935. * protobuf_c_data_buffer_vprintf:
  936. * @buffer: the buffer to append to.
  937. * @format: printf-style format string describing what to append to buffer.
  938. * @args: values referenced by @format string.
  939. *
  940. * Append printf-style content to a buffer, given a va_list.
  941. */
  942. void protobuf_c_data_buffer_vprintf (ProtobufCDataBuffer *buffer,
  943. const char *format,
  944. va_list args)
  945. {
  946. gsize size = g_printf_string_upper_bound (format, args);
  947. if (size < 1024)
  948. {
  949. char buf[1024];
  950. g_vsnprintf (buf, sizeof (buf), format, args);
  951. protobuf_c_data_buffer_append_string (buffer, buf);
  952. }
  953. else
  954. {
  955. char *buf = g_strdup_vprintf (format, args);
  956. protobuf_c_data_buffer_append_foreign (buffer, buf, strlen (buf), g_free, buf);
  957. }
  958. }
  959. /* --- protobuf_c_data_buffer_polystr_index_of implementation --- */
  960. /* Test to see if a sequence of buffer fragments
  961. * starts with a particular NUL-terminated string.
  962. */
  963. static gboolean
  964. fragment_n_str(ProtobufCDataBufferFragment *frag,
  965. size_t frag_index,
  966. const char *string)
  967. {
  968. size_t len = strlen (string);
  969. for (;;)
  970. {
  971. size_t test_len = frag->buf_length - frag_index;
  972. if (test_len > len)
  973. test_len = len;
  974. if (memcmp (string,
  975. protobuf_c_data_buffer_fragment_start (frag) + frag_index,
  976. test_len) != 0)
  977. return FALSE;
  978. len -= test_len;
  979. string += test_len;
  980. if (len <= 0)
  981. return TRUE;
  982. frag_index += test_len;
  983. if (frag_index >= frag->buf_length)
  984. {
  985. frag = frag->next;
  986. if (frag == NULL)
  987. return FALSE;
  988. }
  989. }
  990. }
  991. /**
  992. * protobuf_c_data_buffer_polystr_index_of:
  993. * @buffer: buffer to scan.
  994. * @strings: NULL-terminated set of string.
  995. *
  996. * Scans for the first instance of any of the strings
  997. * in the buffer.
  998. *
  999. * returns: the index of that instance, or -1 if not found.
  1000. */
  1001. int
  1002. protobuf_c_data_buffer_polystr_index_of (ProtobufCDataBuffer *buffer,
  1003. char **strings)
  1004. {
  1005. uint8_t init_char_map[16];
  1006. int num_strings;
  1007. int num_bits = 0;
  1008. int total_index = 0;
  1009. ProtobufCDataBufferFragment *frag;
  1010. memset (init_char_map, 0, sizeof (init_char_map));
  1011. for (num_strings = 0; strings[num_strings] != NULL; num_strings++)
  1012. {
  1013. uint8_t c = strings[num_strings][0];
  1014. uint8_t mask = (1 << (c % 8));
  1015. uint8_t *rack = init_char_map + (c / 8);
  1016. if ((*rack & mask) == 0)
  1017. {
  1018. *rack |= mask;
  1019. num_bits++;
  1020. }
  1021. }
  1022. if (num_bits == 0)
  1023. return 0;
  1024. for (frag = buffer->first_frag; frag != NULL; frag = frag->next)
  1025. {
  1026. const char *frag_start;
  1027. const char *at;
  1028. int remaining = frag->buf_length;
  1029. frag_start = protobuf_c_data_buffer_fragment_start (frag);
  1030. at = frag_start;
  1031. while (at != NULL)
  1032. {
  1033. const char *start = at;
  1034. if (num_bits == 1)
  1035. {
  1036. at = memchr (start, strings[0][0], remaining);
  1037. if (at == NULL)
  1038. remaining = 0;
  1039. else
  1040. remaining -= (at - start);
  1041. }
  1042. else
  1043. {
  1044. while (remaining > 0)
  1045. {
  1046. uint8_t i = (uint8_t) (*at);
  1047. if (init_char_map[i / 8] & (1 << (i % 8)))
  1048. break;
  1049. remaining--;
  1050. at++;
  1051. }
  1052. if (remaining == 0)
  1053. at = NULL;
  1054. }
  1055. if (at == NULL)
  1056. break;
  1057. /* Now test each of the strings manually. */
  1058. {
  1059. char **test;
  1060. for (test = strings; *test != NULL; test++)
  1061. {
  1062. if (fragment_n_str(frag, at - frag_start, *test))
  1063. return total_index + (at - frag_start);
  1064. }
  1065. at++;
  1066. }
  1067. }
  1068. total_index += frag->buf_length;
  1069. }
  1070. return -1;
  1071. }
  1072. #endif