/// <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> /// Parses the TPI from specified <see cref="MemoryStream"/>. /// </summary> /// <param name="Stream">Instance of <see cref="MemoryStream"/> containing the TPI file data.</param> /// <returns>Parsed data of TPI as <see cref="TPIPackageClass"/>.</returns> public static TPIPackageClass FromStream(MemoryStream Stream) { using (Stream Bytes = new MemoryStream(Stream.ToArray())) { try { TPIPackageClass Pack = Expressions.CreateTPIPackage(); while (ConditionsOK(Bytes)) { uint Header = Expressions.GetUNumber(Expressions.GetBytes(Bytes, 0, 4)); if (Header == (uint)ChunkType.Head) { //Processing the HEAD. Reading first 4 bytes to find out length. int Next = Expressions.GetNumber(Expressions.GetBytes(Bytes, 0, 4)); //Buaa getting all bytes now. byte[] Data = Expressions.GetBytes(Bytes, 0, Next); Pack.PackageID = Expressions.GetCRCID(Data.SubArray(0, 4)); //Next 4 bytes are indicating total files used by this TPI. But it is read-only because it uses the ones //actually parsed by the parser. //Now, we should have DATA. Ending this if else. } else if (Header == (uint)ChunkType.Data) { //Processing the DATA. int Next = Expressions.GetNumber(Expressions.GetBytes(Bytes, 0, 4)); //Fun part ;) int NameLen = Expressions.GetUNumber16(Expressions.GetBytes(Bytes, 0, 2)); Pack.PackageName = Expressions.GetText(Bytes, 0, NameLen); int VerLen = Expressions.GetUNumber16(Expressions.GetBytes(Bytes, 0, 2)); Pack.PackageVer = Expressions.GetText(Bytes, 0, VerLen); int OwnerLen = Expressions.GetUNumber16(Expressions.GetBytes(Bytes, 0, 2)); Pack.PackageOwner = Expressions.GetText(Bytes, 0, OwnerLen); Pack.Type = (PackageType)Expressions.GetNumber(Expressions.GetBytes(Bytes, 0, 4)); //Now, we should have FILEs. Ending this if else and letting while continue it's work. } else if (Header == (uint)ChunkType.File) { TTFileClass File = Expressions.CreateTTFile(); int Next = Expressions.GetNumber(Expressions.GetBytes(Bytes, 0, 4)); File.CRC = Expressions.GetCRCID(Expressions.GetBytes(Bytes, 0, 4)); File.FileSize = Expressions.GetUNumber(Expressions.GetBytes(Bytes, 0, 4)); int namelen = Expressions.GetUNumber16(Expressions.GetBytes(Bytes, 0, 2)); File.FileName = Expressions.GetText(Bytes, 0, namelen); //No NULs after file name, so let while loop read next header if Stream not ended. //Let's add file to collection... Pack.Files.Add(File); } else { //Hmm... } } //Return when everything is good to go. return(Pack); } catch (Exception ex) { throw new TPIParserException("Failed to parse TPI.", ex); //Wrapping the exception to our TPIParserException class. } } }