summaryrefslogtreecommitdiffstats
path: root/depends/lzma/wrapper/compress.c
diff options
context:
space:
mode:
Diffstat (limited to 'depends/lzma/wrapper/compress.c')
-rw-r--r--depends/lzma/wrapper/compress.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/depends/lzma/wrapper/compress.c b/depends/lzma/wrapper/compress.c
new file mode 100644
index 00000000..38ca0a68
--- /dev/null
+++ b/depends/lzma/wrapper/compress.c
@@ -0,0 +1,297 @@
+/*
+ * Written in 2009 by Lloyd Hilaiel
+ *
+ * License
+ *
+ * All the cruft you find here is public domain. You don't have to credit
+ * anyone to use this code, but my personal request is that you mention
+ * Igor Pavlov for his hard, high quality work.
+ */
+
+#include "compress.h"
+#include "lzma_header.h"
+#include "lzip_header.h"
+#include "common_internal.h"
+
+#include "pavlov/Types.h"
+#include "pavlov/LzmaEnc.h"
+#include "pavlov/7zCrc.h"
+
+#include <string.h>
+
+struct _elzma_compress_handle
+{
+ CLzmaEncProps props;
+ CLzmaEncHandle encHand;
+ unsigned long long uncompressedSize;
+ elzma_file_format format;
+ struct elzma_alloc_struct allocStruct;
+ struct elzma_format_handler formatHandler;
+};
+
+elzma_compress_handle elzma_compress_alloc()
+{
+ elzma_compress_handle hand = malloc(sizeof(struct _elzma_compress_handle));
+ memset((void *)hand, 0, sizeof(struct _elzma_compress_handle));
+
+ /* "reasonable" defaults for props */
+ LzmaEncProps_Init(&(hand->props));
+ hand->props.lc = 3;
+ hand->props.lp = 0;
+ hand->props.pb = 2;
+ hand->props.level = 5;
+ hand->props.algo = 1;
+ hand->props.fb = 32;
+ hand->props.dictSize = 1 << 24;
+ hand->props.btMode = 1;
+ hand->props.numHashBytes = 4;
+ hand->props.mc = 32;
+ hand->props.numThreads = 1;
+ hand->props.writeEndMark = 1;
+
+ init_alloc_struct(&(hand->allocStruct), NULL, NULL, NULL, NULL);
+
+ /* default format is LZMA-Alone */
+ initializeLZMAFormatHandler(&(hand->formatHandler));
+
+ return hand;
+}
+
+void elzma_compress_free(elzma_compress_handle *hand)
+{
+ if (hand && *hand)
+ {
+ if ((*hand)->encHand)
+ {
+ LzmaEnc_Destroy((*hand)->encHand);
+ }
+ }
+ *hand = NULL;
+}
+
+int elzma_compress_config(elzma_compress_handle hand, unsigned char lc, unsigned char lp,
+ unsigned char pb, unsigned char level, unsigned int dictionarySize,
+ elzma_file_format format, unsigned long long uncompressedSize)
+{
+ /* XXX: validate arguments are in valid ranges */
+
+ hand->props.lc = lc;
+ hand->props.lp = lp;
+ hand->props.pb = pb;
+ hand->props.level = level;
+ hand->props.dictSize = dictionarySize;
+ hand->uncompressedSize = uncompressedSize;
+ hand->format = format;
+
+ /* default of LZMA-Alone is set at alloc time, and there are only
+ * two possible formats */
+ if (format == ELZMA_lzip)
+ {
+ initializeLZIPFormatHandler(&(hand->formatHandler));
+ }
+
+ return ELZMA_E_OK;
+}
+
+/* use Igor's stream hooks for compression. */
+struct elzmaInStream
+{
+ SRes (*ReadPtr)(void *p, void *buf, size_t *size);
+ elzma_read_callback inputStream;
+ void *inputContext;
+ unsigned int crc32;
+ unsigned int crc32a;
+ unsigned int crc32b;
+ unsigned int crc32c;
+ int calculateCRC;
+};
+
+static SRes elzmaReadFunc(void *p, void *buf, size_t *size)
+{
+ int rv;
+ struct elzmaInStream *is = (struct elzmaInStream *)p;
+ rv = is->inputStream(is->inputContext, buf, size);
+ if (rv == 0 && *size > 0 && is->calculateCRC)
+ {
+ is->crc32 = CrcUpdate(is->crc32, buf, *size);
+ }
+ return rv;
+}
+
+struct elzmaOutStream
+{
+ size_t (*WritePtr)(void *p, const void *buf, size_t size);
+ elzma_write_callback outputStream;
+ void *outputContext;
+};
+
+static size_t elzmaWriteFunc(void *p, const void *buf, size_t size)
+{
+ struct elzmaOutStream *os = (struct elzmaOutStream *)p;
+ return os->outputStream(os->outputContext, buf, size);
+}
+
+/* use Igor's stream hooks for compression. */
+struct elzmaProgressStruct
+{
+ SRes (*Progress)(void *p, uint64_t inSize, uint64_t outSize);
+ long long unsigned int uncompressedSize;
+ elzma_progress_callback progressCallback;
+ void *progressContext;
+};
+
+#include <stdio.h>
+static SRes elzmaProgress(void *p, uint64_t inSize, uint64_t outSize)
+{
+ struct elzmaProgressStruct *ps = (struct elzmaProgressStruct *)p;
+ if (ps->progressCallback)
+ {
+ ps->progressCallback(ps->progressContext, inSize, ps->uncompressedSize);
+ }
+ return SZ_OK;
+}
+
+void elzma_compress_set_allocation_callbacks(elzma_compress_handle hand,
+ elzma_malloc mallocFunc, void *mallocFuncContext,
+ elzma_free freeFunc, void *freeFuncContext)
+{
+ if (hand)
+ {
+ init_alloc_struct(&(hand->allocStruct), mallocFunc, mallocFuncContext, freeFunc,
+ freeFuncContext);
+ }
+}
+
+int elzma_compress_run(elzma_compress_handle hand, elzma_read_callback inputStream,
+ void *inputContext, elzma_write_callback outputStream,
+ void *outputContext, elzma_progress_callback progressCallback,
+ void *progressContext)
+{
+ struct elzmaInStream inStreamStruct;
+ struct elzmaOutStream outStreamStruct;
+ struct elzmaProgressStruct progressStruct;
+ SRes r;
+
+ CrcGenerateTable();
+
+ if (hand == NULL || inputStream == NULL)
+ return ELZMA_E_BAD_PARAMS;
+
+ /* initialize stream structrures */
+ inStreamStruct.ReadPtr = elzmaReadFunc;
+ inStreamStruct.inputStream = inputStream;
+ inStreamStruct.inputContext = inputContext;
+ inStreamStruct.crc32 = CRC_INIT_VAL;
+ inStreamStruct.calculateCRC = (hand->formatHandler.serialize_footer != NULL);
+
+ outStreamStruct.WritePtr = elzmaWriteFunc;
+ outStreamStruct.outputStream = outputStream;
+ outStreamStruct.outputContext = outputContext;
+
+ progressStruct.Progress = elzmaProgress;
+ progressStruct.uncompressedSize = hand->uncompressedSize;
+ progressStruct.progressCallback = progressCallback;
+ progressStruct.progressContext = progressContext;
+
+ /* create an encoding object */
+ hand->encHand = LzmaEnc_Create();
+
+ if (hand->encHand == NULL)
+ {
+ return ELZMA_E_COMPRESS_ERROR;
+ }
+
+ /* inintialize with compression parameters */
+ if (SZ_OK != LzmaEnc_SetProps(hand->encHand, &(hand->props)))
+ {
+ return ELZMA_E_BAD_PARAMS;
+ }
+
+ /* verify format is sane */
+ if (ELZMA_lzma != hand->format && ELZMA_lzip != hand->format)
+ {
+ return ELZMA_E_UNSUPPORTED_FORMAT;
+ }
+
+ /* now write the compression header header */
+ {
+ unsigned char *hdr =
+ hand->allocStruct.Alloc(&(hand->allocStruct), hand->formatHandler.header_size);
+
+ struct elzma_file_header h;
+ size_t wt;
+
+ hand->formatHandler.init_header(&h);
+ h.pb = (unsigned char)hand->props.pb;
+ h.lp = (unsigned char)hand->props.lp;
+ h.lc = (unsigned char)hand->props.lc;
+ h.dictSize = hand->props.dictSize;
+ h.isStreamed = (unsigned char)(hand->uncompressedSize == 0);
+ h.uncompressedSize = hand->uncompressedSize;
+
+ hand->formatHandler.serialize_header(hdr, &h);
+
+ wt = outputStream(outputContext, (void *)hdr, hand->formatHandler.header_size);
+
+ hand->allocStruct.Free(&(hand->allocStruct), hdr);
+
+ if (wt != hand->formatHandler.header_size)
+ {
+ return ELZMA_E_OUTPUT_ERROR;
+ }
+ }
+
+ /* begin LZMA encoding */
+ /* XXX: expose encoding progress */
+ r = LzmaEnc_Encode(hand->encHand, (ISeqOutStream *)&outStreamStruct,
+ (ISeqInStream *)&inStreamStruct, (ICompressProgress *)&progressStruct);
+
+ if (r != SZ_OK)
+ return ELZMA_E_COMPRESS_ERROR;
+
+ /* support a footer! (lzip) */
+ if (hand->formatHandler.serialize_footer != NULL && hand->formatHandler.footer_size > 0)
+ {
+ size_t wt;
+ unsigned char *ftrBuf =
+ hand->allocStruct.Alloc(&(hand->allocStruct), hand->formatHandler.footer_size);
+ struct elzma_file_footer ftr;
+ ftr.crc32 = inStreamStruct.crc32 ^ 0xFFFFFFFF;
+ ftr.uncompressedSize = hand->uncompressedSize;
+
+ hand->formatHandler.serialize_footer(&ftr, ftrBuf);
+
+ wt = outputStream(outputContext, (void *)ftrBuf, hand->formatHandler.footer_size);
+
+ hand->allocStruct.Free(&(hand->allocStruct), ftrBuf);
+
+ if (wt != hand->formatHandler.footer_size)
+ {
+ return ELZMA_E_OUTPUT_ERROR;
+ }
+ }
+
+ return ELZMA_E_OK;
+}
+
+unsigned int elzma_get_dict_size(unsigned long long size)
+{
+ int i = 13; /* 16k dict is minimum */
+
+ /* now we'll find the closes power of two with a max at 16< *
+ * if the size is greater than 8m, we'll divide by two, all of this
+ * is based on a quick set of emperical tests on hopefully
+ * representative sample data */
+ if (size > (1 << 23))
+ size >>= 1;
+
+ while (size >> i)
+ i++;
+
+ if (i > 23)
+ return 1 << 23;
+
+ /* now 1 << i is greater than size, let's return either 1<<i or 1<<(i-1),
+ * whichever is closer to size */
+ return 1 << ((((1 << i) - size) > (size - (1 << (i - 1)))) ? i - 1 : i);
+}