Files
Webcam/include/modules/io_zip/io_zip.cpp

212 lines
6.5 KiB
C++

/*------------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "io_zip/io_zip.h"
#include "unzip.h"
#include "filesystem/io_handle_segment.h"
#include "filesystem/filesystem.h"
#include "platform.h"
#include "log/log.h"
using namespace GS::IO;
//------------------------------------------------------------------------------
// I/O wrapper for unzip (allows archive access from various I/O systems).
static voidpf Zip_open_file_func(voidpf opaque, const char *filename, int mode)
{
__LOG__ << "ZipOpenFileFunc(); filename: " << filename << ", mode: " << mode << ".\n";
if (mode & ZLIB_FILEFUNC_MODE_READ)
return GS::Platform::Get().io->Open(filename);
if (mode & ZLIB_FILEFUNC_MODE_WRITE)
return GS::Platform::Get().io->Open(filename, ModeWrite);
return NULL;
}
static uLong Zip_read_file_func(voidpf opaque, voidpf stream, void *buf, uLong size)
{ return ((Handle *)stream)->Read(buf, size); }
static uLong Zip_write_file_func(voidpf opaque, voidpf stream, const void *buf, uLong size)
{ return ((Handle *)stream)->Write(buf, size); }
static int Zip_close_file_func(voidpf opaque, voidpf stream)
{
__LOG__ << "ZipCloseFileFunc();\n";
delete ((Handle *)stream);
return UNZ_OK;
}
static int Zip_testerror_file_func(voidpf opaque, voidpf stream)
{ return UNZ_OK; }
static long Zip_tell_file_func(voidpf opaque, voidpf stream)
{ return ((Handle *)stream)->Tell(); }
static long Zip_seek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin)
{
static Base::SeekRef ref[] = { Base::SeekStart, Base::SeekCurrent, Base::SeekEnd };
return ((Handle *)stream)->Seek(offset, ref[origin]) == -1 ? -1 : 0;
}
//------------------------------------------------------------------------------
static zlib_filefunc_def Zip_filefunc =
{ Zip_open_file_func, Zip_read_file_func, Zip_write_file_func, Zip_tell_file_func, Zip_seek_file_func, Zip_close_file_func, Zip_testerror_file_func, 0 };
//------------------------------------------------------------------------------
bool Zip::SetArchive(const char *uri, const char *pass)
{
if (zfile)
unzClose(zfile);
zfile = NULL;
if (!uri)
return true;
__LOG_H__ << "Zip::SetArchive() connect to archive '" << uri << "', password: " << (pass ? pass : "(empty)") << ".\n";
password = pass;
return uri ? (zfile = unzOpen2(uri, &Zip_filefunc)) != NULL : false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Zip::GetCaps() const
{ return CanRead | CanSeek| IsCaseSensitive; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Handle *Zip::Open(const char *path, Mode mode)
{
if (!zfile)
__ERR__(__LOG_E__ << "Cannot open file with no archive support.\n", NULL)
if (mode == ModeWrite)
return NULL; // unsupported
/*
Query the memory file system so that multiple accesses to the same
compressed file will share a single uncompressed memory buffer.
*/
bool is_memory_handle = false;
Handle *h = memfs->Open(path, mode);
if (!h)
if (unzLocateFile(zfile, path, 1) == UNZ_OK) // case-sensitive
{
// Get file info.
unz_file_info info;
unzGetCurrentFileInfo(zfile, &info, 0, 0, 0, 0, 0, 0);
if (info.compression_method == 0)
{
unzOpenCurrentFile(zfile);
size_t offset = (size_t)unzGetCurrentFileZStreamPos64(zfile);
unzCloseCurrentFile(zfile);
__LOG__ << "Mapping zip segment to '" << path << "' @" << int(offset) << "\n";
Handle *zh = (Handle *)unzGetFileStream(zfile);
h = new HandleSegment(zh, offset, info.uncompressed_size);
}
else
{
__LOG__ << "Mapping unzipped '" << path << "' to memory...\n";
// Load the whole file into memory.
Array <char> data(info.uncompressed_size, Alloc::Filesystem);
if (data.GetSize() != info.uncompressed_size)
__ERR__(__LOG_E__ << "Failed to allocate decompression space for '" << path << "'.\n", NULL)
int r = password.IsEmpty() ? unzOpenCurrentFile(zfile) : unzOpenCurrentFilePassword(zfile, password);
if (r != UNZ_OK)
__ERR__(__LOG_E__ << "Failed to open file '" << path << "'.\n", NULL)
if (unzReadCurrentFile(zfile, (voidp)data.c_ptr(), info.uncompressed_size) != (int)info.uncompressed_size)
__ERR__(__LOG_E__ << "Failed to read file '" << path << "'.\n", NULL)
unzCloseCurrentFile(zfile);
// Write to the support I/O memory filesystem.
AutoPtr <Handle> wh(memfs->Open(path, ModeWrite));
if (wh.IsValid())
wh->Write(data.c_ptr(), data.GetSize());
// Open memory based uncompressed file.
h = memfs->Open(path, mode);
is_memory_handle = true;
}
}
if (h)
if (ZipHandle *z = new ZipHandle(this))
{
// Wrap memory I/O handle.
if (is_memory_handle)
{
// Increase refcount for this file.
Pair <String, int> *p = refc_map.Get(path);
if (!p)
p = refc_map.Add(path, 0);
++p->value;
z->p = p;
}
z->h = h;
return z;
}
return NULL;
}
void Zip::Close(Handle *h)
{
if (ZipHandle *z = (ZipHandle *)h)
{
if (z->p)
{
// If refcount for this entry reaches 0, drop it from the support I/O.
if (--z->p->value == 0)
{
memfs->Delete(z->p->key);
refc_map.Delete(z->p);
}
z->p = NULL;
}
z->h = NULL;
}
}
bool Zip::Delete(const char *uri)
{ return false; }
size_t Zip::Seek(Handle *h, ptrdiff_t offset, SeekRef ref)
{
if (ZipHandle *z = (ZipHandle *)h)
return z->h->Seek(offset, ref);
return (size_t)-1;
}
size_t Zip::Tell(Handle *h)
{
if (ZipHandle *z = (ZipHandle *)h)
return z->h->Tell();
return (size_t)-1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t Zip::Read(Handle *h, void *b, size_t size)
{
if (ZipHandle *z = (ZipHandle *)h)
return z->h->Read(b, size);
return 0;
}
size_t Zip::Write(Handle *h, const void *b, size_t size)
{ return 0; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Zip::Zip(const char *uri, const char *password)
{
zfile = NULL;
memfs = new Memory;
SetArchive(uri, password);
}
Zip::~Zip()
{ SetArchive(NULL, NULL); }
//------------------------------------------------------------------------------