forked from Mirror/GodMode9
Show splash screen when initializing
This commit is contained in:
parent
6597a5e30e
commit
c12d944076
16
Makefile
16
Makefile
@ -21,9 +21,9 @@ ifeq ($(MODE),safe)
|
|||||||
export TARGET := SafeMode9
|
export TARGET := SafeMode9
|
||||||
endif
|
endif
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source source/common source/fs source/crypto source/fatfs source/nand source/virtual source/game source/gamecart
|
SOURCES := source source/common source/fs source/crypto source/fatfs source/nand source/virtual source/game source/gamecart source/quicklz
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := source source/common source/font source/fs source/crypto source/fatfs source/nand source/virtual source/game source/gamecart
|
INCLUDES := source source/common source/font source/fs source/crypto source/fatfs source/nand source/virtual source/game source/gamecart source/quicklz
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
@ -86,7 +86,10 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
|||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/gm9*.*)))
|
||||||
|
ifeq ($(MODE),safe)
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/sm9*.*)))
|
||||||
|
endif
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
@ -188,6 +191,13 @@ $(OUTPUT).elf : $(OFILES)
|
|||||||
@$(OBJCOPY) --set-section-flags .bss=alloc,load,contents -O binary $< $@
|
@$(OBJCOPY) --set-section-flags .bss=alloc,load,contents -O binary $< $@
|
||||||
@echo built ... $(notdir $@)
|
@echo built ... $(notdir $@)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.qlz.o: %.qlz
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
-include $(DEPENDS)
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
BIN
data/gm9_splash.qlz
Normal file
BIN
data/gm9_splash.qlz
Normal file
Binary file not shown.
BIN
data/sm9_splash.qlz
Normal file
BIN
data/sm9_splash.qlz
Normal file
Binary file not shown.
BIN
resources/gm9_splash.png
Normal file
BIN
resources/gm9_splash.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
resources/sm9_splash.png
Normal file
BIN
resources/sm9_splash.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -62,10 +62,17 @@
|
|||||||
#define DIR_BUFFER_SIZE (0x100000)
|
#define DIR_BUFFER_SIZE (0x100000)
|
||||||
// buffer area defines (temporary, in use by various functions)
|
// buffer area defines (temporary, in use by various functions)
|
||||||
// -> godmode.c hexviewer
|
// -> godmode.c hexviewer
|
||||||
|
// -> godmode.c loading payloads
|
||||||
// -> ncch.c seed setup
|
// -> ncch.c seed setup
|
||||||
// -> cia.c ticket / titlekey setup
|
// -> cia.c ticket / titlekey setup
|
||||||
// -> gameutil.c various temporary stuff
|
// -> gameutil.c various temporary stuff
|
||||||
// -> nandcmac.c for processing agbsave
|
// -> nandcmac.c for processing agbsave
|
||||||
|
// -> nandutil.c for storing essential backup
|
||||||
|
// -> ctrtransfer.c for SecureInfo (temporary)
|
||||||
|
// -> vgame.c for handling FIRMs
|
||||||
|
// -> vtickdb.c for parsing ticket.db
|
||||||
|
// -> qlzcomp.c for temporary compression stuff
|
||||||
|
// meaning: careful when using this!
|
||||||
#define TEMP_BUFFER ((u8*)0x21100000)
|
#define TEMP_BUFFER ((u8*)0x21100000)
|
||||||
#define TEMP_BUFFER_SIZE (0x100000)
|
#define TEMP_BUFFER_SIZE (0x100000)
|
||||||
// buffer area defines (in use by fsutil.c, fsinit.c and gameutil.c)
|
// buffer area defines (in use by fsutil.c, fsinit.c and gameutil.c)
|
||||||
|
@ -94,10 +94,10 @@ u32 GetDrawStringHeight(const char* str) {
|
|||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetDrawStringWidth(char* str) {
|
u32 GetDrawStringWidth(const char* str) {
|
||||||
u32 width = 0;
|
u32 width = 0;
|
||||||
char* old_lf = str;
|
char* old_lf = (char*) str;
|
||||||
char* str_end = str + strnlen(str, STRBUF_SIZE);
|
char* str_end = (char*) str + strnlen(str, STRBUF_SIZE);
|
||||||
for (char* lf = strchr(str, '\n'); lf != NULL; lf = strchr(lf + 1, '\n')) {
|
for (char* lf = strchr(str, '\n'); lf != NULL; lf = strchr(lf + 1, '\n')) {
|
||||||
if ((u32) (lf - old_lf) > width) width = lf - old_lf;
|
if ((u32) (lf - old_lf) > width) width = lf - old_lf;
|
||||||
old_lf = lf;
|
old_lf = lf;
|
||||||
|
@ -64,7 +64,7 @@ void DrawString(unsigned char *screen, const char *str, int x, int y, int color,
|
|||||||
void DrawStringF(unsigned char *screen, int x, int y, int color, int bgcolor, const char *format, ...);
|
void DrawStringF(unsigned char *screen, int x, int y, int color, int bgcolor, const char *format, ...);
|
||||||
|
|
||||||
u32 GetDrawStringHeight(const char* str);
|
u32 GetDrawStringHeight(const char* str);
|
||||||
u32 GetDrawStringWidth(char* str);
|
u32 GetDrawStringWidth(const char* str);
|
||||||
|
|
||||||
void ResizeString(char* dest, const char* orig, int nsize, int tpos, bool align_right);
|
void ResizeString(char* dest, const char* orig, int nsize, int tpos, bool align_right);
|
||||||
void TruncateString(char* dest, const char* orig, int nsize, int tpos);
|
void TruncateString(char* dest, const char* orig, int nsize, int tpos);
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
// temporary
|
|
||||||
// #include "fsinit.h"
|
|
||||||
// #include "fsdrive.h"
|
|
||||||
// #include "fsperm.h"
|
|
||||||
|
|
||||||
// move / copy flags
|
// move / copy flags
|
||||||
#define OVERRIDE_PERM (1UL<<0)
|
#define OVERRIDE_PERM (1UL<<0)
|
||||||
|
@ -17,6 +17,16 @@
|
|||||||
#include "ncchinfo.h"
|
#include "ncchinfo.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "chainload.h"
|
#include "chainload.h"
|
||||||
|
#include "qlzcomp.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
#ifndef SAFEMODE
|
||||||
|
#include "gm9_splash_qlz.h"
|
||||||
|
#define QLZ_SPLASH gm9_splash_qlz
|
||||||
|
#else
|
||||||
|
#include "sm9_splash_qlz.h"
|
||||||
|
#define QLZ_SPLASH sm9_splash_qlz
|
||||||
|
#endif
|
||||||
|
|
||||||
#define N_PANES 2
|
#define N_PANES 2
|
||||||
|
|
||||||
@ -1119,6 +1129,23 @@ u32 HomeMoreMenu(char* current_path, DirStruct* current_dir, DirStruct* clipboar
|
|||||||
return HomeMoreMenu(current_path, current_dir, clipboard);
|
return HomeMoreMenu(current_path, current_dir, clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 SplashInit() {
|
||||||
|
const char* namestr = FLAVOR " Explorer v" VERSION;
|
||||||
|
const char* loadstr = "loading...";
|
||||||
|
const u32 pos_xb = 10;
|
||||||
|
const u32 pos_yb = 10;
|
||||||
|
const u32 pos_xu = SCREEN_WIDTH_BOT - 10 - GetDrawStringWidth(loadstr);
|
||||||
|
const u32 pos_yu = SCREEN_HEIGHT - 10 - GetDrawStringHeight(loadstr);
|
||||||
|
|
||||||
|
ClearScreenF(true, true, COLOR_STD_BG);
|
||||||
|
QlzDecompress(TOP_SCREEN, QLZ_SPLASH, 0);
|
||||||
|
DrawStringF(BOT_SCREEN, pos_xb, pos_yb, COLOR_STD_FONT, COLOR_STD_BG, "%s\n%*.*s\n%s", namestr, strnlen(namestr, 64), strnlen(namestr, 64),
|
||||||
|
"------------------------------", "https://github.com/d0k3/GodMode9");
|
||||||
|
DrawStringF(BOT_SCREEN, pos_xu, pos_yu, COLOR_STD_FONT, COLOR_STD_BG, loadstr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 GodMode() {
|
u32 GodMode() {
|
||||||
static const u32 quick_stp = 20;
|
static const u32 quick_stp = 20;
|
||||||
u32 exit_mode = GODMODE_EXIT_REBOOT;
|
u32 exit_mode = GODMODE_EXIT_REBOOT;
|
||||||
@ -1140,19 +1167,19 @@ u32 GodMode() {
|
|||||||
ShowPrompt(false, "Out of memory!"); // just to be safe
|
ShowPrompt(false, "Out of memory!"); // just to be safe
|
||||||
return exit_mode;
|
return exit_mode;
|
||||||
}
|
}
|
||||||
while (!InitSDCardFS()) {
|
|
||||||
const char* optionstr[] = { "Retry initialising", "Poweroff system", "Reboot system", "No SD mode (exp.)", "SD format menu" };
|
SplashInit();
|
||||||
u32 user_select = ShowSelectPrompt(5, optionstr, "Initialising SD card failed!\nSelect action:" );
|
timer_start(); // show splash for at least 1 sec
|
||||||
if (user_select == 2) return GODMODE_EXIT_POWEROFF;
|
|
||||||
else if (user_select == 3) return GODMODE_EXIT_REBOOT;
|
InitSDCardFS();
|
||||||
else if (user_select == 4) break;
|
|
||||||
else if (user_select == 5) SdFormatMenu();
|
|
||||||
ClearScreenF(true, true, COLOR_STD_BG);
|
|
||||||
}
|
|
||||||
InitEmuNandBase(true);
|
InitEmuNandBase(true);
|
||||||
InitNandCrypto();
|
InitNandCrypto();
|
||||||
InitExtFS();
|
InitExtFS();
|
||||||
|
|
||||||
|
// do this now so we don't have to do it later
|
||||||
|
GetFreeSpace("0:");
|
||||||
|
InitVCartDrive();
|
||||||
|
|
||||||
// could also check for a9lh via this: ((*(vu32*) 0x101401C0) == 0)
|
// could also check for a9lh via this: ((*(vu32*) 0x101401C0) == 0)
|
||||||
if ((!IS_O3DS) && !CheckSlot0x05Crypto()) {
|
if ((!IS_O3DS) && !CheckSlot0x05Crypto()) {
|
||||||
if (!ShowPrompt(true, "Warning: slot0x05 crypto fail!\nCould not set up slot0x05keyY.\nContinue?")) {
|
if (!ShowPrompt(true, "Warning: slot0x05 crypto fail!\nCould not set up slot0x05keyY.\nContinue?")) {
|
||||||
@ -1165,6 +1192,10 @@ u32 GodMode() {
|
|||||||
GetDirContents(current_dir, "");
|
GetDirContents(current_dir, "");
|
||||||
clipboard->n_entries = 0;
|
clipboard->n_entries = 0;
|
||||||
memset(panedata, 0x00, 0x10000);
|
memset(panedata, 0x00, 0x10000);
|
||||||
|
|
||||||
|
while(timer_sec() < 1); // show splash for at least 1 sec
|
||||||
|
ClearScreenF(true, true, COLOR_STD_BG); // clear splash
|
||||||
|
|
||||||
while (true) { // this is the main loop
|
while (true) { // this is the main loop
|
||||||
int curr_drvtype = DriveType(current_path);
|
int curr_drvtype = DriveType(current_path);
|
||||||
|
|
||||||
|
17
source/quicklz/qlzcomp.c
Normal file
17
source/quicklz/qlzcomp.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "qlzcomp.h"
|
||||||
|
#include "quicklz.h"
|
||||||
|
|
||||||
|
u32 QlzCompress(void* out, const void* in, u32 size_in) {
|
||||||
|
if (TEMP_BUFFER_SIZE < sizeof(qlz_state_compress)) return 1;
|
||||||
|
qlz_state_compress *state_compress = (qlz_state_compress*) (void*) TEMP_BUFFER;
|
||||||
|
memset(state_compress, 0, sizeof(qlz_state_compress));
|
||||||
|
return (qlz_compress(in, out, size_in, state_compress) > 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 QlzDecompress(void* out, const void* in, u32 size_out) {
|
||||||
|
if (TEMP_BUFFER_SIZE < sizeof(qlz_state_decompress)) return 1;
|
||||||
|
if (size_out && (qlz_size_decompressed(in) != size_out)) return 1;
|
||||||
|
qlz_state_decompress *state_decompress = (qlz_state_decompress*) (void*) TEMP_BUFFER;
|
||||||
|
memset(state_decompress, 0, sizeof(qlz_state_decompress));
|
||||||
|
return (qlz_decompress(in, out, state_decompress) > 0) ? 0 : 1;
|
||||||
|
}
|
6
source/quicklz/qlzcomp.h
Normal file
6
source/quicklz/qlzcomp.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
u32 QlzCompress(void* out, const void* in, u32 size_decomp);
|
||||||
|
u32 QlzDecompress(void* out, const void* in, u32 size);
|
848
source/quicklz/quicklz.c
Normal file
848
source/quicklz/quicklz.c
Normal file
@ -0,0 +1,848 @@
|
|||||||
|
// Fast data compression library
|
||||||
|
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
|
||||||
|
// lar@quicklz.com
|
||||||
|
//
|
||||||
|
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
|
||||||
|
// released into public must be open source) or under a commercial license if such
|
||||||
|
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
|
||||||
|
// does not cover derived or ported versions created by third parties under GPL.
|
||||||
|
|
||||||
|
// 1.5.0 final
|
||||||
|
|
||||||
|
#include "quicklz.h"
|
||||||
|
|
||||||
|
#if QLZ_VERSION_MAJOR != 1 || QLZ_VERSION_MINOR != 5 || QLZ_VERSION_REVISION != 0
|
||||||
|
#error quicklz.c and quicklz.h have different versions
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64))
|
||||||
|
#define X86X64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MINOFFSET 2
|
||||||
|
#define UNCONDITIONAL_MATCHLEN 6
|
||||||
|
#define UNCOMPRESSED_END 4
|
||||||
|
#define CWORD_LEN 4
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1 && defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0
|
||||||
|
#define OFFSET_BASE source
|
||||||
|
#define CAST (ui32)(size_t)
|
||||||
|
#else
|
||||||
|
#define OFFSET_BASE 0
|
||||||
|
#define CAST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int qlz_get_setting(int setting)
|
||||||
|
{
|
||||||
|
switch (setting)
|
||||||
|
{
|
||||||
|
case 0: return QLZ_COMPRESSION_LEVEL;
|
||||||
|
case 1: return sizeof(qlz_state_compress);
|
||||||
|
case 2: return sizeof(qlz_state_decompress);
|
||||||
|
case 3: return QLZ_STREAMING_BUFFER;
|
||||||
|
#ifdef QLZ_MEMORY_SAFE
|
||||||
|
case 6: return 1;
|
||||||
|
#else
|
||||||
|
case 6: return 0;
|
||||||
|
#endif
|
||||||
|
case 7: return QLZ_VERSION_MAJOR;
|
||||||
|
case 8: return QLZ_VERSION_MINOR;
|
||||||
|
case 9: return QLZ_VERSION_REVISION;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
static int same(const unsigned char *src, size_t n)
|
||||||
|
{
|
||||||
|
while(n > 0 && *(src + n) == *src)
|
||||||
|
n--;
|
||||||
|
return n == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void reset_table_compress(qlz_state_compress *state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < QLZ_HASH_VALUES; i++)
|
||||||
|
{
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
state->hash[i].offset = 0;
|
||||||
|
#else
|
||||||
|
state->hash_counter[i] = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reset_table_decompress(qlz_state_decompress *state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
(void)state;
|
||||||
|
(void)i;
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
for(i = 0; i < QLZ_HASH_VALUES; i++)
|
||||||
|
{
|
||||||
|
state->hash_counter[i] = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline ui32 hash_func(ui32 i)
|
||||||
|
{
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
return ((i >> 9) ^ (i >> 13) ^ i) & (QLZ_HASH_VALUES - 1);
|
||||||
|
#else
|
||||||
|
return ((i >> 12) ^ i) & (QLZ_HASH_VALUES - 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline ui32 fast_read(void const *src, ui32 bytes)
|
||||||
|
{
|
||||||
|
#ifndef X86X64
|
||||||
|
unsigned char *p = (unsigned char*)src;
|
||||||
|
switch (bytes)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24);
|
||||||
|
case 3:
|
||||||
|
return(*p | *(p + 1) << 8 | *(p + 2) << 16);
|
||||||
|
case 2:
|
||||||
|
return(*p | *(p + 1) << 8);
|
||||||
|
case 1:
|
||||||
|
return(*p);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
if (bytes >= 1 && bytes <= 4)
|
||||||
|
return *((ui32*)src);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline ui32 hashat(const unsigned char *src)
|
||||||
|
{
|
||||||
|
ui32 fetch, hash;
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
hash = hash_func(fetch);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void fast_write(ui32 f, void *dst, size_t bytes)
|
||||||
|
{
|
||||||
|
#ifndef X86X64
|
||||||
|
unsigned char *p = (unsigned char*)dst;
|
||||||
|
|
||||||
|
switch (bytes)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
*p = (unsigned char)f;
|
||||||
|
*(p + 1) = (unsigned char)(f >> 8);
|
||||||
|
*(p + 2) = (unsigned char)(f >> 16);
|
||||||
|
*(p + 3) = (unsigned char)(f >> 24);
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
*p = (unsigned char)f;
|
||||||
|
*(p + 1) = (unsigned char)(f >> 8);
|
||||||
|
*(p + 2) = (unsigned char)(f >> 16);
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
*p = (unsigned char)f;
|
||||||
|
*(p + 1) = (unsigned char)(f >> 8);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
*p = (unsigned char)f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
switch (bytes)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
*((ui32*)dst) = f;
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
*((ui32*)dst) = f;
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
*((ui16 *)dst) = (ui16)f;
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
*((unsigned char*)dst) = (unsigned char)f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t qlz_size_decompressed(const char *source)
|
||||||
|
{
|
||||||
|
ui32 n, r;
|
||||||
|
n = (((*source) & 2) == 2) ? 4 : 1;
|
||||||
|
r = fast_read(source + 1 + n, n);
|
||||||
|
r = r & (0xffffffff >> ((4 - n)*8));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qlz_size_compressed(const char *source)
|
||||||
|
{
|
||||||
|
ui32 n, r;
|
||||||
|
n = (((*source) & 2) == 2) ? 4 : 1;
|
||||||
|
r = fast_read(source + 1, n);
|
||||||
|
r = r & (0xffffffff >> ((4 - n)*8));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qlz_size_header(const char *source)
|
||||||
|
{
|
||||||
|
size_t n = 2*((((*source) & 2) == 2) ? 4 : 1) + 1;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, ui32 n)
|
||||||
|
{
|
||||||
|
// Caution if modifying memcpy_up! Overlap of dst and src must be special handled.
|
||||||
|
#ifndef X86X64
|
||||||
|
unsigned char *end = dst + n;
|
||||||
|
while(dst < end)
|
||||||
|
{
|
||||||
|
*dst = *src;
|
||||||
|
dst++;
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ui32 f = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*(ui32 *)(dst + f) = *(ui32 *)(src + f);
|
||||||
|
f += MINOFFSET + 1;
|
||||||
|
}
|
||||||
|
while (f < n);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline void update_hash(qlz_state_decompress *state, const unsigned char *s)
|
||||||
|
{
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
ui32 hash;
|
||||||
|
hash = hashat(s);
|
||||||
|
state->hash[hash].offset = s;
|
||||||
|
state->hash_counter[hash] = 1;
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
ui32 hash;
|
||||||
|
unsigned char c;
|
||||||
|
hash = hashat(s);
|
||||||
|
c = state->hash_counter[hash];
|
||||||
|
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = s;
|
||||||
|
c++;
|
||||||
|
state->hash_counter[hash] = c;
|
||||||
|
#endif
|
||||||
|
(void)state;
|
||||||
|
(void)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL <= 2
|
||||||
|
static void update_hash_upto(qlz_state_decompress *state, unsigned char **lh, const unsigned char *max)
|
||||||
|
{
|
||||||
|
while(*lh < max)
|
||||||
|
{
|
||||||
|
(*lh)++;
|
||||||
|
update_hash(state, *lh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static size_t qlz_compress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_compress *state)
|
||||||
|
{
|
||||||
|
const unsigned char *last_byte = source + size - 1;
|
||||||
|
const unsigned char *src = source;
|
||||||
|
unsigned char *cword_ptr = destination;
|
||||||
|
unsigned char *dst = destination + CWORD_LEN;
|
||||||
|
ui32 cword_val = 1U << 31;
|
||||||
|
const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END;
|
||||||
|
ui32 fetch = 0;
|
||||||
|
unsigned int lits = 0;
|
||||||
|
|
||||||
|
(void) lits;
|
||||||
|
|
||||||
|
if(src <= last_matchstart)
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
|
||||||
|
while(src <= last_matchstart)
|
||||||
|
{
|
||||||
|
if ((cword_val & 1) == 1)
|
||||||
|
{
|
||||||
|
// store uncompressed if compression ratio is too low
|
||||||
|
if (src > source + (size >> 1) && dst - destination > src - source - ((src - source) >> 5))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN);
|
||||||
|
|
||||||
|
cword_ptr = dst;
|
||||||
|
dst += CWORD_LEN;
|
||||||
|
cword_val = 1U << 31;
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
}
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
{
|
||||||
|
const unsigned char *o;
|
||||||
|
ui32 hash, cached;
|
||||||
|
|
||||||
|
hash = hash_func(fetch);
|
||||||
|
cached = fetch ^ state->hash[hash].cache;
|
||||||
|
state->hash[hash].cache = fetch;
|
||||||
|
|
||||||
|
o = state->hash[hash].offset + OFFSET_BASE;
|
||||||
|
state->hash[hash].offset = CAST(src - OFFSET_BASE);
|
||||||
|
|
||||||
|
#ifdef X86X64
|
||||||
|
if ((cached & 0xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6))))
|
||||||
|
{
|
||||||
|
if(cached != 0)
|
||||||
|
{
|
||||||
|
#else
|
||||||
|
if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6))))
|
||||||
|
{
|
||||||
|
if (*(o + 3) != *(src + 3))
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
hash <<= 4;
|
||||||
|
cword_val = (cword_val >> 1) | (1U << 31);
|
||||||
|
fast_write((3 - 2) | hash, dst, 2);
|
||||||
|
src += 3;
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const unsigned char *old_src = src;
|
||||||
|
size_t matchlen;
|
||||||
|
hash <<= 4;
|
||||||
|
|
||||||
|
cword_val = (cword_val >> 1) | (1U << 31);
|
||||||
|
src += 4;
|
||||||
|
|
||||||
|
if(*(o + (src - old_src)) == *src)
|
||||||
|
{
|
||||||
|
src++;
|
||||||
|
if(*(o + (src - old_src)) == *src)
|
||||||
|
{
|
||||||
|
size_t q = last_byte - UNCOMPRESSED_END - (src - 5) + 1;
|
||||||
|
size_t remaining = q > 255 ? 255 : q;
|
||||||
|
src++;
|
||||||
|
while(*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining)
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matchlen = src - old_src;
|
||||||
|
if (matchlen < 18)
|
||||||
|
{
|
||||||
|
fast_write((ui32)(matchlen - 2) | hash, dst, 2);
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fast_write((ui32)(matchlen << 16) | hash, dst, 3);
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
lits = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lits++;
|
||||||
|
*dst = *src;
|
||||||
|
src++;
|
||||||
|
dst++;
|
||||||
|
cword_val = (cword_val >> 1);
|
||||||
|
#ifdef X86X64
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
#else
|
||||||
|
fetch = (fetch >> 8 & 0xffff) | (*(src + 2) << 16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL >= 2
|
||||||
|
{
|
||||||
|
const unsigned char *o, *offset2;
|
||||||
|
ui32 hash, matchlen, k, m, best_k = 0;
|
||||||
|
unsigned char c;
|
||||||
|
size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1);
|
||||||
|
(void)best_k;
|
||||||
|
|
||||||
|
|
||||||
|
//hash = hashat(src);
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
hash = hash_func(fetch);
|
||||||
|
|
||||||
|
c = state->hash_counter[hash];
|
||||||
|
|
||||||
|
offset2 = state->hash[hash].offset[0];
|
||||||
|
if(offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3) ^ fetch) & 0xffffff) == 0)
|
||||||
|
{
|
||||||
|
matchlen = 3;
|
||||||
|
if(*(offset2 + matchlen) == *(src + matchlen))
|
||||||
|
{
|
||||||
|
matchlen = 4;
|
||||||
|
while(*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining)
|
||||||
|
matchlen++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
matchlen = 0;
|
||||||
|
for(k = 1; k < QLZ_POINTERS && c > k; k++)
|
||||||
|
{
|
||||||
|
o = state->hash[hash].offset[k];
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 3
|
||||||
|
if(((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET)
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
if(*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
m = 3;
|
||||||
|
while(*(o + m) == *(src + m) && m < remaining)
|
||||||
|
m++;
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 3
|
||||||
|
if ((m > matchlen) || (m == matchlen && o > offset2))
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
if (m > matchlen)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
offset2 = o;
|
||||||
|
matchlen = m;
|
||||||
|
best_k = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = offset2;
|
||||||
|
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src;
|
||||||
|
c++;
|
||||||
|
state->hash_counter[hash] = c;
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 3
|
||||||
|
if(matchlen > 2 && src - o < 131071)
|
||||||
|
{
|
||||||
|
ui32 u;
|
||||||
|
size_t offset = src - o;
|
||||||
|
|
||||||
|
for(u = 1; u < matchlen; u++)
|
||||||
|
{
|
||||||
|
hash = hashat(src + u);
|
||||||
|
c = state->hash_counter[hash]++;
|
||||||
|
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src + u;
|
||||||
|
}
|
||||||
|
|
||||||
|
cword_val = (cword_val >> 1) | (1U << 31);
|
||||||
|
src += matchlen;
|
||||||
|
|
||||||
|
if(matchlen == 3 && offset <= 63)
|
||||||
|
{
|
||||||
|
*dst = (unsigned char)(offset << 2);
|
||||||
|
dst++;
|
||||||
|
}
|
||||||
|
else if (matchlen == 3 && offset <= 16383)
|
||||||
|
{
|
||||||
|
ui32 f = (ui32)((offset << 2) | 1);
|
||||||
|
fast_write(f, dst, 2);
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else if (matchlen <= 18 && offset <= 1023)
|
||||||
|
{
|
||||||
|
ui32 f = ((matchlen - 3) << 2) | ((ui32)offset << 6) | 2;
|
||||||
|
fast_write(f, dst, 2);
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(matchlen <= 33)
|
||||||
|
{
|
||||||
|
ui32 f = ((matchlen - 2) << 2) | ((ui32)offset << 7) | 3;
|
||||||
|
fast_write(f, dst, 3);
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui32 f = ((matchlen - 3) << 7) | ((ui32)offset << 15) | 3;
|
||||||
|
fast_write(f, dst, 4);
|
||||||
|
dst += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dst = *src;
|
||||||
|
src++;
|
||||||
|
dst++;
|
||||||
|
cword_val = (cword_val >> 1);
|
||||||
|
}
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
|
||||||
|
if(matchlen > 2)
|
||||||
|
{
|
||||||
|
cword_val = (cword_val >> 1) | (1U << 31);
|
||||||
|
src += matchlen;
|
||||||
|
|
||||||
|
if (matchlen < 10)
|
||||||
|
{
|
||||||
|
ui32 f = best_k | ((matchlen - 2) << 2) | (hash << 5);
|
||||||
|
fast_write(f, dst, 2);
|
||||||
|
dst += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui32 f = best_k | (matchlen << 16) | (hash << 5);
|
||||||
|
fast_write(f, dst, 3);
|
||||||
|
dst += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dst = *src;
|
||||||
|
src++;
|
||||||
|
dst++;
|
||||||
|
cword_val = (cword_val >> 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
while (src <= last_byte)
|
||||||
|
{
|
||||||
|
if ((cword_val & 1) == 1)
|
||||||
|
{
|
||||||
|
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN);
|
||||||
|
cword_ptr = dst;
|
||||||
|
dst += CWORD_LEN;
|
||||||
|
cword_val = 1U << 31;
|
||||||
|
}
|
||||||
|
#if QLZ_COMPRESSION_LEVEL < 3
|
||||||
|
if (src <= last_byte - 3)
|
||||||
|
{
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
ui32 hash, fetch;
|
||||||
|
fetch = fast_read(src, 3);
|
||||||
|
hash = hash_func(fetch);
|
||||||
|
state->hash[hash].offset = CAST(src - OFFSET_BASE);
|
||||||
|
state->hash[hash].cache = fetch;
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
ui32 hash;
|
||||||
|
unsigned char c;
|
||||||
|
hash = hashat(src);
|
||||||
|
c = state->hash_counter[hash];
|
||||||
|
state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src;
|
||||||
|
c++;
|
||||||
|
state->hash_counter[hash] = c;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*dst = *src;
|
||||||
|
src++;
|
||||||
|
dst++;
|
||||||
|
cword_val = (cword_val >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while((cword_val & 1) != 1)
|
||||||
|
cword_val = (cword_val >> 1);
|
||||||
|
|
||||||
|
fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN);
|
||||||
|
|
||||||
|
// min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument
|
||||||
|
return dst - destination < 9 ? 9 : dst - destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history)
|
||||||
|
{
|
||||||
|
const unsigned char *src = source + qlz_size_header((const char *)source);
|
||||||
|
unsigned char *dst = destination;
|
||||||
|
const unsigned char *last_destination_byte = destination + size - 1;
|
||||||
|
ui32 cword_val = 1;
|
||||||
|
const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END;
|
||||||
|
unsigned char *last_hashed = destination - 1;
|
||||||
|
const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1;
|
||||||
|
static const ui32 bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
|
||||||
|
|
||||||
|
(void) last_source_byte;
|
||||||
|
(void) last_hashed;
|
||||||
|
(void) state;
|
||||||
|
(void) history;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
ui32 fetch;
|
||||||
|
|
||||||
|
if (cword_val == 1)
|
||||||
|
{
|
||||||
|
#ifdef QLZ_MEMORY_SAFE
|
||||||
|
if(src + CWORD_LEN - 1 > last_source_byte)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
cword_val = fast_read(src, CWORD_LEN);
|
||||||
|
src += CWORD_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QLZ_MEMORY_SAFE
|
||||||
|
if(src + 4 - 1 > last_source_byte)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fetch = fast_read(src, 4);
|
||||||
|
|
||||||
|
if ((cword_val & 1) == 1)
|
||||||
|
{
|
||||||
|
ui32 matchlen;
|
||||||
|
const unsigned char *offset2;
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
ui32 hash;
|
||||||
|
cword_val = cword_val >> 1;
|
||||||
|
hash = (fetch >> 4) & 0xfff;
|
||||||
|
offset2 = (const unsigned char *)(size_t)state->hash[hash].offset;
|
||||||
|
|
||||||
|
if((fetch & 0xf) != 0)
|
||||||
|
{
|
||||||
|
matchlen = (fetch & 0xf) + 2;
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matchlen = *(src + 2);
|
||||||
|
src += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
ui32 hash;
|
||||||
|
unsigned char c;
|
||||||
|
cword_val = cword_val >> 1;
|
||||||
|
hash = (fetch >> 5) & 0x7ff;
|
||||||
|
c = (unsigned char)(fetch & 0x3);
|
||||||
|
offset2 = state->hash[hash].offset[c];
|
||||||
|
|
||||||
|
if((fetch & (28)) != 0)
|
||||||
|
{
|
||||||
|
matchlen = ((fetch >> 2) & 0x7) + 2;
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matchlen = *(src + 2);
|
||||||
|
src += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 3
|
||||||
|
ui32 offset;
|
||||||
|
cword_val = cword_val >> 1;
|
||||||
|
if ((fetch & 3) == 0)
|
||||||
|
{
|
||||||
|
offset = (fetch & 0xff) >> 2;
|
||||||
|
matchlen = 3;
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
else if ((fetch & 2) == 0)
|
||||||
|
{
|
||||||
|
offset = (fetch & 0xffff) >> 2;
|
||||||
|
matchlen = 3;
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
else if ((fetch & 1) == 0)
|
||||||
|
{
|
||||||
|
offset = (fetch & 0xffff) >> 6;
|
||||||
|
matchlen = ((fetch >> 2) & 15) + 3;
|
||||||
|
src += 2;
|
||||||
|
}
|
||||||
|
else if ((fetch & 127) != 3)
|
||||||
|
{
|
||||||
|
offset = (fetch >> 7) & 0x1ffff;
|
||||||
|
matchlen = ((fetch >> 2) & 0x1f) + 2;
|
||||||
|
src += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset = (fetch >> 15);
|
||||||
|
matchlen = ((fetch >> 7) & 255) + 3;
|
||||||
|
src += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset2 = dst - offset;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QLZ_MEMORY_SAFE
|
||||||
|
if(offset2 < history || offset2 > dst - MINOFFSET - 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy_up(dst, offset2, matchlen);
|
||||||
|
dst += matchlen;
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL <= 2
|
||||||
|
update_hash_upto(state, &last_hashed, dst - matchlen);
|
||||||
|
last_hashed = dst - 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dst < last_matchstart)
|
||||||
|
{
|
||||||
|
unsigned int n = bitlut[cword_val & 0xf];
|
||||||
|
#ifdef X86X64
|
||||||
|
*(ui32 *)dst = *(ui32 *)src;
|
||||||
|
#else
|
||||||
|
memcpy_up(dst, src, 4);
|
||||||
|
#endif
|
||||||
|
cword_val = cword_val >> n;
|
||||||
|
dst += n;
|
||||||
|
src += n;
|
||||||
|
#if QLZ_COMPRESSION_LEVEL <= 2
|
||||||
|
update_hash_upto(state, &last_hashed, dst - 3);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(dst <= last_destination_byte)
|
||||||
|
{
|
||||||
|
if (cword_val == 1)
|
||||||
|
{
|
||||||
|
src += CWORD_LEN;
|
||||||
|
cword_val = 1U << 31;
|
||||||
|
}
|
||||||
|
#ifdef QLZ_MEMORY_SAFE
|
||||||
|
if(src >= last_source_byte + 1)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
*dst = *src;
|
||||||
|
dst++;
|
||||||
|
src++;
|
||||||
|
cword_val = cword_val >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL <= 2
|
||||||
|
update_hash_upto(state, &last_hashed, last_destination_byte - 3); // todo, use constant
|
||||||
|
#endif
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state)
|
||||||
|
{
|
||||||
|
size_t r;
|
||||||
|
ui32 compressed;
|
||||||
|
size_t base;
|
||||||
|
|
||||||
|
if(size == 0 || size > 0xffffffff - 400)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(size < 216)
|
||||||
|
base = 3;
|
||||||
|
else
|
||||||
|
base = 9;
|
||||||
|
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
reset_table_compress(state);
|
||||||
|
r = base + qlz_compress_core((const unsigned char *)source, (unsigned char*)destination + base, size, state);
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
reset_table_compress(state);
|
||||||
|
#endif
|
||||||
|
if(r == base)
|
||||||
|
{
|
||||||
|
memcpy(destination + base, source, size);
|
||||||
|
r = size + base;
|
||||||
|
compressed = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compressed = 1;
|
||||||
|
}
|
||||||
|
state->stream_counter = 0;
|
||||||
|
}
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned char *src = state->stream_buffer + state->stream_counter;
|
||||||
|
|
||||||
|
memcpy(src, source, size);
|
||||||
|
r = base + qlz_compress_core(src, (unsigned char*)destination + base, size, state);
|
||||||
|
|
||||||
|
if(r == base)
|
||||||
|
{
|
||||||
|
memcpy(destination + base, src, size);
|
||||||
|
r = size + base;
|
||||||
|
compressed = 0;
|
||||||
|
reset_table_compress(state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compressed = 1;
|
||||||
|
}
|
||||||
|
state->stream_counter += size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(base == 3)
|
||||||
|
{
|
||||||
|
*destination = (unsigned char)(0 | compressed);
|
||||||
|
*(destination + 1) = (unsigned char)r;
|
||||||
|
*(destination + 2) = (unsigned char)size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*destination = (unsigned char)(2 | compressed);
|
||||||
|
fast_write((ui32)r, destination + 1, 4);
|
||||||
|
fast_write((ui32)size, destination + 5, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
*destination |= (QLZ_COMPRESSION_LEVEL << 2);
|
||||||
|
*destination |= (1 << 6);
|
||||||
|
*destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3))) << 4);
|
||||||
|
|
||||||
|
// 76543210
|
||||||
|
// 01SSLLHC
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state)
|
||||||
|
{
|
||||||
|
size_t dsiz = qlz_size_decompressed(source);
|
||||||
|
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if((*source & 1) == 1)
|
||||||
|
{
|
||||||
|
reset_table_decompress(state);
|
||||||
|
dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(destination, source + qlz_size_header(source), dsiz);
|
||||||
|
}
|
||||||
|
state->stream_counter = 0;
|
||||||
|
reset_table_decompress(state);
|
||||||
|
}
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned char *dst = state->stream_buffer + state->stream_counter;
|
||||||
|
if((*source & 1) == 1)
|
||||||
|
{
|
||||||
|
dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(dst, source + qlz_size_header(source), dsiz);
|
||||||
|
reset_table_decompress(state);
|
||||||
|
}
|
||||||
|
memcpy(destination, dst, dsiz);
|
||||||
|
state->stream_counter += dsiz;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return dsiz;
|
||||||
|
}
|
||||||
|
|
151
source/quicklz/quicklz.h
Normal file
151
source/quicklz/quicklz.h
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#ifndef QLZ_HEADER
|
||||||
|
#define QLZ_HEADER
|
||||||
|
|
||||||
|
// Fast data compression library
|
||||||
|
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
|
||||||
|
// lar@quicklz.com
|
||||||
|
//
|
||||||
|
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
|
||||||
|
// released into public must be open source) or under a commercial license if such
|
||||||
|
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
|
||||||
|
// does not cover derived or ported versions created by third parties under GPL.
|
||||||
|
|
||||||
|
// You can edit following user settings. Data must be decompressed with the same
|
||||||
|
// setting of QLZ_COMPRESSION_LEVEL and QLZ_STREAMING_BUFFER as it was compressed
|
||||||
|
// (see manual). If QLZ_STREAMING_BUFFER > 0, scratch buffers must be initially
|
||||||
|
// zeroed out (see manual). First #ifndef makes it possible to define settings from
|
||||||
|
// the outside like the compiler command line.
|
||||||
|
|
||||||
|
// 1.5.0 final
|
||||||
|
|
||||||
|
#ifndef QLZ_COMPRESSION_LEVEL
|
||||||
|
|
||||||
|
// 1 gives fastest compression speed. 3 gives fastest decompression speed and best
|
||||||
|
// compression ratio.
|
||||||
|
//#define QLZ_COMPRESSION_LEVEL 1
|
||||||
|
//#define QLZ_COMPRESSION_LEVEL 2
|
||||||
|
#define QLZ_COMPRESSION_LEVEL 3
|
||||||
|
|
||||||
|
// If > 0, zero out both states prior to first call to qlz_compress() or qlz_decompress()
|
||||||
|
// and decompress packets in the same order as they were compressed
|
||||||
|
#define QLZ_STREAMING_BUFFER 0
|
||||||
|
//#define QLZ_STREAMING_BUFFER 1000
|
||||||
|
//#define QLZ_STREAMING_BUFFER 100000
|
||||||
|
//#define QLZ_STREAMING_BUFFER 1000000
|
||||||
|
|
||||||
|
// Guarantees that decompression of corrupted data cannot crash. Decreases decompression
|
||||||
|
// speed 10-20%. Compression speed not affected.
|
||||||
|
//#define QLZ_MEMORY_SAFE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define QLZ_VERSION_MAJOR 1
|
||||||
|
#define QLZ_VERSION_MINOR 5
|
||||||
|
#define QLZ_VERSION_REVISION 0
|
||||||
|
|
||||||
|
// Using size_t, memset() and memcpy()
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Verify compression level
|
||||||
|
#if QLZ_COMPRESSION_LEVEL != 1 && QLZ_COMPRESSION_LEVEL != 2 && QLZ_COMPRESSION_LEVEL != 3
|
||||||
|
#error QLZ_COMPRESSION_LEVEL must be 1, 2 or 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned int ui32;
|
||||||
|
typedef unsigned short int ui16;
|
||||||
|
|
||||||
|
// Decrease QLZ_POINTERS for level 3 to increase compression speed. Do not touch any other values!
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
#define QLZ_POINTERS 1
|
||||||
|
#define QLZ_HASH_VALUES 4096
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
#define QLZ_POINTERS 4
|
||||||
|
#define QLZ_HASH_VALUES 2048
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 3
|
||||||
|
#define QLZ_POINTERS 16
|
||||||
|
#define QLZ_HASH_VALUES 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Detect if pointer size is 64-bit. It's not fatal if some 64-bit target is not detected because this is only for adding an optional 64-bit optimization.
|
||||||
|
#if defined _LP64 || defined __LP64__ || defined __64BIT__ || _ADDR64 || defined _WIN64 || defined __arch64__ || __WORDSIZE == 64 || (defined __sparc && defined __sparcv9) || defined __x86_64 || defined __amd64 || defined __x86_64__ || defined _M_X64 || defined _M_IA64 || defined __ia64 || defined __IA64__
|
||||||
|
#define QLZ_PTR_64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// hash entry
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
ui32 cache;
|
||||||
|
#if defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0
|
||||||
|
unsigned int offset;
|
||||||
|
#else
|
||||||
|
const unsigned char *offset;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
const unsigned char *offset[QLZ_POINTERS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} qlz_hash_compress;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1
|
||||||
|
const unsigned char *offset;
|
||||||
|
#else
|
||||||
|
const unsigned char *offset[QLZ_POINTERS];
|
||||||
|
#endif
|
||||||
|
} qlz_hash_decompress;
|
||||||
|
|
||||||
|
|
||||||
|
// states
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
unsigned char stream_buffer[QLZ_STREAMING_BUFFER];
|
||||||
|
#endif
|
||||||
|
size_t stream_counter;
|
||||||
|
qlz_hash_compress hash[QLZ_HASH_VALUES];
|
||||||
|
unsigned char hash_counter[QLZ_HASH_VALUES];
|
||||||
|
} qlz_state_compress;
|
||||||
|
|
||||||
|
|
||||||
|
#if QLZ_COMPRESSION_LEVEL == 1 || QLZ_COMPRESSION_LEVEL == 2
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
unsigned char stream_buffer[QLZ_STREAMING_BUFFER];
|
||||||
|
#endif
|
||||||
|
qlz_hash_decompress hash[QLZ_HASH_VALUES];
|
||||||
|
unsigned char hash_counter[QLZ_HASH_VALUES];
|
||||||
|
size_t stream_counter;
|
||||||
|
} qlz_state_decompress;
|
||||||
|
#elif QLZ_COMPRESSION_LEVEL == 3
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#if QLZ_STREAMING_BUFFER > 0
|
||||||
|
unsigned char stream_buffer[QLZ_STREAMING_BUFFER];
|
||||||
|
#endif
|
||||||
|
#if QLZ_COMPRESSION_LEVEL <= 2
|
||||||
|
qlz_hash_decompress hash[QLZ_HASH_VALUES];
|
||||||
|
#endif
|
||||||
|
size_t stream_counter;
|
||||||
|
} qlz_state_decompress;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Public functions of QuickLZ
|
||||||
|
size_t qlz_size_decompressed(const char *source);
|
||||||
|
size_t qlz_size_compressed(const char *source);
|
||||||
|
size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state);
|
||||||
|
size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state);
|
||||||
|
int qlz_get_setting(int setting);
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user