private IList <IArchiveFileInfo> LoadSwitch(Stream input) { using var br = new BinaryReaderX(input, true); // Read header _header = br.ReadType <MtHeader>(); // Read entries var entries = br.ReadMultiple <MtEntrySwitch>(_header.entryCount); // Add files var result = new List <IArchiveFileInfo>(); foreach (var entry in entries) { var fileStream = new SubStream(input, entry.Offset, entry.CompSize); var fileName = entry.FileName.TrimEnd('\0') + MtArcSupport.DetermineExtension(entry.ExtensionHash); // It seems every file is compressed with ZLib on Switch // Reasoning: Example file game.arc contains of at least one file "om120a" where compressed and uncompressed size are equal but the file is still compressed // the decompressed file is really the same size; comparing with other entries no clear differences were found, that would indicate a // compression flag result.Add(new MtArchiveFileInfo(fileStream, fileName, entry, Kompression.Implementations.Compressions.ZLib, entry.GetDecompressedSize(_platform))); } return(result); }
private IList <IArchiveFileInfo> LoadLittleEndian(Stream input) { using var br = new BinaryReaderX(input, true); // Read header _header = br.ReadType <MtHeader>(); // Skip additional int under certain conditions if (_header.version != 7 && _header.version != 8) { br.ReadInt32(); } // Read entries var entries = br.ReadMultiple <MtEntry>(_header.entryCount); // Add files var result = new List <IArchiveFileInfo>(); foreach (var entry in entries) { var fileStream = new SubStream(input, entry.Offset, entry.CompSize); var fileName = entry.FileName.TrimEnd('\0') + MtArcSupport.DetermineExtension(entry.ExtensionHash); result.Add(CreateAfi(fileStream, fileName, entry, _platform)); } return(result); }
public IList <IArchiveFileInfo> Load(Stream input) { using var br = new BinaryReaderX(input, true); // Read header _header = br.ReadType <MtHeader>(); // Read entries var key = GetCipherKey("imaguy_uyrag_igurustim_", "enokok_ikorodo_odohuran"); var entryStream = new MtBlowfishStream(new SubStream(input, HeaderSize, _header.entryCount * EntrySize), key); using var entryBr = new BinaryReaderX(entryStream); var entries = entryBr.ReadMultiple <MtEntry>(_header.entryCount); // Add files var result = new List <IArchiveFileInfo>(); foreach (var entry in entries) { var fileStream = new MtBlowfishStream(new SubStream(input, entry.Offset, entry.CompSize), key); var name = entry.FileName + MtArcSupport.DetermineExtension(entry.ExtensionHash); result.Add(MtArc.CreateAfi(fileStream, name, entry, MtArcPlatform.LittleEndian)); } return(result); }
public IList <IArchiveFileInfo> Load(Stream input) { _isEncrypted = IsEncrypted(input); var key = GetCipherKey("imaguy_uyrag_igurustim_", "enokok_ikorodo_odohuran"); using var br = new BinaryReaderX(input, true); // Determine byte order var magic = br.ReadString(4); br.ByteOrder = _byteOrder = magic == "\0CRA" ? ByteOrder.BigEndian : ByteOrder.LittleEndian; input.Position -= 4; // Header _header = br.ReadType <MtHeader>(); // Determine possible platform the arc was found on _platform = MtArcSupport.DeterminePlatform(_byteOrder, _header); // Skip additional int under certain conditions if (_byteOrder == ByteOrder.LittleEndian && _header.version != 7 && _header.version != 8 && _header.version != 9) { br.ReadInt32(); } // Read entries Stream entryStream = new SubStream(input, br.BaseStream.Position, input.Length - br.BaseStream.Position); if (_isEncrypted) { entryStream = new MtBlowfishStream(entryStream, key); } using var entryBr = new BinaryReaderX(entryStream); var entries = entryBr.ReadMultiple(_header.entryCount, _header.version == 9 ? typeof(MtEntrySwitch) : typeof(MtEntry)).Cast <IMtEntry>(); // Add files var result = new List <IArchiveFileInfo>(); foreach (var entry in entries) { Stream subStream = new SubStream(input, entry.Offset, entry.CompSize); var fileName = entry.FileName.TrimEnd('\0') + MtArcSupport.DetermineExtension(entry.ExtensionHash); if (_isEncrypted) { subStream = new MtBlowfishStream(subStream, key); } result.Add(CreateAfi(subStream, fileName, entry, _platform)); } return(result); }
public async Task Load(IFileSystem fileSystem, UPath filePath, LoadContext loadContext) { _hasAddedFiles = false; _hasDeletedFiles = false; var fileStream = await fileSystem.OpenFileAsync(filePath); var platform = MtArcSupport.DeterminePlatform(fileStream); Files = _arc.Load(fileStream, platform); }
public static int GetArchiveSize(IList <IArchiveFileInfo> files, int version, ByteOrder byteOrder) { // Get header size var isExtendedHeader = version != 7 && version != 8; var headerSize = HeaderSize + (isExtendedHeader ? 4 : 0); // Get file offset var fileOffset = MtArcSupport.DetermineFileOffset(byteOrder, version, files.Count, headerSize); // Add file sizes var fileRegionSize = (int)files.Cast <MtArchiveFileInfo>().Sum(x => x.GetFinalStream().Length); return(fileOffset + fileRegionSize); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { var key = GetCipherKey("imaguy_uyrag_igurustim_", "enokok_ikorodo_odohuran"); using var bw = new BinaryWriterX(output); // Calculate offsets var entryOffset = HeaderSize; var fileOffset = MtArcSupport.DetermineFileOffset(ByteOrder.LittleEndian, _header.version, files.Count, entryOffset); // Prepare output stream output.SetLength(MtArc.GetArchiveSize(files, _header.version, ByteOrder.LittleEndian)); // Write files var entries = new List <IMtEntry>(); var filePosition = fileOffset; foreach (var file in files.Cast <MtArchiveFileInfo>()) { var fileStream = file.GetFinalStream(); Stream targetStream = new SubStream(output, filePosition, fileStream.Length); targetStream = new MtBlowfishStream(targetStream, key); fileStream.CopyTo(targetStream); file.Entry.Offset = filePosition; file.Entry.SetDecompressedSize((int)file.FileSize, MtArcPlatform.LittleEndian); file.Entry.CompSize = (int)fileStream.Length; entries.Add(file.Entry); filePosition += (int)fileStream.Length; } // Write entries Stream entryStream = new SubStream(output, entryOffset, output.Length - entryOffset); entryStream = new MtBlowfishStream(entryStream, key); using var entryBw = new BinaryWriterX(entryStream); entryBw.WriteMultiple(entries); // Write header _header.entryCount = (short)files.Count; output.Position = 0; bw.WriteType(_header); }
public IArchiveFileInfo Add(Stream fileData, UPath filePath) { // Determine extension hash var extensionHash = Regex.IsMatch(filePath.GetExtensionWithDot(), @"\.[\da-fA-F]{8}") ? uint.Parse(filePath.GetExtensionWithDot().Substring(1), NumberStyles.HexNumber) : MtArcSupport.DetermineExtensionHash(filePath.GetExtensionWithDot()); // Create entry IMtEntry entry; switch (_platform) { case MtArcPlatform.Switch: entry = new MtEntrySwitch { ExtensionHash = extensionHash, FileName = (filePath.GetDirectory() / filePath.GetNameWithoutExtension()).FullName, decompSize = (int)fileData.Length }; break; case MtArcPlatform.LittleEndian: case MtArcPlatform.BigEndian: entry = new MtEntry { ExtensionHash = extensionHash, FileName = (filePath.GetDirectory() / filePath.GetNameWithoutExtension()).FullName, decompSize = (int)fileData.Length, }; break; default: throw new InvalidOperationException(); } // Create ArchiveFileInfo return(CreateAfi(fileData, filePath.FullName, entry, _platform)); }
private void SaveLittleEndian(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output); var isExtendedHeader = _header.version != 7 && _header.version != 8; // Calculate offsets var entryOffset = HeaderSize + (isExtendedHeader ? 4 : 0); var fileOffset = MtArcSupport.DetermineFileOffset(ByteOrder.LittleEndian, _header.version, files.Count, entryOffset); // Write files var entries = new List <IMtEntry>(); var filePosition = fileOffset; foreach (var file in files.Cast <MtArchiveFileInfo>()) { output.Position = filePosition; var writtenSize = file.SaveFileData(output); file.Entry.Offset = filePosition; file.Entry.SetDecompressedSize((int)file.FileSize, _platform); file.Entry.CompSize = (int)writtenSize; entries.Add(file.Entry); filePosition += (int)writtenSize; } // Write entries output.Position = entryOffset; bw.WriteMultiple(entries); // Write header _header.entryCount = (short)files.Count; output.Position = 0; bw.WriteType(_header); }
private IList <IArchiveFileInfo> LoadBigEndian(Stream input) { using var br = new BinaryReaderX(input, true, ByteOrder.BigEndian); // Read header _header = br.ReadType <MtHeader>(); // Read entries var entries = br.ReadMultiple <MtEntry>(_header.entryCount); // Add files var result = new List <IArchiveFileInfo>(); foreach (var entry in entries) { var fileStream = new SubStream(input, entry.Offset, entry.CompSize); var fileName = entry.FileName.TrimEnd('\0') + MtArcSupport.DetermineExtension(entry.ExtensionHash); result.Add(CreateAfi(fileStream, fileName, entry, _platform)); } return(result); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { var key = GetCipherKey("imaguy_uyrag_igurustim_", "enokok_ikorodo_odohuran"); using var bw = new BinaryWriterX(output, _byteOrder); var isExtendedHeader = _byteOrder == ByteOrder.LittleEndian && _header.version != 7 && _header.version != 8 && _header.version != 9; // Calculate offsets var entryOffset = HeaderSize + (isExtendedHeader ? 4 : 0); var fileOffset = MtArcSupport.DetermineFileOffset(_byteOrder, _header.version, files.Count, entryOffset); // Write files var entries = new List <IMtEntry>(); var filePosition = fileOffset; foreach (var file in files.Cast <MtArchiveFileInfo>()) { output.Position = filePosition; long writtenSize; if (!_isEncrypted) { writtenSize = file.SaveFileData(output); } else { var fileStream = file.GetFinalStream(); var ms = new MemoryStream(); var encryptedStream = new MtBlowfishStream(ms, key); fileStream.CopyTo(encryptedStream); ms.Position = 0; ms.CopyTo(output); writtenSize = fileStream.Length; } file.Entry.Offset = filePosition; file.Entry.SetDecompressedSize((int)file.FileSize, _platform); file.Entry.CompSize = (int)writtenSize; entries.Add(file.Entry); filePosition += (int)writtenSize; } // Write entries Stream entryStream = new SubStream(output, entryOffset, output.Length - entryOffset); if (_isEncrypted) { entryStream = new MtBlowfishStream(entryStream, key); } using var entryBw = new BinaryWriterX(entryStream, _byteOrder); entryBw.WriteMultiple(entries); // Write header _header.entryCount = (short)files.Count; output.Position = 0; bw.WriteType(_header); }