Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/libs/compr/blz.c
1476 views
1
/*
2
* Copyright (c) 2018 rajkosto
3
* Copyright (c) 2018 SciresM
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms and conditions of the GNU General Public License,
7
* version 2, as published by the Free Software Foundation.
8
*
9
* This program is distributed in the hope it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include "blz.h"
22
23
const blz_footer *blz_get_footer(const u8 *comp_data, u32 comp_data_size, blz_footer *out_footer)
24
{
25
if (comp_data_size < sizeof(blz_footer))
26
return NULL;
27
28
const blz_footer *src_footer = (const blz_footer *)&comp_data[comp_data_size - sizeof(blz_footer)];
29
if (out_footer)
30
memcpy(out_footer, src_footer, sizeof(blz_footer)); // Must be a memcpy because no unaligned accesses on ARMv4.
31
32
return src_footer;
33
}
34
35
// From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM!
36
int blz_uncompress_inplace(u8 *data, u32 comp_size, const blz_footer *footer)
37
{
38
u32 addl_size = footer->addl_size;
39
u32 header_size = footer->header_size;
40
u32 cmp_and_hdr_size = footer->cmp_and_hdr_size;
41
42
u8 *cmp_start = &data[comp_size] - cmp_and_hdr_size;
43
u32 cmp_ofs = cmp_and_hdr_size - header_size;
44
u32 out_ofs = cmp_and_hdr_size + addl_size;
45
46
while (out_ofs)
47
{
48
u8 control = cmp_start[--cmp_ofs];
49
for (u32 i = 0; i < 8; i++)
50
{
51
if (control & 0x80)
52
{
53
if (cmp_ofs < 2)
54
return 0; // Out of bounds.
55
56
cmp_ofs -= 2;
57
u16 seg_val = ((u32)(cmp_start[cmp_ofs + 1]) << 8) | cmp_start[cmp_ofs];
58
u32 seg_size = ((seg_val >> 12) & 0xF) + 3;
59
u32 seg_ofs = (seg_val & 0x0FFF) + 3;
60
61
// Kernel restricts segment copy to stay in bounds.
62
if (out_ofs < seg_size)
63
seg_size = out_ofs;
64
65
out_ofs -= seg_size;
66
67
for (u32 j = 0; j < seg_size; j++)
68
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
69
}
70
else // Copy directly.
71
{
72
if (cmp_ofs < 1)
73
return 0; // Out of bounds.
74
75
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
76
}
77
78
control <<= 1;
79
80
if (!out_ofs) // Blz works backwards, so if it reaches byte 0, it's done.
81
return 1;
82
}
83
}
84
85
return 1;
86
}
87
88
int blz_uncompress_srcdest(const u8 *comp_data, u32 comp_data_size, u8 *dst_data, u32 dst_size)
89
{
90
blz_footer footer;
91
const blz_footer *comp_footer = blz_get_footer(comp_data, comp_data_size, &footer);
92
if (!comp_footer)
93
return 0;
94
95
// Decompression happens in-place, so need to copy the relevant compressed data first.
96
u32 comp_bytes = (const u8 *)comp_footer - comp_data;
97
memcpy(dst_data, comp_data, comp_bytes);
98
memset(&dst_data[comp_bytes], 0, dst_size - comp_bytes);
99
100
return blz_uncompress_inplace(dst_data, comp_data_size, &footer);
101
}
102
103