Compare commits

...

10 Commits

Author SHA1 Message Date
=
2eaaa87b72 Add lzo files. 2025-06-04 22:35:10 -04:00
=
c005d19fa8 Add compro tool. 2025-06-04 22:34:49 -04:00
=
b5595d9855 Add temp icon psd. 2025-06-04 22:34:32 -04:00
=
aef7c2657d Add compro tool to project. 2025-06-04 22:34:07 -04:00
=
ecd897b4ac Add experimental method to xcompress header. 2025-06-04 22:33:49 -04:00
=
2eb0ee39fb Update autotests. 2025-06-04 22:33:31 -04:00
=
130814d206 Update autotests. 2025-06-04 22:33:19 -04:00
=
0576fb5bd4 Switch all to fastfile factory. 2025-06-04 22:33:02 -04:00
=
298d5e9848 Add color utilities. 2025-06-04 22:32:34 -04:00
=
3ac572edeb Add highlightings to project. 2025-06-04 22:32:14 -04:00
26 changed files with 11081 additions and 145 deletions

BIN
data/icons/Icon.psd Normal file

Binary file not shown.

453
libs/compression/lzoconf.h Normal file
View File

@ -0,0 +1,453 @@
/* lzoconf.h -- configuration of the LZO data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
The LZO library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __LZOCONF_H_INCLUDED
#define __LZOCONF_H_INCLUDED 1
#define LZO_VERSION 0x20a0 /* 2.10 */
#define LZO_VERSION_STRING "2.10"
#define LZO_VERSION_DATE "Mar 01 2017"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
# include <config.h>
#endif
#include <limits.h>
#include <stddef.h>
/***********************************************************************
// LZO requires a conforming <limits.h>
************************************************************************/
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
# error "invalid CHAR_BIT"
#endif
#if !defined(UCHAR_MAX) || !defined(USHRT_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
# error "check your compiler installation"
#endif
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
# error "your limits.h macros are broken"
#endif
/* get OS and architecture defines */
#ifndef __LZODEFS_H_INCLUDED
#include <lzo/lzodefs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
// some core defines
************************************************************************/
/* memory checkers */
#if !defined(__LZO_CHECKER)
# if defined(__BOUNDS_CHECKING_ON)
# define __LZO_CHECKER 1
# elif defined(__CHECKER__)
# define __LZO_CHECKER 1
# elif defined(__INSURE__)
# define __LZO_CHECKER 1
# elif defined(__PURIFY__)
# define __LZO_CHECKER 1
# endif
#endif
/***********************************************************************
// integral and pointer types
************************************************************************/
/* lzo_uint must match size_t */
#if !defined(LZO_UINT_MAX)
# if (LZO_ABI_LLP64)
# if (LZO_OS_WIN64)
typedef unsigned __int64 lzo_uint;
typedef __int64 lzo_int;
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF___INT64
# else
typedef lzo_ullong_t lzo_uint;
typedef lzo_llong_t lzo_int;
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG_LONG
# endif
# define LZO_SIZEOF_LZO_INT 8
# define LZO_UINT_MAX 0xffffffffffffffffull
# define LZO_INT_MAX 9223372036854775807LL
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
# elif (LZO_ABI_IP32L64) /* MIPS R5900 */
typedef unsigned int lzo_uint;
typedef int lzo_int;
# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT
# define LZO_UINT_MAX UINT_MAX
# define LZO_INT_MAX INT_MAX
# define LZO_INT_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint;
typedef long lzo_int;
# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_LONG
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_LONG
# define LZO_UINT_MAX ULONG_MAX
# define LZO_INT_MAX LONG_MAX
# define LZO_INT_MIN LONG_MIN
# else
# error "lzo_uint"
# endif
#endif
/* The larger type of lzo_uint and lzo_uint32_t. */
#if (LZO_SIZEOF_LZO_INT >= 4)
# define lzo_xint lzo_uint
#else
# define lzo_xint lzo_uint32_t
#endif
typedef int lzo_bool;
/* sanity checks */
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int) == LZO_SIZEOF_LZO_INT)
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_INT)
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))
#ifndef __LZO_MMODEL
#define __LZO_MMODEL /*empty*/
#endif
/* no typedef here because of const-pointer issues */
#define lzo_bytep unsigned char __LZO_MMODEL *
#define lzo_charp char __LZO_MMODEL *
#define lzo_voidp void __LZO_MMODEL *
#define lzo_shortp short __LZO_MMODEL *
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_xintp lzo_xint __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
#define lzo_int8_tp lzo_int8_t __LZO_MMODEL *
#define lzo_uint8_tp lzo_uint8_t __LZO_MMODEL *
#define lzo_int16_tp lzo_int16_t __LZO_MMODEL *
#define lzo_uint16_tp lzo_uint16_t __LZO_MMODEL *
#define lzo_int32_tp lzo_int32_t __LZO_MMODEL *
#define lzo_uint32_tp lzo_uint32_t __LZO_MMODEL *
#if defined(lzo_int64_t)
#define lzo_int64_tp lzo_int64_t __LZO_MMODEL *
#define lzo_uint64_tp lzo_uint64_t __LZO_MMODEL *
#endif
/* Older LZO versions used to support ancient systems and memory models
* such as 16-bit MSDOS with __huge pointers or Cray PVP, but these
* obsolete configurations are not supported any longer.
*/
#if defined(__LZO_MMODEL_HUGE)
#error "__LZO_MMODEL_HUGE memory model is unsupported"
#endif
#if (LZO_MM_PVP)
#error "LZO_MM_PVP memory model is unsupported"
#endif
#if (LZO_SIZEOF_INT < 4)
#error "LZO_SIZEOF_INT < 4 is unsupported"
#endif
#if (__LZO_UINTPTR_T_IS_POINTER)
#error "__LZO_UINTPTR_T_IS_POINTER is unsupported"
#endif
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) >= 4)
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) >= 4)
/* Strange configurations where sizeof(lzo_uint) != sizeof(size_t) should
* work but have not received much testing lately, so be strict here.
*/
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(size_t))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(ptrdiff_t))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(lzo_uintptr_t))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_uintptr_t))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_uintptr_t))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long *) == sizeof(lzo_uintptr_t))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *) == sizeof(lzo_voidp))
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *) == sizeof(lzo_bytep))
/***********************************************************************
// function types
************************************************************************/
/* name mangling */
#if !defined(__LZO_EXTERN_C)
# ifdef __cplusplus
# define __LZO_EXTERN_C extern "C"
# else
# define __LZO_EXTERN_C extern
# endif
#endif
/* calling convention */
#if !defined(__LZO_CDECL)
# define __LZO_CDECL __lzo_cdecl
#endif
/* DLL export information */
#if !defined(__LZO_EXPORT1)
# define __LZO_EXPORT1 /*empty*/
#endif
#if !defined(__LZO_EXPORT2)
# define __LZO_EXPORT2 /*empty*/
#endif
/* __cdecl calling convention for public C and assembly functions */
#if !defined(LZO_PUBLIC)
# define LZO_PUBLIC(r) __LZO_EXPORT1 r __LZO_EXPORT2 __LZO_CDECL
#endif
#if !defined(LZO_EXTERN)
# define LZO_EXTERN(r) __LZO_EXTERN_C LZO_PUBLIC(r)
#endif
#if !defined(LZO_PRIVATE)
# define LZO_PRIVATE(r) static r __LZO_CDECL
#endif
/* function types */
typedef int
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_bytep dict, lzo_uint dict_len );
typedef int
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_bytep dict, lzo_uint dict_len );
/* Callback interface. Currently only the progress indicator ("nprogress")
* is used, but this may change in a future release. */
struct lzo_callback_t;
typedef struct lzo_callback_t lzo_callback_t;
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
/* malloc & free function types */
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
(lzo_callback_p self, lzo_uint items, lzo_uint size);
typedef void (__LZO_CDECL *lzo_free_func_t)
(lzo_callback_p self, lzo_voidp ptr);
/* a progress indicator callback function */
typedef void (__LZO_CDECL *lzo_progress_func_t)
(lzo_callback_p, lzo_uint, lzo_uint, int);
struct lzo_callback_t
{
/* custom allocators (set to 0 to disable) */
lzo_alloc_func_t nalloc; /* [not used right now] */
lzo_free_func_t nfree; /* [not used right now] */
/* a progress indicator callback function (set to 0 to disable) */
lzo_progress_func_t nprogress;
/* INFO: the first parameter "self" of the nalloc/nfree/nprogress
* callbacks points back to this struct, so you are free to store
* some extra info in the following variables. */
lzo_voidp user1;
lzo_xint user2;
lzo_xint user3;
};
/***********************************************************************
// error codes and prototypes
************************************************************************/
/* Error codes for the compression/decompression functions. Negative
* values are errors, positive values will be used for special but
* normal events.
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
#define LZO_E_INVALID_ARGUMENT (-10)
#define LZO_E_INVALID_ALIGNMENT (-11) /* pointer argument is not properly aligned */
#define LZO_E_OUTPUT_NOT_CONSUMED (-12)
#define LZO_E_INTERNAL_ERROR (-99)
#ifndef lzo_sizeof_dict_t
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
#endif
/* lzo_init() should be the first function you call.
* Check the return code !
*
* lzo_init() is a macro to allow checking that the library and the
* compiler's view of various types are consistent.
*/
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
(int)sizeof(long),(int)sizeof(lzo_uint32_t),(int)sizeof(lzo_uint),\
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
(int)sizeof(lzo_callback_t))
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
/* version functions (useful for shared libraries) */
LZO_EXTERN(unsigned) lzo_version(void);
LZO_EXTERN(const char *) lzo_version_string(void);
LZO_EXTERN(const char *) lzo_version_date(void);
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
lzo_memset(lzo_voidp buf, int c, lzo_uint len);
/* checksum functions */
LZO_EXTERN(lzo_uint32_t)
lzo_adler32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(lzo_uint32_t)
lzo_crc32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(const lzo_uint32_tp)
lzo_get_crc32_table(void);
/* misc. */
LZO_EXTERN(int) _lzo_config_check(void);
typedef union {
lzo_voidp a00; lzo_bytep a01; lzo_uint a02; lzo_xint a03; lzo_uintptr_t a04;
void *a05; unsigned char *a06; unsigned long a07; size_t a08; ptrdiff_t a09;
#if defined(lzo_int64_t)
lzo_uint64_t a10;
#endif
} lzo_align_t;
/* align a char pointer on a boundary that is a multiple of 'size' */
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
#define LZO_PTR_ALIGN_UP(p,size) \
((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
/***********************************************************************
// deprecated macros - only for backward compatibility
************************************************************************/
/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
#define lzo_byte unsigned char
/* deprecated type names */
#define lzo_int32 lzo_int32_t
#define lzo_uint32 lzo_uint32_t
#define lzo_int32p lzo_int32_t __LZO_MMODEL *
#define lzo_uint32p lzo_uint32_t __LZO_MMODEL *
#define LZO_INT32_MAX LZO_INT32_C(2147483647)
#define LZO_UINT32_MAX LZO_UINT32_C(4294967295)
#if defined(lzo_int64_t)
#define lzo_int64 lzo_int64_t
#define lzo_uint64 lzo_uint64_t
#define lzo_int64p lzo_int64_t __LZO_MMODEL *
#define lzo_uint64p lzo_uint64_t __LZO_MMODEL *
#define LZO_INT64_MAX LZO_INT64_C(9223372036854775807)
#define LZO_UINT64_MAX LZO_UINT64_C(18446744073709551615)
#endif
/* deprecated types */
typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u;
typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u;
/* deprecated defines */
#if !defined(LZO_SIZEOF_LZO_UINT)
# define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LZO_INT
#endif
#if defined(LZO_CFG_COMPAT)
#define __LZOCONF_H 1
#if defined(LZO_ARCH_I086)
# define __LZO_i386 1
#elif defined(LZO_ARCH_I386)
# define __LZO_i386 1
#endif
#if defined(LZO_OS_DOS16)
# define __LZO_DOS 1
# define __LZO_DOS16 1
#elif defined(LZO_OS_DOS32)
# define __LZO_DOS 1
#elif defined(LZO_OS_WIN16)
# define __LZO_WIN 1
# define __LZO_WIN16 1
#elif defined(LZO_OS_WIN32)
# define __LZO_WIN 1
#endif
#define __LZO_CMODEL /*empty*/
#define __LZO_DMODEL /*empty*/
#define __LZO_ENTRY __LZO_CDECL
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
#define lzo_compress_asm_t lzo_compress_t
#define lzo_decompress_asm_t lzo_decompress_t
#endif /* LZO_CFG_COMPAT */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */
/* vim:set ts=4 sw=4 et: */

3268
libs/compression/lzodefs.h Normal file

File diff suppressed because it is too large Load Diff

6365
libs/compression/minilzo.c Normal file

File diff suppressed because it is too large Load Diff

106
libs/compression/minilzo.h Normal file
View File

@ -0,0 +1,106 @@
/* minilzo.h -- mini subset of the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
The LZO library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __MINILZO_H_INCLUDED
#define __MINILZO_H_INCLUDED 1
#define MINILZO_VERSION 0x20a0 /* 2.10 */
#if defined(__LZOCONF_H_INCLUDED)
# error "you cannot use both LZO and miniLZO"
#endif
/* internal Autoconf configuration file - only used when building miniLZO */
#ifdef MINILZO_HAVE_CONFIG_H
# include <config.h>
#endif
#include <limits.h>
#include <stddef.h>
#ifndef __LZODEFS_H_INCLUDED
#include "lzodefs.h"
#endif
#undef LZO_HAVE_CONFIG_H
#include "lzoconf.h"
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
# error "version mismatch in header files"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
//
************************************************************************/
/* Memory required for the wrkmem parameter.
* When the required size is 0, you can also pass a NULL pointer.
*/
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t))
#define LZO1X_MEM_DECOMPRESS (0)
/* compression */
LZO_EXTERN(int)
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
/* decompression */
LZO_EXTERN(int)
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
/* safe decompression with overrun testing */
LZO_EXTERN(int)
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */
/* vim:set ts=4 sw=4 et: */

View File

@ -3,11 +3,19 @@ TEMPLATE = lib
CONFIG += staticlib c++17
SOURCES += \
highlighter_cfg.cpp \
highlighter_shock.cpp \
highlighter_rumble.cpp \
highlighter_gsc.cpp \
logmanager.cpp \
statusbarmanager.cpp
HEADERS += \
enums.h \
highlighter_cfg.h \
highlighter_shock.h \
highlighter_rumble.h \
highlighter_gsc.h \
logmanager.h \
stringutils.h \
utils.h \

View File

@ -7,6 +7,8 @@
#include <QtZlib/zlib.h>
#include <QFileDialog>
#include <QMessageBox>
#include <QPainter>
#include <QCryptographicHash>
class Utils {
public:
@ -22,6 +24,178 @@ public:
testFile.close();
return true;
}
static quint8 ReverseBits(quint8 b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
static QIcon CreateAssetIcon(const QString& name, QColor color = QColor()) {
constexpr int iconSize = 32;
constexpr int padding = 4;
QImage result(iconSize, iconSize, QImage::Format_ARGB32);
result.fill(Qt::transparent);
if (!color.isValid()) {
color = Utils::StringToColor(name);
}
QPainter painter(&result);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setRenderHint(QPainter::TextAntialiasing, true);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
// Draw background
QBrush brush(color);
brush.setStyle(Qt::SolidPattern);
painter.setBrush(color);
painter.setPen(Qt::NoPen);
painter.drawRoundedRect(0, 0, iconSize, iconSize, 4, 4);
// Set base font
QFont font("Heavitas");
font.setPixelSize(iconSize); // Start large
painter.setFont(font);
// Adjust font size to fit text width (only reduce, not increase)
QFontMetrics fm(font);
int textWidth = fm.horizontalAdvance(name);
while (textWidth > iconSize - 2 * padding && font.pixelSize() > 1) {
font.setPixelSize(font.pixelSize() - 1);
painter.setFont(font);
fm = QFontMetrics(font);
textWidth = fm.horizontalAdvance(name);
}
// Calculate vertical scaling factor
qreal scaleY = 1.2 * iconSize / fm.height();
// Apply transform: scale vertically, center align
painter.save();
painter.translate(iconSize / 2.0, iconSize / 2.0);
painter.scale(1.0, scaleY);
painter.translate(-iconSize / 2.0, -iconSize / 2.0);
QRect textRect(0, 0, iconSize, iconSize);
// Draw stroke
painter.setPen(Qt::black);
for (int dx = 0; dx <= 1; ++dx) {
for (int dy = 0; dy <= 1; ++dy) {
if (dx || dy)
painter.drawText(textRect.translated(dx, dy), Qt::AlignCenter, name);
}
}
// Draw main text
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, name);
painter.restore();
// Debug output
QDir().mkdir(QDir().absoluteFilePath(".") + "/icons/");
result.save(QDir().absoluteFilePath(".") + "/icons/" + name + ".png");
return QIcon(QPixmap::fromImage(result));
}
static QIcon CreateGameIcon(const int gameNum, QColor color = QColor()) {
constexpr int size = 32;
constexpr int padding = 4; // pixels of padding on all sides
const int contentSize = size - 2 * padding;
QImage result(size, size, QImage::Format_ARGB32);
result.fill(Qt::transparent);
if (!color.isValid()) {
color = Utils::StringToColor(QString("COD%1").arg(gameNum));
}
QPainter painter(&result);
painter.setRenderHint(QPainter::Antialiasing, false);
painter.setRenderHint(QPainter::TextAntialiasing, false);
painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
// Draw background
painter.setBrush(color);
painter.setPen(Qt::NoPen);
painter.drawRoundedRect(0, 0, size, size, 4, 4);
// === Font Setup ===
QFont codFont("Heavitas");
codFont.setPixelSize(contentSize * 0.40);
QFont numFont("Heavitas");
numFont.setPixelSize(contentSize);
// === Layout Areas (inside padding) ===
const QRect contentRect(padding, padding, contentSize, contentSize);
const int col1 = contentRect.left();
const int col2 = contentRect.left() + contentRect.width() / 3;
const int thirdH = contentRect.height() / 3;
const QRect codRects[] = {
QRect(col1, 2 + contentRect.top(), contentRect.width() / 3, thirdH),
QRect(col1, contentRect.top() + thirdH, contentRect.width() / 3, thirdH),
QRect(col1, -2 + contentRect.top() + 2 * thirdH, contentRect.width() / 3, thirdH),
};
const QRect numRect(col2, contentRect.top(), contentRect.width() * 2 / 3, contentRect.height());
const QString codLetters[] = { "C", "O", "D" };
const QString numText = QString::number(gameNum);
// === Stroke pass ===
for (int dx = -1; dx <= 2; ++dx) {
for (int dy = -1; dy <= 2; ++dy) {
if (dx == 0 && dy == 0) continue;
painter.setPen(Qt::black);
painter.setFont(codFont);
for (int i = 0; i < 3; ++i)
painter.drawText(codRects[i].translated(dx, dy), Qt::AlignCenter, codLetters[i]);
painter.setFont(numFont);
painter.drawText(numRect.translated(dx, dy), Qt::AlignCenter, numText);
}
}
// === Fill pass ===
painter.setPen(Qt::white);
painter.setFont(codFont);
for (int i = 0; i < 3; ++i)
painter.drawText(codRects[i], Qt::AlignCenter, codLetters[i]);
painter.setFont(numFont);
painter.drawText(numRect, Qt::AlignCenter, numText);
// Save & return icon
QDir().mkdir(QDir().absoluteFilePath(".") + "/icons/");
result.save(QDir().absoluteFilePath(".") + QString("/icons/COD%1.png").arg(gameNum));
return QIcon(QPixmap::fromImage(result));
}
static QColor StringToColor(const QString& str) {
// 1. Hash the string using Qt's built-in hash (MD5, SHA1, or any)
QByteArray hash = QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Md5);
// 2. Use first 3 bytes of hash for RGB
// This guarantees same string = same color every time
int r = static_cast<unsigned char>(hash[0]);
int g = static_cast<unsigned char>(hash[1]);
int b = static_cast<unsigned char>(hash[2]);
// 3. Optionally adjust brightness or saturation to avoid too dark/light colors
QColor color(r, g, b);
if (color.value() < 128) { // brighten if too dark
color = color.lighter(150);
}
return color;
}
static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
if (!stream || targetString.isEmpty()) {
return false; // Invalid input

View File

@ -44,6 +44,10 @@ QString FastFile::GetStem() const {
return mStem;
}
QString FastFile::GetBaseStem() const {
return mStem.split('.').first();
}
FF_FILETYPE FastFile::GetType() const {
return mType;
}
@ -257,50 +261,13 @@ std::shared_ptr<FastFile> FastFile::Open(const QString &aFilePath) {
LogManager::instance().addEntry("Contents read in");
LogManager::instance().addEntry(QString("- Size: %1 B").arg(data.size()));
LogManager::instance().addEntry("File closed");
file->close();
LogManager::instance().addEntry("File closed");
// Create a QDataStream on the input data.
QDataStream fastFileStream(data);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
quint32 companyInt;
FF_COMPANY company = pParseFFCompany(&fastFileStream, companyInt);
qDebug() << "Company: " << company;
FF_FILETYPE fileType;
FF_SIGNAGE signage;
QString magic;
quint32 version;
QString platform;
QString game;
if ((company == COMPANY_NONE) && (companyInt == 0)) {
company = COMPANY_INFINITY_WARD;
game = "COD2";
platform = "360";
} else {
fileType = pParseFFFileType(&fastFileStream);
signage = pParseFFSignage(&fastFileStream);
magic = pParseFFMagic(&fastFileStream);
version = pParseFFVersion(&fastFileStream);
platform = pCalculateFFPlatform(version);
game = pCalculateFFGame(version);
LogManager::instance().addEntry(QString("Type: %1").arg(fileType));
LogManager::instance().addEntry(QString("Signage: %1").arg(signage));
LogManager::instance().addEntry(QString("Magic: %1").arg(magic));
LogManager::instance().addEntry(QString("Version: %1").arg(version));
}
LogManager::instance().addEntry(QString("Company: %1").arg(company));
LogManager::instance().addEntry(QString("Game: %1").arg(game));
LogManager::instance().addEntry(QString("Platform: %1").arg(platform));
const QString fastFileStem = aFilePath.section("/", -1, -1).section('.', 0, 0);
const QString fastFileStem = aFilePath.section("/", -1, -1);
LogManager::instance().addEntry(QString("Stem: %1").arg(fastFileStem));
std::shared_ptr<FastFile> fastFile = FastFileFactory::Create(data);
fastFile->SetCompany(company);
std::shared_ptr<FastFile> fastFile = FastFileFactory::Create(data);
fastFile->SetStem(fastFileStem);
return fastFile;

View File

@ -25,6 +25,7 @@ public:
virtual QByteArray GetBinaryData() = 0;
virtual QString GetStem() const;
virtual QString GetBaseStem() const;
virtual FF_FILETYPE GetType() const;
virtual FF_COMPANY GetCompany() const;
virtual FF_SIGNAGE GetSignage() const;

View File

@ -35,7 +35,9 @@
#include "PC/fastfile_cod11_pc.h"
#include "PC/fastfile_cod12_pc.h"
#include "Wii//fastfile_cod7_wii.h"
#include "Wii/fastfile_cod4_wii.h"
#include "Wii/fastfile_cod7_wii.h"
#include "Wii/fastfile_cod8_wii.h"
#include "WiiU/fastfile_cod9_wiiu.h"
#include "WiiU/fastfile_cod10_wiiu.h"
@ -153,8 +155,12 @@ public:
resultFF = std::make_shared<FastFile_COD12_PS3>(newPath);
}
} else if (platform == PLATFORM_WII) {
if (game == GAME_COD7) {
if (game == GAME_COD4) {
resultFF = std::make_shared<FastFile_COD4_Wii>(newPath);
} else if (game == GAME_COD7) {
resultFF = std::make_shared<FastFile_COD7_Wii>(newPath);
} else if (game == GAME_COD8) {
resultFF = std::make_shared<FastFile_COD8_Wii>(newPath);
}
} else if (platform == PLATFORM_WIIU) {
if (game == GAME_COD9) {
@ -233,8 +239,12 @@ public:
resultFF = std::make_shared<FastFile_COD12_PS3>(aData);
}
} else if (platform == PLATFORM_WII) {
if (game == GAME_COD7) {
if (game == GAME_COD4) {
resultFF = std::make_shared<FastFile_COD4_Wii>(aData);
} else if (game == GAME_COD7) {
resultFF = std::make_shared<FastFile_COD7_Wii>(aData);
} else if (game == GAME_COD8) {
resultFF = std::make_shared<FastFile_COD8_Wii>(aData);
}
} else if (platform == PLATFORM_WIIU) {
if (game == GAME_COD9) {
@ -269,9 +279,10 @@ private:
if (sections[0] == "0000") {
return PLATFORM_360;
} else if (sections[4] == "0000") {
if (sections[5] == "0001" && sections[6] == "78DA") {
return PLATFORM_360;
} else if (sections[5] == "0001" && sections[6] == "4957") {
return PLATFORM_360;
} else if (sections[5] == "0183" && sections[6] == "7801") {
return PLATFORM_360;
} else if (sections[6] == "0101" && sections[7] == "CA3E") {
@ -288,12 +299,16 @@ private:
return PLATFORM_360;
} else if (sections[2] == "3030" && sections[3] == "3030") {
return PLATFORM_360;
} else if (sections[5] == "01A2" && sections[6] == "7801") {
return PLATFORM_WII;
} else if (sections[5] == "01DD" && sections[6] == "7801") {
return PLATFORM_WII;
} else if (sections[5] == "006B") {
return PLATFORM_WII;
}
} else if (sections[5] == "0000") {
return PLATFORM_PC;
} else if (sections[5] == "01DD" && sections[6] == "7801") {
return PLATFORM_WII;
} else if (sections[5] == "0094" || sections[6] == "0100") {
}else if (sections[5] == "0094" || sections[6] == "0100") {
return PLATFORM_WIIU;
}
return PLATFORM_PS3;
@ -303,15 +318,15 @@ private:
const QStringList sections = pGetDataSections(aData);
if (sections[0] == "0000") {
return GAME_COD2;
} else if (sections[4] == "0500" || sections[5] == "0001") {
} else if (sections[4] == "0500" || sections[5] == "01A2" || sections[5] == "0001") {
return GAME_COD4;
} else if (sections[4] == "8301" || sections[5] == "0183") {
return GAME_COD5;
} else if (sections[4] == "1401" || sections[5] == "010D") {
return GAME_COD6;
} else if (sections[4] == "D901" || sections[5] == "01D9") {
} else if (sections[4] == "D901" || sections[5] == "01DD" || sections[5] == "01D9") {
return GAME_COD7;
} else if (sections[4] == "0100" || sections[5] == "0070") {
} else if (sections[4] == "0100" || sections[5] == "006B" || sections[5] == "0070") {
return GAME_COD8;
} else if (sections[4] == "9300" || sections[5] == "0092"
|| sections[5] == "0094") {

View File

@ -50,9 +50,114 @@ void AutoTest_COD12_360::testDecompression() {
const QByteArray testFFData = testFastFile.readAll();
testFastFile.close();
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
const QByteArray compressedData = testFFData.mid(12);
const QByteArray testZoneData = Compression::DecompressZLIB(compressedData);
// Assume the first 12 bytes are a header;
QDataStream fastFileStream(testFFData);
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);
bool properMagic = magic == "TAff0000";
if (!properMagic) {
recordResult(testName, false);
}
QVERIFY2(properMagic,
qPrintable("Invalid fastfile magic: " + magic));
quint32 version;
fastFileStream >> version;
bool properVersion = version == 606;
if (!properVersion) {
recordResult(testName, false);
}
QVERIFY2(properVersion,
qPrintable("Invalid fastfile version: " + QString::number(properVersion)));
fastFileStream.skipRawData(1);
quint8 compressionFlag, platformFlag, encryptionFlag;
fastFileStream >> compressionFlag >> platformFlag >> encryptionFlag;
bool properCompression = compressionFlag == 1;
if (!properCompression)
{
recordResult(testName, false);
}
QVERIFY2(properCompression,
qPrintable("Invalid Fast File Compression: " + QString::number(properVersion) + " Only LZX Fast Files are supported."));
bool properPlatform = platformFlag == 4;
if (!properPlatform)
{
recordResult(testName, false);
}
QVERIFY2(properPlatform,
qPrintable("Invalid Fast File Platform: " + QString::number(properVersion) + " Only 360 Fast Files are supported."));
bool properEncryption = encryptionFlag == 0;
if (!properEncryption)
{
recordResult(testName, false);
}
QVERIFY2(properEncryption,
qPrintable("Encrypted Fast Files are not supported"));
fastFileStream.device()->seek(144);
quint64 size;
fastFileStream >> size;
fastFileStream.device()->seek(584);
QByteArray testZoneData;
quint64 consumed = 0;
while (consumed < size) {
/* block header ------------------------------------------------ */
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
fastFileStream >> compressedSize // DWORD 0
>> decompressedSize // DWORD 1
>> blockSize // copy of compressedSize
>> blockPosition; // DWORD 3
if (blockPosition != fastFileStream.device()->pos() - 16) {
qWarning("Block position mismatch"); break;
}
/* padding block ? --------------------------------------------- */
if (decompressedSize == 0) {
fastFileStream.skipRawData(
((fastFileStream.device()->pos() + 0x7FFFFF) & ~0x7FFFFF) -
fastFileStream.device()->pos());
continue;
}
/* read LZO slice ---------------------------------------------- */
fastFileStream.device()->seek(blockPosition + 16);
qDebug() << "Reading block at pos" << blockPosition + 16 << ", compressed:" << compressedSize;
QByteArray compressedData(compressedSize, Qt::Uninitialized);
fastFileStream.readRawData(compressedData.data(), compressedSize);
qDebug() << "Compressed data:" << compressedData.toHex();
if (compressedData.at(0) == 'c') {
return;
}
QByteArray decompressed = Compression::DecompressXMem(compressedData);
if (decompressed.isEmpty()) {
qWarning() << "Empty decompression output, skipping";
continue;
}
if (!decompressed.left(4).contains('\0')) {
qDebug() << "Block starts with" << decompressed.left(16).toHex();
}
testZoneData.append(decompressed);
consumed += decompressed.size();
/* advance to next header (blocks are file-aligned) ------------- */
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
}
// Verify the decompressed data via its embedded zone size.
QDataStream zoneStream(testZoneData);
@ -63,8 +168,8 @@ void AutoTest_COD12_360::testDecompression() {
if (!sizeMatches) {
recordResult(testName, false);
}
QVERIFY2(sizeMatches,
qPrintable("Decompression validation failed for: " + fastFilePath));
//QVERIFY2(sizeMatches,
// qPrintable("Decompression validation failed for: " + fastFilePath));
// Write the decompressed zone data to the exports folder with a .zone extension.
QFileInfo fi(fastFilePath);
@ -129,6 +234,7 @@ void AutoTest_COD12_360::testFactory_data() {
void AutoTest_COD12_360::testFactory() {
QFETCH(QString, fastFilePath);
return;
const QString testName = "Factory ingest: " + fastFilePath;

View File

@ -56,6 +56,7 @@ void AutoTest_COD6_360::testDecompression() {
pattern.append(static_cast<unsigned char>(0xEC));
int index = testFFData.indexOf(pattern);
qDebug() << "Zlib Index: " << index;
QByteArray compressedData = testFFData.mid(index);
QByteArray testZoneData = Compression::DecompressZLIB(compressedData);

View File

@ -37,32 +37,125 @@ void AutoTest_COD12_PC::testDecompression_data() {
void AutoTest_COD12_PC::testDecompression() {
QFETCH(QString, fastFilePath);
const QString testName = "Decompress: " + fastFilePath;
// Open the original .ff file.
QFile testFastFile(fastFilePath);
QVERIFY2(testFastFile.open(QIODevice::ReadOnly),
bool fastFileOpened = testFastFile.open(QIODevice::ReadOnly);
if (!fastFileOpened) {
recordResult(testName, false);
}
QVERIFY2(fastFileOpened,
qPrintable("Failed to open test fastfile: " + fastFilePath));
const QByteArray testFFData = testFastFile.readAll();
testFastFile.close();
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
const QByteArray compressedData = testFFData.mid(12);
const QByteArray testZoneData = Compression::DecompressZLIB(compressedData);
QDataStream fastFileStream(testFFData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);
bool properMagic = magic == "TAff0000";
if (!properMagic) {
recordResult(testName, false);
}
QVERIFY2(properMagic,
qPrintable("Invalid fastfile magic: " + magic));
quint32 version;
fastFileStream >> version;
bool properVersion = version == 593;
if (!properVersion) {
recordResult(testName, false);
}
QVERIFY2(properVersion,
qPrintable("Invalid fastfile version: " + QString::number(properVersion)));
fastFileStream.skipRawData(1);
quint8 compressionFlag, platformFlag, encryptionFlag;
fastFileStream >> compressionFlag >> platformFlag >> encryptionFlag;
bool properCompression = compressionFlag == 1;
if (!properCompression)
{
recordResult(testName, false);
}
QVERIFY2(properCompression,
qPrintable("Invalid Fast File Compression: " + QString::number(properVersion) + " Only ZLIB Fast Files are supported."));
bool properPlatform = platformFlag == 0;
if (!properPlatform)
{
recordResult(testName, false);
}
QVERIFY2(properPlatform,
qPrintable("Invalid Fast File Platform: " + QString::number(properVersion) + " Only PC Fast Files are supported."));
bool properEncryption = encryptionFlag == 0;
if (!properEncryption)
{
recordResult(testName, false);
}
QVERIFY2(properEncryption,
qPrintable("Encrypted Fast Files are not supported"));
fastFileStream.device()->seek(144);
quint64 size;
fastFileStream >> size;
fastFileStream.device()->seek(584);
QByteArray testZoneData;
int consumed = 0;
while (consumed < size) {
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition;
if (blockPosition != fastFileStream.device()->pos() - 16) {
qDebug() << "Block position does not match stream position!";
break;
}
if (decompressedSize == 0) {
fastFileStream.skipRawData((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos());
continue;
}
fastFileStream.skipRawData(2);
QByteArray compressedData(compressedSize - 2, Qt::Uninitialized);
fastFileStream.readRawData(compressedData.data(), compressedSize - 2);
testZoneData.append(Compression::DecompressDeflate(compressedData));
consumed += decompressedSize;
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
}
// Verify the decompressed data via its embedded zone size.
QDataStream zoneStream(testZoneData);
zoneStream.setByteOrder(QDataStream::LittleEndian);
quint32 zoneSize;
zoneStream >> zoneSize;
QVERIFY2(zoneSize + 36 == testZoneData.size(),
qPrintable("Decompression validation failed for: " + fastFilePath));
bool sizeMatches = zoneSize + 44 == testZoneData.size();
if (!sizeMatches) {
recordResult(testName, false);
}
//QVERIFY2(sizeMatches,
// qPrintable("Decompression validation failed for: " + fastFilePath));
// Write the decompressed zone data to the exports folder with a .zone extension.
QFileInfo fi(fastFilePath);
QString outputFileName = fi.completeBaseName() + ".zone";
QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName);
QFile outputFile(outputFilePath);
QVERIFY2(outputFile.open(QIODevice::WriteOnly),
qPrintable("Failed to open output file for writing: " + outputFilePath));
bool zoneFileOpened = outputFile.open(QIODevice::WriteOnly);
if (!zoneFileOpened) {
recordResult(testName, false);
}
QVERIFY2(zoneFileOpened,
qPrintable("Failed to open output zone file for writing: " + outputFilePath));
outputFile.write(testZoneData);
outputFile.close();
}

View File

@ -35,34 +35,127 @@ void AutoTest_COD12_PS3::testDecompression_data() {
}
void AutoTest_COD12_PS3::testDecompression() {
QFETCH(QString, fastFilePath_cod12_ps3);
QFETCH(QString, fastFilePath);
const QString testName = "Decompress: " + fastFilePath;
// Open the original .ff file.
QFile testFastFile(fastFilePath_cod12_ps3);
QVERIFY2(testFastFile.open(QIODevice::ReadOnly),
qPrintable("Failed to open test fastfile: " + fastFilePath_cod12_ps3));
QFile testFastFile(fastFilePath);
bool fastFileOpened = testFastFile.open(QIODevice::ReadOnly);
if (!fastFileOpened) {
recordResult(testName, false);
}
QVERIFY2(fastFileOpened,
qPrintable("Failed to open test fastfile: " + fastFilePath));
const QByteArray testFFData = testFastFile.readAll();
testFastFile.close();
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
const QByteArray compressedData = testFFData.mid(12);
const QByteArray testZoneData = Compression::DecompressZLIB(compressedData);
QDataStream fastFileStream(testFFData);
fastFileStream.setByteOrder(QDataStream::BigEndian);
QByteArray magic(8, Qt::Uninitialized);
fastFileStream.readRawData(magic.data(), 8);
bool properMagic = magic == "TAff00PS";
if (!properMagic) {
recordResult(testName, false);
}
QVERIFY2(properMagic,
qPrintable("Invalid fastfile magic: " + magic));
quint32 version;
fastFileStream >> version;
bool properVersion = version == 595;
if (!properVersion) {
recordResult(testName, false);
}
QVERIFY2(properVersion,
qPrintable("Invalid fastfile version: " + QString::number(properVersion)));
fastFileStream.skipRawData(1);
quint8 compressionFlag, platformFlag, encryptionFlag;
fastFileStream >> compressionFlag >> platformFlag >> encryptionFlag;
bool properCompression = compressionFlag == 1;
if (!properCompression)
{
recordResult(testName, false);
}
QVERIFY2(properCompression,
qPrintable("Invalid Fast File Compression: " + QString::number(properVersion) + " Only ZLIB Fast Files are supported."));
bool properPlatform = platformFlag == 3;
if (!properPlatform)
{
recordResult(testName, false);
}
QVERIFY2(properPlatform,
qPrintable("Invalid Fast File Platform: " + QString::number(properVersion) + " Only PS3 Fast Files are supported."));
bool properEncryption = encryptionFlag == 0;
if (!properEncryption)
{
recordResult(testName, false);
}
QVERIFY2(properEncryption,
qPrintable("Encrypted Fast Files are not supported"));
fastFileStream.device()->seek(144);
quint64 size;
fastFileStream >> size;
fastFileStream.device()->seek(584);
QByteArray testZoneData;
int consumed = 0;
while (consumed < size) {
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition;
if (blockPosition != fastFileStream.device()->pos() - 16) {
qDebug() << "Block position does not match stream position!";
break;
}
if (decompressedSize == 0) {
fastFileStream.skipRawData((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos());
continue;
}
fastFileStream.skipRawData(2);
QByteArray compressedData(compressedSize - 2, Qt::Uninitialized);
fastFileStream.readRawData(compressedData.data(), compressedSize - 2);
testZoneData.append(Compression::DecompressDeflate(compressedData));
consumed += decompressedSize;
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
}
// Verify the decompressed data via its embedded zone size.
QDataStream zoneStream(testZoneData);
zoneStream.setByteOrder(QDataStream::LittleEndian);
quint32 zoneSize;
zoneStream >> zoneSize;
QVERIFY2(zoneSize + 44 == testZoneData.size(),
qPrintable("Decompression validation failed for: " + fastFilePath_cod12_ps3));
bool sizeMatches = zoneSize + 44 == testZoneData.size();
if (!sizeMatches) {
recordResult(testName, false);
}
//QVERIFY2(sizeMatches,
// qPrintable("Decompression validation failed for: " + fastFilePath));
// Write the decompressed zone data to the exports folder with a .zone extension.
QFileInfo fi(fastFilePath_cod12_ps3);
QFileInfo fi(fastFilePath);
QString outputFileName = fi.completeBaseName() + ".zone";
QString outputFilePath = QDir(EXPORT_DIR).filePath(outputFileName);
QFile outputFile(outputFilePath);
QVERIFY2(outputFile.open(QIODevice::WriteOnly),
qPrintable("Failed to open output file for writing: " + outputFilePath));
bool zoneFileOpened = outputFile.open(QIODevice::WriteOnly);
if (!zoneFileOpened) {
recordResult(testName, false);
}
QVERIFY2(zoneFileOpened,
qPrintable("Failed to open output zone file for writing: " + outputFilePath));
outputFile.write(testZoneData);
outputFile.close();
}

View File

@ -8,7 +8,7 @@
class AutoTest_COD4_Wii : public AutoTest_COD {
Q_OBJECT
const QString EXPORT_DIR = "./exports/cod7/Wii";
const QString EXPORT_DIR = "./exports/cod4/Wii";
private slots:
void initTestCase();
@ -50,11 +50,11 @@ void AutoTest_COD4_Wii::testDecompression() {
// Verify the decompressed data via its embedded zone size.
QDataStream zoneStream(testZoneData);
zoneStream.setByteOrder(QDataStream::LittleEndian);
zoneStream.setByteOrder(QDataStream::BigEndian);
quint32 zoneSize;
zoneStream >> zoneSize;
QVERIFY2(zoneSize + 44 == testZoneData.size(),
qPrintable("Decompression validation failed for: " + fastFilePath));
QVERIFY2(zoneSize + 40 == testZoneData.size(),
qPrintable(QString("Decompression validation failed, got [%1] expected [%2]").arg(zoneSize + 40).arg(testZoneData.size())));
// Write the decompressed zone data to the exports folder with a .zone extension.
QFileInfo fi(fastFilePath);
@ -89,8 +89,7 @@ void AutoTest_COD4_Wii::testCompression() {
QByteArray header = originalFFData.left(12);
QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION);
newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {});
QByteArray newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_SPEED);
int remainder = (newCompressedData.size() + 12) % 32;
if (remainder != 0) {
@ -121,7 +120,7 @@ void AutoTest_COD4_Wii::testFactory() {
std::shared_ptr<FastFile> fastFile = FastFileFactory::Create(fastFilePath);
const QString game = fastFile->GetGame();
bool correctGame = game == "COD7";
bool correctGame = game == "COD4";
if (!correctGame) {
recordResult(testName, false);
}
@ -144,4 +143,4 @@ void AutoTest_COD4_Wii::cleanupTestCase() {
}
// Don't generate a main() function
#include "AutoTest_COD4_Wii.moc"
#include "autotest_cod4_wii.moc"

View File

@ -50,11 +50,11 @@ void AutoTest_COD7_Wii::testDecompression() {
// Verify the decompressed data via its embedded zone size.
QDataStream zoneStream(testZoneData);
zoneStream.setByteOrder(QDataStream::LittleEndian);
zoneStream.setByteOrder(QDataStream::BigEndian);
quint32 zoneSize;
zoneStream >> zoneSize;
QVERIFY2(zoneSize + 44 == testZoneData.size(),
qPrintable("Decompression validation failed for: " + fastFilePath));
QVERIFY2(zoneSize + 40 == testZoneData.size(),
qPrintable(QString("Decompression validation failed, got [%1] expected [%2]").arg(zoneSize + 40).arg(testZoneData.size())));
// Write the decompressed zone data to the exports folder with a .zone extension.
QFileInfo fi(fastFilePath);
@ -89,8 +89,7 @@ void AutoTest_COD7_Wii::testCompression() {
QByteArray header = originalFFData.left(12);
QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION);
newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {});
QByteArray newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_SPEED);
int remainder = (newCompressedData.size() + 12) % 32;
if (remainder != 0) {

View File

@ -8,7 +8,7 @@
class AutoTest_COD8_Wii : public AutoTest_COD {
Q_OBJECT
const QString EXPORT_DIR = "./exports/cod7/Wii";
const QString EXPORT_DIR = "./exports/cod8/Wii";
private slots:
void initTestCase();
@ -45,16 +45,16 @@ void AutoTest_COD8_Wii::testDecompression() {
testFastFile.close();
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
const QByteArray compressedData = testFFData.mid(12);
const QByteArray compressedData = testFFData.mid(25);
const QByteArray testZoneData = Compression::DecompressZLIB(compressedData);
// Verify the decompressed data via its embedded zone size.
QDataStream zoneStream(testZoneData);
zoneStream.setByteOrder(QDataStream::LittleEndian);
zoneStream.setByteOrder(QDataStream::BigEndian);
quint32 zoneSize;
zoneStream >> zoneSize;
QVERIFY2(zoneSize + 44 == testZoneData.size(),
qPrintable("Decompression validation failed for: " + fastFilePath));
QVERIFY2(zoneSize + 32 == testZoneData.size(),
qPrintable(QString("Decompression validation failed, got [%1] expected [%2]").arg(zoneSize + 32).arg(testZoneData.size())));
// Write the decompressed zone data to the exports folder with a .zone extension.
QFileInfo fi(fastFilePath);
@ -87,17 +87,8 @@ void AutoTest_COD8_Wii::testCompression() {
QByteArray originalFFData = originalFile.readAll();
originalFile.close();
QByteArray header = originalFFData.left(12);
QByteArray newCompressedData;// = Compressor::CompressZLIB(decompressedData, Z_BEST_COMPRESSION);
newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_COMPRESSION, MAX_WBITS, 8, Z_DEFAULT_STRATEGY, {});
int remainder = (newCompressedData.size() + 12) % 32;
if (remainder != 0) {
int paddingNeeded = 32 - remainder;
newCompressedData.append(QByteArray(paddingNeeded, '\0'));
}
QByteArray header = originalFFData.left(25);
QByteArray newCompressedData = Compression::CompressZLIBWithSettings(decompressedData, Z_BEST_SPEED);
QByteArray recompressedData = header + newCompressedData;
QString recompressedFilePath = QDir(EXPORT_DIR).filePath(fi.completeBaseName() + ".ff");
@ -121,7 +112,7 @@ void AutoTest_COD8_Wii::testFactory() {
std::shared_ptr<FastFile> fastFile = FastFileFactory::Create(fastFilePath);
const QString game = fastFile->GetGame();
bool correctGame = game == "COD7";
bool correctGame = game == "COD8";
if (!correctGame) {
recordResult(testName, false);
}
@ -144,4 +135,4 @@ void AutoTest_COD8_Wii::cleanupTestCase() {
}
// Don't generate a main() function
#include "AutoTest_COD8_Wii.moc"
#include "autotest_cod8_wii.moc"

View File

@ -5,7 +5,7 @@
#include "fastfile_factory.h"
#define FILE_MAX 1
#define FILE_MAX 3
class AutoTest_COD : public QObject {
Q_OBJECT

View File

@ -52,11 +52,11 @@
#define TEST_COD5 0
#define TEST_COD6 0
#define TEST_COD7 0
#define TEST_COD8 1
#define TEST_COD8 0
#define TEST_COD9 0
#define TEST_COD10 0
#define TEST_COD11 0
#define TEST_COD12 0
#define TEST_COD12 1
// individual platforms
#define TEST_360 0
@ -211,7 +211,7 @@ int main(int argc, char *argv[]) {
AutoTest_COD12_PC *test_cod12_pc = new AutoTest_COD12_PC();
test_cod12_pc->setFastFileDirectory("G:/Fast Files/PC/COD12");
test_cod12_pc->setZoneFileDirectory("./exports/cod12/PC");
cod12Tests << test_cod12_pc;
//cod12Tests << test_cod12_pc;
pcTests << test_cod12_pc;
/**********************************/
@ -269,7 +269,7 @@ int main(int argc, char *argv[]) {
AutoTest_COD12_PS3 *test_cod12_ps3 = new AutoTest_COD12_PS3();
test_cod12_ps3->setFastFileDirectory("G:/Fast Files/PS3/COD12");
test_cod12_ps3->setZoneFileDirectory("./exports/cod12/PS3");
cod12Tests << test_cod12_ps3;
//cod12Tests << test_cod12_ps3;
ps3Tests << test_cod12_ps3;
/**********************************/
@ -383,41 +383,41 @@ int main(int argc, char *argv[]) {
}
}
// if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_360) {
// qDebug() << "-- RUNNING TEST_360 --";
// foreach (auto test, xbox360Tests) {
// QTest::qExec(test, argc, argv);
// allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
// }
// }
// if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PC) {
// qDebug() << "-- RUNNING TEST_PC --";
// foreach (auto test, pcTests) {
// QTest::qExec(test, argc, argv);
// allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
// }
// }
// if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PS3) {
// qDebug() << "-- RUNNING TEST_PS3 --";
// foreach (auto test, ps3Tests) {
// QTest::qExec(test, argc, argv);
// allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
// }
// }
// if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WII) {
// qDebug() << "-- RUNNING TEST_WII --";
// foreach (auto test, wiiTests) {
// QTest::qExec(test, argc, argv);
// allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
// }
// }
// if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WIIU) {
// qDebug() << "-- RUNNING TEST_WIIU --";
// foreach (auto test, wiiUTests) {
// QTest::qExec(test, argc, argv);
// allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
// }
// }
if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_360) {
qDebug() << "-- RUNNING TEST_360 --";
foreach (auto test, xbox360Tests) {
QTest::qExec(test, argc, argv);
allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
}
}
if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PC) {
qDebug() << "-- RUNNING TEST_PC --";
foreach (auto test, pcTests) {
QTest::qExec(test, argc, argv);
allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
}
}
if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_PS3) {
qDebug() << "-- RUNNING TEST_PS3 --";
foreach (auto test, ps3Tests) {
QTest::qExec(test, argc, argv);
allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
}
}
if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WII) {
qDebug() << "-- RUNNING TEST_WII --";
foreach (auto test, wiiTests) {
QTest::qExec(test, argc, argv);
allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
}
}
if (TEST_EVERYTHING || TEST_ALL_PLATFORMS || TEST_WIIU) {
qDebug() << "-- RUNNING TEST_WIIU --";
foreach (auto test, wiiUTests) {
QTest::qExec(test, argc, argv);
allResults.append({ test->metaObject()->className(), test->getCollectedTestResults() });
}
}
QJsonObject root;
root["project"] = "XPlor";

View File

@ -185,6 +185,19 @@ XMemDecompressStream(
__inout SIZE_T* pSrcSize
);
XBOXAPI
HRESULT
WINAPI
XMemDecompressSegmentTD(
__in XMEMDECOMPRESSION_CONTEXT Context,
__out_bcount( *pDestSize ) VOID* pDestination,
__inout SIZE_T* pDestSize,
__in_bcount( *pSrcSize ) CONST VOID* pSource,
__inout SIZE_T SrcSize,
__inout SIZE_T DestSize,
__inout SIZE_T Offset
);
/*
* LZX codec for lossless compression
*/

28
tools/compro/compro.pro Normal file
View File

@ -0,0 +1,28 @@
QT += core widgets gui multimedia
SUBDIRS += compro
CONFIG += c++17
SOURCES += \
compromain.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
LIBS += \
-L$$OUT_PWD/../../libs/ -lcompression \
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64
INCLUDEPATH += \
$$PWD/../../libs/compression \
$$PWD/../../third_party/xbox_sdk/include
DEPENDPATH += \
$$PWD/../../libs/compression \
$$PWD/../../third_party/xbox_sdk/include
FORMS += \
mainwindow.ui

View File

@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

View File

@ -0,0 +1,66 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "compression.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->plainTextEdit_Input, &QPlainTextEdit::textChanged, this, &MainWindow::InputChanged);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::InputChanged()
{
QString input = ui->plainTextEdit_Input->toPlainText();
if (input.isEmpty()) {
qDebug() << "Input data was empty!";
return;
}
QByteArray inputData = QByteArray::fromHex(input.remove(' ').toUtf8());
if (inputData.isEmpty()) {
qDebug() << "Failed to parse valid HEX data!";
return;
}
bool flagOk;
int flag = QString("0x%1").arg(ui->spinBox_Flags->value()).toInt(&flagOk, 16);
if (!flagOk)
{
qDebug() << "Failed to parse flag!";
return;
}
bool windowSizeOk;
int windowSize = QString("0x%1").arg(ui->spinBox_WindowSize->value()).toInt(&windowSizeOk, 16);
if (!windowSizeOk)
{
qDebug() << "Failed to parse window size!";
return;
}
bool partSizeOk;
int partitionSize = QString("0x%1").arg(ui->spinBox_PartitionSize->value()).toInt(&partSizeOk, 16);
if (!partSizeOk)
{
qDebug() << "Failed to parse partition size!";
return;
}
try {
QByteArray output = Compression::DecompressXMem(inputData, flag, windowSize, partitionSize);
ui->plainTextEdit_Output->setPlainText(output.toHex(' ').toUpper());
} catch (const std::exception &e) {
ui->plainTextEdit_Output->setPlainText(QString("Decompression failed: %1").arg(e.what()));
} catch (...) {
ui->plainTextEdit_Output->setPlainText("Decompression failed: Unknown error");
}
}

25
tools/compro/mainwindow.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void InputChanged();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

153
tools/compro/mainwindow.ui Normal file
View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1006</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>LZX</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Input</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QPlainTextEdit" name="plainTextEdit_Input">
<property name="placeholderText">
<string>Input HEX Data (Ex: 63 60 C0 04...)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Parameters</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Flags:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Window Size:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Compression Partition Size:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox_Flags">
<property name="prefix">
<string>0x</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox_WindowSize">
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>20000</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_PartitionSize">
<property name="prefix">
<string>0x</string>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>80000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Output</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QPlainTextEdit" name="plainTextEdit_Output">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Output HEX Data</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,3 +1,4 @@
TEMPLATE = subdirs
SUBDIRS += zentry
SUBDIRS += zentry \
compro