public Container(byte[] data) { var reader = new SpanReader(data); var compressionType = (CompressionType)reader.ReadByte(); var length = reader.ReadInt32BigEndian(); // TODO check if valid compression type // TODO xtea decrypt var uncompressedLength = compressionType == CompressionType.None ? length : reader.ReadInt32BigEndian(); Data = compressionType switch { CompressionType.None => reader.ReadSlice(length).ToArray(), CompressionType.Bzip2 => CompressionHelper.DecompressBzip2(reader.ReadSlice(length), uncompressedLength), CompressionType.Gzip => CompressionHelper.DecompressGzip(reader.ReadSlice(length), uncompressedLength), _ => throw new ArgumentException($"Invalid compression type of {compressionType}.") }; }
public static ReferenceTable Decode(byte[] data) { var reader = new SpanReader(data); var format = reader.ReadByte(); if (format < FormatVersion || format > FormatVersionSmart) { throw new ArgumentException($"Unknown reference table format of {format} given."); } var version = format >= FormatVersion?reader.ReadInt32BigEndian() : 0; var flags = reader.ReadByte(); var hasNames = (flags & FlagNameHashes) != 0; var hasWhirlpool = (flags & FlagWhirlpool) != 0; var hasUnknown4 = (flags & FlagUnknown4) != 0; var hasUnknown8 = (flags & FlagUnknown8) != 0; var entryCount = format >= FormatVersionSmart ? reader.ReadUIntSmartBigEndian() : reader.ReadUInt16BigEndian(); var entries = new Archive[entryCount]; // create the Archive objects var lastEntryId = 0; for (var i = 0; i < entries.Length; i++) { var id = lastEntryId += format >= FormatVersionSmart ? reader.ReadUIntSmartBigEndian() : reader.ReadUInt16BigEndian(); entries[i] = new Archive(id); } // if the reference table has identifiers, read them if (hasNames) { for (var i = 0; i < entryCount; i++) { entries[i].NameHash = reader.ReadInt32BigEndian(); } } // read the checksums for (var i = 0; i < entryCount; i++) { entries[i].Crc = reader.ReadInt32BigEndian(); } // TODO identify this if (hasUnknown8) { for (var i = 0; i < entryCount; i++) { reader.ReadInt32BigEndian(); } } // read the whirlpool digests if (hasWhirlpool) { for (var i = 0; i < entryCount; i++) { var whirlpoolSlice = reader.ReadSlice(WhirlpoolDigestLength); entries[i].WhirlpoolDigest = whirlpoolSlice.ToArray(); } } // TODO identify this if (hasUnknown4) { for (var i = 0; i < entryCount; i++) { reader.ReadInt32BigEndian(); reader.ReadInt32BigEndian(); } } // read the entry versions for (var i = 0; i < entryCount; i++) { entries[i].Version = reader.ReadInt32BigEndian(); } // create our child entries for (var i = 0; i < entryCount; i++) { var count = format >= FormatVersionSmart ? reader.ReadUIntSmartBigEndian() : reader.ReadUInt16BigEndian(); var entry = entries[i]; entry.Files = new ArchiveFile[count]; } // read the child entry ids for (var i = 0; i < entryCount; i++) { var childEntries = entries[i].Files; var childEntriesLength = childEntries.Length; var lastChildEntryId = 0; for (var j = 0; j < childEntriesLength; j++) { var id = lastChildEntryId += format >= FormatVersionSmart ? reader.ReadUIntSmartBigEndian() : reader.ReadUInt16BigEndian(); var childEntry = childEntries[j]; childEntry.Id = id; } } // if the child entries have identifiers, read them if (hasNames) { for (var i = 0; i < entryCount; i++) { var childEntries = entries[i].Files; var childEntriesLength = childEntries.Length; for (var j = 0; j < childEntriesLength; j++) { var identifier = reader.ReadInt32BigEndian(); var childEntry = childEntries[j]; childEntry.NameHash = identifier; } } } return(new ReferenceTable(format, version, entries)); }