mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-22 12:01:13 +00:00
- zip64 handling
This commit is contained in:
parent
6cb035b7b2
commit
4aa04f11ce
3 changed files with 116 additions and 33 deletions
|
@ -115,7 +115,7 @@ bool FCompressedBuffer::Decompress(char *destbuffer)
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
static uint32_t Zip_FindCentralDir(FileReader &fin)
|
static uint32_t Zip_FindCentralDir(FileReader &fin, bool* zip64)
|
||||||
{
|
{
|
||||||
unsigned char buf[BUFREADCOMMENT + 4];
|
unsigned char buf[BUFREADCOMMENT + 4];
|
||||||
uint32_t FileSize;
|
uint32_t FileSize;
|
||||||
|
@ -145,15 +145,18 @@ static uint32_t Zip_FindCentralDir(FileReader &fin)
|
||||||
|
|
||||||
for (i = (int)uReadSize - 3; (i--) > 0;)
|
for (i = (int)uReadSize - 3; (i--) > 0;)
|
||||||
{
|
{
|
||||||
if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6)
|
if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 5 && buf[i+3] == 6 && !*zip64 && uPosFound == 0)
|
||||||
{
|
{
|
||||||
|
*zip64 = false;
|
||||||
uPosFound = uReadPos + i;
|
uPosFound = uReadPos + i;
|
||||||
break;
|
}
|
||||||
|
if (buf[i] == 'P' && buf[i+1] == 'K' && buf[i+2] == 6 && buf[i+3] == 6)
|
||||||
|
{
|
||||||
|
*zip64 = true;
|
||||||
|
uPosFound = uReadPos + i;
|
||||||
|
return uPosFound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uPosFound != 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return uPosFound;
|
return uPosFound;
|
||||||
}
|
}
|
||||||
|
@ -172,8 +175,8 @@ FZipFile::FZipFile(const char * filename, FileReader &file)
|
||||||
|
|
||||||
bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
||||||
{
|
{
|
||||||
uint32_t centraldir = Zip_FindCentralDir(Reader);
|
bool zip64 = false;
|
||||||
FZipEndOfCentralDirectory info;
|
uint32_t centraldir = Zip_FindCentralDir(Reader, &zip64);
|
||||||
int skipped = 0;
|
int skipped = 0;
|
||||||
|
|
||||||
Lumps = NULL;
|
Lumps = NULL;
|
||||||
|
@ -184,6 +187,10 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t dirsize, DirectoryOffset;
|
||||||
|
if (!zip64)
|
||||||
|
{
|
||||||
|
FZipEndOfCentralDirectory info;
|
||||||
// Read the central directory info.
|
// Read the central directory info.
|
||||||
Reader.Seek(centraldir, FileReader::SeekSet);
|
Reader.Seek(centraldir, FileReader::SeekSet);
|
||||||
Reader.Read(&info, sizeof(FZipEndOfCentralDirectory));
|
Reader.Read(&info, sizeof(FZipEndOfCentralDirectory));
|
||||||
|
@ -197,12 +204,33 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
NumLumps = LittleShort(info.NumEntries);
|
NumLumps = LittleShort(info.NumEntries);
|
||||||
|
dirsize = LittleLong(info.DirectorySize);
|
||||||
|
DirectoryOffset = LittleLong(info.DirectoryOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FZipEndOfCentralDirectory64 info;
|
||||||
|
// Read the central directory info.
|
||||||
|
Reader.Seek(centraldir, FileReader::SeekSet);
|
||||||
|
Reader.Read(&info, sizeof(FZipEndOfCentralDirectory64));
|
||||||
|
|
||||||
|
// No multi-disk zips!
|
||||||
|
if (info.NumEntries != info.NumEntriesOnAllDisks ||
|
||||||
|
info.FirstDisk != 0 || info.DiskNumber != 0)
|
||||||
|
{
|
||||||
|
if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumLumps = info.NumEntries;
|
||||||
|
dirsize = info.DirectorySize;
|
||||||
|
DirectoryOffset = info.DirectoryOffset;
|
||||||
|
}
|
||||||
Lumps = new FZipLump[NumLumps];
|
Lumps = new FZipLump[NumLumps];
|
||||||
|
|
||||||
// Load the entire central directory. Too bad that this contains variable length entries...
|
// Load the entire central directory. Too bad that this contains variable length entries...
|
||||||
int dirsize = LittleLong(info.DirectorySize);
|
|
||||||
void *directory = malloc(dirsize);
|
void *directory = malloc(dirsize);
|
||||||
Reader.Seek(LittleLong(info.DirectoryOffset), FileReader::SeekSet);
|
Reader.Seek(DirectoryOffset, FileReader::SeekSet);
|
||||||
Reader.Read(directory, dirsize);
|
Reader.Read(directory, dirsize);
|
||||||
|
|
||||||
char *dirptr = (char*)directory;
|
char *dirptr = (char*)directory;
|
||||||
|
@ -305,7 +333,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
||||||
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
|
if (name0.IsNotEmpty()) name = name.Mid(name0.Len());
|
||||||
|
|
||||||
// skip Directories
|
// skip Directories
|
||||||
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize) == 0))
|
if (name.IsEmpty() || (name.Back() == '/' && LittleLong(zip_fh->UncompressedSize32) == 0))
|
||||||
{
|
{
|
||||||
skipped++;
|
skipped++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -336,8 +364,38 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
||||||
FixPathSeperator(name);
|
FixPathSeperator(name);
|
||||||
name.ToLower();
|
name.ToLower();
|
||||||
|
|
||||||
|
uint32_t UncompressedSize =LittleLong(zip_fh->UncompressedSize32);
|
||||||
|
uint32_t CompressedSize = LittleLong(zip_fh->CompressedSize32);
|
||||||
|
uint64_t LocalHeaderOffset = LittleLong(zip_fh->LocalHeaderOffset32);
|
||||||
|
if (zip_fh->ExtraLength > 0)
|
||||||
|
{
|
||||||
|
uint8_t* rawext = (uint8_t*)zip_fh + sizeof(*zip_fh) + zip_fh->NameLength;
|
||||||
|
uint32_t ExtraLength = LittleLong(zip_fh->ExtraLength);
|
||||||
|
|
||||||
|
while (ExtraLength > 0)
|
||||||
|
{
|
||||||
|
auto zip_64 = (FZipCentralDirectoryInfo64BitExt*)rawext;
|
||||||
|
uint32_t BlockLength = LittleLong(zip_64->Length);
|
||||||
|
rawext += BlockLength + 4;
|
||||||
|
ExtraLength -= BlockLength + 4;
|
||||||
|
if (LittleLong(zip_64->Type) == 1 && BlockLength >= 0x18)
|
||||||
|
{
|
||||||
|
if (zip_64->CompressedSize > 0x7fffffff || zip_64->UncompressedSize > 0x7fffffff)
|
||||||
|
{
|
||||||
|
// The file system is limited to 32 bit file sizes;
|
||||||
|
if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is too large.\n", FileName.GetChars(), name.GetChars());
|
||||||
|
skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UncompressedSize = (uint32_t)zip_64->UncompressedSize;
|
||||||
|
CompressedSize = (uint32_t)zip_64->CompressedSize;
|
||||||
|
LocalHeaderOffset = zip_64->LocalHeaderOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lump_p->LumpNameSetup(name);
|
lump_p->LumpNameSetup(name);
|
||||||
lump_p->LumpSize = LittleLong(zip_fh->UncompressedSize);
|
lump_p->LumpSize = UncompressedSize;
|
||||||
lump_p->Owner = this;
|
lump_p->Owner = this;
|
||||||
// The start of the Reader will be determined the first time it is accessed.
|
// The start of the Reader will be determined the first time it is accessed.
|
||||||
lump_p->Flags = LUMPF_FULLPATH;
|
lump_p->Flags = LUMPF_FULLPATH;
|
||||||
|
@ -346,8 +404,8 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
||||||
if (lump_p->Method != METHOD_STORED) lump_p->Flags |= LUMPF_COMPRESSED;
|
if (lump_p->Method != METHOD_STORED) lump_p->Flags |= LUMPF_COMPRESSED;
|
||||||
lump_p->GPFlags = zip_fh->Flags;
|
lump_p->GPFlags = zip_fh->Flags;
|
||||||
lump_p->CRC32 = zip_fh->CRC32;
|
lump_p->CRC32 = zip_fh->CRC32;
|
||||||
lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize);
|
lump_p->CompressedSize = CompressedSize;
|
||||||
lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset);
|
lump_p->Position = LocalHeaderOffset;
|
||||||
lump_p->CheckEmbedded(filter);
|
lump_p->CheckEmbedded(filter);
|
||||||
|
|
||||||
lump_p++;
|
lump_p++;
|
||||||
|
@ -585,15 +643,15 @@ int AppendCentralDirectory(FileWriter *zip_file, const char *filename, FCompress
|
||||||
dir.ModTime = LittleShort(dostime.first);
|
dir.ModTime = LittleShort(dostime.first);
|
||||||
dir.ModDate = LittleShort(dostime.second);
|
dir.ModDate = LittleShort(dostime.second);
|
||||||
dir.CRC32 = content.mCRC32;
|
dir.CRC32 = content.mCRC32;
|
||||||
dir.CompressedSize = LittleLong(content.mCompressedSize);
|
dir.CompressedSize32 = LittleLong(content.mCompressedSize);
|
||||||
dir.UncompressedSize = LittleLong(content.mSize);
|
dir.UncompressedSize32 = LittleLong(content.mSize);
|
||||||
dir.NameLength = LittleShort((unsigned short)strlen(filename));
|
dir.NameLength = LittleShort((unsigned short)strlen(filename));
|
||||||
dir.ExtraLength = 0;
|
dir.ExtraLength = 0;
|
||||||
dir.CommentLength = 0;
|
dir.CommentLength = 0;
|
||||||
dir.StartingDiskNumber = 0;
|
dir.StartingDiskNumber = 0;
|
||||||
dir.InternalAttributes = 0;
|
dir.InternalAttributes = 0;
|
||||||
dir.ExternalAttributes = 0;
|
dir.ExternalAttributes = 0;
|
||||||
dir.LocalHeaderOffset = LittleLong(position);
|
dir.LocalHeaderOffset32 = LittleLong(position);
|
||||||
|
|
||||||
if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) ||
|
if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) ||
|
||||||
zip_file->Write(filename, strlen(filename)) != strlen(filename))
|
zip_file->Write(filename, strlen(filename)) != strlen(filename))
|
||||||
|
|
|
@ -15,7 +15,7 @@ struct FZipLump : public FResourceLump
|
||||||
uint8_t Method;
|
uint8_t Method;
|
||||||
bool NeedFileStart;
|
bool NeedFileStart;
|
||||||
int CompressedSize;
|
int CompressedSize;
|
||||||
int Position;
|
int64_t Position;
|
||||||
unsigned CRC32;
|
unsigned CRC32;
|
||||||
|
|
||||||
virtual FileReader *GetReader();
|
virtual FileReader *GetReader();
|
||||||
|
|
|
@ -17,6 +17,22 @@ struct FZipEndOfCentralDirectory
|
||||||
uint16_t ZipCommentLength;
|
uint16_t ZipCommentLength;
|
||||||
} FORCE_PACKED;
|
} FORCE_PACKED;
|
||||||
|
|
||||||
|
struct FZipEndOfCentralDirectory64
|
||||||
|
{
|
||||||
|
uint32_t Magic;
|
||||||
|
uint64_t StructSize;
|
||||||
|
uint16_t VersionMadeBy;
|
||||||
|
uint16_t VersionNeeded;
|
||||||
|
uint32_t DiskNumber;
|
||||||
|
uint32_t FirstDisk;
|
||||||
|
uint64_t NumEntries;
|
||||||
|
uint64_t NumEntriesOnAllDisks;
|
||||||
|
uint64_t DirectorySize;
|
||||||
|
uint64_t DirectoryOffset;
|
||||||
|
uint16_t ZipCommentLength;
|
||||||
|
} FORCE_PACKED;
|
||||||
|
|
||||||
|
|
||||||
// FZipFileInfo
|
// FZipFileInfo
|
||||||
struct FZipCentralDirectoryInfo
|
struct FZipCentralDirectoryInfo
|
||||||
{
|
{
|
||||||
|
@ -28,18 +44,28 @@ struct FZipCentralDirectoryInfo
|
||||||
uint16_t ModTime;
|
uint16_t ModTime;
|
||||||
uint16_t ModDate;
|
uint16_t ModDate;
|
||||||
uint32_t CRC32;
|
uint32_t CRC32;
|
||||||
uint32_t CompressedSize;
|
uint32_t CompressedSize32;
|
||||||
uint32_t UncompressedSize;
|
uint32_t UncompressedSize32;
|
||||||
uint16_t NameLength;
|
uint16_t NameLength;
|
||||||
uint16_t ExtraLength;
|
uint16_t ExtraLength;
|
||||||
uint16_t CommentLength;
|
uint16_t CommentLength;
|
||||||
uint16_t StartingDiskNumber;
|
uint16_t StartingDiskNumber;
|
||||||
uint16_t InternalAttributes;
|
uint16_t InternalAttributes;
|
||||||
uint32_t ExternalAttributes;
|
uint32_t ExternalAttributes;
|
||||||
uint32_t LocalHeaderOffset;
|
uint32_t LocalHeaderOffset32;
|
||||||
// file name and other variable length info follows
|
// file name and other variable length info follows
|
||||||
} FORCE_PACKED;
|
} FORCE_PACKED;
|
||||||
|
|
||||||
|
struct FZipCentralDirectoryInfo64BitExt
|
||||||
|
{
|
||||||
|
uint16_t Type;
|
||||||
|
uint16_t Length;
|
||||||
|
uint64_t UncompressedSize;
|
||||||
|
uint64_t CompressedSize;
|
||||||
|
uint64_t LocalHeaderOffset;
|
||||||
|
uint32_t DiskNo;
|
||||||
|
} FORCE_PACKED;
|
||||||
|
|
||||||
// FZipLocalHeader
|
// FZipLocalHeader
|
||||||
struct FZipLocalFileHeader
|
struct FZipLocalFileHeader
|
||||||
{
|
{
|
||||||
|
@ -57,7 +83,6 @@ struct FZipLocalFileHeader
|
||||||
// file name and other variable length info follows
|
// file name and other variable length info follows
|
||||||
} FORCE_PACKED;
|
} FORCE_PACKED;
|
||||||
|
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
#define ZIP_LOCALFILE MAKE_ID('P','K',3,4)
|
#define ZIP_LOCALFILE MAKE_ID('P','K',3,4)
|
||||||
|
|
Loading…
Reference in a new issue