public void CharStringWrites() { var expect = new byte[] { 0x33, 0x34, 0x34, 0x02, 0x35, 0x35, 0x06, 0x36, 0x00, 0x36, 0x00, 0x00, 0x00, 0x03, 0x37, 0x37, 0x00, 0x38, 0x38, 0x00, 0x02, 0x38, 0x38, 0x38, 0x38 }; var ms = new MemoryStream(); using (var bw = new BinaryWriterX(ms)) { bw.Write('3'); bw.Write(new char[] { '4', '4' }); bw.Write("55"); bw.WriteString("66", Encoding.Unicode); bw.WriteString("77", Encoding.GetEncoding("SJIS")); bw.WriteString("88", Encoding.ASCII, false, true); bw.WriteString("88", Encoding.ASCII, true, false); bw.WriteString("88", Encoding.ASCII, false, false); Assert.IsTrue(ms.ToArray().SequenceEqual(expect)); } }
private void WriteStrings(Stream output, IList <IArchiveFileInfo> afis) { var directories = new HashSet <string>(); var files = new List <string>(afis.Count); foreach (var file in OrderFiles(afis)) { directories.Add(file.FilePath.GetDirectory().ToRelative().FullName + "/"); files.Add(file.FilePath.GetName()); } var strings = new MemoryStream(); using var bw = new BinaryWriterX(strings, true); foreach (var s in directories) { bw.WriteString(s, Encoding.ASCII, false); } foreach (var s in files) { bw.WriteString(s, Encoding.ASCII, false); } var compStrings = new MemoryStream(); XfsaSupport.Compress(strings, compStrings, Level5CompressionMethod.Lz10); compStrings.CopyTo(output); while (output.Position % 4 > 0) { output.WriteByte(0); } }
public void Save(Stream output, ImageInfo imageInfo) { using var bw = new BinaryWriterX(output); // Calculate offsets var texOffset = HeaderSize + imageInfo.ImageData.Length; // Write image data bw.WriteType(new ImgHeader { magic = "IMG0", size = imageInfo.ImageData.Length }); bw.Write(imageInfo.ImageData); // Write tex header bw.WriteType(new ImgHeader { magic = "TEXR", size = 0x10 }); bw.WriteType(new ImgEntry { width = imageInfo.ImageSize.Width, height = imageInfo.ImageSize.Height }); // Write end header bw.WriteString("!END", Encoding.ASCII, false, false); bw.WritePadding(3); }
/// <summary> /// /// </summary> /// <param name="output"></param> /// <returns></returns> public bool Save(Stream output) { using (var bw = new BinaryWriterX(output, true)) { bw.WriteType(_header); bw.BaseStream.Position = 0x40; bw.WriteMultiple(_padding); var offsetTablePos = bw.BaseStream.Position; bw.BaseStream.Position += (0x14 * _header.FileCount); foreach (var b in Bitmaps) { bw.WriteString(b.Name, System.Text.Encoding.ASCII, false, true); } var newOffsets = new List <OffsetEntry>(); foreach (var b in Bitmaps) { var kbi = b as KsltBitmapInfo; newOffsets.Add(new OffsetEntry() { Offset = (int)bw.BaseStream.Position }); kbi.Header.Width = (short)kbi.Image.Width; kbi.Header.Height = (short)kbi.Image.Height; kbi.Header.DataSize = kbi.ImageData.Length; bw.WriteType(kbi.Header); bw.Write(kbi.ImageData); } bw.BaseStream.Position = offsetTablePos; bw.WriteMultiple(newOffsets); } return(true); }
public void Save(Stream output, TextEntry textEntry) { using (var bw = new BinaryWriterX(output, true)) { _content.CharacterCount = (short)textEntry.EditedText.Trim().Length; _content.CharacterDataSize = (short)Encoding.UTF8.GetByteCount(textEntry.EditedText); bw.WriteType(_content); bw.WriteType(_drawingFrames[0]); short newFrame = _drawingFrames[0].FrameCounter; string TextLength = textEntry.EditedText.Trim(); TextLength = TextLength.Replace("\r", "").Replace("\n", ""); for (var i = 1; i < TextLength.Length; i++) { bw.WriteType(_drawingFrames[0].Indicator); newFrame += 0x0C; bw.Write(newFrame); } for (var i = 0; i < TextLength.Length; i++) { bw.WriteType(_colorStructs[0]); } bw.WriteString(textEntry.EditedText, Encoding.UTF8, false); } }
public void Save(Stream output, IList <IArchiveFileInfo> files) { // Wrap encryption output = new XorStream(output, _selectedKey); using var bw = new BinaryWriterX(output, ByteOrder.BigEndian); // Calculate offsets var sizeOffset = 2 + files.Sum(x => Encoding.UTF8.GetByteCount(x.FilePath.ToRelative().FullName)) + files.Count * 2; var dataOffset = sizeOffset + 2 + files.Count * 4; // Write files output.Position = dataOffset; foreach (var file in files.Cast <ArchiveFileInfo>()) { file.SaveFileData(output); } // Write sizes output.Position = sizeOffset; bw.Write((short)files.Count); bw.WriteMultiple(files.Select(x => (int)x.FileSize)); // Write names output.Position = 0; bw.Write((short)files.Count); foreach (var file in files) { var name = file.FilePath.ToRelative().FullName; bw.Write((short)Encoding.UTF8.GetByteCount(name)); bw.WriteString(name, Encoding.UTF8, false, false); } }
/// <summary> /// /// </summary> /// <param name="output"></param> public void Save(Stream output) { using (var bw = new BinaryWriterX(output, true)) { // Updates Header.Width = (short)Texture.Width; Header.Height = (short)Texture.Height; // Header bw.WriteType(Header); bw.WriteAlignment(); bw.WriteString(FileName, Encoding.ASCII, false); bw.WriteAlignment(); // Setup if (Header.Format == ImageFormat.Palette_8) { var settings = new PaletteImageSettings(Formats[ImageFormat.RGBA8888], PaletteFormats[ImageFormat.Palette_8], Header.Width, Header.Height); var data = Common.Save(Texture, Palette, settings); bw.Write(data.indexData); bw.Write(data.paletteData); } else { var settings = new ImageSettings(Formats[ImageFormat.RGBA8888], Header.Width, Header.Height); var data = Common.Save(Texture, settings); bw.Write(data); } } }
public void Save(Stream binOutput, Stream arcOutput, IList <IArchiveFileInfo> files) { using var binBw = new BinaryWriterX(binOutput); using var arcBw = new BinaryWriterX(arcOutput); // Calculate offsets var fileOffset = 0x10; var entryOffset = 0x20; var offsetsOffset = entryOffset + files.Count * EntrySize; var stringOffset = offsetsOffset + ((files.Count * 4 + 0xF) & ~0xF); // Write files var offsets = new List <int>(); var entries = new List <PaaEntry>(); var filePosition = fileOffset; var stringPosition = stringOffset; foreach (var file in files.Cast <PaaArchiveFileInfo>()) { arcOutput.Position = filePosition; var writtenSize = file.SaveFileData(arcOutput); arcBw.WriteAlignment(); file.Entry.size = (int)writtenSize; file.Entry.nameOffset = stringPosition; offsets.Add(filePosition); entries.Add(file.Entry); filePosition += ((int)writtenSize + 0xF) & ~0xF; stringPosition += (file.FilePath.ToRelative().FullName.Length + 1 + 0xF) & ~0xF; } // Write strings binOutput.Position = stringOffset; foreach (var file in files) { binBw.WriteString(file.FilePath.ToRelative().FullName, Encoding.ASCII, false); binBw.WriteAlignment(); } // Write offsets binOutput.Position = offsetsOffset; binBw.WriteMultiple(offsets); // Write entries binOutput.Position = entryOffset; binBw.WriteMultiple(entries); // Write header binOutput.Position = 0; _header.fileCount = files.Count; _header.entryOffset = entryOffset; _header.offsetsOffset = offsetsOffset; _header.unk2 = _header.fileCount / 2; binBw.WriteType(_header); }
private long WriteEntries(BinaryWriterX bw, DirectoryEntry entry, Stream imgStream) { // Collect offsets var entryOffset = bw.BaseStream.Position; var stringOffset = entryOffset + (entry.Directories.Count + entry.Files.Count) * EntrySize; var entryEndOffset = stringOffset + entry.Directories.Sum(x => EucJpEncoding.GetByteCount(x.Name) + 1) + entry.Files.Sum(x => EucJpEncoding.GetByteCount(x.FilePath.GetName()) + 1); entryEndOffset = (entryEndOffset + 0x3) & ~0x3; // Create holder entries var entries = entry.Directories.Select(x => new DdtInfoHolder(x)) .Concat(entry.Files.Select(x => new DdtInfoHolder(x))) .OrderBy(x => x.Name, StringComparer.Ordinal) .ToArray(); // Write files foreach (var file in entries.Where(x => x.IsFile)) { file.Entry.entryOffset = (uint)(imgStream.Position / Alignment_); file.Entry.entrySize = (int)file.File.FileSize; (file.File as ArchiveFileInfo).SaveFileData(imgStream); while (imgStream.Position % Alignment_ != 0) { imgStream.WriteByte(0); } } // Write deeper directory entries foreach (var directory in entries.Where(x => !x.IsFile)) { directory.Entry.entryOffset = (uint)entryEndOffset; directory.Entry.entrySize = -(directory.Directory.Directories.Count + directory.Directory.Files.Count); bw.BaseStream.Position = entryEndOffset; entryEndOffset = (uint)WriteEntries(bw, directory.Directory, imgStream); } // Write strings bw.BaseStream.Position = stringOffset; foreach (var infoHolder in entries) { infoHolder.Entry.nameOffset = (uint)bw.BaseStream.Position; bw.WriteString(infoHolder.Name, EucJpEncoding, false); } // Write current entries bw.BaseStream.Position = entryOffset; foreach (var infoHolder in entries) { bw.WriteType(infoHolder.Entry); } return(entryEndOffset); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output); var fileEntryStartOffset = _headerSize; var nameStartOffset = _headerSize + files.Count * _fileEntrySize; // Write names var fileOffset = 0; var nameOffset = 0; var fileEntries = new List <Lpc2FileEntry>(); foreach (var file in files) { fileEntries.Add(new Lpc2FileEntry { fileOffset = fileOffset, fileSize = (int)file.FileSize, nameOffset = nameOffset }); bw.BaseStream.Position = nameStartOffset + nameOffset; bw.WriteString(file.FilePath.FullName, Encoding.ASCII, false); nameOffset = (int)bw.BaseStream.Position - nameStartOffset; fileOffset += (int)file.FileSize; } // Write file data var dataOffset = (int)bw.BaseStream.Position; foreach (var file in files.Cast <ArchiveFileInfo>()) { file.SaveFileData(bw.BaseStream, null); } // Write file entries bw.BaseStream.Position = fileEntryStartOffset; foreach (var fileEntry in fileEntries) { bw.WriteType(fileEntry); } // Write header bw.BaseStream.Position = 0; bw.WriteType(new Lpc2Header { fileEntryOffset = fileEntryStartOffset, nameOffset = nameStartOffset, dataOffset = dataOffset, fileCount = files.Count, headerSize = _headerSize, fileSize = (int)bw.BaseStream.Length }); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output, _header.byteOrder); // Calculate offsets var sizeOffset = HeaderSize; var unknownValueOffset = sizeOffset + files.Count * 4; var dataOffset = unknownValueOffset + files.Count * 8; // Write files var offsets = new List <int>(); foreach (var file in files.Cast <PackArchiveFileInfo>()) { offsets.Add(dataOffset); // Write file name output.Position = dataOffset + 8; bw.WriteString(file.FilePath.GetName(), Encoding.ASCII, false); // Pad to file start var alignment = PackSupport.GetAlignment(file.FilePath.GetExtensionWithDot()); output.Position = dataOffset + 0x28; bw.WriteAlignment(alignment); file.Entry.fileStart = (short)(output.Position - dataOffset); // Write file data output.Position = dataOffset + file.Entry.fileStart; var writtenSize = file.SaveFileData(output); var nextOffset = output.Position; // Write file entry file.Entry.fileSize = (uint)writtenSize; output.Position = dataOffset; bw.WriteType(file.Entry); dataOffset = (int)nextOffset; } // Write unknown values output.Position = unknownValueOffset; bw.WriteMultiple(_unknownValues); // Write offsets output.Position = sizeOffset; bw.WriteMultiple(offsets); // Write header _header.fileCount = (short)files.Count; _header.size = (int)output.Length; output.Position = 0; bw.WriteType(_header); }
public void Write(BinaryWriterX bw) { var startPosition = bw.BaseStream.Position; bw.BaseStream.Position += _headerLength; // Write child nodes and data if (Data != null) { Data.Position = 0; Data.CopyTo(bw.BaseStream); // Update header _header.size = (int)(bw.BaseStream.Position - startPosition - 8); bw.WriteAlignment(2); } else { foreach (var node in Nodes) { node.Write(bw); } // Update header _header.size = (int)(bw.BaseStream.Position - startPosition - 8); } var currentPosition = bw.BaseStream.Position; // Write header bw.BaseStream.Position = startPosition; bw.WriteString(_header.magic, Encoding.ASCII, false, false); bw.Write(_header.size); if (_headerLength > 8) { bw.WriteString(_header.description, Encoding.ASCII, false, false); } bw.BaseStream.Position = currentPosition; }
public void Save(Stream output, IList <IArchiveFileInfo> files) { var crc32 = Crc32.Default; using var bw = new BinaryWriterX(output, true); // Calculate offsets var entryOffset = HeaderSize; var nameOffset = entryOffset + files.Count * EntrySize; var dataOffset = (nameOffset + 0x7F) & ~0x7F; // Write files var namePosition = nameOffset; var dataPosition = dataOffset; var entries = new List <JarcEntry>(); foreach (var file in files.Cast <JarcArchiveFileInfo>()) { output.Position = dataPosition; file.SaveFileData(output); entries.Add(new JarcEntry { fileOffset = dataPosition, nameOffset = namePosition, fileSize = (int)file.FileSize, hash = crc32.ComputeValue(file.FilePath.ToRelative().FullName), unk1 = file.Entry.unk1 }); dataPosition += (int)((file.FileSize + 0x7F) & ~0x7F); namePosition += Encoding.ASCII.GetByteCount(file.FilePath.ToRelative().FullName) + 1; } // Write names output.Position = nameOffset; foreach (var file in files) { bw.WriteString(file.FilePath.ToRelative().FullName, Encoding.ASCII, false); } // Write entries output.Position = entryOffset; bw.WriteMultiple(entries); // Write header _header.fileCount = files.Count; _header.fileSize = (int)output.Length; output.Position = 0; bw.WriteType(_header); }
private static void WriteFnt(BinaryWriterX bw, int baseOffset, ref int fntOffset, ref int contentOffset, ref int fileId, ref int dirId, int parentDirId, DirectoryEntry entry) { // Write dir entry bw.BaseStream.Position = fntOffset; bw.WriteType(new MainFntEntry { subTableOffset = contentOffset - baseOffset, firstFileId = (short)fileId, parentDirectory = (ushort)(0xF000 + parentDirId) }); fntOffset += 8; // Write file names bw.BaseStream.Position = contentOffset; foreach (var file in entry.Files.Cast <IFileIdArchiveFileInfo>()) { bw.WriteString(file.FilePath.GetName(), Encoding.ASCII, true, false); file.FileId = fileId++; } contentOffset = (int)bw.BaseStream.Position; // Write directory entries var nextContentOffset = (int)(bw.BaseStream.Position + entry.Directories.Sum(x => x.Name.Length + 3) + 1); var currentDirId = dirId; foreach (var dir in entry.Directories) { bw.BaseStream.Position = contentOffset; bw.Write((byte)(dir.Name.Length + 0x80)); bw.WriteString(dir.Name, Encoding.ASCII, false, false); bw.Write((ushort)(0xF000 + ++dirId)); contentOffset = (int)bw.BaseStream.Position; WriteFnt(bw, baseOffset, ref fntOffset, ref nextContentOffset, ref fileId, ref dirId, currentDirId, dir); } contentOffset = nextContentOffset; }
private void WriteTypeString(BinaryWriterX bw, string writeValue, MemberAttributeInfo fieldAttributes, ValueStorage storage) { var attributeValues = GetLengthAttributeValues(fieldAttributes, storage); if (!attributeValues.HasValue) { return; } var(length, encoding) = attributeValues.Value; if (encoding.GetByteCount(writeValue) != length) { throw new FieldLengthMismatchException(encoding.GetByteCount(writeValue), length); } bw.WriteString(writeValue, encoding, false, false); }
public async void Save(IFileSystem fileSystem, UPath savePath) { using var archiveBw = new BinaryWriterX(await fileSystem.OpenFileAsync(savePath, FileMode.Create, FileAccess.ReadWrite)); using var indexBw = new BinaryWriterX(await fileSystem.OpenFileAsync("index.bin", FileMode.Create, FileAccess.ReadWrite)); archiveBw.WriteString("ARC0", Encoding.UTF8, false, false); indexBw.WriteString("IDX0", Encoding.UTF8, false, false); indexBw.Write(_files.Count); archiveBw.Write(new byte[0xC]); foreach (var file in _files) { indexBw.Write((int)archiveBw.BaseStream.Position); indexBw.Write((int)file.FileSize); file.SaveFileData(archiveBw.BaseStream, null); } }
public void Save(Stream output, ImageInfo imageInfo) { using var bw = new BinaryWriterX(output); // Calculate offsets var nameOffset = HeaderSize; var dataOffset = (nameOffset + imageInfo.Name.Length + 0x10) & ~0xF; // 0x10 = 0x1 + 0xF var paletteOffset = (dataOffset + imageInfo.ImageData.Length + (imageInfo.MipMapData?.Sum(x => x.Length) ?? 0) + 0x3F) & ~0x3F; // Write name output.Position = nameOffset; bw.WriteString(imageInfo.Name, Encoding.ASCII, false); // Write image data output.Position = dataOffset; bw.Write(imageInfo.ImageData); // Write mip levels foreach (var mipData in imageInfo.MipMapData) { bw.Write(mipData); } // Write palette data if (imageInfo.HasPaletteInformation) { output.Position = paletteOffset; bw.Write(imageInfo.PaletteData); } // Update header _header.nameOffset = nameOffset; _header.dataOffset = dataOffset; _header.paletteOffset = paletteOffset; _header.mipLevels = (byte)imageInfo.MipMapCount; _header.format = (byte)imageInfo.ImageFormat; _header.width = (short)imageInfo.ImageSize.Width; _header.height = (short)imageInfo.ImageSize.Height; // Write header output.Position = 0; bw.WriteType(_header); }
public void Save(Stream output, ImageInfo imageInfo) { using var bw = new BinaryWriterX(output); // Calculate offsets var commentOffset = HeaderSize; var paletteOffset = commentOffset + 0x1C; var dataOffset = paletteOffset + (imageInfo.HasPaletteInformation ? GetPaletteDataSize((int)_header.paletteFormat, _header.imageFormat) : 0); // Write image data output.Position = dataOffset; output.Write(imageInfo.ImageData); if (imageInfo.MipMapCount > 0) { foreach (var mipData in imageInfo.MipMapData) { output.Write(mipData); } } // Write palette data if (imageInfo.HasPaletteInformation) { output.Position = paletteOffset; output.Write(imageInfo.PaletteData); } // Write comment output.Position = commentOffset; bw.WriteString(_comment, Encoding.ASCII, false); // Write header _header.imageFormat = (TMXPixelFormat)imageInfo.ImageFormat; _header.paletteFormat = (TMXPixelFormat)(imageInfo.HasPaletteInformation ? imageInfo.PaletteFormat : 0); _header.width = (short)imageInfo.ImageSize.Width; _header.height = (short)imageInfo.ImageSize.Height; _header.fileSize = (int)output.Length; _header.mipmapCount = (byte)imageInfo.MipMapCount; output.Position = 0; bw.WriteType(_header); }
public static void WriteStringTable(Stream input, IList <string> strings) { using var bw = new BinaryWriterX(input, true); var position = input.Position; // Write strings var stringPosition = (position + 0x20 + strings.Count * 4 + 0xF) & ~0xF; input.Position = stringPosition; var offsets = new List <int>(); foreach (var s in strings) { offsets.Add((int)(input.Position - stringPosition)); bw.WriteString(s, Encoding.ASCII, false); } bw.WriteAlignment(); var endPosition = input.Position; // Write offsets input.Position = position + 0x20; bw.WriteMultiple(offsets); // Write header input.Position = position + 0x10; bw.WriteType(new ApkStringHeader { sectionSize = (int)(endPosition - position - 0x10), stringCount = strings.Count, dataOffset = (int)(stringPosition - position - 0x10) }); // Write section header input.Position = position; bw.WriteType(new ApkSectionHeader { magic = ApkSection.StringTable, sectionSize = (int)(endPosition - position - 0x10) }); input.Position = endPosition; }
public override long SaveFileData(Stream output, bool compress, IProgressContext progress = null) { var position = output.Position; var offset = 0; if (UsesCompression) { offset = 0x20; } output.Position += offset; var writtenSize = base.SaveFileData(output, compress, progress); // Padding while (output.Position % 4 != 0) { output.WriteByte(0); } if (!UsesCompression) { return(writtenSize + offset); } var bkPos = output.Position; using var bw = new BinaryWriterX(output, true); output.Position = position; bw.WriteString("ACMP", Encoding.ASCII, false, false); bw.Write((int)writtenSize); bw.Write(0x20); bw.Write(0); bw.Write((int)FileSize); bw.Write(0x01234567); bw.Write(0x01234567); bw.Write(0x01234567); output.Position = bkPos; return(writtenSize + offset); }
/// <summary> /// /// </summary> /// <param name="output"></param> public void Save(Stream output) { using (var bw = new BinaryWriterX(output, true)) { // Updates Header.Width = (short)Texture.Width; Header.Height = (short)Texture.Height; // Header bw.WriteType(Header); bw.WriteAlignment(); bw.WriteString(FileName, Encoding.ASCII, false); bw.WriteAlignment(); // Setup if (Header.Format == ImageFormat.Palette_8) { var settings = new IndexedImageSettings(IndexEncodings[(int)Header.Format], PaletteEncodings[(int)Header.Format], Header.Width, Header.Height) { QuantizationSettings = new QuantizationSettings(new WuColorQuantizer(6, 3), Header.Width, Header.Height) { ColorCount = 256, ParallelCount = 8 } }; var data = Kolors.Save(Texture, settings); bw.Write(data.indexData); bw.Write(data.paletteData); } else { var settings = new ImageSettings(Encodings[(int)Header.Format], Header.Width, Header.Height); var data = Kolors.Save(Texture, settings); bw.Write(data); } } }
public void Save(Stream output, ImageInfo imageInfo) { using var bw = new BinaryWriterX(output); // Calculate offsets var entryOffset = HeaderSize; var nameOffset = entryOffset + EntrySize; var dataOffset = (nameOffset + Encoding.ASCII.GetByteCount(imageInfo.Name) + 1 + 0x7F) & ~0x7F; // Write image data output.Position = dataOffset; output.Write(imageInfo.ImageData); // Write name output.Position = nameOffset; bw.WriteString(imageInfo.Name, Encoding.ASCII, false); // Write entry output.Position = entryOffset; bw.WriteType(new StexEntry { offset = dataOffset, unk1 = (imageInfo as StexImageInfo).Entry.unk1 }); // Write header var header = new StexHeader { width = imageInfo.ImageSize.Width, height = imageInfo.ImageSize.Height, dataSize = (int)(output.Length - dataOffset), dataType = (uint)((imageInfo.ImageFormat >> 16) & 0xFFFF), imageFormat = (uint)(imageInfo.ImageFormat & 0xFFFF) }; output.Position = 0; bw.WriteType(header); }
public void Save(Stream output, IList <ArchiveFileInfo> files) { // Since this is a pointerless archive, we need to keep the original offsets in tact as much as possible using var bw = new BinaryWriterX(output); for (var i = 0; i < files.Count; i++) { var offset = output.Position; bw.WriteString("3DS-LZ\r\n", Encoding.ASCII, false, false); var writtenSize = files[i].SaveFileData(output); var paddedSize = (writtenSize + 0x3F) & ~0x3F; var finalSize = paddedSize - 8; if (i + 1 < files.Count && finalSize > _sizes[i]) { throw new InvalidOperationException("Plugin can not save larger files than their original."); } output.Position = offset + _sizes[i] + 8; } }
public void Save(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output); var fileOffsetsPosition = _headerSize; var fileHashesPosition = fileOffsetsPosition + files.Count * (_offsetSize + _lengthSize); var unkIdsPosition = fileHashesPosition + files.Count * _hashSize; var stringOffsetPosition = (unkIdsPosition + _unkIdsSize + 3) & ~3; var stringPosition = (stringOffsetPosition + _stringOffsetSize + 3) & ~3; // Write strings var crc32 = Crc32.Default; bw.BaseStream.Position = stringOffsetPosition; var fileHashes = new List <uint>(); var relativeStringOffset = stringPosition - stringOffsetPosition; for (var i = 0; i < files.Count; i++) { // Write string offset bw.BaseStream.Position = stringOffsetPosition + i * _stringOffsetSize; bw.Write((short)relativeStringOffset); // Add hash fileHashes.Add(crc32.ComputeValue(files[i].FilePath.ToRelative().FullName)); // Write string bw.BaseStream.Position = stringOffsetPosition + relativeStringOffset; bw.WriteString(files[i].FilePath.ToRelative().FullName, Encoding.ASCII, false); relativeStringOffset = (int)(bw.BaseStream.Position - stringOffsetPosition); } var fileDataPosition = (bw.BaseStream.Position + 3) & ~3; // Write file data bw.BaseStream.Position = fileDataPosition; var fileOffset = new List <int>(); var fileSizes = new List <int>(); foreach (var file in files.Cast <ArchiveFileInfo>()) { fileOffset.Add((int)((bw.BaseStream.Position - _headerSize) >> 2)); var writtenSize = file.SaveFileData(bw.BaseStream, null); bw.WriteAlignment(0x20); fileSizes.Add((int)writtenSize); } // Write file information bw.BaseStream.Position = fileOffsetsPosition; bw.WriteMultiple(fileOffset); bw.WriteMultiple(fileSizes); bw.WriteMultiple(fileHashes); // Write unknown information bw.WriteMultiple(_unkIds); // Write header bw.BaseStream.Position = 0; _header.fileCount = files.Count; _header.contentSize = (int)(bw.BaseStream.Length - _headerSize); _header.table2EntryCount = (short)fileHashes.Count; bw.WriteType(_header); }
private void BuildTables(IEnumerable <XfsaArchiveFileInfo <Xfsa1FileEntry> > files, out IList <Xfsa1DirectoryEntry> directoryEntries, out IList <uint> directoryHashes, out IList <XfsaArchiveFileInfo <Xfsa1FileEntry> > fileEntries, out Stream nameStream) { var groupedFiles = files.OrderBy(x => x.FilePath.GetDirectory()) .GroupBy(x => x.FilePath.GetDirectory()) .ToArray(); var crc32 = Crc32.Default; var sjis = Encoding.GetEncoding("SJIS"); nameStream = new MemoryStream(); using var nameBw = new BinaryWriterX(nameStream, true); var fileInfos = new List <XfsaArchiveFileInfo <Xfsa1FileEntry> >(); directoryEntries = new List <Xfsa1DirectoryEntry>(); directoryHashes = new List <uint>(); var fileOffset = 0; foreach (var fileGroup in groupedFiles) { var fileIndex = fileInfos.Count; var fileGroupEntries = fileGroup.ToArray(); // Add directory entry first var directoryNameOffset = (int)nameBw.BaseStream.Position; var directoryName = fileGroup.Key.ToRelative().FullName; if (!string.IsNullOrEmpty(directoryName)) { directoryName += "/"; } nameBw.WriteString(directoryName, sjis, false); var hash = BinaryPrimitives.ReadUInt32BigEndian(crc32.Compute(sjis.GetBytes(directoryName.ToLower()))); var newDirectoryEntry = new Xfsa1DirectoryEntry { crc32 = string.IsNullOrEmpty(fileGroup.Key.ToRelative().FullName) ? 0xFFFFFFFF : hash, DirectoryCount = (short)groupedFiles.Count(gf => fileGroup.Key != gf.Key && gf.Key.IsInDirectory(fileGroup.Key, false)), FileCount = (short)fileGroupEntries.Length, firstFileIndex = (ushort)fileIndex, DirectoryNameOffset = directoryNameOffset, FileNameStartOffset = (int)nameBw.BaseStream.Position }; if (newDirectoryEntry.crc32 != 0xFFFFFFFF) { directoryHashes.Add(newDirectoryEntry.crc32); } directoryEntries.Add(newDirectoryEntry); // Write file names in alphabetic order foreach (var fileEntry in fileGroupEntries) { fileEntry.Entry.NameOffset = (int)(nameBw.BaseStream.Position - newDirectoryEntry.FileNameStartOffset); fileEntry.Entry.crc32 = BinaryPrimitives.ReadUInt32BigEndian(crc32.Compute(sjis.GetBytes(fileEntry.FilePath.GetName().ToLower()))); fileEntry.Entry.FileOffset = fileOffset; fileEntry.Entry.FileSize = (int)fileEntry.FileSize; fileOffset = (int)((fileOffset + fileEntry.FileSize + 15) & ~15); nameBw.WriteString(fileEntry.FilePath.GetName(), sjis, false); } // Add file entries in order of ascending hash fileInfos.AddRange(fileGroupEntries.OrderBy(x => x.Entry.crc32)); } fileEntries = fileInfos; // Order directory entries by hash and set directoryIndex accordingly var directoryIndex = 0; directoryEntries = directoryEntries.OrderBy(x => x.crc32).Select(x => { x.firstDirectoryIndex = (ushort)directoryIndex; directoryIndex += x.DirectoryCount; return(x); }).ToList(); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { var crc16 = Crc16.X25; using var bw = new BinaryWriterX(output); // Calculate offsets var fileInfoOffset = HeaderSize; var nameOffset = fileInfoOffset + files.Count * EntrySize; var dataOffset = (nameOffset + files.Sum(x => Encoding.ASCII.GetByteCount(x.FilePath.GetName()) + 1) + 3) & ~3; // Write files var fileInfos = new List <GfspFileInfo>(); var fileOffset = 0; var stringOffset = 0; foreach (var file in files.Cast <ArchiveFileInfo>()) { output.Position = dataOffset + fileOffset; var writtenSize = file.SaveFileData(output); bw.WriteAlignment(4); fileInfos.Add(new GfspFileInfo { hash = crc16.ComputeValue(file.FilePath.GetName()), FileOffset = fileOffset, NameOffset = stringOffset, size = (ushort)writtenSize }); fileOffset += (int)file.FileSize; stringOffset += Encoding.ASCII.GetByteCount(file.FilePath.GetName()) + 1; } // Write names output.Position = nameOffset; foreach (var name in files.Select(x => x.FilePath.GetName())) { bw.WriteString(name, Encoding.ASCII, false); } // Write entries output.Position = fileInfoOffset; bw.WriteMultiple(fileInfos); // Write header var header = new GfspHeader { FileCount = (ushort)files.Count, FileInfoOffset = (ushort)fileInfoOffset, FilenameTableOffset = (ushort)nameOffset, DataOffset = (ushort)dataOffset, FileInfoSize = (ushort)(nameOffset - fileInfoOffset), FilenameTableSize = (ushort)(dataOffset - nameOffset), DataSize = (uint)(output.Length - dataOffset) }; output.Position = 0; bw.WriteType(header); }
public void Save(StreamInfo output) { using (var bw = new BinaryWriterX(output.FileData, ByteOrder, BitOrder)) { // Header Header.Magic = ByteOrder == ByteOrder.LittleEndian ? "GFD\0" : "\0DFG"; Header.CharacterCount = Characters.Count; Header.FontTexCount = Textures.Count; bw.WriteType(Header); foreach (var f in HeaderF) { bw.Write(f); } // Name bw.Write(Name.Length); bw.WriteString(Name, Encoding.ASCII, false, false); bw.Write((byte)0); // Characters bw.WriteMultiple(Characters.Select(ci => new CharacterInfo { Character = ci.Character, Block1 = new Block1 { GlyphY = ci.GlyphY, GlyphX = ci.GlyphX, TextureIndex = ci.TextureID }, Block2 = new Block2 { GlyphHeight = ci.GlyphHeight, GlyphWidth = ci.GlyphWidth, XAdjust = ci.XAdjust }, Block3 = new Block3 { IsSpace = ci.IsSpace ? 1 : 0, Superscript = ci.Superscript ? 1 : 0, CharacterWidth = ci.CharacterWidth } })); // Textures for (var i = 0; i < Header.FontTexCount; i++) { IMtFrameworkTextureAdapter texAdapter = _texAdapters.Where(adapter => adapter is IIdentifyFiles). FirstOrDefault(adapter => ((IIdentifyFiles)adapter). Identify(new StreamInfo(File.OpenRead(GetTexName(_sourceFile, i)), GetTexName(_sourceFile, i)), null)); if (texAdapter == null) { continue; } ((ILoadFiles)texAdapter).Load(new StreamInfo(File.OpenRead(GetTexName(_sourceFile, i)), GetTexName(_sourceFile, i)), null); ((IImageAdapter)texAdapter).BitmapInfos[0].Image = Textures[i]; ((ISaveFiles)texAdapter).Save(new StreamInfo(File.OpenRead(GetTexName(_sourceFile, i)), GetTexName(_sourceFile, i)), null); } _sourceFile = output.FileName; } }
public void Save(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output); // Calculate offsets var fatOffset = NarcHeaderSize; var fntOffset = fatOffset + FatHeaderSize + files.Count * FatEntrySize; // Write FNT int fntSize; if (!_hasNames) { output.Position = fntOffset + 8; bw.Write(4); bw.Write(0x10000); fntSize = 0x10; } else { NdsSupport.WriteFnt(bw, fntOffset + 8, files); fntSize = (int)(bw.BaseStream.Position - fntOffset); } output.Position = fntOffset; bw.WriteType(new NarcFntHeader { chunkSize = fntSize }); // Write GMIF var fatEntries = new List <FatEntry>(); var gmifOffset = fntOffset + fntSize; output.Position = gmifOffset + 8; foreach (var file in files.Cast <FileIdArchiveFileInfo>().OrderBy(x => x.FileId)) { var filePosition = output.Position; var writtenSize = file.SaveFileData(output); fatEntries.Add(new FatEntry { offset = (int)filePosition - gmifOffset - 8, endOffset = (int)(filePosition - gmifOffset - 8 + writtenSize) }); } output.Position = gmifOffset; bw.WriteString("GMIF", Encoding.ASCII, false, false); bw.Write((int)(output.Length - gmifOffset)); // Write FAT output.Position = fatOffset; bw.WriteType(new NarcFatHeader { chunkSize = FatHeaderSize + files.Count * FatEntrySize, fileCount = (short)files.Count }); bw.WriteMultiple(fatEntries); // Write header output.Position = 0; bw.WriteType(new NarcHeader { fileSize = (int)output.Length }); }
public void Save(Stream output, IList <IArchiveFileInfo> files, bool isCompressed) { var simpleHash = new SimpleHash(_sfatHeader.hashMultiplier); using var bw = new BinaryWriterX(output, true, _byteOrder); var sortedFiles = files.Cast <SarcArchiveFileInfo>().OrderBy(x => _sfntHeader == null ? x.Entry.nameHash : simpleHash.ComputeValue(x.FilePath.ToRelative().FullName)).ToArray(); // Calculate offsets var sfatOffset = HeaderSize; var sfntOffset = sfatOffset + SfatHeaderSize + files.Count * SfatEntrySize; var dataOffset = _sfntHeader == null ? sfntOffset + SfntHeaderSize : sfntOffset + SfntHeaderSize + files.Sum(x => (x.FilePath.ToRelative().FullName.Length + 4) & ~3); var alignment = sortedFiles.Max(x => SarcSupport.DetermineAlignment(x, _byteOrder, isCompressed)); var alignedDataOffset = (dataOffset + alignment - 1) & ~(alignment - 1); // Write files var entries = new List <SfatEntry>(); var strings = new List <string>(); var stringPosition = 0; var dataPosition = alignedDataOffset; foreach (var file in sortedFiles) { // Write file data alignment = SarcSupport.DetermineAlignment(file, _byteOrder, isCompressed); var alignedDataPosition = (dataPosition + alignment - 1) & ~(alignment - 1); output.Position = alignedDataPosition; var writtenSize = file.SaveFileData(output); // Add entry entries.Add(new SfatEntry { startOffset = alignedDataPosition - alignedDataOffset, endOffset = (int)(alignedDataPosition + writtenSize - alignedDataOffset), Flags = (short)(_sfntHeader == null ? 0 : 0x100), FntOffset = (short)(_sfntHeader == null ? 0 : stringPosition), nameHash = _sfntHeader == null ? file.Entry.nameHash : simpleHash.ComputeValue(file.FilePath.ToRelative().FullName) }); // Add string strings.Add(file.FilePath.ToRelative().FullName); dataPosition = (int)(alignedDataPosition + writtenSize); stringPosition += (file.FilePath.ToRelative().FullName.Length + 4) & ~3; } // Write SFNT output.Position = sfntOffset; bw.WriteType(new SfntHeader()); if (_sfntHeader != null) { foreach (var s in strings) { bw.WriteString(s, Encoding.ASCII, false); bw.WriteAlignment(4); } } // Write SFAT output.Position = sfatOffset; bw.WriteType(new SfatHeader { entryCount = (short)files.Count, hashMultiplier = _sfatHeader.hashMultiplier }); bw.WriteMultiple(entries); // Write header output.Position = 0; bw.WriteType(new SarcHeader { byteOrder = _byteOrder, dataOffset = alignedDataOffset, fileSize = (int)output.Length, unk1 = _header.unk1 }); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output); // Calculate offsets var nameOffset = 8; // Build string tree var fileNames = files.Select(x => x.FilePath.ToRelative().FullName).ToArray(); var rootNode = new StringNode(); rootNode.AddRange(fileNames); // Assign offsets to nodes var nodeOffsetMap = new Dictionary <StringNode, int>(); var nameTableOffset = AssignOffsets(rootNode, nameOffset, nodeOffsetMap); nameTableOffset = (nameTableOffset + 1) & ~1; // Write node tree output.Position = nameTableOffset; var fileId = 0; WriteNodes(rootNode, bw, nodeOffsetMap, ref fileId); var entryOffset = bw.BaseStream.Length; var fileOffset = entryOffset + files.Count * EntrySize; // Write files var entries = new List <PakEntry>(); var filePosition = fileOffset; foreach (var file in files.Cast <ArchiveFileInfo>()) { output.Position = filePosition; var writtenSize = file.SaveFileData(output); entries.Add(new PakEntry { offset = (int)filePosition, size = (int)writtenSize }); filePosition += writtenSize; } // Write entries output.Position = entryOffset; bw.WriteMultiple(entries); // Write strings foreach (var pair in nodeOffsetMap) { output.Position = pair.Value; bw.WriteString(pair.Key.Text, Encoding.ASCII, false); } // Write header output.Position = 0; bw.WriteType(new PakHeader { fileCount = (short)files.Count, entryOffset = (int)entryOffset, nameTable = (short)nameTableOffset }); }