Files
BinaryObjectScanner/BurnOutSharp/External/libmspack/OAB/Implementation.cs
Matt Nadareski c54181e9ac "as" not "cast"
2022-05-19 11:56:38 -07:00

627 lines
20 KiB
C#

/* This file is part of libmspack.
* © 2013 Intel Corporation
*
* 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
*/
/* The Exchange Online Addressbook (OAB or sometimes OAL) is distributed
* as a .LZX file in one of two forms. Either a "full download" containing
* the entire address list, or an incremental binary patch which should be
* applied to a previous version of the full decompressed data.
*
* The contents and format of the decompressed OAB are not handled here.
*
* For a complete description of the format, see the MSDN site:
*
* http://msdn.microsoft.com/en-us/library/cc463914 - [MS-OXOAB].pdf
* http://msdn.microsoft.com/en-us/library/cc483133 - [MS-PATCH].pdf
*/
using System;
using LibMSPackSharp.Compression;
namespace LibMSPackSharp.OAB
{
public class Implementation
{
#region OAB decompression definitions
private const int oabhead_VersionHi = 0x0000;
private const int oabhead_VersionLo = 0x0004;
private const int oabhead_BlockMax = 0x0008;
private const int oabhead_TargetSize = 0x000c;
private const int oabhead_SIZEOF = 0x0010;
private const int oabblk_Flags = 0x0000;
private const int oabblk_CompSize = 0x0004;
private const int oabblk_UncompSize = 0x0008;
private const int oabblk_CRC = 0x000c;
private const int oabblk_SIZEOF = 0x0010;
private const int patchhead_VersionHi = 0x0000;
private const int patchhead_VersionLo = 0x0004;
private const int patchhead_BlockMax = 0x0008;
private const int patchhead_SourceSize = 0x000c;
private const int patchhead_TargetSize = 0x0010;
private const int patchhead_SourceCRC = 0x0014;
private const int patchhead_TargetCRC = 0x0018;
private const int patchhead_SIZEOF = 0x001c;
private const int patchblk_PatchSize = 0x0000;
private const int patchblk_TargetSize = 0x0004;
private const int patchblk_SourceSize = 0x0008;
private const int patchblk_CRC = 0x000c;
private const int patchblk_SIZEOF = 0x0010;
#endregion
#region OABD_SYS_READ
private static int SysRead(object baseFile, byte[] buf, int pointer, int size)
{
InternalFile file = baseFile as InternalFile;
if (file == null)
return 0;
int bytes_read;
if (size > file.Available)
size = file.Available;
bytes_read = file.OrigSys.Read(file.OrigFile, buf, pointer, size);
if (bytes_read < 0)
return bytes_read;
file.Available -= bytes_read;
return bytes_read;
}
#endregion
#region OABD_SYS_WRITE
private static int SysWrite(object baseFile, byte[] buf, int pointer, int size)
{
InternalFile file = baseFile as InternalFile;
if (file == null)
return 0;
int bytes_written = file.OrigSys.Write(file.OrigFile, buf, pointer, size);
if (bytes_written > 0)
file.CRC = Checksum.CRC32(buf, 0, bytes_written, file.CRC);
return bytes_written;
}
#endregion
#region OABD_DECOMPRESS
public static Error Decompress(Decompressor d, string input, string output)
{
DecompressorImpl self = d as DecompressorImpl;
byte[] hdrbuf = new byte[oabhead_SIZEOF];
LZXDStream lzx = null;
Error ret = Error.MSPACK_ERR_OK;
if (self == null)
return Error.MSPACK_ERR_ARGS;
SystemImpl sys = self.System;
object infh = sys.Open(sys, input, OpenMode.MSPACK_SYS_OPEN_READ);
if (infh == null)
{
ret = Error.MSPACK_ERR_OPEN;
if (lzx != null)
LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
return ret;
}
if (sys.Read(infh, hdrbuf, 0, oabhead_SIZEOF) != oabhead_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
if (lzx != null)
LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
return ret;
}
if (BitConverter.ToUInt32(hdrbuf, oabhead_VersionHi) != 3 ||
BitConverter.ToUInt32(hdrbuf, oabhead_VersionLo) != 1)
{
ret = Error.MSPACK_ERR_SIGNATURE;
if (lzx != null)
LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
return ret;
}
uint block_max = BitConverter.ToUInt32(hdrbuf, oabhead_BlockMax);
uint target_size = BitConverter.ToUInt32(hdrbuf, oabhead_TargetSize);
object outfh = sys.Open(sys, output, OpenMode.MSPACK_SYS_OPEN_WRITE);
if (outfh == null)
{
ret = Error.MSPACK_ERR_OPEN;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
return ret;
}
byte[] buf = new byte[self.BufferSize];
SystemImpl oabd_sys = sys;
oabd_sys.Read = SysRead;
oabd_sys.Write = SysWrite;
InternalFile in_ofh = new InternalFile();
in_ofh.OrigSys = sys;
in_ofh.OrigFile = infh;
InternalFile out_ofh = new InternalFile();
out_ofh.OrigSys = sys;
out_ofh.OrigFile = outfh;
while (target_size != 0)
{
if (sys.Read(infh, buf, 0, oabblk_SIZEOF) != oabblk_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
uint blk_flags = BitConverter.ToUInt32(buf, oabblk_Flags);
uint blk_csize = BitConverter.ToUInt32(buf, oabblk_CompSize);
uint blk_dsize = BitConverter.ToUInt32(buf, oabblk_UncompSize);
uint blk_crc = BitConverter.ToUInt32(buf, oabblk_CRC);
if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1)
{
ret = Error.MSPACK_ERR_DATAFORMAT;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
if (blk_flags == 0)
{
// Uncompressed block
if (blk_dsize != blk_csize)
{
ret = Error.MSPACK_ERR_DATAFORMAT;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
ret = CopyFileHandle(sys, infh, outfh, (int)blk_dsize, buf, self.BufferSize);
if (ret != Error.MSPACK_ERR_OK)
{
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
}
else
{
// LZX compressed block
int window_bits = 17;
while (window_bits < 25 && (1U << window_bits) < blk_dsize)
{
window_bits++;
}
in_ofh.Available = (int)blk_csize;
out_ofh.CRC = 0xffffffff;
lzx = LZX.Init(oabd_sys, in_ofh, out_ofh, window_bits, 0, self.BufferSize, blk_dsize, true);
if (lzx == null)
{
ret = Error.MSPACK_ERR_NOMEMORY;
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
ret = LZX.Decompress(lzx, blk_dsize);
if (ret != Error.MSPACK_ERR_OK)
{
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
LZX.Free(lzx);
lzx = null;
// Consume any trailing padding bytes before the next block
ret = CopyFileHandle(sys, infh, null, in_ofh.Available, buf, self.BufferSize);
if (ret != Error.MSPACK_ERR_OK)
{
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
if (out_ofh.CRC != blk_crc)
{
ret = Error.MSPACK_ERR_CHECKSUM;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
}
target_size -= blk_dsize;
}
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
#endregion
#region OABD_DECOMPRESS_INCREMENTAL
public static Error DecompressIncremental(Decompressor d, string input, string basePath, string output)
{
DecompressorImpl self = d as DecompressorImpl;
byte[] hdrbuf = new byte[patchhead_SIZEOF];
LZXDStream lzx = null;
int window_bits;
uint window_size;
Error ret = Error.MSPACK_ERR_OK;
if (self == null)
return Error.MSPACK_ERR_ARGS;
SystemImpl sys = self.System;
object infh = sys.Open(sys, input, OpenMode.MSPACK_SYS_OPEN_READ);
if (infh == null)
{
ret = Error.MSPACK_ERR_OPEN;
if (lzx != null)
LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
return ret;
}
if (sys.Read(infh, hdrbuf, 0, patchhead_SIZEOF) != patchhead_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
if (lzx != null)
LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
return ret;
}
if (BitConverter.ToUInt32(hdrbuf, patchhead_VersionHi) != 3 ||
BitConverter.ToUInt32(hdrbuf, patchhead_VersionLo) != 2)
{
ret = Error.MSPACK_ERR_SIGNATURE;
if (lzx != null)
LZX.Free(lzx);
if (infh != null)
sys.Close(infh);
return ret;
}
uint block_max = BitConverter.ToUInt32(hdrbuf, patchhead_BlockMax);
uint target_size = BitConverter.ToUInt32(hdrbuf, patchhead_TargetSize);
// We use it for reading block headers too
if (block_max < patchblk_SIZEOF)
block_max = patchblk_SIZEOF;
object basefh = sys.Open(sys, basePath, OpenMode.MSPACK_SYS_OPEN_READ);
if (basefh == null)
{
ret = Error.MSPACK_ERR_OPEN;
if (lzx != null)
LZX.Free(lzx);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
return ret;
}
object outfh = sys.Open(sys, output, OpenMode.MSPACK_SYS_OPEN_WRITE);
if (outfh == null)
{
ret = Error.MSPACK_ERR_OPEN;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
return ret;
}
byte[] buf = new byte[self.BufferSize];
SystemImpl oabd_sys = sys;
oabd_sys.Read = SysRead;
oabd_sys.Write = SysWrite;
InternalFile in_ofh = new InternalFile();
in_ofh.OrigSys = sys;
in_ofh.OrigFile = infh;
InternalFile out_ofh = new InternalFile();
out_ofh.OrigSys = sys;
out_ofh.OrigFile = outfh;
while (target_size != 0)
{
if (sys.Read(infh, buf, 0, patchblk_SIZEOF) != patchblk_SIZEOF)
{
ret = Error.MSPACK_ERR_READ;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
uint blk_csize = BitConverter.ToUInt32(buf, patchblk_PatchSize);
uint blk_dsize = BitConverter.ToUInt32(buf, patchblk_TargetSize);
uint blk_ssize = BitConverter.ToUInt32(buf, patchblk_SourceSize);
uint blk_crc = BitConverter.ToUInt32(buf, patchblk_CRC);
if (blk_dsize > block_max || blk_dsize > target_size || blk_ssize > block_max)
{
ret = Error.MSPACK_ERR_DATAFORMAT;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
window_size = (uint)((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 = (int)blk_csize;
out_ofh.CRC = 0xffffffff;
lzx = LZX.Init(oabd_sys, in_ofh, out_ofh, window_bits, 0, 4096, blk_dsize, true);
if (lzx == null)
{
ret = Error.MSPACK_ERR_NOMEMORY;
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
ret = LZX.SetReferenceData(lzx, sys, basefh, blk_ssize);
if (ret != Error.MSPACK_ERR_OK)
{
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
ret = LZX.Decompress(lzx, blk_dsize);
if (ret != Error.MSPACK_ERR_OK)
{
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
LZX.Free(lzx);
lzx = null;
// Consume any trailing padding bytes before the next block
ret = CopyFileHandle(sys, infh, null, in_ofh.Available, buf, self.BufferSize);
if (ret != Error.MSPACK_ERR_OK)
{
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
if (out_ofh.CRC != blk_crc)
{
ret = Error.MSPACK_ERR_CHECKSUM;
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
target_size -= blk_dsize;
}
if (lzx != null)
LZX.Free(lzx);
if (outfh != null)
sys.Close(outfh);
if (basefh != null)
sys.Close(basefh);
if (infh != null)
sys.Close(infh);
sys.Free(buf);
return ret;
}
private static Error CopyFileHandle(SystemImpl sys, object infh, object 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, 0, run) != run)
return Error.MSPACK_ERR_READ;
if (outfh != null && sys.Write(outfh, buf, 0, run) != run)
return Error.MSPACK_ERR_WRITE;
bytes_to_copy -= run;
}
return Error.MSPACK_ERR_OK;
}
#endregion
#region OABD_PARAM
public static Error Param(Decompressor d, Parameters param, int value)
{
DecompressorImpl self = d as DecompressorImpl;
if (self != null && param == Parameters.MSOABD_PARAM_DECOMPBUF && value >= 16)
{
// must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF)
self.BufferSize = value;
return Error.MSPACK_ERR_OK;
}
return Error.MSPACK_ERR_ARGS;
}
#endregion
}
}