From f4492cdb8d09f8e833aa755586ecba2b54f6d7cf Mon Sep 17 00:00:00 2001 From: cielavenir Date: Fri, 8 Oct 2021 03:38:26 +0900 Subject: [PATCH 1/8] Add PKImplodeDecoder --- C/blast/blast.c | 466 +++++++++++++++++++++++++ C/blast/blast.h | 83 +++++ CPP/7zip/Archive/Zip/ZipHandler.cpp | 3 + CPP/7zip/Compress/PKImplodeDecoder.cpp | 71 ++++ CPP/7zip/Compress/PKImplodeDecoder.h | 45 +++ Utils/file_7z_so.py | 2 + Utils/file_7za.py | 4 +- 7 files changed, 673 insertions(+), 1 deletion(-) create mode 100644 C/blast/blast.c create mode 100644 C/blast/blast.h create mode 100644 CPP/7zip/Compress/PKImplodeDecoder.cpp create mode 100644 CPP/7zip/Compress/PKImplodeDecoder.h diff --git a/C/blast/blast.c b/C/blast/blast.c new file mode 100644 index 000000000..e6e659073 --- /dev/null +++ b/C/blast/blast.c @@ -0,0 +1,466 @@ +/* blast.c + * Copyright (C) 2003, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in blast.h + * version 1.3, 24 Aug 2013 + * + * blast.c decompresses data compressed by the PKWare Compression Library. + * This function provides functionality similar to the explode() function of + * the PKWare library, hence the name "blast". + * + * This decompressor is based on the excellent format description provided by + * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the + * example Ben provided in the post is incorrect. The distance 110001 should + * instead be 111000. When corrected, the example byte stream becomes: + * + * 00 04 82 24 25 8f 80 7f + * + * which decompresses to "AIAIAIAIAIAIA" (without the quotes). + */ + +/* + * Change history: + * + * 1.0 12 Feb 2003 - First version + * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data + * 1.2 24 Oct 2012 - Add note about using binary mode in stdio + * - Fix comparisons of differently signed integers + * 1.3 24 Aug 2013 - Return unused input from blast() + * - Fix test code to correctly report unused input + * - Enable the provision of initial input to blast() + */ + +#include /* for NULL */ +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "blast.h" /* prototype for blast() */ + +#define local static /* for local function definitions */ +#define MAXBITS 13 /* maximum code length */ +#define MAXWIN 4096 /* maximum window size */ + +/* input and output state */ +struct state { + /* input state */ + blast_in infun; /* input function provided by user */ + void *inhow; /* opaque information passed to infun() */ + unsigned char *in; /* next input location */ + unsigned left; /* available input at in */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; + + /* output state */ + blast_out outfun; /* output function provided by user */ + void *outhow; /* opaque information passed to outfun() */ + unsigned next; /* index of next write location in out[] */ + int first; /* true to check distances (for first 4K) */ + unsigned char out[MAXWIN]; /* output buffer and sliding window */ +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + int val; /* bit accumulator */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ + s->left--; + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = val >> need; + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return val & ((1 << need) - 1); +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. + * + * - The first code for the shortest length is all ones. Subsequent codes of + * the same length are simply integer decrements of the previous code. When + * moving up a length, a one bit is appended to the code. For a complete + * code, the last code of the longest length will be all zeros. To support + * this ordering, the bits pulled during decoding are inverted to apply the + * more "natural" ordering starting with all zeros and incrementing. + */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= (bitbuf & 1) ^ 1; /* invert code */ + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + bitbuf = *(s->in)++; + s->left--; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} + +/* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + */ +local int construct(struct huffman *h, const unsigned char *rep, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short length[256]; /* code lengths */ + + /* convert compact repeat counts into symbol bit length list */ + symbol = 0; + do { + len = *rep++; + left = (len >> 4) + 1; + len &= 15; + do { + length[symbol++] = len; + } while (--left); + } while (--n); + n = symbol; + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode PKWare Compression Library stream. + * + * Format notes: + * + * - First byte is 0 if literals are uncoded or 1 if they are coded. Second + * byte is 4, 5, or 6 for the number of extra bits in the distance code. + * This is the base-2 logarithm of the dictionary size minus six. + * + * - Compressed data is a combination of literals and length/distance pairs + * terminated by an end code. Literals are either Huffman coded or + * uncoded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - A bit preceding a literal or length/distance pair indicates which comes + * next, 0 for literals, 1 for length/distance. + * + * - If literals are uncoded, then the next eight bits are the literal, in the + * normal bit order in the stream, i.e. no bit-reversal is needed. Similarly, + * no bit reversal is needed for either the length extra bits or the distance + * extra bits. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 518 + * simply copies the last byte 518 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. + */ +local int decomp(struct state *s) +{ + int lit; /* true if literals are coded */ + int dict; /* log2(dictionary size) - 6 */ + int symbol; /* decoded symbol, extra bits for distance */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + int copy; /* copy counter */ + unsigned char *from, *to; /* copy pointers */ + static int virgin = 1; /* build tables once */ + static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ + static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ + static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ + static struct huffman litcode = {litcnt, litsym}; /* length code */ + static struct huffman lencode = {lencnt, lensym}; /* length code */ + static struct huffman distcode = {distcnt, distsym};/* distance code */ + /* bit lengths of literal codes */ + static const unsigned char litlen[] = { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, + 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, + 44, 173}; + /* bit lengths of length codes 0..15 */ + static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; + /* bit lengths of distance codes 0..63 */ + static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; + static const short base[16] = { /* base for length codes */ + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; + static const char extra[16] = { /* extra bits for length codes */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; + + /* set up decoding tables (once--might not be thread-safe) */ + if (virgin) { + construct(&litcode, litlen, sizeof(litlen)); + construct(&lencode, lenlen, sizeof(lenlen)); + construct(&distcode, distlen, sizeof(distlen)); + virgin = 0; + } + + /* read header */ + lit = bits(s, 8); + if (lit > 1) return -1; + dict = bits(s, 8); + if (dict < 4 || dict > 6) return -2; + + /* decode literals and length/distance pairs */ + do { + if (bits(s, 1)) { + /* get length */ + symbol = decode(s, &lencode); + len = base[symbol] + bits(s, extra[symbol]); + if (len == 519) break; /* end code */ + + /* get distance */ + symbol = len == 2 ? 2 : dict; + dist = decode(s, &distcode) << symbol; + dist += bits(s, symbol); + dist++; + if (s->first && dist > s->next) + return -3; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + do { + to = s->out + s->next; + from = to - dist; + copy = MAXWIN; + if (s->next < dist) { + from += copy; + copy = dist; + } + copy -= s->next; + if (copy > len) copy = len; + len -= copy; + s->next += copy; + do { + *to++ = *from++; + } while (--copy); + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } while (len != 0); + } + else { + /* get literal and write it */ + symbol = lit ? decode(s, &litcode) : bits(s, 8); + s->out[s->next++] = symbol; + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } + } while (1); + return 0; +} + +/* See comments in blast.h */ +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, + unsigned *left, unsigned char **in) +{ + struct state s; /* input/output state */ + int err; /* return value */ + + /* initialize input state */ + s.infun = infun; + s.inhow = inhow; + if (left != NULL && *left) { + s.left = *left; + s.in = *in; + } + else + s.left = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* initialize output state */ + s.outfun = outfun; + s.outhow = outhow; + s.next = 0; + s.first = 1; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ + err = 2; /* then skip decomp(), return error */ + else + err = decomp(&s); /* decompress */ + + /* return unused input */ + if (left != NULL) + *left = s.left; + if (in != NULL) + *in = s.left ? s.in : NULL; + + /* write any leftover output and update the error code if needed */ + if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) + err = 1; + return err; +} + +#ifdef TEST +/* Example of how to use blast() */ +#include +#include + +#define CHUNK 16384 + +local unsigned inf(void *how, unsigned char **buf) +{ + static unsigned char hold[CHUNK]; + + *buf = hold; + return fread(hold, 1, CHUNK, (FILE *)how); +} + +local int outf(void *how, unsigned char *buf, unsigned len) +{ + return fwrite(buf, 1, len, (FILE *)how) != len; +} + +/* Decompress a PKWare Compression Library stream from stdin to stdout */ +int main(void) +{ + int ret; + unsigned left; + + /* decompress to stdout */ + left = 0; + ret = blast(inf, stdin, outf, stdout, &left, NULL); + if (ret != 0) + fprintf(stderr, "blast error: %d\n", ret); + + /* count any leftover bytes */ + while (getchar() != EOF) + left++; + if (left) + fprintf(stderr, "blast warning: %u unused bytes of input\n", left); + + /* return blast() error code */ + return ret; +} +#endif diff --git a/C/blast/blast.h b/C/blast/blast.h new file mode 100644 index 000000000..6cf65eda1 --- /dev/null +++ b/C/blast/blast.h @@ -0,0 +1,83 @@ +/* blast.h -- interface for blast.c + Copyright (C) 2003, 2012, 2013 Mark Adler + version 1.3, 24 Aug 2013 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * blast() decompresses the PKWare Data Compression Library (DCL) compressed + * format. It provides the same functionality as the explode() function in + * that library. (Note: PKWare overused the "implode" verb, and the format + * used by their library implode() function is completely different and + * incompatible with the implode compression method supported by PKZIP.) + * + * The binary mode for stdio functions should be used to assure that the + * compressed data is not corrupted when read or written. For example: + * fopen(..., "rb") and fopen(..., "wb"). + */ + + +typedef unsigned (*blast_in)(void *how, unsigned char **buf); +typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); +/* Definitions for input/output functions passed to blast(). See below for + * what the provided functions need to do. + */ + + +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, + unsigned *left, unsigned char **in); +/* Decompress input to output using the provided infun() and outfun() calls. + * On success, the return value of blast() is zero. If there is an error in + * the source data, i.e. it is not in the proper format, then a negative value + * is returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. + * + * The input function is invoked: len = infun(how, &buf), where buf is set by + * infun() to point to the input buffer, and infun() returns the number of + * available bytes there. If infun() returns zero, then blast() returns with + * an input error. (blast() only asks for input if it needs it.) inhow is for + * use by the application to pass an input descriptor to infun(), if desired. + * + * If left and in are not NULL and *left is not zero when blast() is called, + * then the *left bytes are *in are consumed for input before infun() is used. + * + * The output function is invoked: err = outfun(how, buf, len), where the bytes + * to be written are buf[0..len-1]. If err is not zero, then blast() returns + * with an output error. outfun() is always called with len <= 4096. outhow + * is for use by the application to pass an output descriptor to outfun(), if + * desired. + * + * If there is any unused input, *left is set to the number of bytes that were + * read and *in points to them. Otherwise *left is set to zero and *in is set + * to NULL. If left or in are NULL, then they are not set. + * + * The return codes are: + * + * 2: ran out of input before completing decompression + * 1: output error before completing decompression + * 0: successful decompression + * -1: literal flag not zero or one + * -2: dictionary size not in 4..6 + * -3: distance is too far back + * + * At the bottom of blast.c is an example program that uses blast() that can be + * compiled to produce a command-line decompression filter by defining TEST. + */ diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index 480f18db0..f59810b16 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -24,6 +24,7 @@ #include "../../Compress/ShrinkDecoder.h" #include "../../Compress/XzDecoder.h" #include "../../Compress/ZstdDecoder.h" +#include "../../Compress/PKImplodeDecoder.h" #include "../../Crypto/WzAes.h" #include "../../Crypto/ZipCrypto.h" @@ -976,6 +977,8 @@ HRESULT CZipDecoder::Decode( mi.Coder = new CZstdDecoder(); else if (id == NFileHeader::NCompressionMethod::kXz) mi.Coder = new NCompress::NXz::CComDecoder; + else if (id == NFileHeader::NCompressionMethod::kPKImploding) + mi.Coder = new NCompress::NPKImplode::NDecoder::CCoder; else if (id == NFileHeader::NCompressionMethod::kPPMd) mi.Coder = new NCompress::NPpmdZip::CDecoder(true); else diff --git a/CPP/7zip/Compress/PKImplodeDecoder.cpp b/CPP/7zip/Compress/PKImplodeDecoder.cpp new file mode 100644 index 000000000..bb88e7672 --- /dev/null +++ b/CPP/7zip/Compress/PKImplodeDecoder.cpp @@ -0,0 +1,71 @@ +// ImplodeDecoder.cpp + +#include +#include "StdAfx.h" + +#include "../../Common/Defs.h" + +#include "PKImplodeDecoder.h" +#include "../../Common/StreamUtils.h" + +extern "C" { +#include "../../../C/blast/blast.h" +} + +namespace NCompress { +namespace NPKImplode { +namespace NDecoder { + +static int BLAST_put(void *out_desc, unsigned char *buf, unsigned int len){ + CCoder *w = (CCoder*)out_desc; + UInt32 rlen=0; + HRESULT res = w->outS->Write(buf, len, &rlen); + w->processedOut += rlen; + if(w->progr) + w->progr->SetRatioInfo(&w->processedIn, &w->processedOut); + return res != S_OK || rlen != len; +} + +static unsigned int BLAST_get(void *in_desc, unsigned char **buf){ + CCoder *r = (CCoder*)in_desc; + *buf = r->buf; + size_t readsize = kS; + HRESULT res = ReadStream(r->inS,r->buf,&readsize); + r->processedIn += readsize; + return res != S_OK ? 0 : readsize; +} + +CCoder::CCoder(){} + +HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + inS = inStream; + outS = outStream; + progr = progress; + processedIn = processedOut = 0; + int x = blast(BLAST_get, this, BLAST_put, this, NULL, NULL); + if(x<0)return E_FAIL; + if(x==2)return E_ABORT; + if(x==1)return E_OUTOFMEMORY; + return x==0 ? S_OK : E_FAIL; +} + + +STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = processedIn; + return S_OK; +} + +}}} + diff --git a/CPP/7zip/Compress/PKImplodeDecoder.h b/CPP/7zip/Compress/PKImplodeDecoder.h new file mode 100644 index 000000000..5c888e980 --- /dev/null +++ b/CPP/7zip/Compress/PKImplodeDecoder.h @@ -0,0 +1,45 @@ +// ImplodeDecoder.h + +#ifndef __COMPRESS_PKIMPLODE_DECODER_H +#define __COMPRESS_PKIMPLODE_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +namespace NCompress { +namespace NPKImplode { +namespace NDecoder { + +static const unsigned int kS = 65536; + +class CCoder: + public ICompressCoder, + public ICompressGetInStreamProcessedSize, + public CMyUnknownImp +{ + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + +public: + unsigned char buf[kS]; + UInt64 processedIn; + UInt64 processedOut; + ISequentialInStream *inS; + ISequentialOutStream *outS; + ICompressProgressInfo *progr; + + MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + CCoder(); +}; + +}}} + +#endif diff --git a/Utils/file_7z_so.py b/Utils/file_7z_so.py index fd49e76c1..513029711 100644 --- a/Utils/file_7z_so.py +++ b/Utils/file_7z_so.py @@ -134,6 +134,7 @@ 'C/brotli/br_static_dict.c', 'C/brotli/br_transform.c', 'C/brotli/br_utf8_util.c', + 'C/blast/blast.c', 'C/hashes/md2.c', 'C/hashes/md4.c', 'C/hashes/md5.c', @@ -330,6 +331,7 @@ 'CPP/7zip/Compress/BrotliDecoder.cpp', 'CPP/7zip/Compress/BrotliEncoder.cpp', 'CPP/7zip/Compress/BrotliRegister.cpp', + 'CPP/7zip/Compress/PKImplodeDecoder.cpp', 'CPP/7zip/Crypto/7zAes.cpp', 'CPP/7zip/Crypto/7zAesRegister.cpp', 'CPP/7zip/Crypto/HmacSha1.cpp', diff --git a/Utils/file_7za.py b/Utils/file_7za.py index 2ba9e343f..24f5a5c83 100644 --- a/Utils/file_7za.py +++ b/Utils/file_7za.py @@ -131,7 +131,8 @@ 'C/brotli/br_state.c', 'C/brotli/br_static_dict.c', 'C/brotli/br_transform.c', - 'C/brotli/br_utf8_util.c' + 'C/brotli/br_utf8_util.c', + 'C/blast/blast.c', ] files_cpp=[ @@ -267,6 +268,7 @@ 'CPP/7zip/Compress/BrotliDecoder.cpp', 'CPP/7zip/Compress/BrotliEncoder.cpp', 'CPP/7zip/Compress/BrotliRegister.cpp', + 'CPP/7zip/Compress/PKImplodeDecoder.cpp', 'CPP/7zip/Crypto/7zAes.cpp', 'CPP/7zip/Crypto/7zAesRegister.cpp', 'CPP/7zip/Crypto/HmacSha1.cpp', From 5e90c272a2e43c36fc8f1fecfcbe2e7f3617af64 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 3 Jan 2022 21:57:53 +0900 Subject: [PATCH 2/8] changed pkimplode class name --- CPP/7zip/Archive/Zip/ZipHandler.cpp | 2 +- CPP/7zip/Compress/PKImplodeDecoder.cpp | 12 ++++++------ CPP/7zip/Compress/PKImplodeDecoder.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index f59810b16..f4c4b5f0d 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -978,7 +978,7 @@ HRESULT CZipDecoder::Decode( else if (id == NFileHeader::NCompressionMethod::kXz) mi.Coder = new NCompress::NXz::CComDecoder; else if (id == NFileHeader::NCompressionMethod::kPKImploding) - mi.Coder = new NCompress::NPKImplode::NDecoder::CCoder; + mi.Coder = new NCompress::NPKImplode::NDecoder::CDecoder; else if (id == NFileHeader::NCompressionMethod::kPPMd) mi.Coder = new NCompress::NPpmdZip::CDecoder(true); else diff --git a/CPP/7zip/Compress/PKImplodeDecoder.cpp b/CPP/7zip/Compress/PKImplodeDecoder.cpp index bb88e7672..1a53274a1 100644 --- a/CPP/7zip/Compress/PKImplodeDecoder.cpp +++ b/CPP/7zip/Compress/PKImplodeDecoder.cpp @@ -17,7 +17,7 @@ namespace NPKImplode { namespace NDecoder { static int BLAST_put(void *out_desc, unsigned char *buf, unsigned int len){ - CCoder *w = (CCoder*)out_desc; + CDecoder *w = (CDecoder*)out_desc; UInt32 rlen=0; HRESULT res = w->outS->Write(buf, len, &rlen); w->processedOut += rlen; @@ -27,7 +27,7 @@ static int BLAST_put(void *out_desc, unsigned char *buf, unsigned int len){ } static unsigned int BLAST_get(void *in_desc, unsigned char **buf){ - CCoder *r = (CCoder*)in_desc; + CDecoder *r = (CDecoder*)in_desc; *buf = r->buf; size_t readsize = kS; HRESULT res = ReadStream(r->inS,r->buf,&readsize); @@ -35,9 +35,9 @@ static unsigned int BLAST_get(void *in_desc, unsigned char **buf){ return res != S_OK ? 0 : readsize; } -CCoder::CCoder(){} +CDecoder::CDecoder(){} -HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) { inS = inStream; @@ -52,7 +52,7 @@ HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *ou } -STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) { try { return CodeReal(inStream, outStream, inSize, outSize, progress); } @@ -61,7 +61,7 @@ STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *o catch(...) { return S_FALSE; } } -STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value) +STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = processedIn; return S_OK; diff --git a/CPP/7zip/Compress/PKImplodeDecoder.h b/CPP/7zip/Compress/PKImplodeDecoder.h index 5c888e980..99f8da3b7 100644 --- a/CPP/7zip/Compress/PKImplodeDecoder.h +++ b/CPP/7zip/Compress/PKImplodeDecoder.h @@ -15,7 +15,7 @@ namespace NDecoder { static const unsigned int kS = 65536; -class CCoder: +class CDecoder: public ICompressCoder, public ICompressGetInStreamProcessedSize, public CMyUnknownImp @@ -37,7 +37,7 @@ class CCoder: const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); - CCoder(); + CDecoder(); }; }}} From a816ddc3057a7b884c69d3de9ec54c669a5f2974 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 3 Jan 2022 21:59:21 +0900 Subject: [PATCH 3/8] register pkimplode --- CPP/7zip/Compress/PKImplode/makefile | 39 ++++++++++++ CPP/7zip/Compress/PKImplode/makefile.depend | 0 CPP/7zip/Compress/PKImplode/makefile.list | 69 +++++++++++++++++++++ CPP/7zip/Compress/PKImplodeRegister.cpp | 20 ++++++ Utils/file_Codecs_PKImplode_so.py | 23 +++++++ Utils/generate.py | 41 +++++++++++- 6 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 CPP/7zip/Compress/PKImplode/makefile create mode 100644 CPP/7zip/Compress/PKImplode/makefile.depend create mode 100644 CPP/7zip/Compress/PKImplode/makefile.list create mode 100644 CPP/7zip/Compress/PKImplodeRegister.cpp create mode 100644 Utils/file_Codecs_PKImplode_so.py diff --git a/CPP/7zip/Compress/PKImplode/makefile b/CPP/7zip/Compress/PKImplode/makefile new file mode 100644 index 000000000..c09dd9a70 --- /dev/null +++ b/CPP/7zip/Compress/PKImplode/makefile @@ -0,0 +1,39 @@ + +TARGET_FLAGS=$(CC_SHARED) -DRegisterCodec=DllRegisterCodec + +MY_WINDOWS= + +include ../../../../makefile.crc32 +include ../../../../makefile.machine + +LOCAL_LINK=$(LINK_SHARED) +LIBS=$(LOCAL_LIBS) + +COMPRESS_OBJS = \ + CodecExports.o \ + DllExportsCompress.o \ + +OPT_OBJS = \ + PKImplodeDecoder.o \ + PKImplodeRegister.o \ + +COMMON_OBJS = + +P7ZIP_COMMON_OBJS = \ + InBuffer.o \ + OutBuffer.o \ + StreamUtils.o \ + +C_OBJS = \ + blast/blast.o \ + +OBJS = \ +MyWindows.o \ +$(COMPRESS_OBJS) \ +$(OPT_OBJS) \ +$(COMMON_OBJS) \ +$(P7ZIP_COMMON_OBJS) \ +$(C_OBJS) \ + +include ../../../../makefile.glb + diff --git a/CPP/7zip/Compress/PKImplode/makefile.depend b/CPP/7zip/Compress/PKImplode/makefile.depend new file mode 100644 index 000000000..e69de29bb diff --git a/CPP/7zip/Compress/PKImplode/makefile.list b/CPP/7zip/Compress/PKImplode/makefile.list new file mode 100644 index 000000000..e31504e02 --- /dev/null +++ b/CPP/7zip/Compress/PKImplode/makefile.list @@ -0,0 +1,69 @@ + + +# WARNING : automatically generated by utils/generate.py + +PROG=../../../../bin/Codecs/PKImplode.so + +all: $(PCH_NAME) $(PROG) + +LOCAL_FLAGS=$(TARGET_FLAGS) \ + -DEXTERNAL_CODECS \ + -D_FILE_OFFSET_BITS=64 \ + -D_LARGEFILE_SOURCE \ + -D_REENTRANT \ + -DENV_UNIX \ + -DBREAK_HANDLER \ + -DUNICODE \ + -D_UNICODE \ + -DUNIX_USE_WIN_FILE \ + +SRCS=\ + ../../../../CPP/7zip/Common/InBuffer.cpp \ + ../../../../CPP/7zip/Common/OutBuffer.cpp \ + ../../../../CPP/7zip/Common/StreamUtils.cpp \ + ../../../../CPP/7zip/Compress/CodecExports.cpp \ + ../../../../CPP/7zip/Compress/DllExportsCompress.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ + ../../../../CPP/Common/MyWindows.cpp \ + +SRCS_C=\ + ../../../../C/blast/blast.c \ + ../../../../C/Alloc.c \ + +StdAfx.h.gch : ../../../myWindows/StdAfx.h + rm -f StdAfx.h.gch + $(CXX) $(CXXFLAGS) ../../../myWindows/StdAfx.h -o StdAfx.h.gch +blast.o : ../../../../C/blast/blast.c + $(CC) $(CFLAGS) ../../../../C/blast/blast.c +Alloc.o : ../../../../C/Alloc.c + $(CC) $(CFLAGS) ../../../../C/Alloc.c +InBuffer.o : ../../../../CPP/7zip/Common/InBuffer.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Common/InBuffer.cpp +OutBuffer.o : ../../../../CPP/7zip/Common/OutBuffer.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Common/OutBuffer.cpp +StreamUtils.o : ../../../../CPP/7zip/Common/StreamUtils.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Common/StreamUtils.cpp +CodecExports.o : ../../../../CPP/7zip/Compress/CodecExports.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/CodecExports.cpp +DllExportsCompress.o : ../../../../CPP/7zip/Compress/DllExportsCompress.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/DllExportsCompress.cpp +PKImplodeDecoder.o : ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp +PKImplodeRegister.o : ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp +MyWindows.o : ../../../../CPP/Common/MyWindows.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/Common/MyWindows.cpp + +OBJS=\ + blast.o \ + Alloc.o \ + InBuffer.o \ + OutBuffer.o \ + StreamUtils.o \ + CodecExports.o \ + DllExportsCompress.o \ + PKImplodeDecoder.o \ + PKImplodeRegister.o \ + MyWindows.o \ + diff --git a/CPP/7zip/Compress/PKImplodeRegister.cpp b/CPP/7zip/Compress/PKImplodeRegister.cpp new file mode 100644 index 000000000..65e13a5d0 --- /dev/null +++ b/CPP/7zip/Compress/PKImplodeRegister.cpp @@ -0,0 +1,20 @@ +// PKImplodeRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "PKImplodeDecoder.h" + +namespace NCompress { + +REGISTER_CODEC_CREATE(CreateCodecPKImplode, NPKImplode::NDecoder::CDecoder()) + +REGISTER_CODECS_VAR +{ + { CreateCodecPKImplode, NULL, 0x4010a, "PKImplode", 1, false } +}; + +REGISTER_CODECS(PKImplode) + +} diff --git a/Utils/file_Codecs_PKImplode_so.py b/Utils/file_Codecs_PKImplode_so.py new file mode 100644 index 000000000..046d6c97f --- /dev/null +++ b/Utils/file_Codecs_PKImplode_so.py @@ -0,0 +1,23 @@ + +files_c=[ + 'C/blast/blast.c', + #'C/7zCrcOpt.c', + 'C/Alloc.c', + #'C/CpuArch.c', + #'C/Ppmd7.c', + #'C/Ppmd7Dec.c', +] + +files_cpp=[ + 'CPP/7zip/Common/InBuffer.cpp', + 'CPP/7zip/Common/OutBuffer.cpp', + 'CPP/7zip/Common/StreamUtils.cpp', + 'CPP/7zip/Compress/CodecExports.cpp', + 'CPP/7zip/Compress/DllExportsCompress.cpp', + 'CPP/7zip/Compress/PKImplodeDecoder.cpp', + 'CPP/7zip/Compress/PKImplodeRegister.cpp', + #'CPP/Common/CRC.cpp', + #'CPP/Common/MyVector.cpp', + 'CPP/Common/MyWindows.cpp', +] + diff --git a/Utils/generate.py b/Utils/generate.py index 4b42d8c52..0013b9519 100644 --- a/Utils/generate.py +++ b/Utils/generate.py @@ -283,6 +283,7 @@ def generate_android_mk(filename,project): import file_7z_so import file_Codecs_Rar_so import file_Codecs_Lzham_so +import file_Codecs_PKImplode_so import file_LzmaCon import file_Client7z import file_P7ZIP @@ -480,8 +481,6 @@ def generate_android_mk(filename,project): -I../../../include_windows ''') - - project_Codecs_Lzham=Structure(name="Lzham",name2="Lzham", type=TYPE_DLL, need_AES=False, @@ -522,6 +521,43 @@ def generate_android_mk(filename,project): ''') +project_Codecs_PKImplode=Structure(name="PKImplode",name2="PKImplode", + type=TYPE_DLL, + need_AES=False, + includedirs=includedirs_7za, + defines=[ "EXTERNAL_CODECS", "_FILE_OFFSET_BITS=64", "_LARGEFILE_SOURCE", "_REENTRANT", "ENV_UNIX", "BREAK_HANDLER", "UNICODE", "_UNICODE", "UNIX_USE_WIN_FILE" ], + files_c=file_Codecs_PKImplode_so.files_c, + files_cpp=file_Codecs_PKImplode_so.files_cpp, + cmake_end=''' + +SET_TARGET_PROPERTIES(PKImplode PROPERTIES PREFIX "") + +find_library(DL_LIB dl) + +link_directories(${DL_LIB_PATH}) + +IF(APPLE) + TARGET_LINK_LIBRARIES(Rar ${COREFOUNDATION_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) +ELSE(APPLE) + IF(HAVE_PTHREADS) + TARGET_LINK_LIBRARIES(Rar ${CMAKE_THREAD_LIBS_INIT} dl) + ENDIF(HAVE_PTHREADS) +ENDIF(APPLE) + +''', +android_header=r''' +LOCAL_CFLAGS := -DANDROID_NDK -fexceptions \ + -DNDEBUG -D_REENTRANT -DENV_UNIX \ + -DEXTERNAL_CODECS \ + -DBREAK_HANDLER \ + -DUNICODE -D_UNICODE -DUNIX_USE_WIN_FILE \ + -I../../../Windows \ + -I../../../Common \ + -I../../../../C \ +-I../../../myWindows \ +-I../../../ \ +-I../../../include_windows +''') project_7zG=Structure(name="7zG",name2="7zG", type=TYPE_EXE, @@ -768,6 +804,7 @@ def generate_android_mk(filename,project): generate_makefile_list('../CPP/7zip/Bundles/Format7zFree/makefile.list',project_Format7zFree) generate_makefile_list('../CPP/7zip/Compress/Rar/makefile.list',project_Codecs_Rar,'../../../../bin/Codecs') generate_makefile_list('../CPP/7zip/Compress/Lzham/makefile.list',project_Codecs_Lzham,'../../../../bin/Codecs') +generate_makefile_list('../CPP/7zip/Compress/PKImplode/makefile.list',project_Codecs_PKImplode,'../../../../bin/Codecs') generate_makefile_list('../CPP/7zip/Bundles/SFXCon/makefile.list',project_7zCon_sfx) generate_makefile_list('../CPP/7zip/UI/GUI/makefile.list',project_7zG) generate_makefile_list('../CPP/7zip/UI/FileManager/makefile.list',project_7zFM) From 87a76d240d83e9fc506126be92018cbaa26e5f20 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 3 Jan 2022 23:34:59 +0900 Subject: [PATCH 4/8] add compression --- C/pklib/explode.c | 522 +++++++++++++++++ C/pklib/implode.c | 676 ++++++++++++++++++++++ C/pklib/pklib.h | 158 +++++ CPP/7zip/Compress/PKImplode/makefile.list | 12 + CPP/7zip/Compress/PKImplodeEncoder.cpp | 95 +++ CPP/7zip/Compress/PKImplodeEncoder.h | 52 ++ CPP/7zip/Compress/PKImplodeRegister.cpp | 14 +- Utils/file_Codecs_PKImplode_so.py | 3 + 8 files changed, 1524 insertions(+), 8 deletions(-) create mode 100644 C/pklib/explode.c create mode 100644 C/pklib/implode.c create mode 100644 C/pklib/pklib.h create mode 100644 CPP/7zip/Compress/PKImplodeEncoder.cpp create mode 100644 CPP/7zip/Compress/PKImplodeEncoder.h diff --git a/C/pklib/explode.c b/C/pklib/explode.c new file mode 100644 index 000000000..0f551d8ed --- /dev/null +++ b/C/pklib/explode.c @@ -0,0 +1,522 @@ +/*****************************************************************************/ +/* explode.c Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Implode function of PKWARE Data Compression library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */ +/* 08.04.03 1.01 Lad Renamed to explode.c to be compatible with pklib */ +/* 02.05.03 1.01 Lad Stress test done */ +/* 22.04.10 1.01 Lad Documented */ +/*****************************************************************************/ + +#include +#include + +#include "pklib.h" + +#define PKDCL_OK 0 +#define PKDCL_STREAM_END 1 // All data from the input stream is read +#define PKDCL_NEED_DICT 2 // Need more data (dictionary) +#define PKDCL_CONTINUE 10 // Internal flag, not returned to user +#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user + +char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" + "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" + "Patent No. 5,051,745\r\n" + "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" + "Version 1.11\r\n"; + +//----------------------------------------------------------------------------- +// Tables + +unsigned char DistBits[0x40] = +{ + 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +unsigned char DistCode[0x40] = +{ + 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, + 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 +}; + +unsigned char ExLenBits[0x10] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +}; + +unsigned short LenBase[0x10] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106 +}; + +unsigned char LenBits[0x10] = +{ + 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 +}; + +unsigned char LenCode[0x10] = +{ + 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 +}; + +unsigned char ChBitsAsc[0x100] = +{ + 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, + 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, + 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, + 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, + 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, + 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, + 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D +}; + +unsigned short ChCodeAsc[0x100] = +{ + 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, + 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, + 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, + 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, + 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, + 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, + 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, + 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, + 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, + 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, + 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, + 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, + 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, + 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, + 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, + 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, + 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, + 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, + 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, + 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, + 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, + 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, + 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, + 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, + 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, + 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, + 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, + 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, + 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, + 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, + 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, + 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000 +}; + +//----------------------------------------------------------------------------- +// Local functions + +static void GenDecodeTabs( + unsigned char * positions, // [out] Table of positions + unsigned char * start_indexes, // [in] Table of start indexes + unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits + size_t elements) // [in] Number of elements in start_indexes and length_bits +{ + unsigned int index; + unsigned int length; + size_t i; + + for(i = 0; i < elements; i++) + { + length = 1 << length_bits[i]; // Get the length in bytes + + for(index = start_indexes[i]; index < 0x100; index += length) + { + positions[index] = (unsigned char)i; + } + } +} + +static void GenAscTabs(TDcmpStruct * pWork) +{ + unsigned short * pChCodeAsc = &ChCodeAsc[0xFF]; + unsigned int acc, add; + unsigned short count; + + for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--) + { + unsigned char * pChBitsAsc = pWork->ChBitsAsc + count; + unsigned char bits_asc = *pChBitsAsc; + + if(bits_asc <= 8) + { + add = (1 << bits_asc); + acc = *pChCodeAsc; + + do + { + pWork->offs2C34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + else if((acc = (*pChCodeAsc & 0xFF)) != 0) + { + pWork->offs2C34[acc] = 0xFF; + + if(*pChCodeAsc & 0x3F) + { + bits_asc -= 4; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 4; + do + { + pWork->offs2D34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + else + { + bits_asc -= 6; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 6; + do + { + pWork->offs2E34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x80); + } + } + else + { + bits_asc -= 8; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 8; + do + { + pWork->offs2EB4[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + } +} + +//----------------------------------------------------------------------------- +// Removes given number of bits in the bit buffer. New bits are reloaded from +// the input buffer, if needed. +// Returns: PKDCL_OK: Operation was successful +// PKDCL_STREAM_END: There are no more bits in the input buffer + +static int WasteBits(TDcmpStruct * pWork, unsigned int nBits) +{ + // If number of bits required is less than number of (bits in the buffer) ? + if(nBits <= pWork->extra_bits) + { + pWork->extra_bits -= nBits; + pWork->bit_buff >>= nBits; + return PKDCL_OK; + } + + // Load input buffer if necessary + pWork->bit_buff >>= pWork->extra_bits; + if(pWork->in_pos == pWork->in_bytes) + { + pWork->in_pos = sizeof(pWork->in_buff); + if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0) + return PKDCL_STREAM_END; + pWork->in_pos = 0; + } + + // Update bit buffer + pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8); + pWork->bit_buff >>= (nBits - pWork->extra_bits); + pWork->extra_bits = (pWork->extra_bits - nBits) + 8; + return PKDCL_OK; +} + +//----------------------------------------------------------------------------- +// Decodes next literal from the input (compressed) data. +// Returns : 0x000: One byte 0x00 +// 0x001: One byte 0x01 +// ... +// 0x0FF: One byte 0xFF +// 0x100: Repetition, length of 0x02 bytes +// 0x101: Repetition, length of 0x03 bytes +// ... +// 0x304: Repetition, length of 0x206 bytes +// 0x305: End of stream +// 0x306: Error + +static unsigned int DecodeLit(TDcmpStruct * pWork) +{ + unsigned int extra_length_bits; // Number of bits of extra literal length + unsigned int length_code; // Length code + unsigned int value; + + // Test the current bit in byte buffer. If is not set, simply return the next 8 bits. + if(pWork->bit_buff & 1) + { + // Remove one bit from the input data + if(WasteBits(pWork, 1)) + return 0x306; + + // The next 8 bits hold the index to the length code table + length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF]; + + // Remove the apropriate number of bits + if(WasteBits(pWork, pWork->LenBits[length_code])) + return 0x306; + + // Are there some extra bits for the obtained length code ? + if((extra_length_bits = pWork->ExLenBits[length_code]) != 0) + { + unsigned int extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1); + + if(WasteBits(pWork, extra_length_bits)) + { + if((length_code + extra_length) != 0x10E) + return 0x306; + } + length_code = pWork->LenBase[length_code] + extra_length; + } + + // In order to distinguish uncompressed byte from repetition length, + // we have to add 0x100 to the length. + return length_code + 0x100; + } + + // Remove one bit from the input data + if(WasteBits(pWork, 1)) + return 0x306; + + // If the binary compression type, read 8 bits and return them as one byte. + if(pWork->ctype == CMP_BINARY) + { + unsigned int uncompressed_byte = pWork->bit_buff & 0xFF; + + if(WasteBits(pWork, 8)) + return 0x306; + return uncompressed_byte; + } + + // When ASCII compression ... + if(pWork->bit_buff & 0xFF) + { + value = pWork->offs2C34[pWork->bit_buff & 0xFF]; + + if(value == 0xFF) + { + if(pWork->bit_buff & 0x3F) + { + if(WasteBits(pWork, 4)) + return 0x306; + + value = pWork->offs2D34[pWork->bit_buff & 0xFF]; + } + else + { + if(WasteBits(pWork, 6)) + return 0x306; + + value = pWork->offs2E34[pWork->bit_buff & 0x7F]; + } + } + } + else + { + if(WasteBits(pWork, 8)) + return 0x306; + + value = pWork->offs2EB4[pWork->bit_buff & 0xFF]; + } + + return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value; +} + +//----------------------------------------------------------------------------- +// Decodes the distance of the repetition, backwards relative to the +// current output buffer position + +static unsigned int DecodeDist(TDcmpStruct * pWork, unsigned int rep_length) +{ + unsigned int dist_pos_code; // Distance position code + unsigned int dist_pos_bits; // Number of bits of distance position + unsigned int distance; // Distance position + + // Next 2-8 bits in the input buffer is the distance position code + dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF]; + dist_pos_bits = pWork->DistBits[dist_pos_code]; + if(WasteBits(pWork, dist_pos_bits)) + return 0; + + if(rep_length == 2) + { + // If the repetition is only 2 bytes length, + // then take 2 bits from the stream in order to get the distance + distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03); + if(WasteBits(pWork, 2)) + return 0; + } + else + { + // If the repetition is more than 2 bytes length, + // then take "dsize_bits" bits in order to get the distance + distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask); + if(WasteBits(pWork, pWork->dsize_bits)) + return 0; + } + return distance + 1; +} + +static unsigned int Expand(TDcmpStruct * pWork) +{ + unsigned int next_literal; // Literal decoded from the compressed data + unsigned int result; // Value to be returned + unsigned int copyBytes; // Number of bytes to copy to the output buffer + + pWork->outputPos = 0x1000; // Initialize output buffer position + + // Decode the next literal from the input data. + // The returned literal can either be an uncompressed byte (next_literal < 0x100) + // or an encoded length of the repeating byte sequence that + // is to be copied to the current buffer position + while((result = next_literal = DecodeLit(pWork)) < 0x305) + { + // If the literal is greater than 0x100, it holds length + // of repeating byte sequence + // literal of 0x100 means repeating sequence of 0x2 bytes + // literal of 0x101 means repeating sequence of 0x3 bytes + // ... + // literal of 0x305 means repeating sequence of 0x207 bytes + if(next_literal >= 0x100) + { + unsigned char * source; + unsigned char * target; + unsigned int rep_length; // Length of the repetition, in bytes + unsigned int minus_dist; // Backward distance to the repetition, relative to the current buffer position + + // Get the length of the repeating sequence. + // Note that the repeating block may overlap the current output position, + // for example if there was a sequence of equal bytes + rep_length = next_literal - 0xFE; + + // Get backward distance to the repetition + if((minus_dist = DecodeDist(pWork, rep_length)) == 0) + { + result = 0x306; + break; + } + + // Target and source pointer + target = &pWork->out_buff[pWork->outputPos]; + source = target - minus_dist; + + // Update buffer output position + pWork->outputPos += rep_length; + + // Copy the repeating sequence + while(rep_length-- > 0) + *target++ = *source++; + } + else + { + pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal; + } + + // Flush the output buffer, if number of extracted bytes has reached the end + if(pWork->outputPos >= 0x2000) + { + // Copy decompressed data into user buffer + copyBytes = 0x1000; + pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); + + // Now copy the decompressed data to the first half of the buffer. + // This is needed because the decompression might reuse them as repetitions. + // Note that if the output buffer overflowed previously, the extra decompressed bytes + // are stored in "out_buff_overflow", and they will now be + // within decompressed part of the output buffer. + memmove(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000); + pWork->outputPos -= 0x1000; + } + } + + // Flush any remaining decompressed bytes + copyBytes = pWork->outputPos - 0x1000; + pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); + return result; +} + + +//----------------------------------------------------------------------------- +// Main exploding function. + +unsigned int PKEXPORT explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param) +{ + TDcmpStruct * pWork = (TDcmpStruct *)work_buf; + + // Initialize work struct and load compressed data + // Note: The caller must zero the "work_buff" before passing it to explode + pWork->read_buf = read_buf; + pWork->write_buf = write_buf; + pWork->param = param; + pWork->in_pos = sizeof(pWork->in_buff); + pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param); + if(pWork->in_bytes <= 4) + return CMP_BAD_DATA; + + pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII) + pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size + pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer + pWork->extra_bits = 0; // Extra (over 8) bits + pWork->in_pos = 3; // Position in input buffer + + // Test for the valid dictionary size + if(4 > pWork->dsize_bits || pWork->dsize_bits > 6) + return CMP_INVALID_DICTSIZE; + + pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction + + if(pWork->ctype != CMP_BINARY) + { + if(pWork->ctype != CMP_ASCII) + return CMP_INVALID_MODE; + + memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc)); + GenAscTabs(pWork); + } + + memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits)); + GenDecodeTabs(pWork->LengthCodes, LenCode, pWork->LenBits, sizeof(pWork->LenBits)); + memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits)); + memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase)); + memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits)); + GenDecodeTabs(pWork->DistPosCodes, DistCode, pWork->DistBits, sizeof(pWork->DistBits)); + if(Expand(pWork) != 0x306) + return CMP_NO_ERROR; + + return CMP_ABORT; +} diff --git a/C/pklib/implode.c b/C/pklib/implode.c new file mode 100644 index 000000000..90cb4821c --- /dev/null +++ b/C/pklib/implode.c @@ -0,0 +1,676 @@ +/*****************************************************************************/ +/* implode.c Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Implode function of PKWARE Data Compression library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.04.03 1.00 Lad First version of implode.c */ +/* 02.05.03 1.00 Lad Stress test done */ +/* 22.04.10 1.01 Lad Documented */ +/*****************************************************************************/ + +#include +#include + +#include "pklib.h" + +#if ((1200 < _MSC_VER) && (_MSC_VER < 1400)) +#pragma optimize("", off) // Fucking Microsoft VS.NET 2003 compiler !!! (_MSC_VER=1310) +#endif + +//----------------------------------------------------------------------------- +// Defines + +#define MAX_REP_LENGTH 0x204 // The longest allowed repetition + +//----------------------------------------------------------------------------- +// Macros + +// Macro for calculating hash of the current byte pair. +// Note that most exact byte pair hash would be buffer[0] + buffer[1] << 0x08, +// but even this way gives nice indication of equal byte pairs, with significantly +// smaller size of the array that holds numbers of those hashes +#define BYTE_PAIR_HASH(buffer) ((buffer[0] * 4) + (buffer[1] * 5)) + +//----------------------------------------------------------------------------- +// Local functions + +// Builds the "hash_to_index" table and "pair_hash_offsets" table. +// Every element of "hash_to_index" will contain lowest index to the +// "pair_hash_offsets" table, effectively giving offset of the first +// occurence of the given PAIR_HASH in the input data. +static void SortBuffer(TCmpStruct * pWork, unsigned char * buffer_begin, unsigned char * buffer_end) +{ + unsigned short * phash_to_index; + unsigned char * buffer_ptr; + unsigned short total_sum = 0; + unsigned long byte_pair_hash; // Hash value of the byte pair + unsigned short byte_pair_offs; // Offset of the byte pair, relative to "work_buff" + + // Zero the entire "phash_to_index" table + memset(pWork->phash_to_index, 0, sizeof(pWork->phash_to_index)); + + // Step 1: Count amount of each PAIR_HASH in the input buffer + // The table will look like this: + // offs 0x000: Number of occurences of PAIR_HASH 0 + // offs 0x001: Number of occurences of PAIR_HASH 1 + // ... + // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 (the highest hash value) + for(buffer_ptr = buffer_begin; buffer_ptr < buffer_end; buffer_ptr++) + pWork->phash_to_index[BYTE_PAIR_HASH(buffer_ptr)]++; + + // Step 2: Convert the table to the array of PAIR_HASH amounts. + // Each element contains count of PAIR_HASHes that is less or equal + // to element index + // The table will look like this: + // offs 0x000: Number of occurences of PAIR_HASH 0 or lower + // offs 0x001: Number of occurences of PAIR_HASH 1 or lower + // ... + // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 or lower + for(phash_to_index = pWork->phash_to_index; phash_to_index < &pWork->phash_to_index_end; phash_to_index++) + { + total_sum = total_sum + phash_to_index[0]; + phash_to_index[0] = total_sum; + } + + // Step 3: Convert the table to the array of indexes. + // Now, each element contains index to the first occurence of given PAIR_HASH + for(buffer_end--; buffer_end >= buffer_begin; buffer_end--) + { + byte_pair_hash = BYTE_PAIR_HASH(buffer_end); + byte_pair_offs = (unsigned short)(buffer_end - pWork->work_buff); + + pWork->phash_to_index[byte_pair_hash]--; + pWork->phash_offs[pWork->phash_to_index[byte_pair_hash]] = byte_pair_offs; + } +} + +static void FlushBuf(TCmpStruct * pWork) +{ + unsigned char save_ch1; + unsigned char save_ch2; + unsigned int size = 0x800; + + pWork->write_buf(pWork->out_buff, &size, pWork->param); + + save_ch1 = pWork->out_buff[0x800]; + save_ch2 = pWork->out_buff[pWork->out_bytes]; + pWork->out_bytes -= 0x800; + + memset(pWork->out_buff, 0, sizeof(pWork->out_buff)); + + if(pWork->out_bytes != 0) + pWork->out_buff[0] = save_ch1; + if(pWork->out_bits != 0) + pWork->out_buff[pWork->out_bytes] = save_ch2; +} + +static void OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff) +{ + unsigned int out_bits; + + // If more than 8 bits to output, do recursion + if(nbits > 8) + { + OutputBits(pWork, 8, bit_buff); + bit_buff >>= 8; + nbits -= 8; + } + + // Add bits to the last out byte in out_buff; + out_bits = pWork->out_bits; + pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits); + pWork->out_bits += nbits; + + // If 8 or more bits, increment number of bytes + if(pWork->out_bits > 8) + { + pWork->out_bytes++; + bit_buff >>= (8 - out_bits); + + pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff; + pWork->out_bits &= 7; + } + else + { + pWork->out_bits &= 7; + if(pWork->out_bits == 0) + pWork->out_bytes++; + } + + // If there is enough compressed bytes, flush them + if(pWork->out_bytes >= 0x800) + FlushBuf(pWork); +} + +// This function searches for a repetition +// (a previous occurence of the current byte sequence) +// Returns length of the repetition, and stores the backward distance +// to pWork structure. +static unsigned int FindRep(TCmpStruct * pWork, unsigned char * input_data) +{ + unsigned short * phash_to_index; // Pointer into pWork->phash_to_index table + unsigned short * phash_offs; // Pointer to the table containing offsets of each PAIR_HASH + unsigned char * repetition_limit; // An eventual repetition must be at position below this pointer + unsigned char * prev_repetition; // Pointer to the previous occurence of the current PAIR_HASH + unsigned char * prev_rep_end; // End of the previous repetition + unsigned char * input_data_ptr; + unsigned short phash_offs_index; // Index to the table with PAIR_HASH positions + unsigned short min_phash_offs; // The lowest allowed hash offset + unsigned short offs_in_rep; // Offset within found repetition + unsigned int equal_byte_count; // Number of bytes that are equal to the previous occurence + unsigned int rep_length = 1; // Length of the found repetition + unsigned int rep_length2; // Secondary repetition + unsigned char pre_last_byte; // Last but one byte from a repetion + unsigned short di_val; + + // Calculate the previous position of the PAIR_HASH + phash_to_index = pWork->phash_to_index + BYTE_PAIR_HASH(input_data); + min_phash_offs = (unsigned short)((input_data - pWork->work_buff) - pWork->dsize_bytes + 1); + phash_offs_index = phash_to_index[0]; + + // If the PAIR_HASH offset is below the limit, find a next one + phash_offs = pWork->phash_offs + phash_offs_index; + if(*phash_offs < min_phash_offs) + { + while(*phash_offs < min_phash_offs) + { + phash_offs_index++; + phash_offs++; + } + *phash_to_index = phash_offs_index; + } + + // Get the first location of the PAIR_HASH, + // and thus the first eventual location of byte repetition + phash_offs = pWork->phash_offs + phash_offs_index; + prev_repetition = pWork->work_buff + phash_offs[0]; + repetition_limit = input_data - 1; + + // If the current PAIR_HASH was not encountered before, + // we haven't found a repetition. + if(prev_repetition >= repetition_limit) + return 0; + + // We have found a match of a PAIR_HASH. Now we have to make sure + // that it is also a byte match, because PAIR_HASH is not unique. + // We compare the bytes and count the length of the repetition + input_data_ptr = input_data; + for(;;) + { + // If the first byte of the repetition and the so-far-last byte + // of the repetition are equal, we will compare the blocks. + if(*input_data_ptr == *prev_repetition && input_data_ptr[rep_length-1] == prev_repetition[rep_length-1]) + { + // Skip the current byte + prev_repetition++; + input_data_ptr++; + equal_byte_count = 2; + + // Now count how many more bytes are equal + while(equal_byte_count < MAX_REP_LENGTH) + { + prev_repetition++; + input_data_ptr++; + + // Are the bytes different ? + if(*prev_repetition != *input_data_ptr) + break; + + equal_byte_count++; + } + + // If we found a repetition of at least the same length, take it. + // If there are multiple repetitions in the input buffer, this will + // make sure that we find the most recent one, which in turn allows + // us to store backward length in less amount of bits + input_data_ptr = input_data; + if(equal_byte_count >= rep_length) + { + // Calculate the backward distance of the repetition. + // Note that the distance is stored as decremented by 1 + pWork->distance = (unsigned int)(input_data - prev_repetition + equal_byte_count - 1); + + // Repetitions longer than 10 bytes will be stored in more bits, + // so they need a bit different handling + if((rep_length = equal_byte_count) > 10) + break; + } + } + + // Move forward in the table of PAIR_HASH repetitions. + // There might be a more recent occurence of the same repetition. + phash_offs_index++; + phash_offs++; + prev_repetition = pWork->work_buff + phash_offs[0]; + + // If the next repetition is beyond the minimum allowed repetition, we are done. + if(prev_repetition >= repetition_limit) + { + // A repetition must have at least 2 bytes, otherwise it's not worth it + return (rep_length >= 2) ? rep_length : 0; + } + } + + // If the repetition has max length of 0x204 bytes, we can't go any fuhrter + if(equal_byte_count == MAX_REP_LENGTH) + { + pWork->distance--; + return equal_byte_count; + } + + // Check for possibility of a repetition that occurs at more recent position + phash_offs = pWork->phash_offs + phash_offs_index; + if(pWork->work_buff + phash_offs[1] >= repetition_limit) + return rep_length; + + // + // The following part checks if there isn't a longer repetition at + // a latter offset, that would lead to better compression. + // + // Example of data that can trigger this optimization: + // + // "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEQQQQQQQQQQQQ" + // "XYZ" + // "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ"; + // + // Description of data in this buffer + // [0x00] Single byte "E" + // [0x01] Single byte "E" + // [0x02] Repeat 0x1E bytes from [0x00] + // [0x20] Single byte "X" + // [0x21] Single byte "Y" + // [0x22] Single byte "Z" + // [0x23] 17 possible previous repetitions of length at least 0x10 bytes: + // - Repetition of 0x10 bytes from [0x00] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x10 bytes from [0x01] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x10 bytes from [0x02] "EEEEEEEEEEEEEEEE" + // ... + // - Repetition of 0x10 bytes from [0x0F] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x1C bytes from [0x10] "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ" + // The last repetition is the best one. + // + + pWork->offs09BC[0] = 0xFFFF; + pWork->offs09BC[1] = 0x0000; + di_val = 0; + + // Note: I failed to figure out what does the table "offs09BC" mean. + // If anyone has an idea, let me know to zezula_at_volny_dot_cz + for(offs_in_rep = 1; offs_in_rep < rep_length; ) + { + if(input_data[offs_in_rep] != input_data[di_val]) + { + di_val = pWork->offs09BC[di_val]; + if(di_val != 0xFFFF) + continue; + } + pWork->offs09BC[++offs_in_rep] = ++di_val; + } + + // + // Now go through all the repetitions from the first found one + // to the current input data, and check if any of them migh be + // a start of a greater sequence match. + // + + prev_repetition = pWork->work_buff + phash_offs[0]; + prev_rep_end = prev_repetition + rep_length; + rep_length2 = rep_length; + + for(;;) + { + rep_length2 = pWork->offs09BC[rep_length2]; + if(rep_length2 == 0xFFFF) + rep_length2 = 0; + + // Get the pointer to the previous repetition + phash_offs = pWork->phash_offs + phash_offs_index; + + // Skip those repetitions that don't reach the end + // of the first found repetition + do + { + phash_offs++; + phash_offs_index++; + prev_repetition = pWork->work_buff + *phash_offs; + if(prev_repetition >= repetition_limit) + return rep_length; + } + while(prev_repetition + rep_length2 < prev_rep_end); + + // Verify if the last but one byte from the repetition matches + // the last but one byte from the input data. + // If not, find a next repetition + pre_last_byte = input_data[rep_length - 2]; + if(pre_last_byte == prev_repetition[rep_length - 2]) + { + // If the new repetition reaches beyond the end + // of previously found repetition, reset the repetition length to zero. + if(prev_repetition + rep_length2 != prev_rep_end) + { + prev_rep_end = prev_repetition; + rep_length2 = 0; + } + } + else + { + phash_offs = pWork->phash_offs + phash_offs_index; + do + { + phash_offs++; + phash_offs_index++; + prev_repetition = pWork->work_buff + *phash_offs; + if(prev_repetition >= repetition_limit) + return rep_length; + } + while(prev_repetition[rep_length - 2] != pre_last_byte || prev_repetition[0] != input_data[0]); + + // Reset the length of the repetition to 2 bytes only + prev_rep_end = prev_repetition + 2; + rep_length2 = 2; + } + + // Find out how many more characters are equal to the first repetition. + while(*prev_rep_end == input_data[rep_length2]) + { + if(++rep_length2 >= 0x204) + break; + prev_rep_end++; + } + + // Is the newly found repetion at least as long as the previous one ? + if(rep_length2 >= rep_length) + { + // Calculate the distance of the new repetition + pWork->distance = (unsigned int)(input_data - prev_repetition - 1); + if((rep_length = rep_length2) == 0x204) + return rep_length; + + // Update the additional elements in the "offs09BC" table + // to reflect new rep length + while(offs_in_rep < rep_length2) + { + if(input_data[offs_in_rep] != input_data[di_val]) + { + di_val = pWork->offs09BC[di_val]; + if(di_val != 0xFFFF) + continue; + } + pWork->offs09BC[++offs_in_rep] = ++di_val; + } + } + } +} + +static void WriteCmpData(TCmpStruct * pWork) +{ + unsigned char * input_data_end; // Pointer to the end of the input data + unsigned char * input_data = pWork->work_buff + pWork->dsize_bytes + 0x204; + unsigned int input_data_ended = 0; // If 1, then all data from the input stream have been already loaded + unsigned int save_rep_length; // Saved length of current repetition + unsigned int save_distance = 0; // Saved distance of current repetition + unsigned int rep_length; // Length of the found repetition + unsigned int phase = 0; // + + // Store the compression type and dictionary size + pWork->out_buff[0] = (char)pWork->ctype; + pWork->out_buff[1] = (char)pWork->dsize_bits; + pWork->out_bytes = 2; + + // Reset output buffer to zero + memset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2); + pWork->out_bits = 0; + + while(input_data_ended == 0) + { + unsigned int bytes_to_load = 0x1000; + int total_loaded = 0; + int bytes_loaded; + + // Load the bytes from the input stream, up to 0x1000 bytes + while(bytes_to_load != 0) + { + bytes_loaded = pWork->read_buf((char *)pWork->work_buff + pWork->dsize_bytes + 0x204 + total_loaded, + &bytes_to_load, + pWork->param); + if(bytes_loaded == 0) + { + if(total_loaded == 0 && phase == 0) + goto __Exit; + input_data_ended = 1; + break; + } + else + { + bytes_to_load -= bytes_loaded; + total_loaded += bytes_loaded; + } + } + + input_data_end = pWork->work_buff + pWork->dsize_bytes + total_loaded; + if(input_data_ended) + input_data_end += 0x204; + + // + // Warning: The end of the buffer passed to "SortBuffer" is actually 2 bytes beyond + // valid data. It is questionable if this is actually a bug or not, + // but it might cause the compressed data output to be dependent on random bytes + // that are in the buffer. + // To prevent that, the calling application must always zero the compression + // buffer before passing it to "implode" + // + + // Search the PAIR_HASHes of the loaded blocks. Also, include + // previously compressed data, if any. + switch(phase) + { + case 0: + SortBuffer(pWork, input_data, input_data_end + 1); + phase++; + if(pWork->dsize_bytes != 0x1000) + phase++; + break; + + case 1: + SortBuffer(pWork, input_data - pWork->dsize_bytes + 0x204, input_data_end + 1); + phase++; + break; + + default: + SortBuffer(pWork, input_data - pWork->dsize_bytes, input_data_end + 1); + break; + } + + // Perform the compression of the current block + while(input_data < input_data_end) + { + // Find if the current byte sequence wasn't there before. + rep_length = FindRep(pWork, input_data); + while(rep_length != 0) + { + // If we found repetition of 2 bytes, that is 0x100 or fuhrter back, + // don't bother. Storing the distance of 0x100 bytes would actually + // take more space than storing the 2 bytes as-is. + if(rep_length == 2 && pWork->distance >= 0x100) + break; + + // When we are at the end of the input data, we cannot allow + // the repetition to go past the end of the input data. + if(input_data_ended && input_data + rep_length > input_data_end) + { + // Shorten the repetition length so that it only covers valid data + rep_length = (unsigned long)(input_data_end - input_data); + if(rep_length < 2) + break; + + // If we got repetition of 2 bytes, that is 0x100 or more backward, don't bother + if(rep_length == 2 && pWork->distance >= 0x100) + break; + goto __FlushRepetition; + } + + if(rep_length >= 8 || input_data + 1 >= input_data_end) + goto __FlushRepetition; + + // Try to find better repetition 1 byte later. + // Example: "ARROCKFORT" "AROCKFORT" + // When "input_data" points to the second string, FindRep + // returns the occurence of "AR". But there is longer repetition "ROCKFORT", + // beginning 1 byte after. + save_rep_length = rep_length; + save_distance = pWork->distance; + rep_length = FindRep(pWork, input_data + 1); + + // Only use the new repetition if it's length is greater than the previous one + if(rep_length > save_rep_length) + { + // If the new repetition if only 1 byte better + // and the previous distance is less than 0x80 bytes, use the previous repetition + if(rep_length > save_rep_length + 1 || save_distance > 0x80) + { + // Flush one byte, so that input_data will point to the secondary repetition + OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); + input_data++; + continue; + } + } + + // Revert to the previous repetition + rep_length = save_rep_length; + pWork->distance = save_distance; + + __FlushRepetition: + + OutputBits(pWork, pWork->nChBits[rep_length + 0xFE], pWork->nChCodes[rep_length + 0xFE]); + if(rep_length == 2) + { + OutputBits(pWork, pWork->dist_bits[pWork->distance >> 2], + pWork->dist_codes[pWork->distance >> 2]); + OutputBits(pWork, 2, pWork->distance & 3); + } + else + { + OutputBits(pWork, pWork->dist_bits[pWork->distance >> pWork->dsize_bits], + pWork->dist_codes[pWork->distance >> pWork->dsize_bits]); + OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->distance); + } + + // Move the begin of the input data by the length of the repetition + input_data += rep_length; + goto _00402252; + } + + // If there was no previous repetition for the current position in the input data, + // just output the 9-bit literal for the one character + OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); + input_data++; +_00402252:; + } + + if(input_data_ended == 0) + { + input_data -= 0x1000; + memmove(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + 0x204); + } + } + +__Exit: + + // Write the termination literal + OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]); + if(pWork->out_bits != 0) + pWork->out_bytes++; + pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param); + return; +} + +//----------------------------------------------------------------------------- +// Main imploding function + +unsigned int PKEXPORT implode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param, + unsigned int *type, + unsigned int *dsize) +{ + TCmpStruct * pWork = (TCmpStruct *)work_buf; + unsigned int nChCode; + unsigned int nCount; + unsigned int i; + int nCount2; + + // Fill the work buffer information + // Note: The caller must zero the "work_buff" before passing it to implode + pWork->read_buf = read_buf; + pWork->write_buf = write_buf; + pWork->dsize_bytes = *dsize; + pWork->ctype = *type; + pWork->param = param; + pWork->dsize_bits = 4; + pWork->dsize_mask = 0x0F; + + // Test dictionary size + switch(*dsize) + { + case CMP_IMPLODE_DICT_SIZE3: // 0x1000 bytes + pWork->dsize_bits++; + pWork->dsize_mask |= 0x20; + // No break here !!! + + case CMP_IMPLODE_DICT_SIZE2: // 0x800 bytes + pWork->dsize_bits++; + pWork->dsize_mask |= 0x10; + // No break here !!! + + case CMP_IMPLODE_DICT_SIZE1: // 0x400 + break; + + default: + return CMP_INVALID_DICTSIZE; + } + + // Test the compression type + switch(*type) + { + case CMP_BINARY: // We will compress data with binary compression type + for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++) + { + pWork->nChBits[nCount] = 9; + pWork->nChCodes[nCount] = (unsigned short)nChCode; + nChCode = (nChCode & 0x0000FFFF) + 2; + } + break; + + + case CMP_ASCII: // We will compress data with ASCII compression type + for(nCount = 0; nCount < 0x100; nCount++) + { + pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1); + pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2); + } + break; + + default: + return CMP_INVALID_MODE; + } + + for(i = 0; i < 0x10; i++) + { + for(nCount2 = 0; nCount2 < (1 << ExLenBits[i]); nCount2++) + { + pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1); + pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1); + nCount++; + } + } + + // Copy the distance codes and distance bits and perform the compression + memcpy(&pWork->dist_codes, DistCode, sizeof(DistCode)); + memcpy(&pWork->dist_bits, DistBits, sizeof(DistBits)); + WriteCmpData(pWork); + return CMP_NO_ERROR; +} diff --git a/C/pklib/pklib.h b/C/pklib/pklib.h new file mode 100644 index 000000000..d9b2a70a8 --- /dev/null +++ b/C/pklib/pklib.h @@ -0,0 +1,158 @@ +/*****************************************************************************/ +/* pklib.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Header file for PKWARE Data Compression Library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.03.03 1.00 Lad The first version of pkware.h */ +/*****************************************************************************/ + +#ifndef __PKLIB_H__ +#define __PKLIB_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define CMP_BINARY 0 // Binary compression +#define CMP_ASCII 1 // Ascii compression + +#define CMP_NO_ERROR 0 +#define CMP_INVALID_DICTSIZE 1 +#define CMP_INVALID_MODE 2 +#define CMP_BAD_DATA 3 +#define CMP_ABORT 4 + +#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024 +#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048 +#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096 + +//----------------------------------------------------------------------------- +// Define calling convention + +#ifndef PKEXPORT +#ifdef WIN32 +#define PKEXPORT __cdecl // Use for normal __cdecl calling +#else +#define PKEXPORT +#endif +#endif + +//----------------------------------------------------------------------------- +// Internal structures + +// Compression structure +typedef struct +{ + unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1 + unsigned int out_bytes; // 0004: # bytes available in out_buff + unsigned int out_bits; // 0008: # of bits available in the last out byte + unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000 + unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000 + unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY) + unsigned int dsize_bytes; // 0018: Dictionary size in bytes + unsigned char dist_bits[0x40]; // 001C: Distance bits + unsigned char dist_codes[0x40]; // 005C: Distance codes + unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream + unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream + unsigned short offs09AE; // 09AE: + + void * param; // 09B0: User parameter + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4 + void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8 + + unsigned short offs09BC[0x204]; // 09BC: + unsigned long offs0DC4; // 0DC4: + unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table + unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table + char out_buff[0x802]; // 1FCA: Compressed data + unsigned char work_buff[0x2204]; // 27CC: Work buffer + // + DICT_OFFSET => Dictionary + // + UNCMP_OFFSET => Uncompressed data + unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH +} TCmpStruct; + +#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure. + // Defined as 36312 in pkware header file + + +// Decompression structure +typedef struct +{ + unsigned long offs0000; // 0000 + unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII) + unsigned long outputPos; // 0008: Position in output buffer + unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000) + unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000) + unsigned long bit_buff; // 0014: 16-bit buffer for processing input data + unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer + unsigned int in_pos; // 001C: Position in in_buff + unsigned long in_bytes; // 0020: Number of bytes in input buffer + void * param; // 0024: Custom parameter + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream + void (*write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream + + unsigned char out_buff[0x2204]; // 0030: Output circle buffer. + // 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions + // 0x1000 - 0x1FFF: Currently decompressed data + // 0x2000 - 0x2203: Reserve space for the longest possible repetition + unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed + unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes + unsigned char LengthCodes[0x100]; // 2B34: Table of length codes + unsigned char offs2C34[0x100]; // 2C34: Buffer for + unsigned char offs2D34[0x100]; // 2D34: Buffer for + unsigned char offs2E34[0x80]; // 2E34: Buffer for + unsigned char offs2EB4[0x100]; // 2EB4: Buffer for + unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for + unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length + unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length + unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block + unsigned short LenBase[0x10]; // 3114: Buffer for +} TDcmpStruct; + +#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure + // Defined as 12596 in pkware headers + +//----------------------------------------------------------------------------- +// Tables (in explode.c) + +extern unsigned char DistBits[0x40]; +extern unsigned char DistCode[0x40]; +extern unsigned char ExLenBits[0x10]; +extern unsigned short LenBase[0x10]; +extern unsigned char LenBits[0x10]; +extern unsigned char LenCode[0x10]; +extern unsigned char ChBitsAsc[0x100]; +extern unsigned short ChCodeAsc[0x100]; + +//----------------------------------------------------------------------------- +// Public functions + +#ifdef __cplusplus + extern "C" { +#endif + +unsigned int PKEXPORT implode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param, + unsigned int *type, + unsigned int *dsize); + + +unsigned int PKEXPORT explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param); + +// The original name "crc32" was changed to "crc32pk" due +// to compatibility with zlib +unsigned long PKEXPORT crc32_pklib(char *buffer, unsigned int *size, unsigned long *old_crc); + +#ifdef __cplusplus + } // End of 'extern "C"' declaration +#endif + +#endif // __PKLIB_H__ diff --git a/CPP/7zip/Compress/PKImplode/makefile.list b/CPP/7zip/Compress/PKImplode/makefile.list index e31504e02..2483945e1 100644 --- a/CPP/7zip/Compress/PKImplode/makefile.list +++ b/CPP/7zip/Compress/PKImplode/makefile.list @@ -24,11 +24,14 @@ SRCS=\ ../../../../CPP/7zip/Compress/CodecExports.cpp \ ../../../../CPP/7zip/Compress/DllExportsCompress.cpp \ ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/Common/MyWindows.cpp \ SRCS_C=\ ../../../../C/blast/blast.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ ../../../../C/Alloc.c \ StdAfx.h.gch : ../../../myWindows/StdAfx.h @@ -36,6 +39,10 @@ StdAfx.h.gch : ../../../myWindows/StdAfx.h $(CXX) $(CXXFLAGS) ../../../myWindows/StdAfx.h -o StdAfx.h.gch blast.o : ../../../../C/blast/blast.c $(CC) $(CFLAGS) ../../../../C/blast/blast.c +explode.o : ../../../../C/pklib/explode.c + $(CC) $(CFLAGS) ../../../../C/pklib/explode.c +implode.o : ../../../../C/pklib/implode.c + $(CC) $(CFLAGS) ../../../../C/pklib/implode.c Alloc.o : ../../../../C/Alloc.c $(CC) $(CFLAGS) ../../../../C/Alloc.c InBuffer.o : ../../../../CPP/7zip/Common/InBuffer.cpp @@ -50,6 +57,8 @@ DllExportsCompress.o : ../../../../CPP/7zip/Compress/DllExportsCompress.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/DllExportsCompress.cpp PKImplodeDecoder.o : ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp +PKImplodeEncoder.o : ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp PKImplodeRegister.o : ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp MyWindows.o : ../../../../CPP/Common/MyWindows.cpp @@ -57,6 +66,8 @@ MyWindows.o : ../../../../CPP/Common/MyWindows.cpp OBJS=\ blast.o \ + explode.o \ + implode.o \ Alloc.o \ InBuffer.o \ OutBuffer.o \ @@ -64,6 +75,7 @@ OBJS=\ CodecExports.o \ DllExportsCompress.o \ PKImplodeDecoder.o \ + PKImplodeEncoder.o \ PKImplodeRegister.o \ MyWindows.o \ diff --git a/CPP/7zip/Compress/PKImplodeEncoder.cpp b/CPP/7zip/Compress/PKImplodeEncoder.cpp new file mode 100644 index 000000000..9484b41e6 --- /dev/null +++ b/CPP/7zip/Compress/PKImplodeEncoder.cpp @@ -0,0 +1,95 @@ +// ImplodeDecoder.cpp + +#include +#include "StdAfx.h" + +#include "../../Common/Defs.h" + +#include "PKImplodeEncoder.h" +#include "../../Common/StreamUtils.h" + +namespace NCompress { +namespace NPKImplode { +namespace NEncoder { + +static void C_put(char *buf, unsigned int *size, void *param){ + CEncoder *w = (CEncoder*)param; + UInt32 rlen=0; + HRESULT res = w->outS->Write(buf, *size, &rlen); + //*size = rlen; + w->processedOut += rlen; + if(w->progr) + w->progr->SetRatioInfo(&w->processedIn, &w->processedOut); + //return res != S_OK || rlen != len; +} + +static unsigned int C_get(char *buf, unsigned int *size, void *param){ + CEncoder *r = (CEncoder*)param; + size_t readsize = *size; + HRESULT res = ReadStream(r->inS,buf,&readsize); + //*size = readsize; + r->processedIn += readsize; + return res != S_OK ? 0 : readsize; +} + +CEncoder::CEncoder(): typ(0), dsize(4096){ + memset(&CmpStruct, 0, sizeof(TCmpStruct)); +} + +STDMETHODIMP CEncoder::SetCoderProperties(const PROPID * propIDs, const PROPVARIANT * coderProps, UInt32 numProps) +{ + typ = 0; + dsize = 4096; + for (UInt32 i = 0; i < numProps; i++){ + const PROPVARIANT & prop = coderProps[i]; + PROPID propID = propIDs[i]; + UInt32 v = (UInt32)prop.ulVal; + switch (propID) + { + case NCoderPropID::kLevel: + { + typ = v/10; + int dsize_ = v%10; + if(typ<0)typ=0; + if(typ>1)typ=1; + if(dsize<1)dsize=1; + if(dsize>3)dsize=3; + dsize = 1<<(9+dsize_); + } + } + } + return S_OK; +} + +HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + inS = inStream; + outS = outStream; + progr = progress; + processedIn = processedOut = 0; + int x = implode(C_get, C_put, (char*)&CmpStruct, this, &typ, &dsize); + if(x<0)return E_FAIL; + if(x==2)return E_ABORT; + if(x==1)return E_OUTOFMEMORY; + return x==0 ? S_OK : E_FAIL; +} + + +STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +STDMETHODIMP CEncoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = processedIn; + return S_OK; +} + +}}} + diff --git a/CPP/7zip/Compress/PKImplodeEncoder.h b/CPP/7zip/Compress/PKImplodeEncoder.h new file mode 100644 index 000000000..0852fe260 --- /dev/null +++ b/CPP/7zip/Compress/PKImplodeEncoder.h @@ -0,0 +1,52 @@ +// ImplodeEncoder.h + +#ifndef __COMPRESS_PKIMPLODE_ENCODER_H +#define __COMPRESS_PKIMPLODE_ENCODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +extern "C" { +#include "../../../C/pklib/pklib.h" +} + +namespace NCompress { +namespace NPKImplode { +namespace NEncoder { + +class CEncoder: + public ICompressCoder, + public ICompressGetInStreamProcessedSize, + public ICompressSetCoderProperties, + public CMyUnknownImp +{ + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + +public: + UInt64 processedIn; + UInt64 processedOut; + ISequentialInStream *inS; + ISequentialOutStream *outS; + ICompressProgressInfo *progr; + + unsigned int typ; + unsigned int dsize; + TCmpStruct CmpStruct; + + MY_UNKNOWN_IMP2(ICompressGetInStreamProcessedSize, ICompressSetCoderProperties) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + STDMETHOD (SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + CEncoder(); +}; + +}}} + +#endif diff --git a/CPP/7zip/Compress/PKImplodeRegister.cpp b/CPP/7zip/Compress/PKImplodeRegister.cpp index 65e13a5d0..2b432e088 100644 --- a/CPP/7zip/Compress/PKImplodeRegister.cpp +++ b/CPP/7zip/Compress/PKImplodeRegister.cpp @@ -5,16 +5,14 @@ #include "../Common/RegisterCodec.h" #include "PKImplodeDecoder.h" +#include "PKImplodeEncoder.h" namespace NCompress { -REGISTER_CODEC_CREATE(CreateCodecPKImplode, NPKImplode::NDecoder::CDecoder()) - -REGISTER_CODECS_VAR -{ - { CreateCodecPKImplode, NULL, 0x4010a, "PKImplode", 1, false } -}; - -REGISTER_CODECS(PKImplode) +REGISTER_CODEC_E( + PKImplode, + NPKImplode::NDecoder::CDecoder(), + NPKImplode::NEncoder::CEncoder(), + 0x4010a, "PKImplode") } diff --git a/Utils/file_Codecs_PKImplode_so.py b/Utils/file_Codecs_PKImplode_so.py index 046d6c97f..7e75200b3 100644 --- a/Utils/file_Codecs_PKImplode_so.py +++ b/Utils/file_Codecs_PKImplode_so.py @@ -1,6 +1,8 @@ files_c=[ 'C/blast/blast.c', + 'C/pklib/explode.c', + 'C/pklib/implode.c', #'C/7zCrcOpt.c', 'C/Alloc.c', #'C/CpuArch.c', @@ -15,6 +17,7 @@ 'CPP/7zip/Compress/CodecExports.cpp', 'CPP/7zip/Compress/DllExportsCompress.cpp', 'CPP/7zip/Compress/PKImplodeDecoder.cpp', + 'CPP/7zip/Compress/PKImplodeEncoder.cpp', 'CPP/7zip/Compress/PKImplodeRegister.cpp', #'CPP/Common/CRC.cpp', #'CPP/Common/MyVector.cpp', From 4e2c2d12e0aff90c75835ba24e3d8b91251bd35d Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 10 Jan 2022 11:41:04 +0900 Subject: [PATCH 5/8] Use pklib to decode as well --- C/blast/blast.c | 466 -------------------- C/blast/blast.h | 83 ---- CPP/7zip/Bundles/Alone/makefile.list | 20 + CPP/7zip/Bundles/Format7zFree/makefile.list | 20 + CPP/7zip/CMAKE/7za/CMakeLists.txt | 5 + CPP/7zip/CMAKE/Format7zFree/CMakeLists.txt | 5 + CPP/7zip/Compress/PKImplode/makefile.list | 4 - CPP/7zip/Compress/PKImplodeDecoder.cpp | 30 +- CPP/7zip/Compress/PKImplodeDecoder.h | 6 + Utils/file_7z_so.py | 5 +- Utils/file_7za.py | 5 +- Utils/file_Codecs_PKImplode_so.py | 1 - 12 files changed, 78 insertions(+), 572 deletions(-) delete mode 100644 C/blast/blast.c delete mode 100644 C/blast/blast.h diff --git a/C/blast/blast.c b/C/blast/blast.c deleted file mode 100644 index e6e659073..000000000 --- a/C/blast/blast.c +++ /dev/null @@ -1,466 +0,0 @@ -/* blast.c - * Copyright (C) 2003, 2012, 2013 Mark Adler - * For conditions of distribution and use, see copyright notice in blast.h - * version 1.3, 24 Aug 2013 - * - * blast.c decompresses data compressed by the PKWare Compression Library. - * This function provides functionality similar to the explode() function of - * the PKWare library, hence the name "blast". - * - * This decompressor is based on the excellent format description provided by - * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the - * example Ben provided in the post is incorrect. The distance 110001 should - * instead be 111000. When corrected, the example byte stream becomes: - * - * 00 04 82 24 25 8f 80 7f - * - * which decompresses to "AIAIAIAIAIAIA" (without the quotes). - */ - -/* - * Change history: - * - * 1.0 12 Feb 2003 - First version - * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data - * 1.2 24 Oct 2012 - Add note about using binary mode in stdio - * - Fix comparisons of differently signed integers - * 1.3 24 Aug 2013 - Return unused input from blast() - * - Fix test code to correctly report unused input - * - Enable the provision of initial input to blast() - */ - -#include /* for NULL */ -#include /* for setjmp(), longjmp(), and jmp_buf */ -#include "blast.h" /* prototype for blast() */ - -#define local static /* for local function definitions */ -#define MAXBITS 13 /* maximum code length */ -#define MAXWIN 4096 /* maximum window size */ - -/* input and output state */ -struct state { - /* input state */ - blast_in infun; /* input function provided by user */ - void *inhow; /* opaque information passed to infun() */ - unsigned char *in; /* next input location */ - unsigned left; /* available input at in */ - int bitbuf; /* bit buffer */ - int bitcnt; /* number of bits in bit buffer */ - - /* input limit error return state for bits() and decode() */ - jmp_buf env; - - /* output state */ - blast_out outfun; /* output function provided by user */ - void *outhow; /* opaque information passed to outfun() */ - unsigned next; /* index of next write location in out[] */ - int first; /* true to check distances (for first 4K) */ - unsigned char out[MAXWIN]; /* output buffer and sliding window */ -}; - -/* - * Return need bits from the input stream. This always leaves less than - * eight bits in the buffer. bits() works properly for need == 0. - * - * Format notes: - * - * - Bits are stored in bytes from the least significant bit to the most - * significant bit. Therefore bits are dropped from the bottom of the bit - * buffer, using shift right, and new bytes are appended to the top of the - * bit buffer, using shift left. - */ -local int bits(struct state *s, int need) -{ - int val; /* bit accumulator */ - - /* load at least need bits into val */ - val = s->bitbuf; - while (s->bitcnt < need) { - if (s->left == 0) { - s->left = s->infun(s->inhow, &(s->in)); - if (s->left == 0) longjmp(s->env, 1); /* out of input */ - } - val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ - s->left--; - s->bitcnt += 8; - } - - /* drop need bits and update buffer, always zero to seven bits left */ - s->bitbuf = val >> need; - s->bitcnt -= need; - - /* return need bits, zeroing the bits above that */ - return val & ((1 << need) - 1); -} - -/* - * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of - * each length, which for a canonical code are stepped through in order. - * symbol[] are the symbol values in canonical order, where the number of - * entries is the sum of the counts in count[]. The decoding process can be - * seen in the function decode() below. - */ -struct huffman { - short *count; /* number of symbols of each length */ - short *symbol; /* canonically ordered symbols */ -}; - -/* - * Decode a code from the stream s using huffman table h. Return the symbol or - * a negative value if there is an error. If all of the lengths are zero, i.e. - * an empty code, or if the code is incomplete and an invalid code is received, - * then -9 is returned after reading MAXBITS bits. - * - * Format notes: - * - * - The codes as stored in the compressed data are bit-reversed relative to - * a simple integer ordering of codes of the same lengths. Hence below the - * bits are pulled from the compressed data one at a time and used to - * build the code value reversed from what is in the stream in order to - * permit simple integer comparisons for decoding. - * - * - The first code for the shortest length is all ones. Subsequent codes of - * the same length are simply integer decrements of the previous code. When - * moving up a length, a one bit is appended to the code. For a complete - * code, the last code of the longest length will be all zeros. To support - * this ordering, the bits pulled during decoding are inverted to apply the - * more "natural" ordering starting with all zeros and incrementing. - */ -local int decode(struct state *s, struct huffman *h) -{ - int len; /* current number of bits in code */ - int code; /* len bits being decoded */ - int first; /* first code of length len */ - int count; /* number of codes of length len */ - int index; /* index of first code of length len in symbol table */ - int bitbuf; /* bits from stream */ - int left; /* bits left in next or left to process */ - short *next; /* next number of codes */ - - bitbuf = s->bitbuf; - left = s->bitcnt; - code = first = index = 0; - len = 1; - next = h->count + 1; - while (1) { - while (left--) { - code |= (bitbuf & 1) ^ 1; /* invert code */ - bitbuf >>= 1; - count = *next++; - if (code < first + count) { /* if length len, return symbol */ - s->bitbuf = bitbuf; - s->bitcnt = (s->bitcnt - len) & 7; - return h->symbol[index + (code - first)]; - } - index += count; /* else update for next length */ - first += count; - first <<= 1; - code <<= 1; - len++; - } - left = (MAXBITS+1) - len; - if (left == 0) break; - if (s->left == 0) { - s->left = s->infun(s->inhow, &(s->in)); - if (s->left == 0) longjmp(s->env, 1); /* out of input */ - } - bitbuf = *(s->in)++; - s->left--; - if (left > 8) left = 8; - } - return -9; /* ran out of codes */ -} - -/* - * Given a list of repeated code lengths rep[0..n-1], where each byte is a - * count (high four bits + 1) and a code length (low four bits), generate the - * list of code lengths. This compaction reduces the size of the object code. - * Then given the list of code lengths length[0..n-1] representing a canonical - * Huffman code for n symbols, construct the tables required to decode those - * codes. Those tables are the number of codes of each length, and the symbols - * sorted by length, retaining their original order within each length. The - * return value is zero for a complete code set, negative for an over- - * subscribed code set, and positive for an incomplete code set. The tables - * can be used if the return value is zero or positive, but they cannot be used - * if the return value is negative. If the return value is zero, it is not - * possible for decode() using that table to return an error--any stream of - * enough bits will resolve to a symbol. If the return value is positive, then - * it is possible for decode() using that table to return an error for received - * codes past the end of the incomplete lengths. - */ -local int construct(struct huffman *h, const unsigned char *rep, int n) -{ - int symbol; /* current symbol when stepping through length[] */ - int len; /* current length when stepping through h->count[] */ - int left; /* number of possible codes left of current length */ - short offs[MAXBITS+1]; /* offsets in symbol table for each length */ - short length[256]; /* code lengths */ - - /* convert compact repeat counts into symbol bit length list */ - symbol = 0; - do { - len = *rep++; - left = (len >> 4) + 1; - len &= 15; - do { - length[symbol++] = len; - } while (--left); - } while (--n); - n = symbol; - - /* count number of codes of each length */ - for (len = 0; len <= MAXBITS; len++) - h->count[len] = 0; - for (symbol = 0; symbol < n; symbol++) - (h->count[length[symbol]])++; /* assumes lengths are within bounds */ - if (h->count[0] == n) /* no codes! */ - return 0; /* complete, but decode() will fail */ - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; /* one possible code of zero length */ - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; /* one more bit, double codes left */ - left -= h->count[len]; /* deduct count from possible codes */ - if (left < 0) return left; /* over-subscribed--return negative */ - } /* left > 0 means incomplete */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + h->count[len]; - - /* - * put symbols in table sorted by length, by symbol order within each - * length - */ - for (symbol = 0; symbol < n; symbol++) - if (length[symbol] != 0) - h->symbol[offs[length[symbol]]++] = symbol; - - /* return zero for complete set, positive for incomplete set */ - return left; -} - -/* - * Decode PKWare Compression Library stream. - * - * Format notes: - * - * - First byte is 0 if literals are uncoded or 1 if they are coded. Second - * byte is 4, 5, or 6 for the number of extra bits in the distance code. - * This is the base-2 logarithm of the dictionary size minus six. - * - * - Compressed data is a combination of literals and length/distance pairs - * terminated by an end code. Literals are either Huffman coded or - * uncoded bytes. A length/distance pair is a coded length followed by a - * coded distance to represent a string that occurs earlier in the - * uncompressed data that occurs again at the current location. - * - * - A bit preceding a literal or length/distance pair indicates which comes - * next, 0 for literals, 1 for length/distance. - * - * - If literals are uncoded, then the next eight bits are the literal, in the - * normal bit order in the stream, i.e. no bit-reversal is needed. Similarly, - * no bit reversal is needed for either the length extra bits or the distance - * extra bits. - * - * - Literal bytes are simply written to the output. A length/distance pair is - * an instruction to copy previously uncompressed bytes to the output. The - * copy is from distance bytes back in the output stream, copying for length - * bytes. - * - * - Distances pointing before the beginning of the output data are not - * permitted. - * - * - Overlapped copies, where the length is greater than the distance, are - * allowed and common. For example, a distance of one and a length of 518 - * simply copies the last byte 518 times. A distance of four and a length of - * twelve copies the last four bytes three times. A simple forward copy - * ignoring whether the length is greater than the distance or not implements - * this correctly. - */ -local int decomp(struct state *s) -{ - int lit; /* true if literals are coded */ - int dict; /* log2(dictionary size) - 6 */ - int symbol; /* decoded symbol, extra bits for distance */ - int len; /* length for copy */ - unsigned dist; /* distance for copy */ - int copy; /* copy counter */ - unsigned char *from, *to; /* copy pointers */ - static int virgin = 1; /* build tables once */ - static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ - static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ - static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ - static struct huffman litcode = {litcnt, litsym}; /* length code */ - static struct huffman lencode = {lencnt, lensym}; /* length code */ - static struct huffman distcode = {distcnt, distsym};/* distance code */ - /* bit lengths of literal codes */ - static const unsigned char litlen[] = { - 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, - 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, - 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, - 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, - 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, - 44, 173}; - /* bit lengths of length codes 0..15 */ - static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; - /* bit lengths of distance codes 0..63 */ - static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; - static const short base[16] = { /* base for length codes */ - 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; - static const char extra[16] = { /* extra bits for length codes */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; - - /* set up decoding tables (once--might not be thread-safe) */ - if (virgin) { - construct(&litcode, litlen, sizeof(litlen)); - construct(&lencode, lenlen, sizeof(lenlen)); - construct(&distcode, distlen, sizeof(distlen)); - virgin = 0; - } - - /* read header */ - lit = bits(s, 8); - if (lit > 1) return -1; - dict = bits(s, 8); - if (dict < 4 || dict > 6) return -2; - - /* decode literals and length/distance pairs */ - do { - if (bits(s, 1)) { - /* get length */ - symbol = decode(s, &lencode); - len = base[symbol] + bits(s, extra[symbol]); - if (len == 519) break; /* end code */ - - /* get distance */ - symbol = len == 2 ? 2 : dict; - dist = decode(s, &distcode) << symbol; - dist += bits(s, symbol); - dist++; - if (s->first && dist > s->next) - return -3; /* distance too far back */ - - /* copy length bytes from distance bytes back */ - do { - to = s->out + s->next; - from = to - dist; - copy = MAXWIN; - if (s->next < dist) { - from += copy; - copy = dist; - } - copy -= s->next; - if (copy > len) copy = len; - len -= copy; - s->next += copy; - do { - *to++ = *from++; - } while (--copy); - if (s->next == MAXWIN) { - if (s->outfun(s->outhow, s->out, s->next)) return 1; - s->next = 0; - s->first = 0; - } - } while (len != 0); - } - else { - /* get literal and write it */ - symbol = lit ? decode(s, &litcode) : bits(s, 8); - s->out[s->next++] = symbol; - if (s->next == MAXWIN) { - if (s->outfun(s->outhow, s->out, s->next)) return 1; - s->next = 0; - s->first = 0; - } - } - } while (1); - return 0; -} - -/* See comments in blast.h */ -int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, - unsigned *left, unsigned char **in) -{ - struct state s; /* input/output state */ - int err; /* return value */ - - /* initialize input state */ - s.infun = infun; - s.inhow = inhow; - if (left != NULL && *left) { - s.left = *left; - s.in = *in; - } - else - s.left = 0; - s.bitbuf = 0; - s.bitcnt = 0; - - /* initialize output state */ - s.outfun = outfun; - s.outhow = outhow; - s.next = 0; - s.first = 1; - - /* return if bits() or decode() tries to read past available input */ - if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ - err = 2; /* then skip decomp(), return error */ - else - err = decomp(&s); /* decompress */ - - /* return unused input */ - if (left != NULL) - *left = s.left; - if (in != NULL) - *in = s.left ? s.in : NULL; - - /* write any leftover output and update the error code if needed */ - if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) - err = 1; - return err; -} - -#ifdef TEST -/* Example of how to use blast() */ -#include -#include - -#define CHUNK 16384 - -local unsigned inf(void *how, unsigned char **buf) -{ - static unsigned char hold[CHUNK]; - - *buf = hold; - return fread(hold, 1, CHUNK, (FILE *)how); -} - -local int outf(void *how, unsigned char *buf, unsigned len) -{ - return fwrite(buf, 1, len, (FILE *)how) != len; -} - -/* Decompress a PKWare Compression Library stream from stdin to stdout */ -int main(void) -{ - int ret; - unsigned left; - - /* decompress to stdout */ - left = 0; - ret = blast(inf, stdin, outf, stdout, &left, NULL); - if (ret != 0) - fprintf(stderr, "blast error: %d\n", ret); - - /* count any leftover bytes */ - while (getchar() != EOF) - left++; - if (left) - fprintf(stderr, "blast warning: %u unused bytes of input\n", left); - - /* return blast() error code */ - return ret; -} -#endif diff --git a/C/blast/blast.h b/C/blast/blast.h deleted file mode 100644 index 6cf65eda1..000000000 --- a/C/blast/blast.h +++ /dev/null @@ -1,83 +0,0 @@ -/* blast.h -- interface for blast.c - Copyright (C) 2003, 2012, 2013 Mark Adler - version 1.3, 24 Aug 2013 - - This software is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Mark Adler madler@alumni.caltech.edu - */ - - -/* - * blast() decompresses the PKWare Data Compression Library (DCL) compressed - * format. It provides the same functionality as the explode() function in - * that library. (Note: PKWare overused the "implode" verb, and the format - * used by their library implode() function is completely different and - * incompatible with the implode compression method supported by PKZIP.) - * - * The binary mode for stdio functions should be used to assure that the - * compressed data is not corrupted when read or written. For example: - * fopen(..., "rb") and fopen(..., "wb"). - */ - - -typedef unsigned (*blast_in)(void *how, unsigned char **buf); -typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); -/* Definitions for input/output functions passed to blast(). See below for - * what the provided functions need to do. - */ - - -int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, - unsigned *left, unsigned char **in); -/* Decompress input to output using the provided infun() and outfun() calls. - * On success, the return value of blast() is zero. If there is an error in - * the source data, i.e. it is not in the proper format, then a negative value - * is returned. If there is not enough input available or there is not enough - * output space, then a positive error is returned. - * - * The input function is invoked: len = infun(how, &buf), where buf is set by - * infun() to point to the input buffer, and infun() returns the number of - * available bytes there. If infun() returns zero, then blast() returns with - * an input error. (blast() only asks for input if it needs it.) inhow is for - * use by the application to pass an input descriptor to infun(), if desired. - * - * If left and in are not NULL and *left is not zero when blast() is called, - * then the *left bytes are *in are consumed for input before infun() is used. - * - * The output function is invoked: err = outfun(how, buf, len), where the bytes - * to be written are buf[0..len-1]. If err is not zero, then blast() returns - * with an output error. outfun() is always called with len <= 4096. outhow - * is for use by the application to pass an output descriptor to outfun(), if - * desired. - * - * If there is any unused input, *left is set to the number of bytes that were - * read and *in points to them. Otherwise *left is set to zero and *in is set - * to NULL. If left or in are NULL, then they are not set. - * - * The return codes are: - * - * 2: ran out of input before completing decompression - * 1: output error before completing decompression - * 0: successful decompression - * -1: literal flag not zero or one - * -2: dictionary size not in 4..6 - * -3: distance is too far back - * - * At the bottom of blast.c is an example program that uses blast() that can be - * compiled to produce a command-line decompression filter by defining TEST. - */ diff --git a/CPP/7zip/Bundles/Alone/makefile.list b/CPP/7zip/Bundles/Alone/makefile.list index ee9f5fc82..4dd8667b8 100644 --- a/CPP/7zip/Bundles/Alone/makefile.list +++ b/CPP/7zip/Bundles/Alone/makefile.list @@ -152,6 +152,9 @@ SRCS=\ ../../../../CPP/7zip/Compress/BrotliDecoder.cpp \ ../../../../CPP/7zip/Compress/BrotliEncoder.cpp \ ../../../../CPP/7zip/Compress/BrotliRegister.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/7zip/Crypto/7zAes.cpp \ ../../../../CPP/7zip/Crypto/7zAesRegister.cpp \ ../../../../CPP/7zip/Crypto/HmacSha1.cpp \ @@ -359,6 +362,8 @@ SRCS_C=\ ../../../../C/brotli/br_static_dict.c \ ../../../../C/brotli/br_transform.c \ ../../../../C/brotli/br_utf8_util.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ StdAfx.h.gch : ../../../myWindows/StdAfx.h rm -f StdAfx.h.gch @@ -627,6 +632,10 @@ br_transform.o : ../../../../C/brotli/br_transform.c $(CC) $(CFLAGS) ../../../../C/brotli/br_transform.c br_utf8_util.o : ../../../../C/brotli/br_utf8_util.c $(CC) $(CFLAGS) ../../../../C/brotli/br_utf8_util.c +explode.o : ../../../../C/pklib/explode.c + $(CC) $(CFLAGS) ../../../../C/pklib/explode.c +implode.o : ../../../../C/pklib/implode.c + $(CC) $(CFLAGS) ../../../../C/pklib/implode.c 7zCompressionMode.o : ../../../../CPP/7zip/Archive/7z/7zCompressionMode.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Archive/7z/7zCompressionMode.cpp 7zDecode.o : ../../../../CPP/7zip/Archive/7z/7zDecode.cpp @@ -891,6 +900,12 @@ BrotliEncoder.o : ../../../../CPP/7zip/Compress/BrotliEncoder.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/BrotliEncoder.cpp BrotliRegister.o : ../../../../CPP/7zip/Compress/BrotliRegister.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/BrotliRegister.cpp +PKImplodeEncoder.o : ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp +PKImplodeDecoder.o : ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp +PKImplodeRegister.o : ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp 7zAes.o : ../../../../CPP/7zip/Crypto/7zAes.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Crypto/7zAes.cpp 7zAesRegister.o : ../../../../CPP/7zip/Crypto/7zAesRegister.cpp @@ -1171,6 +1186,8 @@ OBJS=\ br_static_dict.o \ br_transform.o \ br_utf8_util.o \ + explode.o \ + implode.o \ 7zCompressionMode.o \ 7zDecode.o \ 7zEncode.o \ @@ -1303,6 +1320,9 @@ OBJS=\ BrotliDecoder.o \ BrotliEncoder.o \ BrotliRegister.o \ + PKImplodeEncoder.o \ + PKImplodeDecoder.o \ + PKImplodeRegister.o \ 7zAes.o \ 7zAesRegister.o \ HmacSha1.o \ diff --git a/CPP/7zip/Bundles/Format7zFree/makefile.list b/CPP/7zip/Bundles/Format7zFree/makefile.list index 71a460385..e60f34e31 100644 --- a/CPP/7zip/Bundles/Format7zFree/makefile.list +++ b/CPP/7zip/Bundles/Format7zFree/makefile.list @@ -210,6 +210,9 @@ SRCS=\ ../../../../CPP/7zip/Compress/BrotliDecoder.cpp \ ../../../../CPP/7zip/Compress/BrotliEncoder.cpp \ ../../../../CPP/7zip/Compress/BrotliRegister.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/7zip/Crypto/7zAes.cpp \ ../../../../CPP/7zip/Crypto/7zAesRegister.cpp \ ../../../../CPP/7zip/Crypto/HmacSha1.cpp \ @@ -395,6 +398,8 @@ SRCS_C=\ ../../../../C/brotli/br_static_dict.c \ ../../../../C/brotli/br_transform.c \ ../../../../C/brotli/br_utf8_util.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ ../../../../C/hashes/md2.c \ ../../../../C/hashes/md4.c \ ../../../../C/hashes/md5.c \ @@ -671,6 +676,10 @@ br_transform.o : ../../../../C/brotli/br_transform.c $(CC) $(CFLAGS) ../../../../C/brotli/br_transform.c br_utf8_util.o : ../../../../C/brotli/br_utf8_util.c $(CC) $(CFLAGS) ../../../../C/brotli/br_utf8_util.c +explode.o : ../../../../C/pklib/explode.c + $(CC) $(CFLAGS) ../../../../C/pklib/explode.c +implode.o : ../../../../C/pklib/implode.c + $(CC) $(CFLAGS) ../../../../C/pklib/implode.c md2.o : ../../../../C/hashes/md2.c $(CC) $(CFLAGS) ../../../../C/hashes/md2.c md4.o : ../../../../C/hashes/md4.c @@ -1057,6 +1066,12 @@ BrotliEncoder.o : ../../../../CPP/7zip/Compress/BrotliEncoder.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/BrotliEncoder.cpp BrotliRegister.o : ../../../../CPP/7zip/Compress/BrotliRegister.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/BrotliRegister.cpp +PKImplodeEncoder.o : ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp +PKImplodeDecoder.o : ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp +PKImplodeRegister.o : ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp 7zAes.o : ../../../../CPP/7zip/Crypto/7zAes.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/Crypto/7zAes.cpp 7zAesRegister.o : ../../../../CPP/7zip/Crypto/7zAesRegister.cpp @@ -1291,6 +1306,8 @@ OBJS=\ br_static_dict.o \ br_transform.o \ br_utf8_util.o \ + explode.o \ + implode.o \ md2.o \ md4.o \ md5.o \ @@ -1484,6 +1501,9 @@ OBJS=\ BrotliDecoder.o \ BrotliEncoder.o \ BrotliRegister.o \ + PKImplodeEncoder.o \ + PKImplodeDecoder.o \ + PKImplodeRegister.o \ 7zAes.o \ 7zAesRegister.o \ HmacSha1.o \ diff --git a/CPP/7zip/CMAKE/7za/CMakeLists.txt b/CPP/7zip/CMAKE/7za/CMakeLists.txt index 469e3254e..d73ecf1b2 100644 --- a/CPP/7zip/CMAKE/7za/CMakeLists.txt +++ b/CPP/7zip/CMAKE/7za/CMakeLists.txt @@ -150,6 +150,8 @@ add_executable(7za "../../../../C/brotli/br_static_dict.c" "../../../../C/brotli/br_transform.c" "../../../../C/brotli/br_utf8_util.c" + "../../../../C/pklib/explode.c" + "../../../../C/pklib/implode.c" "../../../../CPP/7zip/Archive/7z/7zCompressionMode.cpp" "../../../../CPP/7zip/Archive/7z/7zDecode.cpp" "../../../../CPP/7zip/Archive/7z/7zEncode.cpp" @@ -282,6 +284,9 @@ add_executable(7za "../../../../CPP/7zip/Compress/BrotliDecoder.cpp" "../../../../CPP/7zip/Compress/BrotliEncoder.cpp" "../../../../CPP/7zip/Compress/BrotliRegister.cpp" + "../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp" + "../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp" + "../../../../CPP/7zip/Compress/PKImplodeRegister.cpp" "../../../../CPP/7zip/Crypto/7zAes.cpp" "../../../../CPP/7zip/Crypto/7zAesRegister.cpp" "../../../../CPP/7zip/Crypto/HmacSha1.cpp" diff --git a/CPP/7zip/CMAKE/Format7zFree/CMakeLists.txt b/CPP/7zip/CMAKE/Format7zFree/CMakeLists.txt index 89f6d4f31..43923d6e3 100644 --- a/CPP/7zip/CMAKE/Format7zFree/CMakeLists.txt +++ b/CPP/7zip/CMAKE/Format7zFree/CMakeLists.txt @@ -152,6 +152,8 @@ add_library(7z MODULE "../../../../C/brotli/br_static_dict.c" "../../../../C/brotli/br_transform.c" "../../../../C/brotli/br_utf8_util.c" + "../../../../C/pklib/explode.c" + "../../../../C/pklib/implode.c" "../../../../C/hashes/md2.c" "../../../../C/hashes/md4.c" "../../../../C/hashes/md5.c" @@ -345,6 +347,9 @@ add_library(7z MODULE "../../../../CPP/7zip/Compress/BrotliDecoder.cpp" "../../../../CPP/7zip/Compress/BrotliEncoder.cpp" "../../../../CPP/7zip/Compress/BrotliRegister.cpp" + "../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp" + "../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp" + "../../../../CPP/7zip/Compress/PKImplodeRegister.cpp" "../../../../CPP/7zip/Crypto/7zAes.cpp" "../../../../CPP/7zip/Crypto/7zAesRegister.cpp" "../../../../CPP/7zip/Crypto/HmacSha1.cpp" diff --git a/CPP/7zip/Compress/PKImplode/makefile.list b/CPP/7zip/Compress/PKImplode/makefile.list index 2483945e1..5ff0d7ffa 100644 --- a/CPP/7zip/Compress/PKImplode/makefile.list +++ b/CPP/7zip/Compress/PKImplode/makefile.list @@ -29,7 +29,6 @@ SRCS=\ ../../../../CPP/Common/MyWindows.cpp \ SRCS_C=\ - ../../../../C/blast/blast.c \ ../../../../C/pklib/explode.c \ ../../../../C/pklib/implode.c \ ../../../../C/Alloc.c \ @@ -37,8 +36,6 @@ SRCS_C=\ StdAfx.h.gch : ../../../myWindows/StdAfx.h rm -f StdAfx.h.gch $(CXX) $(CXXFLAGS) ../../../myWindows/StdAfx.h -o StdAfx.h.gch -blast.o : ../../../../C/blast/blast.c - $(CC) $(CFLAGS) ../../../../C/blast/blast.c explode.o : ../../../../C/pklib/explode.c $(CC) $(CFLAGS) ../../../../C/pklib/explode.c implode.o : ../../../../C/pklib/implode.c @@ -65,7 +62,6 @@ MyWindows.o : ../../../../CPP/Common/MyWindows.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/MyWindows.cpp OBJS=\ - blast.o \ explode.o \ implode.o \ Alloc.o \ diff --git a/CPP/7zip/Compress/PKImplodeDecoder.cpp b/CPP/7zip/Compress/PKImplodeDecoder.cpp index 1a53274a1..10be722e2 100644 --- a/CPP/7zip/Compress/PKImplodeDecoder.cpp +++ b/CPP/7zip/Compress/PKImplodeDecoder.cpp @@ -8,34 +8,33 @@ #include "PKImplodeDecoder.h" #include "../../Common/StreamUtils.h" -extern "C" { -#include "../../../C/blast/blast.h" -} - namespace NCompress { namespace NPKImplode { namespace NDecoder { -static int BLAST_put(void *out_desc, unsigned char *buf, unsigned int len){ - CDecoder *w = (CDecoder*)out_desc; +static void C_put(char *buf, unsigned int *size, void *param){ + CDecoder *w = (CDecoder*)param; UInt32 rlen=0; - HRESULT res = w->outS->Write(buf, len, &rlen); + HRESULT res = w->outS->Write(buf, *size, &rlen); + //*size = rlen; w->processedOut += rlen; if(w->progr) w->progr->SetRatioInfo(&w->processedIn, &w->processedOut); - return res != S_OK || rlen != len; + //return res != S_OK || rlen != len; } -static unsigned int BLAST_get(void *in_desc, unsigned char **buf){ - CDecoder *r = (CDecoder*)in_desc; - *buf = r->buf; - size_t readsize = kS; - HRESULT res = ReadStream(r->inS,r->buf,&readsize); +static unsigned int C_get(char *buf, unsigned int *size, void *param){ + CDecoder *r = (CDecoder*)param; + size_t readsize = *size; + HRESULT res = ReadStream(r->inS,buf,&readsize); + //*size = readsize; r->processedIn += readsize; return res != S_OK ? 0 : readsize; } -CDecoder::CDecoder(){} +CDecoder::CDecoder(){ + memset(&DcmpStruct, 0, sizeof(TDcmpStruct)); +} HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) @@ -44,7 +43,7 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * outS = outStream; progr = progress; processedIn = processedOut = 0; - int x = blast(BLAST_get, this, BLAST_put, this, NULL, NULL); + int x = explode(C_get, C_put, (char*)&DcmpStruct, this); if(x<0)return E_FAIL; if(x==2)return E_ABORT; if(x==1)return E_OUTOFMEMORY; @@ -68,4 +67,3 @@ STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) } }}} - diff --git a/CPP/7zip/Compress/PKImplodeDecoder.h b/CPP/7zip/Compress/PKImplodeDecoder.h index 99f8da3b7..af7e691cf 100644 --- a/CPP/7zip/Compress/PKImplodeDecoder.h +++ b/CPP/7zip/Compress/PKImplodeDecoder.h @@ -9,6 +9,10 @@ #include "../Common/InBuffer.h" +extern "C" { +#include "../../../C/pklib/pklib.h" +} + namespace NCompress { namespace NPKImplode { namespace NDecoder { @@ -31,6 +35,8 @@ class CDecoder: ISequentialOutStream *outS; ICompressProgressInfo *progr; + TDcmpStruct DcmpStruct; + MY_UNKNOWN_IMP1(ICompressGetInStreamProcessedSize) STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, diff --git a/Utils/file_7z_so.py b/Utils/file_7z_so.py index 513029711..d2ff976b6 100644 --- a/Utils/file_7z_so.py +++ b/Utils/file_7z_so.py @@ -134,7 +134,8 @@ 'C/brotli/br_static_dict.c', 'C/brotli/br_transform.c', 'C/brotli/br_utf8_util.c', - 'C/blast/blast.c', + 'C/pklib/explode.c', + 'C/pklib/implode.c', 'C/hashes/md2.c', 'C/hashes/md4.c', 'C/hashes/md5.c', @@ -331,7 +332,9 @@ 'CPP/7zip/Compress/BrotliDecoder.cpp', 'CPP/7zip/Compress/BrotliEncoder.cpp', 'CPP/7zip/Compress/BrotliRegister.cpp', + 'CPP/7zip/Compress/PKImplodeEncoder.cpp', 'CPP/7zip/Compress/PKImplodeDecoder.cpp', + 'CPP/7zip/Compress/PKImplodeRegister.cpp', 'CPP/7zip/Crypto/7zAes.cpp', 'CPP/7zip/Crypto/7zAesRegister.cpp', 'CPP/7zip/Crypto/HmacSha1.cpp', diff --git a/Utils/file_7za.py b/Utils/file_7za.py index 24f5a5c83..aa7823d60 100644 --- a/Utils/file_7za.py +++ b/Utils/file_7za.py @@ -132,7 +132,8 @@ 'C/brotli/br_static_dict.c', 'C/brotli/br_transform.c', 'C/brotli/br_utf8_util.c', - 'C/blast/blast.c', + 'C/pklib/explode.c', + 'C/pklib/implode.c', ] files_cpp=[ @@ -268,7 +269,9 @@ 'CPP/7zip/Compress/BrotliDecoder.cpp', 'CPP/7zip/Compress/BrotliEncoder.cpp', 'CPP/7zip/Compress/BrotliRegister.cpp', + 'CPP/7zip/Compress/PKImplodeEncoder.cpp', 'CPP/7zip/Compress/PKImplodeDecoder.cpp', + 'CPP/7zip/Compress/PKImplodeRegister.cpp', 'CPP/7zip/Crypto/7zAes.cpp', 'CPP/7zip/Crypto/7zAesRegister.cpp', 'CPP/7zip/Crypto/HmacSha1.cpp', diff --git a/Utils/file_Codecs_PKImplode_so.py b/Utils/file_Codecs_PKImplode_so.py index 7e75200b3..288b31d8a 100644 --- a/Utils/file_Codecs_PKImplode_so.py +++ b/Utils/file_Codecs_PKImplode_so.py @@ -1,6 +1,5 @@ files_c=[ - 'C/blast/blast.c', 'C/pklib/explode.c', 'C/pklib/implode.c', #'C/7zCrcOpt.c', From b59cb43aa85cf212262f5ac4067b7729e6fa8ded Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 10 Jan 2022 11:42:37 +0900 Subject: [PATCH 6/8] add pklib LICENSE --- C/pklib/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 C/pklib/LICENSE diff --git a/C/pklib/LICENSE b/C/pklib/LICENSE new file mode 100644 index 000000000..2cb432d4e --- /dev/null +++ b/C/pklib/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 1999-2013 Ladislav Zezula + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 3dee7659ba63bba4cb28300e64e1a8e959d56e92 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 10 Jan 2022 21:11:15 +0900 Subject: [PATCH 7/8] link pkimplode to 7z.so --- CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 8 ++++++++ CPP/7zip/Archive/Zip/ZipHeader.h | 1 + 2 files changed, 9 insertions(+) diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 7d41d334f..96a673c1c 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -19,6 +19,7 @@ #include "../../Compress/PpmdZip.h" #include "../../Compress/XzEncoder.h" #include "../../Compress/ZstdEncoder.h" +#include "../../Compress/PKImplodeEncoder.h" #include "../Common/InStreamWithCRC.h" @@ -181,6 +182,7 @@ HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, U case NCompressionMethod::kPPMd : ver = NCompressionMethod::kExtractVersion_PPMd; break; case NCompressionMethod::kBZip2: ver = NCompressionMethod::kExtractVersion_BZip2; break; case NCompressionMethod::kZstd: ver = NCompressionMethod::kExtractVersion_Zstd; break; + case NCompressionMethod::kPKImploding: ver = NCompressionMethod::kExtractVersion_PKImploding; break; case NCompressionMethod::kLZMA : { ver = NCompressionMethod::kExtractVersion_LZMA; @@ -376,6 +378,12 @@ HRESULT CAddCommon::Compress( NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder(); _compressEncoder = encoder; } + else if (method == NCompressionMethod::kPKImploding) + { + _compressExtractVersion = NCompressionMethod::kExtractVersion_PKImploding; + NCompress::NPKImplode::NEncoder::CEncoder *encoder = new NCompress::NPKImplode::NEncoder::CEncoder(); + _compressEncoder = encoder; + } else { CMethodId methodId; diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index 5439fa03c..d9a063015 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -72,6 +72,7 @@ namespace NFileHeader const Byte kExtractVersion_ZipCrypto = 20; const Byte kExtractVersion_Deflate = 20; const Byte kExtractVersion_Deflate64 = 21; + const Byte kExtractVersion_PKImploding = 25; const Byte kExtractVersion_Zip64 = 45; const Byte kExtractVersion_BZip2 = 46; const Byte kExtractVersion_Aes = 51; From 312deab2499fa973c4df649fbf078ffe7ea5dbde Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 10 Jan 2022 21:11:37 +0900 Subject: [PATCH 8/8] apply generate.py --- CPP/7zip/PREMAKE/premake4.lua | 5 +++++ CPP/7zip/QMAKE/7za/7za.pro | 5 +++++ CPP/7zip/QMAKE/Format7zFree/Format7zFree.pro | 5 +++++ CPP/ANDROID/7za/jni/Android.mk | 5 +++++ CPP/ANDROID/Format7zFree/jni/Android.mk | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/CPP/7zip/PREMAKE/premake4.lua b/CPP/7zip/PREMAKE/premake4.lua index 431c6ba50..0b9a73fd2 100644 --- a/CPP/7zip/PREMAKE/premake4.lua +++ b/CPP/7zip/PREMAKE/premake4.lua @@ -154,6 +154,8 @@ solution "p7zip" "../../../../C/brotli/br_static_dict.c", "../../../../C/brotli/br_transform.c", "../../../../C/brotli/br_utf8_util.c", + "../../../../C/pklib/explode.c", + "../../../../C/pklib/implode.c", } --------------------------------- @@ -293,6 +295,9 @@ solution "p7zip" "../../../../CPP/7zip/Compress/BrotliDecoder.cpp", "../../../../CPP/7zip/Compress/BrotliEncoder.cpp", "../../../../CPP/7zip/Compress/BrotliRegister.cpp", + "../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp", + "../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp", + "../../../../CPP/7zip/Compress/PKImplodeRegister.cpp", "../../../../CPP/7zip/Crypto/7zAes.cpp", "../../../../CPP/7zip/Crypto/7zAesRegister.cpp", "../../../../CPP/7zip/Crypto/HmacSha1.cpp", diff --git a/CPP/7zip/QMAKE/7za/7za.pro b/CPP/7zip/QMAKE/7za/7za.pro index 955e49b9f..55bd73d77 100644 --- a/CPP/7zip/QMAKE/7za/7za.pro +++ b/CPP/7zip/QMAKE/7za/7za.pro @@ -164,6 +164,8 @@ SOURCES += \ ../../../../C/brotli/br_static_dict.c \ ../../../../C/brotli/br_transform.c \ ../../../../C/brotli/br_utf8_util.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ ../../../../CPP/7zip/Archive/7z/7zCompressionMode.cpp \ ../../../../CPP/7zip/Archive/7z/7zDecode.cpp \ ../../../../CPP/7zip/Archive/7z/7zEncode.cpp \ @@ -296,6 +298,9 @@ SOURCES += \ ../../../../CPP/7zip/Compress/BrotliDecoder.cpp \ ../../../../CPP/7zip/Compress/BrotliEncoder.cpp \ ../../../../CPP/7zip/Compress/BrotliRegister.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/7zip/Crypto/7zAes.cpp \ ../../../../CPP/7zip/Crypto/7zAesRegister.cpp \ ../../../../CPP/7zip/Crypto/HmacSha1.cpp \ diff --git a/CPP/7zip/QMAKE/Format7zFree/Format7zFree.pro b/CPP/7zip/QMAKE/Format7zFree/Format7zFree.pro index c61f885e0..2eb2ca0cd 100644 --- a/CPP/7zip/QMAKE/Format7zFree/Format7zFree.pro +++ b/CPP/7zip/QMAKE/Format7zFree/Format7zFree.pro @@ -166,6 +166,8 @@ SOURCES += \ ../../../../C/brotli/br_static_dict.c \ ../../../../C/brotli/br_transform.c \ ../../../../C/brotli/br_utf8_util.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ ../../../../C/hashes/md2.c \ ../../../../C/hashes/md4.c \ ../../../../C/hashes/md5.c \ @@ -359,6 +361,9 @@ SOURCES += \ ../../../../CPP/7zip/Compress/BrotliDecoder.cpp \ ../../../../CPP/7zip/Compress/BrotliEncoder.cpp \ ../../../../CPP/7zip/Compress/BrotliRegister.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/7zip/Crypto/7zAes.cpp \ ../../../../CPP/7zip/Crypto/7zAesRegister.cpp \ ../../../../CPP/7zip/Crypto/HmacSha1.cpp \ diff --git a/CPP/ANDROID/7za/jni/Android.mk b/CPP/ANDROID/7za/jni/Android.mk index 16eb8fb5e..b60364533 100644 --- a/CPP/ANDROID/7za/jni/Android.mk +++ b/CPP/ANDROID/7za/jni/Android.mk @@ -170,6 +170,9 @@ LOCAL_SRC_FILES := \ ../../../../CPP/7zip/Compress/BrotliDecoder.cpp \ ../../../../CPP/7zip/Compress/BrotliEncoder.cpp \ ../../../../CPP/7zip/Compress/BrotliRegister.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/7zip/Crypto/7zAes.cpp \ ../../../../CPP/7zip/Crypto/7zAesRegister.cpp \ ../../../../CPP/7zip/Crypto/HmacSha1.cpp \ @@ -375,6 +378,8 @@ LOCAL_SRC_FILES := \ ../../../../C/brotli/br_static_dict.c \ ../../../../C/brotli/br_transform.c \ ../../../../C/brotli/br_utf8_util.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ # Needed since ANDROID 5, these programs run on android-16 (Android 4.1+) LOCAL_CFLAGS += -fPIE diff --git a/CPP/ANDROID/Format7zFree/jni/Android.mk b/CPP/ANDROID/Format7zFree/jni/Android.mk index eed1f650c..dd9d2a310 100644 --- a/CPP/ANDROID/Format7zFree/jni/Android.mk +++ b/CPP/ANDROID/Format7zFree/jni/Android.mk @@ -211,6 +211,9 @@ LOCAL_SRC_FILES := \ ../../../../CPP/7zip/Compress/BrotliDecoder.cpp \ ../../../../CPP/7zip/Compress/BrotliEncoder.cpp \ ../../../../CPP/7zip/Compress/BrotliRegister.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeEncoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeDecoder.cpp \ + ../../../../CPP/7zip/Compress/PKImplodeRegister.cpp \ ../../../../CPP/7zip/Crypto/7zAes.cpp \ ../../../../CPP/7zip/Crypto/7zAesRegister.cpp \ ../../../../CPP/7zip/Crypto/HmacSha1.cpp \ @@ -394,6 +397,8 @@ LOCAL_SRC_FILES := \ ../../../../C/brotli/br_static_dict.c \ ../../../../C/brotli/br_transform.c \ ../../../../C/brotli/br_utf8_util.c \ + ../../../../C/pklib/explode.c \ + ../../../../C/pklib/implode.c \ ../../../../C/hashes/md2.c \ ../../../../C/hashes/md4.c \ ../../../../C/hashes/md5.c \