public void Save(string filename) { long bk; labelCount = 0; if (type == 2) { using (BinaryWriterX br = new BinaryWriterX(File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write))) { br.Write(pckEntries.Count); for (int i = 0; i < pckEntries.Count; i++) { br.WriteStruct <pckEntryStruct>(pckEntries[i]); } for (int i = 0; i < pckEntries.Count; i++) { int offset = (int)br.BaseStream.Length; int basis = 0; if (pckCrc32Count[i] != -1) { br.Write((short)0x64); br.Write((short)pckCrc32Count[i]); br.BaseStream.Position += pckCrc32Count[i] * 4; basis = pckCrc32Count[i] * 4 + 4; } BinaryReaderX br2 = createCfg(i); br2.BaseStream.Position = 0; br.Write(br2.ReadBytes((int)br2.BaseStream.Length)); bk = br.BaseStream.Position; br.BaseStream.Position = i * 3 * 4 + 4 + 4; br.Write(offset); br.Write((int)br2.BaseStream.Length + 4 + pckCrc32Count[i] * 4); br.BaseStream.Position = bk; } br.Close(); } } else if (type == 1) { using (BinaryWriterX br = new BinaryWriterX(File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write))) { BinaryReaderX br2 = createCfg(0); br2.BaseStream.Position = 0; br.Write(br2.ReadBytes((int)br2.BaseStream.Length)); br.Close(); } } }
public static string Pack(string filename, string path) { string result = "Files successfully packed."; if (Directory.Exists(path)) { FileStream fs = System.IO.File.Create(filename); BinaryWriterX bw = new BinaryWriterX(fs); try { string[] files = Directory.GetFiles(path, "*.msbt"); UInt32 offsetsLength = ((UInt32)files.Length + 1) * (sizeof(UInt32) * 2); UInt32 runningTotal = 0; foreach (string file in files) { FileInfo fi = new FileInfo(file); UInt32 offset = offsetsLength + runningTotal; UInt32 size = (UInt32)fi.Length; runningTotal += (UInt32)fi.Length; bw.Write(offset); bw.Write(size); } bw.Write(0x00000000); bw.Write(0x00000000); foreach (string file in files) { FileStream fs2 = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read); BinaryReaderX br = new BinaryReaderX(fs2); bw.Write(br.ReadBytes((Int32)fs2.Length)); br.Close(); } } catch (Exception ex) { result = ex.Message; } finally { bw.Close(); } } return(result); }
/// <summary> /// Creates an RARC archive from the given directory and settings. /// </summary> /// <param name="directory">The directory to be converted to an RARC archive.</param> /// <param name="archiveType">The type of archive this will be treated as.</param> /// <param name="compressionType">The compression type of the final archive, if one is desired.</param> public RARC(string directory, ArchiveType archiveType = ArchiveType.MemoryArchive, CompressionType compressionType = CompressionType.None) { if (!Directory.Exists(directory)) { throw new ArgumentException("Constructor expects a valid directory!", nameof(directory)); } var archiveName = $"{Path.GetFileName(directory)}.arc"; if (compressionType != CompressionType.None) { archiveName += compressionType == CompressionType.SZP ? ".szp" : ".szs"; } var archiveFileName = Path.Combine(Path.GetDirectoryName(directory), archiveName); using var writer = new BinaryWriterX(File.Create(archiveFileName), ByteOrder.BigEndian); Header = new RARCHeader(); CreateArchive(writer, directory, archiveType, compressionType); writer.Close(); // Compress the archive if requested if (compressionType != CompressionType.None) { var fileData = File.ReadAllBytes(archiveFileName); switch (compressionType) { case CompressionType.SZP: var szpData = Yay0.Compress(fileData); if (szpData.Length < fileData.Length) { File.WriteAllBytes(archiveFileName, szpData); } break; case CompressionType.SZS: var szsData = Yaz0.Compress(fileData); if (szsData.Length < fileData.Length) { File.WriteAllBytes(archiveFileName, szsData); } break; } } }
// Saving public bool Save(string filename) { bool result = false; try { using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)) { BinaryWriterX bw = new BinaryWriterX(fs); // Byte Order bw.ByteOrder = Header.ByteOrderMark[0] > Header.ByteOrderMark[1] ? ByteOrder.LittleEndian : ByteOrder.BigEndian; // Header bw.WriteASCII(Header.Identifier); bw.Write(Header.ByteOrderMark); bw.Write(Header.Unknown1); bw.Write((byte)Header.EncodingByte); bw.Write(Header.Unknown2); bw.Write(Header.NumberOfSections); bw.Write(Header.Unknown3); bw.Write(Header.FileSize); bw.Write(Header.Unknown4); foreach (string section in SectionOrder) { if (section == "LBL1") { WriteLBL1(bw); } else if (section == "NLI1") { WriteNLI1(bw); } else if (section == "ATO1") { WriteATO1(bw); } else if (section == "ATR1") { WriteATR1(bw); } else if (section == "TSY1") { WriteTSY1(bw); } else if (section == "TXT2") { WriteTXT2(bw); } } // Update FileSize long fileSize = bw.BaseStream.Position; bw.BaseStream.Seek(Header.FileSizeOffset, SeekOrigin.Begin); bw.Write((uint)fileSize); bw.Close(); result = true; } } catch (Exception) { } return(result); }
// Manipulation //TODO: Manipulation functions // Saving public bool Save(string filename) { bool result = false; try { using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)) { BinaryWriterX bw = new BinaryWriterX(fs); // Header bw.WriteASCII(Header.Identifier + "\0"); bw.Write(Header.Unknown1); bw.Write(Header.Unknown2); bw.Write(Header.Unknown3); bw.Write(Header.NumberOfLabels); bw.Write(Header.NumberOfOffsets); bw.Write(Header.Unknown4); long dataSizeOffset = bw.BaseStream.Position; bw.Write(Header.DataSize); bw.Write(Header.NameLength); bw.WriteASCII(Header.Name + "\0"); foreach (Label label in Labels) { bw.Write(label.ID); bw.Write(label.Unknown1); bw.Write(label.Unknown2); bw.Write(label.Unknown3); bw.Write(label.Unknown4); } bw.Write(Unknown1024); // Read in the label names foreach (Label label in Labels) { bw.WriteASCII(label.Name); bw.Write(new byte[] { 0x0 }); } // Read in the text data uint dataSize = 0; foreach (Label label in Labels) { bw.Write(label.Text); bw.Write(new byte[] { 0x0 }); dataSize += (uint)label.Text.Length + 1; } // Update DataSize bw.BaseStream.Seek(dataSizeOffset, SeekOrigin.Begin); bw.Write(dataSize); bw.Close(); result = true; } } catch (Exception) { } return(result); }
// Injector private void workerInjector_DoWork(object sender, DoWorkEventArgs e) { List <Entry> injectedEntries = new List <Entry>(); // Sort Entries if (_kup.OptimizeStrings) { _kup.Entries = _kup.Entries.Select(o => o).OrderByDescending(o => _kup.Encoding.GetByteCount(o.EditedText)).ThenBy(o => o.EditedText).ToList(); } // Bound Setup foreach (Bound bound in _kup.StringBounds) { bound.NextAvailableOffset = bound.StartLong; } // Copy Injection File File.Copy(txtFilename.Text, txtFilename.Text + ".injected", true); FileInfo codeFile = new FileInfo(txtFilename.Text + ".injected"); // Begin Injection FileStream fs = new FileStream(codeFile.FullName, FileMode.Open, FileAccess.Write, FileShare.Read); BinaryWriterX bw = new BinaryWriterX(fs, ByteOrder.LittleEndian); _workerInjector.ReportProgress(0, "STATUS|Injecting strings..."); bool outOfSpace = false; int count = 0, optimizedCount = 0; foreach (Entry entry in _kup.Entries) { byte[] editedText = _kup.Encoding.GetBytes(entry.EditedText); count++; if (entry.Relocatable) { // Optimization pass bool optimized = false; if (_kup.OptimizeStrings) { foreach (Entry injectedEntry in injectedEntries) { if (injectedEntry.EditedText.EndsWith(entry.EditedText)) { byte[] injectedText = _kup.Encoding.GetBytes(injectedEntry.EditedText); // Update the pointer foreach (Pointer pointer in entry.Pointers) { bw.BaseStream.Seek(pointer.AddressLong, SeekOrigin.Begin); bw.Write((uint)(injectedEntry.InjectedOffsetLong + (injectedText.Length - editedText.Length) + _kup.RamOffsetUInt)); } optimized = true; optimizedCount++; break; } } } if (!optimized) { // Select bound Bound bound = null; foreach (Bound stringBound in _kup.StringBounds) { if (!stringBound.Full && stringBound.Injectable && editedText.Length < stringBound.SpaceRemaining) { bound = stringBound; break; } } if (bound != null) { // Update the pointer foreach (Pointer pointer in entry.Pointers) { bw.BaseStream.Seek(pointer.AddressLong, SeekOrigin.Begin); bw.Write((uint)(bound.NextAvailableOffset + _kup.RamOffsetUInt)); } // Write the string bw.BaseStream.Seek(bound.NextAvailableOffset, SeekOrigin.Begin); bw.Write(editedText); entry.InjectedOffsetLong = bound.NextAvailableOffset; if (_kup.Encoding.IsSingleByte) { bw.Write(new byte[] { 0x0 }); } else { bw.Write(new byte[] { 0x0, 0x0 }); } bound.NextAvailableOffset = bw.BaseStream.Position; injectedEntries.Add(entry); } else { // Ran out of injection space outOfSpace = true; break; } } } else { // In place string update bw.BaseStream.Seek(entry.OffsetLong, SeekOrigin.Begin); var start = bw.BaseStream.Position; bw.Write(editedText, 0, Math.Min(editedText.Length, entry.MaxLength)); if (_kup.Encoding.IsSingleByte) { if (entry.MaxLength - (bw.BaseStream.Position - start) > 0) { bw.Write(new byte[] { 0x0 }); } } else { if (entry.MaxLength - (bw.BaseStream.Position - start) > 1) { bw.Write(new byte[] { 0x0, 0x0 }); } } } _workerInjector.ReportProgress((int)(((double)count) / ((double)_kup.Entries.Count) * prgBottom.Maximum), "BOTTOM"); } if (outOfSpace) { _workerInjector.ReportProgress(0, "STATUS|The injector has run out of space to inject strings."); _workerInjector.ReportProgress(0, "STATUS|Injected " + injectedEntries.Count + " strings..."); if (_kup.OptimizeStrings) { _workerInjector.ReportProgress(0, "STATUS|Optimized " + optimizedCount + " strings..."); } _workerInjector.ReportProgress(0, "STATUS|" + (_kup.Entries.Count - count) + " strings were not injected."); } else { _workerInjector.ReportProgress(0, "STATUS|Injected " + injectedEntries.Count + " strings..."); if (_kup.OptimizeStrings) { _workerInjector.ReportProgress(0, "STATUS|Optimized " + optimizedCount + " strings..."); } } bw.Close(); }
public bool Save(string filename) { bool result = false; try { using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None)) { BinaryWriterX bw = new BinaryWriterX(fs); // Header bw.WriteASCII(Header.Identifier); uint fileSizeOffset = (uint)bw.BaseStream.Position; bw.Write(Header.FileSize); bw.Write(Header.NumberOfEntries); bw.Write(Header.Version); uint labelsOffset = 0; if (Header.Version == 0x11) { bw.Write(Header.HasLabels); labelsOffset = (uint)bw.BaseStream.Position; bw.Write(Header.LabelsOffset - Header.Size); } uint entryStart = Header.Size; uint textStart = (uint)bw.BaseStream.Position + (uint)(Labels.Count * 2 * 8); // Text bw.BaseStream.Seek(textStart, SeekOrigin.Begin); for (int i = 0; i < Header.NumberOfEntries; i++) { Label label = Labels[i]; label.TextOffset = (uint)bw.BaseStream.Position - Header.Size; bw.Write(FileEncoding.GetBytes(label.Text)); bw.Write(new byte[] { 0x0, 0x0 }); } // Extra for (int i = 0; i < Header.NumberOfEntries; i++) { Label label = Labels[i]; label.ExtraOffset = (uint)bw.BaseStream.Position - Header.Size; bw.Write(FileEncoding.GetBytes(label.Extra)); bw.Write(new byte[] { 0x0, 0x0 }); } // Pad to the nearest 8 bytes PaddingWrite(bw, Header.Version == 0x11 ? 8 : 4); // Set label offset variables uint labelsOffsets = (uint)bw.BaseStream.Position; uint labelsStart = (uint)bw.BaseStream.Position + (uint)(Labels.Count * 4); // Grab the new LabelsOffset if (Header.HasLabels == 0x0101) { Header.LabelsOffset = (uint)bw.BaseStream.Position - Header.Size; } else { Header.LabelsOffset = 0; } // Text Offsets bw.BaseStream.Seek(entryStart, SeekOrigin.Begin); for (int i = 0; i < Header.NumberOfEntries; i++) { Label label = Labels[i]; bw.Write(label.TextID); bw.Write(label.TextOffset); } // Extra Offsets for (int i = 0; i < Header.NumberOfEntries; i++) { Label label = Labels[i]; bw.Write(label.ExtraID); bw.Write(label.ExtraOffset); } // Labels if (Header.HasLabels == 0x0101) { // Label Names bw.BaseStream.Seek(labelsStart, SeekOrigin.Begin); for (int i = 0; i < Header.NumberOfEntries; i++) { Label label = Labels[i]; label.NameOffset = (uint)bw.BaseStream.Position - Header.Size; bw.WriteASCII(label.Name); bw.Write((byte)0x0); } // Pad to the nearest 8 bytes PaddingWrite(bw, Header.Version == 0x11 ? 8 : 4); // Label Offsets bw.BaseStream.Seek(labelsOffsets, SeekOrigin.Begin); for (int i = 0; i < Header.NumberOfEntries; i++) { bw.Write(Labels[i].NameOffset); } // Update LabelsOffset bw.BaseStream.Seek(labelsOffset, SeekOrigin.Begin); bw.Write(Header.LabelsOffset); } // Update FileSize Header.FileSize = (uint)bw.BaseStream.Length; bw.BaseStream.Seek(fileSizeOffset, SeekOrigin.Begin); bw.Write(Header.FileSize); bw.Close(); } result = true; } catch (Exception) { } return(result); }
/// <summary> /// Writes the current <see cref="CpkTable"/> data to the output <see cref="Stream"/>. /// </summary> /// <param name="output"></param> public void Save(Stream output) { using (var bw = new BinaryWriterX(output, true)) { var valuesOffset = 0; var binaryOffset = 0; var nameOffset = 0; // Write the main header bw.WriteType(Header); // Switch to BE bw.ByteOrder = ByteOrder.BigEndian; // Write the table info bw.WriteType(TableInfo); #region Strings var strings = new Dictionary <string, int>(); var stringStream = new BinaryWriterX(new MemoryStream()); void AddString(string str) { if (strings.ContainsKey(str)) { return; } strings.Add(str, (int)stringStream.BaseStream.Position); stringStream.WriteString(str, Encoding.ASCII, false); } // NULL AddString("<NULL>"); // Table name AddString(Name); // Column names and constant value strings foreach (var column in Columns) { AddString(column.Name); if (column.Storage == CpkColumnStorage.Const && column.Type == CpkDataType.String) { AddString((string)column.Value.Value); } } // Row column value strings foreach (var row in Rows) { foreach (var column in Columns) { if (column.Storage == CpkColumnStorage.Row && column.Type == CpkDataType.String) { AddString((string)row[column.Name].Value); } } } // Reset string stream position stringStream.BaseStream.Position = 0; #endregion #region Data // TODO: Handle saving binary data columns #endregion // Write out columns foreach (var column in Columns) { var flags = (byte)((int)column.Storage ^ (int)column.Type); bw.Write(flags); bw.Write(strings[column.Name]); switch (column.Storage) { case CpkColumnStorage.Const: WriteValue(bw, column.Value, column, strings); break; } } // Write out rows foreach (var row in Rows) { foreach (var column in Columns) { if (column.Storage == CpkColumnStorage.Row) { WriteValue(bw, row[column.Name], column, strings); } } } // Update Strings Offset and write out the stings TableInfo.StringsOffset = (int)bw.BaseStream.Position - 0x18; stringStream.BaseStream.CopyTo(bw.BaseStream); stringStream.Close(); // Align to nearest 8 bytes bw.WriteAlignment(8); } }
public static string Extract(string filename, string path, bool overwrite = true) { string result = "Files successfully extracted."; if (File.Exists(filename) && new FileInfo(filename).Length > 0) { FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None); BinaryReaderX br = new BinaryReaderX(fs); try { // Read in file headers List <FileEntry> entries = new List <FileEntry>(); FileEntry entry = new FileEntry(); uint index = 0; while (1 == 1 && br.BaseStream.Position < br.BaseStream.Length) { entry.Offset = br.ReadUInt32(); entry.Size = br.ReadUInt32(); entry.Index = index; if (entry.Offset == 0 && entry.Size == 0) { break; } else { entries.Add(entry); } entry = new FileEntry(); index++; } // Extract! for (int i = 0; i < entries.Count; i++) { FileEntry fe = entries[i]; string extension = ".msbt"; string outFile = Path.Combine(path, fe.Index.ToString("00000000") + extension); Debug.Print("[" + fe.Offset.ToString("X8") + "] " + fe.Index + extension); if (!File.Exists(outFile) || (File.Exists(outFile) && overwrite)) { FileStream fsr = new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None); BinaryWriterX bw = new BinaryWriterX(fsr); br.BaseStream.Seek(fe.Offset, SeekOrigin.Begin); bw.Write(br.ReadBytes((int)fe.Size)); bw.Close(); } } result = entries.Count + " files were found and " + entries.Count + " files were successfully extracted!"; } catch (InvalidUMSBTException ibex) { result = ibex.Message; } catch (Exception ex) { result = ex.Message; } finally { br.Close(); } } return(result); }
public static string Extract(string filename, string path, bool overwrite = true) { string result = "Files successfully extracted."; if (File.Exists(filename) && new FileInfo(filename).Length > 0) { FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None); BinaryReaderX br = new BinaryReaderX(fs); try { string magic = Encoding.ASCII.GetString(br.ReadBytes(4)); if (magic != "BG4\0") { throw new InvalidBG4Exception("The file provided is not a valid BG4 archive."); } ushort Constant1 = br.ReadUInt16(); ushort NumberOfHeaders = br.ReadUInt16(); uint SizeOfHeaders = br.ReadUInt32(); ushort NumberOfHeadersDerived = br.ReadUInt16(); ushort NumberOfHeadersMultiplier = br.ReadUInt16(); // Read in file headers List <FileEntry> entries = new List <FileEntry>(); FileEntry entry = new FileEntry(); for (int i = 0; i < NumberOfHeaders; i++) { uint offsetTemp = br.ReadUInt32(); if ((offsetTemp & 0x80000000) == 0x80000000) { entry.Compressed = true; } entry.Offset = entry.Compressed ? (offsetTemp ^ 0x80000000) : offsetTemp; entry.Size = br.ReadUInt32(); entry.Unknown1 = br.ReadUInt32(); entry.NameIndex = br.ReadUInt16(); if (entry.Unknown1 != 0xFFFFFFFF) { entries.Add(entry); } entry = new FileEntry(); } // Sort the file entries into NameIndex order entries.Sort(); // Read in file names bool eofn = false; List <string> filenames = new List <string>(); while (!eofn) { if (br.PeekString(2) == Encoding.ASCII.GetString(new byte[] { 0xFF, 0xFF })) { eofn = true; } else { bool eos = false; string name = string.Empty; while (!eos) { byte chr = br.ReadByte(); if (chr == 0x00) { eos = true; } else { name += (char)chr; } } if (name != "(invalid)") { filenames.Add(name); } } } // Extract! for (int i = 0; i < entries.Count; i++) { FileEntry fe = entries[i]; string extension = (!Regex.IsMatch(filenames[i], @"\..*?$") ? ".bin" : string.Empty); if (extension != string.Empty) { br.BaseStream.Seek(fe.Offset, SeekOrigin.Begin); magic = Encoding.ASCII.GetString(br.ReadBytes(8)); if (magic.StartsWith("MsgStdBn")) { extension = ".msbt"; } else if (magic.StartsWith("BCH")) { extension = ".bch"; } else if (magic.StartsWith("PTX")) { extension = ".ptx"; } // TODO: Add more known magic/extension pairs } Debug.Print("[" + fe.Offset.ToString("X8") + "] " + fe.NameIndex + " (" + fe.Unknown1 + ") " + filenames[i] + extension); FileInfo fi = new FileInfo(filename); FileStream fsr = new FileStream(Path.Combine(path, filenames[i] + extension), FileMode.Create, FileAccess.Write, FileShare.None); BinaryWriterX bw = new BinaryWriterX(fsr); br.BaseStream.Seek(fe.Offset, SeekOrigin.Begin); bw.Write(br.ReadBytes((int)fe.Size)); bw.Close(); } result = NumberOfHeaders + " header(s) were scanned and " + entries.Count + " files were successfully extracted!"; } catch (InvalidBG4Exception ibex) { result = ibex.Message; } catch (Exception ex) { result = ex.Message; } finally { br.Close(); } } return(result); }