public void Save(String filename) { using (var bw = new BinaryWriterX(File.Create(filename))) { bw.BaseStream.Position = 0x1c; GetDirInfo(); int nameListLength = 0; foreach (var name in dirEntries) { nameListLength += (name.dir.Length + 1) * 2; } //Write Entry table int filesOffset = 0; int offset = 0; int dataOffset = 0x1c + dirEntries.Count * 0xc + nameListLength; for (int i = 0; i < dirEntries.Count; i++) { if (dirEntries[i].dir != "." && dirEntries[i].dir.Contains('.')) { bw.Write(offset); bw.Write(dataOffset); bw.Write((uint)Files[filesOffset].FileSize.GetValueOrDefault()); dataOffset += (int)Files[filesOffset++].FileSize.GetValueOrDefault(); offset += (dirEntries[i].dir.Length + 1) * 2; } else { bw.Write(offset | 0x01000000); bw.Write(dirEntries[i].lvl); bw.Write(dirEntries[i].dirCount); offset += (dirEntries[i].dir.Length + 1) * 2; } } //Write names foreach (var dir in dirEntries) { for (int i = 0; i < dir.dir.Length; i++) { bw.Write((short)dir.dir[i]); } bw.Write((short)0); } //Write FileData foreach (var data in Files) { bw.Write(new BinaryReaderX(data.FileData).ReadBytes((int)data.FileSize.GetValueOrDefault())); } //Header bw.BaseStream.Position = 0; header.fileSize = (int)bw.BaseStream.Length; header.tableLength = dirEntries.Count * 0xc + nameListLength; header.dataOffset = 0x1c + dirEntries.Count * 0xc + nameListLength; bw.WriteStruct(header); } }
public static byte[] Save(Bitmap bmp, ImageSettings settings) { settings.Width = bmp.Width; settings.Height = bmp.Height; var points = GetPointSequence(settings); var ms = new MemoryStream(); var etc1encoder = new ETC1.Encoder(); Enum.TryParse <DXT.Formats>(settings.Format.ToString(), false, out var dxtFormat); var dxtencoder = new DXT.Encoder(dxtFormat); using (var bw = new BinaryWriterX(ms)) { foreach (var point in points) { int x = Clamp(point.X, 0, bmp.Width); int y = Clamp(point.Y, 0, bmp.Height); var color = bmp.GetPixel(x, y); if (settings.PixelShader != null) { color = settings.PixelShader(color); } switch (settings.Format) { case Format.L8: bw.Write(color.G); break; case Format.A8: bw.Write(color.A); break; case Format.LA44: bw.WriteNibble(color.A / 16); bw.WriteNibble(color.G / 16); break; case Format.LA88: bw.Write(color.A); bw.Write(color.G); break; case Format.HL88: bw.Write(color.G); bw.Write(color.R); break; case Format.RGB565: bw.Write((short)((color.R / 8 << 11) | (color.G / 4 << 5) | (color.B / 8))); break; case Format.RGB888: bw.Write(color.B); bw.Write(color.G); bw.Write(color.R); break; case Format.RGBA5551: bw.Write((short)((color.R / 8 << 11) | (color.G / 8 << 6) | (color.B / 8 << 1) | color.A / 128)); break; case Format.RGBA4444: bw.WriteNibble(color.A / 16); bw.WriteNibble(color.B / 16); bw.WriteNibble(color.G / 16); bw.WriteNibble(color.R / 16); break; case Format.RGBA8888: bw.Write(color.A); bw.Write(color.B); bw.Write(color.G); bw.Write(color.R); break; case Format.ETC1: case Format.ETC1A4: etc1encoder.Set(color, data => { if (settings.Format == Format.ETC1A4) { bw.Write(data.Alpha); } bw.WriteStruct(data.Block); }); break; case Format.DXT1: case Format.DXT5: dxtencoder.Set(color, data => { if (settings.Format == Format.DXT5) { bw.Write(data.alpha); } bw.Write(data.block); }); break; case Format.L4: bw.WriteNibble(color.G / 16); break; case Format.A4: bw.WriteNibble(color.A / 16); break; default: throw new NotSupportedException(); } } } return(ms.ToArray()); }
public void Save(string filename) { using (var bw = new BinaryWriterX(File.Create(filename))) { var table1Offset = 0x10 + bmps.Count * 0x4; var ptgtTableOffset = table1Offset + 0x4 + table1Entries.Count * 0x4 + table1Entries.SelectMany(x => x.SelectMany(b => new[] { b })).Count(); var imgDataSize = (ptgtTableOffset + 0x8 + ptgtEntries.Length + 0x7f) & ~0x7f;//ptgtEntries.Count * 0x8 + ptgtEntries.Count * 0xe + 0x7f) & ~0x7f; //Header bw.Write(Encoding.ASCII.GetBytes("IOBJ")); bw.Write(table1Offset); bw.Write(ptgtTableOffset); bw.Write(bmps.Count); //Table1 bw.BaseStream.Position = table1Offset; bw.Write(table1Entries.Count); var offset = 0x4 + table1Entries.Count * 0x4; foreach (var entry in table1Entries) { bw.Write(offset); offset += entry.Length; } foreach (var entry in table1Entries) { bw.Write(entry); } //PTGT bw.WriteStruct(ptgtHeader); bw.Write(ptgtEntries); /*bw.Write(ptgtEntries.Count); * foreach (var entry in ptgtEntries) * bw.WriteStruct(entry.offsetEntry); * foreach (var entry in ptgtEntries) * foreach (var floatEntry in entry.floats) * bw.Write(floatEntry); * bw.WriteAlignment(0x80);*/ //Images var imgOffsets = new List <int>(); var count = 0; foreach (var bmp in bmps) { imgOffsets.Add((int)bw.BaseStream.Position); Format format; using (var br = new BinaryReaderX(new MemoryStream(imgMetaInf[count]))) format = (Format)br.ReadInt32(); throw new System.NotImplementedException(); var settings = new ImageSettings { Width = bmp.Width, Height = bmp.Height, //Orientation = Orientation.XFlip, Format = ImageSettings.ConvertFormat(((int)format > 0x12) ? Format.ETC1A4 : format) }; var pic = Common.Save(bmp, settings); bw.Write(pic.Length); bw.Write(bmp.Width); bw.Write(bmp.Height); bw.Write(imgMetaInf[count++]); bw.Write(pic); bw.WriteAlignment(0x80); } //imgOffsets in Header bw.BaseStream.Position = 0x10; foreach (var imgOff in imgOffsets) { bw.Write(imgOff); } } }
public void Save(Stream output) { using (var bw = new BinaryWriterX(output, ByteOrder)) { bw.BaseStream.Position = HeaderLength + Header.NameSize + 1; // Section Entries if (Header.Version == Versions.Version1) { foreach (var entry in EntriesV1) { bw.WriteStruct(entry); } } else if (Header.Version == Versions.Version2) { foreach (var entry in EntriesV2) { bw.WriteStruct(entry); } } // Unknown Version 2 Section if (Header.Version == Versions.Version2) { bw.Write(UnknownV2); } // Labels uint labelSize = 0; for (var i = 0; i < Header.LabelCount; i++) { bw.WriteASCII(Names[i]); bw.Write((byte)0); labelSize += (uint)Names[i].Length + 1; } Header.LabelSize = labelSize; // Sections var textStart = bw.BaseStream.Position; var textS = new MemoryStream(); using (var textW = new BinaryWriterX(textS, true)) { foreach (var label in Labels) { textW.Write(Encoding.UTF8.GetBytes(label.Text)); textW.Write((byte)0); } } //ReXOR if needed, only for version 1 for now if (Header.Version == Versions.Version1 && IsXORed) { var xor = new XOR(Header.Version); var tmp = xor.Obfuscate(new BinaryReaderX(textS).ReadAllBytes()); textS.Position = 0; new BinaryWriterX(textS, true).Write(tmp); } bw.Write(new BinaryReaderX(textS).ReadAllBytes()); Header.SectionSize = (uint)(bw.BaseStream.Position - textStart); // Header bw.BaseStream.Position = 0; bw.WriteStruct(Header); bw.WriteASCII(Name); bw.Write((byte)0); } }
public void Save(Stream input) { //Sanity check for (int i = 0; i < bmps.Count; i++) { var padWidth = 2 << (int)Math.Log(bmps[i].Width - 1, 2); var padHeight = 2 << (int)Math.Log(bmps[i].Height - 1, 2); if (padWidth >= Math.Pow(2, 16) || padHeight >= Math.Pow(2, 16)) { throw new Exception($"Image {i} has to be smaller than {Math.Pow(2, 15)}x{Math.Pow(2, 15)}"); } } using (BinaryWriterX bw = new BinaryWriterX(input, ByteOrder)) { //Create offsetlist var offsetList = new List <int>(); var off = header.texCount * 4; for (int i = 0; i < header.texCount; i++) { offsetList.Add(off); off += 0x8 + ((metaExt[i] != null) ? metaExt[i].Length + 4 : 0); off += bmps[i].Width * bmps[i].Height * Support.Format[meta[i].format].BitDepth / 8; } //Update meta for (int i = 0; i < header.texCount; i++) { meta[i].dimension = (byte)((int)(Math.Log(bmps[i].Width - 1, 2) + 1) | ((int)(Math.Log(bmps[i].Height - 1, 2) + 1) * 16)); } //Write updated data bw.BaseStream.Position = header.dataOffset; foreach (var offInt in offsetList) { bw.Write(offInt); } //Write images for (int i = 0; i < bmps.Count; i++) { bw.WriteStruct(meta[i]); if (metaExt[i] != null) { bw.Write(metaExt[i].Length + 4); bw.Write(metaExt[i]); } IImageSwizzle swizzle = null; if (vita) { swizzle = new VitaSwizzle(2 << (int)Math.Log(bmps[i].Width - 1, 2), 2 << (int)Math.Log(bmps[i].Height - 1, 2), Support.Format[meta[i].format].FormatName.Contains("DXT")); } else if (Support.Format[meta[i].format].FormatName.Contains("DXT")) { swizzle = new BlockSwizzle(2 << (int)Math.Log(bmps[i].Width - 1, 2), 2 << (int)Math.Log(bmps[i].Height - 1, 2)); } var setting = new ImageSettings { Width = 2 << (int)Math.Log(bmps[i].Width - 1, 2), Height = 2 << (int)Math.Log(bmps[i].Height - 1, 2), Swizzle = swizzle, Format = Support.Format[meta[i].format] }; bw.Write(Common.Save(bmps[i], setting)); } header.fileSize = (int)bw.BaseStream.Length; //Header bw.BaseStream.Position = 0; bw.WriteStruct(header); } }
private void SaveSystemGar(Stream input) { int Align(int value, int align) => value + (align - 1) & ~(align - 1); using (var bw = new BinaryWriterX(input)) { var files = Files.OrderBy(x => x.ext.Length).ToList(); //get Extension and their count Dictionary <string, int> exts = new Dictionary <string, int>(); foreach (var file in files) { var ext = Path.GetExtension(file.FileName).Replace(".", ""); if (!exts.ContainsKey(ext)) { exts.Add(ext, 1); } else { exts[ext]++; } } //get offsets int chunkExtNameOffset = _header.chunkEntryOffset + (exts.Count + 1) * 0x20; int chunkSubTableOffset = Align(chunkExtNameOffset + Encoding.ASCII.GetByteCount("unknown\0") + exts.Aggregate(0, (a, b) => a + Encoding.ASCII.GetByteCount(b.Key) + 1), 4); int chunkInfoOffset = chunkSubTableOffset + sysEntriesSubTable.Length; int chunkInfoNameOffset = chunkInfoOffset + Files.Count * 0x10; int dataOffset = Align(chunkInfoNameOffset + Files.Aggregate(0, (a, b) => a + Encoding.ASCII.GetByteCount(Path.GetFileName(b.FileName)) + 1), 0x80); bw.BaseStream.Position = 0x20; //Write chunkEntries int localChunkNameOffset = chunkExtNameOffset; //Add "unknown" chunk Entry bw.Write(0); bw.Write(0x4); bw.Write(0xFFFFFFFF); bw.Write(localChunkNameOffset); bw.Write(0xFFFFFFFF); bw.BaseStream.Position += 0xC; localChunkNameOffset += Encoding.ASCII.GetByteCount("unknown\0"); //Add all other chunk entries int filesAdded = 0; foreach (var ext in exts) { bw.Write(ext.Value); bw.Write(sysEntries.FirstOrDefault(x => x.name == ext.Key)?.unk1 ?? 0x4); bw.Write(filesAdded); bw.Write(localChunkNameOffset); bw.Write(sysEntries.FirstOrDefault(x => x.name == ext.Key)?.subTableOffset ?? 0x0); bw.BaseStream.Position += 0xC; filesAdded += ext.Value; localChunkNameOffset += Encoding.ASCII.GetByteCount(ext.Key) + 1; } //Add chunk Extensions bw.WriteASCII("unknown\0"); foreach (var ext in exts) { bw.WriteASCII(ext.Key + "\0"); } bw.WriteAlignment(4); //Add subtable bw.Write(sysEntriesSubTable); //Write chunkInfos and Files var localChunkInfoOffset = chunkInfoOffset; var localChunkInfoNameOffset = chunkInfoNameOffset; var localDataOffset = dataOffset; foreach (var ext in exts) { var filesToAdd = Files.Where(x => x.ext == ext.Key); foreach (var toAdd in filesToAdd) { bw.BaseStream.Position = localChunkInfoOffset; bw.Write((int)toAdd.FileSize); bw.Write(localDataOffset); bw.Write(localChunkInfoNameOffset); bw.Write(0xFFFFFFFF); bw.BaseStream.Position = localChunkInfoNameOffset; bw.WriteASCII(Path.GetFileNameWithoutExtension(toAdd.FileName) + "\0"); bw.BaseStream.Position = localDataOffset; toAdd.FileData.CopyTo(bw.BaseStream); localDataOffset += (int)toAdd.FileSize; localChunkInfoNameOffset += Encoding.ASCII.GetByteCount(Path.GetFileNameWithoutExtension(toAdd.FileName)) + 1; localChunkInfoOffset += 0x10; } } //Header bw.BaseStream.Position = 0; _header.fileSize = (uint)bw.BaseStream.Length; _header.fileChunks = (short)(exts.Count + 1); _header.fileCount = (short)files.Count; _header.chunkInfOffset = chunkInfoOffset; _header.offset3 = dataOffset; bw.WriteStruct(_header); } }
public void Save(Stream output) { int Pad128(int n) => (n + 127) & ~127; using (var bw = new BinaryWriterX(output)) { //get nameList Length int nameListLength = (Files.Sum(afi => afi.FileName.Length + 1) + 3) & ~3; //Offsets int nameOffset = (Files.Count + 1) * 0x20 + Files.Count * 0x4; //Header bw.WriteStruct(new Header { texCount = (short)Files.Count, texSecOffset = Pad128(nameOffset + nameListLength + Files.Count * 12), texSecSize = (int)Files.Sum(afi => afi.FileSize), crc32SecOffset = nameOffset + nameListLength, texInfoOffset = nameOffset + nameListLength + Files.Count * 0x8 }); //entryList int dataOffset = 0; foreach (var afi in Files) { dataOffset = Pad128(dataOffset); var entry = afi.Entry; entry.texDataSize = (int)afi.FileData.Length; entry.nameOffset = nameOffset; entry.texOffset = dataOffset; bw.WriteStruct(entry); nameOffset += afi.FileName.Length + 1; dataOffset += (int)afi.FileSize; } //texInfo 1 List foreach (var afi in Files) { bw.Write((int)afi.FileData.Length); } //nameList foreach (var afi in Files) { bw.WriteASCII(afi.FileName + '\0'); } while (bw.BaseStream.Position % 4 != 0) { bw.BaseStream.Position++; } //crc32List foreach (var afi in Files) { bw.Write(afi.hashEntry.crc32); bw.Write(afi.hashEntry.entryNr); } //texInfo 2 List foreach (var afi in Files) { bw.Write(afi.texInfo); } //Write data foreach (var afi in Files) { bw.Write(new byte[Pad128((int)bw.BaseStream.Length) - (int)bw.BaseStream.Length]); afi.FileData.CopyTo(bw.BaseStream); } } }
public void Save(String filename) { if (isRaw) { SaveRaw(filename); } else { using (BinaryWriterX bw = new BinaryWriterX(File.Create(filename))) { var settings = new ImageSettings { Width = bmp.Width, Height = bmp.Height, Format = ImageSettings.ConvertFormat(entries[0].imageFormat), PadToPowerOf2 = false }; byte[] resBmp = Common.Save(bmp, settings); int diff = resBmp.Length - entries[0].texDataSize; entries[0].width = (short)bmp.Width; entries[0].height = (short)bmp.Height; entries[0].texDataSize = resBmp.Length; for (int i = 1; i < header.texCount; i++) { entries[i].texOffset -= diff; } texSizeList[0] = resBmp.Length; //write entries bw.BaseStream.Position = 0x20; for (int i = 0; i < header.texCount; i++) { bw.WriteStruct(entries[i]); } //write texSizeInfo for (int i = 0; i < header.texCount; i++) { bw.Write(texSizeList[i]); } //write names for (int i = 0; i < header.texCount; i++) { bw.WriteASCII(nameList[i]); bw.Write((byte)0); } //write hashes crc32List = crc32List.OrderBy(e => e.crc32).ToList(); bw.BaseStream.Position = header.crc32SecOffset; for (int i = 0; i < header.texCount; i++) { bw.Write(crc32List[i].crc32); bw.Write(crc32List[i].entryNr); } //write texInfo bw.BaseStream.Position = header.texInfoOffset; for (int i = 0; i < header.texCount; i++) { bw.Write(texInfoList2[i]); } //write texData bw.BaseStream.Position = header.texSecOffset; bw.Write(resBmp); bw.Write(rest); header.texSecSize = (int)bw.BaseStream.Length - header.texSecOffset; bw.BaseStream.Position = 0; bw.WriteStruct(header); } } }
public void Save(string filename) { // Write file data and remember the relative offsets var fileData = new MemoryStream(); var fileOffsets = new List <int>(); foreach (var file in Files) { fileData.Position = (fileData.Position + 0x1F) & ~0x1F; fileOffsets.Add((int)fileData.Position); file.FileData.Position = 0; file.FileData.CopyTo(fileData); } // It seems the file data portion in itself is aligned to 0x20 while (fileData.Position % 0x20 != 0) { fileData.WriteByte(0); } using (var bw = new BinaryWriterX(File.OpenWrite(filename))) { // Write table information bw.BaseStream.Position = header.headerSize; // Write file offsets last, due to their relative property to the following tables bw.BaseStream.Position += Files.Count * 0x4; foreach (var file in Files) { bw.Write((int)file.FileSize); } foreach (var file in Files) { bw.Write(Crc32.Create(file.FileName)); } foreach (var unkId in _unkIds) { bw.Write(unkId); } bw.WriteAlignment(4); var stringRelativeOffset = (Files.Count * 2 + 3) & ~3; foreach (var file in Files) { bw.Write((short)stringRelativeOffset); stringRelativeOffset += Encoding.ASCII.GetByteCount(file.FileName) + 1; } bw.WriteAlignment(4); foreach (var file in Files) { bw.WriteASCII(file.FileName + '\0'); } bw.WriteAlignment(); bw.BaseStream.Position = 0x40; foreach (var offset in fileOffsets) { bw.Write((int)((offset + bw.BaseStream.Length - 0x40) >> 2)); } // Write file data bw.BaseStream.Position = bw.BaseStream.Length; fileData.Position = 0; fileData.CopyTo(bw.BaseStream); // Create header var newHeader = new Header { contentSize = (int)bw.BaseStream.Length - 0x40, fileCount = Files.Count, table2EntryCount = (short)Files.Count, table3EntryCount = (short)(Files.Count * 2), unk2 = header.unk2, unk3 = header.unk3 }; bw.BaseStream.Position = 0; bw.WriteStruct(newHeader); } }
public void Save(Stream output) { using (BinaryWriterX bw = new BinaryWriterX(output)) { bw.BaseStream.Position = 0x48; //first unknown half of info section bw.Write(unk1); bw.Write(unk2); //entryList and Data uint dataOffset = 0; uint movDataOffset = (uint)(0x48 + unk1.Length + unk2.Length + Files.Count * 0x10); foreach (var name in dirStruct) { movDataOffset += 1 + (uint)Encoding.GetEncoding("SJIS").GetBytes((name.Last() != '/') ? name.Split('/').Last() : name).Length; } while (movDataOffset % 4 != 0) { movDataOffset++; } header.dataOffset = movDataOffset; header.nameOffset = (uint)(0x48 + unk1.Length + unk2.Length + Files.Count * 0x10); header.folderCount = (short)folderCounts.Count; header.fileCount = Files.Count; header.fileCount2 = Files.Count; int pos = 0; foreach (var folderCount in folderCounts) { var nameSorted = new List <NameEntry>(); for (int i = 0; i < folderCount; i++) { nameSorted.Add(new NameEntry { name = Files[pos + i].FileName, crc32 = Files[pos + i].crc32, size = (uint)Files[pos + i].FileSize }); } nameSorted = nameSorted.OrderBy(x => x.name, StringComparer.OrdinalIgnoreCase).ToList(); var entriesTmp = new List <Entry>(); uint nameOffset = 0; for (int i = 0; i < folderCount; i++) { entriesTmp.Add(new Entry { crc32 = Files[pos + i].crc32 }); } for (int i = 0; i < folderCount; i++) { var foundEntry = entriesTmp.Find(x => x.crc32 == nameSorted[i].crc32); foundEntry.nameOffsetInFolder = nameOffset; foundEntry.fileOffset = dataOffset; foundEntry.fileSize = nameSorted[i].size; var t = ""; if (bw.BaseStream.Position == 0x74fc) { t = nameSorted[i].name; } t = ""; nameOffset += 1 + (uint)nameSorted[i].name.Split('/').Last().Length; long bk = bw.BaseStream.Position; bw.BaseStream.Position = movDataOffset; Files.Find(x => x.FileName == nameSorted[i].name).FileData.CopyTo(bw.BaseStream); bw.BaseStream.Position++; while (bw.BaseStream.Position % 4 != 0) { bw.BaseStream.Position++; } dataOffset += (uint)bw.BaseStream.Position - movDataOffset; movDataOffset = (uint)bw.BaseStream.Position; bw.BaseStream.Position = bk; } for (int i = 0; i < folderCount; i++) { bw.WriteStruct(entriesTmp[i]); } pos += folderCount; } //nameList foreach (var name in dirStruct) { bw.Write((byte)0); if (name.Last() != '/') { bw.Write(Encoding.GetEncoding("SJIS").GetBytes(name.Split('/').Last())); } else { bw.Write(Encoding.GetEncoding("SJIS").GetBytes(name)); } } bw.BaseStream.Position++; while (bw.BaseStream.Position % 4 != 0) { bw.BaseStream.Position++; } //Write Header bw.BaseStream.Position = 0; bw.WriteStruct(header); } }
public void Save(Stream output) { using (var bw = new BinaryWriterX(output)) { var newHeight = bmps[0].Height; var newWidth = bmps[0].Width; var newMipMapCount = headerInfo.mipMapCount; if (headerInfo.mipMapCount > 1) { if (bmps[0].Width >= bmps[0].Height) { newWidth = 2 << (int)Math.Log(bmps[0].Width - 1, 2); newHeight = (int)(newWidth / (bmps[0].Width / bmps[0].Height)); } else { newHeight = 2 << (int)Math.Log(bmps[0].Height - 1, 2); newWidth = (int)(newHeight / (bmps[0].Height / bmps[0].Width)); } newMipMapCount = ((int)Math.Log(Math.Max(newWidth, newHeight), 2) + 1); } header.Block1 = (uint)((ushort)headerInfo.version | (headerInfo.format << 16) | (headerInfo.unk1 << 24)); header.Block2 = (uint)((headerInfo.r1 << 4) | (headerInfo.unk2)); header.Block3 = (uint)((newMipMapCount << 26) | (newHeight << 13) | (ushort)newWidth); bw.WriteStruct(header); if (headerInfo.format == 0xc) { bw.BaseStream.Position = 0x10 + 3 * 2 * 0x4; var texOffsets = new List <uint>(); var texSizes = new List <uint>(); for (int i = 0; i < bmps.Count; i++) { settings = new ImageSettings { Width = bmps[i].Width, Height = bmps[i].Height }; if (i == 0) { settings.Format = new DXT(DXT.Version.DXT5); settings.Swizzle = new BlockSwizzle(settings.Width, settings.Height); } else if (i == 1) { settings.Format = new PVRTC(PVRTC.Format.PVRTCA_4bpp); (settings.Format as PVRTC)._width = settings.Width; (settings.Format as PVRTC)._height = settings.Height; settings.Swizzle = null; } else { settings.Format = new ATC(true, Kontract.Image.Support.ATC.AlphaMode.Interpolated); settings.Swizzle = new BlockSwizzle(settings.Width, settings.Height); } var texData = Common.Save(bmps[i], settings); texOffsets.Add((uint)bw.BaseStream.Position); texSizes.Add((uint)texData.Length); bw.Write(texData); } bw.BaseStream.Position = 0x10; foreach (var offset in texOffsets) { bw.Write(offset); } foreach (var size in texSizes) { bw.Write(size); } } else { var settings = new ImageSettings { Format = Support.Format[headerInfo.format] }; bw.BaseStream.Position = 0x28; for (int i = 0; i < newMipMapCount; i++) { settings.Width = Math.Max(newWidth >> i, 1); settings.Height = Math.Max(newHeight >> i, 1); if (Support.Format[headerInfo.format].FormatName.Contains("DXT") || settings.Format.FormatName.Contains("ETC")) { settings.Swizzle = new BlockSwizzle(newWidth >> i, newHeight >> i); } bw.Write(Common.Save(bmps[0].Resize(settings.Width, settings.Height), settings)); } bw.BaseStream.Position = 0x10; for (int i = 0; i < 3; i++) { bw.Write(0x28); } } } }
public void Save(string filename) { long bk; using (var bw = new BinaryWriterX(File.Create(filename))) { bw.WriteStruct(cfgHeader); for (int j = 0; j < editorEntries.Count; j++) { if (j > 0) { EditorStruct bk2 = editorEntries[j]; var success1 = (cfgHeader.dataOffset > bw.BaseStream.Length) ? bk2.entryOffset = 0 : bk2.entryOffset = (uint)bw.BaseStream.Length - cfgHeader.dataOffset; bk = bw.BaseStream.Position; var success2 = (cfgHeader.dataOffset > bw.BaseStream.Length) ? bw.BaseStream.Position = cfgHeader.dataOffset : bw.BaseStream.Position = bw.BaseStream.Length; bw.Write(Encoding.GetEncoding("shift-jis").GetBytes(Labels[labelCount++].Text)); bw.Write((byte)0x00); bw.BaseStream.Position = bk; editorEntries[j] = bk2; } bw.WriteStruct <EditorStruct>(editorEntries[j]); } if (editorRest != null) { bw.Write(editorRest); } else { for (int j = 0; j < textEntries.Count; j++) { if (j > 0 && textEntries[j].entryOffset != 0xFFFFFFFF) { TextStruct bk2 = textEntries[j]; var success1 = (cfgHeader.dataOffset > bw.BaseStream.Length) ? bk2.entryOffset = 0 : bk2.entryOffset = (uint)bw.BaseStream.Length - cfgHeader.dataOffset; bk = bw.BaseStream.Position; var success2 = (cfgHeader.dataOffset > bw.BaseStream.Length) ? bw.BaseStream.Position = cfgHeader.dataOffset : bw.BaseStream.Position = bw.BaseStream.Length; bw.Write(Encoding.GetEncoding("shift-jis").GetBytes(Labels[labelCount++].Text)); bw.Write((byte)0x00); bw.BaseStream.Position = bk; textEntries[j] = bk2; } bw.WriteStruct(textEntries[j]); } if (textRest != null) { bw.Write(textRest); } } bw.BaseStream.Position = 0x8; bw.Write((int)(bw.BaseStream.Length - cfgHeader.dataOffset)); bw.BaseStream.Position = bw.BaseStream.Length; bw.WriteAlignment(0x10, 0xff); } }
public BinaryReaderX createCfg(int part) { long bk; BinaryWriterX br = new BinaryWriterX(new MemoryStream()); br.WriteStruct <Header>(headerList[part]); for (int j = 0; j < editorEntries[part].Count; j++) { if (j > 0) { EditorStruct bk2 = editorEntries[part][j]; var success1 = (headerList[part].dataOffset > br.BaseStream.Length) ? bk2.entryOffset = 0 : bk2.entryOffset = (uint)br.BaseStream.Length - headerList[part].dataOffset; bk = br.BaseStream.Position; var success2 = (headerList[part].dataOffset > br.BaseStream.Length) ? br.BaseStream.Position = headerList[part].dataOffset : br.BaseStream.Position = br.BaseStream.Length; br.Write(Encoding.GetEncoding("shift-jis").GetBytes(Labels[labelCount++].Text)); br.Write((byte)0x00); br.BaseStream.Position = bk; editorEntries[part][j] = bk2; } br.WriteStruct <EditorStruct>(editorEntries[part][j]); } if (editorRest[part] != null) { br.Write(editorRest[part]); } else { for (int j = 0; j < textEntries[part].Count; j++) { if (j > 0 && textEntries[part][j].entryOffset != 0xFFFFFFFF) { TextStruct bk2 = textEntries[part][j]; var success1 = (headerList[part].dataOffset > br.BaseStream.Length) ? bk2.entryOffset = 0 : bk2.entryOffset = (uint)br.BaseStream.Length - headerList[part].dataOffset; bk = br.BaseStream.Position; var success2 = (headerList[part].dataOffset > br.BaseStream.Length) ? br.BaseStream.Position = headerList[part].dataOffset : br.BaseStream.Position = br.BaseStream.Length; br.Write(Encoding.GetEncoding("shift-jis").GetBytes(Labels[labelCount++].Text)); br.Write((byte)0x00); br.BaseStream.Position = bk; textEntries[part][j] = bk2; } br.WriteStruct <TextStruct>(textEntries[part][j]); } if (textRest[part] != null) { br.Write(textRest[part]); } } br.BaseStream.Position = 0x8; br.Write((int)(br.BaseStream.Length - headerList[part].dataOffset)); br.BaseStream.Position = br.BaseStream.Length; while (br.BaseStream.Position % 16 != 0) { br.Write((byte)0xFF); } return(new BinaryReaderX(br.BaseStream)); }
public void Save(Stream output, bool leaveOpen = false) { using (var bw = new BinaryWriterX(output, leaveOpen, byteOrder)) { //Create SARCHeader var header = new SARCHeader { byteOrder = byteOrder, dataOffset = Files.Aggregate( 0x14 + 0xc + 0x8 + Files.Sum(afi => usesSFNT ? ((afi.FileName.Length + 4) & ~3) + 0x10 : 0x10), (n, file) => Support.Pad(n, file.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU)) }; //SFATHeader bw.BaseStream.Position = 0x14; bw.WriteStruct(new SFATHeader { hashMultiplier = (int)hashMultiplier, nodeCount = (short)Files.Count }); //SFAT List + nameList int nameOffset = 0; int dataOffset = 0; foreach (var afi in Files) { dataOffset = Support.Pad(dataOffset, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU); var fileLen = (int)afi.FileData.Length; var sfatEntry = new SFATEntry { nameHash = usesSFNT ? SimpleHash.Create(afi.FileName, hashMultiplier) : Convert.ToUInt32(afi.FileName.Substring(2, 8), 16), SFNTOffsetFlag = (uint)(((usesSFNT ? 0x100 : 0) << 16) | (usesSFNT ? nameOffset / 4 : 0)), dataStart = dataOffset, dataEnd = dataOffset + fileLen }; bw.WriteStruct(sfatEntry); nameOffset = (nameOffset + afi.FileName.Length + 4) & ~3; dataOffset = sfatEntry.dataEnd; } //SFNT bw.WriteStruct(new SFNTHeader()); if (usesSFNT) { foreach (var afi in Files) { bw.WriteASCII(afi.FileName + "\0"); bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3; } } //FileData bw.WriteAlignment(header.dataOffset); foreach (var afi in Files) { bw.WriteAlignment(Support.Pad((int)bw.BaseStream.Length, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU)); //(unusual) padding scheme through filenames afi.FileData.CopyTo(bw.BaseStream); } bw.BaseStream.Position = 0; header.fileSize = (int)bw.BaseStream.Length; bw.WriteStruct(header); } }
public void Save(Stream output) { void Align(Stream input) => input.Position = (input.Position + (mediaUnitSize - 1)) & ~(mediaUnitSize - 1); void RomFSAlign(Stream input) => input.Position = (input.Position + (0x1000 - 1)) & ~(0x1000 - 1); output.Seek(ncchHeaderSize, SeekOrigin.Begin); ncchHeader.rsa2048 = new byte[0x100]; if (exHeader != null) { var exHFile = Files.Where(f => f.FileName == "ExHeader.bin").First(); ncchHeader.exHeaderSize = (int)exHFile.FileSize; ncchHeader.exHeaderHash = Kontract.Hash.SHA256.Create(exHFile.FileData); exHFile.FileData.CopyTo(output); Align(output); } if (plainRegion != null) { var plRFile = Files.Where(f => f.FileName == "PlainRegion.bin").First(); ncchHeader.plainRegionOffset = (int)Math.Ceiling((double)output.Position / mediaUnitSize); ncchHeader.plainRegionSize = (int)Math.Ceiling((double)plRFile.FileSize / mediaUnitSize); plRFile.FileData.CopyTo(output); Align(output); } if (logoRegion != null) { var loRFile = Files.Where(f => f.FileName == "Logo.icn").First(); ncchHeader.plainRegionOffset = (int)Math.Ceiling((double)output.Position / mediaUnitSize); ncchHeader.plainRegionSize = (int)Math.Ceiling((double)loRFile.FileSize / mediaUnitSize); loRFile.FileData.CopyTo(output); Align(output); } if (exeFS != null) { var exeFSOffset = output.Position; var exeFSSize = ExeFSBuilder.Rebuild(output, Files.Where(f => f.FileName.StartsWith("ExeFS\\")).Select(f => (ExeFSFileInfo)f).ToList(), "ExeFS\\"); ncchHeader.exeFSOffset = (int)Math.Ceiling((double)exeFSOffset / mediaUnitSize); ncchHeader.exeFSSize = (int)Math.Ceiling((double)exeFSSize / mediaUnitSize); ncchHeader.exeFSSuperBlockHash = Kontract.Hash.SHA256.Create(output, exeFSOffset, ExeFS.exeFSHeaderSize); RomFSAlign(output); } if (romFS != null) { var romFSOffset = output.Position; var romFSSize = RomFSBuilder.Rebuild(output, romFSOffset, Files.Where(f => f.FileName.StartsWith("RomFS\\")).ToList(), "RomFS\\"); ncchHeader.romFSOffset = (int)Math.Ceiling((double)romFSOffset / mediaUnitSize); ncchHeader.romFSSize = (int)Math.Ceiling((double)romFSSize / mediaUnitSize); ncchHeader.romFSHashRegSize = (int)Math.Ceiling((double)RomFSBuilder.SuperBlockSize / mediaUnitSize); ncchHeader.romFSSuperBlockHash = RomFSBuilder.SuperBlockHash; output.Position = romFSOffset + romFSSize; Align(output); } //Header output.Seek(0, SeekOrigin.Begin); using (var bw = new BinaryWriterX(output)) bw.WriteStruct(ncchHeader); }
public void Save(string filename) { var parStr = new List <byte[]>(); foreach (var label in Labels) { parStr.Add(ParseString(label.Text)); } using (BinaryWriterX bw = new BinaryWriterX(File.Create(filename), byteOrder)) { bw.BaseStream.Position = headerSize; //INF1 bw.Write(Encoding.ASCII.GetBytes("INF1")); bw.Write((0x10 + items.Count * (0x4 + items[0].attr.Length) + align) & ~align); bw.Write((short)items.Count); bw.Write((short)(0x4 + items[0].attr.Length)); bw.BaseStream.Position += 4; var strOffset = items[0].strOffset; for (int i = 0; i < items.Count; i++) { bw.Write(strOffset); bw.Write(items[i].attr); strOffset += parStr[i].Length; } bw.WriteAlignment(align + 1); //DAT1 bw.Write(Encoding.ASCII.GetBytes("DAT1")); bw.Write((0x8 + items[0].strOffset + parStr.Aggregate(0, (o, i) => o += i.Length) + align) & ~align); bw.Write(new byte[items[0].strOffset]); foreach (var str in parStr) { bw.Write(str); } bw.WriteAlignment(align + 1); //MID1 if (midUsed) { bw.Write(Encoding.ASCII.GetBytes("MID1")); bw.Write((0x10 + Labels.Count * 0x4 + align) & ~align); bw.Write((short)Labels.Count); bw.Write(midUnk1); bw.BaseStream.Position += 4; foreach (var label in Labels) { bw.Write(label.TextID); } bw.WriteAlignment(align + 1); } //Header bw.BaseStream.Position = 0; header.fileSize = (int)bw.BaseStream.Length; bw.WriteStruct(header); } }
private void SaveZeldaGar(Stream input) { using (var bw = new BinaryWriterX(input)) { var files = Files.OrderBy(x => x.ext.Length).ToList(); //get Extension and their count List <string> exts = new List <string>(); List <int> extsCount = new List <int>(); foreach (var file in files) { if (!exts.Contains(Path.GetExtension(file.FileName).Split('.')[1])) { exts.Add(Path.GetExtension(file.FileName).Split('.')[1]); extsCount.Add(1); } else { extsCount[exts.FindIndex(x => x == Path.GetExtension(file.FileName).Split('.')[1])]++; } } //get offsets int chunkIDOffset = 0x20 + (exts.Count + 1) * 0x10; int chunkInfOffset = chunkIDOffset + 8 + files.Count * 0x4; for (int i = 0; i < exts.Count; i++) { chunkInfOffset += (exts[i].Length + 1); while (chunkInfOffset % 4 != 0) { chunkInfOffset++; } } int nameOffset = chunkInfOffset + files.Count * 0xc; int offListOffset = nameOffset; for (int i = 0; i < files.Count; i++) { offListOffset += files[i].FileName.Length + 1; offListOffset += files[i].FileName.Split('.')[0].Length + 1; while (offListOffset % 4 != 0) { offListOffset++; } } int dataOffset = offListOffset + files.Count * 0x4; bw.BaseStream.Position = 0x20; //write chunkEntries int tmp = chunkIDOffset; for (int i = 0; i <= exts.Count; i++) { if (i == 0) { bw.Write(0); bw.Write(0xFFFFFFFF); bw.Write(tmp); bw.Write(0xFFFFFFFF); tmp += 8; } else { bw.Write(extsCount[i - 1]); bw.Write(tmp); bw.Write(tmp + extsCount[i - 1] * 4); bw.Write(0xFFFFFFFF); var padding = 0; while ((exts[i - 1].Length + 1 + padding) % 4 != 0) { padding++; } tmp += extsCount[i - 1] * 4 + exts[i - 1].Length + 1 + padding; } } //write chunkIDs and magics int id = 0; for (int i = 0; i <= exts.Count; i++) { if (i == 0) { bw.WriteASCII("unknown"); bw.Write((byte)0); } else { for (int j = 0; j < extsCount[i - 1]; j++) { bw.Write(id++); } bw.WriteASCII(exts[i - 1]); bw.Write((byte)0); while (bw.BaseStream.Position % 4 != 0) { bw.BaseStream.Position++; } } } //write chunkInfos tmp = nameOffset; foreach (var file in files) { bw.Write((uint)file.FileSize); bw.Write(tmp + file.FileName.Length + 1); bw.Write(tmp); tmp += file.FileName.Length + 1 + file.FileName.Split('.')[0].Length + 1; while (tmp % 4 != 0) { tmp++; } } //write names foreach (var file in files) { bw.WriteASCII(file.FileName); bw.Write((byte)0); bw.WriteASCII(file.FileName.Split('.')[0]); bw.Write((byte)0); while (bw.BaseStream.Position % 4 != 0) { bw.BaseStream.Position++; } } //write offsets tmp = dataOffset; foreach (var file in files) { bw.Write(tmp); tmp += (int)file.FileSize; } //write fileData foreach (var file in files) { file.FileData.CopyTo(bw.BaseStream); } //Header bw.BaseStream.Position = 0; _header.fileSize = (uint)bw.BaseStream.Length; _header.fileChunks = (short)(exts.Count + 1); _header.fileCount = (short)files.Count; _header.chunkInfOffset = chunkInfOffset; _header.offset3 = offListOffset; bw.WriteStruct(_header); } }
public void Save(Stream output) { var files = Files.Where(f => f.State != ArchiveFileState.Deleted).ToList(); //Update content Indeces ciaHeader.contentIndex = new byte[0x2000]; for (int i = 0; i < files.Count / 8; i++) { ciaHeader.contentIndex[i] = 0xFF; } if (files.Count % 8 > 0) { var ind = files.Count / 8; for (int i = 0; i < files.Count % 8; i++) { ciaHeader.contentIndex[ind] = (byte)((ciaHeader.contentIndex[ind] >> 1) | 0x80); } } //update contentCount in TMD tmd.header.contentCount = tmd.contentInfoRecord[0].contentChunkCount = (short)files.Count; //Update contentRecords var index = 0; tmd.contentChunkRecord = new List <TMD.ContentChunkRecord>(); foreach (var f in files) { tmd.contentChunkRecord.Add(new TMD.ContentChunkRecord { contentID = index, contentIndex = (short)index++, contentType = (short)((index == 1) ? 0 : 0x4000), contentSize = (long)f.FileSize, sha256 = Kontract.Hash.SHA256.Create(f.FileData) }); } using (var bw = new BinaryWriterX(output)) { bw.BaseStream.Position = ciaHeader.headerSize; bw.WriteAlignment(alignement); //CertChain certChain.Write(bw.BaseStream); bw.WriteAlignment(alignement); //Ticket ticket.Write(bw.BaseStream); bw.WriteAlignment(alignement); //TMD ciaHeader.tmdSize = tmd.Write(bw.BaseStream); bw.WriteAlignment(alignement); //Actual data var dataOffset = bw.BaseStream.Position; foreach (var f in files) { f.FileData.CopyTo(bw.BaseStream); } //CIA Header bw.BaseStream.Position = 0; ciaHeader.contentSize = bw.BaseStream.Length - dataOffset; bw.WriteStruct(ciaHeader); } }
public void Save(Stream output) { using (var bw = new BinaryWriterX(output, ByteOrder)) { Header.Block1 = (uint)((int)HeaderInfo.Version | (HeaderInfo.Unknown1 << 12) | (HeaderInfo.Unused1 << 24) | ((int)HeaderInfo.AlphaChannelFlags << 28)); Header.Block2 = (uint)(HeaderInfo.MipMapCount | (HeaderInfo.Width << 6) | (HeaderInfo.Height << 19)); Header.Block3 = (uint)(HeaderInfo.Unknown2 | ((int)HeaderInfo.Format << 8) | (HeaderInfo.Unknown3 << 16)); bw.WriteStruct(Header); //var format = HeaderInfo.Format.ToString().StartsWith("DXT1") ? Format.DXT1 : HeaderInfo.Format.ToString().StartsWith("DXT5") ? Format.DXT5 : HeaderInfo.Format; Settings.Format = (HeaderInfo.Version == image_mt.Version._Switchv1) ? SwitchFormats[HeaderInfo.Format] : Formats[HeaderInfo.Format]; if ((Format)HeaderInfo.Format == Format.DXT5_B) { Settings.PixelShader = ToNoAlpha; } else if ((Format)HeaderInfo.Format == Format.DXT5_YCbCr) { Settings.PixelShader = ToOptimisedColors; } List <byte[]> bitmaps = new List <byte[]>(); foreach (var bmp in Bitmaps) { //Set possible Swizzles if (HeaderInfo.Version == image_mt.Version._3DSv1 || HeaderInfo.Version == image_mt.Version._3DSv2 || HeaderInfo.Version == image_mt.Version._3DSv3) { Settings.Swizzle = new CTRSwizzle(bmp.Width, bmp.Height); } else if (HeaderInfo.Version == image_mt.Version._Switchv1) { Settings.Swizzle = new SwitchSwizzle(bmp.Width, bmp.Height, Settings.Format.BitDepth, GetSwitchSwizzleFormat(Settings.Format.FormatName)); //Switch Swizzle } else if (Settings.Format.FormatName.Contains("DXT")) { Settings.Swizzle = new BlockSwizzle(bmp.Width, bmp.Height); } bitmaps.Add(Common.Save(bmp, Settings)); } // Mipmaps, but not for Version 3DS v1 if (HeaderInfo.Version != image_mt.Version._3DSv1) { if (HeaderInfo.Version == image_mt.Version._Switchv1) { bw.Write(bitmaps.Sum(b => b.Length)); } var offset = HeaderInfo.Version == image_mt.Version._PS3v1 ? HeaderInfo.MipMapCount * sizeof(int) + HeaderLength : 0; foreach (var bitmap in bitmaps) { bw.Write(offset); offset += bitmap.Length; } } // Bitmaps foreach (var bitmap in bitmaps) { bw.Write(bitmap); } } }
public void Save(string filename) { using (BinaryWriterX bw = new BinaryWriterX(File.Create(filename))) { var textOffset = 0x40 + entries.Count() * 0x20 + sceEntries.Count() * 0x8; //Write texts and update textEntries bw.BaseStream.Position = textOffset; var count = 0; for (int i = 0; i < entries.Count(); i++) { entries[i].nameOffset = (int)bw.BaseStream.Position; entries[i].nameLength = Encoding.ASCII.GetByteCount(Labels[count].Name); bw.Write(Encoding.ASCII.GetBytes(Labels[count].Name)); bw.WritePadding(2); bw.WriteAlignment(2); entries[i].stringOffset = (int)bw.BaseStream.Position; entries[i].stringLength = Encoding.GetEncoding("UTF-16").GetByteCount(Labels[count].Text) / 2; var modText = Labels[count++].Text.Replace("\r\n", "\x1b"); entries[i].stringLength += modText.Count(m => m == '\x1b'); bw.Write(Encoding.GetEncoding("UTF-16").GetBytes(modText)); bw.WritePadding(4 + modText.Count(m => m == '\x1b') * 4); } bw.WriteAlignment(4); //Write scenario Containers and update sceEntries count = 0; for (int i = 0; i < sceEntries.Count(); i++) { if ((bw.BaseStream.Position & 0x4) == 0) { bw.WritePadding(4); } if (sceEntries[i].containerOffset != 0) { sceEntries[i].containerOffset = (int)bw.BaseStream.Position; foreach (var sceTextEntry in scenarios[count++]) { bw.Write(sceTextEntry); } } } //final nulls, they seem to have no reason to exist ;) bw.WritePadding(textOffset); //Write both tables bw.BaseStream.Position = 0x40; foreach (var entry in entries) { bw.WriteStruct(entry); } foreach (var sceContainer in sceEntries) { bw.WriteStruct(sceContainer); } //Header bw.BaseStream.Position = 0x0; bw.WriteStruct(header); bw.WriteStruct(entryHeader); bw.BaseStream.Position += 0x10; bw.WriteStruct(sceHeader); bw.Write(unk1); } }
public void Save(Stream input, bool leaveOpen) { using (BinaryWriterX bw = new BinaryWriterX(input, leaveOpen)) { //check original sizes CheckOriginalSizes(); //Write CTPK Header bw.WriteStruct(header); bw.BaseStream.Position = 0x20; //Write TexEntries foreach (var entry in entries) { bw.WriteStruct(entry.texEntry); } //Write dataSizes foreach (var entry in entries) { foreach (var size in entry.dataSizes) { bw.Write(size); } } //Write names foreach (var entry in entries) { bw.WriteASCII(entry.name + "\0"); } //Write hashes bw.BaseStream.Position = (bw.BaseStream.Position + 0x3) & ~0x3; List <HashEntry> hash = entries.Select(c => c.hash).OrderBy(c => c.crc32).ToList(); foreach (var entry in hash) { bw.WriteStruct(entry); } //Write mipmapInfo foreach (var entry in entries) { bw.WriteStruct(entry.mipmapEntry); } //Write bitmaps bw.BaseStream.Position = header.texSecOffset; var index = 0; foreach (var entry in entries) { var settings = new ImageSettings { Width = bmps[index].bmp.Width, Height = bmps[index].bmp.Height, Format = ImageSettings.ConvertFormat(entry.texEntry.imageFormat), PadToPowerOf2 = false }; bw.Write(Common.Save(bmps[index++].bmp, settings)); if (entry.texEntry.mipLvl > 1) { for (int i = 1; i < entry.texEntry.mipLvl; i++) { settings = new ImageSettings { Width = bmps[index].bmp.Width << i, Height = bmps[index].bmp.Height << i, Format = ImageSettings.ConvertFormat(entry.mipmapEntry.mipmapFormat), PadToPowerOf2 = false }; bw.Write(Common.Save(bmps[index++].bmp, settings)); } } } } }
public void Save(string filename) { var ascii = Encoding.ASCII; var utf16 = Encoding.Unicode; var texts = new List <byte[]>(); var names = new List <byte[]>(); foreach (var label in Labels) { texts.Add(utf16.GetBytes(label.Text + "\0")); names.Add(ascii.GetBytes(label.Name + "\0")); } var papaHeaderSize = 0x8; var entryHeaderSize = 0x14; var entryCount = Labels.Count; using (BinaryWriterX bw = new BinaryWriterX(File.Create(filename))) { //PAPA Header bw.WriteASCII("PAPA\0\0\0\0"); //Offset list var offsetHeader = new OffsetHeader(); offsetHeader.entryCount = entryCount + 1; offsetHeader.dataSize = (entryCount + 1) * sizeof(int) + papaHeaderSize; bw.WriteStruct(offsetHeader); //Offsets var initOff = offsetHeader.headerSize + offsetHeader.dataSize; for (int i = 0; i < entryCount; i++) { bw.Write(initOff); initOff += entryHeaderSize + 4 + texts[i].Length; initOff = (initOff + 3) & ~3; initOff += names[i].Length; initOff = (initOff + 3) & ~3; } bw.Write(initOff); //Entries for (int i = 0; i < entryCount; i++) { var entryDataSize = (((entryHeaderSize + 4 + texts[i].Length + 3) & ~3) + names[i].Length + 3) & ~3; bw.Write(entryDataSize); bw.Write(3); bw.Write(0x14); bw.Write(0x18); bw.Write((entryHeaderSize + 4 + texts[i].Length + 3) & ~3); bw.WriteASCII("Msg\0"); bw.Write(texts[i]); bw.WriteAlignment(4); bw.Write(names[i]); bw.WriteAlignment(4); } //End Mark Entry bw.Write(0); bw.Write(0); } }
public void Save(Stream xfsa) { //Update FileInfo int offset = 0; foreach (var file in Files) { entries[file.dirEntry.fileEntryOffset + file.fileCountInDir].offset = offset >> 4; file.fileEntry.offset = offset >> 4; entries[file.dirEntry.fileEntryOffset + file.fileCountInDir].size = (int)file.FileSize; file.fileEntry.size = (int)file.FileSize; var newOffset = ((offset + file.FileSize) % 16 == 0) ? offset + file.FileSize + 16 : (offset + file.FileSize + 0xf) & ~0xf; offset = (int)newOffset; } using (var bw = new BinaryWriterX(xfsa)) { //Table 0 bw.BaseStream.Position = 0x24; header.table0Offset = (int)bw.BaseStream.Position; header.table0EntryCount = (short)table0.Count; bw.Write(CompressTable(table0, table0Comp)); //Table 1 bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3; header.table1Offset = (int)bw.BaseStream.Position; header.table1EntryCount = (short)table1.Count; bw.Write(CompressTable(table1, table1Comp)); //FileEntries bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3; header.fileEntryTableOffset = (int)bw.BaseStream.Position; header.fileEntryCount = entries.Count; bw.Write(CompressTable(entries, entriesComp)); //StringTable bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3; header.nameTableOffset = (int)bw.BaseStream.Position; bw.Write(Level5.Compress(new MemoryStream(stringTable), stringComp)); //FileData bw.BaseStream.Position = (bw.BaseStream.Position + 0xf) & ~0xf; header.dataOffset = (int)bw.BaseStream.Position; foreach (var file in Files) { bw.BaseStream.Position = header.dataOffset + (file.fileEntry.offset << 4); file.FileData.CopyTo(bw.BaseStream); if (bw.BaseStream.Position % 16 == 0) { bw.WritePadding(16); } else { bw.WriteAlignment(16); } } //Header bw.BaseStream.Position = 0; bw.WriteStruct(header); } //Table 1 /*var ms = new MemoryStream(); * new BinaryWriterX(ms, true).WriteMultiple(table0); * ms.Position = 0; * var newTable1 = Level5.Compress(ms, (Level5.Method)table1Comp); * * //Table 2 * ms = new MemoryStream(); * new BinaryWriterX(ms, true).WriteMultiple(table1); * ms.Position = 0; * var newTable2 = Level5.Compress(ms, (Level5.Method)table2Comp); * * //Update Entries * Files = Files.OrderBy(f => f.entry.entry.comb1 & 0x01ffffff).ToList(); * int offset = 0; * foreach (var file in Files) offset = file.UpdateEntry(offset); * * //Get compressed Entry section * Files = Files.OrderBy(f => f.entry.ID).ToList(); * ms = new MemoryStream(); * new BinaryWriterX(ms, true).WriteMultiple(Files.Select(f => f.entry.entry)); * ms.Position = 0; * var newEntryTable = Level5.Compress(ms, (Level5.Method)entriesComp); * * //Update header * header.nameTableOffset = (uint)(0x24 + ((newTable1.Length + 3) & ~3) + ((newTable2.Length + 3) & ~3) + ((newEntryTable.Length + 3) & ~3)); * header.dataOffset = (uint)(((header.nameTableOffset + nameC.Length) + 0xf) & ~0xf); * * using (BinaryWriterX bw = new BinaryWriterX(xfsa)) * { * //Header * bw.WriteStruct(header); * * //Table 1 * bw.Write(newTable1); * bw.WriteAlignment(4); * * //Table 2 * bw.Write(newTable2); * bw.WriteAlignment(4); * * //Entries * bw.Write(newEntryTable); * bw.WriteAlignment(4); * * //Names * bw.Write(nameC); * bw.WriteAlignment(); * * //Files * Files = Files.OrderBy(f => f.entry.entry.comb1 & 0x01ffffff).ToList(); * foreach (var file in Files) * { * file.FileData.CopyTo(bw.BaseStream); * if (bw.BaseStream.Position % 0x10 != 0) * bw.WriteAlignment(); * else * { * bw.Write(new byte[0x10]); * } * } * * * //FileEntries Table * //bw.Write((entries.Count * 0xc) << 3); * * /*uint offset = 0; * List<XFSAFileInfo> files = new List<XFSAFileInfo>(); * foreach (var entry in entries) * { * var file = Files.Find(c => c.entry.comb1 == entry.comb1); * files.Add(file); * * //catch file limits * if (file.FileData.Length >= 0x100000) * { * throw new Exception("File " + file.FileName + " is too big to pack into this archive type!"); * } * else if (offset + dataOffset >= 0x20000000) * { * throw new Exception("The archive can't be bigger than 0x10000000 Bytes."); * } * * //edit entry * entry.comb1 = (entry.comb1 & 0xfe000000) | (offset >> 4); * entry.comb2 = (entry.comb1 & 0xfff00000) | ((uint)file.FileData.Length); * * //write entry * bw.WriteStruct(entry); * * //edit values * offset = (uint)(((offset + file.FileData.Length) + 0xf) & ~0xf); * }*/ //Nametable //bw.Write(nameC); //Files //bw.BaseStream.Position = dataOffset; //foreach (var file in files) //{ // file.FileData.CopyTo(bw.BaseStream); // bw.BaseStream.Position = (bw.BaseStream.Position + 0xf) & ~0xf; //} //Header //header.nameTableOffset = (uint)(0x24 + table1.Length + table2.Length + entries.Count * 0xc + 4); //header.dataOffset = (uint)dataOffset; //bw.BaseStream.Position = 0; //bw.WriteStruct(header); //} }
public void Save(Stream output) { using (var bw = new BinaryWriterX(output)) { // Header bw.Write(Magic); bw.Write(Count); bw.Write(nIDOffset); bw.Write(Unk1); bw.Write(nIDStringOffset); bw.Write(pstrBgmNameOffset); bw.Write(pstrArtistNameOffset); bw.Write(pstrFileNameOffset); bw.Write(nOrderOffset); bw.Write(nMixOffset); bw.Write(pstrRcidOffset); bw.Write(Unk2); bw.Write(Unk3); bw.WritePadding(0x10, 0x77); // Constant Strings bw.BaseStream.Position = nIDStringOffset; bw.WriteASCII(nIDString); bw.Write((byte)0); bw.WriteASCII(pstrBgmNameString); bw.Write((byte)0); bw.WriteASCII(pstrArtistNameString); bw.Write((byte)0); bw.WriteASCII(pstrFileNameString); bw.Write((byte)0); bw.WriteASCII(nOrderString); bw.Write((byte)0); bw.WriteASCII(nMixString); bw.Write((byte)0); bw.WriteASCII(pstrRcidString); bw.Write((byte)0); // BgmName Data.pstrBgmNameOffset = (int)bw.BaseStream.Position; bw.WriteASCII(BgmName); bw.Write((byte)0); // ArtistName Data.pstrArtistNameOffset = (int)bw.BaseStream.Position; bw.WriteASCII(ArtistName); bw.Write((byte)0); // FileName Data.pstrFileNameOffset = (int)bw.BaseStream.Position; bw.WriteASCII(FileName); bw.Write((byte)0); // Rcid Data.pstrRcidOffset = (int)bw.BaseStream.Position; bw.WriteASCII(Rcid); bw.Write((byte)0); // Data bw.BaseStream.Position = nIDOffset; Data.nID -= 1; bw.WriteStruct(Data); bw.WritePadding(0x4, 0x77); } }