-
Notifications
You must be signed in to change notification settings - Fork 2
/
lz4_depack.c
105 lines (90 loc) · 2.48 KB
/
lz4_depack.c
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
/*
* blz4 - Example of LZ4 compression with BriefLZ algorithms
*
* C depacker
*
* Copyright (c) 2018 Joergen Ibsen
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must
* not claim that you wrote the original software. If you use this
* software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must
* not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "lz4.h"
#include <assert.h>
unsigned long
lz4_depack(const void *src, void *dst, unsigned long packed_size)
{
const unsigned char *in = (unsigned char *) src;
unsigned char *out = (unsigned char *) dst;
unsigned long dst_size = 0;
unsigned long cur = 0;
unsigned long prev_match_start = 0;
if (in[0] == 0) {
return 0;
}
/* Main decompression loop */
while (cur < packed_size) {
unsigned long token = in[cur++];
unsigned long lit_len = token >> 4;
unsigned long len = (token & 0x0F) + 4;
unsigned long offs;
unsigned long i;
/* Read extra literal length bytes */
if (lit_len == 15) {
while (in[cur] == 255) {
lit_len += 255;
++cur;
}
lit_len += in[cur++];
}
/* Copy literals */
for (i = 0; i < lit_len; ++i) {
out[dst_size++] = in[cur++];
}
/* Check for last incomplete sequence */
if (cur == packed_size) {
/* Check parsing restrictions */
if (dst_size >= 5 && lit_len < 5) {
return LZ4_ERROR;
}
if (dst_size > 12 && dst_size - prev_match_start < 12) {
return LZ4_ERROR;
}
break;
}
/* Read offset */
offs = (unsigned long) in[cur] | ((unsigned long) in[cur + 1] << 8);
cur += 2;
/* Read extra length bytes */
if (len == 19) {
while (in[cur] == 255) {
len += 255;
++cur;
}
len += in[cur++];
}
prev_match_start = dst_size;
/* Copy match */
for (i = 0; i < len; ++i) {
out[dst_size] = out[dst_size - offs];
++dst_size;
}
}
/* Return decompressed size */
return dst_size;
}