/src/fwupd/libfwupdplugin/fu-lzma-common.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2021 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | | #include "config.h" |
8 | | |
9 | | #include <lzma.h> |
10 | | |
11 | | #include "fu-lzma-common.h" |
12 | | |
13 | | /** |
14 | | * fu_lzma_decompress_bytes: |
15 | | * @blob: data |
16 | | * @memlimit: decompression memory limit, in bytes |
17 | | * @error: (nullable): optional return location for an error |
18 | | * |
19 | | * Decompresses a LZMA stream. |
20 | | * |
21 | | * Returns: (transfer full): decompressed data |
22 | | * |
23 | | * Since: 2.0.7 |
24 | | **/ |
25 | | GBytes * |
26 | | fu_lzma_decompress_bytes(GBytes *blob, guint64 memlimit, GError **error) |
27 | 1.50k | { |
28 | 1.50k | const gsize tmpbufsz = 0x20000; |
29 | 1.50k | lzma_ret rc; |
30 | 1.50k | lzma_stream strm = LZMA_STREAM_INIT; |
31 | 1.50k | g_autofree guint8 *tmpbuf = g_malloc0(tmpbufsz); |
32 | 1.50k | g_autoptr(GByteArray) buf = g_byte_array_new(); |
33 | | |
34 | 1.50k | strm.next_in = g_bytes_get_data(blob, NULL); |
35 | 1.50k | strm.avail_in = g_bytes_get_size(blob); |
36 | | |
37 | 1.50k | rc = lzma_auto_decoder(&strm, memlimit, LZMA_TELL_UNSUPPORTED_CHECK); |
38 | 1.50k | if (rc != LZMA_OK) { |
39 | 0 | lzma_end(&strm); |
40 | 0 | g_set_error(error, |
41 | 0 | FWUPD_ERROR, |
42 | 0 | FWUPD_ERROR_NOT_SUPPORTED, |
43 | 0 | "failed to set up LZMA decoder rc=%u", |
44 | 0 | rc); |
45 | 0 | return NULL; |
46 | 0 | } |
47 | 4.36k | do { |
48 | 4.36k | strm.next_out = tmpbuf; |
49 | 4.36k | strm.avail_out = tmpbufsz; |
50 | 4.36k | rc = lzma_code(&strm, LZMA_RUN); |
51 | 4.36k | if (rc != LZMA_OK && rc != LZMA_STREAM_END) |
52 | 623 | break; |
53 | 3.74k | g_byte_array_append(buf, tmpbuf, tmpbufsz - strm.avail_out); |
54 | 3.74k | } while (rc == LZMA_OK); |
55 | 1.50k | lzma_end(&strm); |
56 | | |
57 | | /* success */ |
58 | 1.50k | if (rc != LZMA_OK && rc != LZMA_STREAM_END) { |
59 | 623 | g_set_error(error, |
60 | 623 | FWUPD_ERROR, |
61 | 623 | FWUPD_ERROR_NOT_SUPPORTED, |
62 | 623 | "failed to decode LZMA data rc=%u", |
63 | 623 | rc); |
64 | 623 | return NULL; |
65 | 623 | } |
66 | 883 | return g_bytes_new(buf->data, buf->len); |
67 | 1.50k | } |
68 | | |
69 | | /** |
70 | | * fu_lzma_compress_bytes: |
71 | | * @blob: data |
72 | | * @error: (nullable): optional return location for an error |
73 | | * |
74 | | * Compresses into a LZMA stream. |
75 | | * |
76 | | * Returns: (transfer full): compressed data |
77 | | * |
78 | | * Since: 1.9.8 |
79 | | **/ |
80 | | GBytes * |
81 | | fu_lzma_compress_bytes(GBytes *blob, GError **error) |
82 | 146 | { |
83 | 146 | const gsize tmpbufsz = 0x20000; |
84 | 146 | lzma_ret rc; |
85 | 146 | lzma_stream strm = LZMA_STREAM_INIT; |
86 | 146 | g_autofree guint8 *tmpbuf = g_malloc0(tmpbufsz); |
87 | 146 | g_autoptr(GByteArray) buf = g_byte_array_new(); |
88 | | |
89 | 146 | strm.next_in = g_bytes_get_data(blob, NULL); |
90 | 146 | strm.avail_in = g_bytes_get_size(blob); |
91 | | |
92 | | /* xz default compression level is 6, higher values increase CPU and memory usage */ |
93 | 146 | rc = lzma_easy_encoder(&strm, 6, LZMA_CHECK_CRC64); |
94 | 146 | if (rc != LZMA_OK) { |
95 | 0 | lzma_end(&strm); |
96 | 0 | g_set_error(error, |
97 | 0 | FWUPD_ERROR, |
98 | 0 | FWUPD_ERROR_NOT_SUPPORTED, |
99 | 0 | "failed to set up LZMA encoder rc=%u", |
100 | 0 | rc); |
101 | 0 | return NULL; |
102 | 0 | } |
103 | 146 | do { |
104 | 146 | strm.next_out = tmpbuf; |
105 | 146 | strm.avail_out = tmpbufsz; |
106 | 146 | rc = lzma_code(&strm, LZMA_FINISH); |
107 | 146 | if (rc != LZMA_OK && rc != LZMA_STREAM_END) |
108 | 0 | break; |
109 | 146 | g_byte_array_append(buf, tmpbuf, tmpbufsz - strm.avail_out); |
110 | 146 | } while (rc == LZMA_OK); |
111 | 146 | lzma_end(&strm); |
112 | | |
113 | | /* success */ |
114 | 146 | if (rc != LZMA_OK && rc != LZMA_STREAM_END) { |
115 | 0 | g_set_error(error, |
116 | 0 | FWUPD_ERROR, |
117 | 0 | FWUPD_ERROR_NOT_SUPPORTED, |
118 | 0 | "failed to encode LZMA data rc=%u", |
119 | 0 | rc); |
120 | 0 | return NULL; |
121 | 0 | } |
122 | 146 | return g_bytes_new(buf->data, buf->len); |
123 | 146 | } |