/// <summary> /// Parses the TTFS data from specified <see cref="MemoryStream"/>. /// </summary> /// <param name="Stream">Instance of <see cref="MemoryStream"/> containing the TTFS data.</param> /// <returns>Parsed data of TTFS data as <see cref="TTFSDataClass"/>.</returns> /// <exception cref="TTFSParserException">Occurs when a general parsing exception thrown wrapping the original exception data.</exception> public static TTFSDataClass FromStream(MemoryStream Stream) { try { TTFSDataClass Class = Expressions.CreateTTFSData(); using (Stream Bytes = new MemoryStream(Stream.ToArray())) { while (TPIClass.ConditionsOK(Bytes)) { uint Header = Expressions.GetUNumber(Expressions.GetBytes(Bytes, 0, 4)); if (Header == (uint)ChunkType.Package) //Doc: GKCP<Weird 4 Bytes (Length of TPI)><Content> { //Processing the GKCP. Reading first 4 bytes to find out length. //Every PCKG starts with length, but the length string is terminated with "€" everytime. And it's HEX value is 20AC. //So we're ignoring it as it still works without it and it messes up the stuff. var ABytes = Expressions.GetBytes(Bytes, 0, 4); ABytes[3] = (byte)0x00; uint Next = Expressions.GetUNumber(ABytes); //The thing we just read must be a whole TPI now. byte[] Data = Expressions.GetBytes(Bytes, 0, (int)Next); try { Class.Packages.Add(TPIClass.FromBytes(Data)); //Parsing the TPI and adding output to enumeration. } catch (Exception Ex) { //Uh-oh! TPI parser failed. throw new FormatException("Failed to parse TTFS Package Data.", Ex); } } else //We don't expect to receive something else from this. Throwing an exception... { throw new FormatException("Received an invalid header from file."); } } } //Return when everything is good to go. return(Class); } catch (Exception ex) { if (ex is TPIParserException) { throw ex; } else { throw new TTFSParserException("Failed to parse TTFS Data.", ex); //Wrapping the exception to our TTFSParserException class. } } }
/// <summary> /// Saves the specified <see cref="TTFSDataClass"/> into a <see cref="MemoryStream"/> /// </summary> /// <param name="Dat">Instance of <see cref="TTFSDataClass"/> which will be saved.</param> /// <returns>An instance of <see cref="MemoryStream"/> saved into Renegade-readable format.</returns> /// <exception cref="TTFSParserException">Occurs when a general saving exception thrown wrapping the original exception data.</exception> public static MemoryStream Save(TTFSDataClass Dat) { try { using (MemoryStream ms = new MemoryStream()) { foreach (TPIPackageClass TPI in Dat.Packages) { using (var Stream = TPIClass.Save(TPI)) { ms.Write("GKCP"); long len = Stream.Length & 0x7FFFFFFF; if ((len & 0x80000000) != 0) { len |= 0x80000000; } var barr = BitConverter.GetBytes((uint)len); Array.Resize(ref barr, 3); ms.Write(barr); ms.Write(Encoding.Default.GetBytes("€")); Stream.WriteTo(ms); } } MemoryStream Str = new MemoryStream(); ms.WriteTo(Str); return(Str); } } catch (Exception ex) { if (ex is TPIParserException) { throw ex; } else { throw new TTFSParserException("Failed to save TTFS Data.", ex); //Wrapping the exception to our TTFSParserException class. } } }
/// <summary> /// Saves the specified <see cref="TTFSDataClass"/> into a file. /// </summary> /// <param name="Dat">Instance of <see cref="TTFSDataClass"/> which will be saved.</param> /// <param name="FileLoc">Path to the target file.</param> /// <exception cref="TTFSParserException">Occurs when a general saving exception thrown wrapping the original exception data.</exception> public static void Save(TTFSDataClass Dat, string FileLoc) => File.WriteAllBytes(FileLoc, Save(Dat).ToArray());