1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * $Id: gimv_io_mem.c,v 1.2 2004/09/21 08:44:32 makeinu Exp $
22  */
23 
24 #include "gimv_io_mem.h"
25 
26 #include <string.h>
27 
28 
29 static GimvIOStatus   gimv_io_mem_read  (GimvIO      *gio,
30                                          gchar       *buf,
31                                          guint        count,
32                                          guint       *bytes_read);
33 static GimvIOStatus   gimv_io_mem_write (GimvIO      *gio,
34                                          const gchar *buf,
35                                          guint        count,
36                                          guint       *bytes_written);
37 static GimvIOStatus   gimv_io_mem_seek  (GimvIO      *gio,
38                                          glong        offset,
39                                          gint         whence);
40 static GimvIOStatus   gimv_io_mem_tell  (GimvIO      *gio,
41                                          glong       *offset);
42 static void           gimv_io_mem_close (GimvIO      *gio);
43 
44 
45 GimvIOFuncs gimv_io_mem_funcs =
46 {
47    gimv_io_mem_read,
48    gimv_io_mem_write,
49    gimv_io_mem_seek,
50    gimv_io_mem_tell,
51    gimv_io_mem_close,
52 };
53 
54 
55 void
gimv_io_mem_init(GimvIOMem * memio,const gchar * url,const gchar * mode,GimvIOMemMode memio_mode)56 gimv_io_mem_init (GimvIOMem *memio,
57                   const gchar *url,
58                   const gchar *mode,
59                   GimvIOMemMode memio_mode)
60 {
61    GimvIO *gio;
62    gint i;
63 
64    g_return_if_fail (memio);
65 
66    gio  = (GimvIO *) memio;
67 
68    gimv_io_init (gio, url);
69    gio->funcs = &gimv_io_mem_funcs;
70 
71    memio->memio_mode = memio_mode;
72    switch (memio->memio_mode) {
73    case GimvIOMemModeWrap:
74       memio->free_buf = FALSE;
75       memio->buf = NULL;
76       break;
77    case GimvIOMemModeStack:
78    default:
79       memio->buf = g_new0 (gchar *, GIMV_IO_MEM_BLOCKS_STEP);
80       for (i = 0; i < GIMV_IO_MEM_BLOCKS_STEP; i++)
81          ((gchar **)memio->buf)[i] = NULL;
82       break;
83    }
84    memio->bufsize = 0;
85    memio->pos     = 0;
86 }
87 
88 
89 GimvIO *
gimv_io_mem_new(const gchar * url,const gchar * mode,GimvIOMemMode memio_mode)90 gimv_io_mem_new (const gchar *url,
91                  const gchar *mode,
92                  GimvIOMemMode memio_mode)
93 {
94    GimvIOMem *memio;
95 
96    memio = g_new0 (GimvIOMem, 1);
97 
98    gimv_io_mem_init (memio, url, mode, memio_mode);
99 
100    return (GimvIO *) memio;
101 }
102 
103 
104 void
gimv_io_mem_stack(GimvIOMem * memio,const gchar * buf,guint bufsize)105 gimv_io_mem_stack (GimvIOMem *memio,
106                    const gchar *buf, guint bufsize)
107 {
108    gint i, src_blocks, dest_blocks, src_steps, dest_steps;
109    guint bytes, src_size, dest_size, remain, offset;
110    const gchar *src;
111 
112    g_return_if_fail (memio);
113    g_return_if_fail (memio->memio_mode == GimvIOMemModeStack);
114    g_return_if_fail (buf);
115 
116    src_size  = memio->bufsize;
117    dest_size = memio->bufsize + bufsize;
118 
119    src_blocks  = src_size  / GIMV_IO_MEM_BLOCK_SIZE + 1;
120    dest_blocks = dest_size / GIMV_IO_MEM_BLOCK_SIZE + 1;
121 
122    src_steps  = src_blocks  / GIMV_IO_MEM_BLOCKS_STEP + 1;
123    dest_steps = dest_blocks / GIMV_IO_MEM_BLOCKS_STEP + 1;
124 
125    if (dest_steps > src_steps) {
126       memio->buf
127          = g_renew (gchar *, memio->buf,
128                     GIMV_IO_MEM_BLOCKS_STEP * dest_steps);
129       for (i = GIMV_IO_MEM_BLOCKS_STEP * src_steps; i < dest_blocks; i++) {
130          ((gchar **) memio->buf)[i] = NULL;
131       }
132    }
133 
134    remain = bufsize;
135 
136    bytes = MIN (src_blocks * GIMV_IO_MEM_BLOCK_SIZE - src_size, remain);
137    src = buf;
138    if (!((gchar **) memio->buf)[src_blocks - 1])
139       ((gchar **) memio->buf)[src_blocks - 1]
140          = g_new0 (gchar, GIMV_IO_MEM_BLOCK_SIZE);
141    offset = src_size - (src_blocks - 1) * GIMV_IO_MEM_BLOCK_SIZE;
142    memcpy (((gchar **) memio->buf)[src_blocks - 1] + offset, src, bytes);
143    remain -= bytes;
144 
145    for (i = src_blocks; i < dest_blocks; i++) {
146       bytes = MIN (GIMV_IO_MEM_BLOCK_SIZE, remain);
147       src = buf + (bufsize - remain);
148       if (!((gchar **) memio->buf)[i])
149          ((gchar **) memio->buf)[i] = g_new0 (gchar, GIMV_IO_MEM_BLOCK_SIZE);
150       memcpy (((gchar **) memio->buf)[i], src, bytes);
151       remain -= bytes;
152    }
153 
154    memio->bufsize = dest_size;
155 }
156 
157 
158 void
gimv_io_mem_wrap(GimvIOMem * memio,const gchar * buf,guint bufsize,gboolean free)159 gimv_io_mem_wrap (GimvIOMem *memio,
160                   const gchar *buf, guint bufsize,
161                   gboolean free)
162 {
163    g_return_if_fail (memio);
164    g_return_if_fail (memio->memio_mode == GimvIOMemModeWrap);
165    g_return_if_fail (buf);
166 
167    if (memio->buf && memio->free_buf)
168       g_free (memio->buf);
169 
170    memio->free_buf = free;
171    memio->buf = (gpointer) buf;
172    memio->bufsize = bufsize;
173 }
174 
175 
176 static GimvIOStatus
io_mem_read_stack_mode(GimvIOMem * memio,gchar * buf,guint count,guint * bytes_read)177 io_mem_read_stack_mode (GimvIOMem *memio,
178                         gchar     *buf,
179                         guint      count,
180                         guint     *bytes_read)
181 {
182    gchar *dest;
183    guint idx, offset;
184    guint bytes, remain;
185 
186    g_return_val_if_fail (memio->pos <= memio->bufsize, GIMV_IO_STATUS_ERROR);
187    g_return_val_if_fail (bytes_read, GIMV_IO_STATUS_ERROR);
188 
189    remain = count;
190    *bytes_read = 0;
191 
192    idx = memio->pos / GIMV_IO_MEM_BLOCK_SIZE;
193    offset = memio->pos % GIMV_IO_MEM_BLOCK_SIZE;
194    bytes = MIN (remain, GIMV_IO_MEM_BLOCK_SIZE - offset);
195    dest = buf;
196 
197    memcpy (dest, ((gchar **) memio->buf)[idx] + offset, bytes);
198 
199    *bytes_read += bytes;
200    memio->pos += bytes;
201    remain -= bytes;
202    dest += bytes;
203 
204    while (remain > 0) {
205       idx++;
206 
207       bytes = MIN (remain, GIMV_IO_MEM_BLOCK_SIZE);
208 
209       memcpy (dest, ((gchar **) memio->buf)[idx], bytes);
210 
211       *bytes_read += bytes;
212       memio->pos += bytes;
213       remain -= bytes;
214       dest += bytes;
215    }
216 
217    return GIMV_IO_STATUS_NORMAL;
218 }
219 
220 
221 static GimvIOStatus
gimv_io_mem_read(GimvIO * gio,gchar * buf,guint count,guint * bytes_read)222 gimv_io_mem_read (GimvIO *gio,
223                   gchar  *buf,
224                   guint   count,
225                   guint  *bytes_read)
226 {
227    GimvIOMem *memio = (GimvIOMem *) gio;
228 
229    *bytes_read = 0;
230 
231    if (memio->pos == memio->bufsize) {
232       return GIMV_IO_STATUS_NORMAL;
233    } else if (memio->pos > memio->bufsize) {
234       memio->pos = memio->bufsize;
235       return GIMV_IO_STATUS_ERROR;
236    }
237 
238    switch (memio->memio_mode) {
239    case GimvIOMemModeWrap:
240       *bytes_read = MIN (count, ((guint) memio->bufsize - memio->pos));
241       memcpy (buf, ((char *) memio->buf) + memio->pos, *bytes_read);
242       memio->pos += *bytes_read;
243       break;
244    case GimvIOMemModeStack:
245    default:
246       io_mem_read_stack_mode (memio, buf, count, bytes_read);
247       break;
248    }
249 
250    return GIMV_IO_STATUS_NORMAL;
251 }
252 
253 
254 static GimvIOStatus
gimv_io_mem_write(GimvIO * gio,const gchar * buf,guint count,guint * bytes_written)255 gimv_io_mem_write (GimvIO      *gio,
256                    const gchar *buf,
257                    guint        count,
258                    guint       *bytes_written)
259 
260 {
261    /* GimvIOMem *memio = (GimvIOMem *) gio; */
262 
263    /* FIXME */
264 
265    return GIMV_IO_STATUS_ERROR;
266 }
267 
268 
269 static GimvIOStatus
gimv_io_mem_seek(GimvIO * gio,glong offset,gint whence)270 gimv_io_mem_seek  (GimvIO *gio,
271                    glong   offset,
272                    gint    whence)
273 {
274    GimvIOMem *memio = (GimvIOMem *) gio;
275    glong pos;
276 
277    switch (whence) {
278    case SEEK_CUR:
279       pos = memio->pos + offset;
280       break;
281    case SEEK_SET:
282       pos = offset;
283       break;
284    case SEEK_END:
285       pos = memio->bufsize + offset;
286       break;
287    default:
288       return GIMV_IO_STATUS_ERROR;
289       break;
290    }
291 
292    if (pos > memio->bufsize) {
293       memio->pos = memio->bufsize;
294       return GIMV_IO_STATUS_ERROR;
295    } else if (pos < 0) {
296       memio->pos = 0;
297       return GIMV_IO_STATUS_ERROR;
298    }
299 
300    memio->pos = pos;
301 
302    return GIMV_IO_STATUS_NORMAL;
303 }
304 
305 
306 static GimvIOStatus
gimv_io_mem_tell(GimvIO * gio,glong * offset)307 gimv_io_mem_tell  (GimvIO *gio,
308                    glong  *offset)
309 {
310    GimvIOMem *memio = (GimvIOMem *) gio;
311 
312    g_return_val_if_fail (offset, GIMV_IO_STATUS_ERROR);
313 
314    *offset = memio->pos;
315 
316    return GIMV_IO_STATUS_NORMAL;
317 }
318 
319 
320 static void
gimv_io_mem_close(GimvIO * gio)321 gimv_io_mem_close  (GimvIO *gio)
322 {
323    GimvIOMem *memio = (GimvIOMem *) gio;
324    gint block_num, i;
325 
326    switch (memio->memio_mode) {
327    case GimvIOMemModeWrap:
328       if (memio->free_buf)
329          g_free (memio->buf);
330       memio->buf = NULL;
331       break;
332    case GimvIOMemModeStack:
333    default:
334       block_num = memio->bufsize / GIMV_IO_MEM_BLOCK_SIZE + 1;
335       for (i = 0; i < block_num; i++) {
336          g_free (((gchar **)memio->buf)[i]);
337       }
338       g_free (memio->buf);
339       break;
340    }
341 }
342