public void Save(System.IO.Stream stream) { using (var writer = new FileWriter(stream)) { writer.SetByteOrder(true); writer.Write(Unknowns); //ID list? long currentOffset = 0; for (int i = 0; i < Files.Count; i++) { if (currentOffset != 0) { long nextOffset = writer.Position; using (writer.TemporarySeek(currentOffset + 8, System.IO.SeekOrigin.Begin)) { writer.Write((uint)nextOffset); } } currentOffset = writer.Position; writer.Write((uint)Files[i].Type); writer.Write((uint)Files[i].FileData.Length); writer.Write((uint)0); writer.Write(new byte[20]); writer.Write(Files[i].AsBytes()); writer.AlignBytes(32); } } }
//Align the last set of bytes so everything gets encrypted back correctly static byte[] IntoBytes(string contents) { var mem = new MemoryStream(); using (var writer = new FileWriter(mem)) { writer.Write(Encoding.UTF8.GetBytes(contents)); writer.AlignBytes(128); } return(mem.ToArray()); }
private void WriteMessageData(FileWriter writer, MessageData messData, Encoding encoding, uint version) { if (messData.Entries.Count == 0) { writer.Write(messData.Data); } else { if (version <= 5) { long startPos = writer.Position; writer.Write(messData.Entries.Count); writer.Write(new uint[messData.Entries.Count]); long sectionSizePos = writer.Position; writer.Write(uint.MaxValue); for (int i = 0; i < messData.Entries.Count; i++) { writer.WriteUint32Offset(startPos + 4 + (i * 4), startPos); writer.Write((byte)0xB); WriteString(writer, messData.Entries[i].Value); writer.AlignBytes(4); } writer.WriteSectionSizeU32(sectionSizePos, writer.Position - startPos); } else { long startPos = writer.Position; writer.Write(messData.Entries.Count); writer.Write(new uint[messData.Entries.Count]); long sectionSizePos = writer.Position; for (int i = 0; i < messData.Entries.Count; i++) { writer.WriteUint32Offset(startPos + 4 + (i * 4), startPos + 4); writer.Write(((MessageEntryV2)messData.Entries[i]).ID); WriteString(writer, messData.Entries[i].Value); writer.AlignBytes(4); } } } }
public static void WriteSection(FileWriter writer, Header header, string magic, MSBTEntry section) { long startPos = writer.Position; writer.WriteSignature(magic); writer.Write(uint.MaxValue); section.Write(writer, header); long endPos = writer.Position; writer.AlignBytes(16, 0xAB); //Skip 20 bytes from the header writer.WriteSectionSizeU32(startPos + 4, startPos + 0x10, endPos); }
//Saves data in recusive order private void SaveFileData(FileWriter writer, ref uint dataPos, DirectoryEntry parentDir) { for (int i = 0; i < parentDir.Children.Count; i++) { if (parentDir.Children[i] is FileEntry) { var entry = (FileEntry)parentDir.Children[i]; long pos = writer.Position; using (writer.TemporarySeek(entry._dataOffsetPos, SeekOrigin.Begin)) { writer.Write((uint)dataPos); } writer.Write(entry.AsBytes()); writer.AlignBytes(32); dataPos += (uint)(writer.Position - pos); } if (parentDir.Children[i] is DirectoryEntry) { SaveFileData(writer, ref dataPos, (DirectoryEntry)parentDir.Children[i]); } } }
public void Write(FileWriter writer, List <APAKFileInfo> files) { writer.SetByteOrder(IsBigEndian); writer.WriteSignature("APAK"); writer.Write((ushort)0); writer.Write(Version); writer.Write(files.Count); writer.Write(Unknown1); writer.Write(files.Count * 64); writer.Write(uint.MaxValue); long fileInfoPos = writer.Position; for (int i = 0; i < files.Count; i++) { files[i].SaveFileFormat(); writer.Write(files[i].Hash); writer.Write(uint.MaxValue); writer.Write(files[i].FileData.Length); writer.Write(files[i].FileData.Length); writer.Write(files[i].Alignment); writer.Write(files[i].Unknown1); writer.Write(files[i].Unknown2); writer.Write(files[i].Unknown3); writer.WriteString(files[i].FileName, 0x20); } //The data gets ordered by largest alignment size to lowest //Then by the file name var filesSorted = files.OrderByDescending(x => x.Alignment) .ThenBy(x => x.FileName) .ToList(); writer.Align((int)files.Max(x => x.Alignment)); long pos = writer.Position; for (int i = 0; i < files.Count; i++) { var file = filesSorted[i]; int index = files.IndexOf(file); long dataPos = writer.Position; writer.WriteUint32Offset((fileInfoPos + 4) + index * 64); writer.Write(file.FileData); writer.AlignBytes((int)file.Alignment); long dataEndPos = writer.Position; using (writer.TemporarySeek((fileInfoPos + 12) + index * 64, SeekOrigin.Begin)) { writer.Write((uint)(dataEndPos - dataPos)); } } long endPos = writer.Position; uint dataSize = (uint)(endPos - pos); using (writer.TemporarySeek(0x14, SeekOrigin.Begin)) { writer.Write(dataSize); } //Idk what this format is doing but there's tons of padding at the end and idk why :( //Even combining all the alignments it can still be too small writer.AlignBytes((int)files.Sum(x => x.Alignment)); }
private void Write(FileWriter writer) { OrderLists(); writer.SetByteOrder(true); writer.Write(Version); writer.WriteString(InternalName, 0xB); writer.Write(new uint[21]); //reserve space for offsets List <Texture> textures = Textures.Values.ToList(); List <Sampler> samplers = Samplers.Values.ToList(); List <Material> materials = Materials.Values.ToList(); List <SceneGraphNode> nodes = SceneGraphs.Values.ToList(); List <ShapeBatch> batches = Batches.Values.ToList(); //Save texture header writer.WriteUint32Offset(12); long texturePos = writer.Position; for (int i = 0; i < textures.Count; i++) { textures[i].Write(writer, this); } writer.Align(32); //Save texture data for (int i = 0; i < textures.Count; i++) { writer.WriteUint32Offset(texturePos + 8 + (i * hTextureSize), texturePos); writer.Write(textures[i].ImageData); writer.Align(32); } //Save samplers writer.WriteUint32Offset(16); for (int i = 0; i < samplers.Count; i++) { samplers[i].TextureIndex = (short)textures.IndexOf(samplers[i].Texture); samplers[i].Write(writer, this); } //Save vertices List <Vector3> positions = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Vector4> colors = new List <Vector4>(); List <Vector2> texcoords = new List <Vector2>(); for (int i = 0; i < batches.Count; i++) { foreach (var packet in batches[i].Packets) { for (int v = 0; v < packet.Vertices.Length; v++) { var vert = packet.Vertices[v]; Vector3 shortPos = new Vector3( (short)vert.Position.X, (short)vert.Position.Y, (short)vert.Position.Z); if (!positions.Contains(shortPos)) { positions.Add(shortPos); } if (!normals.Contains(vert.Normal) && vert.Normal != null) { normals.Add(vert.Normal); } if (!texcoords.Contains(vert.Texcoord) && vert.Texcoord != null) { texcoords.Add(vert.Texcoord); } if (!colors.Contains(vert.Color0) && vert.Color0 != null) { colors.Add(vert.Color0); } vert.PositionIndex = (short)positions.IndexOf(vert.Position); vert.NormalIndex = (short)normals.IndexOf(vert.Normal); vert.TexCoordIndex[0] = (short)texcoords.IndexOf(vert.Texcoord); vert.Color0Index = (short)colors.IndexOf(vert.Color0); } } } writer.WriteUint32Offset(20); for (int i = 0; i < positions.Count; i++) { writer.Write((short)positions[i].X); writer.Write((short)positions[i].Y); writer.Write((short)positions[i].Z); } writer.Align(32); if (normals.Count > 0) { writer.WriteUint32Offset(24); for (int i = 0; i < normals.Count; i++) { writer.Write(normals[i].X); writer.Write(normals[i].Y); writer.Write(normals[i].Z); } writer.Align(32); } if (colors.Count > 0) { writer.WriteUint32Offset(28); for (int i = 0; i < colors.Count; i++) { writer.Write((byte)(colors[i].X * 255)); writer.Write((byte)(colors[i].Y * 255)); writer.Write((byte)(colors[i].Z * 255)); writer.Write((byte)(colors[i].W * 255)); } writer.Align(32); } if (texcoords.Count > 0) { writer.WriteUint32Offset(36); for (int i = 0; i < texcoords.Count; i++) { writer.Write(texcoords[i].X); writer.Write(texcoords[i].Y); } writer.Align(32); } writer.WriteUint32Offset(52); for (int i = 0; i < materials.Count; i++) { for (int j = 0; j < materials[i].Samplers.Count; j++) { materials[i].SamplerIndices[j] = (short)samplers.IndexOf(materials[i].Samplers[j]); } materials[i].Write(writer, this); } long batchPos = writer.Position; writer.WriteUint32Offset(56); for (int i = 0; i < Batches.Count; i++) { Batches[i].Write(writer, this); } for (int i = 0; i < Batches.Count; i++) { writer.WriteUint32Offset(batchPos + 12 + (i * hShapeBatchSize), batchPos); long pos = writer.Position; for (int d = 0; d < Batches[i].Packets.Count; d++) { Batches[i].Packets[d].Write(Batches[i], writer, this); } writer.Align(32); long endpos = writer.Position; using (writer.TemporarySeek(batchPos + 2 + (i * hShapeBatchSize), SeekOrigin.Begin)) { writer.Write((ushort)((endpos - pos) / 0x20)); } } long sceneGraphPos = writer.Position; writer.WriteUint32Offset(60); for (int i = 0; i < nodes.Count; i++) { nodes[i].Write(writer, this); } for (int i = 0; i < nodes.Count; i++) { writer.WriteUint32Offset(sceneGraphPos + 80 + (hSceneGraphSize * i), sceneGraphPos); for (int d = 0; d < nodes[i].DrawnParts.Count; d++) { var part = nodes[i].DrawnParts[d]; part.MaterialIndex = (short)materials.IndexOf(part.Material); part.ShapeBatchIndex = (short)batches.IndexOf(part.Batch); part.Write(writer, this); } } writer.AlignBytes(16); }
void Write(FileWriter writer) { writer.SetByteOrder(true); writer.Write((ushort)Banks.Count); writer.Write((ushort)Patterns.Count); writer.Write((ushort)Textures.Count); writer.Write(NumReferences); writer.Write(0); writer.Write(0); writer.Write(0); if (Patterns.Count > 0) { long patternsPos = writer.Position; writer.WriteUint32Offset(0xC); for (int i = 0; i < Patterns.Count; i++) { Patterns[i].Write(writer); } for (int i = 0; i < Patterns.Count; i++) { if (Patterns[i].Layers.Count > 0) { writer.WriteUint32Offset(patternsPos + 0xC + (i * 0x10)); foreach (var layer in Patterns[i].Layers) { writer.WriteStruct(layer); } } } } if (Banks.Count > 0) { long banksPos = writer.Position; writer.WriteUint32Offset(0x8); for (int i = 0; i < Banks.Count; i++) { Banks[i].Write(writer); } for (int i = 0; i < Banks.Count; i++) { if (Banks[i].AnimFrames.Count > 0) { writer.WriteUint32Offset(banksPos + 4 + (i * 0x08)); foreach (var frame in Banks[i].AnimFrames) { writer.WriteStruct(frame); } } } } if (Textures.Count > 0) { writer.WriteUint32Offset(0x10); long texPos = writer.Position; for (int i = 0; i < Textures.Count; i++) { writer.Write(Textures[i].Bpp); writer.Write(Textures[i].Format); if (Textures[i].PaletteData != null) { writer.Write((ushort)Textures[i].PaletteData.Length / 2); } else { writer.Write((ushort)0); } writer.Write(Textures[i].Width); writer.Write(Textures[i].Height); writer.Write(Textures[i].ImageData.Length); } writer.AlignBytes(32, 0x88); for (int i = 0; i < Textures.Count; i++) { writer.WriteUint32Offset(texPos + 0x0C + (0x14 * i)); if (Textures[i].PaletteData != null) { writer.Write(Textures[i].PaletteData); } writer.WriteUint32Offset(texPos + 0x10 + (0x14 * i)); writer.Write(Textures[i].ImageData); } } }
public void Write(FileWriter writer, FFNT Header) { Header.BlockCounter += 1; long pos = writer.Position; writer.WriteSignature("CMAP"); writer.Write(uint.MaxValue); //Section Size if (Header.Platform == FFNT.PlatformType.NX) { writer.Write((uint)CharacterCodeBegin); writer.Write((uint)CharacterCodeEnd); } else { writer.Write((ushort)CharacterCodeBegin); writer.Write((ushort)CharacterCodeEnd); } writer.Write(MappingMethod, true); writer.Seek(2); long DataPos = writer.Position; writer.Write(0); //Next Section Offset //Write the data switch (MappingMethod) { case Mapping.Direct: writer.Write(((CMAPDirect)MappingData).Offset); break; case Mapping.Table: for (int i = 0; i < ((CMAPIndexTable)MappingData).Table.Length; i++) { writer.Write(((CMAPIndexTable)MappingData).Table[i]); } break; case Mapping.Scan: writer.Write((ushort)((CMAPScanMapping)MappingData).Codes.Length); if (Header.Platform == FFNT.PlatformType.NX) writer.Seek(2); //Padding for (int i = 0; i < ((CMAPScanMapping)MappingData).Codes.Length; i++) { if (Header.Platform == FFNT.PlatformType.NX) { writer.Write((uint)((CMAPScanMapping)MappingData).Codes[i]); writer.Write(((CMAPScanMapping)MappingData).Indexes[i]); writer.Write((ushort)0); //Padding } else { writer.Write((ushort)((CMAPScanMapping)MappingData).Codes[i]); writer.Write(((CMAPScanMapping)MappingData).Indexes[i]); } } break; } writer.AlignBytes(4); //Padding //Save section size long endPos = writer.Position; using (writer.TemporarySeek(pos + 4, SeekOrigin.Begin)) { writer.Write((uint)(endPos - pos)); } if (NextCodeMapSection != null) { writer.WriteUint32Offset(DataPos, -8); NextCodeMapSection.Write(writer, Header); } }