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 /* Do not: (*ui_progress)(acquire_cabinet->uri);
41 * as we currently extract some specific file out of it.
45 acquire_cabinet->offset=offset;
48 void acquire_cabinet_seek_skip(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOffset offset)
50 g_return_if_fail(acquire_cabinet!=NULL);
54 acquire_cabinet->offset+=offset;
57 GnomeVFSFileOffset acquire_cabinet_tell(struct acquire_cabinet *acquire_cabinet)
59 g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
63 return acquire_cabinet->offset;
66 #define ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,pos) (!(acquire_cabinet)->base_cached \
67 || (acquire_cabinet)->base_cached[(pos)/8] & 1<<((pos)&7))
68 #define ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,pos) ((acquire_cabinet)->base_cached[(pos)/8] |= 1<<((pos)&7))
70 GnomeVFSResult acquire_cabinet_read
71 (struct acquire_cabinet *acquire_cabinet,gpointer buffer,GnomeVFSFileSize bytes,GnomeVFSFileSize *bytes_read)
73 GnomeVFSFileOffset offset_start,offset_end,read_behind;
74 GnomeVFSResult errvfsresult;
75 GnomeVFSFileSize bytes_read_now;
77 g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
78 g_return_val_if_fail(buffer!=NULL || bytes==0,GNOME_VFS_ERROR_BAD_PARAMETERS);
80 if ((*ui_progress)(NULL))
81 return GNOME_VFS_ERROR_INTERRUPTED;
83 bytes=MAX(0,MIN(bytes,acquire_cabinet->size-acquire_cabinet->offset));
85 return GNOME_VFS_ERROR_EOF;
89 read_behind =acquire_cabinet->offset+bytes;
91 /* GnomeVFS block transfer: */
92 offset_start=acquire_cabinet->offset;
93 offset_end =acquire_cabinet->offset;
94 while (offset_end<read_behind && !ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,offset_end))
96 if (offset_end>offset_start) {
97 if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_seek(acquire_cabinet->handle,GNOME_VFS_SEEK_START,offset_start)))
99 errvfsresult=gnome_vfs_read(acquire_cabinet->handle,
100 acquire_cabinet->base+offset_start,offset_end-offset_start,&bytes_read_now);
101 if (errvfsresult!=GNOME_VFS_OK)
103 g_assert(bytes_read_now>0);
104 while (bytes_read_now) {
105 ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,offset_start);
111 /* Memory block transfer: */
112 offset_start=acquire_cabinet->offset;
113 offset_end =acquire_cabinet->offset;
114 while (offset_end<read_behind && ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,offset_end))
116 memcpy(buffer,acquire_cabinet->base+offset_start,offset_end-offset_start);
118 *bytes_read+=offset_end-offset_start;
119 buffer+=offset_end-offset_start;
120 bytes-=offset_end-offset_start;
121 acquire_cabinet->offset=offset_end;
127 static void acquire_cabinet_set_uri(struct acquire_cabinet *acquire_cabinet,GnomeVFSURI *uri)
129 GnomeVFSURI *uri_cabextract;
131 g_return_if_fail(acquire_cabinet!=NULL);
132 g_return_if_fail(uri!=NULL);
134 /* FIXME: HACK: Use proper 'cabextract' scheme after it gets implemented.
135 * GnomeVFS will return NULL on gnome_vfs_uri_new() with scheme not available.
137 uri_cabextract=gnome_vfs_uri_new("file://");
138 g_assert(uri_cabextract->parent==NULL);
139 /* Do not: g_assert(!strcmp(uri_cabextract->method_string,"file"));
140 * uri_cabextract->method_string=g_strdup("cabextract");
141 * as it will just strip such anchor. FIXME: Why?
144 uri_cabextract->parent=gnome_vfs_uri_dup(uri);
146 acquire_cabinet->uri=uri_cabextract;
147 acquire_cabinet->filename=gnome_vfs_uri_to_string(acquire_cabinet->uri,GNOME_VFS_URI_HIDE_PASSWORD);
150 struct acquire_cabinet *acquire_cabinet_new_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
152 struct acquire_cabinet *r;
154 g_return_val_if_fail(file_base!=NULL,NULL);
155 g_return_val_if_fail(uri!=NULL,NULL);
158 r->base=(/* de-const */ gpointer)file_base;
163 acquire_cabinet_set_uri(r,uri);
168 struct acquire_cabinet *acquire_cabinet_new_from_handle(GnomeVFSHandle *handle,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri)
170 struct acquire_cabinet *r;
172 g_return_val_if_fail(handle!=NULL,NULL);
173 g_return_val_if_fail(file_info!=NULL,NULL);
174 g_return_val_if_fail(uri!=NULL,NULL);
177 if (MAP_FAILED==(r->base=mmap(
179 CAPTIVE_ROUND_UP64(file_info->size,getpagesize()), /* length */
180 PROT_READ|PROT_WRITE,
181 MAP_ANONYMOUS|MAP_PRIVATE /* flags */
182 |MAP_NORESERVE, /* We will not probably not read the whole cabinet. */
183 -1, /* fd; ignored due to MAP_ANONYMOUS */
184 0))) { /* offset; ignored due to MAP_ANONYMOUS */
186 g_return_val_if_reached(NULL);
188 captive_new0n(r->base_cached,CAPTIVE_ROUND_UP64(file_info->size,8)/8);
191 r->size=file_info->size;
192 acquire_cabinet_set_uri(r,uri);
197 void acquire_cabinet_free(struct acquire_cabinet *acquire_cabinet)
199 g_return_if_fail(acquire_cabinet!=NULL);
201 if (acquire_cabinet->base_cached) {
202 munmap(acquire_cabinet->base,CAPTIVE_ROUND_UP64(acquire_cabinet->size,getpagesize())); /* errors ignored */
203 g_free(acquire_cabinet->base_cached);
205 g_free((/* de-const */ gchar *)acquire_cabinet->filename);
206 gnome_vfs_uri_unref(acquire_cabinet->uri);
207 g_free(acquire_cabinet);
210 static struct file *file_write_fi_assertion;
211 static GByteArray *file_write_bytearray;
213 int file_write(struct file *fi, UBYTE *buf, size_t length)
215 g_return_val_if_fail(fi!=NULL,0);
216 g_return_val_if_fail(buf!=NULL || length==0,0);
218 g_return_val_if_fail(fi==file_write_fi_assertion,0);
219 g_return_val_if_fail(file_write_bytearray!=NULL,0);
221 if ((*ui_progress)(NULL))
224 g_byte_array_append(file_write_bytearray,buf,length);
226 return 1; /* success */
229 void acquire_cabinet_load(struct acquire_cabinet *acquire_cabinet)
231 struct cabinet *basecab;
232 struct file *filelist,*fi;
234 g_return_if_fail(acquire_cabinet!=NULL);
236 if ((*ui_progress)(acquire_cabinet->uri))
239 basecab=find_cabs_in_file(acquire_cabinet);
244 if (basecab->prevcab || basecab->nextcab)
247 filelist=process_files(basecab);
249 for (fi=filelist;fi;fi=fi->next) {
250 gpointer file_buffer;
253 if (!captivemodid_module_length_is_valid(fi->length))
256 uri_fi=gnome_vfs_uri_append_file_name(acquire_cabinet->uri,fi->filename);
257 if ((*ui_progress)(uri_fi)) {
258 gnome_vfs_uri_unref(uri_fi);
262 file_write_fi_assertion=fi;
263 file_write_bytearray=g_byte_array_new();
265 0, /* lower; ignored now */
267 NULL); /* dir; ignored now */
268 if (fi->length!=file_write_bytearray->len) {
269 g_byte_array_free(file_write_bytearray,
270 TRUE); /* free_segment */
271 gnome_vfs_uri_unref(uri_fi);
274 file_buffer=g_byte_array_free(file_write_bytearray,
275 FALSE); /* free_segment */
276 mod_uri_load_file_from_memory(file_buffer,fi->length,uri_fi);
277 gnome_vfs_uri_unref(uri_fi);