[libyelp/yelp-mallard-document] Support for Mallard Facets extension
[yelp.git] / libyelp / yelp-magic-decompressor.c
blob6b3a83ccc178187e4844d6ac7be1a87e029ef571
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2009 Red Hat, Inc.
4 * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Author: Shaun McCance <shaunm@gnome.org>
24 #include "config.h"
26 #include <glib/gi18n.h>
27 #include <string.h>
29 #include "yelp-magic-decompressor.h"
31 #ifdef ENABLE_BZ2
32 #include "yelp-bz2-decompressor.h"
33 #endif
35 #ifdef ENABLE_LZMA
36 #include "yelp-lzma-decompressor.h"
37 #endif
40 static void yelp_magic_decompressor_iface_init (GConverterIface *iface);
42 struct _YelpMagicDecompressor
44 GObject parent_instance;
46 GConverter *magic_decoder_ring;
48 gboolean first;
51 G_DEFINE_TYPE_WITH_CODE (YelpMagicDecompressor, yelp_magic_decompressor, G_TYPE_OBJECT,
52 G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
53 yelp_magic_decompressor_iface_init))
55 static void
56 yelp_magic_decompressor_dispose (GObject *object)
58 YelpMagicDecompressor *decompressor = YELP_MAGIC_DECOMPRESSOR (object);
60 if (decompressor->magic_decoder_ring) {
61 g_object_unref (decompressor->magic_decoder_ring);
62 decompressor->magic_decoder_ring = NULL;
65 G_OBJECT_CLASS (yelp_magic_decompressor_parent_class)->dispose (object);
68 static void
69 yelp_magic_decompressor_init (YelpMagicDecompressor *decompressor)
71 decompressor->magic_decoder_ring = NULL;
72 decompressor->first = TRUE;
75 static void
76 yelp_magic_decompressor_class_init (YelpMagicDecompressorClass *klass)
78 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
80 gobject_class->dispose = yelp_magic_decompressor_dispose;
83 YelpMagicDecompressor *
84 yelp_magic_decompressor_new (void)
86 YelpMagicDecompressor *decompressor;
88 decompressor = g_object_new (YELP_TYPE_MAGIC_DECOMPRESSOR, NULL);
90 return decompressor;
93 static void
94 yelp_magic_decompressor_reset (GConverter *converter)
96 YelpMagicDecompressor *decompressor = YELP_MAGIC_DECOMPRESSOR (converter);
98 if (decompressor->magic_decoder_ring)
99 g_converter_reset (decompressor->magic_decoder_ring);
102 static GConverter*
103 yelp_magic_decompressor_choose (const void *inbuf, gsize inbuf_size)
105 /* If input_size is less than two the first time, we end up
106 * not getting detection. Might be worth addressing. Not
107 * sure I care.
109 * The two-byte magic we're doing here is not sufficient in
110 * the general case. It is sufficient for the specific data
111 * Yelp deals with.
113 if (inbuf_size <= 2)
114 return NULL;
116 #ifdef ENABLE_BZ2
117 if (((gchar *) inbuf)[0] == 'B' && ((gchar *) inbuf)[1] == 'Z') {
118 return (GConverter *) yelp_bz2_decompressor_new ();
120 #endif
121 #ifdef ENABLE_LZMA
122 if (((gchar *) inbuf)[0] == ']' && ((gchar *) inbuf)[1] == '\0') {
123 return (GConverter *) yelp_lzma_decompressor_new ();
125 #endif
126 if (((guint8*) inbuf)[0] == 0x1F && ((guint8*) inbuf)[1] == 0x8B) {
127 return (GConverter *) g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
130 return NULL;
133 static GConverterResult
134 yelp_magic_decompressor_convert (GConverter *converter,
135 const void *inbuf,
136 gsize inbuf_size,
137 void *outbuf,
138 gsize outbuf_size,
139 GConverterFlags flags,
140 gsize *bytes_read,
141 gsize *bytes_written,
142 GError **error)
144 YelpMagicDecompressor *decompressor;
145 gsize txfer_size;
147 decompressor = YELP_MAGIC_DECOMPRESSOR (converter);
149 if (decompressor->first) {
150 decompressor->magic_decoder_ring =
151 yelp_magic_decompressor_choose (inbuf, inbuf_size);
152 decompressor->first = FALSE;
155 if (decompressor->magic_decoder_ring) {
156 return g_converter_convert (decompressor->magic_decoder_ring,
157 inbuf, inbuf_size,
158 outbuf, outbuf_size,
159 flags,
160 bytes_read, bytes_written,
161 error);
164 /* If there's no magic_decoder_ring, we just copy the data
165 * straight through. */
166 txfer_size = MIN (inbuf_size, outbuf_size);
167 memcpy (outbuf, inbuf, txfer_size);
168 *bytes_read = txfer_size;
169 *bytes_written = txfer_size;
171 return G_CONVERTER_CONVERTED;
174 static void
175 yelp_magic_decompressor_iface_init (GConverterIface *iface)
177 iface->convert = yelp_magic_decompressor_convert;
178 iface->reset = yelp_magic_decompressor_reset;