ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / libgnomevfs / gnome-vfs-mime-sniff-buffer.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4  * gnome-vfs-mime-sniff-buffer.c
5  * Utility for implementing gnome_vfs_mime_type_from_magic, and other
6  * mime-type sniffing calls.
7  *
8  * Copyright (C) 2000 Eazel, Inc.
9  * All rights reserved.
10  *
11  * This file is part of the Gnome Library.
12  *
13  * The Gnome Library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public License as
15  * published by the Free Software Foundation; either version 2 of the
16  * License, or (at your option) any later version.
17  *
18  * The Gnome Library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public
24  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
25  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26  * Boston, MA 02111-1307, USA.
27  */
28
29 #include <config.h>
30 #include "gnome-vfs-mime-sniff-buffer.h"
31
32 #include "gnome-vfs-handle.h"
33 #include "gnome-vfs-mime-sniff-buffer-private.h"
34 #include "gnome-vfs-ops.h"
35 #include <string.h>
36
37 static GnomeVFSResult
38 handle_seek_glue (gpointer context, GnomeVFSSeekPosition whence, 
39         GnomeVFSFileOffset offset)
40 {
41         GnomeVFSHandle *handle = (GnomeVFSHandle *)context;
42         return gnome_vfs_seek (handle, whence, offset);
43 }
44
45 static GnomeVFSResult
46 handle_read_glue (gpointer context, gpointer buffer, 
47         GnomeVFSFileSize bytes, GnomeVFSFileSize *bytes_read)
48 {
49         GnomeVFSHandle *handle = (GnomeVFSHandle *)context;
50         return gnome_vfs_read (handle, buffer, bytes, bytes_read);
51 }
52
53 GnomeVFSMimeSniffBuffer *
54 _gnome_vfs_mime_sniff_buffer_new_from_handle (GnomeVFSHandle *file)
55 {
56         GnomeVFSMimeSniffBuffer *result;
57
58         result = g_new0 (GnomeVFSMimeSniffBuffer, 1);
59         result->owning = TRUE;
60         result->context = file;
61         result->seek = handle_seek_glue;
62         result->read = handle_read_glue;
63
64         return result;
65 }
66
67 GnomeVFSMimeSniffBuffer *
68 _gnome_vfs_mime_sniff_buffer_new_generic (GnomeVFSSniffBufferSeekCall seek_callback, 
69                                          GnomeVFSSniffBufferReadCall read_callback,
70                                          gpointer context)
71 {
72         GnomeVFSMimeSniffBuffer * result;
73         
74         result = g_new0 (GnomeVFSMimeSniffBuffer, 1);
75
76         result->owning = TRUE;
77         result->seek = seek_callback;
78         result->read = read_callback;
79         result->context = context;
80
81         return result;
82 }
83
84 GnomeVFSMimeSniffBuffer * 
85 _gnome_vfs_mime_sniff_buffer_new_from_memory (const guchar *buffer, 
86                                              gssize buffer_length)
87 {
88         GnomeVFSMimeSniffBuffer *result;
89
90         result = g_new0 (GnomeVFSMimeSniffBuffer, 1);
91         result->owning = TRUE;
92         result->buffer = g_malloc (buffer_length);
93         result->buffer_length = buffer_length;
94         memcpy (result->buffer, buffer, buffer_length);
95         result->read_whole_file = TRUE;
96
97         return result;
98 }
99
100 GnomeVFSMimeSniffBuffer *
101 gnome_vfs_mime_sniff_buffer_new_from_existing_data (const guchar *buffer, 
102                                                     gssize buffer_length)
103 {
104         GnomeVFSMimeSniffBuffer *result;
105
106         result = g_new0 (GnomeVFSMimeSniffBuffer, 1);
107         result->owning = FALSE;
108         result->buffer = (guchar *)buffer;
109         result->buffer_length = buffer_length;
110         result->read_whole_file = TRUE;
111
112         return result;
113 }
114
115 void
116 gnome_vfs_mime_sniff_buffer_free (GnomeVFSMimeSniffBuffer *buffer)
117 {
118         if (buffer->owning)
119                 g_free (buffer->buffer);
120         g_free (buffer);
121 }
122
123 enum {
124         GNOME_VFS_SNIFF_BUFFER_INITIAL_CHUNK = 256,
125         GNOME_VFS_SNIFF_BUFFER_MIN_CHUNK = 128
126 };
127
128 GnomeVFSResult
129 _gnome_vfs_mime_sniff_buffer_get (GnomeVFSMimeSniffBuffer *buffer,
130                                  gssize size)
131 {
132         GnomeVFSResult result;
133         GnomeVFSFileSize bytes_to_read, bytes_read;
134
135         /* check to see if we already have enough data */
136         if (buffer->buffer_length >= size) {
137                 return GNOME_VFS_OK;
138         }
139
140         /* if we've read the whole file, don't try to read any more */
141         if (buffer->read_whole_file) {
142                 return GNOME_VFS_ERROR_EOF;
143         }
144
145         /* figure out how much to read */
146         bytes_to_read = size - buffer->buffer_length;
147
148         /* don't bother to read less than this */
149         if (bytes_to_read < GNOME_VFS_SNIFF_BUFFER_MIN_CHUNK) {
150                 bytes_to_read = GNOME_VFS_SNIFF_BUFFER_MIN_CHUNK;
151         }
152
153         /* make room in buffer for new data */
154         buffer->buffer = g_realloc (buffer->buffer,
155                                     buffer->buffer_length + bytes_to_read);
156
157         /* read in more data */
158         result = (* buffer->read) (buffer->context, 
159                                    buffer->buffer + buffer->buffer_length,
160                                    bytes_to_read,
161                                    &bytes_read);
162         if (result == GNOME_VFS_ERROR_EOF) {
163                 /* only happens with 0-byte files, due to other logic */
164                 buffer->read_whole_file = TRUE;
165         }
166         if (result != GNOME_VFS_OK) {
167                 return result;
168         }
169         if (bytes_read < bytes_to_read) {
170                 buffer->read_whole_file = TRUE;
171         }
172         buffer->buffer_length += bytes_read;
173
174         /* check to see if we have enough data */
175         if (buffer->buffer_length >= size) {
176                 return GNOME_VFS_OK;
177         }
178
179         /* not enough data */
180         return GNOME_VFS_ERROR_EOF;
181 }