1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Copyright (C) 2002-2006 Dom Lachowicz (cinamod@hotmail.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 #include <gsf-config.h>
22 #include <gsf/gsf-output-memory.h>
23 #include <gsf/gsf-output-impl.h>
24 #include <gsf/gsf-impl-utils.h>
28 #define MAX_STEP (MIN_BLOCK * 128)
30 static GsfOutputClass *parent_class;
32 struct _GsfOutputMemory {
39 GsfOutputClass output_class;
40 } GsfOutputMemoryClass;
43 * gsf_output_memory_new :
45 * Returns: a new file or %NULL.
48 gsf_output_memory_new (void)
50 return g_object_new (GSF_OUTPUT_MEMORY_TYPE, NULL);
54 gsf_output_memory_close (GsfOutput *output)
56 return (parent_class->Close == NULL) ||
57 parent_class->Close (output);
61 gsf_output_memory_finalize (GObject *obj)
63 GsfOutputMemory *mem = GSF_OUTPUT_MEMORY (obj);
68 G_OBJECT_CLASS (parent_class)->finalize (obj);
72 gsf_output_memory_seek (G_GNUC_UNUSED GsfOutput *output,
73 G_GNUC_UNUSED gsf_off_t offset,
74 G_GNUC_UNUSED GSeekType whence)
76 /* let parent implementation handle maneuvering cur_offset */
81 gsf_output_memory_expand (GsfOutputMemory *mem, gsf_off_t needed)
83 gsf_off_t capacity = MAX (mem->capacity, MIN_BLOCK);
86 /* If we need >= MAX_STEP, align to a next multiple of MAX_STEP.
87 * Since MAX_STEP is probably a power of two, this computation
88 * should reduce to "dec, shr, inc, shl", which is probably
89 * quicker then branching.
91 if (needed < MAX_STEP)
92 while (capacity < needed)
95 capacity = ((needed - 1) / MAX_STEP + 1) * MAX_STEP;
97 /* Check for overflow: g_renew() casts its parameters to gsize. */
99 if ((gsf_off_t) lcapacity != capacity || capacity < 0) {
100 g_warning ("overflow in gsf_output_memory_expand");
103 mem->buffer = g_renew (guint8, mem->buffer, lcapacity);
104 mem->capacity = capacity;
110 gsf_output_memory_write (GsfOutput *output,
112 guint8 const *buffer)
114 GsfOutputMemory *mem = GSF_OUTPUT_MEMORY (output);
116 g_return_val_if_fail (mem != NULL, FALSE);
119 mem->buffer = g_new (guint8, MIN_BLOCK);
120 mem->capacity = MIN_BLOCK;
122 if (num_bytes + output->cur_offset > mem->capacity) {
123 if (!gsf_output_memory_expand (mem, output->cur_offset + num_bytes))
127 memcpy (mem->buffer + output->cur_offset, buffer, num_bytes);
131 static gsf_off_t gsf_output_memory_vprintf (GsfOutput *output,
132 char const *format, va_list args) G_GNUC_PRINTF (2, 0);
135 gsf_output_memory_vprintf (GsfOutput *output, char const *format, va_list args)
137 GsfOutputMemory *mem = (GsfOutputMemory *)output;
144 * We need to make a copy as args will become unusable after
145 * the g_vsnprintf call.
147 G_VA_COPY (args2, args);
149 len = g_vsnprintf (mem->buffer + output->cur_offset,
150 mem->capacity - output->cur_offset,
153 /* There was insufficient space */
154 if (len >= (gsf_off_t)(mem->capacity - output->cur_offset))
155 len = parent_class->Vprintf (output, format, args2);
161 return parent_class->Vprintf (output, format, args);
165 gsf_output_memory_init (GObject *obj)
167 GsfOutputMemory *mem = GSF_OUTPUT_MEMORY (obj);
174 gsf_output_memory_class_init (GObjectClass *gobject_class)
176 GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
178 gobject_class->finalize = gsf_output_memory_finalize;
179 output_class->Close = gsf_output_memory_close;
180 output_class->Seek = gsf_output_memory_seek;
181 output_class->Write = gsf_output_memory_write;
182 output_class->Vprintf = gsf_output_memory_vprintf;
184 parent_class = GSF_OUTPUT_CLASS (g_type_class_peek_parent (gobject_class));
188 * gsf_output_memory_get_bytes :
189 * @mem : the output device.
191 * Returns: The data that has been written to @mem, or %null
194 gsf_output_memory_get_bytes (GsfOutputMemory * mem)
196 g_return_val_if_fail (mem != NULL, NULL);
200 GSF_CLASS (GsfOutputMemory, gsf_output_memory,
201 gsf_output_memory_class_init, gsf_output_memory_init,