1/*
2 * Copyright (c) 2009, 2010, 2013
3 * Phillip Lougher <phillip@squashfs.org.uk>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2,
8 * or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * lzma_wrapper.c
20 *
21 * Support for LZMA1 compression using LZMA SDK (4.65 used in
22 * development, other versions may work) http://www.7-zip.org/sdk.html
23 */
24
25#include <LzmaLib.h>
26
27#include "squashfs_fs.h"
28#include "compressor.h"
29
30#define LZMA_HEADER_SIZE	(LZMA_PROPS_SIZE + 8)
31
32static int lzma_compress(void *strm, void *dest, void *src, int size, int block_size,
33		int *error)
34{
35	unsigned char *d = dest;
36	size_t props_size = LZMA_PROPS_SIZE,
37		outlen = block_size - LZMA_HEADER_SIZE;
38	int res;
39
40	res = LzmaCompress(dest + LZMA_HEADER_SIZE, &outlen, src, size, dest,
41		&props_size, 5, block_size, 3, 0, 2, 32, 1);
42
43	if(res == SZ_ERROR_OUTPUT_EOF) {
44		/*
45		 * Output buffer overflow.  Return out of buffer space error
46		 */
47		return 0;
48	}
49
50	if(res != SZ_OK) {
51		/*
52		 * All other errors return failure, with the compressor
53		 * specific error code in *error
54		 */
55		*error = res;
56		return -1;
57	}
58
59	/*
60	 * Fill in the 8 byte little endian uncompressed size field in the
61	 * LZMA header.  8 bytes is excessively large for squashfs but
62	 * this is the standard LZMA header and which is expected by the kernel
63	 * code
64	 */
65	d[LZMA_PROPS_SIZE] = size & 255;
66	d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255;
67	d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255;
68	d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255;
69	d[LZMA_PROPS_SIZE + 4] = 0;
70	d[LZMA_PROPS_SIZE + 5] = 0;
71	d[LZMA_PROPS_SIZE + 6] = 0;
72	d[LZMA_PROPS_SIZE + 7] = 0;
73
74	/*
75	 * Success, return the compressed size.  Outlen returned by the LZMA
76	 * compressor does not include the LZMA header space
77	 */
78	return outlen + LZMA_HEADER_SIZE;
79}
80
81
82static int lzma_uncompress(void *dest, void *src, int size, int outsize,
83	int *error)
84{
85	unsigned char *s = src;
86	size_t outlen, inlen = size - LZMA_HEADER_SIZE;
87	int res;
88
89	outlen = s[LZMA_PROPS_SIZE] |
90		(s[LZMA_PROPS_SIZE + 1] << 8) |
91		(s[LZMA_PROPS_SIZE + 2] << 16) |
92		(s[LZMA_PROPS_SIZE + 3] << 24);
93
94	if(outlen > outsize) {
95		*error = 0;
96		return -1;
97	}
98
99	res = LzmaUncompress(dest, &outlen, src + LZMA_HEADER_SIZE, &inlen, src,
100		LZMA_PROPS_SIZE);
101
102	if(res == SZ_OK)
103		return outlen;
104	else {
105		*error = res;
106		return -1;
107	}
108}
109
110
111struct compressor lzma_comp_ops = {
112	.init = NULL,
113	.compress = lzma_compress,
114	.uncompress = lzma_uncompress,
115	.options = NULL,
116	.usage = NULL,
117	.id = LZMA_COMPRESSION,
118	.name = "lzma",
119	.supported = 1
120};
121
122