public override void Export(String path, IProgressReport progress = null) { string filename; if (Directory.Exists(path)) { filename = Path.Combine(path, this.Name); } else { filename = path; } if (progress != null) { progress.SetMessage("Extracting " + this.Name + "."); } using (FileStream file = File.Create(filename)) { using (Stream stream = this.Data.GetStream()) { stream.CopyToCount(file, this.Data.GetSize(), progress); } } }
public override void Export(String foldername, IProgressReport progress = null) { string filename; if (Directory.Exists(foldername)) { filename = Path.Combine(foldername, this.Name); } else { filename = foldername; } if (progress != null) { progress.SetMessage("Extracting " + this.Name + "."); } switch (Properties.Settings.Default.ExportResourcesChoice) { case Settings.ExportResourcesChoice.RSC7: { using (FileStream file = File.Create(filename)) { using (BinaryWriter writer = new BinaryWriter(new StreamKeeper(file))) { // big endian resource 7 for now writer.Write("RSC7".ToArray()); writer.Write(Structs.SwapEndian((uint)this.Version)); writer.Write(Structs.SwapEndian(this.SystemFlag)); writer.Write(Structs.SwapEndian(this.GraphicsFlag)); } using (Stream stream = this.Data.GetStream()) { stream.CopyToCount(file, this.Data.GetSize(), progress); } } break; } case Settings.ExportResourcesChoice.SYSGFX: { if (progress != null) { progress = new SubProgressReport(progress, (int)(this.SystemSize + this.GraphicsFlag)); } using (Stream stream = this.Data.GetStream()) { // If there is no graphics information, no need to extract into two files string sysExtension = this.GraphicSize == 0 ? "" : ".sys"; if (this.SystemSize != 0) { using (FileStream file = File.Create(filename + sysExtension)) { stream.CopyToCount(file, this.SystemSize, progress == null ? null : new SubProgressReport(progress, 0, this.SystemSize)); } } if (this.GraphicSize != 0) { using (FileStream file = File.Create(filename + ".gfx")) { stream.CopyToCount(file, this.GraphicSize, progress == null ? null : new SubProgressReport(progress, this.SystemSize, (int)(this.SystemSize + this.GraphicsFlag))); } } } break; } case Settings.ExportResourcesChoice.RAW: { using (FileStream file = File.Create(filename)) { // Well, it isn't REALLY raw. We are rewriting it, so of the regular random-header, there are zeros, //but it is close enough, that information is random anyway this.Write(file); if (progress != null) { progress.SetProgress(progress.GetFullValue()); } } break; } } }
public void SetMessage(string message) { Parent.SetMessage(message); }
/* TODO: * private void WriteDataInline(Stream stream, List<Entry> entries, Dictionary<Entry, Structs.RPF7EntryInfoTemplate> entriesInfo, int headersEnd) * { * Range<FileEntry> oldFileLayout = new Range<FileEntry>(Math.Max(stream.Length, (long)headersEnd)); * List<FileEntry> emptyEntries = new List<FileEntry>(); * List<FileEntry> moveEntries = new List<FileEntry>(); * List<FileEntry> newEntries = new List<FileEntry>(); * // Entries that should be written to temporary files * List<FileEntry> newSavedEntries = new List<FileEntry>(); * * // A dictionary of the raw data stream that we need to write to the file * Dictionary<FileEntry, Stream> entriesStream = new Dictionary<FileEntry, System.IO.Stream>(); * * // Add the header * oldFileLayout.AddItem(0, headersEnd, null); * * foreach (Entry entry in entries) * { * FileEntry fentry = entry as FileEntry; * if (fentry != null) * { * * // We need to find all the files that depends on the origianl stream first * FileStreamCreator originalStream = fentry.TryGetOriginalFileStreamCreator(); * if (fentry.Data.GetSize() == 0 && fentry.IsRegularFile() && !((RegularFileEntry)fentry).Compressed) * { * emptyEntries.Add(fentry); * } * else if (originalStream != null && originalStream.FileStream == this.Stream) * { * if (originalStream.Offset < headersEnd) { * moveEntries.Add(fentry); * } * if (!oldFileLayout.AddItem(originalStream.Offset, originalStream.Size, fentry, false)) * { * // If failed for some reason.. well it can happen if two entries have the same data. Anyway I don't want that two entries will use the same data. * newSavedEntries.Add(fentry); * } * else * { * entriesStream[fentry] = new PartialStream(this.Stream, originalStream.Offset, originalStream.Size); * } * } * else if (fentry.Data is FileStreamCreator && ((FileStreamCreator)fentry.Data).FileStream == this.Stream) * { * // This file points to the original file, but something about it changed (compression, encryption, ..) * newSavedEntries.Add(fentry); * } * // From here are entries that are not depends on the original strema * else if ((fentry.IsRegularFile() && ((RegularFileEntry)fentry).Compressed) || fentry.IsResource()) * { * newSavedEntries.Add(fentry); * } * else * { * entriesStream[fentry] = fentry.Data.GetStream(); * newEntries.Add(fentry); * } * } * } * * foreach (FileEntry entry in newSavedEntries) * { * string filepath = Path.GetTempFileName(); * // Let's copy the file to temp folder, this file will be deleted on close * FileStream writeStream = new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete, 0x1000, FileOptions.DeleteOnClose); * * entry.Data.GetStream().CopyTo(writeStream); * * // Take an handle to the file, so it will be delete only when this handle will be closed. * FileStream readStream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); * writeStream.Close(); * * entriesStream[entry] = writeStream; * } * * Range<FileEntry> newFileLayout = new Range<FileEntry>(); * } */ public void Write(Stream stream, IProgressReport progressReport = null) { if (progressReport != null) { progressReport.SetMessage("Preparing..."); progressReport.SetProgress(-1); } if (this.Filename == "") { throw new Exception("Can't save"); } // Get all the entries List <Entry> entries = new List <Entry>(); this.Root.AddToList(entries); Dictionary <Entry, Structs.RPF7EntryInfoTemplate> entriesInfo = new Dictionary <Entry, Structs.RPF7EntryInfoTemplate>(); foreach (Entry entry in entries) { Structs.RPF7EntryInfoTemplate entryInfo = new Structs.RPF7EntryInfoTemplate(); // update the is resource field entryInfo.Field1 = (entry is ResourceEntry) ? 1U : 0U; entriesInfo[entry] = entryInfo; } int shiftNameAccessBy; Stream names = WriteNames(entries, entriesInfo, out shiftNameAccessBy); // Fill the header Info.EntriesCount = entries.Count; Info.ShiftNameAccessBy = shiftNameAccessBy; Info.EntriesNamesLength = (int)names.Length; // Go to current position stream.Seek(0x10 + 0x10 * Info.EntriesCount + Info.EntriesNamesLength, SeekOrigin.Begin); // align to 0x200 if (stream.Position % (1 << 9) != 0) { stream.Write(new byte[(1 << 9) - ((int)stream.Position % (1 << 9))], 0, (1 << 9) - ((int)stream.Position % (1 << 9))); } WriteData(stream, entries, entriesInfo, progressReport); long end = stream.Position; using (Stream writer = AES.EncryptStream(new StreamKeeper(stream), sixteenRoundsDecrypt)) { int currentFreeIndex = 1; // Last finish to build and write the file stream.Seek(0, SeekOrigin.Begin); Info.Write(stream); Queue <Entry> entriesToProcess = new Queue <Entry>(); entriesToProcess.Enqueue(this.Root); while (entriesToProcess.Count > 0) { Entry entry = entriesToProcess.Dequeue(); if (entry is DirectoryEntry) { Structs.RPF7EntryInfoTemplate entryInfo = entriesInfo[entry]; IList <Entry> subentries = (entry as DirectoryEntry).GetEntries(); // Update the info on the sub entries entryInfo.Field5 = (uint)currentFreeIndex; entryInfo.Field6 = (uint)subentries.Count; entriesInfo[entry] = entryInfo; // Process the sub entries foreach (Entry subentry in subentries) { entriesToProcess.Enqueue(subentry); } currentFreeIndex += subentries.Count; } // Write the entry info entriesInfo[entry].Write(writer); } // Write names names.Seek(0, SeekOrigin.Begin); names.CopyTo(writer); } // Seek to end stream.Seek(end, SeekOrigin.Begin); // Done! }