chunk basis.
Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
int zck_comp_close(zckCtx *zck);
/* Compress data src of size src_size, and write to chunk */
int zck_compress(zckCtx *zck, const char *src, const size_t src_size);
+/* Finish compressing chunk */
+int zck_end_chunk(zckCtx *zck);
/* Decompress data src of size src_size, and write to dst, while setting
* dst_size */
int zck_decompress(zckCtx *zck, const char *src, const size_t src_size,
#endif
#define BLK_SIZE 32768
+#define VALIDATE(f) if(!f) { \
+ zck_log(ZCK_LOG_ERROR, "zckCtx not initialized\n"); \
+ return False; \
+ }
static char unknown[] = "Unknown(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
};
int zck_comp_init(zckCtx *zck) {
+ VALIDATE(zck);
+
zckComp *comp = &(zck->comp);
char *dst = NULL;
size_t dst_size = 0;
if(!zck->comp.compress(comp, zck->comp.dict, zck->comp.dict_size, &dst,
&dst_size, 0))
return False;
-
if(!zck_write(zck->temp_fd, dst, dst_size)) {
free(dst);
return False;
}
zck_index_add_to_chunk(zck, dst, dst_size, zck->comp.dict_size);
+ free(dst);
+ dst = NULL;
+ dst_size = 0;
+
+ if(!zck->comp.end_chunk(comp, &dst, &dst_size, 0))
+ return False;
+ if(!zck_write(zck->temp_fd, dst, dst_size)) {
+ free(dst);
+ return False;
+ }
+ zck_index_add_to_chunk(zck, dst, dst_size, 0);
zck_index_finish_chunk(zck);
free(dst);
}
}
int zck_compress(zckCtx *zck, const char *src, const size_t src_size) {
- zckComp *comp = &(zck->comp);
- char *dst;
- size_t dst_size;
+ VALIDATE(zck);
if(!zck->comp.started) {
zck_log(ZCK_LOG_ERROR, "Compression hasn't been initialized yet\n");
if(src_size == 0)
return True;
- if(!zck->comp.compress(comp, src, src_size, &dst, &dst_size, 1))
+ char *dst = NULL;
+ size_t dst_size = 0;
+ if(!zck->comp.compress(&(zck->comp), src, src_size, &dst, &dst_size, 1))
return False;
+ if(dst_size > 0 && !zck_write(zck->temp_fd, dst, dst_size)) {
+ free(dst);
+ return False;
+ }
+ if(!zck_index_add_to_chunk(zck, dst, dst_size, src_size)) {
+ free(dst);
+ return False;
+ }
+ free(dst);
+ return True;
+}
- if(!zck_write(zck->temp_fd, dst, dst_size)) {
+int zck_end_chunk(zckCtx *zck) {
+ VALIDATE(zck);
+
+ if(!zck->comp.started) {
+ zck_log(ZCK_LOG_ERROR, "Compression hasn't been initialized yet\n");
+ return False;
+ }
+
+ /* No point in compressing empty data */
+ if(zck->comp.data_size == 0) {
+ if(!zck_index_finish_chunk(zck))
+ return False;
+ return True;
+ }
+
+ char *dst = NULL;
+ size_t dst_size = 0;
+ if(!zck->comp.end_chunk(&(zck->comp), &dst, &dst_size, 1))
+ return False;
+ if(dst_size > 0 && !zck_write(zck->temp_fd, dst, dst_size)) {
+ free(dst);
+ return False;
+ }
+ if(!zck_index_add_to_chunk(zck, dst, dst_size, 0)) {
+ free(dst);
+ return False;
+ }
+ if(!zck_index_finish_chunk(zck)) {
free(dst);
return False;
}
- zck_index_add_to_chunk(zck, dst, dst_size, src_size);
- zck_index_finish_chunk(zck);
free(dst);
return True;
}
int zck_decompress(zckCtx *zck, const char *src, const size_t src_size,
char **dst, size_t dst_size) {
+ VALIDATE(zck);
+
zckComp *comp = &(zck->comp);
*dst = NULL;
}
int zck_comp_close(zckCtx *zck) {
- if(zck->comp.cctx) {
- zck->comp.started = 0;
- return zck->comp.close(&(zck->comp));
- }
- return True;
+ VALIDATE(zck);
+
+ zck->comp.started = 0;
+ if(zck->comp.close == NULL)
+ return True;
+ return zck->comp.close(&(zck->comp));
}
int zck_set_compression_type(zckCtx *zck, int type) {
+ VALIDATE(zck);
+
zckComp *comp = &(zck->comp);
/* Cannot change compression type after compression has started */
}
int zck_set_comp_parameter(zckCtx *zck, int option, void *value) {
+ VALIDATE(zck);
+
/* Cannot change compression parameters after compression has started */
if(zck && zck->comp.started) {
zck_log(ZCK_LOG_ERROR,
return True;
}
+static int zck_nocomp_end_chunk(zckComp *comp, char **dst, size_t *dst_size,
+ int use_dict) {
+ *dst = NULL;
+ *dst_size = 0;
+
+ return True;
+}
+
static int zck_nocomp_comp(zckComp *comp, const char *src, const size_t src_size,
- char **dst, size_t *dst_size, int use_dict) {
+ char **dst, size_t *dst_size, int use_dict) {
*dst = zmalloc(src_size);
if(dst == NULL) {
zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", src_size);
return True;
}
-static int zck_nocomp_decomp(zckComp *comp, const char *src, const size_t src_size,
- char **dst, size_t dst_size, int use_dict) {
+static int zck_nocomp_decomp(zckComp *comp, const char *src,
+ const size_t src_size, char **dst, size_t dst_size,
+ int use_dict) {
*dst = zmalloc(src_size);
if(dst == NULL) {
zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", src_size);
comp->init = zck_nocomp_init;
comp->set_parameter = zck_nocomp_set_parameter;
comp->compress = zck_nocomp_comp;
+ comp->end_chunk = zck_nocomp_end_chunk;
comp->decompress = zck_nocomp_decomp;
comp->close = zck_nocomp_close;
comp->type = ZCK_COMP_NONE;
#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <zstd.h>
#include <zck.h>
#include "zck_private.h"
-static int zck_zstd_init(zckComp *comp) {
+#define VALIDATE(f) if(!f) { \
+ zck_log(ZCK_LOG_ERROR, "zckComp not initialized\n"); \
+ return False; \
+ }
+
+static int init(zckComp *comp) {
comp->cctx = ZSTD_createCCtx();
comp->dctx = ZSTD_createDCtx();
if(comp->dict && comp->dict_size > 0) {
return True;
}
-static int zck_zstd_compress(zckComp *comp, const char *src,
- const size_t src_size, char **dst,
- size_t *dst_size, int use_dict) {
- size_t max_size = ZSTD_compressBound(src_size);
+/* The zstd compression format doesn't allow streaming compression with a dict
+ * unless you statically link to it. If we have a dict, we do pseudo-streaming
+ * compression where we buffer the data until the chunk ends. */
+static int compress(zckComp *comp, const char *src, const size_t src_size,
+ char **dst, size_t *dst_size, int use_dict) {
+ if(comp->data == NULL)
+ comp->data = zmalloc(src_size);
+ else
+ comp->data = realloc(comp->data, comp->data_size + src_size);
+ if(comp->data == NULL) {
+ zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n",
+ comp->data_size + src_size);
+ return False;
+ }
+ memcpy(comp->data + comp->data_size, src, src_size);
+ *dst = NULL;
+ *dst_size = 0;
+ comp->data_size += src_size;
+ return True;
+}
+
+static int end_chunk(zckComp *comp, char **dst, size_t *dst_size,
+ int use_dict) {
+ VALIDATE(comp);
+ size_t max_size = ZSTD_compressBound(comp->data_size);
if(ZSTD_isError(max_size)) {
zck_log(ZCK_LOG_ERROR, "zstd compression error: %s\n",
ZSTD_getErrorName(max_size));
}
if(use_dict && comp->cdict_ctx) {
- *dst_size = ZSTD_compress_usingCDict(comp->cctx, *dst, max_size, src,
- src_size, comp->cdict_ctx);
+ *dst_size = ZSTD_compress_usingCDict(comp->cctx, *dst, max_size,
+ comp->data, comp->data_size,
+ comp->cdict_ctx);
} else {
- *dst_size = ZSTD_compressCCtx(comp->cctx, *dst, max_size, src, src_size,
- comp->level);
+ *dst_size = ZSTD_compressCCtx(comp->cctx, *dst, max_size, comp->data,
+ comp->data_size, comp->level);
}
+ free(comp->data);
+ comp->data = NULL;
+ comp->data_size = 0;
if(ZSTD_isError(*dst_size)) {
zck_log(ZCK_LOG_ERROR, "zstd compression error: %s\n",
ZSTD_getErrorName(*dst_size));
return True;
}
-static int zck_zstd_decompress(zckComp *comp, const char *src,
- const size_t src_size, char **dst,
- size_t dst_size, int use_dict) {
+static int decompress(zckComp *comp, const char *src, const size_t src_size,
+ char **dst, size_t dst_size, int use_dict) {
+ VALIDATE(comp);
+
*dst = zmalloc(dst_size);
if(dst == NULL) {
zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n", dst_size);
return True;
}
-static int zck_zstd_close(zckComp *comp) {
+static int close(zckComp *comp) {
if(comp->cdict_ctx) {
ZSTD_freeCDict(comp->cdict_ctx);
comp->cdict_ctx = NULL;
ZSTD_freeDCtx(comp->dctx);
comp->dctx = NULL;
}
+ if(comp->data) {
+ free(comp->data);
+ comp->data = NULL;
+ }
+ comp->data_size = 0;
return True;
}
-static int zck_zstd_set_parameter(zckComp *comp, int option, void *value) {
+static int set_parameter(zckComp *comp, int option, void *value) {
if(option == ZCK_ZCK_COMP_LEVEL) {
if(*(int*)value >= 0 && *(int*)value <= ZSTD_maxCLevel()) {
comp->level = *(int*)value;
return False;
}
-static int zck_zstd_set_default_parameters(zckComp *comp) {
+static int set_default_parameters(zckComp *comp) {
/* Set default compression level to 16 */
int level=16;
- return zck_zstd_set_parameter(comp, ZCK_ZCK_COMP_LEVEL, &level);
+ return set_parameter(comp, ZCK_ZCK_COMP_LEVEL, &level);
}
int zck_zstd_setup(zckComp *comp) {
- comp->init = zck_zstd_init;
- comp->set_parameter = zck_zstd_set_parameter;
- comp->compress = zck_zstd_compress;
- comp->decompress = zck_zstd_decompress;
- comp->close = zck_zstd_close;
+ comp->init = init;
+ comp->set_parameter = set_parameter;
+ comp->compress = compress;
+ comp->end_chunk = end_chunk;
+ comp->decompress = decompress;
+ comp->close = close;
comp->type = ZCK_COMP_ZSTD;
- return zck_zstd_set_default_parameters(comp);
+ return set_default_parameters(comp);
}
size_t orig_size) {
VALIDATE(zck);
- if(comp_size == 0)
- return True;
-
if(zck->work_index_item == NULL && !zck_index_create_chunk(zck))
return False;
+ zck->work_index_item->length += orig_size;
+ if(comp_size == 0)
+ return True;
+
if(!zck_hash_update(&(zck->full_hash), data, comp_size))
return False;
if(!zck_hash_update(&(zck->work_index_hash), data, comp_size))
return False;
zck->work_index_item->comp_length += comp_size;
- zck->work_index_item->length += orig_size;
return True;
}
"Attempting to initialize an empty compression dictionary\n");
return False;
}
+ zck_log(ZCK_LOG_DEBUG, "Closing compression\n");
if(!zck_comp_close(zck))
return False;
+ zck_log(ZCK_LOG_DEBUG, "setting dict 1\n");
if(!zck_set_comp_parameter(zck, ZCK_COMMON_DICT, data))
return False;
+ zck_log(ZCK_LOG_DEBUG, "setting dict 2\n");
if(!zck_set_comp_parameter(zck, ZCK_COMMON_DICT_SIZE, &size))
return False;
+ zck_log(ZCK_LOG_DEBUG, "Initializing\n");
if(!zck_comp_init(zck))
return False;
return True;
"Unable to calculate %s checksum for full file\n");
return False;
}
+ zck_log(ZCK_LOG_DEBUG, "Checking data checksum\n");
if(memcmp(digest, zck->full_hash_digest, zck->hash_type.digest_size) != 0) {
free(digest);
- zck_log(ZCK_LOG_ERROR, "Final file failed checksum\n");
+ zck_log(ZCK_LOG_ERROR, "Data checksum failed!\n");
return False;
}
+ zck_log(ZCK_LOG_DEBUG, "Data checksum valid\n");
free(digest);
return True;
}
typedef int (*finit)(struct zckComp *comp);
typedef int (*fparam)(struct zckComp *comp, int option, void *value);
+typedef int (*fcompend)(struct zckComp *comp, char **dst, size_t *dst_size,
+ int use_dict);
typedef int (*fcomp)(struct zckComp *comp, const char *src,
const size_t src_size, char **dst, size_t *dst_size,
int use_dict);
void *ddict_ctx;
void *dict;
size_t dict_size;
+
+ char *data;
+ size_t data_size;
+
finit init;
fparam set_parameter;
fcomp compress;
+ fcompend end_chunk;
fdecomp decompress;
fcclose close;
} zckComp;
char *out_name;
char *dict = NULL;
size_t dict_size = 0;
- zckCtx *zck = zck_create();
zck_set_log_level(ZCK_LOG_DEBUG);
exit(1);
}
free(out_name);
+
+ zckCtx *zck = zck_create();
+ if(zck == NULL)
+ exit(1);
if(!zck_init_write(zck, dst_fd))
exit(1);
printf("Compressing %li bytes\n", next-found);
if(!zck_compress(zck, found, next-found))
exit(1);
+ if(!zck_end_chunk(zck))
+ exit(1);
found = next;
search = next + 1;
if(search > data + in_size)
printf("Completing %li bytes\n", data+in_size-found);
if(!zck_compress(zck, found, data+in_size-found))
exit(1);
+ if(!zck_end_chunk(zck))
+ exit(1);
search = NULL;
}
}
printf("Completing %li bytes\n", cur_loc-start);
if(!zck_compress(zck, start, cur_loc-start))
exit(1);
+ if(!zck_end_chunk(zck))
+ exit(1);
start = cur_loc;
}
}