2 * cabextract interface for acquiration installation utility
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "cabinet.h" /* self */
23 #include <glib/gmessages.h>
24 #include <libgnomevfs/gnome-vfs-file-size.h>
25 #include <libgnomevfs/gnome-vfs-ops.h>
26 #include "cabextract/cabextract.h"
27 #include "captivemodid.h"
28 #include "moduriload.h"
33 #include <captive/macros.h>
36 void acquire_cabinet_seek(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOffset offset)
38 g_return_if_fail(acquire_cabinet!=NULL);
40 (*ui_search_is_aborted)();
42 acquire_cabinet->offset=offset;
45 void acquire_cabinet_seek_skip(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOffset offset)
47 g_return_if_fail(acquire_cabinet!=NULL);
49 (*ui_search_is_aborted)();
51 acquire_cabinet->offset+=offset;
54 GnomeVFSFileOffset acquire_cabinet_tell(struct acquire_cabinet *acquire_cabinet)
56 g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
58 (*ui_search_is_aborted)();
60 return acquire_cabinet->offset;
63 #define ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,pos) (!(acquire_cabinet)->base_cached \
64 || (acquire_cabinet)->base_cached[(pos)/8] & 1<<((pos)&7))
65 #define ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,pos) ((acquire_cabinet)->base_cached[(pos)/8] |= 1<<((pos)&7))
67 GnomeVFSResult acquire_cabinet_read
68 (struct acquire_cabinet *acquire_cabinet,gpointer buffer,GnomeVFSFileSize bytes,GnomeVFSFileSize *bytes_read)
70 GnomeVFSFileOffset offset_start,offset_end,read_behind;
71 GnomeVFSResult errvfsresult;
72 GnomeVFSFileSize bytes_read_now;
74 g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
75 g_return_val_if_fail(buffer!=NULL || bytes==0,GNOME_VFS_ERROR_BAD_PARAMETERS);
77 if ((*ui_search_is_aborted)())
78 return GNOME_VFS_ERROR_INTERRUPTED;
80 bytes=MAX(0,MIN(bytes,acquire_cabinet->size-acquire_cabinet->offset));
82 return GNOME_VFS_ERROR_EOF;
86 read_behind =acquire_cabinet->offset+bytes;
88 /* GnomeVFS block transfer: */
89 offset_start=acquire_cabinet->offset;
90 offset_end =acquire_cabinet->offset;
91 while (offset_end<read_behind && !ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,offset_end))
93 if (offset_end>offset_start) {
94 if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_seek(acquire_cabinet->handle,GNOME_VFS_SEEK_START,offset_start)))
96 errvfsresult=gnome_vfs_read(acquire_cabinet->handle,
97 acquire_cabinet->base+offset_start,offset_end-offset_start,&bytes_read_now);
98 if (errvfsresult!=GNOME_VFS_OK)
100 g_assert(bytes_read_now>0);
101 while (bytes_read_now) {
102 ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,offset_start);
108 /* Memory block transfer: */
109 offset_start=acquire_cabinet->offset;
110 offset_end =acquire_cabinet->offset;
111 while (offset_end<read_behind && ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,offset_end))
113 memcpy(buffer,acquire_cabinet->base+offset_start,offset_end-offset_start);
115 *bytes_read+=offset_end-offset_start;
116 buffer+=offset_end-offset_start;
117 bytes-=offset_end-offset_start;
118 acquire_cabinet->offset=offset_end;
124 static void acquire_cabinet_set_uri(struct acquire_cabinet *acquire_cabinet,GnomeVFSURI *uri)
126 GnomeVFSURI *uri_cabextract;
128 g_return_if_fail(acquire_cabinet!=NULL);
129 g_return_if_fail(uri!=NULL);
131 /* FIXME: HACK: Use proper 'cabextract' scheme after it gets implemented.
132 * GnomeVFS will return NULL on gnome_vfs_uri_new() with scheme not available.
134 uri_cabextract=gnome_vfs_uri_new("file://");
135 g_assert(uri_cabextract->parent==NULL);
136 /* Do not: g_assert(!strcmp(uri_cabextract->method_string,"file"));
137 * uri_cabextract->method_string=g_strdup("cabextract");
138 * as it will just strip such anchor. FIXME: Why?
141 uri_cabextract->parent=gnome_vfs_uri_dup(uri);
143 acquire_cabinet->uri=uri_cabextract;
144 acquire_cabinet->filename=gnome_vfs_uri_to_string(acquire_cabinet->uri,GNOME_VFS_URI_HIDE_PASSWORD);
147 struct acquire_cabinet *acquire_cabinet_new_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
149 struct acquire_cabinet *r;
151 g_return_val_if_fail(file_base!=NULL,NULL);
152 g_return_val_if_fail(uri!=NULL,NULL);
155 r->base=(/* de-const */ gpointer)file_base;
160 acquire_cabinet_set_uri(r,uri);
165 struct acquire_cabinet *acquire_cabinet_new_from_handle(GnomeVFSHandle *handle,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri)
167 struct acquire_cabinet *r;
169 g_return_val_if_fail(handle!=NULL,NULL);
170 g_return_val_if_fail(file_info!=NULL,NULL);
171 g_return_val_if_fail(uri!=NULL,NULL);
174 if (MAP_FAILED==(r->base=mmap(
175 NULL,CAPTIVE_ROUND_UP64(file_info->size,getpagesize()),PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0))) {
177 g_return_val_if_reached(NULL);
179 captive_new0n(r->base_cached,CAPTIVE_ROUND_UP64(file_info->size,8)/8);
182 r->size=file_info->size;
183 acquire_cabinet_set_uri(r,uri);
188 void acquire_cabinet_free(struct acquire_cabinet *acquire_cabinet)
190 g_return_if_fail(acquire_cabinet!=NULL);
192 if (acquire_cabinet->base_cached) {
193 munmap(acquire_cabinet->base,CAPTIVE_ROUND_UP64(acquire_cabinet->size,getpagesize())); /* errors ignored */
194 g_free(acquire_cabinet->base_cached);
196 g_free((/* de-const */ gchar *)acquire_cabinet->filename);
197 gnome_vfs_uri_unref(acquire_cabinet->uri);
198 g_free(acquire_cabinet);
201 static struct file *file_write_fi_assertion;
202 static GByteArray *file_write_bytearray;
204 int file_write(struct file *fi, UBYTE *buf, size_t length)
206 g_return_val_if_fail(fi!=NULL,0);
207 g_return_val_if_fail(buf!=NULL || length==0,0);
209 g_return_val_if_fail(fi==file_write_fi_assertion,0);
210 g_return_val_if_fail(file_write_bytearray!=NULL,0);
212 if ((*ui_search_is_aborted)())
215 g_byte_array_append(file_write_bytearray,buf,length);
217 return 1; /* success */
220 void acquire_cabinet_load(struct acquire_cabinet *acquire_cabinet)
222 struct cabinet *basecab;
223 struct file *filelist,*fi;
225 g_return_if_fail(acquire_cabinet!=NULL);
227 if ((*ui_search_is_aborted)())
230 basecab=find_cabs_in_file(acquire_cabinet);
235 if (basecab->prevcab || basecab->nextcab)
238 filelist=process_files(basecab);
240 for (fi=filelist;fi;fi=fi->next) {
241 gpointer file_buffer;
244 if (!captivemodid_module_length_is_valid(fi->length))
247 if ((*ui_search_is_aborted)())
250 file_write_fi_assertion=fi;
251 file_write_bytearray=g_byte_array_new();
253 0, /* lower; ignored now */
255 NULL); /* dir; ignored now */
256 if (fi->length!=file_write_bytearray->len) {
257 g_byte_array_free(file_write_bytearray,
258 TRUE); /* free_segment */
261 file_buffer=g_byte_array_free(file_write_bytearray,
262 FALSE); /* free_segment */
263 uri_fi=gnome_vfs_uri_append_file_name(acquire_cabinet->uri,fi->filename);
264 mod_uri_load_file_from_memory(file_buffer,fi->length,uri_fi);
265 gnome_vfs_uri_unref(uri_fi);