/* * Copyright (c) 2008, Roman Shaposhnik * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY Roman Shaposhnik ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Roman Shaposhnik BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include /* Every compressed lofi file begins with this */ struct lofi_header { char compression_name[36]; uint32_t uncompressed_block_size; uint32_t number_of_blocks; uint32_t size_of_last_block; uint64_t index[]; }; uint64_t ntohll(uint64_t x) { static union {uint16_t i; char c[2];} u = {.c = {32, 0}}; u.i &= 0xff; return ((ntohl(x&0xffffffff)<>32)<<(32-u.i))); } void bail_out(char* msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr, msg, args); exit(-1); } int main(int argc, char** argv) { int i, sf, df, sz; uint8_t *in; uint8_t *out; struct lofi_header *lofi_header; z_stream strm; if (argc != 3) bail_out("Usage: delofi compressed_image raw_image\n"); if ((lofi_header = malloc(sizeof(*lofi_header))) == NULL) bail_out("Not enough memory\n"); if ((sf = open(argv[1], O_RDONLY)) < 0 || (df = creat(argv[2], 0777)) < 0) bail_out("Can't open files\n"); if (read(sf, lofi_header, sizeof(*lofi_header)) != sizeof(*lofi_header)) bail_out("Can't read header\n"); /* the header is stored in the network byte order */ lofi_header->uncompressed_block_size = ntohl(lofi_header->uncompressed_block_size); lofi_header->number_of_blocks = ntohl(lofi_header->number_of_blocks); lofi_header->size_of_last_block = ntohl(lofi_header->size_of_last_block); printf("Compression method: %s; uncomressed block size: 0x%x; # of blocks: %d; size of last block: 0x%x\n", lofi_header->compression_name, lofi_header->uncompressed_block_size, lofi_header->number_of_blocks, lofi_header->size_of_last_block); /* reading an entire index */ sz = lofi_header->number_of_blocks*sizeof(lofi_header->index[0]); if ((lofi_header = realloc(lofi_header, sz+8+sizeof(*lofi_header))) == NULL) bail_out("Not enough memory\n"); if (read(sf, &lofi_header->index, sz) != sz) bail_out("Can't read index\n"); /* the index entries are stored in the network byte order as well */ for (i=0; i < lofi_header->number_of_blocks-1; i++) lofi_header->index[i] = ntohll(lofi_header->index[i+1]) - ntohll(lofi_header->index[i]); lofi_header->index[i] = lofi_header->size_of_last_block; sz = lofi_header->uncompressed_block_size*2; if ((in = malloc(sz*2)) == NULL) bail_out("Not enough memory\n"); out = in + sz; for (i=0; i < lofi_header->number_of_blocks; i++) { /* since every block is independently compressed we have to do this for every iteration */ strm = (z_stream){ .zalloc = Z_NULL, .zfree = Z_NULL, .opaque = Z_NULL, .avail_in = 0, .next_in = Z_NULL }; if (inflateInit(&strm) != Z_OK) bail_out("Can't init zlib\n"); strm.avail_out = sz; strm.next_out = out; strm.avail_in = lofi_header->index[i]; strm.next_in = in; if (read(sf, in, strm.avail_in) != strm.avail_in) bail_out("Can't read block %d\n", i); /* the first byte determines if the block is compressed at all */ if (in[0]) { ++strm.next_in; --strm.avail_in; /* need to skip the first byte of the block */ if (inflate(&strm, Z_FINISH) != Z_STREAM_END) bail_out("Decompression failed for block %d\n", i); strm.avail_out = sz - strm.avail_out; } else { strm.avail_out = strm.avail_in; } if (write(df, out, strm.avail_out) != strm.avail_out) bail_out("Can't write block %d\n", i); } return 0; }