mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
[FileTools] More fiddling with Tzip
This commit is contained in:
@@ -397,7 +397,7 @@ namespace SabreTools.Helper
|
||||
}
|
||||
|
||||
// Now try to open the file for reading
|
||||
_zipstream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite);
|
||||
_zipstream = new FileStream(filename, FileMode.Open, FileAccess.Read);
|
||||
int read = _zipstream.Read(new byte[1], 0, 1);
|
||||
if (read != 1)
|
||||
{
|
||||
|
||||
@@ -174,110 +174,109 @@ namespace SabreTools.Helper
|
||||
try
|
||||
{
|
||||
// Open the stream for reading
|
||||
using (BinaryReader br = new BinaryReader(_zipstream))
|
||||
BinaryReader br = new BinaryReader(_zipstream);
|
||||
|
||||
// If the first bytes aren't a central directory header, log and return
|
||||
if (br.ReadUInt32() != Constants.CentralDirectoryHeaderSignature)
|
||||
{
|
||||
// If the first bytes aren't a central directory header, log and return
|
||||
if (br.ReadUInt32() != Constants.CentralDirectoryHeaderSignature)
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
|
||||
// Now read in available information, skipping the unnecessary
|
||||
_versionMadeBy = (ArchiveVersion)br.ReadUInt16();
|
||||
_versionNeeded = (ArchiveVersion)br.ReadUInt16();
|
||||
_generalPurposeBitFlag = (GeneralPurposeBitFlag)br.ReadUInt16();
|
||||
_compressionMethod = (CompressionMethod)br.ReadUInt16();
|
||||
|
||||
// If we have an unsupported compression method, log and return
|
||||
if (_compressionMethod != CompressionMethod.Stored && _compressionMethod != CompressionMethod.Deflated)
|
||||
{
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
|
||||
// Keep reading available information, skipping the unnecessary
|
||||
_lastModFileTime = br.ReadUInt16();
|
||||
_lastModFileDate = br.ReadUInt16();
|
||||
_crc = br.ReadUInt32();
|
||||
_compressedSize = br.ReadUInt32();
|
||||
_uncompressedSize = br.ReadUInt32();
|
||||
|
||||
// Now store some temp vars to find the filename, extra field, and comment
|
||||
ushort fileNameLength = br.ReadUInt16();
|
||||
ushort extraFieldLength = br.ReadUInt16();
|
||||
ushort fileCommentLength = br.ReadUInt16();
|
||||
|
||||
// Even more reading available information, skipping the unnecessary
|
||||
br.ReadUInt16(); // Disk number start
|
||||
_internalFileAttributes = (InternalFileAttributes)br.ReadUInt16();
|
||||
_externalFileAttributes = br.ReadUInt32();
|
||||
_relativeOffset = br.ReadUInt32();
|
||||
byte[] fileNameBytes = br.ReadBytes(fileNameLength);
|
||||
_fileName = ((_generalPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0
|
||||
? Encoding.ASCII.GetString(fileNameBytes)
|
||||
: Encoding.UTF8.GetString(fileNameBytes, 0, fileNameLength));
|
||||
_extraField = br.ReadBytes(extraFieldLength);
|
||||
_comment = br.ReadBytes(fileCommentLength);
|
||||
|
||||
/*
|
||||
Full disclosure: this next section is in GordonJ's work but I honestly
|
||||
have no idea everything that it does. It seems to do something to figure
|
||||
out if it's Zip64, or possibly check for random things but it uses the
|
||||
extra field for this, which I do not fully understand. It's copied in
|
||||
its entirety below in the hope that it makes things better...
|
||||
*/
|
||||
|
||||
int pos = 0;
|
||||
while (extraFieldLength > pos)
|
||||
{
|
||||
ushort type = BitConverter.ToUInt16(_extraField, pos);
|
||||
pos += 2;
|
||||
ushort blockLength = BitConverter.ToUInt16(_extraField, pos);
|
||||
pos += 2;
|
||||
switch (type)
|
||||
{
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
case 0x0001:
|
||||
Zip64 = true;
|
||||
if (UncompressedSize == 0xffffffff)
|
||||
{
|
||||
UncompressedSize = BitConverter.ToUInt64(_extraField, pos);
|
||||
pos += 8;
|
||||
}
|
||||
if (_compressedSize == 0xffffffff)
|
||||
{
|
||||
_compressedSize = BitConverter.ToUInt64(_extraField, pos);
|
||||
pos += 8;
|
||||
}
|
||||
if (_relativeOffset == 0xffffffff)
|
||||
{
|
||||
_relativeOffset = BitConverter.ToUInt64(_extraField, pos);
|
||||
pos += 8;
|
||||
}
|
||||
break;
|
||||
case 0x7075:
|
||||
//byte version = extraField[pos];
|
||||
pos += 1;
|
||||
uint nameCRC32 = BitConverter.ToUInt32(_extraField, pos);
|
||||
pos += 4;
|
||||
|
||||
// Now read in available information, skipping the unnecessary
|
||||
_versionMadeBy = (ArchiveVersion)br.ReadUInt16();
|
||||
_versionNeeded = (ArchiveVersion)br.ReadUInt16();
|
||||
_generalPurposeBitFlag = (GeneralPurposeBitFlag)br.ReadUInt16();
|
||||
_compressionMethod = (CompressionMethod)br.ReadUInt16();
|
||||
CRC32 crcTest = new CRC32();
|
||||
crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength);
|
||||
uint fCRC = (uint)crcTest.Crc32Result;
|
||||
|
||||
// If we have an unsupported compression method, log and return
|
||||
if (_compressionMethod != CompressionMethod.Stored && _compressionMethod != CompressionMethod.Deflated)
|
||||
{
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
if (nameCRC32 != fCRC)
|
||||
{
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
|
||||
// Keep reading available information, skipping the unnecessary
|
||||
_lastModFileTime = br.ReadUInt16();
|
||||
_lastModFileDate = br.ReadUInt16();
|
||||
_crc = br.ReadUInt32();
|
||||
_compressedSize = br.ReadUInt32();
|
||||
_uncompressedSize = br.ReadUInt32();
|
||||
int charLen = blockLength - 5;
|
||||
|
||||
// Now store some temp vars to find the filename, extra field, and comment
|
||||
ushort fileNameLength = br.ReadUInt16();
|
||||
ushort extraFieldLength = br.ReadUInt16();
|
||||
ushort fileCommentLength = br.ReadUInt16();
|
||||
_fileName = Encoding.UTF8.GetString(_extraField, pos, charLen);
|
||||
pos += charLen;
|
||||
|
||||
// Even more reading available information, skipping the unnecessary
|
||||
br.ReadUInt16(); // Disk number start
|
||||
_internalFileAttributes = (InternalFileAttributes)br.ReadUInt16();
|
||||
_externalFileAttributes = br.ReadUInt16();
|
||||
_relativeOffset = br.ReadUInt32();
|
||||
byte[] fileNameBytes = br.ReadBytes(fileNameLength);
|
||||
_fileName = ((_generalPurposeBitFlag & GeneralPurposeBitFlag.LanguageEncodingFlag) == 0
|
||||
? Encoding.ASCII.GetString(fileNameBytes)
|
||||
: Encoding.UTF8.GetString(fileNameBytes, 0, fileNameLength));
|
||||
_extraField = br.ReadBytes(extraFieldLength);
|
||||
_comment = br.ReadBytes(fileCommentLength);
|
||||
|
||||
/*
|
||||
Full disclosure: this next section is in GordonJ's work but I honestly
|
||||
have no idea everything that it does. It seems to do something to figure
|
||||
out if it's Zip64, or possibly check for random things but it uses the
|
||||
extra field for this, which I do not fully understand. It's copied in
|
||||
its entirety below in the hope that it makes things better...
|
||||
*/
|
||||
|
||||
int pos = 0;
|
||||
while (extraFieldLength > pos)
|
||||
{
|
||||
ushort type = BitConverter.ToUInt16(_extraField, pos);
|
||||
pos += 2;
|
||||
ushort blockLength = BitConverter.ToUInt16(_extraField, pos);
|
||||
pos += 2;
|
||||
switch (type)
|
||||
{
|
||||
case 0x0001:
|
||||
Zip64 = true;
|
||||
if (UncompressedSize == 0xffffffff)
|
||||
{
|
||||
UncompressedSize = BitConverter.ToUInt64(_extraField, pos);
|
||||
pos += 8;
|
||||
}
|
||||
if (_compressedSize == 0xffffffff)
|
||||
{
|
||||
_compressedSize = BitConverter.ToUInt64(_extraField, pos);
|
||||
pos += 8;
|
||||
}
|
||||
if (_relativeOffset == 0xffffffff)
|
||||
{
|
||||
_relativeOffset = BitConverter.ToUInt64(_extraField, pos);
|
||||
pos += 8;
|
||||
}
|
||||
break;
|
||||
case 0x7075:
|
||||
//byte version = extraField[pos];
|
||||
pos += 1;
|
||||
uint nameCRC32 = BitConverter.ToUInt32(_extraField, pos);
|
||||
pos += 4;
|
||||
|
||||
CRC32 crcTest = new CRC32();
|
||||
crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength);
|
||||
uint fCRC = (uint)crcTest.Crc32Result;
|
||||
|
||||
if (nameCRC32 != fCRC)
|
||||
{
|
||||
return ZipReturn.ZipCentralDirError;
|
||||
}
|
||||
|
||||
int charLen = blockLength - 5;
|
||||
|
||||
_fileName = Encoding.UTF8.GetString(_extraField, pos, charLen);
|
||||
pos += charLen;
|
||||
|
||||
break;
|
||||
default:
|
||||
pos += blockLength;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pos += blockLength;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ namespace SabreTools.Helper
|
||||
// Set internal variables
|
||||
Stream readStream = null;
|
||||
Stream writeStream = null;
|
||||
ZipFile oldZipFile = new ZipFile();
|
||||
ZipFile zipFile = new ZipFile();
|
||||
ZipReturn zipReturn = ZipReturn.ZipGood;
|
||||
|
||||
@@ -135,27 +136,35 @@ namespace SabreTools.Helper
|
||||
// Open or create the archive
|
||||
if (!File.Exists(archiveFileName))
|
||||
{
|
||||
zipReturn = zipFile.Create(archiveFileName);
|
||||
zipReturn = zipFile.Create(archiveFileName + ".new");
|
||||
}
|
||||
else
|
||||
{
|
||||
zipReturn = zipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, false);
|
||||
zipFile.ZipOpen = ZipOpenType.OpenWrite;
|
||||
}
|
||||
|
||||
if (zipReturn != ZipReturn.ZipGood)
|
||||
{
|
||||
zipFile.Dispose();
|
||||
return success;
|
||||
// Open the old archive for reading
|
||||
oldZipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, false);
|
||||
zipFile.Create(archiveFileName + ".new");
|
||||
|
||||
// Copy over all files to the new archive
|
||||
for (int i = 0; i < oldZipFile.EntriesCount; i++)
|
||||
{
|
||||
// Instantiate the streams
|
||||
CompressionMethod icompressionMethod = CompressionMethod.Stored;
|
||||
ulong istreamSize = 0;
|
||||
oldZipFile.OpenReadStream(i, true, out readStream, out istreamSize, out icompressionMethod);
|
||||
zipFile.OpenWriteStream(true, true, oldZipFile.Filename(i), streamSize, CompressionMethod.Deflated, out writeStream);
|
||||
|
||||
// Copy the input stream to the output
|
||||
byte[] ibuffer = new byte[8 * 1024];
|
||||
int ilen;
|
||||
while ((ilen = readStream.Read(ibuffer, 0, ibuffer.Length)) > 0)
|
||||
{
|
||||
writeStream.Write(ibuffer, 0, ilen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Open the stream for writing
|
||||
// Now open the write stream for the new rom
|
||||
zipReturn = zipFile.OpenWriteStream(false, true, rom.Name, streamSize, CompressionMethod.Deflated, out writeStream);
|
||||
if (zipReturn != ZipReturn.ZipGood)
|
||||
{
|
||||
zipFile.Dispose();
|
||||
return success;
|
||||
}
|
||||
|
||||
// Copy the input stream to the output
|
||||
byte[] buffer = new byte[8 * 1024];
|
||||
@@ -186,8 +195,16 @@ namespace SabreTools.Helper
|
||||
finally
|
||||
{
|
||||
zipFile.Dispose();
|
||||
oldZipFile.Dispose();
|
||||
}
|
||||
|
||||
// If the old file exists, delete it and replace
|
||||
if (File.Exists(archiveFileName))
|
||||
{
|
||||
File.Delete(archiveFileName);
|
||||
}
|
||||
File.Move(archiveFileName + ".new", archiveFileName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user