public IList <IArchiveFileInfo> Load(Stream input) { // Prepare binary readers using var br = new BinaryReaderX(input, true); var isoStream = new SubStream(input, 0x1800, input.Length - 0x1800); // Read header _header = br.ReadType <CvmHeader>(); _zoneInfo = br.ReadType <CvmZoneInfo>(); _unkDataLoc = br.ReadBytes(0x800); // Prepare decryption stream Stream decStream = isoStream; if (_header.IsEncrypted) { _detectedPassword = DetectPassword(isoStream); decStream = new RofsCryptoStream(isoStream, _detectedPassword, 0, 0x800); } using var decBr = new BinaryReaderX(decStream); // Read ISO primary descriptor decStream.Position = 0x8000; _primeDesc = decBr.ReadType <IsoPrimaryDescriptor>(); // Read record tree return(ParseDirTree(decBr, isoStream, _primeDesc.rootDirRecord.extentLe, _primeDesc.rootDirRecord.sizeLe, UPath.Root).ToArray()); }
private string DetectPassword(Stream input) { input = new SubStream(input, 0x8000, 0x800); foreach (var pw in Passwords) { using var cipher = new RofsCryptoStream(input, pw, 0x10, 0x800); using var cipherBr = new BinaryReaderX(cipher); cipher.Position = 1; if (cipherBr.ReadString(5) == "CD001") { return(pw); } } throw new InvalidOperationException("Password could not be detected. Please report this on the github of the developers of Kuriimu2."); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { var fileTree = files.ToTree(); // Pre-calculate size of the TOC var dirSize = CalculateDirTreeSize(fileTree); // Prepare streams output.SetLength(0xB800 + dirSize); Stream tocStream = new SubStream(output, 0x1800, 0xA000 + dirSize); if (_header.IsEncrypted) { tocStream = new RofsCryptoStream(tocStream, _detectedPassword, 0, 0x800); } // Write files and TOC using var tocBw = new BinaryWriterX(tocStream); var fileOffset = (long)(0xB800 + dirSize); WriteDirTree(fileTree, output, tocBw, 0xA000, ref fileOffset); // Write pre TOC information _primeDesc.volSizeBe = (int)((output.Length - 0x1800 + 0x7FF) & ~0x7FF); _primeDesc.volSizeLe = (int)((output.Length - 0x1800 + 0x7FF) & ~0x7FF); _primeDesc.logicalBlockSizeLe = 0x800; _primeDesc.logicalBlockSizeBe = 0x800; _primeDesc.rootDirRecord.sizeLe = (uint)dirSize; _primeDesc.rootDirRecord.sizeBe = (uint)dirSize; tocStream.Position = 0x8000; tocBw.WriteType(_primeDesc); tocBw.WriteAlignment(0x800); // Write end ISO sector tocBw.Write((byte)0xFF); tocBw.WriteString("CD001", Encoding.ASCII, false, false); tocBw.Write((short)0x1); tocBw.WriteAlignment(0x800); // Write root dir information in little endian tocBw.Write((short)0x1); tocBw.Write(0x14); tocBw.Write((short)1); tocBw.WriteAlignment(0x800); // Write root dir information in big endian tocBw.Write((short)0x1); tocBw.ByteOrder = ByteOrder.BigEndian; tocBw.Write(0x14); tocBw.Write((short)1); // Write CVM header information _header.fileSize = output.Length; _zoneInfo.isoDataLoc.length = output.Length - 0x1800; using var bw = new BinaryWriterX(output); output.Position = 0; bw.WriteType(_header); bw.WriteType(_zoneInfo); bw.Write(_unkDataLoc); }