public override void ReplaceChild(Chunk xiFrom, Chunk xiTo) { if (xiFrom == NamedImageGroups) { NamedImageGroups = (GroupingChunk)xiTo; } else if (xiFrom == OBJTFalseStart) { OBJTFalseStart = (RawDataChunk)xiTo; } else if (xiFrom == OBJT) { OBJT = (OBJTChunk)xiTo; } else if (xiFrom == Dunno) { Dunno = (RawDataChunk)xiTo; } else if (xiFrom == SHET) { SHET = (SHETChunk)xiTo; } else { throw new ArgumentException("xifrom not found!"); } }
public override void Serialise(Stream outStr) { BinaryWriter bout = new BinaryWriter(outStr); bout.Write((int)Label.Length); bout.Write((int)1); bout.Write(Label); foreach (Chunk child in mChildren) { if (child is TIMChunk) { TIMChunk childTim = (TIMChunk)child; bout.Write((int)childTim.DataLength); bout.Write((int)0); childTim.Serialise(outStr); } else if (child is RawDataChunk) { RawDataChunk childRaw = (RawDataChunk)child; bout.Write((int)childRaw.mData.Length); bout.Write((int)0); childRaw.Serialise(outStr); } else { throw new Exception("Expecting TIMChunk or RawDataChunk"); } } }
public override void Deserialise(Stream inStr) { if (inStr is FileStream) { mName = ((FileStream)inStr).Name; } //BinaryReader is little-endian BinaryReader bin = new BinaryReader(inStr); //first, a header of 4 int32s: Header = new int[4]; for (int i = 0; i < Header.Length; i++) Header[i] = bin.ReadInt32(); //then, a block of zero bytes (int32 aligned) int nextInt = bin.ReadInt32(); ZeroByteCount = 0; while (nextInt == 0) { ZeroByteCount += 4; nextInt = bin.ReadInt32(); } ArrayList imageGroups = new ArrayList(); //now, an array of image or comment structs int lTIMIdx = 0; while (nextInt != 0) { bin.BaseStream.Seek(-4, SeekOrigin.Current); NamedImageGroup nim = new NamedImageGroup(bin.BaseStream, ref lTIMIdx); imageGroups.Add(nim); nextInt = bin.ReadInt32(); } //nextInt is len == 0. //There will be one more zero int32, then OBJTs nextInt = bin.ReadInt32(); if (nextInt != 0) throw new DeserialisationException(string.Format("Expecting int32 0, found {0} at offset {1}", nextInt, inStr.Position - 4)); //make a child to hold the EOF marker imageGroups.Add(new RawDataChunk("EOF marker", new byte[8])); //put the children so far in a grouping chunk NamedImageGroups = new GroupingChunk("textures and sprites", (Chunk[])imageGroups.ToArray(typeof(Chunk))); //Now the objects: //because of a bizzarre quirk here, the object chunk starts, then stops, then starts again long lObjtFalseStartPos = inStr.Position; try { OBJTChunk lFalseObjt = new OBJTChunk(); lFalseObjt.Deserialise(inStr); OBJT = lFalseObjt; } catch (DeserialisationException e) { //Console.Error.WriteLine("OBJT false start found, searching for restart..."); //look for X,0,65,0 in first bit: inStr.Seek(lObjtFalseStartPos, SeekOrigin.Begin); int lX = bin.ReadInt32(); if (bin.ReadInt32() != 0) throw new DeserialisationException("Expecting 0", inStr.Position); if (bin.ReadInt32() != 65) throw new DeserialisationException("Expecting 65", inStr.Position); if (bin.ReadInt32() != 0) throw new DeserialisationException("Expecting 0", inStr.Position); if (lX == 65) throw new Exception("I haven't planned for this case!"); int[] lMatcher = new int[] { 0, 65, 0 }; //longest observed false starts are Pool3 (1052 bytes) and Rest4 (2032 bytes) while (inStr.Position - lObjtFalseStartPos < 2100) { int lNext = bin.ReadInt32(); if (lNext == lX) { if (Utils.ArrayCompare(lMatcher, new int[] { bin.ReadInt32(), bin.ReadInt32(), bin.ReadInt32() })) { int lFalseStartLen = (int)(inStr.Position - 4 * 4 - lObjtFalseStartPos); inStr.Seek(lObjtFalseStartPos, SeekOrigin.Begin); OBJTFalseStart = new RawDataChunk("OBJT False Start", bin.ReadBytes(lFalseStartLen)); OBJT = new OBJTChunk(); OBJT.Deserialise(inStr); break; } } } if (OBJT == null) { string lFileName = inStr is FileStream ? ((FileStream)inStr).Name : "unknown"; System.Windows.Forms.MessageBox.Show(string.Format("Warning: OBJTs not loaded on level {0}: unable to find false start resumption after: {1}", lFileName, e)); inStr.Seek(lObjtFalseStartPos, SeekOrigin.Begin); } } //read the rest of the file into a "remainder" //byte array so we can search for the SHET long lStartOfObjts = inStr.Position; byte[] lRest = new byte[inStr.Length - lStartOfObjts]; StreamUtils.EnsureRead(inStr, lRest); //use a heuristic to find the SHET. // //we need an 8bit char set (ASCII is 7bit). windows-1252 will do string lRestAsString = Encoding.GetEncoding("windows-1252").GetString(lRest); Regex lSHETStartRegex = new Regex( "([a-zA-Z0-9'()*+.\\-_ ]{10,13})\0([a-zA-Z0-9'()*+.\\-_ ]{10,13})\0(.{7})", RegexOptions.CultureInvariant | RegexOptions.Singleline); MatchCollection matches = lSHETStartRegex.Matches(lRestAsString); if (matches.Count != 1) throw new DeserialisationException(string.Format("Expecting exactly one match for SHET start regex. Found {0}", matches.Count)); int SHETstart = matches[0].Index; //(relative to end of images section) byte[] dunno = new byte[SHETstart]; Array.Copy(lRest, 0, dunno, 0, SHETstart); Dunno = new RawDataChunk("Dunno", dunno); //seek to the start of the SHET, and pretend we got here without cheating! dunno = lRest = null; inStr.Seek(lStartOfObjts + SHETstart, SeekOrigin.Begin); SHET = new SHETChunk(inStr, bin); }
public override void Deserialise(Stream inStr) { if (inStr is FileStream) { mName = ((FileStream)inStr).Name; } //BinaryReader is little-endian BinaryReader bin = new BinaryReader(inStr); //first, a header of 4 int32s: Header = new int[4]; for (int i = 0; i < Header.Length; i++) { Header[i] = bin.ReadInt32(); } //then, a block of zero bytes (int32 aligned) int nextInt = bin.ReadInt32(); ZeroByteCount = 0; while (nextInt == 0) { ZeroByteCount += 4; nextInt = bin.ReadInt32(); } ArrayList imageGroups = new ArrayList(); //now, an array of image or comment structs int lTIMIdx = 0; while (nextInt != 0) { bin.BaseStream.Seek(-4, SeekOrigin.Current); NamedImageGroup nim = new NamedImageGroup(bin.BaseStream, ref lTIMIdx); imageGroups.Add(nim); nextInt = bin.ReadInt32(); } //nextInt is len == 0. //There will be one more zero int32, then OBJTs nextInt = bin.ReadInt32(); if (nextInt != 0) { throw new DeserialisationException(string.Format("Expecting int32 0, found {0} at offset {1}", nextInt, inStr.Position - 4)); } //make a child to hold the EOF marker imageGroups.Add(new RawDataChunk("EOF marker", new byte[8])); //put the children so far in a grouping chunk NamedImageGroups = new GroupingChunk("textures and sprites", (Chunk[])imageGroups.ToArray(typeof(Chunk))); //Now the objects: //because of a bizzarre quirk here, the object chunk starts, then stops, then starts again long lObjtFalseStartPos = inStr.Position; try { OBJTChunk lFalseObjt = new OBJTChunk(); lFalseObjt.Deserialise(inStr); OBJT = lFalseObjt; } catch (DeserialisationException e) { //Console.Error.WriteLine("OBJT false start found, searching for restart..."); //look for X,0,65,0 in first bit: inStr.Seek(lObjtFalseStartPos, SeekOrigin.Begin); int lX = bin.ReadInt32(); if (bin.ReadInt32() != 0) { throw new DeserialisationException("Expecting 0", inStr.Position); } if (bin.ReadInt32() != 65) { throw new DeserialisationException("Expecting 65", inStr.Position); } if (bin.ReadInt32() != 0) { throw new DeserialisationException("Expecting 0", inStr.Position); } if (lX == 65) { throw new Exception("I haven't planned for this case!"); } int[] lMatcher = new int[] { 0, 65, 0 }; //longest observed false starts are Pool3 (1052 bytes) and Rest4 (2032 bytes) while (inStr.Position - lObjtFalseStartPos < 2100) { int lNext = bin.ReadInt32(); if (lNext == lX) { if (Utils.ArrayCompare(lMatcher, new int[] { bin.ReadInt32(), bin.ReadInt32(), bin.ReadInt32() })) { int lFalseStartLen = (int)(inStr.Position - 4 * 4 - lObjtFalseStartPos); inStr.Seek(lObjtFalseStartPos, SeekOrigin.Begin); OBJTFalseStart = new RawDataChunk("OBJT False Start", bin.ReadBytes(lFalseStartLen)); OBJT = new OBJTChunk(); OBJT.Deserialise(inStr); break; } } } if (OBJT == null) { string lFileName = inStr is FileStream ? ((FileStream)inStr).Name : "unknown"; System.Windows.Forms.MessageBox.Show(string.Format("Warning: OBJTs not loaded on level {0}: unable to find false start resumption after: {1}", lFileName, e)); inStr.Seek(lObjtFalseStartPos, SeekOrigin.Begin); } } //read the rest of the file into a "remainder" //byte array so we can search for the SHET long lStartOfObjts = inStr.Position; byte[] lRest = new byte[inStr.Length - lStartOfObjts]; StreamUtils.EnsureRead(inStr, lRest); //use a heuristic to find the SHET. // //we need an 8bit char set (ASCII is 7bit). windows-1252 will do string lRestAsString = Encoding.GetEncoding("windows-1252").GetString(lRest); Regex lSHETStartRegex = new Regex( "([a-zA-Z0-9'()*+.\\-_ ]{10,13})\0([a-zA-Z0-9'()*+.\\-_ ]{10,13})\0(.{7})", RegexOptions.CultureInvariant | RegexOptions.Singleline); MatchCollection matches = lSHETStartRegex.Matches(lRestAsString); if (matches.Count != 1) { throw new DeserialisationException(string.Format("Expecting exactly one match for SHET start regex. Found {0}", matches.Count)); } int SHETstart = matches[0].Index; //(relative to end of images section) byte[] dunno = new byte[SHETstart]; Array.Copy(lRest, 0, dunno, 0, SHETstart); Dunno = new RawDataChunk("Dunno", dunno); //seek to the start of the SHET, and pretend we got here without cheating! dunno = lRest = null; inStr.Seek(lStartOfObjts + SHETstart, SeekOrigin.Begin); SHET = new SHETChunk(inStr, bin); }