no message
This was SVN commit r55.
This commit is contained in:
parent
393014829e
commit
e2a65abe1b
@ -26,6 +26,7 @@
|
||||
//extern "C" {
|
||||
#endif
|
||||
|
||||
// check if compiler supports C99
|
||||
// avoid ICC warning about undefined macros in #if
|
||||
#undef HAVE_C99
|
||||
#ifdef __STDC_VERSION__
|
||||
@ -57,7 +58,7 @@ type temp = type(CASSERT_##id());\
|
||||
(void)sizeof(temp);\
|
||||
}
|
||||
|
||||
|
||||
#define cassert2(expr, id) struct CASSERT_##id { a : expr; };
|
||||
|
||||
|
||||
|
||||
|
278
source/lib/zip.cpp
Executable file
278
source/lib/zip.cpp
Executable file
@ -0,0 +1,278 @@
|
||||
// ZIP archiving (on top of ZLib)
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "zip.h"
|
||||
#include "posix.h"
|
||||
#include "misc.h"
|
||||
#include "res.h"
|
||||
#include "mem.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "zlib.lib")
|
||||
#endif
|
||||
|
||||
|
||||
// H_ZARCHIVE
|
||||
// information about a Zip archive
|
||||
struct ZARCHIVE
|
||||
{
|
||||
Handle hm; // archive in memory (usually mapped)
|
||||
|
||||
const char* fn; // archive filename
|
||||
|
||||
// file lookup
|
||||
u16 num_files;
|
||||
u16 last_file; // index of last file we found (speed up lookups of sequential files)
|
||||
u32* fn_hashs; // split for more efficient search
|
||||
ZFILE* files;
|
||||
};
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
static const char ecdr_id[] = "PK\5\6"; // End of Central Directory Header identifier
|
||||
static const char cdfh_id[] = "PK\1\2"; // Central File Header identifier
|
||||
static const char lfh_id[] = "PK\3\4"; // Local File Header identifier
|
||||
|
||||
|
||||
|
||||
|
||||
static void zarchive_dtor(void* p)
|
||||
{
|
||||
ZARCHIVE* za = (ZARCHIVE*)p;
|
||||
|
||||
mem_free(za->hm);
|
||||
mem_free((void*)za->fn);
|
||||
mem_free(za->fn_hashs); // both fn_hashs[] and files[]
|
||||
}
|
||||
|
||||
|
||||
// open and return a handle to the zip archive indicated by <fn>
|
||||
Handle zip_open(const char* const fn)
|
||||
{
|
||||
const u8* ecdr; // declared here to avoid goto scope problems
|
||||
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
|
||||
// allocate a handle
|
||||
ZARCHIVE* za;
|
||||
Handle ha = h_alloc(fn_hash, H_ZARCHIVE, zarchive_dtor, (void**)&za);
|
||||
// .. failed
|
||||
if(!ha)
|
||||
return 0;
|
||||
// .. archive already loaded
|
||||
if(za->hm)
|
||||
return ha;
|
||||
|
||||
// map the Zip file
|
||||
const u8* zfile;
|
||||
size_t size;
|
||||
Handle hm = vfs_load(fn, (void*&)zfile, size);
|
||||
if(!hm)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
// find end of central dir record
|
||||
// by scanning last 66000 bytes of file for ecdr_id magic
|
||||
// (zip comment <= 65535 bytes, sizeof(ECDR) = 22, add some for safety)
|
||||
// if the zip file is < 66000 bytes, scan the whole file
|
||||
|
||||
size_t bytes_left = min(size, 66000);
|
||||
ecdr = zfile + size - bytes_left;
|
||||
|
||||
while(bytes_left-3 > 0)
|
||||
{
|
||||
if(*(u32*)ecdr == *(u32*)&ecdr_id)
|
||||
goto found_ecdr;
|
||||
|
||||
// check next 4 bytes (non aligned!!)
|
||||
ecdr++;
|
||||
bytes_left--;
|
||||
}
|
||||
|
||||
// reached EOF and still haven't found the ECDR identifier
|
||||
}
|
||||
|
||||
fail:
|
||||
h_free(ha, H_ZARCHIVE);
|
||||
mem_free(hm);
|
||||
return 0;
|
||||
|
||||
found_ecdr:
|
||||
{
|
||||
// read ECDR
|
||||
const u16 num_files = read_le16(ecdr+10);
|
||||
const u32 cd_ofs = read_le32(ecdr+16);
|
||||
|
||||
// memory for fn_hash and File arrays
|
||||
void* mem = mem_alloc(num_files * (sizeof(u32) + sizeof(ZFILE)), 4*KB, MEM_HEAP);
|
||||
if(!mem)
|
||||
goto fail;
|
||||
|
||||
za->hm = hm;
|
||||
za->fn_hashs = (u32*)mem;
|
||||
za->files = (ZFILE*)((u8*)mem + sizeof(u32)*num_files);
|
||||
za->last_file = 0;
|
||||
|
||||
za->fn = (const char*)mem_alloc(strlen(fn)+1);
|
||||
strcpy((char*)za->fn, fn);
|
||||
|
||||
// cache file list for faster lookups
|
||||
// currently linear search, comparing filename hash.
|
||||
// TODO: if too slow, use hash table.
|
||||
const u8* cdfh = zfile+cd_ofs;
|
||||
u32* hs = za->fn_hashs;
|
||||
ZFILE* f = za->files;
|
||||
uint i;
|
||||
for(i = 0; i < num_files; i++)
|
||||
{
|
||||
// read CDFH
|
||||
if(*(u32*)cdfh != *(u32*)cdfh_id)
|
||||
continue;
|
||||
const u32 csize = read_le32(cdfh+20);
|
||||
const u32 ucsize = read_le32(cdfh+24);
|
||||
const u16 fn_len = read_le16(cdfh+28);
|
||||
const u16 e_len = read_le16(cdfh+30);
|
||||
const u16 c_len = read_le16(cdfh+32);
|
||||
const u32 lfh_ofs = read_le32(cdfh+42);
|
||||
const u8 method = cdfh[10];
|
||||
|
||||
if(method & ~8) // neither deflated nor stored
|
||||
continue;
|
||||
|
||||
// read LFH
|
||||
const u8* const lfh = zfile + lfh_ofs;
|
||||
if(*(u32*)lfh != *(u32*)lfh_id)
|
||||
continue;
|
||||
const u16 lfh_fn_len = read_le16(lfh+26);
|
||||
const u16 lfh_e_len = read_le16(lfh+28);
|
||||
const char* lfh_fn = (const char*)lfh+30;
|
||||
|
||||
*hs++ = fnv_hash(lfh_fn, lfh_fn_len);
|
||||
f->ofs = lfh_ofs + 30 + lfh_fn_len + lfh_e_len;
|
||||
f->csize = csize;
|
||||
f->ucsize = ucsize;
|
||||
f++;
|
||||
|
||||
(int&)cdfh += 46 + fn_len + e_len + c_len;
|
||||
}
|
||||
|
||||
za->num_files = i;
|
||||
}
|
||||
|
||||
return ha;
|
||||
}
|
||||
|
||||
|
||||
int zip_close(Handle ha)
|
||||
{
|
||||
return h_free(ha, H_ZARCHIVE);
|
||||
}
|
||||
|
||||
|
||||
ZFILE* zip_lookup(Handle ha, const char* fn)
|
||||
{
|
||||
ZARCHIVE* za = (ZARCHIVE*)h_user_data(ha, H_ZARCHIVE);
|
||||
if(!za)
|
||||
return 0;
|
||||
|
||||
// find its File descriptor
|
||||
const u32 fn_hash = fnv_hash(fn, strlen(fn));
|
||||
uint i = za->last_file+1;
|
||||
if(i >= za->num_files || za->fn_hashs[i] != fn_hash)
|
||||
{
|
||||
for(i = 0; i < za->num_files; i++)
|
||||
if(za->fn_hashs[i] == fn_hash)
|
||||
break;
|
||||
if(i == za->num_files)
|
||||
return 0;
|
||||
|
||||
za->last_file = i;
|
||||
}
|
||||
|
||||
return &za->files[i];
|
||||
}
|
||||
|
||||
|
||||
int zip_stat(Handle ha, const char* fn, struct stat* s)
|
||||
{
|
||||
ZFILE* zf = zip_lookup(ha, fn);
|
||||
if(!zf)
|
||||
return -1;
|
||||
|
||||
s->st_size = zf->ucsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int zip_archive_info(Handle ha, char* fn, Handle* hm)
|
||||
{
|
||||
ZARCHIVE* za = (ZARCHIVE*)h_user_data(ha, H_ZARCHIVE);
|
||||
if(!za)
|
||||
return -1;
|
||||
|
||||
if(fn)
|
||||
strcpy(fn, za->fn);
|
||||
|
||||
if(hm)
|
||||
*hm = za->hm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void* zip_inflate_start(void* out, size_t out_size)
|
||||
{
|
||||
z_stream* stream = (z_stream*)mem_alloc(sizeof(z_stream), 4, MEM_POOL);
|
||||
memset(stream, 0, sizeof(stream));
|
||||
|
||||
if(inflateInit2(stream, -MAX_WBITS) != Z_OK)
|
||||
return 0;
|
||||
// -MAX_WBITS indicates no zlib header present
|
||||
|
||||
stream->next_out = (Bytef*)out;
|
||||
stream->avail_out = out_size;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
int zip_inflate_process(void* ctx, void* p, size_t size)
|
||||
{
|
||||
z_stream* stream = (z_stream*)ctx;
|
||||
|
||||
stream->next_in = (Bytef*)p;
|
||||
stream->avail_in = size;
|
||||
return inflate(stream, 0);
|
||||
}
|
||||
|
||||
|
||||
int zip_inflate_end(void* ctx)
|
||||
{
|
||||
z_stream* stream = (z_stream*)ctx;
|
||||
inflateEnd(stream);
|
||||
|
||||
// didn't read everything
|
||||
if(stream->avail_out || stream->avail_in)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
48
source/lib/zip.h
Executable file
48
source/lib/zip.h
Executable file
@ -0,0 +1,48 @@
|
||||
// ZIP archiving (on top of ZLib)
|
||||
//
|
||||
// Copyright (c) 2003 Jan Wassenberg
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// Contact info:
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
#ifndef __ZIP_H__
|
||||
#define __ZIP_H__
|
||||
|
||||
#include "res.h"
|
||||
|
||||
// open and return a handle to the zip archive indicated by <fn>
|
||||
extern Handle zip_open(const char* fn);
|
||||
extern int zip_close(Handle ha);
|
||||
|
||||
extern int zip_archive_info(Handle ha, char* fn, Handle* hm);
|
||||
|
||||
extern int zip_stat(Handle ha, const char* fn, struct stat* s);
|
||||
|
||||
|
||||
struct ZFILE
|
||||
{
|
||||
size_t ofs;
|
||||
size_t csize;
|
||||
size_t ucsize;
|
||||
};
|
||||
|
||||
// return information about file <fn> in archive <ha> (i.e. 'open' it)
|
||||
extern ZFILE* zip_lookup(Handle ha, const char* fn);
|
||||
|
||||
extern void* zip_inflate_start(void* out, size_t out_size);
|
||||
extern int zip_inflate_process(void* ctx, void* p, size_t size);
|
||||
extern int zip_inflate_end(void* ctx);
|
||||
|
||||
|
||||
#endif // #ifndef __ZIP_H__
|
Loading…
Reference in New Issue
Block a user