public static RDAFile FromUnmanaged(FileHeader.Version version, DirEntry dir, BlockInfo block, BinaryReader reader, RDAMemoryResidentHelper mrm) { RDAFile rdaFile = new RDAFile(); rdaFile.FileName = dir.filename; rdaFile.Version = version; if ((block.flags & 4) != 4) { if ((block.flags & 1) == 1) { rdaFile.Flags |= Flag.Compressed; } if ((block.flags & 2) == 2) { rdaFile.Flags |= Flag.Encrypted; } } if ((block.flags & 4) == 4) { rdaFile.Flags |= Flag.MemoryResident; } if ((block.flags & 8) == 8) { rdaFile.Flags |= Flag.Deleted; } rdaFile.Offset = dir.offset; rdaFile.UncompressedSize = dir.filesize; rdaFile.CompressedSize = dir.compressed; rdaFile.TimeStamp = DateTimeExtension.FromTimeStamp(dir.timestamp); rdaFile.BinaryFile = mrm == null ? reader : new BinaryReader(mrm.Data); return(rdaFile); }
private static FileHeader ReadFileHeader(BinaryReader reader, FileHeader.Version expectedVersion) { Encoding expectedEncoding = FileHeader.GetMagicEncoding(expectedVersion); string expectedMagic = FileHeader.GetMagic(expectedVersion); int expectedByteCount = expectedEncoding.GetByteCount(expectedMagic); byte[] actualBytes = reader.ReadBytes(expectedByteCount); string actualMagic = expectedEncoding.GetString(actualBytes); if (actualMagic == expectedMagic) { uint unknownBytes = FileHeader.GetUnknownSize(expectedVersion); return(new FileHeader { magic = actualMagic, version = expectedVersion, unkown = reader.ReadBytes((int)unknownBytes), firstBlockOffset = ReadUIntVersionAware(reader, expectedVersion), }); } else { throw new Exception("Invalid or unsupported RDA file!"); } }
public static uint GetSize(FileHeader.Version version) { switch (version) { case FileHeader.Version.Version_2_0: return(20); case FileHeader.Version.Version_2_2: return(32); } return(0); }
public static uint GetSize(FileHeader.Version version) { switch (version) { case FileHeader.Version.Version_2_0: return(GetFilenameSize() + 20); case FileHeader.Version.Version_2_2: return(GetFilenameSize() + 40); } return(0); }
private static string GetVersionString(FileHeader.Version version) { switch (version) { case FileHeader.Version.Version_2_0: return("2.0 (Anno 1404 & 2070)"); case FileHeader.Version.Version_2_2: return("2.2 (Anno 2205)"); } return(""); }
public static RDAFolder GenerateFrom(List <RDAFile> file, FileHeader.Version version) { RDAFolder root = new RDAFolder(version); root.Files.AddRange(file.FindAll(f => !f.FileName.Contains("/"))); foreach (RDAFile rdaFile in file.FindAll(f => f.FileName.Contains("/"))) { NavigateTo(root, Path.GetDirectoryName(rdaFile.FileName), "").Files.Add(rdaFile); } return(root); }
public static int GetDecryptionSeed(FileHeader.Version version) { switch (version) { case FileHeader.Version.Invalid: throw new ArgumentException("Invalid file version", "version"); case FileHeader.Version.Version_2_0: return(0xA2C2A); // 0x800A2C2A would also work, but the number doesn't fit into int case FileHeader.Version.Version_2_2: return(0x71C71C71); // 0xF1C71C71 would also work, but the number doesn't fit into int } throw new ArgumentException("Files of version " + Enum.GetName(version.GetType(), version) + " cannot be decrypted yet.", "version"); }
private void SaveFile(string fileName) { SaveRDAFileWindow saveRdaFileWindow = new SaveRDAFileWindow(); saveRdaFileWindow.Folder = CurrentReader.rdaFolder; saveRdaFileWindow.field_OutputFile.Text = fileName; saveRdaFileWindow.MustChooseFolderVersionDueToEncryptedBlocks = CurrentReader.SkippedDataSections.Count > 0; if (!saveRdaFileWindow.ShowDialog().GetValueOrDefault()) { return; } fileName = saveRdaFileWindow.field_OutputFile.Text; FileHeader.Version version = CurrentReader.SkippedDataSections.Count > 0 ? CurrentReader.rdaFolder.Version : saveRdaFileWindow.SelectedVersion; bool compress = saveRdaFileWindow.check_IsCompressed.IsChecked.Value; if (!Directory.Exists(Path.GetDirectoryName(fileName))) { Directory.CreateDirectory(Path.GetDirectoryName(fileName)); } RDAWriter writer = new RDAWriter(CurrentReader.rdaFolder); BackgroundWorker wrk = new BackgroundWorker(); wrk.WorkerReportsProgress = true; progressBar_Status.Visibility = Visibility.Visible; wrk.ProgressChanged += (s, e2) => DispatcherExtension.Dispatch(System.Windows.Application.Current, () => { label_Status.Text = writer.UI_LastMessage; progressBar_Status.Value = e2.ProgressPercentage; }); wrk.RunWorkerCompleted += (s, e2) => DispatcherExtension.Dispatch(System.Windows.Application.Current, () => { label_Status.Text = CurrentReader.rdaFolder.GetAllFiles().Count + " files"; progressBar_Status.Visibility = Visibility.Collapsed; }); wrk.DoWork += (s, e2) => { try { writer.Write(fileName, version, compress, CurrentReader, wrk); } catch (Exception ex) { int num2 = (int)DispatcherExtension.Dispatch(System.Windows.Application.Current, () => MessageWindow.Show(ex.Message)); } }; wrk.RunWorkerAsync(); return; }
private void Window_Loaded(object sender, RoutedEventArgs e) { SelectedVersion = Folder.Version; // add version RadioButtons foreach (var version in (FileHeader.Version[])Enum.GetValues(typeof(FileHeader.Version))) { if (version != FileHeader.Version.Invalid) { RadioButton radioButton = new RadioButton(); radioButton.GroupName = "version"; radioButton.Content = GetVersionString(version); radioButton.Tag = version; radioButton.Checked += radioButton_Version_Checked; if (SelectedVersion == version) { radioButton.IsChecked = true; } if (MustChooseFolderVersionDueToEncryptedBlocks) { radioButton.IsEnabled = false; radioButton.ToolTip = "Files with encrypted blocks must be saved with the same version as the original."; ToolTipService.SetShowOnDisabled(radioButton, true); } versionsPanel.Children.Add(radioButton); } } // pre-select compression for version 2.0 check_IsCompressed.IsChecked = SelectedVersion == FileHeader.Version.Version_2_0; // add compression CheckBoxes foreach (string str in Folder.GetAllExtensions()) { CheckBox checkBox = new CheckBox(); checkBox.Content = str; if (RDABlockCreator.FileType_CompressedExtensions.Contains(str)) { checkBox.IsChecked = new bool?(true); } compressedTypesPanel.Children.Add(checkBox); } }
private static byte[] CreateDirEntryBytes(DirEntry dirEntry, FileHeader.Version version) { byte[] result = new byte[DirEntry.GetSize(version)]; MemoryStream memoryStream = new MemoryStream(result); BinaryWriter writer = new BinaryWriter(memoryStream); byte[] filenameBytes = Encoding.Unicode.GetBytes(dirEntry.filename); writer.Write(filenameBytes, 0, (int)Math.Min(DirEntry.GetFilenameSize(), filenameBytes.Length)); writer.BaseStream.Position = DirEntry.GetFilenameSize(); FileHeader.WriteUIntVersionAware(writer, dirEntry.offset, version); FileHeader.WriteUIntVersionAware(writer, dirEntry.compressed, version); FileHeader.WriteUIntVersionAware(writer, dirEntry.filesize, version); FileHeader.WriteUIntVersionAware(writer, dirEntry.timestamp, version); FileHeader.WriteUIntVersionAware(writer, dirEntry.unknown, version); return(result); }
private void Window_Loaded(object sender, RoutedEventArgs e) { SelectedVersion = Folder.Version; // add version RadioButtons foreach (var version in (FileHeader.Version[])Enum.GetValues(typeof(FileHeader.Version))) { if (version != FileHeader.Version.Invalid) { RadioButton radioButton = new RadioButton(); radioButton.GroupName = "version"; radioButton.Content = GetVersionString(version); radioButton.Tag = version; radioButton.Checked += radioButton_Version_Checked; if (SelectedVersion == version) radioButton.IsChecked = true; if (MustChooseFolderVersionDueToEncryptedBlocks) { radioButton.IsEnabled = false; radioButton.ToolTip = "Files with encrypted blocks must be saved with the same version as the original."; ToolTipService.SetShowOnDisabled(radioButton, true); } versionsPanel.Children.Add(radioButton); } } // pre-select compression for version 2.0 check_IsCompressed.IsChecked = SelectedVersion == FileHeader.Version.Version_2_0; // add compression CheckBoxes foreach (string str in Folder.GetAllExtensions()) { CheckBox checkBox = new CheckBox(); checkBox.Content = str; if (RDABlockCreator.FileType_CompressedExtensions.Contains(str)) checkBox.IsChecked = new bool?(true); compressedTypesPanel.Children.Add(checkBox); } }
public static RDAFile Create(FileHeader.Version version, string file, string folderpath) { FileInfo fileInfo = new FileInfo(file); RDAFile rdaFile = new RDAFile(); rdaFile.FileName = FileNameToRDAFileName(file, folderpath); rdaFile.Version = version; rdaFile.OverwrittenFilePath = file; rdaFile.TimeStamp = fileInfo.LastWriteTime; rdaFile.Offset = 0; rdaFile.CompressedSize = (ulong)fileInfo.Length; rdaFile.UncompressedSize = (ulong)fileInfo.Length; FileStream fileStream = RDAFileStreamCache.Open(file); if (fileStream == null) { return(null); } rdaFile.BinaryFile = new BinaryReader(fileStream); return(rdaFile); }
public RDAMemoryResidentHelper(ulong offset, ulong datasize, ulong compressed, Stream datasource, BlockInfo info, FileHeader.Version version) { Offset = offset; DataSize = datasize; Compressed = compressed; Info = info; Data = new MemoryStream(); byte[] numArray = new byte[compressed]; datasource.Position = (long)offset; datasource.Read(numArray, 0, (int)compressed); if ((info.flags & 2) == 2) { numArray = BinaryExtension.Decrypt(numArray, BinaryExtension.GetDecryptionSeed(version)); } if ((info.flags & 1) == 1) { numArray = ZLib.ZLib.Uncompress(numArray, (int)datasize); } Data.Write(numArray, 0, numArray.Length); }
public RDAFolder(RDAFolder parent) { this.Parent = parent; this.Version = parent.Version; }
public RDAFolder(FileHeader.Version version) { this.Version = version; }
private void radioButton_Version_Checked(object sender, RoutedEventArgs e) { SelectedVersion = (FileHeader.Version)((RadioButton)sender).Tag; }
private static ulong ReadUIntVersionAware(BinaryReader reader, FileHeader.Version version) { return(FileHeader.ReadUIntVersionAware(reader, version)); }
private static void WriteBlockInfo(BinaryWriter writer, ulong offset, BlockInfo blockInfo, FileHeader.Version version) { writer.BaseStream.Position = (long)offset; writer.Write((System.UInt32)blockInfo.flags); writer.Write((System.UInt32)blockInfo.fileCount); FileHeader.WriteUIntVersionAware(writer, blockInfo.directorySize, version); FileHeader.WriteUIntVersionAware(writer, blockInfo.decompressedSize, version); FileHeader.WriteUIntVersionAware(writer, blockInfo.nextBlock, version); }
public void Write(string Filename, FileHeader.Version version, bool compress, RDAReader originalReader, BackgroundWorker wrk) { FileStream fileStream = new FileStream(Filename, FileMode.Create); BinaryWriter writer = new BinaryWriter(fileStream); // we'll write the header at the end, when we know the offset to the first block writer.BaseStream.Position = FileHeader.GetSize(version); // blocks are organized by file type. there is one RDAFolder per block List <RDAFolder> blockFolders = RDABlockCreator.GenerateOf(Folder); int numBlocks = (int)originalReader.NumSkippedBlocks + blockFolders.Count; BlockInfo[] blockInfos = new BlockInfo[numBlocks]; ulong[] blockInfoOffsets = new ulong[numBlocks]; int writeBlockIndex = 0; // Write blocks skipped when reading. They have to appear at exactly the place where they came // from, because the file data offsets are encrypted and can therefore not be changed. for (int skippedBlockIndex = 0; skippedBlockIndex < originalReader.NumSkippedBlocks; ++skippedBlockIndex) { RDASkippedDataSection skippedBlock = originalReader.SkippedDataSections[skippedBlockIndex]; if (wrk != null) { UI_LastMessage = "Writing Block " + (writeBlockIndex + 1) + "/" + numBlocks + " => ??? files (encrypted)"; wrk.ReportProgress((int)((double)writeBlockIndex / numBlocks * 100.0)); } // Skip ahead to the correct position. // This will create "holes" in the file if the skipped sections are not contiguous or // don't start at the beginning of the file, but we'll have to live with it to some extent // anyway (we won't fit our "own" data in perfectly). And I'm just too afraid to get the // bin-packing wrong. writer.BaseStream.WriteBytes((skippedBlock.offset - (ulong)writer.BaseStream.Position), 0); // write the data originalReader.CopySkippedDataSextion(skippedBlock.offset, skippedBlock.size, writer.BaseStream); // generate the new block info BlockInfo blockInfo = skippedBlock.blockInfo.Clone(); blockInfos[writeBlockIndex] = blockInfo; blockInfoOffsets[writeBlockIndex] = (ulong)writer.BaseStream.Position; if (writeBlockIndex > 0) { blockInfos[writeBlockIndex - 1].nextBlock = blockInfoOffsets[writeBlockIndex]; } // we'll write the block info at the end, once we know the next block offset writer.BaseStream.Position += BlockInfo.GetSize(version); ++writeBlockIndex; } // write regular blocks for (int blockFolderIndex = 0; blockFolderIndex < blockFolders.Count; ++blockFolderIndex) { RDAFolder blockFolder = blockFolders[blockFolderIndex]; bool compressBlock = compress && blockFolder.RDABlockCreator_FileType_IsCompressable.GetValueOrDefault(false); if (wrk != null) { UI_LastMessage = "Writing Block " + (writeBlockIndex + 1) + "/" + numBlocks + " => " + blockFolder.Files.Count + " files"; wrk.ReportProgress((int)((double)writeBlockIndex / numBlocks * 100.0)); } Dictionary <RDAFile, ulong> dirEntryOffsets = new Dictionary <RDAFile, ulong>(); Dictionary <RDAFile, ulong> dirEntryCompressedSizes = new Dictionary <RDAFile, ulong>(); foreach (RDAFile file in blockFolder.Files) { byte[] dataToWrite = file.GetData(); if (compressBlock) { dataToWrite = ZLib.ZLib.Compress(dataToWrite); } dirEntryOffsets.Add(file, (ulong)writer.BaseStream.Position); dirEntryCompressedSizes.Add(file, (ulong)dataToWrite.Length); writer.Write(dataToWrite); } int dirEntrySize = (int)DirEntry.GetSize(version); int decompressedDirEntriesSize = blockFolder.Files.Count * dirEntrySize; byte[] decompressedDirEntries = new byte[decompressedDirEntriesSize]; for (int dirEntryIndex = 0; dirEntryIndex < blockFolder.Files.Count; ++dirEntryIndex) { RDAFile file = blockFolder.Files[dirEntryIndex]; DirEntry dirEntry = new DirEntry() { compressed = dirEntryCompressedSizes[file], filesize = file.UncompressedSize, filename = file.FileName, timestamp = file.TimeStamp.ToTimeStamp(), unknown = 0, offset = dirEntryOffsets[file], }; byte[] dirEntryBytes = CreateDirEntryBytes(dirEntry, version); Buffer.BlockCopy(dirEntryBytes, 0, decompressedDirEntries, dirEntryIndex * dirEntrySize, dirEntrySize); } byte[] compressedDirEntries = compressBlock ? ZLib.ZLib.Compress(decompressedDirEntries) : decompressedDirEntries; writer.Write(compressedDirEntries); BlockInfo blockInfo = new BlockInfo() { flags = compressBlock ? 1u : 0u, fileCount = (uint)blockFolder.Files.Count, directorySize = (ulong)compressedDirEntries.Length, decompressedSize = (ulong)decompressedDirEntriesSize, nextBlock = 0, // will set this at the end of the next block }; blockInfos[writeBlockIndex] = blockInfo; blockInfoOffsets[writeBlockIndex] = (ulong)writer.BaseStream.Position; if (writeBlockIndex > 0) { blockInfos[writeBlockIndex - 1].nextBlock = blockInfoOffsets[writeBlockIndex]; } // we'll write the block info at the end, once we know the next block offset writer.BaseStream.Position += BlockInfo.GetSize(version); ++writeBlockIndex; } // the last block gets nextBlockOffset after end of file blockInfos[blockInfos.Length - 1].nextBlock = blockInfoOffsets[blockInfos.Length - 1] + BlockInfo.GetSize(version); // now write all block infos for (int index = 0; index < blockInfos.Length; ++index) { WriteBlockInfo(writer, blockInfoOffsets[index], blockInfos[index], version); } // now write the header FileHeader fileHeader = FileHeader.Create(version); fileHeader.firstBlockOffset = blockInfoOffsets[0]; WriteHeader(writer, 0, fileHeader, version); fileStream.Close(); }
private static uint GetUIntSizeVersionAware(FileHeader.Version version) { return(FileHeader.GetUIntSize(version)); }
private static void WriteHeader(BinaryWriter writer, ulong offset, FileHeader fileHeader, FileHeader.Version version) { writer.BaseStream.Position = (long)offset; byte[] magic = FileHeader.GetMagicBytes(fileHeader.version); writer.Write(magic); writer.Write(fileHeader.unkown); FileHeader.WriteUIntVersionAware(writer, fileHeader.firstBlockOffset, version); }