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