private static void Decode(Stream stream, ShpOffset[] offsets, int width, int height, byte[][] frames, byte[] src, ref int recdepth) { if (recdepth > frames.Length) { throw new NotImplementedException("Format 40/20 frames contain infinite loop!"); } for (uint i = 0; i < frames.Length; i++) { byte[] frame = new byte[width * height]; byte[] refframe = null; ShpOffset curoff = offsets[i + 0]; ShpOffset nxtoff = offsets[i + 1]; int srclen = (int)(nxtoff.Offset - curoff.Offset); stream.Read(src, 0, srclen); switch (curoff.OffsetFormat) { // Format 20 case 0x20: refframe = frames[i - 1]; goto do_format40; // Format 40 case 0x40: int j = Array.FindIndex(offsets, o => o.Offset == curoff.Ref); if (j < 0) { throw new IndexOutOfRangeException("Invalid frame reference!"); } refframe = frames[j]; do_format40: if (refframe == null) { recdepth++; Decode(stream, offsets, width, height, frames, src, ref recdepth); recdepth--; } Format40.Decode(src, srclen, frame, refframe); break; // Format 80 case 0x80: Format80.Decode(src, 0, frame, 0, srclen); break; // Invalid format default: throw new NotImplementedException("Invalid format!"); } frames[i] = frame; } }
void Decompress(ImageHeader h) { // No extra work is required for empty frames if (h.Size.Width == 0 || h.Size.Height == 0) { return; } if (recurseDepth > imageCount) { throw new InvalidDataException("Format20/40 headers contain infinite loop"); } switch (h.Format) { case Format.Format20: case Format.Format40: { if (h.RefImage.Data == null) { ++recurseDepth; Decompress(h.RefImage); --recurseDepth; } h.Data = CopyImageData(h.RefImage.Data); Format40.DecodeInto(shpBytes, h.Data, (int)(h.FileOffset - shpBytesFileOffset)); break; } case Format.Format80: { var imageBytes = new byte[Size.Width * Size.Height]; Format80.DecodeInto(shpBytes, imageBytes, (int)(h.FileOffset - shpBytesFileOffset)); h.Data = imageBytes; break; } default: throw new InvalidDataException(); } }