compress_buf.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /* Copyright (c) 2003, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file compress_buf.c
  7. *
  8. * \brief Working with compressed data in buffers.
  9. **/
  10. #define BUFFERS_PRIVATE
  11. #include "lib/cc/compat_compiler.h"
  12. #include "lib/container/buffers.h"
  13. #include "lib/compress/compress.h"
  14. #include "lib/log/util_bug.h"
  15. #ifdef PARANOIA
  16. /** Helper: If PARANOIA is defined, assert that the buffer in local variable
  17. * <b>buf</b> is well-formed. */
  18. #define check() STMT_BEGIN buf_assert_ok(buf); STMT_END
  19. #else
  20. #define check() STMT_NIL
  21. #endif /* defined(PARANOIA) */
  22. /** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the
  23. * compression state <b>state</b>, appending the result to <b>buf</b>. If
  24. * <b>done</b> is true, flush the data in the state and finish the
  25. * compression/uncompression. Return -1 on failure, 0 on success. */
  26. int
  27. buf_add_compress(buf_t *buf, tor_compress_state_t *state,
  28. const char *data, size_t data_len,
  29. const int done)
  30. {
  31. char *next;
  32. size_t old_avail, avail;
  33. int over = 0;
  34. do {
  35. int need_new_chunk = 0;
  36. if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) {
  37. size_t cap = data_len / 4;
  38. buf_add_chunk_with_capacity(buf, cap, 1);
  39. }
  40. next = CHUNK_WRITE_PTR(buf->tail);
  41. avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail);
  42. switch (tor_compress_process(state, &next, &avail,
  43. &data, &data_len, done)) {
  44. case TOR_COMPRESS_DONE:
  45. over = 1;
  46. break;
  47. case TOR_COMPRESS_ERROR:
  48. return -1;
  49. case TOR_COMPRESS_OK:
  50. if (data_len == 0) {
  51. tor_assert_nonfatal(!done);
  52. over = 1;
  53. }
  54. break;
  55. case TOR_COMPRESS_BUFFER_FULL:
  56. if (avail) {
  57. /* The compression module says we need more room
  58. * (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically,
  59. * whether were going to or not. */
  60. need_new_chunk = 1;
  61. }
  62. if (data_len == 0 && !done) {
  63. /* We've consumed all the input data, though, so there's no
  64. * point in forging ahead right now. */
  65. over = 1;
  66. }
  67. break;
  68. }
  69. buf->datalen += old_avail - avail;
  70. buf->tail->datalen += old_avail - avail;
  71. if (need_new_chunk) {
  72. buf_add_chunk_with_capacity(buf, data_len/4, 1);
  73. }
  74. } while (!over);
  75. check();
  76. return 0;
  77. }