1
0
mirror of https://github.com/borgesdan/xn65 synced 2024-12-29 21:54:47 +01:00

Remove implementação de LzxDecoder

This commit is contained in:
Danilo 2024-06-04 14:37:28 -03:00
parent 5e47529377
commit 6151e60755
13 changed files with 2676 additions and 918 deletions

View File

@ -10,12 +10,13 @@ if (POLICY CMP0141)
endif()
# CMAKE_TOOLCHAIN_FILE
set(VCPKG_USER_DIRECTORY "C:/vcpkg")
include("${VCPKG_USER_DIRECTORY}/scripts/buildsystems/vcpkg.cmake")
set(PROJECT_VCPKG_DIRECTORY "C:/vcpkg")
set(PROJECT_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/inc")
include("${PROJECT_VCPKG_DIRECTORY}/scripts/buildsystems/vcpkg.cmake")
project ("xna")
# Include sub-projects.
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
include_directories(${PROJECT_INCLUDE_DIR})
add_subdirectory ("framework")
add_subdirectory ("samples")

View File

@ -4,14 +4,13 @@
# Add source to this project's executable.
add_library (Xn65 STATIC
"../samples/01_blank/xna.cpp"
"csharp/stream.cpp"
"game/component.cpp"
"content/manager.cpp"
"content/reader.cpp"
"csharp/binary.cpp"
"content/lzx/decoder.cpp"
"content/lzx/decoderstream.cpp"
"content/typereadermanager.cpp"
"csharp/object.cpp"
"csharp/type.cpp"
@ -52,4 +51,7 @@ endif()
find_package(directxtk CONFIG REQUIRED)
target_link_libraries(Xn65 D3d11.lib dxgi.lib dxguid.lib d3dcompiler.lib Microsoft::DirectXTK)
target_link_libraries(
Xn65 D3d11.lib dxgi.lib dxguid.lib d3dcompiler.lib Microsoft::DirectXTK
"${PROJECT_INCLUDE_DIR}/libmspack/mspack.lib"
)

View File

@ -1,5 +1,45 @@
#include "xna/content/lzx/decoder.hpp"
#include "libmspack/mspack.h"
#include "libmspack/lzx.h"
namespace xna {
LzxDecoder::LzxDecoder(int window) {
if (window < 15 || window > 21)
return;
window_bits = window;
}
int LzxDecoder::Decompress(Stream* inData, int inLen, Stream* outData, int outLen) {
auto input = reinterpret_cast<mspack_file*>(inData->Data());
auto output = reinterpret_cast<mspack_file*>(outData->Data());
auto lzxstream = lzxd_init(
//struct mspack_system* system,
nullptr,
//struct mspack_file* input,
input + inData->Position(),
//struct mspack_file* output,
output + outData->Position(),
//int window_bits,
window_bits,
//int reset_interval,
0,
//int input_buffer_size,
inLen,
//off_t output_length,
outLen,
//char is_delta
0
);
auto result = lzxd_decompress(
//struct lzxd_stream* lzx,
lzxstream,
//off_t out_bytes
0
);
return result;
}
}

View File

@ -1,40 +0,0 @@
#include "xna/content/lzx/decoderstream.hpp"
namespace xna {
Int LzxDecoderStream::Length()
{
return 0;
}
Long LzxDecoderStream::Position()
{
return 0;
}
void LzxDecoderStream::Close()
{
}
Long LzxDecoderStream::Seek(Long offset, SeekOrigin const& origin)
{
return Long();
}
Int LzxDecoderStream::Read(Byte* buffer, Int bufferLength, Int offset, Int count)
{
return decompressedStream->Read(buffer, bufferLength, offset, count);
}
Int LzxDecoderStream::Read(std::vector<Byte>& buffer, Int offset, Int count)
{
return decompressedStream->Read(buffer, offset, count);
}
Int LzxDecoderStream::ReadByte()
{
return Int();
}
void LzxDecoderStream::Write(Byte const* buffer, Int bufferLength, Int offset, Int count)
{
}
void LzxDecoderStream::Write(std::vector<Byte> const& buffer, Int offset, Int count)
{
}
void LzxDecoderStream::WriteByte(Byte value)
{
}
}

View File

@ -1,6 +1,5 @@
#include "xna/content/reader.hpp"
#include "xna/content/manager.hpp"
#include "xna/content/lzx/decoderstream.hpp"
#include "xna/content/typereadermanager.hpp"
namespace xna {
@ -152,9 +151,7 @@ namespace xna {
const Int compressedTodo = num2 - 14;
const auto decompressedTodo = binaryReader.ReadInt32();
auto lzxStream = New<LzxDecoderStream>(input, compressedTodo, decompressedTodo);
return reinterpret_pointer_cast<Stream>(lzxStream);
throw std::runtime_error("ContentReader::PrepareStream: LzxDecoder not implemented.");
}
Int ContentReader::ReadHeader() {

222
inc/libmspack/lzx.h Normal file
View File

@ -0,0 +1,222 @@
/* This file is part of libmspack.
* (C) 2003-2013 Stuart Caie.
*
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
* by Microsoft 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
*/
#include <sys/types.h>
#ifndef MSPACK_LZX_H
#define MSPACK_LZX_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* LZX compression / decompression definitions */
/* some constants defined by the LZX specification */
#define LZX_MIN_MATCH (2)
#define LZX_MAX_MATCH (257)
#define LZX_NUM_CHARS (256)
#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
#define LZX_BLOCKTYPE_VERBATIM (1)
#define LZX_BLOCKTYPE_ALIGNED (2)
#define LZX_BLOCKTYPE_UNCOMPRESSED (3)
#define LZX_PRETREE_NUM_ELEMENTS (20)
#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
/* LZX huffman defines: tweak tablebits as desired */
#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
#define LZX_PRETREE_TABLEBITS (6)
#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 290*8)
#define LZX_MAINTREE_TABLEBITS (12)
#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
#define LZX_LENGTH_TABLEBITS (12)
#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
#define LZX_ALIGNED_TABLEBITS (7)
#define LZX_LENTABLE_SAFETY (64) /* table decoding overruns are allowed */
#define LZX_FRAME_SIZE (32768) /* the size of a frame in LZX */
struct lzxd_stream {
struct mspack_system *sys; /* I/O routines */
struct mspack_file *input; /* input file handle */
struct mspack_file *output; /* output file handle */
off_t offset; /* number of bytes actually output */
off_t length; /* overall decompressed length of stream */
unsigned char *window; /* decoding window */
unsigned int window_size; /* window size */
unsigned int ref_data_size; /* LZX DELTA reference data size */
unsigned int num_offsets; /* number of match_offset entries in table */
unsigned int window_posn; /* decompression offset within window */
unsigned int frame_posn; /* current frame offset within in window */
unsigned int frame; /* the number of 32kb frames processed */
unsigned int reset_interval; /* which frame do we reset the compressor? */
unsigned int R0, R1, R2; /* for the LRU offset system */
unsigned int block_length; /* uncompressed length of this LZX block */
unsigned int block_remaining; /* uncompressed bytes still left to decode */
signed int intel_filesize; /* magic header value used for transform */
unsigned char intel_started; /* has intel E8 decoding started? */
unsigned char block_type; /* type of the current block */
unsigned char header_read; /* have we started decoding at all yet? */
unsigned char input_end; /* have we reached the end of input? */
unsigned char is_delta; /* does stream follow LZX DELTA spec? */
int error;
/* I/O buffering */
unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
unsigned int bit_buffer, bits_left, inbuf_size;
/* huffman code lengths */
unsigned char PRETREE_len [LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
unsigned char MAINTREE_len [LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
unsigned char LENGTH_len [LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
unsigned char ALIGNED_len [LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
/* huffman decoding tables */
unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
(LZX_PRETREE_MAXSYMBOLS * 2)];
unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
(LZX_MAINTREE_MAXSYMBOLS * 2)];
unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
(LZX_LENGTH_MAXSYMBOLS * 2)];
unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
(LZX_ALIGNED_MAXSYMBOLS * 2)];
unsigned char LENGTH_empty;
/* this is used purely for doing the intel E8 transform */
unsigned char e8_buf[LZX_FRAME_SIZE];
};
/**
* Allocates and initialises LZX decompression state for decoding an LZX
* stream.
*
* This routine uses system->alloc() to allocate memory. If memory
* allocation fails, or the parameters to this function are invalid,
* NULL is returned.
*
* @param system an mspack_system structure used to read from
* the input stream and write to the output
* stream, also to allocate and free memory.
* @param input an input stream with the LZX data.
* @param output an output stream to write the decoded data to.
* @param window_bits the size of the decoding window, which must be
* between 15 and 21 inclusive for regular LZX
* data, or between 17 and 25 inclusive for
* LZX DELTA data.
* @param reset_interval the interval at which the LZX bitstream is
* reset, in multiples of LZX frames (32678
* bytes), e.g. a value of 2 indicates the input
* stream resets after every 65536 output bytes.
* A value of 0 indicates that the bitstream never
* resets, such as in CAB LZX streams.
* @param input_buffer_size the number of bytes to use as an input
* bitstream buffer.
* @param output_length the length in bytes of the entirely
* decompressed output stream, if known in
* advance. It is used to correctly perform the
* Intel E8 transformation, which must stop 6
* bytes before the very end of the
* decompressed stream. It is not otherwise used
* or adhered to. If the full decompressed
* length is known in advance, set it here.
* If it is NOT known, use the value 0, and call
* lzxd_set_output_length() once it is
* known. If never set, 4 of the final 6 bytes
* of the output stream may be incorrect.
* @param is_delta should be zero for all regular LZX data,
* non-zero for LZX DELTA encoded data.
* @return a pointer to an initialised lzxd_stream structure, or NULL if
* there was not enough memory or parameters to the function were wrong.
*/
extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
struct mspack_file *input,
struct mspack_file *output,
int window_bits,
int reset_interval,
int input_buffer_size,
off_t output_length,
char is_delta);
/* see description of output_length in lzxd_init() */
extern void lzxd_set_output_length(struct lzxd_stream *lzx,
off_t output_length);
/**
* Reads LZX DELTA reference data into the window and allows
* lzxd_decompress() to reference it.
*
* Call this before the first call to lzxd_decompress().
* @param lzx the LZX stream to apply this reference data to
* @param system an mspack_system implementation to use with the
* input param. Only read() will be called.
* @param input an input file handle to read reference data using
* system->read().
* @param length the length of the reference data. Cannot be longer
* than the LZX window size.
* @return an error code, or MSPACK_ERR_OK if successful
*/
extern int lzxd_set_reference_data(struct lzxd_stream *lzx,
struct mspack_system *system,
struct mspack_file *input,
unsigned int length);
/**
* Decompresses entire or partial LZX streams.
*
* The number of bytes of data that should be decompressed is given as the
* out_bytes parameter. If more bytes are decoded than are needed, they
* will be kept over for a later invocation.
*
* The output bytes will be passed to the system->write() function given in
* lzxd_init(), using the output file handle given in lzxd_init(). More than
* one call may be made to system->write().
* Input bytes will be read in as necessary using the system->read()
* function given in lzxd_init(), using the input file handle given in
* lzxd_init(). This will continue until system->read() returns 0 bytes,
* or an error. Errors will be passed out of the function as
* MSPACK_ERR_READ errors. Input streams should convey an "end of input
* stream" by refusing to supply all the bytes that LZX asks for when they
* reach the end of the stream, rather than return an error code.
*
* If any error code other than MSPACK_ERR_OK is returned, the stream
* should be considered unusable and lzxd_decompress() should not be
* called again on this stream.
*
* @param lzx LZX decompression state, as allocated by lzxd_init().
* @param out_bytes the number of bytes of data to decompress.
* @return an error code, or MSPACK_ERR_OK if successful
*/
extern int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes);
/**
* Frees all state associated with an LZX data stream. This will call
* system->free() using the system pointer given in lzxd_init().
*
* @param lzx LZX decompression state to free.
*/
void lzxd_free(struct lzxd_stream *lzx);
#ifdef __cplusplus
}
#endif
#endif

2385
inc/libmspack/mspack.h Normal file

File diff suppressed because it is too large Load Diff

BIN
inc/libmspack/mspack.lib Normal file

Binary file not shown.

View File

@ -6,781 +6,10 @@
#include <algorithm>
namespace xna {
struct LzxConstants {
static constexpr Ushort MIN_MATCH = 2;
static constexpr Ushort MAX_MATCH = 257;
static constexpr Ushort NUM_CHARS = 256;
enum class BLOCKTYPE {
INVALID = 0,
VERBATIM = 1,
ALIGNED = 2,
UNCOMPRESSED = 3
};
static constexpr Ushort PRETREE_NUM_ELEMENTS = 20;
static constexpr Ushort ALIGNED_NUM_ELEMENTS = 8;
static constexpr Ushort NUM_PRIMARY_LENGTHS = 7;
static constexpr Ushort NUM_SECONDARY_LENGTHS = 249;
static constexpr Ushort PRETREE_MAXSYMBOLS = PRETREE_NUM_ELEMENTS;
static constexpr Ushort PRETREE_TABLEBITS = 6;
static constexpr Ushort MAINTREE_MAXSYMBOLS = NUM_CHARS + 50 * 8;
static constexpr Ushort MAINTREE_TABLEBITS = 12;
static constexpr Ushort LENGTH_MAXSYMBOLS = NUM_SECONDARY_LENGTHS + 1;
static constexpr Ushort LENGTH_TABLEBITS = 12;
static constexpr Ushort ALIGNED_MAXSYMBOLS = ALIGNED_NUM_ELEMENTS;
static constexpr Ushort ALIGNED_TABLEBITS = 7;
static constexpr Ushort LENTABLE_SAFETY = 64;
};
struct LzxState {
Uint R0{ 1 }, R1{ 1 }, R2{ 1 }; /* for the LRU offset system */
Ushort main_elements{ 0 }; /* number of main tree elements */
Int header_read{ 0 }; /* have we started decoding at all yet? */
LzxConstants::BLOCKTYPE block_type{ LzxConstants::BLOCKTYPE::INVALID }; /* type of this block */
Uint block_length{ 0 }; /* uncompressed length of this block */
Uint block_remaining{ 0 }; /* uncompressed bytes still left to decode */
Uint frames_read{ 0 }; /* the number of CFDATA blocks processed */
Int intel_filesize{ 0 }; /* magic header value used for transform */
Int intel_curpos{ 0 }; /* current offset in transform space */
Int intel_started{ 0 }; /* have we seen any translateable data yet? */
std::vector<Ushort> PRETREE_table;
std::vector<Byte> PRETREE_len;
std::vector<Ushort> MAINTREE_table;
std::vector<Byte> MAINTREE_len;
std::vector<Ushort> LENGTH_table;
std::vector<Byte> LENGTH_len;
std::vector<Ushort> ALIGNED_table;
std::vector<Byte> ALIGNED_len;
// NEEDED MEMBERS
// CAB actualsize
// CAB window
// CAB window_size
// CAB window_posn
Uint actual_size{ 0 };
std::vector<Byte> window;
Uint window_size{ 0 };
Uint window_posn{ 0 };
};
class BitBuffer {
public:
BitBuffer(sptr<Stream> const& stream) : byteStream(stream) {
InitBitStream();
}
constexpr void InitBitStream() {
buffer = 0;
bitsleft = 0;
}
void EnsureBits(Byte bits) {
while (bitsleft < bits) {
const auto lo = static_cast<Byte>(byteStream->ReadByte());
const auto hi = static_cast<Byte>(byteStream->ReadByte());
//int amount2shift = sizeofstatic_cast<Uint>(*8 - 16 - bitsleft;
buffer |= static_cast<Uint>(((hi << 8) | lo) << (sizeof(Uint) * 8 - 16 - bitsleft));
bitsleft += 16;
}
}
constexpr Uint PeekBits(Byte bits) const
{
return (buffer >> ((sizeof(Uint) * 8) - bits));
}
constexpr void RemoveBits(Byte bits) {
buffer <<= bits;
bitsleft -= bits;
}
Uint ReadBits(Byte bits)
{
Uint ret = 0;
if (bits > 0)
{
EnsureBits(bits);
ret = PeekBits(bits);
RemoveBits(bits);
}
return ret;
}
constexpr Uint GetBuffer() const {
return buffer;
}
constexpr Byte GetBitsLeft() const {
return bitsleft;
}
private:
Uint buffer{ 0 };
Byte bitsleft{ 0 };
sptr<Stream> byteStream = nullptr;
};
class LzxDecoder {
public:
LzxDecoder(Int window) {
Uint wndsize = (Uint)(1 << window);
Int posn_slots = 0;
// setup proper exception
if (window < 15 || window > 21)
return;
// let's initialise our state
m_state.window = std::vector<Byte>(wndsize, 0xDC);
m_state.actual_size = wndsize;
m_state.window_size = wndsize;
/* initialize static tables */
if (extra_bits.empty()) {
extra_bits.resize(52);
for (size_t i = 0, j = 0; i <= 50; i += 2) {
extra_bits[i] = extra_bits[i + 1] = static_cast<Byte>(j);
if ((i != 0) && (j < 17))
j++;
}
}
if (position_base.empty()) {
position_base.resize(51);
for (size_t i = 0, j = 0; i <= 50; i++) {
position_base[i] = static_cast<Uint>(j);
j += static_cast<size_t>(1) << extra_bits[i];
}
}
/* calculate required position slots */
if (window == 20)
posn_slots = 42;
else if (window == 21)
posn_slots = 50;
else
posn_slots = window << 1;
m_state.main_elements = static_cast<Ushort>(LzxConstants::NUM_CHARS + (posn_slots << 3));
// yo dawg i herd u liek arrays so we put arrays in ur arrays so u can array while u array
m_state.PRETREE_table = std::vector<Ushort>((1 << LzxConstants::PRETREE_TABLEBITS) + (LzxConstants::PRETREE_MAXSYMBOLS << 1));
m_state.PRETREE_len = std::vector<Byte>(LzxConstants::PRETREE_MAXSYMBOLS + LzxConstants::LENTABLE_SAFETY);
m_state.MAINTREE_table = std::vector<Ushort>((1 << LzxConstants::MAINTREE_TABLEBITS) + (LzxConstants::MAINTREE_MAXSYMBOLS << 1));
m_state.MAINTREE_len = std::vector<Byte>(LzxConstants::MAINTREE_MAXSYMBOLS + LzxConstants::LENTABLE_SAFETY);
m_state.LENGTH_table = std::vector<Ushort>((1 << LzxConstants::LENGTH_TABLEBITS) + (LzxConstants::LENGTH_MAXSYMBOLS << 1));
m_state.LENGTH_len = std::vector<Byte>(LzxConstants::LENGTH_MAXSYMBOLS + LzxConstants::LENTABLE_SAFETY);
m_state.ALIGNED_table = std::vector<Ushort>((1 << LzxConstants::ALIGNED_TABLEBITS) + (LzxConstants::ALIGNED_MAXSYMBOLS << 1));
m_state.ALIGNED_len = std::vector<Byte>(LzxConstants::ALIGNED_MAXSYMBOLS + LzxConstants::LENTABLE_SAFETY);
/* initialise tables to 0 (because deltas will be applied to them) */
for (size_t i = 0; i < LzxConstants::MAINTREE_MAXSYMBOLS; i++)
m_state.MAINTREE_len[i] = 0;
for (size_t i = 0; i < LzxConstants::LENGTH_MAXSYMBOLS; i++)
m_state.LENGTH_len[i] = 0;
}
Int Decompress(sptr<Stream>& inData, Int inLen, sptr<Stream>& outData, Int outLen) {
BitBuffer bitbuf(inData);
auto startpos = inData->Position();
auto endpos = inData->Position() + inLen;
auto& window = m_state.window;
Uint window_posn = m_state.window_posn;
Uint window_size = m_state.window_size;
Uint R0 = m_state.R0;
Uint R1 = m_state.R1;
Uint R2 = m_state.R2;
Uint i = 0;
Uint j = 0;
Int togo = outLen;
Int this_run = 0;
Int main_element = 0;
Int match_length = 0;
Int match_offset = 0;
Int length_footer = 0;
Int extra = 0;
Int verbatim_bits = 0;
Int rundest = 0;
Int runsrc = 0;
Int copy_length = 0;
Int aligned_bits = 0;
bitbuf.InitBitStream();
/* read header if necessary */
if (m_state.header_read == 0)
{
const auto intel = bitbuf.ReadBits(1);
if (intel != 0)
{
// read the filesize
i = bitbuf.ReadBits(16);
j = bitbuf.ReadBits(16);
m_state.intel_filesize = static_cast<Int>((i << 16) | j);
}
m_state.header_read = 1;
}
while (togo > 0)
{
/* last block finished, new block expected */
if (m_state.block_remaining == 0)
{
// TODO may screw something up here
if (m_state.block_type == LzxConstants::BLOCKTYPE::UNCOMPRESSED) {
if ((m_state.block_length & 1) == 1)
inData->ReadByte(); /* realign bitstream to word */
bitbuf.InitBitStream();
}
m_state.block_type = static_cast<LzxConstants::BLOCKTYPE>(bitbuf.ReadBits(3));
i = bitbuf.ReadBits(16);
j = bitbuf.ReadBits(8);
m_state.block_remaining = m_state.block_length = static_cast<Uint>((i << 8) | j);
switch (m_state.block_type) {
case LzxConstants::BLOCKTYPE::ALIGNED: {
for (i = 0, j = 0; i < 8; i++) {
j = bitbuf.ReadBits(3);
m_state.ALIGNED_len[i] = static_cast<Byte>(j);
}
MakeDecodeTable(LzxConstants::ALIGNED_MAXSYMBOLS, LzxConstants::ALIGNED_TABLEBITS,
m_state.ALIGNED_len, m_state.ALIGNED_table);
//O mesmo que verbatim
ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
MakeDecodeTable(LzxConstants::MAINTREE_MAXSYMBOLS, LzxConstants::MAINTREE_TABLEBITS,
m_state.MAINTREE_len, m_state.MAINTREE_table);
if (m_state.MAINTREE_len[0xE8] != 0)
m_state.intel_started = 1;
ReadLengths(m_state.LENGTH_len, 0, LzxConstants::NUM_SECONDARY_LENGTHS, bitbuf);
MakeDecodeTable(LzxConstants::LENGTH_MAXSYMBOLS, LzxConstants::LENGTH_TABLEBITS,
m_state.LENGTH_len, m_state.LENGTH_table);
break;
}
case LzxConstants::BLOCKTYPE::VERBATIM: {
ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
MakeDecodeTable(LzxConstants::MAINTREE_MAXSYMBOLS, LzxConstants::MAINTREE_TABLEBITS,
m_state.MAINTREE_len, m_state.MAINTREE_table);
if (m_state.MAINTREE_len[0xE8] != 0)
m_state.intel_started = 1;
ReadLengths(m_state.LENGTH_len, 0, LzxConstants::NUM_SECONDARY_LENGTHS, bitbuf);
MakeDecodeTable(LzxConstants::LENGTH_MAXSYMBOLS, LzxConstants::LENGTH_TABLEBITS,
m_state.LENGTH_len, m_state.LENGTH_table);
break;
}
case LzxConstants::BLOCKTYPE::UNCOMPRESSED: {
m_state.intel_started = 1; /* because we can't assume otherwise */
bitbuf.EnsureBits(16); /* get up to 16 pad bits into the buffer */
if (bitbuf.GetBitsLeft() > 16)
inData->Seek(-2, SeekOrigin::Current); /* and align the bitstream! */
Byte hi = 0;
Byte mh = 0;
Byte ml = 0;
Byte lo = 0;
lo = static_cast<Byte>(inData->ReadByte());
ml = static_cast<Byte>(inData->ReadByte());
mh = static_cast<Byte>(inData->ReadByte());
hi = static_cast<Byte>(inData->ReadByte());
R0 = static_cast<Uint>(lo | ml << 8 | mh << 16 | hi << 24);
lo = static_cast<Byte>(inData->ReadByte());
ml = static_cast<Byte>(inData->ReadByte());
mh = static_cast<Byte>(inData->ReadByte());
hi = static_cast<Byte>(inData->ReadByte());
R1 = static_cast<Uint>(lo | ml << 8 | mh << 16 | hi << 24);
lo = static_cast<Byte>(inData->ReadByte());
ml = static_cast<Byte>(inData->ReadByte());
mh = static_cast<Byte>(inData->ReadByte());
hi = static_cast<Byte>(inData->ReadByte());
R2 = static_cast<Uint>(lo | ml << 8 | mh << 16 | hi << 24);
break;
}
default:
return -1; // TODO throw proper exception
}
}
return 0;
/* buffer exhaustion check */
if (inData->Position() > (startpos + inLen))
{
/* it's possible to have a file where the next run is less than
* 16 bits in size. In this case, the READ_HUFFSYM() macro used
* in building the tables will exhaust the buffer, so we should
* allow for this, but not allow those accidentally read bits to
* be used (so we check that there are at least 16 bits
* remaining - in this boundary case they aren't really part of
* the compressed data)
*/
//Debug.WriteLine("WTF");
if (inData->Position() > (startpos + inLen + 2) || bitbuf.GetBitsLeft() < 16)
return -1; //TODO throw proper exception
}
while ((this_run = static_cast<Int>(m_state.block_remaining)) > 0 && togo > 0)
{
if (this_run > togo)
this_run = togo;
togo -= this_run;
m_state.block_remaining -= static_cast<Uint>(this_run);
/* apply 2^x-1 mask */
window_posn &= window_size - 1;
/* runs can't straddle the window wraparound */
if ((window_posn + this_run) > window_size)
return -1; //TODO throw proper exception
switch (m_state.block_type)
{
case LzxConstants::BLOCKTYPE::VERBATIM: {
while (this_run > 0)
{
main_element = static_cast<Int>(ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
LzxConstants::MAINTREE_MAXSYMBOLS, LzxConstants::MAINTREE_TABLEBITS,
bitbuf));
if (main_element < LzxConstants::NUM_CHARS)
{
/* literal: 0 to NUM_CHARS-1 */
window[window_posn++] = static_cast<Byte>(main_element);
this_run--;
}
else
{
/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
main_element -= LzxConstants::NUM_CHARS;
match_length = main_element & LzxConstants::NUM_PRIMARY_LENGTHS;
if (match_length == LzxConstants::NUM_PRIMARY_LENGTHS)
{
length_footer = static_cast<Int>(ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
LzxConstants::LENGTH_MAXSYMBOLS, LzxConstants::LENGTH_TABLEBITS,
bitbuf));
match_length += length_footer;
}
match_length += LzxConstants::MIN_MATCH;
match_offset = main_element >> 3;
if (match_offset > 2)
{
/* not repeated offset */
if (match_offset != 3)
{
extra = extra_bits[match_offset];
verbatim_bits = static_cast<Int>(bitbuf.ReadBits(static_cast<Int>(extra)));
match_offset = static_cast<Int>(position_base[match_offset]) - 2 + verbatim_bits;
}
else
{
match_offset = 1;
}
/* update repeated offset LRU queue */
R2 = R1; R1 = R0; R0 = static_cast<Uint>(match_offset);
}
else if (match_offset == 0)
{
match_offset = (int)R0;
}
else if (match_offset == 1)
{
match_offset = (int)R1;
R1 = R0; R0 = static_cast<Uint>(match_offset);
}
else /* match_offset == 2 */
{
match_offset = (int)R2;
R2 = R0; R0 = static_cast<Uint>(match_offset);
}
rundest = (int)window_posn;
this_run -= match_length;
/* copy any wrapped around source data */
if (static_cast<Int>(window_posn) >= match_offset)
{
/* no wrap */
runsrc = rundest - match_offset;
}
else
{
runsrc = rundest + ((int)window_size - match_offset);
copy_length = match_offset - (int)window_posn;
if (copy_length < match_length)
{
match_length -= copy_length;
window_posn += static_cast<Uint>(copy_length);
while (copy_length-- > 0) window[rundest++] = window[runsrc++];
runsrc = 0;
}
}
window_posn += static_cast<Uint>(match_length);
/* copy match data - no worries about destination wraps */
while (match_length-- > 0) window[rundest++] = window[runsrc++];
}
}
break;
}
case LzxConstants::BLOCKTYPE::ALIGNED: {
while (this_run > 0)
{
main_element = static_cast<Int>(ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
LzxConstants::MAINTREE_MAXSYMBOLS, LzxConstants::MAINTREE_TABLEBITS,
bitbuf));
if (main_element < LzxConstants::NUM_CHARS)
{
/* literal 0 to NUM_CHARS-1 */
window[window_posn++] = static_cast<Byte>(main_element);
this_run--;
}
else
{
/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
main_element -= LzxConstants::NUM_CHARS;
match_length = main_element & LzxConstants::NUM_PRIMARY_LENGTHS;
if (match_length == LzxConstants::NUM_PRIMARY_LENGTHS)
{
length_footer = static_cast<Int>(ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
LzxConstants::LENGTH_MAXSYMBOLS, LzxConstants::LENGTH_TABLEBITS,
bitbuf));
match_length += length_footer;
}
match_length += LzxConstants::MIN_MATCH;
match_offset = main_element >> 3;
if (match_offset > 2)
{
/* not repeated offset */
extra = extra_bits[match_offset];
match_offset = static_cast<Int>(position_base[match_offset]) - 2;
if (extra > 3)
{
/* verbatim and aligned bits */
extra -= 3;
verbatim_bits = static_cast<Int>(bitbuf.ReadBits(static_cast<Byte>(extra)));
match_offset += (verbatim_bits << 3);
aligned_bits = static_cast<Int>(ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
LzxConstants::ALIGNED_MAXSYMBOLS, LzxConstants::ALIGNED_TABLEBITS,
bitbuf));
match_offset += aligned_bits;
}
else if (extra == 3)
{
/* aligned bits only */
aligned_bits = static_cast<Int>(ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
LzxConstants::ALIGNED_MAXSYMBOLS, LzxConstants::ALIGNED_TABLEBITS,
bitbuf));
match_offset += aligned_bits;
}
else if (extra > 0) /* extra==1, extra==2 */
{
/* verbatim bits only */
verbatim_bits = static_cast<Int>(bitbuf.ReadBits(static_cast<Byte>(extra)));
match_offset += verbatim_bits;
}
else /* extra == 0 */
{
/* ??? */
match_offset = 1;
}
/* update repeated offset LRU queue */
R2 = R1; R1 = R0; R0 = static_cast<Uint>(match_offset);
}
else if (match_offset == 0)
{
match_offset = (int)R0;
}
else if (match_offset == 1)
{
match_offset = (int)R1;
R1 = R0; R0 = static_cast<Uint>(match_offset);
}
else /* match_offset == 2 */
{
match_offset = (int)R2;
R2 = R0; R0 = static_cast<Uint>(match_offset);
}
rundest = (int)window_posn;
this_run -= match_length;
/* copy any wrapped around source data */
if (static_cast<Int>(window_posn) >= match_offset)
{
/* no wrap */
runsrc = rundest - match_offset;
}
else
{
runsrc = rundest + ((int)window_size - match_offset);
copy_length = match_offset - (int)window_posn;
if (copy_length < match_length)
{
match_length -= copy_length;
window_posn += static_cast<Uint>(copy_length);
while (copy_length-- > 0) window[rundest++] = window[runsrc++];
runsrc = 0;
}
}
window_posn += static_cast<Uint>(match_length);
/* copy match data - no worries about destination wraps */
while (match_length-- > 0) window[rundest++] = window[runsrc++];
}
}
break;
}
case LzxConstants::BLOCKTYPE::UNCOMPRESSED: {
if ((inData->Position() + this_run) > endpos) return -1; //TODO throw proper exception
std::vector<Byte> temp_buffer(this_run);
inData->Read(temp_buffer, 0, this_run);
for (size_t offset = 0; offset < temp_buffer.size(); ++offset)
window[window_posn + offset] = temp_buffer[offset];
window_posn += static_cast<Uint>(this_run);
break;
}
default:
return -1; //TODO throw proper exception
}
}
}
if (togo != 0)
return -1; //TODO throw proper exception
Int start_window_pos = static_cast<Int>(window_posn);
if (start_window_pos == 0)
start_window_pos = static_cast<Int>(window_size);
start_window_pos -= outLen;
outData->Write(window, start_window_pos, outLen);
m_state.window_posn = window_posn;
m_state.R0 = R0;
m_state.R1 = R1;
m_state.R2 = R2;
// TODO finish intel E8 decoding
/* intel E8 decoding */
if ((m_state.frames_read++ < 32768) && m_state.intel_filesize != 0)
{
if (outLen <= 6 || m_state.intel_started == 0)
{
m_state.intel_curpos += outLen;
}
else
{
Int dataend = outLen - 10;
auto curpos = static_cast<Uint>(m_state.intel_curpos);
m_state.intel_curpos = static_cast<Int>(curpos) + outLen;
while (outData->Position() < dataend)
{
if (outData->ReadByte() != 0xE8) {
curpos++;
continue;
}
}
}
return -1;
}
return 0;
}
public:
inline static std::vector<Uint> position_base;
inline static std::vector<Byte> extra_bits;
private:
LzxState m_state;
Int MakeDecodeTable(Uint nsyms, Uint nbits, std::vector<Byte>& length, std::vector<Ushort>& table) {
Ushort sym = 0;
Uint leaf = 0;
Byte bit_num = 1;
Uint fill;
Uint pos = 0; /* the current position in the decode table */
Uint table_mask = static_cast<Uint>(1 << static_cast<Int>(nbits));
Uint bit_mask = table_mask >> 1; /* don't do 0 length codes */
Uint next_symbol = bit_mask; /* base of allocation for long codes */
/* fill entries for codes short enough for a direct mapping */
while (bit_num <= nbits)
{
for (sym = 0; sym < nsyms; sym++)
{
if (length[sym] == bit_num)
{
leaf = pos;
if ((pos += bit_mask) > table_mask) return 1; /* table overrun */
/* fill all possible lookups of this symbol with the symbol itself */
fill = bit_mask;
while (fill-- > 0) table[leaf++] = sym;
}
}
bit_mask >>= 1;
bit_num++;
}
/* if there are any codes longer than nbits */
if (pos != table_mask)
{
/* clear the remainder of the table */
for (sym = static_cast<Ushort>(pos);
sym < table_mask; sym++) table[sym] = 0;
/* give ourselves room for codes to grow by up to 16 more bits */
pos <<= 16;
table_mask <<= 16;
bit_mask = 1 << 15;
while (bit_num <= 16)
{
for (sym = 0; sym < nsyms; sym++)
{
if (length[sym] == bit_num)
{
leaf = pos >> 16;
for (fill = 0; fill < bit_num - nbits; fill++)
{
/* if this path hasn't been taken yet, 'allocate' two entries */
if (table[leaf] == 0)
{
table[(next_symbol << 1)] = 0;
table[(next_symbol << 1) + 1] = 0;
table[leaf] = static_cast<Ushort>(next_symbol++);
}
/* follow the path and select either left or right for next bit */
leaf = static_cast<Uint>(table[leaf] << 1);
if (((pos >> static_cast<Int>(15 - fill)) & 1) == 1) leaf++;
}
table[leaf] = sym;
if ((pos += bit_mask) > table_mask) return 1;
}
}
bit_mask >>= 1;
bit_num++;
}
}
/* full talbe? */
if (pos == table_mask) return 0;
/* either erroneous table, or all elements are 0 - let's find out. */
for (sym = 0; sym < nsyms; sym++) if (length[sym] != 0) return 1;
return 0;
}
void ReadLengths(std::vector<Byte>& lens, Uint first, Uint last, BitBuffer& bitbuf) {
Uint x = 0;
Uint y = 0;
Int z = 0;
// hufftbl pointer here?
for (x = 0; x < 20; x++)
{
y = bitbuf.ReadBits(4);
m_state.PRETREE_len[x] = static_cast<Byte>(y);
}
MakeDecodeTable(LzxConstants::PRETREE_MAXSYMBOLS, LzxConstants::PRETREE_TABLEBITS,
m_state.PRETREE_len, m_state.PRETREE_table);
for (x = first; x < last;)
{
z = (int)ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
LzxConstants::PRETREE_MAXSYMBOLS, LzxConstants::PRETREE_TABLEBITS, bitbuf);
if (z == 17)
{
y = bitbuf.ReadBits(4); y += 4;
while (y-- != 0) lens[x++] = 0;
}
else if (z == 18)
{
y = bitbuf.ReadBits(5); y += 20;
while (y-- != 0) lens[x++] = 0;
}
else if (z == 19)
{
y = bitbuf.ReadBits(1); y += 4;
z = static_cast<Int>(ReadHuffSym(m_state.PRETREE_table, m_state.PRETREE_len,
LzxConstants::PRETREE_MAXSYMBOLS, LzxConstants::PRETREE_TABLEBITS, bitbuf));
z = lens[x] - z; if (z < 0) z += 17;
while (y-- != 0) lens[x++] = static_cast<Byte>(z);
}
else
{
z = lens[x] - z; if (z < 0) z += 17;
lens[x++] = static_cast<Byte>(z);
}
}
}
Uint ReadHuffSym(std::vector<Ushort>& table, std::vector<Byte>& lengths, Uint nsyms, Uint nbits, BitBuffer& bitbuf) {
Uint i = 0;
Uint j = 0;
bitbuf.EnsureBits(16);
if ((i = table[bitbuf.PeekBits(static_cast<Byte>(nbits))]) >= nsyms)
{
j = static_cast<Uint>(1 << static_cast<Int>((sizeof(Uint) * 8) - nbits));
do
{
j >>= 1; i <<= 1; i |= (bitbuf.GetBuffer() & j) != 0 ? static_cast<Uint>(1) : 0;
if (j == 0) return 0; // TODO throw proper exception
} while ((i = table[i]) >= nsyms);
}
j = lengths[i];
bitbuf.RemoveBits(static_cast<Byte>(j));
return i;
}
struct LzxDecoder {
LzxDecoder(int window);
int Decompress(Stream* inData, int inLen, Stream* outData, int outLen);
int window_bits = 0;
};
}

View File

@ -1,89 +0,0 @@
#ifndef XNA_CONTENT_LZX_DECODERSTREAM_HPP
#define XNA_CONTENT_LZX_DECODERSTREAM_HPP
#include "decoder.hpp"
namespace xna {
class LzxDecoderStream : public Stream {
public:
LzxDecoderStream(sptr<Stream>& input, Int decompressedSize, Int compressedSize) {
dec = New<LzxDecoder>(16);
Decompress(input, decompressedSize, compressedSize);
}
private:
void Decompress(sptr<Stream>& stream, Int decompressedSize, Int compressedSize) {
//thanks to ShinAli (https://bitbucket.org/alisci01/xnbdecompressor)
// default window size for XNB encoded files is 64Kb (need 16 bits to represent it)
decompressedStream = New<MemoryStream>(decompressedSize);
auto startPos = stream->Position();
auto pos = startPos;
while (pos - startPos < compressedSize)
{
// the compressed stream is seperated into blocks that will decompress
// into 32Kb or some other size if specified.
// normal, 32Kb output blocks will have a short indicating the size
// of the block before the block starts
// blocks that have a defined output will be preceded by a byte of value
// 0xFF (255), then a short indicating the output size and another
// for the block size
// all shorts for these cases are encoded in big endian order
Int hi = stream->ReadByte();
Int lo = stream->ReadByte();
Int block_size = (hi << 8) | lo;
Int frame_size = 0x8000; // frame size is 32Kb by default
// does this block define a frame size?
if (hi == 0xFF) {
hi = lo;
lo = static_cast<Byte>(stream->ReadByte());
frame_size = (hi << 8) | lo;
hi = static_cast<Byte>(stream->ReadByte());
lo = static_cast<Byte>(stream->ReadByte());
block_size = (hi << 8) | lo;
pos += 5;
}
else
pos += 2;
// either says there is nothing to decode
if (block_size == 0 || frame_size == 0)
break;
auto decompressed = reinterpret_pointer_cast<Stream>(decompressedStream);
dec->Decompress(stream, block_size, decompressed, frame_size);
pos += block_size;
// reset the position of the input just incase the bit buffer
// read in some unused bytes
stream->Seek(pos, SeekOrigin::Begin);
}
if (decompressedStream->Position() != decompressedSize)
{
return;
}
decompressedStream->Seek(0, SeekOrigin::Begin);
}
private:
sptr<LzxDecoder> dec = nullptr;
sptr<MemoryStream>decompressedStream = nullptr;
// Inherited via Stream
Int Length() override;
Long Position() override;
void Close() override;
Long Seek(Long offset, SeekOrigin const& origin) override;
Int Read(Byte* buffer, Int bufferLength, Int offset, Int count) override;
Int Read(std::vector<Byte>& buffer, Int offset, Int count) override;
Int ReadByte() override;
void Write(Byte const* buffer, Int bufferLength, Int offset, Int count) override;
void Write(std::vector<Byte> const& buffer, Int offset, Int count) override;
void WriteByte(Byte value) override;
virtual constexpr bool IsClosed() override { return false; }
};
}
#endif

View File

@ -40,6 +40,8 @@ namespace xna {
//Writes a byte to the current position in the stream and advances the position within the stream by one byte.
virtual void WriteByte(Byte value) = 0;
virtual void* Data() = 0;
};
//A simplified port of the System.IO.MemoryStream.
@ -83,6 +85,10 @@ namespace xna {
virtual void Write(std::vector<Byte> const& buffer, Int offset, Int count) override;
virtual void WriteByte(Byte value) override;
virtual void* Data() override {
return _buffer.data();
}
public:
std::vector<Byte> _buffer;
private:
@ -124,6 +130,10 @@ namespace xna {
virtual void Write(std::vector<Byte> const& buffer, Int offset, Int count) override;
virtual void WriteByte(Byte value) override;
virtual void* Data() override {
return _fstream.rdbuf();
}
public:
std::fstream _fstream;

View File

@ -19,7 +19,6 @@
#include "content/reader.hpp"
#include "content/typereadermanager.hpp"
#include "content/lzx/decoder.hpp"
#include "content/lzx/decoderstream.hpp"
#include "csharp/binary.hpp"
#include "csharp/buffer.hpp"
#include "csharp/object.hpp"

View File

@ -3,11 +3,13 @@
#
# Add source to this project's executable.
add_executable (BlankApp WIN32 "game.cpp" "animation.cpp" "enemy.cpp" "level.cpp" "player.cpp" "gem.cpp")
add_executable (PlatformApp WIN32 "game.cpp" "animation.cpp" "enemy.cpp" "level.cpp" "player.cpp" "gem.cpp")
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET BlankApp PROPERTY CXX_STANDARD 20)
set_property(TARGET PlatformApp PROPERTY CXX_STANDARD 20)
endif()
# TODO: Add tests and install targets if needed.
target_link_libraries(BlankApp Xn65)
target_link_libraries(
PlatformApp Xn65
)