summaryrefslogtreecommitdiff
path: root/util/cbfstool/lzma/lzma.c
diff options
context:
space:
mode:
authorStefan Reinauer <reinauer@chromium.org>2013-03-28 16:51:45 -0700
committerRonald G. Minnich <rminnich@gmail.com>2013-04-03 02:35:28 +0200
commitaa3f7ba36ebe3a933aa664f826382f60b31e86f1 (patch)
treed5db7081e310d418322f1ecc519439c488a9f4fd /util/cbfstool/lzma/lzma.c
parent60a4a73fcd7babd4819853542a5566293a097ed4 (diff)
downloadcoreboot-aa3f7ba36ebe3a933aa664f826382f60b31e86f1.tar.xz
cbfstool: Replace C++ code with C code
cbfstool was using a C++ wrapper around the C written LZMA functions. And a C wrapper around those C++ functions. Drop the mess and rewrite the functions to be all C. Change-Id: Ieb6645a42f19efcc857be323ed8bdfcd9f48ee7c Signed-off-by: Stefan Reinauer <reinauer@google.com> Reviewed-on: http://review.coreboot.org/3010 Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'util/cbfstool/lzma/lzma.c')
-rw-r--r--util/cbfstool/lzma/lzma.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/util/cbfstool/lzma/lzma.c b/util/cbfstool/lzma/lzma.c
new file mode 100644
index 0000000000..914d8b7da9
--- /dev/null
+++ b/util/cbfstool/lzma/lzma.c
@@ -0,0 +1,198 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../common.h"
+#include "C/LzmaDec.h"
+#include "C/LzmaEnc.h"
+
+/* Endianness / unaligned memory access handling */
+
+#if defined(__x86_64__) || defined(__i386__)
+#define LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK
+#else
+#undef LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK
+#endif
+
+#define L (uint64_t)
+
+static inline uint64_t get_64(const void *p)
+{
+#ifdef LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK
+ return *(const uint64_t *)p;
+#else
+ const unsigned char *data = (const unsigned char *)p;
+ return (L data[0]) | (L data[1] << 8) | (L data[2] << 16) |
+ (L data[3] << 24) | (L data [4] << 32) | (L data[5] << 40) |
+ (L data[6] << 48) | (L data[7] << 56);
+#endif
+}
+
+static void put_64(void *p, uint64_t value)
+{
+#ifdef LITTLE_ENDIAN_AND_UNALIGNED_ACCESS_OK
+ *(uint64_t *) p = value;
+#else
+ unsigned char *data = (unsigned char *)p;
+ data[0] = value & 0xff;
+ data[1] = (value >> 8) & 0xff;
+ data[2] = (value >> 16) & 0xff;
+ data[3] = (value >> 24) & 0xff;
+ data[4] = (value >> 32) & 0xff;
+ data[5] = (value >> 40) & 0xff;
+ data[6] = (value >> 48) & 0xff;
+ data[7] = (value >> 56) & 0xff;
+#endif
+}
+
+/* Memory Allocation API */
+
+static void *SzAlloc(void *unused, size_t size)
+{
+ return malloc(size);
+}
+
+static void SzFree(void *unused, void *address)
+{
+ free(address);
+}
+
+static ISzAlloc LZMAalloc = { SzAlloc, SzFree };
+
+/* Streaming API */
+
+typedef struct vector {
+ char *p;
+ size_t pos;
+ size_t size;
+} vector_t;
+
+static vector_t instream, outstream;
+
+static SRes Read(void *unused, void *buf, size_t *size)
+{
+ if ((instream.size - instream.pos) < *size)
+ *size = instream.size - instream.pos;
+ memcpy(buf, instream.p + instream.pos, *size);
+ instream.pos += *size;
+ return SZ_OK;
+}
+
+static size_t Write(void *unused, const void *buf, size_t size)
+{
+ if(outstream.size - outstream.pos < size)
+ size = outstream.size - outstream.pos;
+ memcpy(outstream.p + outstream.pos, buf, size);
+ outstream.pos += size;
+ return size;
+}
+
+static ISeqInStream is = { Read };
+static ISeqOutStream os = { Write };
+
+/**
+ * Compress a buffer with lzma
+ * Don't copy the result back if it is too large.
+ * @param in a pointer to the buffer
+ * @param in_len the length in bytes
+ * @param out a pointer to a buffer of at least size in_len
+ * @param out_len a pointer to the compressed length of in
+ */
+
+void do_lzma_compress(char *in, int in_len, char *out, int *out_len)
+{
+ if (in_len == 0) {
+ ERROR("LZMA: Input length is zero.\n");
+ return;
+ }
+
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.dictSize = in_len;
+ props.pb = 0; /* PosStateBits, default: 2, range: 0..4 */
+ props.lp = 0; /* LiteralPosStateBits, default: 0, range: 0..4 */
+ props.lc = 1; /* LiteralContextBits, default: 3, range: 0..8 */
+ props.fb = 273; /* NumFastBytes */
+ props.mc = 0; /* MatchFinderCycles, default: 0 */
+ props.algo = 1; /* AlgorithmNo, apparently, 0 and 1 are valid values. 0 = fast mode */
+ props.numThreads = 1;
+
+ switch (props.algo) {
+ case 0: // quick: HC4
+ props.btMode = 0;
+ props.level = 1;
+ break;
+ case 1: // full: BT4
+ default:
+ props.level = 9;
+ props.btMode = 1;
+ props.numHashBytes = 4;
+ break;
+ }
+
+ CLzmaEncHandle p = LzmaEnc_Create(&LZMAalloc);
+
+ int res = LzmaEnc_SetProps(p, &props);
+ if (res != SZ_OK) {
+ ERROR("LZMA: LzmaEnc_SetProps failed.\n");
+ return;
+ }
+
+ unsigned char propsEncoded[LZMA_PROPS_SIZE + 8];
+ size_t propsSize = sizeof propsEncoded;
+ res = LzmaEnc_WriteProperties(p, propsEncoded, &propsSize);
+ if (res != SZ_OK) {
+ ERROR("LZMA: LzmaEnc_WriteProperties failed.\n");
+ return;
+ }
+
+ instream.p = in;
+ instream.size = in_len;
+
+ outstream.p = out;
+ outstream.size = in_len;
+
+ put_64(propsEncoded + LZMA_PROPS_SIZE, in_len);
+ Write(&os, propsEncoded, LZMA_PROPS_SIZE+8);
+
+ res = LzmaEnc_Encode(p, &os, &is, 0, &LZMAalloc, &LZMAalloc);
+ if (res != SZ_OK) {
+ ERROR("LZMA: LzmaEnc_Encode failed %d.\n", res);
+ return;
+ }
+
+ *out_len = outstream.pos;
+}
+
+void do_lzma_uncompress(char *dst, int dst_len, char *src, int src_len)
+{
+ if (src_len <= LZMA_PROPS_SIZE + 8) {
+ ERROR("LZMA: Input length is too small.\n");
+ return;
+ }
+
+ uint64_t out_sizemax = get_64(&src[LZMA_PROPS_SIZE]);
+
+ if (out_sizemax > (size_t) dst_len) {
+ ERROR("Not copying %d bytes to %d-byte buffer!\n",
+ (unsigned int)out_sizemax, dst_len);
+ return;
+ }
+
+ ELzmaStatus status;
+
+ size_t destlen = out_sizemax;
+ size_t srclen = src_len - (LZMA_PROPS_SIZE + 8);
+
+ int res = LzmaDecode((Byte *) dst, &destlen,
+ (Byte *) &src[LZMA_PROPS_SIZE + 8], &srclen,
+ (Byte *) &src[0], LZMA_PROPS_SIZE,
+ LZMA_FINISH_END,
+ &status,
+ &LZMAalloc);
+
+ if (res != SZ_OK) {
+ ERROR("Error while decompressing.\n");
+ return;
+ }
+}