public void Deserialise(System.IO.Stream inStr, int xiExpectedDataSize) { long lStartOffset = xiExpectedDataSize >= 0 ? inStr.Position : -1; // magic number BinaryReader bin = new BinaryReader(inStr); int lTIMMagicNumber = bin.ReadInt32(); if (TIM_MAGIC_NUMBER != lTIMMagicNumber) { throw new DeserialisationException(string.Format("TIM should start with 4 byte magic number 0x10, found 0x{0:x}", lTIMMagicNumber), inStr.Position - 4); } // bits per pixel BPP = (TimBPP)bin.ReadInt32(); if (BPP != TimBPP._4BPP && BPP != TimBPP._8BPP && BPP != TimBPP._16BPP) { throw new TIMTypeNotImplementedException(string.Format("Only 4BPP, 8BPP or 16BPP TIMs are supported. Found 0x{0:x} BPP type", BPP), inStr.Position - 8); } if (BPP != TimBPP._16BPP) { // Now the palette header: ClutSize = bin.ReadInt32(); PaletteOrgX = bin.ReadInt16(); PaletteOrgY = bin.ReadInt16(); ClutColors = bin.ReadInt16(); ClutCount = bin.ReadInt16(); //sanity checks if (ClutCount * ClutColors * 2 != ClutSize - 12) throw new DeserialisationException("bad TIM: ClutCount*ClutColors*2 != ClutSize - 12", inStr.Position); //TODO: if (ClutCount != 1) throw new DeserialisationException("Multi-clut TIMs are not yet supported. Please extend TIMChunk.cs using info from timgfx.txt"); //CLUT: Palette = new short[ClutCount * ClutColors]; for (int i = 0; i < Palette.Length; i++) { Palette[i] = bin.ReadInt16(); } } //colour count int lPixelsPerTwoBytes; switch (BPP) { case TimBPP._4BPP: if (ClutColors != 16) throw new DeserialisationException("bad TIM: ClutColors != 16, but BPP == 4", inStr.Position); lPixelsPerTwoBytes = 4; break; case TimBPP._8BPP: if (ClutColors != 256) throw new DeserialisationException("bad TIM: ClutColors != 256, but BPP == 8", inStr.Position); lPixelsPerTwoBytes = 2; break; case TimBPP._16BPP: if (ClutColors != 0) throw new DeserialisationException("bad TIM: ClutColors != 0, but BPP == 16", inStr.Position); lPixelsPerTwoBytes = 1; break; default: throw new Exception("unreachable case"); } //Second header: ImageDataSize = bin.ReadInt32(); ImageOrgX = bin.ReadInt16(); ImageOrgY = bin.ReadInt16(); //short * short is int !?! ImageWidth = (short)(lPixelsPerTwoBytes * bin.ReadInt16()); ImageHeight = bin.ReadInt16(); //sanity checks //some observed TIMs fail this check: if (ImageWidth * ImageHeight / lPixelsPerTwoBytes * 2 != ImageDataSize - 12) { //throw new DeserialisationException System.Diagnostics.Trace.WriteLine(string.Format("bad TIM: ImageWidth * ImageHeight / PixelsPerByte != ImageDataSize - 12, near {0}", inStr.Position)); } //read the image data ImageData = bin.ReadBytes(ImageWidth * ImageHeight / lPixelsPerTwoBytes * 2); if (xiExpectedDataSize >= 0) { long lObservedSize = inStr.Position - lStartOffset; if (lObservedSize < xiExpectedDataSize) { ZeroPadding = bin.ReadBytes((int)(xiExpectedDataSize - lObservedSize)); foreach (byte b in ZeroPadding) if (b != 0) throw new DeserialisationException(string.Format("Non zero value found in zero-padding section: {0}", b), inStr.Position); } else if (lObservedSize > xiExpectedDataSize) { throw new DeserialisationException(string.Format("Expected TIM datasize was {0}, found {1}", xiExpectedDataSize, lObservedSize)); } } }
public void Deserialise(System.IO.Stream inStr, int xiExpectedDataSize) { long lStartOffset = xiExpectedDataSize >= 0 ? inStr.Position : -1; // magic number BinaryReader bin = new BinaryReader(inStr); int lTIMMagicNumber = bin.ReadInt32(); if (TIM_MAGIC_NUMBER != lTIMMagicNumber) { throw new DeserialisationException(string.Format("TIM should start with 4 byte magic number 0x10, found 0x{0:x}", lTIMMagicNumber), inStr.Position - 4); } // bits per pixel BPP = (TimBPP)bin.ReadInt32(); if (BPP != TimBPP._4BPP && BPP != TimBPP._8BPP && BPP != TimBPP._16BPP) { throw new TIMTypeNotImplementedException(string.Format("Only 4BPP, 8BPP or 16BPP TIMs are supported. Found 0x{0:x} BPP type", BPP), inStr.Position - 8); } if (BPP != TimBPP._16BPP) { // Now the palette header: ClutSize = bin.ReadInt32(); PaletteOrgX = bin.ReadInt16(); PaletteOrgY = bin.ReadInt16(); ClutColors = bin.ReadInt16(); ClutCount = bin.ReadInt16(); //sanity checks if (ClutCount * ClutColors * 2 != ClutSize - 12) { throw new DeserialisationException("bad TIM: ClutCount*ClutColors*2 != ClutSize - 12", inStr.Position); } //TODO: if (ClutCount != 1) { throw new DeserialisationException("Multi-clut TIMs are not yet supported. Please extend TIMChunk.cs using info from timgfx.txt"); } //CLUT: Palette = new short[ClutCount * ClutColors]; for (int i = 0; i < Palette.Length; i++) { Palette[i] = bin.ReadInt16(); } } //colour count int lPixelsPerTwoBytes; switch (BPP) { case TimBPP._4BPP: if (ClutColors != 16) { throw new DeserialisationException("bad TIM: ClutColors != 16, but BPP == 4", inStr.Position); } lPixelsPerTwoBytes = 4; break; case TimBPP._8BPP: if (ClutColors != 256) { throw new DeserialisationException("bad TIM: ClutColors != 256, but BPP == 8", inStr.Position); } lPixelsPerTwoBytes = 2; break; case TimBPP._16BPP: if (ClutColors != 0) { throw new DeserialisationException("bad TIM: ClutColors != 0, but BPP == 16", inStr.Position); } lPixelsPerTwoBytes = 1; break; default: throw new Exception("unreachable case"); } //Second header: ImageDataSize = bin.ReadInt32(); ImageOrgX = bin.ReadInt16(); ImageOrgY = bin.ReadInt16(); //short * short is int !?! ImageWidth = (short)(lPixelsPerTwoBytes * bin.ReadInt16()); ImageHeight = bin.ReadInt16(); //sanity checks //some observed TIMs fail this check: if (ImageWidth * ImageHeight / lPixelsPerTwoBytes * 2 != ImageDataSize - 12) { //throw new DeserialisationException System.Diagnostics.Trace.WriteLine(string.Format("bad TIM: ImageWidth * ImageHeight / PixelsPerByte != ImageDataSize - 12, near {0}", inStr.Position)); } //read the image data ImageData = bin.ReadBytes(ImageWidth * ImageHeight / lPixelsPerTwoBytes * 2); if (xiExpectedDataSize >= 0) { long lObservedSize = inStr.Position - lStartOffset; if (lObservedSize < xiExpectedDataSize) { ZeroPadding = bin.ReadBytes((int)(xiExpectedDataSize - lObservedSize)); foreach (byte b in ZeroPadding) { if (b != 0) { throw new DeserialisationException(string.Format("Non zero value found in zero-padding section: {0}", b), inStr.Position); } } } else if (lObservedSize > xiExpectedDataSize) { throw new DeserialisationException(string.Format("Expected TIM datasize was {0}, found {1}", xiExpectedDataSize, lObservedSize)); } } }