Add everything from oab.c (nw)

This commit is contained in:
Matt Nadareski
2023-09-19 16:03:14 -04:00
parent 3f4de3ee67
commit f23078d792
4 changed files with 370 additions and 9 deletions

View File

@@ -1,3 +1,5 @@
using static SabreTools.Compression.libmspack.oab;
namespace SabreTools.Compression.libmspack
{
/// <summary>
@@ -7,7 +9,7 @@ namespace SabreTools.Compression.libmspack
/// </summary>
/// <see cref="mspack_create_oab_decompressor()"/>
/// <see cref="mspack_destroy_oab_decompressor()"/>
public abstract class msoab_decompressor
public unsafe class msoab_decompressor
{
public mspack_system system { get; set; }
@@ -28,8 +30,150 @@ namespace SabreTools.Compression.libmspack
/// The filename of the output file. This is passed
/// directly to mspack_system::open().
/// </param>
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
public abstract MSPACK_ERR decompress(in string input, in string output);
/// <returns>An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful</returns>
public MSPACK_ERR decompress(in string input, in string output)
{
msoab_decompressor_p* self = (msoab_decompressor_p*)_self;
mspack_system* sys;
mspack_file* infh = NULL;
mspack_file* outfh = NULL;
byte* buf = NULL;
byte[] hdrbuf = new byte[oabhead_SIZEOF];
uint block_max, target_size;
lzxd_stream* lzx = NULL;
mspack_system oabd_sys;
oabd_file in_ofh, out_ofh;
uint window_bits;
int ret = MSPACK_ERR_OK;
if (!self) return MSPACK_ERR_ARGS;
sys = self->system;
infh = sys->open(sys, input, MSPACK_SYS_OPEN_READ);
if (!infh)
{
ret = MSPACK_ERR_OPEN;
goto outlbl;
}
if (sys->read(infh, hdrbuf, oabhead_SIZEOF) != oabhead_SIZEOF)
{
ret = MSPACK_ERR_READ;
goto outlbl;
}
if (EndGetI32(&hdrbuf[oabhead_VersionHi]) != 3 ||
EndGetI32(&hdrbuf[oabhead_VersionLo]) != 1)
{
ret = MSPACK_ERR_SIGNATURE;
goto outlbl;
}
block_max = EndGetI32(&hdrbuf[oabhead_BlockMax]);
target_size = EndGetI32(&hdrbuf[oabhead_TargetSize]);
outfh = sys->open(sys, output, MSPACK_SYS_OPEN_WRITE);
if (!outfh)
{
ret = MSPACK_ERR_OPEN;
goto outlbl;
}
buf = sys->alloc(sys, self->buf_size);
if (!buf)
{
ret = MSPACK_ERR_NOMEMORY;
goto outlbl;
}
oabd_sys = *sys;
oabd_sys.read = oabd_sys_read;
oabd_sys.write = oabd_sys_write;
in_ofh.orig_sys = sys;
in_ofh.orig_file = infh;
out_ofh.orig_sys = sys;
out_ofh.orig_file = outfh;
while (target_size)
{
uint blk_csize, blk_dsize, blk_crc, blk_flags;
if (sys->read(infh, buf, oabblk_SIZEOF) != oabblk_SIZEOF)
{
ret = MSPACK_ERR_READ;
goto outlbl;
}
blk_flags = EndGetI32(&buf[oabblk_Flags]);
blk_csize = EndGetI32(&buf[oabblk_CompSize]);
blk_dsize = EndGetI32(&buf[oabblk_UncompSize]);
blk_crc = EndGetI32(&buf[oabblk_CRC]);
if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1)
{
ret = MSPACK_ERR_DATAFORMAT;
goto outlbl;
}
if (!blk_flags)
{
/* Uncompressed block */
if (blk_dsize != blk_csize)
{
ret = MSPACK_ERR_DATAFORMAT;
goto outlbl;
}
ret = copy_fh(sys, infh, outfh, blk_dsize, buf, self->buf_size);
if (ret) goto outlbl;
}
else
{
/* LZX compressed block */
window_bits = 17;
while (window_bits < 25 && (1U << window_bits) < blk_dsize)
window_bits++;
in_ofh.available = blk_csize;
out_ofh.crc = 0xffffffff;
lzx = lzxd_init(&oabd_sys, (void*)&in_ofh, (void*)&out_ofh, window_bits,
0, self->buf_size, blk_dsize, 1);
if (!lzx)
{
ret = MSPACK_ERR_NOMEMORY;
goto outlbl;
}
ret = lzxd_decompress(lzx, blk_dsize);
if (ret != MSPACK_ERR_OK)
goto outlbl;
lzxd_free(lzx);
lzx = NULL;
/* Consume any trailing padding bytes before the next block */
ret = copy_fh(sys, infh, NULL, in_ofh.available, buf, self->buf_size);
if (ret) goto outlbl;
if (out_ofh.crc != blk_crc)
{
ret = MSPACK_ERR_CHECKSUM;
goto outlbl;
}
}
target_size -= blk_dsize;
}
outlbl:
if (lzx) lzxd_free(lzx);
if (outfh) sys->close(outfh);
if (infh) sys->close(infh);
sys->free(buf);
return ret;
}
/// <summary>
/// Decompresses an Offline Address Book with an incremental patch file.
@@ -58,8 +202,169 @@ namespace SabreTools.Compression.libmspack
/// The filename of the output file. This is passed
/// directly to mspack_system::open().
/// </param>
/// <returns>An error code, or MSPACK_ERR_OK if successful</returns>
public abstract MSPACK_ERR decompress_incremental(in string input, in string @base, in string output);
/// <returns>An error code, or MSPACK_ERR.MSPACK_ERR_OK if successful</returns>
public MSPACK_ERR decompress_incremental(in string input, in string @base, in string output)
{
lzxd_stream lzx = null;
uint window_bits, window_size;
MSPACK_ERR ret = MSPACK_ERR.MSPACK_ERR_OK;
mspack_system sys = this.system;
mspack_file infh = sys.open(input, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
if (infh == null)
{
ret = MSPACK_ERR.MSPACK_ERR_OPEN;
goto outlbl;
}
byte[] hdrbuf = new byte[patchhead_SIZEOF];
byte* hdrbufPtr = libmspack.system.GetArrayPointer(hdrbuf);
if (sys.read(infh, hdrbufPtr, patchhead_SIZEOF) != patchhead_SIZEOF)
{
ret = MSPACK_ERR.MSPACK_ERR_READ;
goto outlbl;
}
if (EndGetI32(&hdrbuf[patchhead_VersionHi]) != 3 ||
EndGetI32(&hdrbuf[patchhead_VersionLo]) != 2)
{
ret = MSPACK_ERR.MSPACK_ERR_SIGNATURE;
goto outlbl;
}
uint block_max = EndGetI32(&hdrbuf[patchhead_BlockMax]);
uint target_size = EndGetI32(&hdrbuf[patchhead_TargetSize]);
// We use it for reading block headers too
if (block_max < patchblk_SIZEOF)
block_max = patchblk_SIZEOF;
mspack_file basefh = sys.open(@base, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_READ);
if (basefh == null)
{
ret = MSPACK_ERR.MSPACK_ERR_OPEN;
goto outlbl;
}
mspack_file outfh = sys.open(output, MSPACK_SYS_OPEN.MSPACK_SYS_OPEN_WRITE);
if (outfh == null)
{
ret = MSPACK_ERR.MSPACK_ERR_OPEN;
goto outlbl;
}
byte* buf = (byte*)sys.alloc(this.buf_size);
if (buf == null)
{
ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
goto outlbl;
}
mspack_oab_system oabd_sys = sys as mspack_oab_system;
oabd_file in_ofh = new oabd_file();
in_ofh.orig_sys = sys;
in_ofh.orig_file = infh;
oabd_file out_ofh = new oabd_file();
out_ofh.orig_sys = sys;
out_ofh.orig_file = outfh;
while (target_size > 0)
{
if (sys.read(infh, buf, patchblk_SIZEOF) != patchblk_SIZEOF)
{
ret = MSPACK_ERR.MSPACK_ERR_READ;
goto outlbl;
}
uint blk_csize = EndGetI32(&buf[patchblk_PatchSize]);
uint blk_dsize = EndGetI32(&buf[patchblk_TargetSize]);
uint blk_ssize = EndGetI32(&buf[patchblk_SourceSize]);
uint blk_crc = EndGetI32(&buf[patchblk_CRC]);
if (blk_dsize > block_max || blk_dsize > target_size ||
blk_ssize > block_max)
{
ret = MSPACK_ERR.MSPACK_ERR_DATAFORMAT;
goto outlbl;
}
window_size = (blk_ssize + 32767) & ~32767;
window_size += blk_dsize;
window_bits = 17;
while (window_bits < 25 && (1U << window_bits) < window_size)
window_bits++;
in_ofh.available = blk_csize;
out_ofh.crc = 0xffffffff;
lzx = lzxd_init(&oabd_sys, (void*)&in_ofh, (void*)&out_ofh, window_bits,
0, 4096, blk_dsize, 1);
if (!lzx)
{
ret = MSPACK_ERR.MSPACK_ERR_NOMEMORY;
goto outlbl;
}
ret = lzxd_set_reference_data(lzx, sys, basefh, blk_ssize);
if (ret != MSPACK_ERR.MSPACK_ERR_OK)
goto outlbl;
ret = lzxd_decompress(lzx, blk_dsize);
if (ret != MSPACK_ERR.MSPACK_ERR_OK)
goto outlbl;
lzxd_free(lzx);
lzx = null;
/* Consume any trailing padding bytes before the next block */
ret = copy_fh(sys, infh, null, in_ofh.available, buf, this.buf_size);
if (ret) goto outlbl;
if (out_ofh.crc != blk_crc)
{
ret = MSPACK_ERR.MSPACK_ERR_CHECKSUM;
goto outlbl;
}
target_size -= blk_dsize;
}
outlbl:
if (lzx) lzxd_free(lzx);
if (outfh) sys.close(outfh);
if (basefh) sys.close(basefh);
if (infh) sys.close(infh);
sys.free(buf);
return ret;
}
private static MSPACK_ERR copy_fh(mspack_system sys, mspack_file infh, mspack_file outfh, int bytes_to_copy, byte* buf, int buf_size)
{
while (bytes_to_copy > 0)
{
int run = buf_size;
if (run > bytes_to_copy)
{
run = bytes_to_copy;
}
if (sys.read(infh, buf, run) != run)
{
return MSPACK_ERR.MSPACK_ERR_READ;
}
if (outfh != null && sys.write(outfh, buf, run) != run)
{
return MSPACK_ERR.MSPACK_ERR_WRITE;
}
bytes_to_copy -= run;
}
return MSPACK_ERR.MSPACK_ERR_OK;
}
/// <summary>
/// Sets an OAB decompression engine parameter. Available only in OAB
@@ -72,9 +377,19 @@ namespace SabreTools.Compression.libmspack
/// <param name="param">The parameter to set</param>
/// <param name="value">The value to set the parameter to</param>
/// <returns>
/// MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
/// MSPACK_ERR.MSPACK_ERR_OK if all is OK, or MSPACK_ERR.MSPACK_ERR_ARGS if there
/// is a problem with either parameter or value.
/// </returns>
public abstract MSPACK_ERR set_param(MSOABD_PARAM param, int value);
public MSPACK_ERR set_param(MSOABD_PARAM param, int value)
{
if (param == MSOABD_PARAM.MSOABD_PARAM_DECOMPBUF && value >= 16)
{
// Must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF)
this.buf_size = value;
return MSPACK_ERR.MSPACK_ERR_OK;
}
return MSPACK_ERR.MSPACK_ERR_ARGS;
}
}
}

View File

@@ -120,8 +120,7 @@ namespace SabreTools.Compression.libmspack
/// <inheritdoc/>
public override unsafe void* alloc(int bytes)
{
var arr = new byte[bytes];
return (byte*)arr[0];
return system.CreateArray<byte>(bytes);
}
/// <inheritdoc/>

View File

@@ -0,0 +1,34 @@
namespace SabreTools.Compression.libmspack
{
public unsafe class mspack_oab_system : mspack_default_system
{
/// <inheritdoc/>
public override unsafe int read(mspack_file base_file, void* buf, int size)
{
oabd_file file = (oabd_file)base_file;
int bytes_read;
if (size > file.available)
size = file.available;
bytes_read = file.orig_sys.read(file.orig_file, buf, size);
if (bytes_read < 0)
return bytes_read;
file.available -= bytes_read;
return bytes_read;
}
/// <inheritdoc/>
public override unsafe int write(mspack_file base_file, void* buf, int size)
{
oabd_file file = (oabd_file)base_file;
int bytes_written = file.orig_sys.write(file.orig_file, buf, size);
if (bytes_written > 0)
file.crc = mspack.crc32(file.crc, buf, bytes_written);
return bytes_written;
}
}
}

13
libmspack/oabd_file.cs Normal file
View File

@@ -0,0 +1,13 @@
namespace SabreTools.Compression.libmspack
{
public class oabd_file : mspack_file
{
public mspack_system orig_sys { get; set; }
public mspack_file orig_file { get; set; }
public uint crc { get; set; }
public int available { get; set; }
}
}