コード例 #1
0
        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);
        }
コード例 #2
0
        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!");
            }
        }
コード例 #3
0
        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);
        }
コード例 #4
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);
        }
コード例 #5
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("");
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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");
        }
コード例 #8
0
        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;
        }
コード例 #9
0
        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);
            }
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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);
            }
        }
コード例 #12
0
        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);
        }
コード例 #13
0
 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);
 }
コード例 #14
0
ファイル: RDAFolder.cs プロジェクト: JcBernack/RDAExplorer
 public RDAFolder(RDAFolder parent)
 {
     this.Parent = parent;
     this.Version = parent.Version;
 }
コード例 #15
0
ファイル: RDAFolder.cs プロジェクト: JcBernack/RDAExplorer
 public RDAFolder(FileHeader.Version version)
 {
     this.Version = version;
 }
コード例 #16
0
 private void radioButton_Version_Checked(object sender, RoutedEventArgs e)
 {
     SelectedVersion = (FileHeader.Version)((RadioButton)sender).Tag;
 }
コード例 #17
0
 public RDAFolder(FileHeader.Version version)
 {
     this.Version = version;
 }
コード例 #18
0
 private static ulong ReadUIntVersionAware(BinaryReader reader, FileHeader.Version version)
 {
     return(FileHeader.ReadUIntVersionAware(reader, version));
 }
コード例 #19
0
 public RDAFolder(RDAFolder parent)
 {
     this.Parent  = parent;
     this.Version = parent.Version;
 }
コード例 #20
0
        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);
        }
コード例 #21
0
 private void radioButton_Version_Checked(object sender, RoutedEventArgs e)
 {
     SelectedVersion = (FileHeader.Version)((RadioButton)sender).Tag;
 }
コード例 #22
0
        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();
        }
コード例 #23
0
 private static uint GetUIntSizeVersionAware(FileHeader.Version version)
 {
     return(FileHeader.GetUIntSize(version));
 }
コード例 #24
0
        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);
        }