libropkg: implement compressed file streams and tar-writer functionality
This commit is contained in:
14
libropkg/CMakeLists.txt
Normal file
14
libropkg/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
file(GLOB sources *.c include/ropkg/*.h)
|
||||||
|
|
||||||
|
add_library(libropkg SHARED ${sources})
|
||||||
|
|
||||||
|
set_target_properties(libropkg PROPERTIES
|
||||||
|
OUTPUT_NAME ropkg)
|
||||||
|
target_link_libraries(libropkg
|
||||||
|
${ZSTD_LIBRARY})
|
||||||
|
target_include_directories(libropkg PUBLIC
|
||||||
|
include/
|
||||||
|
${ZSTD_INCLUDE_DIR})
|
||||||
|
target_compile_definitions(libropkg PRIVATE
|
||||||
|
LIBROPKG_EXPORT=1
|
||||||
|
LIBROPKG_STATIC=0)
|
||||||
86
libropkg/compress.c
Normal file
86
libropkg/compress.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include "compress.h"
|
||||||
|
|
||||||
|
#include <ropkg/compress.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern const struct ropkg_compression_function ropkg_zstd;
|
||||||
|
|
||||||
|
static const struct ropkg_compression_function *functions[] = {
|
||||||
|
[ROPKG_COMPRESSION_ZSTD] = &ropkg_zstd,
|
||||||
|
};
|
||||||
|
static const size_t nr_functions = sizeof functions / sizeof functions[0];
|
||||||
|
|
||||||
|
const struct ropkg_compression_function *ropkg_compression_function_for_type(
|
||||||
|
enum ropkg_compression_type type)
|
||||||
|
{
|
||||||
|
if (type >= nr_functions) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return functions[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_compression_function_get_buffer_size(
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
enum ropkg_compression_stream_mode mode,
|
||||||
|
size_t *in_buffer_size,
|
||||||
|
size_t *out_buffer_size)
|
||||||
|
{
|
||||||
|
if (!func->f_buffer_size) {
|
||||||
|
return ROPKG_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return func->f_buffer_size(mode, in_buffer_size, out_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ropkg_compression_function_get_file_extension(
|
||||||
|
const struct ropkg_compression_function *func)
|
||||||
|
{
|
||||||
|
return func->f_extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_compression_stream_open(
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
void *in_buffer,
|
||||||
|
size_t in_max,
|
||||||
|
void *out_buffer,
|
||||||
|
size_t out_max,
|
||||||
|
enum ropkg_compression_stream_mode mode,
|
||||||
|
struct ropkg_compression_stream **out)
|
||||||
|
{
|
||||||
|
if (!func->f_open) {
|
||||||
|
return ROPKG_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return func->f_open(
|
||||||
|
func,
|
||||||
|
mode,
|
||||||
|
in_buffer,
|
||||||
|
in_max,
|
||||||
|
out_buffer,
|
||||||
|
out_max,
|
||||||
|
out);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_compression_stream_process(
|
||||||
|
struct ropkg_compression_stream *stream,
|
||||||
|
size_t in_size,
|
||||||
|
enum ropkg_compression_stream_op op,
|
||||||
|
size_t *out_size)
|
||||||
|
{
|
||||||
|
if (!stream->s_func->f_process) {
|
||||||
|
return ROPKG_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream->s_func->f_process(stream, in_size, op, out_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_compression_stream_close(
|
||||||
|
struct ropkg_compression_stream *stream)
|
||||||
|
{
|
||||||
|
if (!stream->s_func->f_close) {
|
||||||
|
return ROPKG_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream->s_func->f_close(stream);
|
||||||
|
}
|
||||||
36
libropkg/compress.h
Normal file
36
libropkg/compress.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef COMPRESS_H_
|
||||||
|
#define COMPRESS_H_
|
||||||
|
|
||||||
|
#include <ropkg/compress.h>
|
||||||
|
|
||||||
|
struct ropkg_compression_function {
|
||||||
|
const char *f_name;
|
||||||
|
const char *f_extension;
|
||||||
|
enum ropkg_status (*f_buffer_size)(
|
||||||
|
enum ropkg_compression_stream_mode,
|
||||||
|
size_t *,
|
||||||
|
size_t *);
|
||||||
|
enum ropkg_status (*f_open)(
|
||||||
|
const struct ropkg_compression_function *,
|
||||||
|
enum ropkg_compression_stream_mode,
|
||||||
|
void *,
|
||||||
|
size_t,
|
||||||
|
void *,
|
||||||
|
size_t,
|
||||||
|
struct ropkg_compression_stream **);
|
||||||
|
enum ropkg_status (*f_close)(struct ropkg_compression_stream *);
|
||||||
|
enum ropkg_status (*f_process)(
|
||||||
|
struct ropkg_compression_stream *,
|
||||||
|
size_t,
|
||||||
|
enum ropkg_compression_stream_op,
|
||||||
|
size_t *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_compression_stream {
|
||||||
|
const struct ropkg_compression_function *s_func;
|
||||||
|
enum ropkg_compression_stream_mode s_mode;
|
||||||
|
void *s_in, *s_out;
|
||||||
|
size_t s_in_max, s_out_max;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
53
libropkg/include/ropkg/compress.h
Normal file
53
libropkg/include/ropkg/compress.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef ROPKG_COMPRESS_H_
|
||||||
|
#define ROPKG_COMPRESS_H_
|
||||||
|
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct ropkg_compression_function;
|
||||||
|
struct ropkg_compression_stream;
|
||||||
|
|
||||||
|
enum ropkg_compression_stream_mode {
|
||||||
|
ROPKG_COMPRESSION_MODE_COMPRESS = 0,
|
||||||
|
ROPKG_COMPRESSION_MODE_DECOMPRESS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ropkg_compression_stream_op {
|
||||||
|
ROPKG_COMPRESSION_OP_CONTINUE = 0,
|
||||||
|
ROPKG_COMPRESSION_OP_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ropkg_compression_type {
|
||||||
|
ROPKG_COMPRESSION_NONE = 0,
|
||||||
|
ROPKG_COMPRESSION_ZSTD,
|
||||||
|
};
|
||||||
|
|
||||||
|
ROPKG_API const struct ropkg_compression_function *
|
||||||
|
ropkg_compression_function_for_type(enum ropkg_compression_type type);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_compression_function_get_buffer_size(
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
enum ropkg_compression_stream_mode mode,
|
||||||
|
size_t *in_buffer_size,
|
||||||
|
size_t *out_buffer_size);
|
||||||
|
ROPKG_API const char *ropkg_compression_function_get_file_extension(
|
||||||
|
const struct ropkg_compression_function *func);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_compression_stream_open(
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
void *in_buffer,
|
||||||
|
size_t in_max,
|
||||||
|
void *out_buffer,
|
||||||
|
size_t out_max,
|
||||||
|
enum ropkg_compression_stream_mode mode,
|
||||||
|
struct ropkg_compression_stream **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_compression_stream_process(
|
||||||
|
struct ropkg_compression_stream *stream,
|
||||||
|
size_t in_size,
|
||||||
|
enum ropkg_compression_stream_op op,
|
||||||
|
size_t *out_size);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_compression_stream_close(
|
||||||
|
struct ropkg_compression_stream *stream);
|
||||||
|
|
||||||
|
#endif
|
||||||
18
libropkg/include/ropkg/misc.h
Normal file
18
libropkg/include/ropkg/misc.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef ROPKG_MISC_H_
|
||||||
|
#define ROPKG_MISC_H_
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#ifdef LIBROPKG_STATIC
|
||||||
|
#define ROPKG_API extern
|
||||||
|
#else
|
||||||
|
#ifdef LIBROPKG_EXPORT
|
||||||
|
#define ROPKG_API extern __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define ROPKG_API extern __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ROPKG_API extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
14
libropkg/include/ropkg/status.h
Normal file
14
libropkg/include/ropkg/status.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef ROPKG_STATUS_H_
|
||||||
|
#define ROPKG_STATUS_H_
|
||||||
|
|
||||||
|
enum ropkg_status {
|
||||||
|
ROPKG_SUCCESS = 0,
|
||||||
|
ROPKG_ERR_NOT_SUPPORTED,
|
||||||
|
ROPKG_ERR_INVALID_ARGUMENT,
|
||||||
|
ROPKG_ERR_NO_MEMORY,
|
||||||
|
ROPKG_ERR_BAD_STATE,
|
||||||
|
ROPKG_ERR_INTERNAL_FAILURE,
|
||||||
|
ROPKG_ERR_IO_FAILURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
58
libropkg/include/ropkg/stream.h
Normal file
58
libropkg/include/ropkg/stream.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef ROPKG_STREAM_H_
|
||||||
|
#define ROPKG_STREAM_H_
|
||||||
|
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct ropkg_stream;
|
||||||
|
struct ropkg_compression_function;
|
||||||
|
|
||||||
|
enum ropkg_stream_mode {
|
||||||
|
ROPKG_STREAM_READ,
|
||||||
|
ROPKG_STREAM_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_open(
|
||||||
|
FILE *fp,
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
enum ropkg_stream_mode mode,
|
||||||
|
struct ropkg_stream **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_close(struct ropkg_stream *stream);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_begin_compressed_section(
|
||||||
|
struct ropkg_stream *stream);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_end_compressed_section(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
size_t *out_nr_written_compressed,
|
||||||
|
size_t *out_nr_written_uncompressed);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_read(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
void *p,
|
||||||
|
size_t len,
|
||||||
|
size_t *nr_read);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_write(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
const void *p,
|
||||||
|
size_t len,
|
||||||
|
size_t *nr_written);
|
||||||
|
|
||||||
|
ROPKG_API size_t ropkg_stream_get_cursor_position(struct ropkg_stream *stream);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_set_cursor_position(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
size_t pos);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_stream_restore_cursor_position(
|
||||||
|
struct ropkg_stream *stream);
|
||||||
|
|
||||||
|
ROPKG_API bool ropkg_stream_is_in_compressed_section(
|
||||||
|
struct ropkg_stream *stream);
|
||||||
|
|
||||||
|
ROPKG_API size_t ropkg_stream_get_nr_written(struct ropkg_stream *stream);
|
||||||
|
ROPKG_API size_t
|
||||||
|
ropkg_stream_get_nr_written_compressed(struct ropkg_stream *stream);
|
||||||
|
ROPKG_API size_t
|
||||||
|
ropkg_stream_get_nr_written_uncompressed(struct ropkg_stream *stream);
|
||||||
|
|
||||||
|
#endif
|
||||||
36
libropkg/include/ropkg/writer.h
Normal file
36
libropkg/include/ropkg/writer.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef ROPKG_WRITER_H_
|
||||||
|
#define ROPKG_WRITER_H_
|
||||||
|
|
||||||
|
#include <ropkg/misc.h>
|
||||||
|
#include <ropkg/status.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define ROPKG_PATH_DATA "data.tar"
|
||||||
|
#define ROPKG_PATH_CONTROL "control.tar"
|
||||||
|
#define ROPKG_PATH_META "meta.tar"
|
||||||
|
|
||||||
|
struct ropkg_writer;
|
||||||
|
struct ropkg_stream;
|
||||||
|
|
||||||
|
struct ropkg_writer_file_info {
|
||||||
|
size_t f_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_writer_open(
|
||||||
|
struct ropkg_stream *fp,
|
||||||
|
struct ropkg_writer **out);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_writer_close(struct ropkg_writer *pkg);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_writer_begin_file(
|
||||||
|
struct ropkg_writer *pkg,
|
||||||
|
const char *path,
|
||||||
|
const struct ropkg_writer_file_info *info);
|
||||||
|
ROPKG_API enum ropkg_status ropkg_writer_end_file(struct ropkg_writer *pkg);
|
||||||
|
|
||||||
|
ROPKG_API enum ropkg_status ropkg_writer_write(
|
||||||
|
struct ropkg_writer *pkg,
|
||||||
|
const void *p,
|
||||||
|
size_t len,
|
||||||
|
size_t *nr_written);
|
||||||
|
|
||||||
|
#endif
|
||||||
0
libropkg/status.c
Normal file
0
libropkg/status.c
Normal file
355
libropkg/stream.c
Normal file
355
libropkg/stream.c
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include <ropkg/compress.h>
|
||||||
|
#include <ropkg/stream.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_open(
|
||||||
|
FILE *fp,
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
enum ropkg_stream_mode mode,
|
||||||
|
struct ropkg_stream **out)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case ROPKG_STREAM_READ:
|
||||||
|
case ROPKG_STREAM_WRITE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ROPKG_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_stream *stream = malloc(sizeof *stream);
|
||||||
|
if (!stream) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(stream, 0x0, sizeof *stream);
|
||||||
|
|
||||||
|
stream->s_fp = fp;
|
||||||
|
stream->s_mode = mode;
|
||||||
|
|
||||||
|
if (!func) {
|
||||||
|
*out = stream;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_stream_compressor *c = &stream->s_compressor;
|
||||||
|
enum ropkg_compression_stream_mode c_mode;
|
||||||
|
switch (mode) {
|
||||||
|
case ROPKG_STREAM_READ:
|
||||||
|
c_mode = ROPKG_COMPRESSION_MODE_DECOMPRESS;
|
||||||
|
break;
|
||||||
|
case ROPKG_STREAM_WRITE:
|
||||||
|
c_mode = ROPKG_COMPRESSION_MODE_COMPRESS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* this won't happen */
|
||||||
|
return ROPKG_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status status = ropkg_compression_function_get_buffer_size(
|
||||||
|
func,
|
||||||
|
c_mode,
|
||||||
|
&c->c_in_max,
|
||||||
|
&c->c_out_max);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
free(stream);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->c_in_buf = malloc(c->c_in_max);
|
||||||
|
if (!c->c_in_buf) {
|
||||||
|
free(stream);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->c_out_buf = malloc(c->c_out_max);
|
||||||
|
if (!c->c_out_buf) {
|
||||||
|
free(c->c_in_buf);
|
||||||
|
free(stream);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ropkg_compression_stream_open(
|
||||||
|
func,
|
||||||
|
c->c_in_buf,
|
||||||
|
c->c_in_max,
|
||||||
|
c->c_out_buf,
|
||||||
|
c->c_out_max,
|
||||||
|
c_mode,
|
||||||
|
&c->c_stream);
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
free(c->c_in_buf);
|
||||||
|
free(c->c_out_buf);
|
||||||
|
free(stream);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->c_func = func;
|
||||||
|
|
||||||
|
*out = stream;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_close(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
while (stream->s_compression_depth > 0) {
|
||||||
|
ropkg_stream_end_compressed_section(stream, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compressor.c_in_buf) {
|
||||||
|
free(stream->s_compressor.c_in_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compressor.c_out_buf) {
|
||||||
|
free(stream->s_compressor.c_out_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compressor.c_stream) {
|
||||||
|
ropkg_compression_stream_close(stream->s_compressor.c_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stream);
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_begin_compressed_section(
|
||||||
|
struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
if (stream->s_flags & ROPKG_STREAM_F_CURSOR_MOVED) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compression_depth > 0) {
|
||||||
|
stream->s_compression_depth++;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->s_compression_depth = 1;
|
||||||
|
stream->s_compressor.c_in_count = 0;
|
||||||
|
stream->s_compressor.c_nr_written_compressed = 0;
|
||||||
|
stream->s_compressor.c_nr_written_uncompressed = 0;
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_end_compressed_section(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
size_t *out_nr_written_compressed,
|
||||||
|
size_t *out_nr_written_uncompressed)
|
||||||
|
{
|
||||||
|
if (stream->s_flags & ROPKG_STREAM_F_CURSOR_MOVED) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compression_depth == 0) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compression_depth > 1) {
|
||||||
|
stream->s_compression_depth--;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->s_compression_depth = 0;
|
||||||
|
struct ropkg_stream_compressor *c = &stream->s_compressor;
|
||||||
|
if (out_nr_written_compressed) {
|
||||||
|
*out_nr_written_compressed = c->c_nr_written_compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_nr_written_uncompressed) {
|
||||||
|
*out_nr_written_uncompressed = c->c_nr_written_uncompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->c_nr_written_uncompressed == 0) {
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t out_size = 0;
|
||||||
|
|
||||||
|
ropkg_compression_stream_process(
|
||||||
|
c->c_stream,
|
||||||
|
c->c_in_count,
|
||||||
|
ROPKG_COMPRESSION_OP_END,
|
||||||
|
&out_size);
|
||||||
|
|
||||||
|
size_t nr_written = fwrite(c->c_out_buf, 1, out_size, stream->s_fp);
|
||||||
|
if (nr_written != out_size) {
|
||||||
|
return ROPKG_ERR_IO_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->c_nr_written_compressed += nr_written;
|
||||||
|
stream->s_nr_written += out_size;
|
||||||
|
if (out_nr_written_compressed) {
|
||||||
|
*out_nr_written_compressed = c->c_nr_written_compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->s_compressor.c_in_count = 0;
|
||||||
|
stream->s_compressor.c_nr_written_compressed = 0;
|
||||||
|
stream->s_compressor.c_nr_written_uncompressed = 0;
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_read(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
void *p,
|
||||||
|
size_t len,
|
||||||
|
size_t *nr_read)
|
||||||
|
{
|
||||||
|
if (stream->s_mode != ROPKG_STREAM_READ) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status flush_compressed_buffer(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
struct ropkg_stream_compressor *c = &stream->s_compressor;
|
||||||
|
|
||||||
|
size_t out_size;
|
||||||
|
enum ropkg_status status = ropkg_compression_stream_process(
|
||||||
|
c->c_stream,
|
||||||
|
c->c_in_count,
|
||||||
|
ROPKG_COMPRESSION_OP_CONTINUE,
|
||||||
|
&out_size);
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t written = fwrite(c->c_out_buf, 1, out_size, stream->s_fp);
|
||||||
|
|
||||||
|
c->c_nr_written_compressed += c->c_in_count;
|
||||||
|
stream->s_nr_written_compressed = c->c_in_count;
|
||||||
|
stream->s_nr_written += out_size;
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_write(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
const void *p,
|
||||||
|
size_t len,
|
||||||
|
size_t *nr_written)
|
||||||
|
{
|
||||||
|
if (stream->s_mode != ROPKG_STREAM_WRITE) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t w = 0;
|
||||||
|
if (stream->s_compression_depth == 0) {
|
||||||
|
w = fwrite(p, 1, len, stream->s_fp);
|
||||||
|
|
||||||
|
*nr_written = w;
|
||||||
|
if (w != len) {
|
||||||
|
return ROPKG_ERR_IO_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(stream->s_flags & ROPKG_STREAM_F_CURSOR_MOVED)) {
|
||||||
|
stream->s_nr_written_uncompressed += w;
|
||||||
|
stream->s_nr_written += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_flags & ROPKG_STREAM_F_CURSOR_MOVED) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ropkg_stream_compressor *c = &stream->s_compressor;
|
||||||
|
const unsigned char *src = p;
|
||||||
|
enum ropkg_status status = ROPKG_SUCCESS;
|
||||||
|
|
||||||
|
size_t remaining = len;
|
||||||
|
while (remaining > 0 && status == ROPKG_SUCCESS) {
|
||||||
|
unsigned char *dest = c->c_in_buf + c->c_in_count;
|
||||||
|
size_t space_remaining = c->c_in_max - c->c_in_count;
|
||||||
|
|
||||||
|
size_t to_copy = remaining;
|
||||||
|
if (to_copy > space_remaining) {
|
||||||
|
to_copy = space_remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dest, src, to_copy);
|
||||||
|
|
||||||
|
c->c_in_count += to_copy;
|
||||||
|
c->c_nr_written_uncompressed += to_copy;
|
||||||
|
stream->s_nr_written_uncompressed += to_copy;
|
||||||
|
space_remaining -= to_copy;
|
||||||
|
remaining -= to_copy;
|
||||||
|
w += to_copy;
|
||||||
|
|
||||||
|
if (space_remaining == 0) {
|
||||||
|
status = flush_compressed_buffer(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*nr_written = w;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ropkg_stream_get_cursor_position(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
return ftell(stream->s_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_set_cursor_position(
|
||||||
|
struct ropkg_stream *stream,
|
||||||
|
size_t pos)
|
||||||
|
{
|
||||||
|
if (stream->s_flags & ROPKG_STREAM_F_CURSOR_MOVED) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->s_compression_depth > 0) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->s_saved_cursor = ftell(stream->s_fp);
|
||||||
|
fseek(stream->s_fp, pos, SEEK_SET);
|
||||||
|
|
||||||
|
stream->s_flags |= ROPKG_STREAM_F_CURSOR_MOVED;
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_stream_restore_cursor_position(
|
||||||
|
struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
if (!(stream->s_flags & ROPKG_STREAM_F_CURSOR_MOVED)) {
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(stream->s_fp, stream->s_saved_cursor, SEEK_SET);
|
||||||
|
stream->s_saved_cursor = 0;
|
||||||
|
|
||||||
|
stream->s_flags &= ~ROPKG_STREAM_F_CURSOR_MOVED;
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ropkg_stream_is_in_compressed_section(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
return stream->s_compression_depth > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ropkg_stream_get_nr_written(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
return stream->s_nr_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ropkg_stream_get_nr_written_compressed(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
return stream->s_nr_written_compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ropkg_stream_get_nr_written_uncompressed(struct ropkg_stream *stream)
|
||||||
|
{
|
||||||
|
return stream->s_nr_written_uncompressed;
|
||||||
|
}
|
||||||
39
libropkg/stream.h
Normal file
39
libropkg/stream.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _ROPKG_STREAM_H_
|
||||||
|
#define _ROPKG_STREAM_H_
|
||||||
|
|
||||||
|
#include <ropkg/stream.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct ropkg_compression_function;
|
||||||
|
struct ropkg_compression_stream;
|
||||||
|
|
||||||
|
enum ropkg_stream_flags {
|
||||||
|
ROPKG_STREAM_F_CURSOR_MOVED = 0x01u,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_stream_compressor {
|
||||||
|
const struct ropkg_compression_function *c_func;
|
||||||
|
struct ropkg_compression_stream *c_stream;
|
||||||
|
|
||||||
|
size_t c_in_max, c_out_max;
|
||||||
|
void *c_in_buf, *c_out_buf;
|
||||||
|
size_t c_in_count;
|
||||||
|
|
||||||
|
size_t c_nr_written_compressed, c_nr_written_uncompressed;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_stream {
|
||||||
|
FILE *s_fp;
|
||||||
|
enum ropkg_stream_flags s_flags;
|
||||||
|
enum ropkg_stream_mode s_mode;
|
||||||
|
|
||||||
|
unsigned int s_compression_depth;
|
||||||
|
struct ropkg_stream_compressor s_compressor;
|
||||||
|
|
||||||
|
size_t s_saved_cursor;
|
||||||
|
size_t s_nr_written;
|
||||||
|
size_t s_nr_written_compressed;
|
||||||
|
size_t s_nr_written_uncompressed;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
224
libropkg/writer.c
Normal file
224
libropkg/writer.c
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
#include <ropkg/compress.h>
|
||||||
|
#include <ropkg/stream.h>
|
||||||
|
#include <ropkg/writer.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct ustar_header {
|
||||||
|
char tar_filename[100];
|
||||||
|
char tar_mode[8];
|
||||||
|
char tar_uid[8];
|
||||||
|
char tar_gid[8];
|
||||||
|
char tar_filesize[12];
|
||||||
|
char tar_mtime[12];
|
||||||
|
char tar_checksum[8];
|
||||||
|
char tar_type[1];
|
||||||
|
char tar_linkname[100];
|
||||||
|
char tar_ustar_id[6];
|
||||||
|
char tar_ustar_version[2];
|
||||||
|
char tar_owner_name[32];
|
||||||
|
char tar_owner_group[32];
|
||||||
|
char tar_dev_major[8];
|
||||||
|
char tar_dev_minor[8];
|
||||||
|
char tar_filename_prefix[155];
|
||||||
|
char tar_padding[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ropkg_writer {
|
||||||
|
struct ropkg_stream *w_fp;
|
||||||
|
|
||||||
|
struct ustar_header w_file_header;
|
||||||
|
size_t w_file_header_offset;
|
||||||
|
size_t w_file_nr_written;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char zero_padding[512] = {0};
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_writer_open(
|
||||||
|
struct ropkg_stream *fp,
|
||||||
|
struct ropkg_writer **out)
|
||||||
|
{
|
||||||
|
struct ropkg_writer *writer = malloc(sizeof *writer);
|
||||||
|
if (!writer) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(writer, 0x0, sizeof *writer);
|
||||||
|
|
||||||
|
writer->w_fp = fp;
|
||||||
|
|
||||||
|
*out = writer;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_writer_close(struct ropkg_writer *pkg)
|
||||||
|
{
|
||||||
|
memset(&pkg->w_file_header, 0x0, sizeof pkg->w_file_header);
|
||||||
|
|
||||||
|
size_t nr_written;
|
||||||
|
enum ropkg_status status = ropkg_stream_write(
|
||||||
|
pkg->w_fp,
|
||||||
|
&pkg->w_file_header,
|
||||||
|
sizeof pkg->w_file_header,
|
||||||
|
&nr_written);
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ropkg_stream_write(
|
||||||
|
pkg->w_fp,
|
||||||
|
&pkg->w_file_header,
|
||||||
|
sizeof pkg->w_file_header,
|
||||||
|
&nr_written);
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_written != sizeof pkg->w_file_header) {
|
||||||
|
return ROPKG_ERR_IO_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pkg);
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void to_octal(size_t in, char *out, size_t field_size)
|
||||||
|
{
|
||||||
|
// char buf[64];
|
||||||
|
snprintf(out, field_size, "%0*zo", (int)(field_size - 1), in);
|
||||||
|
// memcpy(out, buf, field_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refresh_header_checksum(struct ustar_header *header)
|
||||||
|
{
|
||||||
|
memset(header->tar_checksum, ' ', sizeof header->tar_checksum);
|
||||||
|
|
||||||
|
size_t checksum = 0;
|
||||||
|
unsigned char *v = (unsigned char *)header;
|
||||||
|
for (size_t i = 0; i < sizeof *header; i++) {
|
||||||
|
checksum += v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
to_octal(checksum, header->tar_checksum, sizeof header->tar_checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status encode_header(
|
||||||
|
struct ropkg_writer *pkg,
|
||||||
|
const char *path,
|
||||||
|
const struct ropkg_writer_file_info *info,
|
||||||
|
struct ustar_header *out)
|
||||||
|
{
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
snprintf(out->tar_filename, sizeof out->tar_filename, "%s", path);
|
||||||
|
|
||||||
|
to_octal(info->f_length, out->tar_filesize, sizeof out->tar_filesize);
|
||||||
|
to_octal(0755, out->tar_mode, sizeof out->tar_mode);
|
||||||
|
out->tar_type[0] = '0';
|
||||||
|
snprintf(out->tar_ustar_id, sizeof out->tar_ustar_id, "ustar");
|
||||||
|
out->tar_ustar_version[0] = out->tar_ustar_version[1] = '0';
|
||||||
|
|
||||||
|
refresh_header_checksum(out);
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_writer_begin_file(
|
||||||
|
struct ropkg_writer *pkg,
|
||||||
|
const char *path,
|
||||||
|
const struct ropkg_writer_file_info *info)
|
||||||
|
{
|
||||||
|
if (ropkg_stream_is_in_compressed_section(pkg->w_fp)) {
|
||||||
|
pkg->w_file_header_offset
|
||||||
|
= ropkg_stream_get_nr_written_uncompressed(pkg->w_fp);
|
||||||
|
} else {
|
||||||
|
pkg->w_file_header_offset
|
||||||
|
= ropkg_stream_get_nr_written(pkg->w_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status status
|
||||||
|
= encode_header(pkg, path, info, &pkg->w_file_header);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nr_written;
|
||||||
|
status = ropkg_stream_write(
|
||||||
|
pkg->w_fp,
|
||||||
|
&pkg->w_file_header,
|
||||||
|
sizeof pkg->w_file_header,
|
||||||
|
&nr_written);
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_written != sizeof pkg->w_file_header) {
|
||||||
|
return ROPKG_ERR_IO_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_writer_end_file(struct ropkg_writer *pkg)
|
||||||
|
{
|
||||||
|
enum ropkg_status status;
|
||||||
|
size_t written, file_length, pos;
|
||||||
|
if (ropkg_stream_is_in_compressed_section(pkg->w_fp)) {
|
||||||
|
pos = ropkg_stream_get_nr_written_uncompressed(pkg->w_fp);
|
||||||
|
} else {
|
||||||
|
pos = ropkg_stream_get_nr_written(pkg->w_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_length
|
||||||
|
= pos - pkg->w_file_header_offset - sizeof pkg->w_file_header;
|
||||||
|
|
||||||
|
size_t required_padding = 512 - (file_length % 512);
|
||||||
|
status = ropkg_stream_write(
|
||||||
|
pkg->w_fp,
|
||||||
|
zero_padding,
|
||||||
|
required_padding,
|
||||||
|
&written);
|
||||||
|
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
to_octal(
|
||||||
|
file_length,
|
||||||
|
pkg->w_file_header.tar_filesize,
|
||||||
|
sizeof pkg->w_file_header.tar_filesize);
|
||||||
|
refresh_header_checksum(&pkg->w_file_header);
|
||||||
|
|
||||||
|
status = ropkg_stream_set_cursor_position(
|
||||||
|
pkg->w_fp,
|
||||||
|
pkg->w_file_header_offset);
|
||||||
|
if (status == ROPKG_SUCCESS) {
|
||||||
|
ropkg_stream_write(
|
||||||
|
pkg->w_fp,
|
||||||
|
&pkg->w_file_header,
|
||||||
|
sizeof pkg->w_file_header,
|
||||||
|
&written);
|
||||||
|
ropkg_stream_restore_cursor_position(pkg->w_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ropkg_status ropkg_writer_write(
|
||||||
|
struct ropkg_writer *pkg,
|
||||||
|
const void *p,
|
||||||
|
size_t len,
|
||||||
|
size_t *nr_written)
|
||||||
|
{
|
||||||
|
enum ropkg_status status
|
||||||
|
= ropkg_stream_write(pkg->w_fp, p, len, nr_written);
|
||||||
|
if (status != ROPKG_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg->w_file_nr_written += len;
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
203
libropkg/zstd.c
Normal file
203
libropkg/zstd.c
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
#include "compress.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
|
struct zstd_stream {
|
||||||
|
struct ropkg_compression_stream s_base;
|
||||||
|
union {
|
||||||
|
ZSTD_CCtx *c;
|
||||||
|
ZSTD_DCtx *d;
|
||||||
|
} s_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum ropkg_status zstd_buffer_size(
|
||||||
|
enum ropkg_compression_stream_mode mode,
|
||||||
|
size_t *in_buffer_size,
|
||||||
|
size_t *out_buffer_size)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case ROPKG_COMPRESSION_MODE_COMPRESS:
|
||||||
|
if (in_buffer_size) {
|
||||||
|
*in_buffer_size = ZSTD_CStreamInSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_buffer_size) {
|
||||||
|
*out_buffer_size = ZSTD_CStreamOutSize();
|
||||||
|
}
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
case ROPKG_COMPRESSION_MODE_DECOMPRESS:
|
||||||
|
if (in_buffer_size) {
|
||||||
|
*in_buffer_size = ZSTD_DStreamInSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_buffer_size) {
|
||||||
|
*out_buffer_size = ZSTD_DStreamOutSize();
|
||||||
|
}
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
default:
|
||||||
|
return ROPKG_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status zstd_open(
|
||||||
|
const struct ropkg_compression_function *func,
|
||||||
|
enum ropkg_compression_stream_mode mode,
|
||||||
|
void *in_buffer,
|
||||||
|
size_t in_max,
|
||||||
|
void *out_buffer,
|
||||||
|
size_t out_max,
|
||||||
|
struct ropkg_compression_stream **out)
|
||||||
|
{
|
||||||
|
struct zstd_stream *stream = malloc(sizeof *stream);
|
||||||
|
if (!stream) {
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(stream, 0x0, sizeof *stream);
|
||||||
|
|
||||||
|
stream->s_base.s_in = in_buffer;
|
||||||
|
stream->s_base.s_in_max = in_max;
|
||||||
|
stream->s_base.s_out = out_buffer;
|
||||||
|
stream->s_base.s_out_max = out_max;
|
||||||
|
stream->s_base.s_func = func;
|
||||||
|
stream->s_base.s_mode = mode;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case ROPKG_COMPRESSION_MODE_COMPRESS:
|
||||||
|
stream->s_ctx.c = ZSTD_createCCtx();
|
||||||
|
|
||||||
|
if (!stream->s_ctx.c) {
|
||||||
|
free(stream);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_CCtx_setParameter(
|
||||||
|
stream->s_ctx.c,
|
||||||
|
ZSTD_c_compressionLevel,
|
||||||
|
10);
|
||||||
|
ZSTD_CCtx_setParameter(stream->s_ctx.c, ZSTD_c_checksumFlag, 1);
|
||||||
|
break;
|
||||||
|
case ROPKG_COMPRESSION_MODE_DECOMPRESS:
|
||||||
|
stream->s_ctx.d = ZSTD_createDCtx();
|
||||||
|
|
||||||
|
if (!stream->s_ctx.d) {
|
||||||
|
free(stream);
|
||||||
|
return ROPKG_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
free(stream);
|
||||||
|
return ROPKG_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = &stream->s_base;
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status zstd_close(struct ropkg_compression_stream *stream)
|
||||||
|
{
|
||||||
|
struct zstd_stream *zstream = (struct zstd_stream *)stream;
|
||||||
|
switch (stream->s_mode) {
|
||||||
|
case ROPKG_COMPRESSION_MODE_COMPRESS:
|
||||||
|
ZSTD_freeCCtx(zstream->s_ctx.c);
|
||||||
|
break;
|
||||||
|
case ROPKG_COMPRESSION_MODE_DECOMPRESS:
|
||||||
|
ZSTD_freeDCtx(zstream->s_ctx.d);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stream);
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status zstd_compress(
|
||||||
|
struct zstd_stream *zstream,
|
||||||
|
enum ropkg_compression_stream_op op,
|
||||||
|
ZSTD_inBuffer *in,
|
||||||
|
ZSTD_outBuffer *out)
|
||||||
|
{
|
||||||
|
ZSTD_EndDirective zop;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case ROPKG_COMPRESSION_OP_CONTINUE:
|
||||||
|
zop = ZSTD_e_continue;
|
||||||
|
break;
|
||||||
|
case ROPKG_COMPRESSION_OP_END:
|
||||||
|
zop = ZSTD_e_end;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ROPKG_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
size_t ret
|
||||||
|
= ZSTD_compressStream2(zstream->s_ctx.c, out, in, zop);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (in->pos < in->size);
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status zstd_decompress(
|
||||||
|
struct zstd_stream *zstream,
|
||||||
|
ZSTD_inBuffer *in,
|
||||||
|
ZSTD_outBuffer *out)
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
|
while (in->pos < in->size) {
|
||||||
|
ret = ZSTD_decompressStream(zstream->s_ctx.d, out, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
return ROPKG_ERR_INTERNAL_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum ropkg_status zstd_process(
|
||||||
|
struct ropkg_compression_stream *stream,
|
||||||
|
size_t in_size,
|
||||||
|
enum ropkg_compression_stream_op op,
|
||||||
|
size_t *out_size)
|
||||||
|
{
|
||||||
|
struct zstd_stream *zstream = (struct zstd_stream *)stream;
|
||||||
|
ZSTD_inBuffer in = {.src = stream->s_in, .size = in_size};
|
||||||
|
ZSTD_outBuffer out = {.dst = stream->s_out, .size = stream->s_out_max};
|
||||||
|
|
||||||
|
enum ropkg_status status;
|
||||||
|
switch (stream->s_mode) {
|
||||||
|
case ROPKG_COMPRESSION_MODE_COMPRESS:
|
||||||
|
status = zstd_compress(zstream, op, &in, &out);
|
||||||
|
break;
|
||||||
|
case ROPKG_COMPRESSION_MODE_DECOMPRESS:
|
||||||
|
status = zstd_decompress(zstream, &in, &out);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ROPKG_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_size) {
|
||||||
|
*out_size = out.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROPKG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ropkg_compression_function ropkg_zstd = {
|
||||||
|
.f_name = "zstd",
|
||||||
|
.f_extension = ".zst",
|
||||||
|
.f_buffer_size = zstd_buffer_size,
|
||||||
|
.f_open = zstd_open,
|
||||||
|
.f_close = zstd_close,
|
||||||
|
.f_process = zstd_process,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user