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