diff --git a/libmspack/qtm.cs b/libmspack/qtm.cs
new file mode 100644
index 0000000..df1c3a2
--- /dev/null
+++ b/libmspack/qtm.cs
@@ -0,0 +1,60 @@
+namespace SabreTools.Compression.libmspack
+{
+ public static class qtm
+ {
+ public const int QTM_FRAME_SIZE = 32768;
+
+ ///
+ /// Allocates Quantum decompression state for decoding the given stream.
+ ///
+ /// - returns NULL if window_bits is outwith the range 10 to 21 (inclusive).
+ ///
+ /// - uses system->alloc() to allocate memory
+ ///
+ /// - returns NULL if not enough memory
+ ///
+ /// - window_bits is the size of the Quantum window, from 1Kb (10) to 2Mb (21).
+ ///
+ /// - input_buffer_size is the number of bytes to use to store bitstream data.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static qtmd_stream qtmd_init(mspack_system system, mspack_file input, mspack_file output, int window_bits, int input_buffer_size) => null;
+
+ ///
+ /// Decompresses, or decompresses more of, a Quantum stream.
+ ///
+ /// - out_bytes of data will be decompressed and the function will return
+ /// with an MSPACK_ERR_OK return code.
+ ///
+ /// - decompressing will stop as soon as out_bytes is reached. if the true
+ /// amount of bytes decoded spills over that amount, they will be kept for
+ /// a later invocation of qtmd_decompress().
+ ///
+ /// - the output bytes will be passed to the system->write() function given in
+ /// qtmd_init(), using the output file handle given in qtmd_init(). More
+ /// than one call may be made to system->write()
+ ///
+ /// - Quantum will read input bytes as necessary using the system->read()
+ /// function given in qtmd_init(), using the input file handle given in
+ /// qtmd_init(). This will continue until system->read() returns 0 bytes,
+ /// or an error.
+ ///
+ ///
+ ///
+ ///
+ public static MSPACK_ERR qtmd_decompress(qtmd_stream qtm, long out_bytes) => MSPACK_ERR.MSPACK_ERR_OK;
+
+ ///
+ /// Frees all state associated with a Quantum data stream
+ ///
+ /// - calls system->free() using the system pointer given in qtmd_init()
+ ///
+ ///
+ public static void qtmd_free(qtmd_stream qtm) { }
+ }
+}
\ No newline at end of file
diff --git a/libmspack/qtmd_model.cs b/libmspack/qtmd_model.cs
new file mode 100644
index 0000000..e331261
--- /dev/null
+++ b/libmspack/qtmd_model.cs
@@ -0,0 +1,11 @@
+namespace SabreTools.Compression.libmspack
+{
+ public unsafe class qtmd_model
+ {
+ public int shiftsleft { get; set; }
+
+ public int entries { get; set; }
+
+ public qtmd_modelsym** syms { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/libmspack/qtmd_modelsym.cs b/libmspack/qtmd_modelsym.cs
new file mode 100644
index 0000000..149c610
--- /dev/null
+++ b/libmspack/qtmd_modelsym.cs
@@ -0,0 +1,9 @@
+namespace SabreTools.Compression.libmspack
+{
+ public class qtmd_modelsym
+ {
+ public ushort sym { get; set; }
+
+ public ushort cumfreq { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/libmspack/qtmd_stream.cs b/libmspack/qtmd_stream.cs
new file mode 100644
index 0000000..0c063f3
--- /dev/null
+++ b/libmspack/qtmd_stream.cs
@@ -0,0 +1,160 @@
+namespace SabreTools.Compression.libmspack
+{
+ public unsafe class qtmd_stream
+ {
+ ///
+ /// I/O routines
+ ///
+ public mspack_system sys { get; set; }
+
+ ///
+ /// Input file handle
+ ///
+ public mspack_file input { get; set; }
+
+ ///
+ /// Output file handle
+ ///
+ public mspack_file output { get; set; }
+
+ ///
+ /// Decoding window
+ ///
+ public byte* window { get; set; }
+
+ ///
+ /// Window size
+ ///
+ public uint window_size { get; set; }
+
+ ///
+ /// Decompression offset within window
+ ///
+ public uint window_posn { get; set; }
+
+ ///
+ /// Bytes remaining for current frame
+ ///
+ public uint frame_todo { get; set; }
+
+ ///
+ /// High arith coding state
+ ///
+ public ushort H { get; set; }
+
+ ///
+ /// Low arith coding state
+ ///
+ public ushort L { get; set; }
+
+ ///
+ /// Current arith coding state
+ ///
+ public ushort C { get; set; }
+
+ ///
+ /// Have we started decoding a new frame?
+ ///
+ public byte header_read { get; set; }
+
+ public MSPACK_ERR error { get; set; }
+
+ #region I/O buffering
+
+ public byte* inbuf { get; set; }
+
+ public byte* i_ptr { get; set; }
+
+ public byte* i_end { get; set; }
+
+ public byte* o_ptr { get; set; }
+
+ public byte* o_end { get; set; }
+
+ public uint bit_buffer { get; set; }
+
+ public uint inbuf_size { get; set; }
+
+ public byte bits_left { get; set; }
+
+ public byte input_end { get; set; }
+
+ #endregion
+
+ #region Models
+
+ #region Four literal models, each representing 64 symbols
+
+ ///
+ /// model0 for literals from 0 to 63 (selector = 0)
+ ///
+ public qtmd_model model0 { get; set; }
+
+ ///
+ /// model1 for literals from 64 to 127 (selector = 1)
+ ///
+ public qtmd_model model1 { get; set; }
+
+ ///
+ /// model2 for literals from 128 to 191 (selector = 2)
+ ///
+ public qtmd_model model2 { get; set; }
+
+ ///
+ /// model3 for literals from 129 to 255 (selector = 3)
+ ///
+ public qtmd_model model3 { get; set; }
+
+ #endregion
+
+ #region Three match models
+
+ ///
+ /// model4 for match with fixed length of 3 bytes
+ ///
+ public qtmd_model model4 { get; set; }
+
+ ///
+ /// model5 for match with fixed length of 4 bytes
+ ///
+ public qtmd_model model5 { get; set; }
+
+ ///
+ /// model6 for variable length match, encoded with model6len model
+ ///
+ public qtmd_model model6 { get; set; }
+
+ public qtmd_model model6len { get; set; }
+
+ #endregion
+
+ ///
+ /// selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6)
+ ///
+ public qtmd_model model7 { get; set; }
+
+ #endregion
+
+ #region Symbol arrays for all models
+
+ public qtmd_modelsym[] m0sym { get; set; } = new qtmd_modelsym[64 + 1];
+
+ public qtmd_modelsym[] m1sym { get; set; } = new qtmd_modelsym[64 + 1];
+
+ public qtmd_modelsym[] m2sym { get; set; } = new qtmd_modelsym[64 + 1];
+
+ public qtmd_modelsym[] m3sym { get; set; } = new qtmd_modelsym[64 + 1];
+
+ public qtmd_modelsym[] m4sym { get; set; } = new qtmd_modelsym[24 + 1];
+
+ public qtmd_modelsym[] m5sym { get; set; } = new qtmd_modelsym[36 + 1];
+
+ public qtmd_modelsym[] m6sym { get; set; } = new qtmd_modelsym[42 + 1];
+
+ public qtmd_modelsym[] m6lsym { get; set; } = new qtmd_modelsym[27 + 1];
+
+ public qtmd_modelsym[] m7sym { get; set; } = new qtmd_modelsym[7 + 1];
+
+ #endregion
+ }
+}
\ No newline at end of file