Yes, but ZPAQ has not yet been widely adopted, and I think the reason is the lack of very fast compression models. Going to a higher level maintains backward compatibility with old archives, but you will need to update the decompresser to read new archives. Also, existing models (non-empty COMP section) would still be saved in level 1 format.
Here are some process times (2.0 GHz T3200, Win32, g++ 4.6.1 -O3) on a ZRLE encoder and decoder with enwik8:
zrle c enwik8 enwik8.copy 1.0s (copy)
zrle c enwik8 nul: 0.6s
zrle e enwik8 enwik8.zrle 1.4s (encode)
zrle e enwik8 nul: 1.0s
zrle d enwik8.zrle enwik8 1.7s (decode)
zrle d enwik8.zrle nul: 1.3s
The encoder encodes runs of k=3..255 zero bytes as (0 0 0 k) and marks EOF with (0 0 0 0).
Code:
#include <stdio.h>
int main(int argc, char** argv) {
FILE* in=fopen(argv[2], "rb");
FILE* out=fopen(argv[3], "wb");
int c;
unsigned int z=0;
switch(argv[1][0]) {
case 'c': // copy
while ((c=getc(in))!=EOF) putc(c, out);
break;
case 'e': // ZRLE encode
while ((c=getc(in))!=EOF) {
if (c) {
if (z>2) fprintf(out, "%c%c%c%c", 0, 0, 0, z), z=0;
else for (; z; --z) putc(0, out);
putc(c, out);
}
else {
if (z==255) fprintf(out, "%c%c%c%c", 0, 0, 0, 255), z=0;
++z;
}
}
if (z) fprintf(out, "%c%c%c%c", 0, 0, 0, z);
fprintf(out, "%c%c%c%c", 0, 0, 0, 0);
break;
case 'd': // ZRLE decode
z=getc(in);
z=z<<8|getc(in);
z=z<<8|getc(in);
z=z<<8|getc(in);
while (z) {
if (z>255)
c=z>>24, z=z<<8|getc(in), putc(c, out);
else {
putc(0, out);
if (--z==0) {
z=getc(in);
z=z<<8|getc(in);
z=z<<8|getc(in);
z=z<<8|getc(in);
}
}
}
break;
}
return 0;
}
Edit: the following decodes 0.1 sec. faster:
Code:
while (z) {
if (z>255) {
z=z<<8|z>>24;
putc(z, out);
z=z&-256|getc(in);
}
Edit: some more tests using block encoding with the block size in the header. This appears to be faster.
zrle b enwik8 enwik8.block 1.0s
zrle b enwik8 nul: 0.6s
zrle a enwik8.block enwik8 1.0s
zrle a enwik8 nul: 0.6s
Code:
case 'b': // block encode with size in header
fseek(in, 0, SEEK_END);
z=ftell(in);
rewind(in);
fprintf(out, "%c%c%c%c", z>>24, z>>16, z>>8, z);
while ((c=getc(in))!=EOF) putc(c, out);
break;
case 'a': // block decode
z=getc(in);
z=z<<8|getc(in);
z=z<<8|getc(in);
z=z<<8|getc(in);
for (; z; --z) putc(getc(in), out);
break;