mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-12 13:45:35 +00:00
627 lines
20 KiB
C#
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
|
|
}
|
|
}
|