diff --git a/include/lar.h b/include/lar.h index 18e2a936a9..082fb4834f 100644 --- a/include/lar.h +++ b/include/lar.h @@ -58,8 +58,11 @@ struct lar_header { char magic[8]; u32 len; + u32 reallen; u32 checksum; + u32 compchecksum; u32 offset; + u32 compression; }; struct mem_file { diff --git a/util/lar/create.c b/util/lar/create.c index 51a714f480..558b61dc18 100644 --- a/util/lar/create.c +++ b/util/lar/create.c @@ -3,6 +3,7 @@ * * Copyright (C) 2006-2007 coresystems GmbH * (Written by Stefan Reinauer for coresystems GmbH) + * Copyright (C) 2007 Patrick Georgi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,10 +31,22 @@ #include #include - #include "lib.h" #include "lar.h" +extern enum compalgo algo; + +void compress_impossible(char *in, u32 in_len, char *out, u32 *out_len) { + fprintf(stderr, + "The selected compression algorithm wasn't compiled in.\n"); + exit(1); +} + +void do_no_compress(char *in, u32 in_len, char *out, u32 *out_len) { + memcpy(out, in, in_len); + out_len[0] = in_len; +} + int create_lar(const char *archivename, struct file *files) { int i, ret; @@ -41,14 +54,16 @@ int create_lar(const char *archivename, struct file *files) int bb_header_len = 0; FILE *archive, *source; char *tempmem; - char *filebuf; + char *filebuf, *filetarget; char *pathname; u32 *walk; u32 csum; int pathlen, entrylen, filelen; + u32 compfilelen; long currentsize = 0; struct lar_header *header; struct stat statbuf; + enum compalgo thisalgo; if (!files) { fprintf(stderr, "No files for archive %s\n", archivename); @@ -68,6 +83,13 @@ int create_lar(const char *archivename, struct file *files) while (files) { char *name = files->name; + thisalgo = algo; + + if (strstr(name, "nocompress:") == name) { + name += 11; + thisalgo = none; + } + /* skip ./ if available */ if (name[0] == '.' && name[1] == '/') name += 2; @@ -97,24 +119,35 @@ int create_lar(const char *archivename, struct file *files) pathlen = (pathlen + 15) & 0xfffffff0;/* Align to 16 bytes. */ /* Read file into memory. */ - filebuf = pathname + pathlen; + filebuf = malloc(filelen); + filetarget = pathname + pathlen; source = fopen(name, "r"); if (!source) { fprintf(stderr, "No such file %s\n", name); exit(1); } - fread(filebuf, statbuf.st_size, 1, source); + fread(filebuf, filelen, 1, source); fclose(source); + compress_functions[thisalgo](filebuf, filelen, filetarget, + &compfilelen); + if ((compfilelen >= filelen) && (thisalgo != none)) { + thisalgo = none; + compress_functions[thisalgo](filebuf, filelen, + filetarget, &compfilelen); + } + free(filebuf); /* Create correct header. */ memcpy(header, MAGIC, 8); - header->len = htonl(statbuf.st_size); + header->compression = htonl(thisalgo); + header->reallen = htonl(filelen); + header->len = htonl(compfilelen); header->offset = htonl(sizeof(struct lar_header) + pathlen); /* Calculate checksum. */ csum = 0; for (walk = (u32 *) tempmem; - walk < (u32 *) (tempmem + statbuf.st_size + + walk < (u32 *) (tempmem + compfilelen + sizeof(struct lar_header) + pathlen); walk++) { csum += ntohl(*walk); @@ -122,7 +155,7 @@ int create_lar(const char *archivename, struct file *files) header->checksum = htonl(csum); /* Write out entry to archive. */ - entrylen = (filelen + pathlen + sizeof(struct lar_header) + + entrylen = (compfilelen + pathlen + sizeof(struct lar_header) + 15) & 0xfffffff0; fwrite(tempmem, entrylen, 1, archive); @@ -216,6 +249,7 @@ int create_lar(const char *archivename, struct file *files) /* construct header */ bb=(struct lar_header *)bootblock_header; memcpy(bb->magic, MAGIC, 8); + bb->reallen = htonl(bootblock_len); bb->len = htonl(bootblock_len); bb->offset = htonl(bb_header_len); diff --git a/util/lar/extract.c b/util/lar/extract.c index ffbab36519..8f1ae7a6e5 100644 --- a/util/lar/extract.c +++ b/util/lar/extract.c @@ -3,6 +3,7 @@ * * Copyright (C) 2006-2007 coresystems GmbH * (Written by Stefan Reinauer for coresystems GmbH) + * Copyright (C) 2007 Patrick Georgi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +33,16 @@ #include "lib.h" #include "lar.h" +void uncompress_impossible(char *dst, char *src, u32 len) { + fprintf(stderr, + "Cannot uncompress data (algorithm not compiled in).\n"); + exit(1); +} + +void do_no_uncompress(char *dst, char *src, u32 len) { + memcpy(dst, src, len); +} + int extract_lar(const char *archivename, struct file *files) { int archivefile; @@ -116,8 +127,17 @@ int extract_lar(const char *archivename, struct file *files) exit(1); } - fwrite(walk + ntohl(header->offset), ntohl(header->len), - 1, file_to_extract); + if (ntohl(header->compression) == none) { + fwrite(walk + ntohl(header->offset), + ntohl(header->len), 1, file_to_extract); + } else { + char *buf = malloc(ntohl(header->reallen)); + uncompress_functions[ntohl(header->compression)](buf, + walk + ntohl(header->offset), + ntohl(header->len)); + fwrite(buf, ntohl(header->reallen), 1, file_to_extract); + free(buf); + } fclose(file_to_extract); walk += (ntohl(header->offset) + ntohl(header->len) diff --git a/util/lar/lar.c b/util/lar/lar.c index e138009a74..2deb426b62 100644 --- a/util/lar/lar.c +++ b/util/lar/lar.c @@ -39,6 +39,7 @@ static int isverbose = 0; static long larsize = 0; static char *bootblock = NULL; +enum compalgo algo = none; static void usage(char *name) { @@ -72,6 +73,7 @@ int main(int argc, char *argv[]) static struct option long_options[] = { {"create", 0, 0, 'c'}, + {"compress-algo", 1, 0, 'C'}, {"extract", 0, 0, 'x'}, {"list", 0, 0, 'l'}, {"size", 1, 0, 's'}, @@ -87,12 +89,20 @@ int main(int argc, char *argv[]) exit(1); } - while ((opt = getopt_long(argc, argv, "cxls:b:vVh?", + while ((opt = getopt_long(argc, argv, "cC:xls:b:vVh?", long_options, &option_index)) != EOF) { switch (opt) { case 'c': larmode = CREATE; break; + case 'C': + if (strcmp("lzma", optarg) == 0) { + algo = lzma; + } + if (strcmp("nrv2b", optarg) == 0) { + algo = nrv2b; + } + break; case 'l': larmode = LIST; break; diff --git a/util/lar/lar.h b/util/lar/lar.h index 6aff7ca4ec..765a691c6f 100644 --- a/util/lar/lar.h +++ b/util/lar/lar.h @@ -3,6 +3,7 @@ * * Copyright (C) 2006 coresystems GmbH * (Written by Stefan Reinauer for coresystems GmbH) + * Copyright (C) 2007 Patrick Georgi * * This file is dual-licensed. You can choose between: * - The GNU GPL, version 2, as published by the Free Software Foundation @@ -48,6 +49,7 @@ */ #include +#include "../../build/config.h" #define MAGIC "LARCHIVE" #define MAX_PATHLEN 1024 @@ -58,6 +60,63 @@ typedef uint32_t u32; struct lar_header { char magic[8]; u32 len; + u32 reallen; u32 checksum; + u32 compchecksum; u32 offset; + /* Compression: + * 0 = no compression + * 1 = lzma + * 2 = nrv2b + */ + u32 compression; +}; + +enum compalgo { none = 0, lzma = 1, nrv2b = 2 }; + +typedef void (*compress_func) (char *, u32, char *, u32 *); +typedef void (*uncompress_func) (char *, char *, u32); + +void compress_impossible(char *in, u32 in_len, char *out, u32 *out_len); +void do_no_compress(char *in, u32 in_len, char *out, u32 *out_len); +#ifdef CONFIG_COMPRESSION_LZMA +void do_lzma_compress(char *in, u32 in_len, char *out, u32 *out_len); +#else +#define do_lzma_compress compress_impossible +#endif +#ifdef CONFIG_COMPRESSION_NRV2B +void do_nrv2b_compress(char *in, u32 in_len, char *out, u32 *out_len); +#else +#define do_nrv2b_compress compress_impossible +#endif + +void uncompress_impossible(char *, char *, u32); +void do_no_uncompress(char *, char *, u32); +#ifdef CONFIG_COMPRESSION_LZMA +void do_lzma_uncompress(char *, char *, u32); +#else +#define do_lzma_uncompress uncompress_impossible +#endif +#ifdef CONFIG_COMPRESSION_NRV2B +void do_nrv2b_uncompress(char *, char *, u32); +#else +#define do_nrv2b_uncompress uncompress_impossible +#endif + +static compress_func compress_functions[] = { + do_no_compress, + do_lzma_compress, + do_nrv2b_compress, +}; + +static uncompress_func uncompress_functions[] = { + do_no_uncompress, + do_lzma_uncompress, + do_nrv2b_uncompress, +}; + +static const char *algo_name[] = { + "", + "lzma", + "nrv2b", }; diff --git a/util/lar/lib.c b/util/lar/lib.c index 0ee52fd182..8475f747aa 100644 --- a/util/lar/lib.c +++ b/util/lar/lib.c @@ -121,9 +121,15 @@ int add_files(const char *name) { struct stat filestat; int ret = -1; + const char *realname; + + realname = name; + if (strstr(name, "nocompress:") == name) { + realname = name + 11; + } /* printf("... add_files %s\n", name); */ - if (stat(name, &filestat) == -1) { + if (stat(realname, &filestat) == -1) { fprintf(stderr, "Error getting file attributes of %s\n", name); return -1; } @@ -145,7 +151,7 @@ int add_files(const char *name) } // Is it a directory? if (S_ISDIR(filestat.st_mode)) { - ret = handle_directory(name); + ret = handle_directory(realname); } // Is it a regular file? if (S_ISREG(filestat.st_mode)) { diff --git a/util/lar/list.c b/util/lar/list.c index 154d1c5a23..8d9d5db24f 100644 --- a/util/lar/list.c +++ b/util/lar/list.c @@ -3,6 +3,7 @@ * * Copyright (C) 2006-2007 coresystems GmbH * (Written by Stefan Reinauer for coresystems GmbH) + * Copyright (C) 2007 Patrick Georgi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -91,8 +92,20 @@ int list_lar(const char *archivename, struct file *files) printf(" %s ", walk + sizeof(struct lar_header)); - printf("(%d bytes @0x%lx)\n", ntohl(header->len), - (unsigned long)(walk - inmap) + ntohl(header->offset)); + if (ntohl(header->compression) == none) { + printf("(%d bytes @0x%lx)\n", + ntohl(header->len), + (unsigned long)(walk - inmap) + + ntohl(header->offset)); + } else { + printf("(%d bytes, %s compressed to %d bytes " + "@0x%lx)\n", + ntohl(header->reallen), + algo_name[ntohl(header->compression)], + ntohl(header->len), + (unsigned long)(walk - inmap) + + ntohl(header->offset)); + } walk += (ntohl(header->len) + ntohl(header->offset) - 1) & 0xfffffff0; diff --git a/util/lzma/minilzma.cc b/util/lzma/minilzma.cc index 605b43116b..5782aac218 100644 --- a/util/lzma/minilzma.cc +++ b/util/lzma/minilzma.cc @@ -4,7 +4,8 @@ * Copyright (C) 2002 Eric Biederman * Copyright (C) 2005 Joel Yliluoma * Copyright (C) 2007 coresystems GmbH - * Adapted by Stefan Reinauer for coresystems GmbH. + * (Adapted by Stefan Reinauer for coresystems GmbH) + * Copyright (C) 2007 Patrick Georgi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,8 +22,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA */ - - #include "C/Common/MyInitGuid.h" #include "C/7zip/Compress/LZMA/LZMAEncoder.h" @@ -281,11 +280,18 @@ int main(int argc, char *argv[]) #else extern "C" { -void do_lzma_compress(char* in, unsigned long in_len, char* out, unsigned long* out_len) { +void do_lzma_compress(char *in, unsigned long in_len, char *out, + unsigned long *out_len) { std::vector result; - result = LZMACompress(std::vector(in,in+in_len)); + result = LZMACompress(std::vector(in, in + in_len)); *out_len = result.size(); - std::memcpy(out, &result[0], *out_len); + std::memcpy(out, &result[0], *out_len); +} + +void do_lzma_uncompress(char *dst, char *src, unsigned long len) { + std::vector result; + result = LZMADeCompress(std::vector(src, src + len)); + std::memcpy(dst, &result[0], result.size()); } } diff --git a/util/nrv2b/nrv2b.c b/util/nrv2b/nrv2b.c index 26f4603756..ecae0a724e 100644 --- a/util/nrv2b/nrv2b.c +++ b/util/nrv2b/nrv2b.c @@ -28,6 +28,11 @@ The conversion was performed by Eric Biederman . 20 August 2002 + + Added do_nrv2b_uncompress(). + by Patrick Georgi + 2007-06-26 + **************************************************************/ #define UCLPACK_COMPAT 0 @@ -1304,6 +1309,56 @@ void do_nrv2b_compress(char* in, unsigned long in_len, char* out, unsigned long* out = malloc(*out_len); ucl_nrv2b_99_compress(in, in_len, out, out_len, 0 ); } + +void do_nrv2b_uncompress(char* dst, char* src, unsigned long len) { + unsigned long ilen = 0, olen = 0, last_m_off = 1; + for (;;) { + unsigned int m_off, m_len; + while (GETBIT(bb, src, ilen)) { + FAIL(ilen >= src_len, "input overrun"); + FAIL(olen >= dst_len, "output overrun"); + dst[olen++] = src[ilen++]; + } + m_off = 1; + do { + m_off = (m_off * 2) + GETBIT(bb, src, ilen); + FAIL(ilen >= src_len, "input overrun"); + FAIL(m_off > 0xffffffU +3, "lookbehind overrun"); + } while (!GETBIT(bb, src, ilen)); + if (m_off == 2) { + m_off = last_m_off; + } else { + FAIL(ilen >= src_len, "input overrun"); + m_off = ((m_off - 3) * 256) + src[ilen++]; + if (m_off == 0xffffffffU) + break; + last_m_off = ++m_off; + } + m_len = GETBIT(bb, src, ilen); + m_len = (m_len * 2) + GETBIT(bb, src, ilen); + if (m_len == 0) { + m_len++; + do { + m_len = (m_len * 2) + GETBIT(bb, src, ilen); + FAIL(ilen >= src_len, "input overrun"); + FAIL(m_len >= dst_len, "output overrun"); + } while(!GETBIT(bb, src, ilen)); + m_len += 2; + } + m_len += (m_off > 0xd00); + FAIL(olen + m_len > dst_len, "output overrun"); + FAIL(m_off > olen, "lookbehind overrun"); + { + const uint8_t *m_pos; + m_pos = dst + olen - m_off; + dst[olen++] = *m_pos++; + do { + dst[olen++] = *m_pos++; + } while(--m_len > 0); + } + } + FAIL(ilen < src_len, "input not consumed"); +} #endif #ifdef DECODE