Coverage Report

Created: 2026-05-30 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxmlb/src/xb-lzma-decompressor.c
Line
Count
Source
1
/*
2
 * Copyright 2009 Red Hat, Inc.
3
 * Copyright 2009 Shaun McCance <shaunm@gnome.org>
4
 * Copyright 2021 Richard Hughes <richard@hughsie.com>
5
 *
6
 * SPDX-License-Identifier: LGPL-2.1-or-later
7
 */
8
9
#include "config.h"
10
11
#include <errno.h>
12
#include <gio/gio.h>
13
#include <lzma.h>
14
#include <string.h>
15
16
#include "xb-lzma-decompressor.h"
17
18
static void
19
xb_lzma_decompressor_iface_init(GConverterIface *iface);
20
21
struct _XbLzmaDecompressor {
22
  GObject parent_instance;
23
  lzma_stream lzmastream;
24
};
25
26
0
G_DEFINE_TYPE_WITH_CODE(XbLzmaDecompressor,
27
0
      xb_lzma_decompressor,
28
0
      G_TYPE_OBJECT,
29
0
      G_IMPLEMENT_INTERFACE(G_TYPE_CONVERTER, xb_lzma_decompressor_iface_init))
30
0
31
0
static void
32
0
xb_lzma_decompressor_finalize(GObject *object)
33
0
{
34
0
  XbLzmaDecompressor *self = XB_LZMA_DECOMPRESSOR(object);
35
0
  lzma_end(&self->lzmastream);
36
0
  G_OBJECT_CLASS(xb_lzma_decompressor_parent_class)->finalize(object);
37
0
}
38
39
static void
40
xb_lzma_decompressor_init(XbLzmaDecompressor *self)
41
0
{
42
0
}
43
44
static void
45
xb_lzma_decompressor_constructed(GObject *object)
46
0
{
47
0
  XbLzmaDecompressor *self = XB_LZMA_DECOMPRESSOR(object);
48
0
  lzma_stream tmp = LZMA_STREAM_INIT;
49
0
  lzma_ret res;
50
51
0
  self->lzmastream = tmp;
52
0
  res = lzma_auto_decoder(&self->lzmastream, SIZE_MAX, 0);
53
0
  if (res == LZMA_MEM_ERROR)
54
0
    g_error("XbLzmaDecompressor: Not enough memory for lzma use");
55
0
  if (res == LZMA_OPTIONS_ERROR)
56
0
    g_error("XbLzmaDecompressor: Unsupported flags");
57
0
  if (res != LZMA_OK)
58
0
    g_error("XbLzmaDecompressor: Unexpected lzma error");
59
0
  G_OBJECT_CLASS(xb_lzma_decompressor_parent_class)->constructed(object);
60
0
}
61
62
static void
63
xb_lzma_decompressor_class_init(XbLzmaDecompressorClass *klass)
64
0
{
65
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
66
0
  object_class->finalize = xb_lzma_decompressor_finalize;
67
0
  object_class->constructed = xb_lzma_decompressor_constructed;
68
0
}
69
70
XbLzmaDecompressor *
71
xb_lzma_decompressor_new(void)
72
0
{
73
0
  return g_object_new(XB_TYPE_LZMA_DECOMPRESSOR, NULL);
74
0
}
75
76
static void
77
xb_lzma_decompressor_reset(GConverter *converter)
78
0
{
79
0
  XbLzmaDecompressor *self = XB_LZMA_DECOMPRESSOR(converter);
80
0
  lzma_ret res;
81
82
  /* lzma doesn't have a reset function.  Ending and reiniting
83
   * might do the trick.  But this is untested.  If reset matters
84
   * to you, test this.
85
   */
86
0
  lzma_end(&self->lzmastream);
87
0
  res = lzma_code(&self->lzmastream, LZMA_RUN);
88
0
  if (res == LZMA_MEM_ERROR)
89
0
    g_error("XbLzmaDecompressor: Not enough memory for lzma use");
90
0
  if (res != LZMA_OK)
91
0
    g_error("XbLzmaDecompressor: Unexpected lzma error");
92
0
}
93
94
static GConverterResult
95
xb_lzma_decompressor_convert(GConverter *converter,
96
           const void *inbuf,
97
           gsize inbuf_size,
98
           void *outbuf,
99
           gsize outbuf_size,
100
           GConverterFlags flags,
101
           gsize *bytes_read,
102
           gsize *bytes_written,
103
           GError **error)
104
0
{
105
0
  XbLzmaDecompressor *self = XB_LZMA_DECOMPRESSOR(converter);
106
0
  lzma_ret res;
107
108
0
  self->lzmastream.next_in = (void *)inbuf;
109
0
  self->lzmastream.avail_in = inbuf_size;
110
0
  self->lzmastream.next_out = outbuf;
111
0
  self->lzmastream.avail_out = outbuf_size;
112
113
0
  res = lzma_code(&self->lzmastream, LZMA_RUN);
114
0
  if (res == LZMA_DATA_ERROR) {
115
0
    g_set_error_literal(error,
116
0
            G_IO_ERROR,
117
0
            G_IO_ERROR_INVALID_DATA,
118
0
            "Invalid compressed data");
119
0
    return G_CONVERTER_ERROR;
120
0
  }
121
0
  if (res == LZMA_UNSUPPORTED_CHECK) {
122
0
    g_set_error_literal(error,
123
0
            G_IO_ERROR,
124
0
            G_IO_ERROR_NOT_SUPPORTED,
125
0
            "Cannot calculate the integrity check");
126
0
    return G_CONVERTER_ERROR;
127
0
  }
128
0
  if (res == LZMA_MEM_ERROR) {
129
0
    g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not enough memory");
130
0
    return G_CONVERTER_ERROR;
131
0
  }
132
0
  if (res == LZMA_FORMAT_ERROR) {
133
0
    g_set_error_literal(error,
134
0
            G_IO_ERROR,
135
0
            G_IO_ERROR_NOT_SUPPORTED,
136
0
            "File format not recognized");
137
0
    return G_CONVERTER_ERROR;
138
0
  }
139
0
  if (res == LZMA_OPTIONS_ERROR) {
140
0
    g_set_error_literal(error,
141
0
            G_IO_ERROR,
142
0
            G_IO_ERROR_NOT_SUPPORTED,
143
0
            "Invalid or unsupported options");
144
0
    return G_CONVERTER_ERROR;
145
0
  }
146
0
  if (res == LZMA_BUF_ERROR) {
147
0
    g_set_error_literal(error,
148
0
            G_IO_ERROR,
149
0
            G_IO_ERROR_INVALID_DATA,
150
0
            "No progress is possible");
151
0
    return G_CONVERTER_ERROR;
152
0
  }
153
0
  if (res == LZMA_PROG_ERROR) {
154
0
    g_set_error_literal(error,
155
0
            G_IO_ERROR,
156
0
            G_IO_ERROR_INVALID_ARGUMENT,
157
0
            "Programming error");
158
0
    return G_CONVERTER_ERROR;
159
0
  }
160
0
  if (res == LZMA_OK || res == LZMA_STREAM_END) {
161
0
    *bytes_read = inbuf_size - self->lzmastream.avail_in;
162
0
    *bytes_written = outbuf_size - self->lzmastream.avail_out;
163
0
    if (res == LZMA_STREAM_END)
164
0
      return G_CONVERTER_FINISHED;
165
0
    return G_CONVERTER_CONVERTED;
166
0
  }
167
168
  /* fallback */
169
0
  g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unhandled error code %u", res);
170
0
  return G_CONVERTER_ERROR;
171
0
}
172
173
static void
174
xb_lzma_decompressor_iface_init(GConverterIface *iface)
175
0
{
176
0
  iface->convert = xb_lzma_decompressor_convert;
177
0
  iface->reset = xb_lzma_decompressor_reset;
178
0
}