using System; using System.IO; using System.Text; using System.Threading.Tasks; namespace RobloxFiles { /// <summary> /// Represents a loaded Roblox place/model file. /// RobloxFile is an Instance and its children are the contents of the file. /// </summary> public abstract class RobloxFile : Instance { public static bool LogErrors = false; protected abstract void ReadFile(byte[] buffer); /// <summary> /// Saves this RobloxFile to the provided stream. /// </summary> /// <param name="stream">The stream to save to.</param> public abstract void Save(Stream stream); /// <summary> /// Opens a RobloxFile using the provided buffer. /// </summary> /// <returns>The opened RobloxFile.</returns> public static RobloxFile Open(byte[] buffer) { if (buffer.Length > 14) { string header = Encoding.UTF7.GetString(buffer, 0, 14); RobloxFile file = null; if (header == BinaryRobloxFile.MagicHeader) file = new BinaryRobloxFile(); else if (header.StartsWith("<roblox")) file = new XmlRobloxFile(); if (file != null) { file.ReadFile(buffer); return file; } } throw new Exception("Unrecognized header!"); } /// <summary> /// Opens a Roblox file by reading from a provided Stream. /// </summary> /// <param name="stream">The stream to read the Roblox file from.</param> /// <returns>The opened RobloxFile.</returns> public static RobloxFile Open(Stream stream) { byte[] buffer; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); buffer = memoryStream.ToArray(); } return Open(buffer); } /// <summary> /// Opens a Roblox file from a provided file path. /// </summary> /// <param name="filePath">A path to a Roblox file to be opened.</param> /// <returns>The opened RobloxFile.</returns> public static RobloxFile Open(string filePath) { byte[] buffer = File.ReadAllBytes(filePath); return Open(buffer); } /// <summary> /// Creates and runs a Task to open a Roblox file from a byte sequence that represents the file. /// </summary> /// <param name="buffer">A byte sequence that represents the file.</param> /// <returns>A task which will complete once the file is opened with the resulting RobloxFile.</returns> public static Task<RobloxFile> OpenAsync(byte[] buffer) { return Task.Run(() => Open(buffer)); } /// <summary> /// Creates and runs a Task to open a Roblox file using a provided Stream. /// </summary> /// <param name="stream">The stream to read the Roblox file from.</param> /// <returns>A task which will complete once the file is opened with the resulting RobloxFile.</returns> public static Task<RobloxFile> OpenAsync(Stream stream) { return Task.Run(() => Open(stream)); } /// <summary> /// Opens a Roblox file from a provided file path. /// </summary> /// <param name="filePath">A path to a Roblox file to be opened.</param> /// <returns>A task which will complete once the file is opened with the resulting RobloxFile.</returns> public static Task<RobloxFile> OpenAsync(string filePath) { return Task.Run(() => Open(filePath)); } /// <summary> /// Saves this RobloxFile to the provided file path. /// </summary> /// <param name="filePath">A path to where the file should be saved.</param> public void Save(string filePath) { using (FileStream stream = File.OpenWrite(filePath)) { Save(stream); } } /// <summary> /// Asynchronously saves this RobloxFile to the provided stream. /// </summary> /// <param name="stream">The stream to save to.</param> /// <returns>A task which will complete upon the save's completion.</returns> public Task SaveAsync(Stream stream) { return Task.Run(() => Save(stream)); } /// <summary> /// Asynchronously saves this RobloxFile to the provided file path. /// </summary> /// <param name="filePath">A path to where the file should be saved.</param> /// <returns>A task which will complete upon the save's completion.</returns> public Task SaveAsync(string filePath) { return Task.Run(() => Save(filePath)); } /// <summary> /// Logs an error that occurred while opening a RobloxFile if logs are enabled. /// </summary> /// <param name="message"></param> internal static void LogError(string message) { if (!LogErrors) return; Console.Error.WriteLine(message); } } }