Coverage Report

Created: 2025-06-22 06:29

/src/libxmlb/src/xb-lzma-decompressor.c
Line
Count
Source (jump to first uncovered line)
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
G_DEFINE_TYPE_WITH_CODE(XbLzmaDecompressor,
27
      xb_lzma_decompressor,
28
      G_TYPE_OBJECT,
29
      G_IMPLEMENT_INTERFACE(G_TYPE_CONVERTER, xb_lzma_decompressor_iface_init))
30
31
static void
32
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
}
60
61
static void
62
xb_lzma_decompressor_class_init(XbLzmaDecompressorClass *klass)
63
0
{
64
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
65
0
  object_class->finalize = xb_lzma_decompressor_finalize;
66
0
  object_class->constructed = xb_lzma_decompressor_constructed;
67
0
}
68
69
XbLzmaDecompressor *
70
xb_lzma_decompressor_new(void)
71
0
{
72
0
  return g_object_new(XB_TYPE_LZMA_DECOMPRESSOR, NULL);
73
0
}
74
75
static void
76
xb_lzma_decompressor_reset(GConverter *converter)
77
0
{
78
0
  XbLzmaDecompressor *self = XB_LZMA_DECOMPRESSOR(converter);
79
0
  lzma_ret res;
80
81
  /* lzma doesn't have a reset function.  Ending and reiniting
82
   * might do the trick.  But this is untested.  If reset matters
83
   * to you, test this.
84
   */
85
0
  lzma_end(&self->lzmastream);
86
0
  res = lzma_code(&self->lzmastream, LZMA_RUN);
87
0
  if (res == LZMA_MEM_ERROR)
88
0
    g_error("XbLzmaDecompressor: Not enough memory for lzma use");
89
0
  if (res != LZMA_OK)
90
0
    g_error("XbLzmaDecompressor: Unexpected lzma error");
91
0
}
92
93
static GConverterResult
94
xb_lzma_decompressor_convert(GConverter *converter,
95
           const void *inbuf,
96
           gsize inbuf_size,
97
           void *outbuf,
98
           gsize outbuf_size,
99
           GConverterFlags flags,
100
           gsize *bytes_read,
101
           gsize *bytes_written,
102
           GError **error)
103
0
{
104
0
  XbLzmaDecompressor *self = XB_LZMA_DECOMPRESSOR(converter);
105
0
  lzma_ret res;
106
107
0
  self->lzmastream.next_in = (void *)inbuf;
108
0
  self->lzmastream.avail_in = inbuf_size;
109
0
  self->lzmastream.next_out = outbuf;
110
0
  self->lzmastream.avail_out = outbuf_size;
111
112
0
  res = lzma_code(&self->lzmastream, LZMA_RUN);
113
0
  if (res == LZMA_DATA_ERROR) {
114
0
    g_set_error_literal(error,
115
0
            G_IO_ERROR,
116
0
            G_IO_ERROR_INVALID_DATA,
117
0
            "Invalid compressed data");
118
0
    return G_CONVERTER_ERROR;
119
0
  }
120
0
  if (res == LZMA_UNSUPPORTED_CHECK) {
121
0
    g_set_error_literal(error,
122
0
            G_IO_ERROR,
123
0
            G_IO_ERROR_NOT_SUPPORTED,
124
0
            "Cannot calculate the integrity check");
125
0
    return G_CONVERTER_ERROR;
126
0
  }
127
0
  if (res == LZMA_MEM_ERROR) {
128
0
    g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not enough memory");
129
0
    return G_CONVERTER_ERROR;
130
0
  }
131
0
  if (res == LZMA_FORMAT_ERROR) {
132
0
    g_set_error_literal(error,
133
0
            G_IO_ERROR,
134
0
            G_IO_ERROR_NOT_SUPPORTED,
135
0
            "File format not recognized");
136
0
    return G_CONVERTER_ERROR;
137
0
  }
138
0
  if (res == LZMA_OPTIONS_ERROR) {
139
0
    g_set_error_literal(error,
140
0
            G_IO_ERROR,
141
0
            G_IO_ERROR_NOT_SUPPORTED,
142
0
            "Invalid or unsupported options");
143
0
    return G_CONVERTER_ERROR;
144
0
  }
145
0
  if (res == LZMA_BUF_ERROR) {
146
0
    g_set_error_literal(error,
147
0
            G_IO_ERROR,
148
0
            G_IO_ERROR_INVALID_DATA,
149
0
            "No progress is possible");
150
0
    return G_CONVERTER_ERROR;
151
0
  }
152
0
  if (res == LZMA_PROG_ERROR) {
153
0
    g_set_error_literal(error,
154
0
            G_IO_ERROR,
155
0
            G_IO_ERROR_INVALID_ARGUMENT,
156
0
            "Programming error");
157
0
    return G_CONVERTER_ERROR;
158
0
  }
159
0
  if (res == LZMA_OK || res == LZMA_STREAM_END) {
160
0
    *bytes_read = inbuf_size - self->lzmastream.avail_in;
161
0
    *bytes_written = outbuf_size - self->lzmastream.avail_out;
162
0
    if (res == LZMA_STREAM_END)
163
0
      return G_CONVERTER_FINISHED;
164
0
    return G_CONVERTER_CONVERTED;
165
0
  }
166
167
  /* fallback */
168
0
  g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unhandled error code %u", res);
169
0
  return G_CONVERTER_ERROR;
170
0
}
171
172
static void
173
xb_lzma_decompressor_iface_init(GConverterIface *iface)
174
0
{
175
0
  iface->convert = xb_lzma_decompressor_convert;
176
0
  iface->reset = xb_lzma_decompressor_reset;
177
0
}