2007-11-20 10:51:07 -08:00
|
|
|
/**
|
|
|
|
|
* =========================================================================
|
|
|
|
|
* File : archive_zip.cpp
|
|
|
|
|
* Project : 0 A.D.
|
|
|
|
|
* Description : archive backend for Zip files.
|
|
|
|
|
* =========================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// license: GPL; see lib/license.txt
|
|
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
#include "archive_zip.h"
|
|
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
|
|
#include "lib/bits.h"
|
|
|
|
|
#include "lib/byte_order.h"
|
|
|
|
|
#include "lib/fat_time.h"
|
2007-12-01 10:32:43 -08:00
|
|
|
#include "lib/path_util.h"
|
2007-11-20 10:51:07 -08:00
|
|
|
#include "lib/allocators/pool.h"
|
|
|
|
|
#include "lib/sysdep/cpu.h" // cpu_memcpy
|
|
|
|
|
#include "archive.h"
|
|
|
|
|
#include "codec_zlib.h"
|
|
|
|
|
#include "stream.h"
|
2007-12-22 10:15:52 -08:00
|
|
|
#include "lib/file/file.h"
|
2007-12-20 12:14:21 -08:00
|
|
|
#include "lib/file/file_system_posix.h"
|
|
|
|
|
#include "lib/file/io/io.h"
|
2008-01-20 13:52:54 -08:00
|
|
|
#include "lib/file/io/io_align.h" // BLOCK_SIZE
|
2007-12-22 10:15:52 -08:00
|
|
|
#include "lib/file/io/write_buffer.h"
|
2007-12-20 12:14:21 -08:00
|
|
|
|
2007-12-22 10:15:52 -08:00
|
|
|
static FileSystem_Posix s_fileSystemPosix;
|
2007-11-20 10:51:07 -08:00
|
|
|
|
|
|
|
|
|
2007-12-01 10:32:43 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
2007-12-20 12:14:21 -08:00
|
|
|
// Zip archive definitions
|
2007-12-01 10:32:43 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
static const u32 cdfh_magic = FOURCC_LE('P','K','\1','\2');
|
|
|
|
|
static const u32 lfh_magic = FOURCC_LE('P','K','\3','\4');
|
|
|
|
|
static const u32 ecdr_magic = FOURCC_LE('P','K','\5','\6');
|
|
|
|
|
|
2007-12-01 10:32:43 -08:00
|
|
|
enum ZipMethod
|
|
|
|
|
{
|
|
|
|
|
ZIP_METHOD_NONE = 0,
|
|
|
|
|
ZIP_METHOD_DEFLATE = 8
|
|
|
|
|
};
|
|
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
#pragma pack(push, 1)
|
|
|
|
|
|
|
|
|
|
class LFH
|
|
|
|
|
{
|
|
|
|
|
public:
|
2007-12-20 12:14:21 -08:00
|
|
|
void Init(const FileInfo& fileInfo, off_t csize, ZipMethod method, u32 checksum, const VfsPath& pathname_)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2008-01-07 12:03:19 -08:00
|
|
|
const std::string& pathnameString = pathname_.string();
|
2007-12-20 12:14:21 -08:00
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
m_magic = lfh_magic;
|
|
|
|
|
m_x1 = to_le16(0);
|
|
|
|
|
m_flags = to_le16(0);
|
2007-12-20 12:14:21 -08:00
|
|
|
m_method = to_le16(u16_from_larger(method));
|
2007-12-01 10:32:43 -08:00
|
|
|
m_fat_mtime = to_le32(FAT_from_time_t(fileInfo.MTime()));
|
2007-12-20 12:14:21 -08:00
|
|
|
m_crc = to_le32(checksum);
|
|
|
|
|
m_csize = to_le32(u32_from_larger(csize));
|
2007-12-01 10:32:43 -08:00
|
|
|
m_usize = to_le32(u32_from_larger(fileInfo.Size()));
|
2008-01-07 12:03:19 -08:00
|
|
|
m_fn_len = to_le16(u16_from_larger(pathnameString.length()));
|
2007-11-20 10:51:07 -08:00
|
|
|
m_e_len = to_le16(0);
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
cpu_memcpy((char*)this + sizeof(LFH), pathnameString.c_str(), pathnameString.length());
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t Size() const
|
|
|
|
|
{
|
|
|
|
|
debug_assert(m_magic == lfh_magic);
|
2008-01-20 08:53:09 -08:00
|
|
|
size_t size = sizeof(LFH);
|
|
|
|
|
size += read_le16(&m_fn_len);
|
|
|
|
|
size += read_le16(&m_e_len);
|
2007-11-20 10:51:07 -08:00
|
|
|
// note: LFH doesn't have a comment field!
|
2008-01-20 08:53:09 -08:00
|
|
|
return size;
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
u32 m_magic;
|
|
|
|
|
u16 m_x1; // version needed
|
|
|
|
|
u16 m_flags;
|
|
|
|
|
u16 m_method;
|
|
|
|
|
u32 m_fat_mtime; // last modified time (DOS FAT format)
|
|
|
|
|
u32 m_crc;
|
|
|
|
|
u32 m_csize;
|
|
|
|
|
u32 m_usize;
|
|
|
|
|
u16 m_fn_len;
|
|
|
|
|
u16 m_e_len;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cassert(sizeof(LFH) == 30);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CDFH
|
|
|
|
|
{
|
|
|
|
|
public:
|
2007-12-20 12:14:21 -08:00
|
|
|
void Init(const FileInfo& fileInfo, off_t ofs, off_t csize, ZipMethod method, u32 checksum, const VfsPath& pathname_, size_t slack)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2008-01-07 12:03:19 -08:00
|
|
|
const std::string& pathnameString = pathname_.string();
|
2007-11-20 10:51:07 -08:00
|
|
|
m_magic = cdfh_magic;
|
|
|
|
|
m_x1 = to_le32(0);
|
|
|
|
|
m_flags = to_le16(0);
|
2007-12-20 12:14:21 -08:00
|
|
|
m_method = to_le16(u16_from_larger(method));
|
2007-12-01 10:32:43 -08:00
|
|
|
m_fat_mtime = to_le32(FAT_from_time_t(fileInfo.MTime()));
|
2007-12-20 12:14:21 -08:00
|
|
|
m_crc = to_le32(checksum);
|
|
|
|
|
m_csize = to_le32(u32_from_larger(csize));
|
2007-12-01 10:32:43 -08:00
|
|
|
m_usize = to_le32(u32_from_larger(fileInfo.Size()));
|
2008-01-07 12:03:19 -08:00
|
|
|
m_fn_len = to_le16(u16_from_larger(pathnameString.length()));
|
2007-11-20 10:51:07 -08:00
|
|
|
m_e_len = to_le16(0);
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
m_c_len = to_le16(u16_from_larger((size_t)slack));
|
2007-11-20 10:51:07 -08:00
|
|
|
m_x2 = to_le32(0);
|
|
|
|
|
m_x3 = to_le32(0);
|
2007-12-20 12:14:21 -08:00
|
|
|
m_lfh_ofs = to_le32(ofs);
|
2007-11-20 10:51:07 -08:00
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
cpu_memcpy((char*)this + sizeof(CDFH), pathnameString.c_str(), pathnameString.length());
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
void GetPathname(std::string& pathname) const
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
const size_t length = (size_t)read_le16(&m_fn_len);
|
2007-11-20 10:51:07 -08:00
|
|
|
const char* fn = (const char*)this + sizeof(CDFH); // not 0-terminated!
|
2008-01-07 12:03:19 -08:00
|
|
|
pathname = std::string(fn, length);
|
2007-12-20 12:14:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off_t HeaderOffset() const
|
|
|
|
|
{
|
|
|
|
|
return read_le32(&m_lfh_ofs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off_t USize() const
|
|
|
|
|
{
|
|
|
|
|
return (off_t)read_le32(&m_usize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off_t CSize() const
|
|
|
|
|
{
|
|
|
|
|
return (off_t)read_le32(&m_csize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZipMethod Method() const
|
|
|
|
|
{
|
|
|
|
|
return (ZipMethod)read_le16(&m_method);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 Checksum() const
|
|
|
|
|
{
|
|
|
|
|
return read_le32(&m_crc);
|
|
|
|
|
}
|
2007-11-20 10:51:07 -08:00
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
time_t MTime() const
|
|
|
|
|
{
|
|
|
|
|
const u32 fat_mtime = read_le32(&m_fat_mtime);
|
|
|
|
|
return time_t_from_FAT(fat_mtime);
|
|
|
|
|
}
|
2007-12-01 10:32:43 -08:00
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
size_t Size() const
|
|
|
|
|
{
|
|
|
|
|
size_t size = sizeof(CDFH);
|
|
|
|
|
size += read_le16(&m_fn_len);
|
|
|
|
|
size += read_le16(&m_e_len);
|
|
|
|
|
size += read_le16(&m_c_len);
|
|
|
|
|
return size;
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
u32 m_magic;
|
|
|
|
|
u32 m_x1; // versions
|
|
|
|
|
u16 m_flags;
|
|
|
|
|
u16 m_method;
|
|
|
|
|
u32 m_fat_mtime; // last modified time (DOS FAT format)
|
|
|
|
|
u32 m_crc;
|
|
|
|
|
u32 m_csize;
|
|
|
|
|
u32 m_usize;
|
|
|
|
|
u16 m_fn_len;
|
|
|
|
|
u16 m_e_len;
|
|
|
|
|
u16 m_c_len;
|
|
|
|
|
u32 m_x2; // spanning
|
|
|
|
|
u32 m_x3; // attributes
|
|
|
|
|
u32 m_lfh_ofs;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cassert(sizeof(CDFH) == 46);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ECDR
|
|
|
|
|
{
|
|
|
|
|
public:
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
void Init(size_t cd_numEntries, off_t cd_ofs, off_t cd_size)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
|
|
|
|
m_magic = ecdr_magic;
|
2008-06-16 13:33:47 -07:00
|
|
|
m_diskNum = to_le16(0);
|
|
|
|
|
m_cd_diskNum = to_le16(0);
|
|
|
|
|
m_cd_numEntriesOnDisk = to_le16(u16_from_larger(cd_numEntries));
|
|
|
|
|
m_cd_numEntries = m_cd_numEntriesOnDisk;
|
2007-11-20 10:51:07 -08:00
|
|
|
m_cd_size = to_le32(u32_from_larger(cd_size));
|
|
|
|
|
m_cd_ofs = to_le32(u32_from_larger(cd_ofs));
|
|
|
|
|
m_comment_len = to_le16(0);
|
|
|
|
|
}
|
|
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
void Decompose(size_t& cd_numEntries, off_t& cd_ofs, off_t& cd_size) const
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
cd_numEntries = (size_t)read_le16(&m_cd_numEntries);
|
2007-12-20 12:14:21 -08:00
|
|
|
cd_ofs = (off_t)read_le32(&m_cd_ofs);
|
|
|
|
|
cd_size = (off_t)read_le32(&m_cd_size);
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
u32 m_magic;
|
2008-06-16 13:33:47 -07:00
|
|
|
u16 m_diskNum;
|
|
|
|
|
u16 m_cd_diskNum;
|
|
|
|
|
u16 m_cd_numEntriesOnDisk;
|
2007-11-20 10:51:07 -08:00
|
|
|
u16 m_cd_numEntries;
|
|
|
|
|
u32 m_cd_size;
|
|
|
|
|
u32 m_cd_ofs;
|
|
|
|
|
u16 m_comment_len;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cassert(sizeof(ECDR) == 22);
|
|
|
|
|
|
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2007-12-20 12:14:21 -08:00
|
|
|
// ArchiveFile_Zip
|
2007-11-20 10:51:07 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
class ArchiveFile_Zip : public IArchiveFile
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
|
|
|
|
public:
|
2008-07-17 07:23:51 -07:00
|
|
|
ArchiveFile_Zip(const PIFile& file, off_t ofs, off_t csize, u32 checksum, ZipMethod method)
|
2007-12-20 12:14:21 -08:00
|
|
|
: m_file(file), m_ofs(ofs)
|
|
|
|
|
, m_csize(csize), m_checksum(checksum), m_method((u16)method)
|
|
|
|
|
, m_flags(NeedsFixup)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
virtual size_t Precedence() const
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-01 10:32:43 -08:00
|
|
|
return 2u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual char LocationCode() const
|
|
|
|
|
{
|
|
|
|
|
return 'A';
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-17 07:23:51 -07:00
|
|
|
virtual LibError Load(const std::string& UNUSED(name), const shared_ptr<u8>& buf, size_t size) const
|
2007-12-01 10:32:43 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
AdjustOffset();
|
2007-11-20 10:51:07 -08:00
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
PICodec codec;
|
|
|
|
|
switch(m_method)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
|
|
|
|
case ZIP_METHOD_NONE:
|
|
|
|
|
codec = CreateCodec_ZLibNone();
|
|
|
|
|
break;
|
|
|
|
|
case ZIP_METHOD_DEFLATE:
|
|
|
|
|
codec = CreateDecompressor_ZLibDeflate();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
WARN_RETURN(ERR::ARCHIVE_UNKNOWN_METHOD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stream stream(codec);
|
2007-12-20 12:14:21 -08:00
|
|
|
stream.SetOutputBuffer(buf.get(), size);
|
2008-01-07 12:03:19 -08:00
|
|
|
RETURN_ERR(io_Scan(m_file, m_ofs, m_csize, FeedStream, (uintptr_t)&stream));
|
2007-11-20 10:51:07 -08:00
|
|
|
RETURN_ERR(stream.Finish());
|
2007-12-20 12:14:21 -08:00
|
|
|
#if CODEC_COMPUTE_CHECKSUM
|
|
|
|
|
debug_assert(m_checksum == stream.Checksum());
|
|
|
|
|
#endif
|
2007-11-20 10:51:07 -08:00
|
|
|
|
|
|
|
|
return INFO::OK;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
private:
|
|
|
|
|
enum Flags
|
2007-12-01 10:32:43 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
// indicates m_ofs points to a "local file header" instead of
|
|
|
|
|
// the file data. a fixup routine is called when reading the file;
|
|
|
|
|
// it skips past the LFH and clears this flag.
|
|
|
|
|
// this is somewhat of a hack, but vital to archive open performance.
|
|
|
|
|
// without it, we'd have to scan through the entire archive file,
|
|
|
|
|
// which can take *seconds*.
|
|
|
|
|
// (we cannot use the information in CDFH, because its 'extra' field
|
|
|
|
|
// has been observed to differ from that of the LFH)
|
|
|
|
|
// since we read the LFH right before the rest of the file, the block
|
|
|
|
|
// cache will absorb the IO cost.
|
|
|
|
|
NeedsFixup = 1
|
|
|
|
|
};
|
2007-12-01 10:32:43 -08:00
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
struct LFH_Copier
|
|
|
|
|
{
|
|
|
|
|
u8* lfh_dst;
|
|
|
|
|
size_t lfh_bytes_remaining;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// this code grabs an LFH struct from file block(s) that are
|
|
|
|
|
// passed to the callback. usually, one call copies the whole thing,
|
|
|
|
|
// but the LFH may straddle a block boundary.
|
|
|
|
|
//
|
|
|
|
|
// rationale: this allows using temp buffers for zip_fixup_lfh,
|
|
|
|
|
// which avoids involving the file buffer manager and thus
|
|
|
|
|
// avoids cluttering the trace and cache contents.
|
2007-12-20 12:14:21 -08:00
|
|
|
static LibError lfh_copier_cb(uintptr_t cbData, const u8* block, size_t size)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
|
|
|
|
LFH_Copier* p = (LFH_Copier*)cbData;
|
|
|
|
|
|
|
|
|
|
debug_assert(size <= p->lfh_bytes_remaining);
|
|
|
|
|
cpu_memcpy(p->lfh_dst, block, size);
|
|
|
|
|
p->lfh_dst += size;
|
|
|
|
|
p->lfh_bytes_remaining -= size;
|
|
|
|
|
|
|
|
|
|
return INFO::CB_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2007-12-20 12:14:21 -08:00
|
|
|
* fix up m_ofs (adjust it to point to cdata instead of the LFH).
|
2007-11-20 10:51:07 -08:00
|
|
|
*
|
2007-12-20 12:14:21 -08:00
|
|
|
* note: we cannot use CDFH filename and extra field lengths to skip
|
|
|
|
|
* past LFH since that may not mirror CDFH (has happened).
|
2007-11-20 10:51:07 -08:00
|
|
|
*
|
|
|
|
|
* this is called at file-open time instead of while mounting to
|
|
|
|
|
* reduce seeks: since reading the file will typically follow, the
|
|
|
|
|
* block cache entirely absorbs the IO cost.
|
|
|
|
|
**/
|
2007-12-20 12:14:21 -08:00
|
|
|
void AdjustOffset() const
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
if(!(m_flags & NeedsFixup))
|
|
|
|
|
return;
|
|
|
|
|
m_flags &= ~NeedsFixup;
|
|
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
// performance note: this ends up reading one file block, which is
|
|
|
|
|
// only in the block cache if the file starts in the same block as a
|
|
|
|
|
// previously read file (i.e. both are small).
|
|
|
|
|
LFH lfh;
|
|
|
|
|
LFH_Copier params = { (u8*)&lfh, sizeof(LFH) };
|
2008-01-07 12:03:19 -08:00
|
|
|
if(io_Scan(m_file, m_ofs, sizeof(LFH), lfh_copier_cb, (uintptr_t)¶ms) == INFO::OK)
|
2007-12-20 12:14:21 -08:00
|
|
|
m_ofs += (off_t)lfh.Size();
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
PIFile m_file;
|
2007-11-20 10:51:07 -08:00
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
// all relevant LFH/CDFH fields not covered by FileInfo
|
|
|
|
|
mutable off_t m_ofs;
|
|
|
|
|
off_t m_csize;
|
|
|
|
|
u32 m_checksum;
|
|
|
|
|
u16 m_method;
|
|
|
|
|
mutable u16 m_flags;
|
|
|
|
|
};
|
2007-11-20 10:51:07 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2007-12-20 12:14:21 -08:00
|
|
|
// ArchiveReader_Zip
|
2007-11-20 10:51:07 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
class ArchiveReader_Zip : public IArchiveReader
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
public:
|
|
|
|
|
ArchiveReader_Zip(const Path& pathname)
|
2008-01-07 12:03:19 -08:00
|
|
|
: m_file(CreateFile_Posix())
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
m_file->Open(pathname, 'r');
|
|
|
|
|
|
|
|
|
|
FileInfo fileInfo;
|
2007-12-22 10:15:52 -08:00
|
|
|
s_fileSystemPosix.GetFileInfo(pathname, &fileInfo);
|
2007-12-20 12:14:21 -08:00
|
|
|
m_fileSize = fileInfo.Size();
|
2008-07-17 10:00:00 -07:00
|
|
|
const size_t minFileSize = sizeof(LFH)+sizeof(CDFH)+sizeof(ECDR);
|
|
|
|
|
debug_assert(m_fileSize >= off_t(minFileSize));
|
2007-12-20 12:14:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual LibError ReadEntries(ArchiveEntryCallback cb, uintptr_t cbData)
|
|
|
|
|
{
|
|
|
|
|
// locate and read Central Directory
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
off_t cd_ofs; size_t cd_numEntries; off_t cd_size;
|
2008-01-07 12:03:19 -08:00
|
|
|
RETURN_ERR(LocateCentralDirectory(m_file, m_fileSize, cd_ofs, cd_numEntries, cd_size));
|
2007-12-20 12:14:21 -08:00
|
|
|
shared_ptr<u8> buf = io_Allocate(cd_size, cd_ofs);
|
|
|
|
|
u8* cd;
|
2008-01-07 12:03:19 -08:00
|
|
|
RETURN_ERR(io_Read(m_file, cd_ofs, buf.get(), cd_size, cd));
|
2007-12-20 12:14:21 -08:00
|
|
|
|
|
|
|
|
// iterate over Central Directory
|
|
|
|
|
const u8* pos = cd;
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
for(size_t i = 0; i < cd_numEntries; i++)
|
2007-12-20 12:14:21 -08:00
|
|
|
{
|
|
|
|
|
// scan for next CDFH
|
|
|
|
|
CDFH* cdfh = (CDFH*)FindRecord(cd, cd_size, pos, cdfh_magic, sizeof(CDFH));
|
|
|
|
|
if(!cdfh)
|
|
|
|
|
WARN_RETURN(ERR::CORRUPTED);
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
std::string zipPathname;
|
|
|
|
|
cdfh->GetPathname(zipPathname);
|
2008-01-20 08:53:09 -08:00
|
|
|
const size_t lastSlashOfs = zipPathname.find_last_of('/');
|
|
|
|
|
const size_t nameOfs = (lastSlashOfs == std::string::npos)? 0 : lastSlashOfs+1;
|
|
|
|
|
if(nameOfs != zipPathname.length()) // ignore paths ending in slash (i.e. representing a directory)
|
2007-12-20 12:14:21 -08:00
|
|
|
{
|
2008-01-20 08:53:09 -08:00
|
|
|
const std::string name = zipPathname.substr(nameOfs, zipPathname.length()-nameOfs);
|
|
|
|
|
FileInfo fileInfo(name, cdfh->USize(), cdfh->MTime());
|
2007-12-20 12:14:21 -08:00
|
|
|
shared_ptr<ArchiveFile_Zip> archiveFile(new ArchiveFile_Zip(m_file, cdfh->HeaderOffset(), cdfh->CSize(), cdfh->Checksum(), cdfh->Method()));
|
2008-01-07 12:03:19 -08:00
|
|
|
cb(zipPathname, fileInfo, archiveFile, cbData);
|
2007-12-20 12:14:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos += cdfh->Size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return INFO::OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* scan buffer for a Zip file record.
|
|
|
|
|
*
|
|
|
|
|
* @param start position within buffer
|
|
|
|
|
* @param magic signature of record
|
|
|
|
|
* @param recordSize size of record (including signature)
|
|
|
|
|
* @return pointer to record within buffer or 0 if not found.
|
|
|
|
|
**/
|
|
|
|
|
static const u8* FindRecord(const u8* buf, size_t size, const u8* start, u32 magic, size_t recordSize)
|
|
|
|
|
{
|
|
|
|
|
// (don't use <start> as the counter - otherwise we can't tell if
|
|
|
|
|
// scanning within the buffer was necessary.)
|
|
|
|
|
for(const u8* p = start; p <= buf+size-recordSize; p++)
|
|
|
|
|
{
|
|
|
|
|
// found it
|
|
|
|
|
if(*(u32*)p == magic)
|
|
|
|
|
{
|
|
|
|
|
debug_assert(p == start); // otherwise, the archive is a bit broken
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// passed EOF, didn't find it.
|
|
|
|
|
// note: do not warn - this happens in the initial ECDR search at
|
|
|
|
|
// EOF if the archive contains a comment field.
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// search for ECDR in the last <maxScanSize> bytes of the file.
|
|
|
|
|
// if found, fill <dst_ecdr> with a copy of the (little-endian) ECDR and
|
|
|
|
|
// return INFO::OK, otherwise IO error or ERR::CORRUPTED.
|
2008-07-17 07:23:51 -07:00
|
|
|
static LibError ScanForEcdr(const PIFile& file, off_t fileSize, u8* buf, off_t maxScanSize, size_t& cd_numEntries, off_t& cd_ofs, off_t& cd_size)
|
2007-12-20 12:14:21 -08:00
|
|
|
{
|
|
|
|
|
// don't scan more than the entire file
|
|
|
|
|
const off_t scanSize = std::min(maxScanSize, fileSize);
|
|
|
|
|
|
|
|
|
|
// read desired chunk of file into memory
|
|
|
|
|
const off_t ofs = fileSize - scanSize;
|
|
|
|
|
u8* data;
|
|
|
|
|
RETURN_ERR(io_Read(file, ofs, buf, scanSize, data));
|
2007-11-20 10:51:07 -08:00
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
// look for ECDR in buffer
|
|
|
|
|
const ECDR* ecdr = (const ECDR*)FindRecord(data, scanSize, data, ecdr_magic, sizeof(ECDR));
|
|
|
|
|
if(!ecdr)
|
|
|
|
|
return INFO::CANNOT_HANDLE;
|
|
|
|
|
|
|
|
|
|
ecdr->Decompose(cd_numEntries, cd_ofs, cd_size);
|
|
|
|
|
return INFO::OK;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-17 07:23:51 -07:00
|
|
|
static LibError LocateCentralDirectory(const PIFile& file, off_t fileSize, off_t& cd_ofs, size_t& cd_numEntries, off_t& cd_size)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
const off_t maxScanSize = 66000u; // see below
|
2008-01-20 13:52:54 -08:00
|
|
|
shared_ptr<u8> buf = io_Allocate(maxScanSize, BLOCK_SIZE-1); // assume worst-case for alignment
|
2007-12-20 12:14:21 -08:00
|
|
|
|
|
|
|
|
// expected case: ECDR at EOF; no file comment
|
|
|
|
|
LibError ret = ScanForEcdr(file, fileSize, const_cast<u8*>(buf.get()), sizeof(ECDR), cd_numEntries, cd_ofs, cd_size);
|
|
|
|
|
if(ret == INFO::OK)
|
|
|
|
|
return INFO::OK;
|
|
|
|
|
// worst case: ECDR precedes 64 KiB of file comment
|
|
|
|
|
ret = ScanForEcdr(file, fileSize, const_cast<u8*>(buf.get()), maxScanSize, cd_numEntries, cd_ofs, cd_size);
|
|
|
|
|
if(ret == INFO::OK)
|
|
|
|
|
return INFO::OK;
|
|
|
|
|
|
|
|
|
|
// both ECDR scans failed - this is not a valid Zip file.
|
|
|
|
|
RETURN_ERR(io_ReadAligned(file, 0, const_cast<u8*>(buf.get()), sizeof(LFH)));
|
|
|
|
|
// the Zip file has an LFH but lacks an ECDR. this can happen if
|
|
|
|
|
// the user hard-exits while an archive is being written.
|
|
|
|
|
// notes:
|
|
|
|
|
// - return ERR::CORRUPTED so VFS will not include this file.
|
|
|
|
|
// - we could work around this by scanning all LFHs, but won't bother
|
|
|
|
|
// because it'd be slow.
|
|
|
|
|
// - do not warn - the corrupt archive will be deleted on next
|
|
|
|
|
// successful archive builder run anyway.
|
|
|
|
|
if(FindRecord(buf.get(), sizeof(LFH), buf.get(), lfh_magic, sizeof(LFH)))
|
|
|
|
|
return ERR::CORRUPTED; // NOWARN
|
|
|
|
|
// totally bogus
|
|
|
|
|
else
|
|
|
|
|
WARN_RETURN(ERR::ARCHIVE_UNKNOWN_FORMAT);
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
PIFile m_file;
|
2007-12-20 12:14:21 -08:00
|
|
|
off_t m_fileSize;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PIArchiveReader CreateArchiveReader_Zip(const Path& archivePathname)
|
|
|
|
|
{
|
|
|
|
|
return PIArchiveReader(new ArchiveReader_Zip(archivePathname));
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// ArchiveWriter_Zip
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
class ArchiveWriter_Zip : public IArchiveWriter
|
|
|
|
|
{
|
|
|
|
|
public:
|
2007-12-20 12:14:21 -08:00
|
|
|
ArchiveWriter_Zip(const Path& archivePathname)
|
2008-06-16 11:36:36 -07:00
|
|
|
: m_file(CreateFile_Posix()), m_fileSize(0)
|
|
|
|
|
, m_unalignedWriter(new UnalignedWriter(m_file, 0))
|
2007-11-20 10:51:07 -08:00
|
|
|
, m_numEntries(0)
|
|
|
|
|
{
|
2008-01-07 12:03:19 -08:00
|
|
|
THROW_ERR(m_file->Open(archivePathname, 'w'));
|
2007-11-20 10:51:07 -08:00
|
|
|
THROW_ERR(pool_create(&m_cdfhPool, 10*MiB, 0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~ArchiveWriter_Zip()
|
|
|
|
|
{
|
|
|
|
|
// append an ECDR to the CDFH list (this allows us to
|
|
|
|
|
// write out both to the archive file in one burst)
|
2007-12-20 12:14:21 -08:00
|
|
|
const off_t cd_size = (off_t)m_cdfhPool.da.pos;
|
2007-11-20 10:51:07 -08:00
|
|
|
ECDR* ecdr = (ECDR*)pool_alloc(&m_cdfhPool, sizeof(ECDR));
|
2007-12-20 12:14:21 -08:00
|
|
|
if(!ecdr)
|
|
|
|
|
throw std::bad_alloc();
|
2008-06-27 18:09:45 -07:00
|
|
|
const off_t cd_ofs = m_fileSize;
|
2008-06-16 11:36:36 -07:00
|
|
|
ecdr->Init(m_numEntries, cd_ofs, cd_size);
|
2007-12-20 12:14:21 -08:00
|
|
|
|
2008-06-16 11:36:36 -07:00
|
|
|
m_unalignedWriter->Append(m_cdfhPool.da.base, cd_size+sizeof(ECDR));
|
|
|
|
|
m_unalignedWriter->Flush();
|
|
|
|
|
m_unalignedWriter.reset();
|
2007-11-20 10:51:07 -08:00
|
|
|
|
|
|
|
|
(void)pool_destroy(&m_cdfhPool);
|
2008-06-16 11:36:36 -07:00
|
|
|
|
|
|
|
|
const Path pathname = m_file->Pathname();
|
|
|
|
|
m_file.reset();
|
|
|
|
|
|
|
|
|
|
m_fileSize += cd_size+sizeof(ECDR);
|
2008-06-16 13:33:47 -07:00
|
|
|
truncate(pathname.external_directory_string().c_str(), m_fileSize);
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
LibError AddFile(const Path& pathname)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
|
|
|
|
FileInfo fileInfo;
|
2007-12-22 10:15:52 -08:00
|
|
|
RETURN_ERR(s_fileSystemPosix.GetFileInfo(pathname, &fileInfo));
|
2007-11-20 10:51:07 -08:00
|
|
|
const off_t usize = fileInfo.Size();
|
|
|
|
|
// skip 0-length files.
|
|
|
|
|
// rationale: zip.cpp needs to determine whether a CDFH entry is
|
|
|
|
|
// a file or directory (the latter are written by some programs but
|
|
|
|
|
// not needed - they'd only pollute the file table).
|
|
|
|
|
// it looks like checking for usize=csize=0 is the safest way -
|
|
|
|
|
// relying on file attributes (which are system-dependent!) is
|
|
|
|
|
// even less safe.
|
|
|
|
|
// we thus skip 0-length files to avoid confusing them with directories.
|
|
|
|
|
if(!usize)
|
|
|
|
|
return INFO::SKIPPED;
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
PIFile file = CreateFile_Posix();
|
|
|
|
|
RETURN_ERR(file->Open(pathname, 'r'));
|
2007-11-20 10:51:07 -08:00
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
const size_t pathnameLength = pathname.string().length();
|
|
|
|
|
const VfsPath vfsPathname(pathname.string());
|
|
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
// choose method and the corresponding codec
|
2007-12-20 12:14:21 -08:00
|
|
|
ZipMethod method;
|
2007-12-01 10:32:43 -08:00
|
|
|
PICodec codec;
|
2007-11-20 10:51:07 -08:00
|
|
|
if(IsFileTypeIncompressible(pathname))
|
|
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
method = ZIP_METHOD_NONE;
|
2007-11-20 10:51:07 -08:00
|
|
|
codec = CreateCodec_ZLibNone();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-12-20 12:14:21 -08:00
|
|
|
method = ZIP_METHOD_DEFLATE;
|
2007-11-20 10:51:07 -08:00
|
|
|
codec = CreateCompressor_ZLibDeflate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// allocate memory
|
2007-12-20 12:14:21 -08:00
|
|
|
const size_t csizeMax = codec->MaxOutputSize(usize);
|
|
|
|
|
shared_ptr<u8> buf = io_Allocate(sizeof(LFH) + pathnameLength + csizeMax);
|
2007-11-20 10:51:07 -08:00
|
|
|
|
|
|
|
|
// read and compress file contents
|
|
|
|
|
size_t csize; u32 checksum;
|
|
|
|
|
{
|
|
|
|
|
u8* cdata = (u8*)buf.get() + sizeof(LFH) + pathnameLength;
|
|
|
|
|
Stream stream(codec);
|
|
|
|
|
stream.SetOutputBuffer(cdata, csizeMax);
|
2007-12-20 12:14:21 -08:00
|
|
|
RETURN_ERR(io_Scan(file, 0, usize, FeedStream, (uintptr_t)&stream));
|
2007-11-20 10:51:07 -08:00
|
|
|
RETURN_ERR(stream.Finish());
|
|
|
|
|
csize = stream.OutSize();
|
|
|
|
|
checksum = stream.Checksum();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build LFH
|
|
|
|
|
{
|
|
|
|
|
LFH* lfh = (LFH*)buf.get();
|
2007-12-20 12:14:21 -08:00
|
|
|
lfh->Init(fileInfo, (off_t)csize, method, checksum, vfsPathname);
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
2007-12-01 10:32:43 -08:00
|
|
|
// append a CDFH to the central directory (in memory)
|
2007-12-20 12:14:21 -08:00
|
|
|
const off_t ofs = m_fileSize;
|
|
|
|
|
const size_t prev_pos = m_cdfhPool.da.pos; // (required to determine padding size)
|
2007-11-20 10:51:07 -08:00
|
|
|
const size_t cdfhSize = sizeof(CDFH) + pathnameLength;
|
|
|
|
|
CDFH* cdfh = (CDFH*)pool_alloc(&m_cdfhPool, cdfhSize);
|
|
|
|
|
if(!cdfh)
|
|
|
|
|
WARN_RETURN(ERR::NO_MEM);
|
|
|
|
|
const size_t slack = m_cdfhPool.da.pos - prev_pos - cdfhSize;
|
2007-12-20 12:14:21 -08:00
|
|
|
cdfh->Init(fileInfo, ofs, (off_t)csize, method, checksum, vfsPathname, slack);
|
2007-11-20 10:51:07 -08:00
|
|
|
m_numEntries++;
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
// write LFH, pathname and cdata to file
|
|
|
|
|
const size_t packageSize = sizeof(LFH) + pathnameLength + csize;
|
2008-06-16 11:36:36 -07:00
|
|
|
RETURN_ERR(m_unalignedWriter->Append(buf.get(), (off_t)packageSize));
|
2007-12-20 12:14:21 -08:00
|
|
|
m_fileSize += (off_t)packageSize;
|
|
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
return INFO::OK;
|
|
|
|
|
}
|
2008-06-16 11:36:36 -07:00
|
|
|
|
2007-11-20 10:51:07 -08:00
|
|
|
private:
|
2007-12-20 12:14:21 -08:00
|
|
|
static bool IsFileTypeIncompressible(const Path& pathname)
|
|
|
|
|
{
|
|
|
|
|
const char* extension = path_extension(pathname.string().c_str());
|
|
|
|
|
|
|
|
|
|
// file extensions that we don't want to compress
|
|
|
|
|
static const char* incompressibleExtensions[] =
|
|
|
|
|
{
|
|
|
|
|
"zip", "rar",
|
|
|
|
|
"jpg", "jpeg", "png",
|
|
|
|
|
"ogg", "mp3"
|
|
|
|
|
};
|
|
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
for(size_t i = 0; i < ARRAY_SIZE(incompressibleExtensions); i++)
|
2007-12-20 12:14:21 -08:00
|
|
|
{
|
|
|
|
|
if(!strcasecmp(extension, incompressibleExtensions[i]))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-07 12:03:19 -08:00
|
|
|
PIFile m_file;
|
2007-11-20 10:51:07 -08:00
|
|
|
off_t m_fileSize;
|
2008-06-16 11:36:36 -07:00
|
|
|
PUnalignedWriter m_unalignedWriter;
|
2007-11-20 10:51:07 -08:00
|
|
|
|
|
|
|
|
Pool m_cdfhPool;
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 11:48:32 -07:00
|
|
|
size_t m_numEntries;
|
2007-11-20 10:51:07 -08:00
|
|
|
};
|
|
|
|
|
|
2007-12-20 12:14:21 -08:00
|
|
|
PIArchiveWriter CreateArchiveWriter_Zip(const Path& archivePathname)
|
2007-11-20 10:51:07 -08:00
|
|
|
{
|
2007-12-01 10:32:43 -08:00
|
|
|
return PIArchiveWriter(new ArchiveWriter_Zip(archivePathname));
|
2007-11-20 10:51:07 -08:00
|
|
|
}
|