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
|
// 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);
|
int read = _zipstream.Read(new byte[1], 0, 1);
|
||||||
if (read != 1)
|
if (read != 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -174,110 +174,109 @@ namespace SabreTools.Helper
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Open the stream for reading
|
// 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
|
return ZipReturn.ZipCentralDirError;
|
||||||
if (br.ReadUInt32() != Constants.CentralDirectoryHeaderSignature)
|
}
|
||||||
|
|
||||||
|
// 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
|
CRC32 crcTest = new CRC32();
|
||||||
_versionMadeBy = (ArchiveVersion)br.ReadUInt16();
|
crcTest.SlurpBlock(fileNameBytes, 0, fileNameLength);
|
||||||
_versionNeeded = (ArchiveVersion)br.ReadUInt16();
|
uint fCRC = (uint)crcTest.Crc32Result;
|
||||||
_generalPurposeBitFlag = (GeneralPurposeBitFlag)br.ReadUInt16();
|
|
||||||
_compressionMethod = (CompressionMethod)br.ReadUInt16();
|
|
||||||
|
|
||||||
// If we have an unsupported compression method, log and return
|
if (nameCRC32 != fCRC)
|
||||||
if (_compressionMethod != CompressionMethod.Stored && _compressionMethod != CompressionMethod.Deflated)
|
{
|
||||||
{
|
return ZipReturn.ZipCentralDirError;
|
||||||
return ZipReturn.ZipCentralDirError;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Keep reading available information, skipping the unnecessary
|
int charLen = blockLength - 5;
|
||||||
_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
|
_fileName = Encoding.UTF8.GetString(_extraField, pos, charLen);
|
||||||
ushort fileNameLength = br.ReadUInt16();
|
pos += charLen;
|
||||||
ushort extraFieldLength = br.ReadUInt16();
|
|
||||||
ushort fileCommentLength = br.ReadUInt16();
|
|
||||||
|
|
||||||
// Even more reading available information, skipping the unnecessary
|
break;
|
||||||
br.ReadUInt16(); // Disk number start
|
default:
|
||||||
_internalFileAttributes = (InternalFileAttributes)br.ReadUInt16();
|
pos += blockLength;
|
||||||
_externalFileAttributes = br.ReadUInt16();
|
break;
|
||||||
_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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ namespace SabreTools.Helper
|
|||||||
// Set internal variables
|
// Set internal variables
|
||||||
Stream readStream = null;
|
Stream readStream = null;
|
||||||
Stream writeStream = null;
|
Stream writeStream = null;
|
||||||
|
ZipFile oldZipFile = new ZipFile();
|
||||||
ZipFile zipFile = new ZipFile();
|
ZipFile zipFile = new ZipFile();
|
||||||
ZipReturn zipReturn = ZipReturn.ZipGood;
|
ZipReturn zipReturn = ZipReturn.ZipGood;
|
||||||
|
|
||||||
@@ -135,27 +136,35 @@ namespace SabreTools.Helper
|
|||||||
// Open or create the archive
|
// Open or create the archive
|
||||||
if (!File.Exists(archiveFileName))
|
if (!File.Exists(archiveFileName))
|
||||||
{
|
{
|
||||||
zipReturn = zipFile.Create(archiveFileName);
|
zipReturn = zipFile.Create(archiveFileName + ".new");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zipReturn = zipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, false);
|
// Open the old archive for reading
|
||||||
zipFile.ZipOpen = ZipOpenType.OpenWrite;
|
oldZipFile.Open(archiveFileName, new FileInfo(archiveFileName).LastWriteTime.Ticks, false);
|
||||||
}
|
zipFile.Create(archiveFileName + ".new");
|
||||||
|
|
||||||
if (zipReturn != ZipReturn.ZipGood)
|
// Copy over all files to the new archive
|
||||||
{
|
for (int i = 0; i < oldZipFile.EntriesCount; i++)
|
||||||
zipFile.Dispose();
|
{
|
||||||
return success;
|
// 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);
|
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
|
// Copy the input stream to the output
|
||||||
byte[] buffer = new byte[8 * 1024];
|
byte[] buffer = new byte[8 * 1024];
|
||||||
@@ -186,8 +195,16 @@ namespace SabreTools.Helper
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
zipFile.Dispose();
|
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;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user