aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/lzp
diff options
context:
space:
mode:
Diffstat (limited to 'libpsn00b/lzp')
-rw-r--r--libpsn00b/lzp/bit.c65
-rw-r--r--libpsn00b/lzp/bit.h26
-rw-r--r--libpsn00b/lzp/compress.c488
-rw-r--r--libpsn00b/lzp/crc.c91
-rw-r--r--libpsn00b/lzp/lzp.c88
-rw-r--r--libpsn00b/lzp/lzp.h223
-rw-r--r--libpsn00b/lzp/lzqlp.h26
-rw-r--r--libpsn00b/lzp/makefile28
-rw-r--r--libpsn00b/lzp/qlp.c64
9 files changed, 1099 insertions, 0 deletions
diff --git a/libpsn00b/lzp/bit.c b/libpsn00b/lzp/bit.c
new file mode 100644
index 0000000..aefa45d
--- /dev/null
+++ b/libpsn00b/lzp/bit.c
@@ -0,0 +1,65 @@
+#include "bit.h"
+
+// Bit I/O
+//
+
+unsigned char* inPtr = 0;
+int inBytes = 0;
+unsigned char* outPtr = 0;
+int outBytes = 0;
+
+int bit_buf;
+int bit_count;
+
+void init_bits() {
+
+ bit_count = bit_buf=0;
+
+}
+
+void put_bits(int n, int x) {
+
+ bit_buf |= x<<bit_count;
+ bit_count += n;
+
+ while(bit_count >= 8) {
+
+ *outPtr = bit_buf;
+ outPtr++;
+ outBytes++;
+
+ bit_buf >>= 8;
+ bit_count -= 8;
+
+ }
+
+}
+
+void flush_bits() {
+
+ put_bits(7, 0);
+ bit_count = bit_buf = 0;
+
+}
+
+int get_bits(int n) {
+
+ int x;
+
+ while(bit_count < n) {
+
+ bit_buf |= *inPtr<<bit_count;
+ inPtr++;
+ inBytes++;
+
+ bit_count += 8;
+
+ }
+
+ x = bit_buf&((1<<n)-1);
+ bit_buf >>= n;
+ bit_count -= n;
+
+ return(x);
+
+}
diff --git a/libpsn00b/lzp/bit.h b/libpsn00b/lzp/bit.h
new file mode 100644
index 0000000..ff71025
--- /dev/null
+++ b/libpsn00b/lzp/bit.h
@@ -0,0 +1,26 @@
+#ifndef _LZP_BIT_H
+#define _LZP_BIT_H
+
+extern unsigned char* inPtr;
+extern int inBytes;
+extern unsigned char* outPtr;
+extern int outBytes;
+
+extern int bit_buf;
+extern int bit_count;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void init_bits();
+void put_bits(int n, int x);
+void flush_bits();
+int get_bits(int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _LZP_BIT_H
diff --git a/libpsn00b/lzp/compress.c b/libpsn00b/lzp/compress.c
new file mode 100644
index 0000000..33af08d
--- /dev/null
+++ b/libpsn00b/lzp/compress.c
@@ -0,0 +1,488 @@
+// Based on ilia muraviev's CRUSH compressor program which falls under public domain
+
+#include <string.h>
+#if LZP_USE_MALLOC == TRUE
+#include <stdlib.h>
+#endif
+
+#include "lzconfig.h"
+#include "bit.h"
+#include "lzp.h"
+
+
+// Internal structure for hash table allocation sizes
+#if LZP_NO_COMPRESS == FALSE
+
+struct {
+ short WindowSize; // Window size (17 - 23)
+ short Hash1Size; // Hash 1 table size (10 - 21)
+ short Hash2Size; // Hash 2 table size (12 - 24)
+} lzHashParam = {
+ LZP_WINDOW_SIZE,
+ LZP_HASH1_SIZE,
+ LZP_HASH2_SIZE
+};
+
+#endif
+
+
+// Defines and macros for lz77 compression/decompression (don't touch)
+#define W_BITS lzHashParam.WindowSize
+#define HASH1_BITS lzHashParam.Hash1Size
+#define HASH2_BITS lzHashParam.Hash2Size
+
+#define W_SIZE (1<<W_BITS)
+#define W_MASK (W_SIZE-1)
+#define SLOT_BITS 4
+#define NUM_SLOTS (1<<SLOT_BITS)
+
+#define A_BITS 2 // 1 xx
+#define B_BITS 2 // 01 xx
+#define C_BITS 2 // 001 xx
+#define D_BITS 3 // 0001 xxx
+#define E_BITS 5 // 00001 xxxxx
+#define F_BITS 9 // 00000 xxxxxxxxx
+#define A (1<<A_BITS)
+#define B ((1<<B_BITS)+A)
+#define C ((1<<C_BITS)+B)
+#define D ((1<<D_BITS)+C)
+#define E ((1<<E_BITS)+D)
+#define F ((1<<F_BITS)+E)
+#define MIN_MATCH 3
+#define MAX_MATCH ((F-1)+MIN_MATCH)
+
+#define BUF_SIZE (1<<26)
+#define TOO_FAR (1<<16)
+
+#define HASH1_LEN MIN_MATCH
+#define HASH2_LEN (MIN_MATCH+1)
+#define HASH1_SIZE (1<<HASH1_BITS)
+#define HASH2_SIZE (1<<HASH2_BITS)
+#define HASH1_MASK (HASH1_SIZE-1)
+#define HASH2_MASK (HASH2_SIZE-1)
+#define HASH1_SHIFT ((HASH1_BITS+(HASH1_LEN-1))/HASH1_LEN)
+#define HASH2_SHIFT ((HASH2_BITS+(HASH2_LEN-1))/HASH2_LEN)
+
+
+// LZ77
+//
+
+#if LZP_NO_COMPRESS == FALSE
+
+int update_hash1(int h, int c) {
+
+ return(((h<<HASH1_SHIFT)+c)&HASH1_MASK);
+
+}
+
+int update_hash2(int h, int c) {
+
+ return(((h<<HASH2_SHIFT)+c)&HASH2_MASK);
+
+}
+
+int get_min(int a, int b) {
+
+ return(a<b?a:b);
+
+}
+
+int get_max(int a, int b) {
+
+ return(a>b?a:b);
+
+}
+
+int get_penalty(int a, int b) {
+
+ int p=0;
+
+ while(a > b) {
+ a >>= 3;
+ ++p;
+ }
+
+ return(p);
+
+}
+
+int lzCompress(void* outBuff, void* inBuff, int inSize, int level) {
+
+ #if LZP_USE_MALLOC == FALSE
+ int head[HASH1_SIZE+HASH2_SIZE];
+ int prev[W_SIZE];
+ #else
+ int* head = malloc(4*(HASH1_SIZE+HASH2_SIZE));
+ int* prev = malloc(4*W_SIZE);
+ #endif
+
+
+ int max_chain[] = {4, 256, 1<<12};
+
+ int i,s;
+ int h1=0;
+ int h2=0;
+ int p=0;
+
+ int len;
+ int offset;
+
+ int max_match;
+ int limit;
+
+ int chain_len;
+ int next_p;
+ int max_lazy;
+ int log;
+
+
+ inPtr = (unsigned char*)inBuff;
+ outPtr = (unsigned char*)outBuff;
+ outBytes = 0;
+
+
+ for (i=0; i<HASH1_SIZE+HASH2_SIZE; ++i)
+ head[i] = -1;
+
+ for (i=0; i<HASH1_LEN; ++i)
+ h1=update_hash1(h1, inPtr[i]);
+
+ for (i=0; i<HASH2_LEN; ++i)
+ h2=update_hash2(h2, inPtr[i]);
+
+ init_bits();
+
+ // Put window size value so that the compressed data will be independent of the compression settings
+ put_bits(5, lzHashParam.WindowSize);
+
+ while(p < inSize) {
+
+ len = MIN_MATCH-1;
+ offset = W_SIZE;
+
+ max_match = get_min(MAX_MATCH, inSize-p);
+ limit = get_max(p-W_SIZE, 0);
+
+ if (head[h1] >= limit) {
+
+ s = head[h1];
+
+ if (inPtr[s] == inPtr[p]) {
+
+ i = 0;
+
+ while(++i < max_match) {
+ if (inPtr[s+i] != inPtr[p+i])
+ break;
+ }
+
+ if (i > len) {
+ len = i;
+ offset = p-s;
+ }
+
+ }
+
+ }
+
+ if (len < MAX_MATCH) {
+
+ chain_len = max_chain[level];
+ s = head[h2+HASH1_SIZE];
+
+ while((chain_len-- != 0) && (s >= limit)) {
+
+ if ((inPtr[s+len] == inPtr[p+len]) && (inPtr[s] == inPtr[p])) {
+
+ i = 0;
+
+ while(++i < max_match) {
+ if (inPtr[s+i] != inPtr[p+i])
+ break;
+ }
+
+ if (i > len+get_penalty((p-s)>>4, offset)) {
+ len = i;
+ offset = p-s;
+ }
+
+ if (i == max_match)
+ break;
+
+ }
+
+ s=prev[s&W_MASK];
+
+ }
+
+ }
+
+ if ((len == MIN_MATCH) && (offset > TOO_FAR))
+ len=0;
+
+ if ((level >= 2) && (len >= MIN_MATCH) && (len < max_match)) {
+
+ next_p = p+1;
+ max_lazy = get_min(len+4, max_match);
+
+ chain_len = max_chain[level];
+ s = head[update_hash2(h2, inPtr[next_p+(HASH2_LEN-1)])+HASH1_SIZE];
+
+ while((chain_len-- != 0) && (s >= limit)) {
+
+ if ((inPtr[s+len] == inPtr[next_p+len]) && (inPtr[s] == inPtr[next_p])) {
+
+ i = 0;
+
+ while(++i < max_lazy) {
+ if (inPtr[s+i] != inPtr[next_p+i])
+ break;
+ }
+
+ if (i > len+get_penalty(next_p-s, offset)) {
+ len = 0;
+ break;
+ }
+
+ if (i == max_lazy)
+ break;
+
+ }
+
+ s = prev[s&W_MASK];
+
+ }
+
+ }
+
+
+ if (len >= MIN_MATCH) { // Match
+
+ put_bits(1, 1);
+
+ i = len-MIN_MATCH;
+
+ if (i < A) {
+ put_bits(1, 1); // 1
+ put_bits(A_BITS, i);
+ } else if (i < B) {
+ put_bits(2, 1<<1); // 01
+ put_bits(B_BITS, i-A);
+ } else if (i < C) {
+ put_bits(3, 1<<2); // 001
+ put_bits(C_BITS, i-B);
+ } else if (i < D) {
+ put_bits(4, 1<<3); // 0001
+ put_bits(D_BITS, i-C);
+ } else if (i < E) {
+ put_bits(5, 1<<4); // 00001
+ put_bits(E_BITS, i-D);
+ } else {
+ put_bits(5, 0); // 00000
+ put_bits(F_BITS, i-E);
+ }
+
+ --offset;
+ log = W_BITS-NUM_SLOTS;
+
+ while(offset >= (2<<log))
+ ++log;
+
+ put_bits(SLOT_BITS, log-(W_BITS-NUM_SLOTS));
+
+ if (log>(W_BITS-NUM_SLOTS))
+ put_bits(log, offset-(1<<log));
+ else
+ put_bits(W_BITS-(NUM_SLOTS-1), offset);
+
+ } else { // Literal
+
+ len = 1;
+ put_bits(9, inPtr[p]<<1); // 0 xxxxxxxx
+
+ }
+
+ while(len-- != 0) { // Insert new strings
+
+ head[h1] = p;
+ prev[p&W_MASK] = head[h2+HASH1_SIZE];
+ head[h2+HASH1_SIZE] = p;
+
+ ++p;
+
+ h1 = update_hash1(h1, inPtr[p+(HASH1_LEN-1)]);
+ h2 = update_hash2(h2, inPtr[p+(HASH2_LEN-1)]);
+
+ }
+
+ }
+
+ flush_bits();
+
+ #if LZP_USE_MALLOC == TRUE
+ free(head);
+ free(prev);
+ #endif
+
+ return(outBytes);
+
+}
+
+void lzSetHashSizes(int window, int hash1, int hash2) {
+
+ lzHashParam.WindowSize = window;
+ lzHashParam.Hash1Size = hash1;
+ lzHashParam.Hash2Size = hash2;
+
+}
+
+void lzResetHashSizes() {
+
+ lzHashParam.WindowSize = LZP_WINDOW_SIZE;
+ lzHashParam.Hash1Size = LZP_HASH1_SIZE;
+ lzHashParam.Hash2Size = LZP_HASH2_SIZE;
+
+}
+
+#endif // LZP_NO_COMPRESS
+
+int lzDecompress(void* outBuff, void* inBuff, int inSize) {
+
+ int p=0;
+ int len;
+ int log;
+ int s;
+ int windowSize;
+
+ inPtr = (unsigned char*)inBuff;
+ outPtr = (unsigned char*)outBuff;
+ inBytes = 0;
+ outBytes = 0;
+
+ init_bits();
+
+ // Get window size value
+ windowSize = get_bits(5);
+
+ while(inBytes < inSize) {
+
+ if (get_bits(1)) {
+
+ if (get_bits(1))
+ len = get_bits(A_BITS);
+ else if (get_bits(1))
+ len = get_bits(B_BITS)+A;
+ else if (get_bits(1))
+ len = get_bits(C_BITS)+B;
+ else if (get_bits(1))
+ len = get_bits(D_BITS)+C;
+ else if (get_bits(1))
+ len = get_bits(E_BITS)+D;
+ else
+ len = get_bits(F_BITS)+E;
+
+ log = get_bits(SLOT_BITS)+(windowSize-NUM_SLOTS);
+
+ s =~ (log>(windowSize-NUM_SLOTS) ? get_bits(log)+(1<<log) : get_bits(windowSize-(NUM_SLOTS-1)))+p;
+
+ if (s < 0)
+ return(LZP_ERR_DECOMPRESS);
+
+ outPtr[p++] = outPtr[s++];
+ outPtr[p++] = outPtr[s++];
+ outPtr[p++] = outPtr[s++];
+
+ while(len-- != 0)
+ outPtr[p++] = outPtr[s++];
+
+ } else {
+
+ outPtr[p++] = get_bits(8);
+
+ }
+
+ }
+
+ return(p);
+
+}
+
+int lzDecompressLen(void* outBuff, int outSize, void* inBuff, int inSize) {
+
+ int p=0;
+ int len;
+ int log;
+ int s;
+ int windowSize;
+
+ inPtr = (unsigned char*)inBuff;
+ outPtr = (unsigned char*)outBuff;
+ inBytes = 0;
+ outBytes = 0;
+
+ init_bits();
+
+ // Get window size value
+ windowSize = get_bits(5);
+
+ while(inBytes < inSize) {
+
+ if (get_bits(1)) {
+
+ if (get_bits(1))
+ len = get_bits(A_BITS);
+ else if (get_bits(1))
+ len = get_bits(B_BITS)+A;
+ else if (get_bits(1))
+ len = get_bits(C_BITS)+B;
+ else if (get_bits(1))
+ len = get_bits(D_BITS)+C;
+ else if (get_bits(1))
+ len = get_bits(E_BITS)+D;
+ else
+ len = get_bits(F_BITS)+E;
+
+ log = get_bits(SLOT_BITS)+(windowSize-NUM_SLOTS);
+
+ s =~ (log>(windowSize-NUM_SLOTS) ? get_bits(log)+(1<<log) : get_bits(windowSize-(NUM_SLOTS-1)))+p;
+
+ if (s < 0)
+ return(LZP_ERR_DECOMPRESS);
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ while(len-- != 0) {
+
+ outPtr[p++] = outPtr[s++];
+ if (p >= outSize)
+ break;
+
+ }
+
+ if (p >= outSize)
+ break;
+
+ } else {
+
+ outPtr[p++] = get_bits(8);
+
+ }
+
+ if (p >= outSize)
+ break;
+
+ }
+
+ return(p);
+
+}
diff --git a/libpsn00b/lzp/crc.c b/libpsn00b/lzp/crc.c
new file mode 100644
index 0000000..c5ab702
--- /dev/null
+++ b/libpsn00b/lzp/crc.c
@@ -0,0 +1,91 @@
+#include "lzp.h"
+
+void initTable16(unsigned short* table) {
+
+ int i, j;
+ unsigned short crc, c;
+
+ for (i=0; i<256; i++) {
+
+ crc = 0;
+ c = (unsigned short) i;
+
+ for (j=0; j<8; j++) {
+
+ if ( (crc ^ c) & 0x0001 )
+ crc = ( crc >> 1 ) ^ 0xA001;
+ else
+ crc = crc >> 1;
+
+ c = c >> 1;
+ }
+
+ table[i] = crc;
+ }
+
+}
+
+void initTable32(unsigned int* table) {
+
+ int i,j;
+ unsigned int crcVal;
+
+ for(i=0; i<256; i++) {
+
+ crcVal = i;
+
+ for(j=0; j<8; j++) {
+
+ if (crcVal&0x00000001L)
+ crcVal = (crcVal>>1)^0xEDB88320L;
+ else
+ crcVal = crcVal>>1;
+
+ }
+
+ table[i] = crcVal;
+
+ }
+
+}
+
+unsigned short lzCRC16(void* buff, int bytes, unsigned short crc) {
+
+ int i;
+ unsigned short tmp, short_c;
+ unsigned short crcTable[256];
+
+ initTable16(crcTable);
+
+ for(i=0; i<bytes; i++) {
+
+ short_c = 0x00ff & (unsigned short)((unsigned char*)buff)[i];
+
+ tmp = crc ^ short_c;
+ crc = (crc >> 8) ^ crcTable[tmp&0xff];
+
+ }
+
+ return(crc);
+
+}
+
+unsigned int lzCRC32(void* buff, int bytes, unsigned int crc) {
+
+ int i;
+ unsigned char* byteBuff = (unsigned char*)buff;
+ unsigned int byte;
+ unsigned int crcTable[256];
+
+ initTable32(crcTable);
+
+ for(i=0; i<bytes; i++) {
+
+ byte = 0x000000ffL&(unsigned int)byteBuff[i];
+ crc = (crc>>8)^crcTable[(crc^byte)&0xff];
+
+ }
+
+ return(crc^0xFFFFFFFF);
+
+}
diff --git a/libpsn00b/lzp/lzp.c b/libpsn00b/lzp/lzp.c
new file mode 100644
index 0000000..1f4fea4
--- /dev/null
+++ b/libpsn00b/lzp/lzp.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "lzp.h"
+
+
+static char* lcase(char* text) {
+
+ int i;
+
+ for(i=0; text[i]!=0x00; i++)
+ text[i] = tolower(text[i]);
+
+ return(text);
+
+}
+
+
+int lzpSearchFile(const char* fileName, void* lzpack) {
+
+ int i;
+ char searchName[16];
+ char compareName[16];
+ LZP_FILE* fileEntry;
+
+ strcpy(searchName, fileName);
+ lcase(searchName);
+
+ fileEntry = (LZP_FILE*)(lzpack+4);
+ for(i=0; i<((LZP_HEAD*)lzpack)->numFiles; i++) {
+
+ strcpy(compareName, fileEntry[i].fileName);
+ lcase(compareName);
+
+ if (strcmp(searchName, compareName) == 0)
+ return(i);
+
+ }
+
+ return(LZP_ERR_NOTFOUND);
+
+}
+
+LZP_FILE* lzpFileEntry(void* lzpack, int fileNum) {
+
+ if (strncmp("LZP", ((LZP_HEAD*)lzpack)->id, 3) != 0)
+ return(NULL);
+
+ if ((fileNum < 0) || (fileNum > (((LZP_HEAD*)lzpack)->numFiles-1)))
+ return(NULL);
+
+ return(&((LZP_FILE*)(lzpack+4))[fileNum]);
+
+}
+
+int lzpFileSize(void* lzpack, int fileNum) {
+
+ if (strncmp("LZP", ((LZP_HEAD*)lzpack)->id, 3) != 0)
+ return 0;
+
+ if ((fileNum < 0) || (fileNum > (((LZP_HEAD*)lzpack)->numFiles-1)))
+ return 0;
+
+ return ((LZP_FILE*)(lzpack+4))[fileNum].fileSize;
+}
+
+int lzpUnpackFile(void* buff, void* lzpack, int fileNum) {
+
+ LZP_FILE* fileEntry = &((LZP_FILE*)(lzpack+4))[fileNum];
+ int unpackedSize;
+
+ // Check ID header
+ if (strncmp("LZP", ((LZP_HEAD*)lzpack)->id, 3) != 0)
+ return(LZP_ERR_INVALID_PACK);
+
+ // Do a CRC16 check of the compressed data's integrity
+ if (lzCRC32(lzpack+fileEntry->offset, fileEntry->packedSize, LZP_CRC32_REMAINDER) != fileEntry->crc)
+ return(LZP_ERR_CRC_MISMATCH);
+
+ // Decompress data to the specified address
+ unpackedSize = lzDecompress(buff, lzpack+fileEntry->offset, fileEntry->packedSize);
+ if (unpackedSize < 0)
+ return(unpackedSize);
+
+ return(unpackedSize);
+
+}
diff --git a/libpsn00b/lzp/lzp.h b/libpsn00b/lzp/lzp.h
new file mode 100644
index 0000000..ffd7933
--- /dev/null
+++ b/libpsn00b/lzp/lzp.h
@@ -0,0 +1,223 @@
+/*! \file lzp.h
+ * \brief Main library header
+ */
+
+/*! \mainpage
+ * \version 0.20b
+ * \author John Wilbert 'Lameguy64' Villamor
+ *
+ * \section creditsSection Credits
+ * - LZ77 data compression/decompression routines based from Ilya Muravyov's
+ * crush.cpp released under public domain. Refined and ported to C by Lameguy64.
+ * - CRC calculation routines based from Lammert Bies' lib_crc routines.
+ *
+ */
+
+#ifndef _LZPACK_H
+#define _LZPACK_H
+
+#include <sys/types.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+/*! \addtogroup crcBaseRemainders CRC Base Remainder Values
+ * @{
+ */
+//! Initial remainder value for lzCRC16()
+#define LZP_CRC16_REMAINDER 0x0000
+//! Initial remainder value for lzCRC32()
+#define LZP_CRC32_REMAINDER 0xFFFFFFFF
+/*! @} */
+
+
+/*! \addtogroup compLevels Compression Levels
+ * \brief Compression levels for the lzCompress() function.
+ * @{
+ */
+//! Minimal (but fast) compression
+#define LZP_COMPRESS_FAST 0
+//! Normal compression level
+#define LZP_COMPRESS_NORMAL 1
+//! Maximum compression level
+#define LZP_COMPRESS_MAX 2
+/*! @} */
+
+
+/*! \addtogroup libraryErrorCodes Library Error Codes
+ * @{
+ */
+//! No error
+#define LZP_ERR_NONE 0
+//! Decompression error
+#define LZP_ERR_DECOMPRESS -1
+//! Not a valid LZP/QLP/PCK archive
+#define LZP_ERR_INVALID_PACK -2
+//! File not found
+#define LZP_ERR_NOTFOUND -3
+//! CRC check mismatch (data corruption)
+#define LZP_ERR_CRC_MISMATCH -4
+/*! @} */
+
+
+//! Header structure of an LZP format archive file
+typedef struct {
+
+ //! File ID (must always be 'LZP')
+ char id[3];
+ //! File count
+ u_char numFiles;
+
+} LZP_HEAD;
+
+//! File entry structure for an LZP format archive file
+typedef struct {
+
+ //! File name
+ char fileName[16];
+ //! CRC32 checksum of file
+ u_int crc;
+ //! Original size of file in bytes
+ u_int fileSize;
+ //! Compressed size of file
+ u_int packedSize;
+ //! File data offset
+ u_int offset;
+
+} LZP_FILE;
+
+
+// Function prototypes
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*! \addtogroup compressFuncs Data Compression and Decompression Functions
+ * \brief Functions to compress and decompress data.
+ * @{
+ */
+
+/*! Compress a block of data.
+ *
+ * \details This function compresses a specified block of data in LZ77 encoding.
+ * Depending on the size of the input data and speed of the computer, compression
+ * may take a while to complete.
+ *
+ * \param[out] *outBuff Pointer to buffer to store compressed data.
+ * \param[in] *inBuff Pointer to data to compress.
+ * \param[in] inSize Size of data to compress in bytes.
+ * \param[in] level Compression level (see \ref compLevels).
+ *
+ * \returns The size of the compressed data in bytes.
+ */
+int lzCompress(void* outBuff, void* inBuff, int inSize, int level);
+
+/*! Decompress a compressed block of data.
+ *
+ * \details Decompressed a compressed block of data produced by lzCompress(). It cannot
+ * return the decompressed size of the data ahead of time so you must preserve the decompressed
+ * size of the data yourself.
+ *
+ * \note The decompression algorithm used in this function is completely independent
+ * of the compression settings set by lzSetHashSizes() before compressing the data with
+ * lzCompress().
+ *
+ * \param[out] *outBuff Pointer to buffer to store decompressed data.
+ * \param[in] *inBuff Pointer to compressed data to decompress.
+ * \param[in] inSize Compressed data size in bytes.
+ *
+ * \returns Size of decompressed data in bytes or LZP_ERR_DECOMPRESS if a
+ * decompression error occurred.
+ */
+int lzDecompress(void* outBuff, void* inBuff, int inSize);
+
+int lzDecompressLen(void* outBuff, int outSize, void* inBuff, int inSize);
+
+/*! Sets the sizes of hash tables for data compression.
+ *
+ * \param[in] window Sliding window size.
+ * \param[in] hash1 Hash table 1 size.
+ * \param[in] hash2 Hash table 2 size.
+ */
+void lzSetHashSizes(int window, int hash1, int hash2);
+
+/*! Reset the sizes of hash tables to their defaults.
+ */
+void lzResetHashSizes();
+
+/*! @} */
+
+
+/*! \addtogroup crcFuncs CRC Hashing Functions
+ * \brief Functions to calculate CRC hashes of data.
+ * @{
+ */
+
+/*! Calculates a CRC16 hash of the specified buffer.
+ *
+ * \param[in] *buff Pointer to buffer to calculate a hash of.
+ * \param[in] bytes Size of buffer in bytes.
+ * \param[in] crc CRC remainder (use LZP_CRC16_REMAINDER).
+ *
+ * \returns CRC16 hash of specified buffer.
+ */
+unsigned short lzCRC16(void* buff, int bytes, unsigned short crc);
+
+/*! Calculates a CRC32 hash of the specified buffer.
+ *
+ * \param[in] *buff Pointer to buffer to calculate a hash of.
+ * \param[in] bytes Size of buffer in bytes.
+ * \param[in] crc CRC remainder (use LZP_CRC16_REMAINDER).
+ *
+ * \returns CRC32 hash of specified buffer.
+ */
+unsigned int lzCRC32(void* buff, int bytes, unsigned int crc);
+
+/*! @} */
+
+
+/*! \addtogroup lzpFunctions LZP Archive Handling Routines
+ * \brief Functions to index and unpack files from LZP archives.
+ * @{
+ */
+
+/*! Searches for a file by name in an LZP archive and returns a file entry number.
+ *
+ * \param[in] *fileName String of file to search (must be less than 13 characters).
+ * \param[in] *lzpack Pointer to LZP archive file.
+ *
+ * \returns File index of found file or one of \ref libraryErrorCodes if an error occurred.
+ */
+int lzpSearchFile(const char* fileName, void* lzpack);
+
+int lzpFileSize(void* lzpack, int fileNum);
+
+/*! Get a pointer to a file entry inside of an LZP archive.
+ *
+ * \param[in] *lzpack Pointer to LZP archive file.
+ * \param[in] fileNum File number to get an entry of (you may use lzpSearchFile()).
+ *
+ * \returns A pointer to an LZP_FILE struct or NULL if an error occurred.
+ */
+LZP_FILE* lzpFileEntry(void* lzpack, int fileNum);
+
+/*! Unpacks a file from an LZP archive to the specified memory buffer.
+ *
+ * \param[in] *buff Pointer to buffer to store unpacked file.
+ * \param[in] *lzpack Pointer to LZP archive file.
+ * \param[in] fileNum File entry number of file to extract (you may use lzpSearchFile()).
+ *
+ * \returns Size of decompressed file in bytes or one of \ref libraryErrorCodes if an error occurred.
+ */
+int lzpUnpackFile(void* buff, void* lzpack, int fileNum);
+
+/*! @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _LZPACK_H
diff --git a/libpsn00b/lzp/lzqlp.h b/libpsn00b/lzp/lzqlp.h
new file mode 100644
index 0000000..fae6438
--- /dev/null
+++ b/libpsn00b/lzp/lzqlp.h
@@ -0,0 +1,26 @@
+#ifndef _QLP_H
+#define _QLP_H
+
+#define PACK_ERR_NONE 0
+#define PACK_ERR_INVALID -1
+#define PACK_ERR_NOTFOUND -2
+#define PACK_ERR_INCOMPLETE -3
+#define PACK_ERR_READ_FAULT -4
+
+typedef struct {
+ char id[3];
+ unsigned char numfiles;
+} QLP_HEAD;
+
+typedef struct {
+ char name[16];
+ unsigned int size;
+ unsigned int offs;
+} QLP_FILE;
+
+int qlpFileCount(void* qlpfile);
+QLP_FILE* qlpFileEntry(int index, void* qlpfile);
+void* qlpFileAddr(int index, void* qlpfile);
+int qlpFindFile(char* fileName, void* qlpfile);
+
+#endif // _QLP_H \ No newline at end of file
diff --git a/libpsn00b/lzp/makefile b/libpsn00b/lzp/makefile
new file mode 100644
index 0000000..cf82872
--- /dev/null
+++ b/libpsn00b/lzp/makefile
@@ -0,0 +1,28 @@
+PREFIX = mipsel-unknown-elf-
+
+TARGET = liblzp.a
+
+CFILES = $(notdir $(wildcard ./*.c))
+OFILES = $(addprefix build/,$(CFILES:.c=.o))
+
+INCLUDE = -I../include
+
+CFLAGS = -O2 -msoft-float -fno-builtin -nostdlib -Wa,--strip-local-absolute
+AFLAGS = -msoft-float --strip-local-absolute
+
+CC = $(PREFIX)gcc
+AR = $(PREFIX)ar
+RANLIB = $(PREFIX)ranlib
+
+all: $(TARGET)
+
+$(TARGET): $(OFILES)
+ $(AR) cr $(TARGET) $(OFILES)
+ $(RANLIB) $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p build
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -Rf build $(OFILES) $(TARGET)
diff --git a/libpsn00b/lzp/qlp.c b/libpsn00b/lzp/qlp.c
new file mode 100644
index 0000000..3be8356
--- /dev/null
+++ b/libpsn00b/lzp/qlp.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "lzqlp.h"
+
+static char* lcase(char* str) {
+
+ while(*str != 0x00) {
+ *str = tolower(*str);
+ str++;
+ }
+
+ return(str);
+
+}
+
+int qlpFileCount(void* qlpfile) {
+
+ if (strncmp(((QLP_HEAD*)qlpfile)->id, "QLP", 3) != 0)
+ return(PACK_ERR_INVALID);
+
+ return(((QLP_HEAD*)qlpfile)->numfiles);
+
+}
+
+QLP_FILE* qlpFileEntry(int index, void* qlpfile) {
+
+ if (strncmp(((QLP_HEAD*)qlpfile)->id, "QLP", 3) != 0)
+ return(NULL);
+
+ if (index > ((QLP_HEAD*)qlpfile)->numfiles)
+ return(NULL);
+
+ return(&((QLP_FILE*)(qlpfile+4))[index]);
+
+}
+
+void* qlpFileAddr(int index, void* qlpfile) {
+
+ return( qlpfile+((QLP_FILE*)(qlpfile+4))[index].offs );
+
+}
+
+int qlpFindFile(char* fileName, void* qlpfile) {
+
+ int i;
+ char nameBuff[2][16];
+
+ strcpy(nameBuff[0], fileName);
+ lcase(nameBuff[0]);
+
+ for(i=0; i<((QLP_HEAD*)qlpfile)->numfiles; i++) {
+
+ strcpy(nameBuff[1], ((QLP_FILE*)(qlpfile+4))[i].name);
+ lcase(nameBuff[1]);
+
+ if (strcmp(nameBuff[0], nameBuff[1]) == 0)
+ return(i);
+
+ }
+
+ return(PACK_ERR_NOTFOUND);
+
+} \ No newline at end of file