aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_dom_decompress_lz4.c
blob: 47875359ab4057b978f645eb802437a73a617279 (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
136
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <endian.h>
#include <stdint.h>

#include "xg_private.h"
#include "xc_dom_decompress.h"

#define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

#define likely(a) a
#define unlikely(a) a

static inline uint_fast16_t le16_to_cpup(const unsigned char *buf)
{
    return buf[0] | (buf[1] << 8);
}

static inline uint_fast32_t le32_to_cpup(const unsigned char *buf)
{
    return le16_to_cpup(buf) | ((uint32_t)le16_to_cpup(buf + 2) << 16);
}

#include "../../xen/include/xen/lz4.h"
#include "../../xen/common/decompress.h"

#ifndef __MINIOS__

#include "../../xen/common/lz4/decompress.c"

#define ARCHIVE_MAGICNUMBER 0x184C2102

int xc_try_lz4_decode(
	struct xc_dom_image *dom, void **blob, size_t *psize)
{
	int ret = -1;
	unsigned char *inp = *blob, *output, *outp;
	ssize_t size = *psize - 4;
	size_t out_len, dest_len, chunksize;
	const char *msg;

	if (size < 4) {
		msg = "input too small";
		goto exit_0;
	}

	out_len = get_unaligned_le32(inp + size);
	if (xc_dom_kernel_check_size(dom, out_len)) {
		msg = "Decompressed image too large";
		goto exit_0;
	}

	output = malloc(out_len);
	if (!output) {
		msg = "Could not allocate output buffer";
		goto exit_0;
	}
	outp = output;

	chunksize = get_unaligned_le32(inp);
	if (chunksize == ARCHIVE_MAGICNUMBER) {
		inp += 4;
		size -= 4;
	} else {
		msg = "invalid header";
		goto exit_2;
	}

	for (;;) {
		if (size < 4) {
			msg = "missing data";
			goto exit_2;
		}
		chunksize = get_unaligned_le32(inp);
		if (chunksize == ARCHIVE_MAGICNUMBER) {
			inp += 4;
			size -= 4;
			continue;
		}
		inp += 4;
		size -= 4;
		if (chunksize > size) {
			msg = "insufficient input data";
			goto exit_2;
		}

		dest_len = out_len - (outp - output);
		ret = lz4_decompress_unknownoutputsize(inp, chunksize, outp,
				&dest_len);
		if (ret < 0) {
			msg = "decoding failed";
			goto exit_2;
		}

		outp += dest_len;
		size -= chunksize;

		if (size == 0)
		{
			*blob = output;
			*psize = out_len;
			return 0;
		}

		if (size < 0) {
			msg = "data corrupted";
			goto exit_2;
		}

		inp += chunksize;
	}

exit_2:
	free(output);
exit_0:
	DOMPRINTF("LZ4 decompression error: %s\n", msg);
	return ret;
}

#else /* __MINIOS__ */

#include "../../xen/common/unlz4.c"

int xc_try_lz4_decode(
    struct xc_dom_image *dom, void **blob, size_t *size)
{
    return xc_dom_decompress_unsafe(unlz4, dom, blob, size);
}

#endif