/* This file is part of libmspack. * (C) 2003-2004 Stuart Caie. * * libmspack is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License (LGPL) version 2.1 * * For further details, see the file COPYING.LIB distributed with libmspack */ using System; using System.Linq; using LibMSPackSharp.Compression; namespace LibMSPackSharp.SZDD { public class Implementation { /// /// Input buffer size during decompression - not worth parameterising IMHO /// private const int SZDD_INPUT_SIZE = 2048; #region SZDDD_OPEN /// /// Opens an SZDD file without decompressing, reads header /// public static Header Open(Decompressor d, string filename) { DecompressorImpl self = d as DecompressorImpl; if (self == null) return null; SystemImpl sys = self.System; object fh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_READ); HeaderImpl hdr = new HeaderImpl(); if (fh != null && hdr != null) { hdr.FileHandle = fh; self.Error = ReadHeaders(sys, fh, hdr); } else { if (fh == null) self.Error = Error.MSPACK_ERR_OPEN; if (hdr == null) self.Error = Error.MSPACK_ERR_NOMEMORY; } if (self.Error != Error.MSPACK_ERR_OK) { if (fh != null) sys.Close(fh); sys.Free(hdr); hdr = null; } return hdr; } #endregion #region SZDDD_CLOSE /// /// Closes an SZDD file /// public static void Close(Decompressor d, Header hdr) { DecompressorImpl self = d as DecompressorImpl; HeaderImpl hdr_p = hdr as HeaderImpl; if (self?.System == null || hdr == null) return; // Close the file handle associated self.System.Close(hdr_p.FileHandle); // Free the memory associated self.System.Free(hdr); self.Error = Error.MSPACK_ERR_OK; } #endregion #region SZDDD_READ_HEADERS private static byte[] expandSignature = new byte[8] { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33 }; private static byte[] qbasicSignature = new byte[8] { 0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1 }; /// /// Reads the headers of an SZDD format file /// public static Error ReadHeaders(SystemImpl sys, object fh, Header hdr) { // Read and check signature byte[] buf = new byte[8]; if (sys.Read(fh, buf, 0, 8) != 8) return Error.MSPACK_ERR_READ; if (buf.SequenceEqual(expandSignature)) { // Common SZDD hdr.Format = Format.MSSZDD_FMT_NORMAL; // Read the rest of the header if (sys.Read(fh, buf, 0, 6) != 6) return Error.MSPACK_ERR_READ; if (buf[0] != 0x41) return Error.MSPACK_ERR_DATAFORMAT; hdr.MissingChar = (char)buf[1]; hdr.Length = BitConverter.ToUInt32(buf, 2); } if (buf.SequenceEqual(qbasicSignature)) { // Special QBasic SZDD hdr.Format = Format.MSSZDD_FMT_QBASIC; if (sys.Read(fh, buf, 0, 4) != 4) return Error.MSPACK_ERR_READ; hdr.MissingChar = '\0'; hdr.Length = BitConverter.ToUInt32(buf, 0); } else { return Error.MSPACK_ERR_SIGNATURE; } return Error.MSPACK_ERR_OK; } #endregion #region SZDDD_EXTRACT /// /// Decompresses an SZDD file /// public static Error Extract(Decompressor d, Header hdr, string filename) { DecompressorImpl self = d as DecompressorImpl; if (self == null) return Error.MSPACK_ERR_ARGS; if (hdr == null) return self.Error = Error.MSPACK_ERR_ARGS; SystemImpl sys = self.System; object fh = (hdr as HeaderImpl)?.FileHandle; if (fh == null) return Error.MSPACK_ERR_ARGS; // Seek to the compressed data long dataOffset = (hdr.Format == Format.MSSZDD_FMT_NORMAL) ? 14 : 12; if (sys.Seek(fh, dataOffset, SeekMode.MSPACK_SYS_SEEK_START)) return self.Error = Error.MSPACK_ERR_SEEK; // Open file for output object outfh; if ((outfh = sys.Open(sys, filename, OpenMode.MSPACK_SYS_OPEN_WRITE)) == null) return self.Error = Error.MSPACK_ERR_OPEN; // Decompress the data self.Error = LZSS.Decompress( sys, fh, outfh, SZDD_INPUT_SIZE, hdr.Format == Format.MSSZDD_FMT_NORMAL ? LZSSMode.LZSS_MODE_EXPAND : LZSSMode.LZSS_MODE_QBASIC); // Close output file sys.Close(outfh); return self.Error; } #endregion #region SZDDD_DECOMPRESS /// /// Unpacks directly from input to output /// public static Error Decompress(Decompressor d, string input, string output) { DecompressorImpl self = d as DecompressorImpl; if (self == null) return Error.MSPACK_ERR_ARGS; Header hdr; if ((hdr = Open(d, input)) == null) return self.Error; Error error = Extract(d, hdr, output); Close(d, hdr); return self.Error = error; } #endregion #region SZDDD_ERROR /// /// Returns the last error that occurred /// public static Error LastError(Decompressor d) { DecompressorImpl self = d as DecompressorImpl; return (self != null) ? self.Error : Error.MSPACK_ERR_ARGS; } #endregion } }