mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
* Start removing mixed usages
* Check for directories before opening
* Fix writing
* Kinda fix rebuild
* One more try
* Better internal handling
* Slighty fix a couple more things
* Update RVWorld Compress code to db7d750bba
* Fix build
Co-authored-by: Matt Nadareski <mnadareski@mparticle.com>
293 lines
10 KiB
C#
293 lines
10 KiB
C#
using System.IO;
|
|
using System.Text;
|
|
using Compress.SevenZip.Compress.LZMA;
|
|
using Compress.SevenZip.Structure;
|
|
using Compress.Utils;
|
|
using Zstandard.Net;
|
|
|
|
namespace Compress.SevenZip
|
|
{
|
|
public partial class SevenZ
|
|
{
|
|
private void Create7ZStructure()
|
|
{
|
|
int fileCount = _localFiles.Count;
|
|
|
|
//FileInfo
|
|
_header.FileInfo = new Structure.FileInfo
|
|
{
|
|
Names = new string[fileCount]
|
|
};
|
|
|
|
ulong emptyStreamCount = 0;
|
|
ulong emptyFileCount = 0;
|
|
for (int i = 0; i < fileCount; i++)
|
|
{
|
|
_header.FileInfo.Names[i] = _localFiles[i].FileName;
|
|
|
|
if (_localFiles[i].UncompressedSize != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!_localFiles[i].IsDirectory)
|
|
{
|
|
emptyFileCount += 1;
|
|
}
|
|
|
|
emptyStreamCount += 1;
|
|
}
|
|
ulong outFileCount = (ulong)_localFiles.Count - emptyStreamCount;
|
|
|
|
_header.FileInfo.EmptyStreamFlags = null;
|
|
_header.FileInfo.EmptyFileFlags = null;
|
|
_header.FileInfo.Attributes = null;
|
|
|
|
if (emptyStreamCount > 0)
|
|
{
|
|
if (emptyStreamCount != emptyFileCount) //then we found directories and need to set the attributes
|
|
{
|
|
_header.FileInfo.Attributes = new uint[fileCount];
|
|
}
|
|
|
|
if (emptyFileCount > 0)
|
|
{
|
|
_header.FileInfo.EmptyFileFlags = new bool[emptyStreamCount];
|
|
}
|
|
|
|
emptyStreamCount = 0;
|
|
_header.FileInfo.EmptyStreamFlags = new bool[fileCount];
|
|
for (int i = 0; i < fileCount; i++)
|
|
{
|
|
if (_localFiles[i].UncompressedSize != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (_localFiles[i].IsDirectory)
|
|
{
|
|
if (_header.FileInfo.Attributes != null)
|
|
_header.FileInfo.Attributes[i] = 0x10; // set attributes to directory
|
|
}
|
|
else
|
|
{
|
|
if (_header.FileInfo.EmptyFileFlags != null)
|
|
_header.FileInfo.EmptyFileFlags[emptyStreamCount] = true; // set empty file flag
|
|
}
|
|
|
|
_header.FileInfo.EmptyStreamFlags[i] = true;
|
|
emptyStreamCount += 1;
|
|
}
|
|
}
|
|
|
|
|
|
//StreamsInfo
|
|
_header.StreamsInfo = new StreamsInfo { PackPosition = 0 };
|
|
|
|
//StreamsInfo.PackedStreamsInfo
|
|
if (_compressed)
|
|
{
|
|
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[1];
|
|
_header.StreamsInfo.PackedStreams[0] = new PackedStreamInfo { PackedSize = _packStreamSize };
|
|
}
|
|
else
|
|
{
|
|
_header.StreamsInfo.PackedStreams = new PackedStreamInfo[outFileCount];
|
|
int fileIndex = 0;
|
|
for (int i = 0; i < fileCount; i++)
|
|
{
|
|
if (_localFiles[i].UncompressedSize == 0)
|
|
{
|
|
continue;
|
|
}
|
|
_header.StreamsInfo.PackedStreams[fileIndex++] = new PackedStreamInfo { PackedSize = _localFiles[i].UncompressedSize };
|
|
}
|
|
}
|
|
//StreamsInfo.PackedStreamsInfo, no CRC or StreamPosition required
|
|
|
|
if (_compressed)
|
|
{
|
|
//StreamsInfo.Folders
|
|
_header.StreamsInfo.Folders = new Folder[1];
|
|
|
|
//StreamsInfo.Folders.Coder
|
|
// flags 0x23
|
|
|
|
Folder folder = new Folder
|
|
{
|
|
BindPairs = null,
|
|
Coders = new[] {
|
|
new Coder {
|
|
Method = new byte[] { 3, 1, 1 },
|
|
NumInStreams = 1,
|
|
NumOutStreams = 1,
|
|
Properties = _codeMSbytes
|
|
}
|
|
},
|
|
PackedStreamIndices = new[] { (ulong)0 },
|
|
UnpackedStreamSizes = new[] { _unpackedStreamSize },
|
|
UnpackedStreamInfo = new UnpackedStreamInfo[outFileCount],
|
|
UnpackCRC = null
|
|
};
|
|
|
|
switch (_lzmaStream)
|
|
{
|
|
case LzmaStream _:
|
|
folder.Coders[0].Method = new byte[] { 3, 1, 1 };
|
|
break;
|
|
case ZstandardStream _:
|
|
folder.Coders[0].Method = new byte[] { 4, 247, 17, 1 };
|
|
break;
|
|
}
|
|
|
|
|
|
int fileIndex = 0;
|
|
for (int i = 0; i < fileCount; i++)
|
|
{
|
|
if (_localFiles[i].UncompressedSize == 0)
|
|
{
|
|
continue;
|
|
}
|
|
UnpackedStreamInfo unpackedStreamInfo = new UnpackedStreamInfo
|
|
{
|
|
UnpackedSize = _localFiles[i].UncompressedSize,
|
|
Crc = Util.bytestouint(_localFiles[i].CRC)
|
|
};
|
|
folder.UnpackedStreamInfo[fileIndex++] = unpackedStreamInfo;
|
|
}
|
|
_header.StreamsInfo.Folders[0] = folder;
|
|
}
|
|
else
|
|
{
|
|
_header.StreamsInfo.Folders = new Folder[outFileCount];
|
|
int fileIndex = 0;
|
|
for (int i = 0; i < fileCount; i++)
|
|
{
|
|
if (_localFiles[i].UncompressedSize == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Folder folder = new Folder
|
|
{
|
|
BindPairs = null,
|
|
Coders = new[] {
|
|
new Coder {
|
|
Method = new byte[] {0},
|
|
NumInStreams = 1,
|
|
NumOutStreams = 1,
|
|
Properties = null
|
|
}
|
|
},
|
|
PackedStreamIndices = new[] { (ulong)i },
|
|
UnpackedStreamSizes = new[] { _localFiles[i].UncompressedSize },
|
|
UnpackCRC = null,
|
|
|
|
UnpackedStreamInfo = new[] {
|
|
new UnpackedStreamInfo {
|
|
UnpackedSize = _localFiles[i].UncompressedSize,
|
|
Crc = Util.bytestouint(_localFiles[i].CRC)
|
|
}
|
|
}
|
|
};
|
|
|
|
_header.StreamsInfo.Folders[fileIndex++] = folder;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void CloseWriting7Zip()
|
|
{
|
|
if (_compressed)
|
|
{
|
|
_lzmaStream.Close();
|
|
}
|
|
|
|
_packStreamSize = (ulong)_zipFs.Position - _packStreamStart;
|
|
|
|
Create7ZStructure();
|
|
|
|
byte[] newHeaderByte;
|
|
using (Stream headerMem = new MemoryStream())
|
|
{
|
|
using (BinaryWriter headerBw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
|
{
|
|
_header.WriteHeader(headerBw);
|
|
|
|
newHeaderByte = new byte[headerMem.Length];
|
|
headerMem.Position = 0;
|
|
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
|
}
|
|
}
|
|
|
|
uint mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
|
|
|
#region Header Compression
|
|
long packedHeaderPos = _zipFs.Position;
|
|
LzmaEncoderProperties ep = new LzmaEncoderProperties(true, GetDictionarySizeFromUncompressedSize((ulong)newHeaderByte.Length), 64);
|
|
LzmaStream lzs = new LzmaStream(ep, false, _zipFs);
|
|
byte[] lzmaStreamProperties = lzs.Properties;
|
|
lzs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
|
lzs.Close();
|
|
|
|
StreamsInfo streamsInfo = new StreamsInfo
|
|
{
|
|
PackPosition = (ulong)(packedHeaderPos - _baseOffset),
|
|
Folders = new[] {
|
|
new Folder {
|
|
BindPairs = new BindPair[0],
|
|
Coders = new [] {
|
|
new Coder {
|
|
Method = new byte[] { 3, 1, 1 },
|
|
NumInStreams = 1,
|
|
NumOutStreams = 1,
|
|
Properties = lzmaStreamProperties
|
|
}
|
|
},
|
|
UnpackedStreamSizes = new[] {(ulong) newHeaderByte.Length},
|
|
UnpackCRC = mainHeaderCRC
|
|
}
|
|
},
|
|
PackedStreams = new[] {
|
|
new PackedStreamInfo
|
|
{
|
|
PackedSize = (ulong)(_zipFs.Position - packedHeaderPos),
|
|
StreamPosition = 0
|
|
}
|
|
}
|
|
};
|
|
|
|
using (Stream headerMem = new MemoryStream())
|
|
{
|
|
using (BinaryWriter bw = new BinaryWriter(headerMem, Encoding.UTF8, true))
|
|
{
|
|
bw.Write((byte)HeaderProperty.kEncodedHeader);
|
|
streamsInfo.WriteHeader(bw);
|
|
|
|
newHeaderByte = new byte[headerMem.Length];
|
|
headerMem.Position = 0;
|
|
headerMem.Read(newHeaderByte, 0, newHeaderByte.Length);
|
|
|
|
}
|
|
}
|
|
mainHeaderCRC = CRC.CalculateDigest(newHeaderByte, 0, (uint)newHeaderByte.Length);
|
|
#endregion
|
|
|
|
|
|
using (BinaryWriter bw = new BinaryWriter(_zipFs, Encoding.UTF8, true))
|
|
{
|
|
ulong headerPosition = (ulong)_zipFs.Position + 32; //tzip header is 32 bytes
|
|
WriteRomVault7Zip(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
|
|
|
_zipFs.Write(newHeaderByte, 0, newHeaderByte.Length);
|
|
_signatureHeader.WriteFinal(bw, headerPosition, (ulong)newHeaderByte.Length, mainHeaderCRC);
|
|
}
|
|
_zipFs.Flush();
|
|
_zipFs.Close();
|
|
_zipFs.Dispose();
|
|
}
|
|
|
|
}
|
|
} |