public static void Create(string path, ContentTree tree, PostprocessFileCallback postprocessFileCallback = null) { using (MemoryStream tableStream = new MemoryStream()) using (MemoryStream dataStream = new MemoryStream()) { WriteContentTreeSection(tree.Root, tableStream, dataStream, postprocessFileCallback); Stream stream; if (DualityApp.ExecContext == DualityApp.ExecutionContext.Game || DualityApp.ExecContext == DualityApp.ExecutionContext.Server) { stream = DualityApp.SystemBackend.FileSystem.CreateFile(path); } else { stream = File.Create(path); } using (stream) { using (BinaryWriter w = new BinaryWriter(stream, Encoding.UTF8, true)) { w.Write((uint)0x5A616544u); // Signature w.Write((byte)1); // Version w.Write((uint)tableStream.Position); } tableStream.Position = 0; tableStream.CopyTo(stream); dataStream.Position = 0; dataStream.CopyTo(stream); } } }
private static void WriteContentTreeSection(ContentTree.Node node, Stream tableStream, Stream dataStream, PostprocessFileCallback postprocessFileCallback) { using (BinaryWriter w = new BinaryWriter(tableStream, Encoding.UTF8, true)) { ResourceFlags flags = 0; if (node.Children.Count > 0) { flags |= ResourceFlags.HasChildren; } if (node.Source != null) { flags |= ResourceFlags.HasResource; flags &= ~ResourceFlags.External; } Stream overrideStream = null; if (postprocessFileCallback != null) { postprocessFileCallback(node, ref flags, ref overrideStream); } try { w.Write((byte)flags); w.WriteAsciiString(node.Name); if ((flags & ResourceFlags.HasChildren) != 0) { w.Write((ushort)node.Children.Count); } if ((flags & ResourceFlags.HasResource) != 0) { if ((flags & ResourceFlags.External) != 0) { if (overrideStream != null) { throw new InvalidOperationException("Cannot use overrideStream with ResourceFlags.External"); } FileResourceSource source = node.Source as FileResourceSource; if (source == null) { throw new InvalidOperationException("Specified resource must be saved as file"); } w.WriteAsciiString(source.Path); w.Write((uint)source.Offset); w.Write((uint)source.Size); } else { long offset = dataStream.Position; if (overrideStream != null) { if ((flags & ResourceFlags.Compressed) != 0) { using (DeflateStream ds = new DeflateStream(dataStream, CompressionLevel.Optimal, true)) { overrideStream.CopyTo(ds); } } else { overrideStream.CopyTo(dataStream); } } else { using (Stream stream = (flags & ResourceFlags.Compressed) != 0 ? node.Source.GetCompressedStream() : node.Source.GetUncompressedStream()) { stream.CopyTo(dataStream); } } long size = (dataStream.Position - offset); w.Write((uint)offset); w.Write((uint)size); } } } finally { if (overrideStream != null) { overrideStream.Dispose(); } } } foreach (ContentTree.Node children in node.Children) { WriteContentTreeSection(children, tableStream, dataStream, postprocessFileCallback); } }