2 * bzip2-method.c - Bzip2 access method for the GNOME Virtual File
5 * Copyright (C) 1999 Free Software Foundation
7 * The Gnome Library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * The Gnome Library 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 GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with the Gnome Library; see the file COPYING.LIB. If not,
19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite
20 * 330, Boston, MA 02111-1307, USA.
22 * Author: Cody Russell <cody@jhu.edu>
27 #include <glib/gmessages.h>
28 #include <glib/gstrfuncs.h>
29 #include <libgnomevfs/gnome-vfs-handle.h>
30 #include <libgnomevfs/gnome-vfs-mime.h>
31 #include <libgnomevfs/gnome-vfs-module.h>
32 #include <libgnomevfs/gnome-vfs-ops.h>
40 #ifdef HAVE_OLDER_BZIP2
41 #define BZ2_bzDecompressInit bzDecompressInit
42 #define BZ2_bzCompressInit bzCompressInit
43 #define BZ2_bzDecompress bzDecompress
44 #define BZ2_bzCompress bzCompress
47 #define BZ_BUFSIZE 5000
49 struct _Bzip2MethodHandle {
51 GnomeVFSHandle *parent_handle;
52 GnomeVFSOpenMode open_mode;
55 GnomeVFSResult last_vfs_result;
61 typedef struct _Bzip2MethodHandle Bzip2MethodHandle;
63 static GnomeVFSResult do_open (GnomeVFSMethod *method,
64 GnomeVFSMethodHandle **method_handle,
66 GnomeVFSOpenMode mode,
67 GnomeVFSContext *context);
69 static GnomeVFSResult do_create (GnomeVFSMethod *method,
70 GnomeVFSMethodHandle **method_handle,
72 GnomeVFSOpenMode mode,
75 GnomeVFSContext *context);
77 static GnomeVFSResult do_close (GnomeVFSMethod *method,
78 GnomeVFSMethodHandle *method_handle,
79 GnomeVFSContext *context);
81 static GnomeVFSResult do_read (GnomeVFSMethod *method,
82 GnomeVFSMethodHandle *method_handle,
84 GnomeVFSFileSize num_bytes,
85 GnomeVFSFileSize *bytes_read,
86 GnomeVFSContext *context);
88 static GnomeVFSResult do_write (GnomeVFSMethod *method,
89 GnomeVFSMethodHandle *method_handle,
91 GnomeVFSFileSize num_bytes,
92 GnomeVFSFileSize *bytes_written,
93 GnomeVFSContext *context);
95 static GnomeVFSResult do_get_file_info (GnomeVFSMethod *method,
97 GnomeVFSFileInfo *file_info,
98 GnomeVFSFileInfoOptions options,
99 GnomeVFSContext *context);
101 static gboolean do_is_local (GnomeVFSMethod *method, const GnomeVFSURI *uri);
103 static GnomeVFSMethod method = {
104 sizeof (GnomeVFSMethod),
112 NULL, /* truncate_handle */
113 NULL, /* open_directory */
114 NULL, /* close_directory */
115 NULL, /* read_directory */
117 NULL, /* get_file_info_from_handle */
119 NULL, /* make_directory */
120 NULL, /* remove_directory */
123 NULL, /* set_file_info */
125 NULL, /* find_directory */
126 NULL /* create_symbolic_link */
129 #define RETURN_IF_FAIL(action) \
131 GnomeVFSResult __tmp_result; \
133 __tmp_result = (action); \
134 if (__tmp_result != GNOME_VFS_OK) \
135 return __tmp_result; \
138 #define VALID_URI(u) ((u)->parent!=NULL&&(((u)->text==NULL)||((u)->text[0]=='\0')||(((u)->text[0]=='/')&&((u)->text[1]=='\0'))))
140 static Bzip2MethodHandle *
141 bzip2_method_handle_new (GnomeVFSHandle *parent_handle,
143 GnomeVFSOpenMode open_mode)
145 Bzip2MethodHandle *new;
147 new = g_new (Bzip2MethodHandle, 1);
149 new->parent_handle = parent_handle;
150 new->uri = gnome_vfs_uri_ref (uri);
151 new->open_mode = open_mode;
159 bzip2_method_handle_destroy (Bzip2MethodHandle *handle)
161 gnome_vfs_uri_unref (handle->uri);
162 g_free (handle->buffer);
167 bzip2_method_handle_init_for_decompress (Bzip2MethodHandle *handle)
169 handle->bzstream.bzalloc = NULL;
170 handle->bzstream.bzfree = NULL;
171 handle->bzstream.opaque = NULL;
173 g_free (handle->buffer);
175 handle->buffer = g_malloc (BZ_BUFSIZE);
176 handle->bzstream.next_in = handle->buffer;
177 handle->bzstream.avail_in = 0;
179 /* FIXME bugzilla.eazel.com 1177: Make small, and possibly verbosity, configurable! */
180 if (BZ2_bzDecompressInit (&handle->bzstream, 0, 0) != BZ_OK) {
181 g_free (handle->buffer);
185 handle->last_bz_result = BZ_OK;
186 handle->last_vfs_result = GNOME_VFS_OK;
192 bzip2_method_handle_init_for_compress (Bzip2MethodHandle *handle) G_GNUC_UNUSED;
195 bzip2_method_handle_init_for_compress (Bzip2MethodHandle *handle)
197 handle->bzstream.bzalloc = NULL;
198 handle->bzstream.bzfree = NULL;
199 handle->bzstream.opaque = NULL;
201 g_free (handle->buffer);
203 handle->buffer = g_malloc (BZ_BUFSIZE);
204 handle->bzstream.next_out = handle->buffer;
205 handle->bzstream.avail_out = BZ_BUFSIZE;
207 /* FIXME bugzilla.eazel.com 1174: We want this to be user configurable. */
208 if (BZ2_bzCompressInit (&handle->bzstream, 3, 0, 30) != BZ_OK) {
209 g_free (handle->buffer);
213 handle->last_bz_result = BZ_OK;
214 handle->last_vfs_result = GNOME_VFS_OK;
219 static GnomeVFSResult
220 result_from_bz_result (gint bz_result)
228 return GNOME_VFS_ERROR_NO_MEMORY;
231 return GNOME_VFS_ERROR_BAD_PARAMETERS;
234 return GNOME_VFS_ERROR_CORRUPTED_DATA;
236 case BZ_UNEXPECTED_EOF:
237 return GNOME_VFS_ERROR_EOF;
239 case BZ_SEQUENCE_ERROR:
240 return GNOME_VFS_ERROR_NOT_PERMITTED;
243 return GNOME_VFS_ERROR_INTERNAL;
247 static GnomeVFSResult
248 flush_write (Bzip2MethodHandle *bzip2_handle)
250 GnomeVFSHandle *parent_handle;
251 GnomeVFSResult result;
256 bzstream = &bzip2_handle->bzstream;
257 bzstream->avail_in = 0;
258 parent_handle = bzip2_handle->parent_handle;
262 while (bz_result == BZ_OK || bz_result == BZ_STREAM_END) {
263 GnomeVFSFileSize bytes_written;
264 GnomeVFSFileSize len;
266 len = BZ_BUFSIZE - bzstream->avail_out;
268 result = gnome_vfs_write (parent_handle, bzip2_handle->buffer,
269 len, &bytes_written);
270 RETURN_IF_FAIL (result);
272 bzstream->next_out = bzip2_handle->buffer;
273 bzstream->avail_out = BZ_BUFSIZE;
278 bz_result = BZ2_bzCompress (bzstream, BZ_FINISH);
280 done = (bzstream->avail_out != 0 || bz_result == BZ_STREAM_END);
283 if (bz_result == BZ_OK || bz_result == BZ_STREAM_END)
286 return result_from_bz_result (bz_result);
290 /* TODO: Check that there is no subpath. */
292 static GnomeVFSResult
293 do_open (GnomeVFSMethod *method,
294 GnomeVFSMethodHandle **method_handle,
296 GnomeVFSOpenMode open_mode,
297 GnomeVFSContext *context)
299 GnomeVFSHandle *parent_handle;
300 GnomeVFSURI *parent_uri;
301 GnomeVFSResult result;
302 Bzip2MethodHandle *bzip2_handle;
304 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
305 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
307 /* Check that the URI is valid. */
308 if (!VALID_URI(uri)) return GNOME_VFS_ERROR_INVALID_URI;
310 if (open_mode & GNOME_VFS_OPEN_WRITE)
311 return GNOME_VFS_ERROR_INVALID_OPEN_MODE;
313 parent_uri = uri->parent;
315 if (open_mode & GNOME_VFS_OPEN_RANDOM)
316 return GNOME_VFS_ERROR_NOT_SUPPORTED;
318 result = gnome_vfs_open_uri (&parent_handle, parent_uri, open_mode);
319 RETURN_IF_FAIL (result);
321 bzip2_handle = bzip2_method_handle_new (parent_handle, uri, open_mode);
323 if (result != GNOME_VFS_OK) {
324 gnome_vfs_close (parent_handle);
325 bzip2_method_handle_destroy (bzip2_handle);
329 if (!bzip2_method_handle_init_for_decompress (bzip2_handle)) {
330 gnome_vfs_close (parent_handle);
331 bzip2_method_handle_destroy (bzip2_handle);
332 return GNOME_VFS_ERROR_INTERNAL;
335 *method_handle = (GnomeVFSMethodHandle *) bzip2_handle;
342 static GnomeVFSResult
343 do_create (GnomeVFSMethod *method,
344 GnomeVFSMethodHandle **method_handle,
346 GnomeVFSOpenMode mode,
349 GnomeVFSContext *context)
351 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
352 _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL);
354 return GNOME_VFS_ERROR_NOT_SUPPORTED;
359 static GnomeVFSResult
360 do_close (GnomeVFSMethod *method,
361 GnomeVFSMethodHandle *method_handle,
362 GnomeVFSContext *context)
364 Bzip2MethodHandle *bzip2_handle;
365 GnomeVFSResult result;
367 _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL);
369 bzip2_handle = (Bzip2MethodHandle *) method_handle;
371 if (bzip2_handle->open_mode & GNOME_VFS_OPEN_WRITE)
372 result = flush_write (bzip2_handle);
374 result = GNOME_VFS_OK;
376 if (result == GNOME_VFS_OK)
377 result = gnome_vfs_close (bzip2_handle->parent_handle);
379 bzip2_method_handle_destroy (bzip2_handle);
386 static GnomeVFSResult
387 fill_buffer (Bzip2MethodHandle *bzip2_handle,
388 GnomeVFSFileSize num_bytes)
390 GnomeVFSResult result;
391 GnomeVFSFileSize count;
394 bzstream = &bzip2_handle->bzstream;
396 if (bzstream->avail_in > 0)
399 result = gnome_vfs_read (bzip2_handle->parent_handle,
400 bzip2_handle->buffer,
404 if (result != GNOME_VFS_OK) {
405 if (bzstream->avail_out == num_bytes)
407 bzip2_handle->last_vfs_result = result;
409 bzstream->next_in = bzip2_handle->buffer;
410 bzstream->avail_in = count;
416 /* TODO: Concatenated Bzip2 file handling. */
418 static GnomeVFSResult
419 do_read (GnomeVFSMethod *method,
420 GnomeVFSMethodHandle *method_handle,
422 GnomeVFSFileSize num_bytes,
423 GnomeVFSFileSize *bytes_read,
424 GnomeVFSContext *context)
426 Bzip2MethodHandle *bzip2_handle;
427 GnomeVFSResult result;
433 bzip2_handle = (Bzip2MethodHandle *) method_handle;
434 bzstream = &bzip2_handle->bzstream;
436 if (bzip2_handle->last_bz_result != BZ_OK) {
437 if (bzip2_handle->last_bz_result == BZ_STREAM_END)
440 return result_from_bz_result (bzip2_handle->last_bz_result);
441 } else if (bzip2_handle->last_vfs_result != GNOME_VFS_OK) {
442 return bzip2_handle->last_vfs_result;
445 bzstream->next_out = buffer;
446 bzstream->avail_out = num_bytes;
448 while (bzstream->avail_out != 0) {
449 result = fill_buffer (bzip2_handle, num_bytes);
450 RETURN_IF_FAIL (result);
452 bz_result = BZ2_bzDecompress (&bzip2_handle->bzstream);
454 if (bzip2_handle->last_bz_result != BZ_OK
455 && bzstream->avail_out == num_bytes) {
456 bzip2_handle->last_bz_result = bz_result;
457 return result_from_bz_result (bzip2_handle->last_bz_result);
460 *bytes_read = num_bytes - bzstream->avail_out;
462 if (bz_result == BZ_STREAM_END) {
463 bzip2_handle->last_bz_result = bz_result;
474 static GnomeVFSResult
475 do_write (GnomeVFSMethod *method,
476 GnomeVFSMethodHandle *method_handle,
477 gconstpointer buffer,
478 GnomeVFSFileSize num_bytes,
479 GnomeVFSFileSize *bytes_written,
480 GnomeVFSContext *context)
482 Bzip2MethodHandle *bzip2_handle;
483 GnomeVFSResult result;
487 bzip2_handle = (Bzip2MethodHandle *) method_handle;
488 bzstream = &bzip2_handle->bzstream;
490 bzstream->next_in = (gpointer) buffer;
491 bzstream->avail_in = num_bytes;
493 result = GNOME_VFS_OK;
495 while (bzstream->avail_in != 0 && result == GNOME_VFS_OK) {
496 if (bzstream->avail_out == 0) {
497 GnomeVFSFileSize written;
499 bzstream->next_out = bzip2_handle->buffer;
500 result = gnome_vfs_write (bzip2_handle->parent_handle,
501 bzip2_handle->buffer,
502 BZ_BUFSIZE, &written);
503 if (result != GNOME_VFS_OK)
506 bzstream->avail_out += written;
509 bz_result = BZ2_bzCompress (bzstream, BZ_RUN);
510 result = result_from_bz_result (bz_result);
513 *bytes_written = num_bytes - bzstream->avail_in;
519 do_is_local (GnomeVFSMethod *method, const GnomeVFSURI *uri)
521 g_return_val_if_fail (uri != NULL, FALSE);
522 return gnome_vfs_uri_is_local (uri->parent);
525 static GnomeVFSResult
526 do_get_file_info (GnomeVFSMethod *method,
528 GnomeVFSFileInfo *file_info,
529 GnomeVFSFileInfoOptions options,
530 GnomeVFSContext *context)
532 GnomeVFSResult result;
534 /* Check that the URI is valid. */
535 if (!VALID_URI(uri)) return GNOME_VFS_ERROR_INVALID_URI;
537 result = gnome_vfs_get_file_info_uri(uri->parent, file_info, options);
539 if(result == GNOME_VFS_OK) {
540 gint namelen = strlen(file_info->name);
542 /* work out the name */
543 /* FIXME bugzilla.eazel.com 2790: handle uppercase */
545 file_info->name[namelen-1] == '2' &&
546 file_info->name[namelen-2] == 'z' &&
547 file_info->name[namelen-3] == 'b' &&
548 file_info->name[namelen-4] == '.')
549 file_info->name[namelen-4] = '\0';
551 /* we can't tell the size without uncompressing it */
552 //file_info->valid_fields &= ~GNOME_VFS_FILE_INFO_FIELDS_SIZE;
554 /* guess the mime type of the file inside */
555 /* FIXME bugzilla.eazel.com 2791: guess mime based on contents */
556 g_free(file_info->mime_type);
557 file_info->mime_type = g_strdup(gnome_vfs_mime_type_from_name(file_info->name));
564 vfs_module_init (const char *method_name, const char *args)
570 vfs_module_shutdown (GnomeVFSMethod *method)