1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
<section> <date> 2005 </date>
<H2> zzip/fseeko </H2> zip access for stdio handle
<BLOCKQUOTE>
These routines are fully independent from the traditional zzip
implementation. They assume a readonly seekable stdio handle
representing a complete zip file. The functions show how to
parse the structure, find files and return a decoded bytestream.
</BLOCKQUOTE>
<section>
<H3> stdio disk handle </H3>
<P>
Other than with the <a href="mmapped.html">mmapped</a> alternative
interface there is no need to build special handle for the zip
disk file. The normal stdio file handle (of type <b><code>FILE</code></b>)
serves as the disk access representation. You can open that stdio file
handle any way you want. Note however that the <code>zzipfseeko</code>
routines modify the access state of that file handle, especially the
read position.
</P>
<P>
To get access to a zipped file, you need a zip archive entry known
under the type <code>ZZIP_ENTRY</code>. This is again modelled after
the <code>DIR_ENTRY</code> type in being a representation of a file
name inside the zip central directory. To get a fresh zzip entry, use
<code>zzip_entry_findfirst</code>, to get the next use
<code>zzip_entry_findnext</code>, and do not forget to free the
resource with <code>zzip_entry_free</code>.
</P>
<PRE>
extern ZZIP_ENTRY* zzip_entry_findfirst(FILE* disk);
extern ZZIP_ENTRY* zzip_entry_findnext(ZZIP_ENTRY* entry);
extern int zzip_entry_free(ZZIP_ENTRY* entry);
</PRE>
<P>
These three calls will allow to walk all zip archive members in the
order listed in the zip central directory. To actually implement a
directory lister ("zzipdir"), you need to get the name string of the
zzip entry. This is not just a pointer: the zzip disk entry is not
null terminated actually. Therefore we have a helper function that
will <code>strdup</code> the entry name as a normal C string:
</P>
<PRE>
#include <zzip/fseeko.h>
void _zzip_dir(FILE* disk)
{
for (ZZIP_ENTRY* entry = zzip_findfirst (disk);
entry ; entry = zzip_findnext (entry)) {
char* name = zzip_entry_strdup_name (entry);
puts (name); free (name);
}
}
</PRE>
</section><section>
<H3> find a zipped file </H3>
<P>
The central directory walk can be used to find any file in the
zip archive. The <code>zzipfseeko</code> library however provides
two convenience functions that allow to jump directly to the
zip disk entry of a given name or pattern. You are free to use
the newly allocated <code>ZZIP_ENTRY</code> for later calls on
that handle type. Do not forget to <code>zzip_entry_free</code>
the handle unless the handle is consumed by a routine, e.g.
<code>zzip_entry_findnext</code> to hit the end of directory.
</P>
<PRE>
extern ZZIP_ENTRY* zzip_entry_findfile(FILE* disk, char* filename,
ZZIP_ENTRY* _zzip_restrict entry,
zzip_strcmp_fn_t compare);
extern ZZIP_ENTRY* zzip_entry_findmatch(FILE* disk, char* filespec,
ZZIP_ENTRY* _zzip_restrict entry,
zzip_fnmatch_fn_t compare, int flags);
</PRE>
<P>
In general only the first two arguments are non-null pointing to the
stdio disk handle and the file name to look for. The "entry" argument
is an old value and allows you to walk the zip directory similar to
<code>zzip_entry_findnext</code> but actually leaping forward. The
compare function can be used for alternate match behavior: the default
of <code>strcmp</code> might be changed to <code>strncmp</code> for
a caseless match. The "flags" of the second call are forwarded to the
posix <code>fnmatch</code> which we use as the default function.
</P>
<P>
If you do know a specific filename then you can just use
<code>zzip_entry_findfile</code> and supply the return value to
<code>zzip_entry_fopen</code> with the second argument set to "1"
to tell the function to actually consume whichever entry was given.
That allows you to skip an explicit <code>zzip_entry_free</code>
as it is included in a later <code>zzip_entry_fclose</code>.
</P>
<PRE>
#include <zzip/fseeko.h>
<small>
/* zzipfseeko already exports this convenience function: */</small>
ZZIP_ENTRY_FILE* zzip_entry_ffile(FILE* disk, char* filename) {
return zzip_entry_fopen (zzip_entry_findfile (filename, 0, 0), 1);
}
int _zzip_read(FILE* disk, char* filename, void* buffer, int bytes)
{
ZZIP_ENTRY_FILE* file = zzip_entry_ffile (disk, filename);
if (! file) return -1;
int bytes = zzip_entry_fread (buffer, 1, bytes, file);
zzip_entry_fclose (file);
return bytes;
}
</PRE>
</section><section>
<H3> reading bytes </H3>
<P>
The example has shown already how to read some bytes off the head of
a zipped file. In general the zzipfseeko api is used to replace a few
stdio routines that access a file. For that purpose we provide three
functions that look very similar to the stdio functions of
<code>fopen()</code>, <code>fread()</code> and <code>fclose()</code>.
These work on an active file descriptor of type <code>ZZIP_ENTRY_FILE</code>.
Note that this <code>zzip_entry_fopen()</code> uses <code>ZZIP_ENTRY</code>
argument as returned by the findfile api. To open a new reader handle from
a disk archive and file name you can use the <code>zzip_entry_ffile()</code>
convenience call.
</P>
<PRE>
ZZIP_ENTRY_FILE* zzip_entry_ffile (FILE* disk, char* filename);
ZZIP_ENTRY_FILE* zzip_entry_fopen (ZZIP_ENTRY* entry, int takeover);
zzip_size_t zzip_entry_fread (void* ptr,
zzip_size_t sized, zzip_size_t nmemb,
ZZIP_ENTRY_FILE* file);
int zzip_entry_fclose (ZZIP_ENTRY_FILE* file);
int zzip_entry_feof (ZZIP_ENTRY_FILE* file);
</PRE>
<P>
In all of the examples you need to remember that you provide a single
stdio <code>FILE</code> descriptor which is in reality a virtual
filesystem on its own. Per default filenames are matched case
sensitive also on win32 systems. The findnext function will walk all
files on the zip virtual filesystem table and return a name entry
with the full pathname, i.e. including any directory names to the
root of the zip disk <code>FILE</code>.
</P>
</section><section>
<H3> ZZIP_ENTRY inspection </H3>
<P>
The <code>ZZIP_ENTRY_FILE</code> is a special file descriptor handle
of the <code>zzipfseeko</code> library - but the <code>ZZIP_ENTRY</code>
is not so special. It is actually a bytewise copy of the data inside the
zip disk archive (plus some internal hints appended). While
<code>zzip/fseeko.h</code> will not reveal the structure on its own,
you can include <code>zzip/format.h</code> to get access to the actual
structure content of a <code>ZZIP_ENTRY</code> by (up)casting it to
<br><b><code> struct zzip_disk_entry</code></b>.
</P>
<P>
In reality however it is not a good idea to actually read the bytes
in the <code>zzip_disk_entry</code> structure unless you seriously know
the internals of a zip archive entry. That includes any byteswapping
needed on bigendian platforms. Instead you want to take advantage of
helper macros defined in <code>zzip/fetch.h</code>. These will take
care to convert any struct data member to the host native format.
</P>
<PRE>
extern uint16_t zzip_disk_entry_get_flags( zzip_disk_entry* entry);
extern uint16_t zzip_disk_entry_get_compr( zzip_disk_entry* entry);
extern uint32_t zzip_disk_entry_get_crc32( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_csize( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_usize( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_namlen( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_extras( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_comment( zzip_disk_entry* entry);
extern int zzip_disk_entry_diskstart( zzip_disk_entry* entry);
extern int zzip_disk_entry_filetype( zzip_disk_entry* entry);
extern int zzip_disk_entry_filemode( zzip_disk_entry* entry);
extern zzip_off_t zzip_disk_entry_fileoffset( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_sizeof_tail( zzip_disk_entry* entry);
extern zzip_size_t zzip_disk_entry_sizeto_end( zzip_disk_entry* entry);
extern char* zzip_disk_entry_skipto_end( zzip_disk_entry* entry);
</PRE>
</section></section>
|