summaryrefslogtreecommitdiff
path: root/compr_lzo.c
blob: d2e2afcc9df79fe97f4d808ef65162f71164a587 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * JFFS2 LZO Compression Interface.
 *
 * Copyright (C) 2007 Nokia Corporation. All rights reserved.
 *
 * Author: Richard Purdie <rpurdie@openedhand.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#ifndef WITHOUT_LZO
#include <asm/types.h>
#include <linux/jffs2.h>
#include <lzo/lzo1x.h>
#include "compr.h"

extern int page_size;

static void *lzo_mem;
static void *lzo_compress_buf;

/*
 * Note about LZO compression.
 *
 * We want to use the _999_ compression routine which gives better compression
 * rates at the expense of time. Decompression time is unaffected. We might as
 * well use the standard lzo library routines for this but they will overflow
 * the destination buffer since they don't check the destination size.
 *
 * We therefore compress to a temporary buffer and copy if it will fit.
 *
 */
static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
			  uint32_t *sourcelen, uint32_t *dstlen)
{
	lzo_uint compress_size;
	int ret;

	ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);

	if (ret != LZO_E_OK)
		return -1;

	if (compress_size > *dstlen)
		return -1;

	memcpy(cpage_out, lzo_compress_buf, compress_size);
	*dstlen = compress_size;

	return 0;
}

static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
				 uint32_t srclen, uint32_t destlen)
{
	int ret;
	lzo_uint dl;

	ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);

	if (ret != LZO_E_OK || dl != destlen)
		return -1;

	return 0;
}

static struct jffs2_compressor jffs2_lzo_comp = {
	.priority = JFFS2_LZO_PRIORITY,
	.name = "lzo",
	.compr = JFFS2_COMPR_LZO,
	.compress = &jffs2_lzo_cmpr,
	.decompress = &jffs2_lzo_decompress,
	.disabled = 1,
};

int jffs2_lzo_init(void)
{
	int ret;

	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
	if (!lzo_mem)
		return -1;

	/* Worse case LZO compression size from their FAQ */
	lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
	if (!lzo_compress_buf) {
		free(lzo_mem);
		return -1;
	}

	ret = jffs2_register_compressor(&jffs2_lzo_comp);
	if (ret < 0) {
		free(lzo_compress_buf);
		free(lzo_mem);
	}

	return ret;
}

void jffs2_lzo_exit(void)
{
	jffs2_unregister_compressor(&jffs2_lzo_comp);
	free(lzo_compress_buf);
	free(lzo_mem);
}

#else

int jffs2_lzo_init(void)
{
	return 0;
}

void jffs2_lzo_exit(void)
{
}

#endif