1e8002815beefa4ccc4db6873615b83d7676540f4plougher/* 28a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher * Copyright (c) 2010, 2013 383d42a3fc898962aa1f1e8387f2ccb1114e0d294Phillip Lougher * Phillip Lougher <phillip@squashfs.org.uk> 4e8002815beefa4ccc4db6873615b83d7676540f4plougher * 5e8002815beefa4ccc4db6873615b83d7676540f4plougher * This program is free software; you can redistribute it and/or 6e8002815beefa4ccc4db6873615b83d7676540f4plougher * modify it under the terms of the GNU General Public License 7e8002815beefa4ccc4db6873615b83d7676540f4plougher * as published by the Free Software Foundation; either version 2, 8e8002815beefa4ccc4db6873615b83d7676540f4plougher * or (at your option) any later version. 9e8002815beefa4ccc4db6873615b83d7676540f4plougher * 10e8002815beefa4ccc4db6873615b83d7676540f4plougher * This program is distributed in the hope that it will be useful, 11e8002815beefa4ccc4db6873615b83d7676540f4plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e8002815beefa4ccc4db6873615b83d7676540f4plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e8002815beefa4ccc4db6873615b83d7676540f4plougher * GNU General Public License for more details. 14e8002815beefa4ccc4db6873615b83d7676540f4plougher * 15e8002815beefa4ccc4db6873615b83d7676540f4plougher * You should have received a copy of the GNU General Public License 16e8002815beefa4ccc4db6873615b83d7676540f4plougher * along with this program; if not, write to the Free Software 17e8002815beefa4ccc4db6873615b83d7676540f4plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18e8002815beefa4ccc4db6873615b83d7676540f4plougher * 191dfd42feb90cb580dfd6deb121a0f2c251346241plougher * lzma_xz_wrapper.c 201dfd42feb90cb580dfd6deb121a0f2c251346241plougher * 211dfd42feb90cb580dfd6deb121a0f2c251346241plougher * Support for LZMA1 compression using XZ Utils liblzma http://tukaani.org/xz/ 22e8002815beefa4ccc4db6873615b83d7676540f4plougher */ 23e8002815beefa4ccc4db6873615b83d7676540f4plougher 24e8002815beefa4ccc4db6873615b83d7676540f4plougher#include <stdio.h> 25e8002815beefa4ccc4db6873615b83d7676540f4plougher#include <string.h> 26e8002815beefa4ccc4db6873615b83d7676540f4plougher#include <lzma.h> 27e8002815beefa4ccc4db6873615b83d7676540f4plougher 28083bf88e09158b4ecc2e56206351e831b339a893plougher#include "squashfs_fs.h" 29083bf88e09158b4ecc2e56206351e831b339a893plougher#include "compressor.h" 30083bf88e09158b4ecc2e56206351e831b339a893plougher 31e8002815beefa4ccc4db6873615b83d7676540f4plougher#define LZMA_PROPS_SIZE 5 32e8002815beefa4ccc4db6873615b83d7676540f4plougher#define LZMA_UNCOMP_SIZE 8 33e8002815beefa4ccc4db6873615b83d7676540f4plougher#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNCOMP_SIZE) 34e8002815beefa4ccc4db6873615b83d7676540f4plougher 35e8002815beefa4ccc4db6873615b83d7676540f4plougher#define LZMA_OPTIONS 5 36e8002815beefa4ccc4db6873615b83d7676540f4plougher#define MEMLIMIT (32 * 1024 * 1024) 37e8002815beefa4ccc4db6873615b83d7676540f4plougher 38742331a7dc261a592b05cc66bc451a8d76af4588plougherstatic int lzma_compress(void *dummy, void *dest, void *src, int size, 39e8002815beefa4ccc4db6873615b83d7676540f4plougher int block_size, int *error) 40e8002815beefa4ccc4db6873615b83d7676540f4plougher{ 41e8002815beefa4ccc4db6873615b83d7676540f4plougher unsigned char *d = (unsigned char *) dest; 42e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_options_lzma opt; 43e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_stream strm = LZMA_STREAM_INIT; 44e8002815beefa4ccc4db6873615b83d7676540f4plougher int res; 45e8002815beefa4ccc4db6873615b83d7676540f4plougher 46e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_lzma_preset(&opt, LZMA_OPTIONS); 47e8002815beefa4ccc4db6873615b83d7676540f4plougher opt.dict_size = block_size; 485c32b60174c319e0dfa4ebcce0086c6aa473f94cplougher 49e8002815beefa4ccc4db6873615b83d7676540f4plougher res = lzma_alone_encoder(&strm, &opt); 50e8002815beefa4ccc4db6873615b83d7676540f4plougher if(res != LZMA_OK) { 51e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_end(&strm); 52e8002815beefa4ccc4db6873615b83d7676540f4plougher goto failed; 53e8002815beefa4ccc4db6873615b83d7676540f4plougher } 54e8002815beefa4ccc4db6873615b83d7676540f4plougher 55e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.next_out = dest; 56e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.avail_out = block_size; 57e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.next_in = src; 58e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.avail_in = size; 59e8002815beefa4ccc4db6873615b83d7676540f4plougher 60e8002815beefa4ccc4db6873615b83d7676540f4plougher res = lzma_code(&strm, LZMA_FINISH); 61e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_end(&strm); 62e8002815beefa4ccc4db6873615b83d7676540f4plougher 63e8002815beefa4ccc4db6873615b83d7676540f4plougher if(res == LZMA_STREAM_END) { 64e8002815beefa4ccc4db6873615b83d7676540f4plougher /* 65e8002815beefa4ccc4db6873615b83d7676540f4plougher * Fill in the 8 byte little endian uncompressed size field in 66e8002815beefa4ccc4db6873615b83d7676540f4plougher * the LZMA header. 8 bytes is excessively large for squashfs 67e8002815beefa4ccc4db6873615b83d7676540f4plougher * but this is the standard LZMA header and which is expected by 68e8002815beefa4ccc4db6873615b83d7676540f4plougher * the kernel code 69e8002815beefa4ccc4db6873615b83d7676540f4plougher */ 70e8002815beefa4ccc4db6873615b83d7676540f4plougher 71e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE] = size & 255; 72e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255; 73e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255; 74e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255; 75e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 4] = 0; 76e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 5] = 0; 77e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 6] = 0; 78e8002815beefa4ccc4db6873615b83d7676540f4plougher d[LZMA_PROPS_SIZE + 7] = 0; 79e8002815beefa4ccc4db6873615b83d7676540f4plougher 80e8002815beefa4ccc4db6873615b83d7676540f4plougher return (int) strm.total_out; 81e8002815beefa4ccc4db6873615b83d7676540f4plougher } 82e8002815beefa4ccc4db6873615b83d7676540f4plougher 83e8002815beefa4ccc4db6873615b83d7676540f4plougher if(res == LZMA_OK) 84e8002815beefa4ccc4db6873615b83d7676540f4plougher /* 85e8002815beefa4ccc4db6873615b83d7676540f4plougher * Output buffer overflow. Return out of buffer space 86e8002815beefa4ccc4db6873615b83d7676540f4plougher */ 87e8002815beefa4ccc4db6873615b83d7676540f4plougher return 0; 88e8002815beefa4ccc4db6873615b83d7676540f4plougher 89e8002815beefa4ccc4db6873615b83d7676540f4plougherfailed: 90e8002815beefa4ccc4db6873615b83d7676540f4plougher /* 91e8002815beefa4ccc4db6873615b83d7676540f4plougher * All other errors return failure, with the compressor 92e8002815beefa4ccc4db6873615b83d7676540f4plougher * specific error code in *error 93e8002815beefa4ccc4db6873615b83d7676540f4plougher */ 94e8002815beefa4ccc4db6873615b83d7676540f4plougher *error = res; 95e8002815beefa4ccc4db6873615b83d7676540f4plougher return -1; 96e8002815beefa4ccc4db6873615b83d7676540f4plougher} 97e8002815beefa4ccc4db6873615b83d7676540f4plougher 98e8002815beefa4ccc4db6873615b83d7676540f4plougher 998a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougherstatic int lzma_uncompress(void *dest, void *src, int size, int outsize, 100e8002815beefa4ccc4db6873615b83d7676540f4plougher int *error) 101e8002815beefa4ccc4db6873615b83d7676540f4plougher{ 102e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_stream strm = LZMA_STREAM_INIT; 103e8002815beefa4ccc4db6873615b83d7676540f4plougher int uncompressed_size = 0, res; 104e8002815beefa4ccc4db6873615b83d7676540f4plougher unsigned char lzma_header[LZMA_HEADER_SIZE]; 105e8002815beefa4ccc4db6873615b83d7676540f4plougher 106e8002815beefa4ccc4db6873615b83d7676540f4plougher res = lzma_alone_decoder(&strm, MEMLIMIT); 107e8002815beefa4ccc4db6873615b83d7676540f4plougher if(res != LZMA_OK) { 108e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_end(&strm); 109e8002815beefa4ccc4db6873615b83d7676540f4plougher goto failed; 110e8002815beefa4ccc4db6873615b83d7676540f4plougher } 111e8002815beefa4ccc4db6873615b83d7676540f4plougher 112e8002815beefa4ccc4db6873615b83d7676540f4plougher memcpy(lzma_header, src, LZMA_HEADER_SIZE); 113e8002815beefa4ccc4db6873615b83d7676540f4plougher uncompressed_size = lzma_header[LZMA_PROPS_SIZE] | 114e8002815beefa4ccc4db6873615b83d7676540f4plougher (lzma_header[LZMA_PROPS_SIZE + 1] << 8) | 115e8002815beefa4ccc4db6873615b83d7676540f4plougher (lzma_header[LZMA_PROPS_SIZE + 2] << 16) | 116e8002815beefa4ccc4db6873615b83d7676540f4plougher (lzma_header[LZMA_PROPS_SIZE + 3] << 24); 1178a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher 1188a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher if(uncompressed_size > outsize) { 1198a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher res = 0; 1208a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher goto failed; 1218a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher } 1228a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher 123e8002815beefa4ccc4db6873615b83d7676540f4plougher memset(lzma_header + LZMA_PROPS_SIZE, 255, LZMA_UNCOMP_SIZE); 124e8002815beefa4ccc4db6873615b83d7676540f4plougher 125e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.next_out = dest; 1268a4692825eb1840d52f2f921e40346d0f8c7e702Phillip Lougher strm.avail_out = outsize; 127e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.next_in = lzma_header; 128e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.avail_in = LZMA_HEADER_SIZE; 129e8002815beefa4ccc4db6873615b83d7676540f4plougher 130e8002815beefa4ccc4db6873615b83d7676540f4plougher res = lzma_code(&strm, LZMA_RUN); 131e8002815beefa4ccc4db6873615b83d7676540f4plougher 132e8002815beefa4ccc4db6873615b83d7676540f4plougher if(res != LZMA_OK || strm.avail_in != 0) { 133e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_end(&strm); 134e8002815beefa4ccc4db6873615b83d7676540f4plougher goto failed; 135e8002815beefa4ccc4db6873615b83d7676540f4plougher } 136e8002815beefa4ccc4db6873615b83d7676540f4plougher 137e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.next_in = src + LZMA_HEADER_SIZE; 138e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.avail_in = size - LZMA_HEADER_SIZE; 139e8002815beefa4ccc4db6873615b83d7676540f4plougher 140e8002815beefa4ccc4db6873615b83d7676540f4plougher res = lzma_code(&strm, LZMA_FINISH); 141e8002815beefa4ccc4db6873615b83d7676540f4plougher lzma_end(&strm); 142e8002815beefa4ccc4db6873615b83d7676540f4plougher 143e8002815beefa4ccc4db6873615b83d7676540f4plougher if(res == LZMA_STREAM_END || (res == LZMA_OK && 144e8002815beefa4ccc4db6873615b83d7676540f4plougher strm.total_out >= uncompressed_size && strm.avail_in == 0)) 145e8002815beefa4ccc4db6873615b83d7676540f4plougher return uncompressed_size; 146e8002815beefa4ccc4db6873615b83d7676540f4plougher 147e8002815beefa4ccc4db6873615b83d7676540f4plougherfailed: 148e8002815beefa4ccc4db6873615b83d7676540f4plougher *error = res; 149e8002815beefa4ccc4db6873615b83d7676540f4plougher return -1; 150e8002815beefa4ccc4db6873615b83d7676540f4plougher} 151083bf88e09158b4ecc2e56206351e831b339a893plougher 152083bf88e09158b4ecc2e56206351e831b339a893plougher 153083bf88e09158b4ecc2e56206351e831b339a893plougherstruct compressor lzma_comp_ops = { 154742331a7dc261a592b05cc66bc451a8d76af4588plougher .init = NULL, 155083bf88e09158b4ecc2e56206351e831b339a893plougher .compress = lzma_compress, 156083bf88e09158b4ecc2e56206351e831b339a893plougher .uncompress = lzma_uncompress, 157083bf88e09158b4ecc2e56206351e831b339a893plougher .options = NULL, 15854a3ff3cfe39f0d08dcf472a8a4ac9e57c87092aplougher .usage = NULL, 159083bf88e09158b4ecc2e56206351e831b339a893plougher .id = LZMA_COMPRESSION, 160083bf88e09158b4ecc2e56206351e831b339a893plougher .name = "lzma", 161083bf88e09158b4ecc2e56206351e831b339a893plougher .supported = 1 162083bf88e09158b4ecc2e56206351e831b339a893plougher}; 163083bf88e09158b4ecc2e56206351e831b339a893plougher 164