123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- * Copyright (c) 2018 Markus Hennecke <markus-hennecke@markus-hennecke.de>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <endian.h>
- #include <err.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <zlib.h>
- #include "buffer.h"
- #define DEFLATE_BUF_SIZE 0x4000
- #define GZIP_ENCODING 16
- #define OS_CODE 0x03
- #define ORIG_NAME 0x08
- struct buffer *
- buffer_new(const char *_data)
- {
- size_t data_len = strlen(_data);
- struct buffer *buf = malloc(sizeof(struct buffer) + data_len);
- if (buf == NULL)
- err(1, NULL);
- buf->size = data_len;
- memcpy(buf->data, _data, data_len);
- return buf;
- }
- struct buffer *
- buffer_bin_new(const void *_data, size_t _size)
- {
- struct buffer *buf = malloc(sizeof(struct buffer) + _size);
- if (buf == NULL)
- err(1, NULL);
- buf->size = _size;
- memcpy(buf->data, _data, _size);
- return buf;
- }
- struct buffer *
- buffer_empty_new(size_t _size)
- {
- struct buffer *buf = malloc(sizeof(struct buffer) + _size);
- if (buf == NULL)
- err(1, NULL);
- buf->size = _size;
- return buf;
- }
- struct buffer_list *
- buffer_list_new(void)
- {
- struct buffer_list *bl = malloc(sizeof(struct buffer_list));
- if (bl == NULL)
- err(1, NULL);
- TAILQ_INIT(&bl->buffers);
- bl->size = 0;
- return bl;
- }
- void
- buffer_list_free(struct buffer_list *_bl)
- {
- if (_bl) {
- struct buffer *b;
- while ((b = buffer_list_rem_head(_bl)))
- free(b);
- }
- }
- ssize_t
- buffer_write(struct buffer *_buf, int _fd)
- {
- size_t off;
- ssize_t nw;
- for (off = 0; off < _buf->size; off += nw) {
- if ((nw = write(_fd, _buf->data + off, _buf->size - off)) == 0
- || nw == -1) {
- warn("write");
- return -1;
- }
- }
- return _buf->size;
- }
- char *
- buffer_list_concat_string(struct buffer_list *_bl)
- {
- struct buffer *buf;
- char *out_string = malloc(_bl->size + 1);
- if (out_string == NULL)
- err(1, NULL);
- char *next_out = out_string;
- TAILQ_FOREACH(buf, &_bl->buffers, entries) {
- memcpy(next_out, buf->data, buf->size);
- next_out += buf->size;
- }
- *next_out = '\0';
- return out_string;
- }
- char *
- buffer_list_concat(struct buffer_list *_bl)
- {
- struct buffer *buf;
- char *out = malloc(_bl->size);
- if (out == NULL)
- err(1, NULL);
- char *next_out = out;
- TAILQ_FOREACH(buf, &_bl->buffers, entries) {
- memcpy(next_out, buf->data, buf->size);
- next_out += buf->size;
- }
- return out;
- }
- void
- buffer_list_add_string(struct buffer_list *_bl, const char *_s)
- {
- struct buffer *buf = buffer_new(_s);
- TAILQ_INSERT_TAIL(&_bl->buffers, buf, entries);
- _bl->size += buf->size;
- }
- void
- buffer_list_add_stringn(struct buffer_list *_bl, const char *_s, size_t _len)
- {
- struct buffer *buf = buffer_empty_new(_len);
- memcpy(buf->data, _s, _len);
- TAILQ_INSERT_TAIL(&_bl->buffers, buf, entries);
- _bl->size += _len;
- }
- void
- buffer_list_add(struct buffer_list *_bl, const void *_data, size_t _size)
- {
- struct buffer *buf = buffer_bin_new(_data, _size);
- TAILQ_INSERT_TAIL(&_bl->buffers, buf, entries);
- _bl->size += buf->size;
- }
- void
- buffer_list_add_buffer(struct buffer_list *_bl, struct buffer *_buf)
- {
- TAILQ_INSERT_TAIL(&_bl->buffers, _buf, entries);
- _bl->size += _buf->size;
- }
- void
- buffer_list_add_list(struct buffer_list *_bl, struct buffer_list *_add)
- {
- struct buffer *b;
- while (_add && (b = buffer_list_rem_head(_add)))
- buffer_list_add_buffer(_bl, b);
- }
- struct buffer *
- buffer_list_rem_head(struct buffer_list *_bl)
- {
- if (! TAILQ_EMPTY(&_bl->buffers)) {
- struct buffer *b = TAILQ_FIRST(&_bl->buffers);
- _bl->size -= b->size;
- TAILQ_REMOVE(&_bl->buffers, b, entries);
- return b;
- }
- return NULL;
- }
- struct buffer *
- buffer_list_rem_tail(struct buffer_list *_bl)
- {
- if (! TAILQ_EMPTY(&_bl->buffers)) {
- struct buffer *b = TAILQ_LAST(&_bl->buffers, buffer_list_head);
- _bl->size -= b->size;
- TAILQ_REMOVE(&_bl->buffers, b, entries);
- return b;
- }
- return NULL;
- }
- struct buffer *
- buffer_list_rem(struct buffer_list *_bl, struct buffer *_buf)
- {
- struct buffer *b;
- TAILQ_FOREACH(b, &_bl->buffers, entries) {
- if (b == _buf) {
- _bl->size -= _buf->size;
- TAILQ_REMOVE(&_bl->buffers, b, entries);
- return b;
- }
- }
- return _buf;
- }
- struct buffer_list *
- buffer_list_gzip(struct buffer_list *_in, const char *_name, uint32_t _mtime)
- {
- z_stream strm = { 0 };
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- u_int32_t crc = crc32(0L, Z_NULL, 0);
- int rc;
- if ((rc = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED,
- -MAX_WBITS, 9,
- Z_DEFAULT_STRATEGY)) != Z_OK)
- errx(1, "deflateInit2: %s", zError(rc));
- struct buffer *input, *output;
- struct buffer_list *out = buffer_list_new();
- unsigned char gzip_header[10];
- gzip_header[0] = 0x1f;
- gzip_header[1] = 0x8b;
- gzip_header[2] = Z_DEFLATED;
- gzip_header[3] = (_name) ? ORIG_NAME : 0;
- gzip_header[4] = _mtime & 0xff;
- gzip_header[5] = _mtime >> 8;
- gzip_header[6] = _mtime >> 16;
- gzip_header[7] = _mtime >> 24;
- gzip_header[8] = 2;
- gzip_header[9] = OS_CODE;
- buffer_list_add(out, gzip_header, sizeof(gzip_header));
- if (_name)
- buffer_list_add(out, _name, strlen(_name) + 1);
- output = buffer_empty_new(DEFLATE_BUF_SIZE);
- strm.total_in = _in->size;
- strm.next_out = output->data;
- strm.avail_out = DEFLATE_BUF_SIZE;
- TAILQ_FOREACH(input, &_in->buffers, entries) {
- strm.avail_in = input->size;
- strm.next_in = input->data;
- while (strm.avail_in) {
- if ((rc = deflate(&strm, Z_NO_FLUSH)) != Z_OK)
- errx(1, "deflate: %s", zError(rc));
- if (strm.avail_out == 0) {
- buffer_list_add_buffer(out, output);
- output = buffer_empty_new(DEFLATE_BUF_SIZE);
- strm.next_out = output->data;
- strm.avail_out = DEFLATE_BUF_SIZE;
- }
- }
- crc = crc32(crc, input->data, input->size);
- }
- if ((rc = deflate(&strm, Z_FINISH)) != Z_STREAM_END)
- errx(1, "deflate: %s", zError(rc));
- if ((rc = deflateEnd(&strm)) != Z_OK)
- errx(1, "deflateEnd: %s", zError(rc));
- size_t last_buf_size = DEFLATE_BUF_SIZE - strm.avail_out;
- if (last_buf_size != 0) {
- buffer_list_add(out, output->data, last_buf_size);
- u_int32_t y = htole32(crc);
- buffer_list_add(out, &y, sizeof(u_int32_t));
- u_int32_t s = htole32(_in->size & 0xffffffff);
- buffer_list_add(out, &s, sizeof(u_int32_t));
- }
- free(output);
- return out;
- }
|