include/wimlib/ntfs_3g.h
endif
+if WITH_ZSTD
+libwim_la_SOURCES += src/zstd_compress.c \
+ src/zstd_decompress.c
+endif
+
if WINDOWS_NATIVE_BUILD
libwim_la_SOURCES += src/wimboot.c \
src/win32_common.c \
$(LIBXML2_CFLAGS) \
$(LIBNTFS_3G_CFLAGS) \
$(LIBFUSE_CFLAGS) \
+ $(LIBZSTD_CFLAGS) \
$(LIBCRYPTO_CFLAGS)
libwim_la_LDFLAGS = $(AM_LDFLAGS) -version-info 29:0:14
$(LIBNTFS_3G_LIBS) \
$(LIBFUSE_LIBS) \
$(LIBRT_LIBS) \
+ $(LIBZSTD_LIBS) \
$(LIBCRYPTO_LIBS) \
$(PLATFORM_LIBS)
fi
AM_CONDITIONAL([ENABLE_SSSE3_SHA1], [test "$ENABLE_SSSE3_SHA1" = "yes"])
+# --------------------------- Zstandard support -------------------------------
+
+AC_MSG_CHECKING([whether to include support for Zstandard compression])
+AC_ARG_WITH([zstd],
+ [AS_HELP_STRING([--with-zstd],
+ [Zstandard compression support via libzstd
+ (EXPERIMENTAL)])],
+ [WITH_ZSTD=$withval],
+ [WITH_ZSTD=no])
+AC_MSG_RESULT([$WITH_ZSTD])
+
+if test "$WITH_ZSTD" = "yes" ; then
+ PKG_CHECK_MODULES([LIBZSTD], [libzstd], [],
+ [AC_MSG_ERROR([Cannot find libzstd! Either install libzstd, or
+ configure --without-zstd to disable Zstandard compression
+ support.])])
+ PKGCONFIG_PRIVATE_REQUIRES="$PKGCONFIG_PRIVATE_REQUIRES zstd"
+ AC_DEFINE([WITH_ZSTD], [1], [Define to 1 if using Zstandard support])
+fi
+AM_CONDITIONAL([WITH_ZSTD], [test "$WITH_ZSTD" = "yes"])
+
# ----------------------------- Other options ---------------------------------
AC_MSG_CHECKING([whether to include error messages])
* up to and including <c>2^30</c>.
*/
WIMLIB_COMPRESSION_TYPE_LZMS = 3,
+
+ /**
+ * The Zstandard compression format. This is a wimlib extension;
+ * Microsoft's WIMGAPI does not support this format. Zstandard supports
+ * chunk sizes from 4096 to 268435456 bytes, with the default being
+ * 131072. Multiple compression levels are supported as well. For
+ * consistency with wimlib's other compression types, the compression
+ * levels exposed by libzstd are multiplied by 5; e.g., wimlib's level
+ * 50 (the default level) corresponds to libzstd's level 10. libzstd
+ * allows levels 1 through 22.
+ */
+ WIMLIB_COMPRESSION_TYPE_ZSTD = 4,
};
/** @} */
extern const struct compressor_ops lzx_compressor_ops;
extern const struct compressor_ops xpress_compressor_ops;
extern const struct compressor_ops lzms_compressor_ops;
+extern const struct compressor_ops zstd_compressor_ops;
#endif /* _WIMLIB_COMPRESSOR_OPS_H */
extern const struct decompressor_ops lzx_decompressor_ops;
extern const struct decompressor_ops xpress_decompressor_ops;
extern const struct decompressor_ops lzms_decompressor_ops;
+extern const struct decompressor_ops zstd_decompressor_ops;
#endif /* _WIMLIB_DECOMPRESSOR_OPS_H */
/* XPRESS, with small chunk size??? */
#define WIM_HDR_FLAG_COMPRESS_XPRESS_2 0x00200000
+#define WIM_HDR_FLAG_COMPRESS_ZSTD 0x00400000
+
#endif /* _WIMLIB_HEADER_H */
" xpress (alias: \"fast\")\n"
" lzx (alias: \"maximum\") (default for capture)\n"
" lzms (alias: \"recovery\")\n"
+#ifdef WITH_ZSTD
+ " zstd (alias: \"zstandard\")\n"
+#endif
"\n"
);
tfputs(s, fp);
ctype = WIMLIB_COMPRESSION_TYPE_LZMS;
} else if (!tstrcasecmp(optarg, T("lzms"))) {
ctype = WIMLIB_COMPRESSION_TYPE_LZMS;
+#ifdef WITH_ZSTD
+ } else if (!tstrcasecmp(optarg, T("zstd")) ||
+ !tstrcasecmp(optarg, T("zstandard"))) {
+ ctype = WIMLIB_COMPRESSION_TYPE_ZSTD;
+#endif
} else if (!tstrcasecmp(optarg, T("none"))) {
ctype = WIMLIB_COMPRESSION_TYPE_NONE;
} else {
[WIMLIB_COMPRESSION_TYPE_XPRESS] = &xpress_compressor_ops,
[WIMLIB_COMPRESSION_TYPE_LZX] = &lzx_compressor_ops,
[WIMLIB_COMPRESSION_TYPE_LZMS] = &lzms_compressor_ops,
+#ifdef WITH_ZSTD
+ [WIMLIB_COMPRESSION_TYPE_ZSTD] = &zstd_compressor_ops,
+#endif
};
/* Scale: 10 = low, 50 = medium, 100 = high */
[WIMLIB_COMPRESSION_TYPE_XPRESS] = &xpress_decompressor_ops,
[WIMLIB_COMPRESSION_TYPE_LZX] = &lzx_decompressor_ops,
[WIMLIB_COMPRESSION_TYPE_LZMS] = &lzms_decompressor_ops,
+#ifdef WITH_ZSTD
+ [WIMLIB_COMPRESSION_TYPE_ZSTD] = &zstd_decompressor_ops,
+#endif
};
static bool
{WIM_HDR_FLAG_COMPRESS_XPRESS, "COMPRESS_XPRESS"},
{WIM_HDR_FLAG_COMPRESS_LZMS, "COMPRESS_LZMS"},
{WIM_HDR_FLAG_COMPRESS_XPRESS_2,"COMPRESS_XPRESS_2"},
+ {WIM_HDR_FLAG_COMPRESS_ZSTD, "COMPRESS_ZSTD"},
};
/* API function documented in wimlib.h */
.default_nonsolid_chunk_size = 131072,
.default_solid_chunk_size = 67108864,
},
+#ifdef WITH_ZSTD
+ [WIMLIB_COMPRESSION_TYPE_ZSTD] = {
+ .name = T("Zstandard"),
+ .min_chunk_size = 4096,
+ .max_chunk_size = 268435456,
+ .default_nonsolid_chunk_size = 131072,
+ .default_solid_chunk_size = 131072,
+ },
+#endif
};
/* Is the specified compression type valid? */
wim->compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
} else if (wim->hdr.flags & WIM_HDR_FLAG_COMPRESS_LZMS) {
wim->compression_type = WIMLIB_COMPRESSION_TYPE_LZMS;
+#ifdef WITH_ZSTD
+ } else if (wim->hdr.flags & WIM_HDR_FLAG_COMPRESS_ZSTD) {
+ wim->compression_type = WIMLIB_COMPRESSION_TYPE_ZSTD;
+#endif
} else {
return WIMLIB_ERR_INVALID_COMPRESSION_TYPE;
}
case WIMLIB_COMPRESSION_TYPE_LZMS:
wim->out_hdr.flags |= WIM_HDR_FLAG_COMPRESS_LZMS;
break;
+ case WIMLIB_COMPRESSION_TYPE_ZSTD:
+ WARNING("Zstandard support is experimental -- use only for benchmarking!");
+ wim->out_hdr.flags |= WIM_HDR_FLAG_COMPRESS_ZSTD;
+ break;
}
}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "wimlib/error.h"
+#include "wimlib/compressor_ops.h"
+#include "wimlib/util.h"
+
+#include <zstd.h>
+
+struct zstd_compressor {
+ unsigned compression_level;
+ ZSTD_CCtx *cctx;
+};
+
+static u64
+zstd_get_needed_memory(size_t max_bufsize, unsigned compression_level,
+ bool destructive)
+{
+ return sizeof(struct zstd_compressor);
+}
+
+static int
+zstd_create_compressor(size_t max_bufsize, unsigned compression_level,
+ bool destructive, void **c_ret)
+{
+ struct zstd_compressor *c;
+
+ c = MALLOC(sizeof(*c));
+ if (!c)
+ goto oom;
+
+ c->cctx = ZSTD_createCCtx();
+ if (!c->cctx)
+ goto oom;
+
+ c->compression_level = compression_level / 5;
+ c->compression_level = max(c->compression_level, 1);
+ c->compression_level = min(c->compression_level, ZSTD_maxCLevel());
+
+ *c_ret = c;
+ return 0;
+
+oom:
+ FREE(c);
+ return WIMLIB_ERR_NOMEM;
+}
+
+static size_t
+zstd_compress(const void *in, size_t in_nbytes,
+ void *out, size_t out_nbytes_avail, void *_c)
+{
+ struct zstd_compressor *c = _c;
+ size_t res;
+
+ res = ZSTD_compressCCtx(c->cctx, out, out_nbytes_avail, in, in_nbytes,
+ c->compression_level);
+
+ if (ZSTD_isError(res))
+ return 0;
+ return res;
+}
+
+static void
+zstd_free_compressor(void *_c)
+{
+ struct zstd_compressor *c = _c;
+
+ FREE(c->cctx);
+ FREE(c);
+}
+
+const struct compressor_ops zstd_compressor_ops = {
+ .get_needed_memory = zstd_get_needed_memory,
+ .create_compressor = zstd_create_compressor,
+ .compress = zstd_compress,
+ .free_compressor = zstd_free_compressor,
+};
+
--- /dev/null
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "wimlib/error.h"
+#include "wimlib/decompressor_ops.h"
+#include "wimlib/util.h"
+
+#include <zstd.h>
+
+static int
+zstd_create_decompressor(size_t max_block_size, void **d_ret)
+{
+ *d_ret = ZSTD_createDCtx();
+ if (!*d_ret)
+ return WIMLIB_ERR_NOMEM;
+ return 0;
+}
+
+static int
+zstd_decompress(const void *in, size_t in_nbytes,
+ void *out, size_t out_nbytes, void *_d)
+{
+ size_t res = ZSTD_decompressDCtx(_d, out, out_nbytes, in, in_nbytes);
+ if (res != out_nbytes)
+ return -1;
+ return 0;
+}
+
+static void
+zstd_free_decompressor(void *_d)
+{
+ ZSTD_freeDCtx(_d);
+}
+
+const struct decompressor_ops zstd_decompressor_ops = {
+ .create_decompressor = zstd_create_decompressor,
+ .decompress = zstd_decompress,
+ .free_decompressor = zstd_free_decompressor,
+};