Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
|
|
@ -1,3 +1,3 @@
|
|||
The Lempel-Ziv-Welch (LZW) algorithm provides lossless data compression.
|
||||
You can read a complete description of it in the [[wp:Lempel-Ziv-Welch|Wikipedia article]] on the subject.
|
||||
It was patented, but it fell in the public domain in 2004.
|
||||
It was patented, but it entered the public domain in 2004.
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ byte* lzw_encode(byte *in, int max_bits)
|
|||
ushort code, c, nc, next_code = M_NEW;
|
||||
lzw_enc_t *d = _new(lzw_enc_t, 512);
|
||||
|
||||
if (max_bits > 16) max_bits = 16;
|
||||
if (max_bits > 15) max_bits = 15;
|
||||
if (max_bits < 9 ) max_bits = 12;
|
||||
|
||||
byte *out = _new(ushort, 4);
|
||||
|
|
|
|||
36
Task/LZW-compression/CoffeeScript/lzw-compression.coffee
Normal file
36
Task/LZW-compression/CoffeeScript/lzw-compression.coffee
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
lzw = (s) ->
|
||||
dct = {} # map substrings to codes between 256 and 4096
|
||||
stream = [] # array of compression results
|
||||
|
||||
# initialize basic ASCII characters
|
||||
for code_num in [0..255]
|
||||
c = String.fromCharCode(code_num)
|
||||
dct[c] = code_num
|
||||
code_num = 256
|
||||
|
||||
i = 0
|
||||
while i < s.length
|
||||
# Find word and new_word
|
||||
# word = longest substr already encountered, or next character
|
||||
# new_word = word plus next character, a new substr to encode
|
||||
word = ''
|
||||
j = i
|
||||
while j < s.length
|
||||
new_word = word + s[j]
|
||||
break if !dct[new_word]
|
||||
word = new_word
|
||||
j += 1
|
||||
|
||||
# stream out the code for the substring
|
||||
stream.push dct[word]
|
||||
|
||||
# build up our encoding dictionary
|
||||
if code_num < 4096
|
||||
dct[new_word] = code_num
|
||||
code_num += 1
|
||||
|
||||
# advance thru the string
|
||||
i += word.length
|
||||
stream
|
||||
|
||||
console.log lzw "TOBEORNOTTOBEORTOBEORNOT"
|
||||
|
|
@ -14,7 +14,7 @@ struct LZW {
|
|||
bytes[i] = i;
|
||||
}
|
||||
|
||||
static Tcomp[] compress(immutable scope T[] original) pure nothrow
|
||||
static Tcomp[] compress(immutable scope T[] original) pure nothrow @safe
|
||||
out(result) {
|
||||
if (!original.empty)
|
||||
assert(result[0] < initDictSize);
|
||||
|
|
@ -28,7 +28,7 @@ struct LZW {
|
|||
// Here built-in slices give lower efficiency.
|
||||
struct Slice {
|
||||
size_t start, end;
|
||||
@property opSlice() const pure nothrow {
|
||||
@property opSlice() const pure nothrow @safe @nogc {
|
||||
return original[start .. end];
|
||||
}
|
||||
alias opSlice this;
|
||||
|
|
@ -53,7 +53,7 @@ struct LZW {
|
|||
return result;
|
||||
}
|
||||
|
||||
static Ta decompress(in Tcomp[] compressed) pure
|
||||
static Ta decompress(in Tcomp[] compressed) pure @safe
|
||||
in {
|
||||
if (!compressed.empty)
|
||||
assert(compressed[0] < initDictSize, "Bad compressed");
|
||||
|
|
@ -91,6 +91,5 @@ void main() {
|
|||
immutable txt = "TOBEORNOTTOBEORTOBEORNOT";
|
||||
immutable compressed = LZW.compress(txt.representation);
|
||||
compressed.writeln;
|
||||
//LZW.decompress(compressed).unrepresentation.writeln;
|
||||
writeln(cast(string)LZW.decompress(compressed));
|
||||
LZW.decompress(compressed).assumeUTF.writeln;
|
||||
}
|
||||
|
|
|
|||
222
Task/LZW-compression/D/lzw-compression-3.d
Normal file
222
Task/LZW-compression/D/lzw-compression-3.d
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
enum Marker: ushort {
|
||||
CLR = 256, // Clear table marker.
|
||||
EOD = 257, // End-of-data marker.
|
||||
NEW = 258 // New code index.
|
||||
}
|
||||
|
||||
|
||||
ubyte[] lzwEncode(scope const(ubyte)[] inp, in uint maxBits) pure nothrow
|
||||
in {
|
||||
assert(maxBits >= 9 && maxBits <= 16);
|
||||
} body {
|
||||
// Encode dictionary array. For encoding, entry at
|
||||
// code index is a list of indices that follow current one,
|
||||
// i.e. if code 97 is 'a', code 387 is 'ab', and code 1022 is 'abc',
|
||||
// then dict[97].next['b'] = 387, dict[387].next['c'] = 1022, etc.
|
||||
alias LZWenc = ushort[256];
|
||||
|
||||
auto len = inp.length;
|
||||
uint bits = 9;
|
||||
auto d = new LZWenc[512];
|
||||
|
||||
auto result = new ubyte[16];
|
||||
size_t outLen = 0;
|
||||
size_t oBits = 0;
|
||||
uint tmp = 0;
|
||||
|
||||
void writeBits(in ushort x) nothrow {
|
||||
tmp = (tmp << bits) | x;
|
||||
oBits += bits;
|
||||
if (result.length / 2 <= outLen)
|
||||
result.length *= 2;
|
||||
while (oBits >= 8) {
|
||||
oBits -= 8;
|
||||
assert(tmp >> oBits <= ubyte.max);
|
||||
result[outLen] = cast(ubyte)(tmp >> oBits);
|
||||
outLen++;
|
||||
tmp &= (1 << oBits) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// writeBits(Marker.CLR);
|
||||
ushort nextCode = Marker.NEW;
|
||||
uint nextShift = 512;
|
||||
ushort code = inp[0];
|
||||
inp = inp[1 .. $]; // popFront.
|
||||
while (--len) {
|
||||
ushort c = inp[0];
|
||||
inp = inp[1 .. $]; // popFront.
|
||||
ushort nc = d[code][c];
|
||||
if (nc) {
|
||||
code = nc;
|
||||
} else {
|
||||
writeBits(code);
|
||||
nc = d[code][c] = nextCode;
|
||||
nextCode++;
|
||||
code = c;
|
||||
}
|
||||
|
||||
// Next new code would be too long for current table.
|
||||
if (nextCode == nextShift) {
|
||||
// Either reset table back to 9 bits.
|
||||
bits++;
|
||||
if (bits > maxBits) {
|
||||
// Table clear marker must occur before bit reset.
|
||||
writeBits(Marker.CLR);
|
||||
|
||||
bits = 9;
|
||||
nextShift = 512;
|
||||
nextCode = Marker.NEW;
|
||||
d[] = LZWenc.init;
|
||||
} else { // Or extend table.
|
||||
nextShift *= 2;
|
||||
d.length = nextShift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeBits(code);
|
||||
writeBits(Marker.EOD);
|
||||
if (tmp) {
|
||||
assert(tmp <= ushort.max);
|
||||
writeBits(cast(ushort)tmp);
|
||||
}
|
||||
|
||||
return result[0 .. outLen];
|
||||
}
|
||||
|
||||
|
||||
ubyte[] lzwDecode(scope const(ubyte)[] inp) pure {
|
||||
// For decoding, dictionary contains index of whatever prefix
|
||||
// index plus trailing ubyte. i.e. like previous example,
|
||||
// dict[1022] = { c: 'c', prev: 387 },
|
||||
// dict[387] = { c: 'b', prev: 97 },
|
||||
// dict[97] = { c: 'a', prev: 0 }
|
||||
// the "back" element is used for temporarily chaining indices
|
||||
// when resolving a code to bytes.
|
||||
static struct LZWdec {
|
||||
ushort prev, back;
|
||||
ubyte c;
|
||||
}
|
||||
|
||||
auto result = new ubyte[4];
|
||||
uint outLen = 0;
|
||||
|
||||
void writeOut(in ubyte c) nothrow {
|
||||
while (outLen >= result.length)
|
||||
result.length *= 2;
|
||||
result[outLen] = c;
|
||||
outLen++;
|
||||
}
|
||||
|
||||
auto d = new LZWdec[512];
|
||||
ushort code = 0;
|
||||
uint bits = 9;
|
||||
uint len = 0;
|
||||
uint nBits = 0;
|
||||
uint tmp = 0;
|
||||
|
||||
void getCode() nothrow {
|
||||
while (nBits < bits) {
|
||||
if (len > 0) {
|
||||
len--;
|
||||
tmp = (tmp << 8) | inp[0];
|
||||
inp = inp[1 .. $]; // popFront.
|
||||
nBits += 8;
|
||||
} else {
|
||||
tmp = tmp << (bits - nBits);
|
||||
nBits = bits;
|
||||
}
|
||||
}
|
||||
|
||||
nBits -= bits;
|
||||
assert(tmp >> nBits <= ushort.max);
|
||||
code = cast(ushort)(tmp >> nBits);
|
||||
tmp &= (1 << nBits) - 1;
|
||||
}
|
||||
|
||||
uint nextShift = 512;
|
||||
ushort nextCode = Marker.NEW;
|
||||
|
||||
void clearTable() nothrow {
|
||||
d[] = LZWdec.init;
|
||||
foreach (immutable ubyte j; 0 .. 256)
|
||||
d[j].c = j;
|
||||
nextCode = Marker.NEW;
|
||||
nextShift = 512;
|
||||
bits = 9;
|
||||
}
|
||||
|
||||
clearTable(); // In case encoded bits didn't start with Marker.CLR.
|
||||
for (len = inp.length; len;) {
|
||||
getCode();
|
||||
if (code == Marker.EOD)
|
||||
break;
|
||||
if (code == Marker.CLR) {
|
||||
clearTable();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code >= nextCode)
|
||||
throw new Error("Bad sequence.");
|
||||
|
||||
auto c = code;
|
||||
d[nextCode].prev = c;
|
||||
while (c > 255) {
|
||||
immutable t = d[c].prev;
|
||||
d[t].back = c;
|
||||
c = t;
|
||||
}
|
||||
|
||||
assert(c <= ubyte.max);
|
||||
d[nextCode - 1].c = cast(ubyte)c;
|
||||
|
||||
while (d[c].back) {
|
||||
writeOut(d[c].c);
|
||||
immutable t = d[c].back;
|
||||
d[c].back = 0;
|
||||
c = t;
|
||||
}
|
||||
writeOut(d[c].c);
|
||||
|
||||
nextCode++;
|
||||
if (nextCode >= nextShift) {
|
||||
bits++;
|
||||
if (bits > 16) {
|
||||
// If input was correct, we'd have hit Marker.CLR before this.
|
||||
throw new Error("Too many bits.");
|
||||
}
|
||||
nextShift *= 2;
|
||||
d.length = nextShift;
|
||||
}
|
||||
}
|
||||
|
||||
// Might be OK, so throw just an exception.
|
||||
if (code != Marker.EOD)
|
||||
throw new Exception("Bits did not end in EOD");
|
||||
|
||||
return result[0 .. outLen];
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
import std.stdio, std.file;
|
||||
|
||||
const inputData = cast(ubyte[])read("unixdict.txt");
|
||||
writeln("Input size: ", inputData.length);
|
||||
|
||||
immutable encoded = lzwEncode(inputData, 12);
|
||||
writeln("Encoded size: ", encoded.length);
|
||||
|
||||
immutable decoded = lzwDecode(encoded);
|
||||
writeln("Decoded size: ", decoded.length);
|
||||
|
||||
if (inputData.length != decoded.length)
|
||||
return writeln("Error: decoded size differs");
|
||||
|
||||
foreach (immutable i, immutable x; inputData)
|
||||
if (x != decoded[i])
|
||||
return writeln("Bad decode at ", i);
|
||||
|
||||
"Decoded OK.".writeln;
|
||||
}
|
||||
81
Task/LZW-compression/JavaScript/lzw-compression.js
Normal file
81
Task/LZW-compression/JavaScript/lzw-compression.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//LZW Compression/Decompression for Strings
|
||||
var LZW = {
|
||||
compress: function (uncompressed) {
|
||||
"use strict";
|
||||
// Build the dictionary.
|
||||
var i,
|
||||
dictionary = {},
|
||||
c,
|
||||
wc,
|
||||
w = "",
|
||||
result = [],
|
||||
dictSize = 256;
|
||||
for (i = 0; i < 256; i += 1) {
|
||||
dictionary[String.fromCharCode(i)] = i;
|
||||
}
|
||||
|
||||
for (i = 0; i < uncompressed.length; i += 1) {
|
||||
c = uncompressed.charAt(i);
|
||||
wc = w + c;
|
||||
//Do not use dictionary[wc] because javascript arrays
|
||||
//will return values for array['pop'], array['push'] etc
|
||||
// if (dictionary[wc]) {
|
||||
if (dictionary.hasOwnProperty(wc)) {
|
||||
w = wc;
|
||||
} else {
|
||||
result.push(dictionary[w]);
|
||||
// Add wc to the dictionary.
|
||||
dictionary[wc] = dictSize++;
|
||||
w = String(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Output the code for w.
|
||||
if (w !== "") {
|
||||
result.push(dictionary[w]);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
|
||||
decompress: function (compressed) {
|
||||
"use strict";
|
||||
// Build the dictionary.
|
||||
var i,
|
||||
dictionary = [],
|
||||
w,
|
||||
result,
|
||||
k,
|
||||
entry = "",
|
||||
dictSize = 256;
|
||||
for (i = 0; i < 256; i += 1) {
|
||||
dictionary[i] = String.fromCharCode(i);
|
||||
}
|
||||
|
||||
w = String.fromCharCode(compressed[0]);
|
||||
result = w;
|
||||
for (i = 1; i < compressed.length; i += 1) {
|
||||
k = compressed[i];
|
||||
if (dictionary[k]) {
|
||||
entry = dictionary[k];
|
||||
} else {
|
||||
if (k === dictSize) {
|
||||
entry = w + w.charAt(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
result += entry;
|
||||
|
||||
// Add w+entry[0] to the dictionary.
|
||||
dictionary[dictSize++] = w + entry.charAt(0);
|
||||
|
||||
w = entry;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}, // For Test Purposes
|
||||
comp = LZW.compress("TOBEORNOTTOBEORTOBEORNOT"),
|
||||
decomp = LZW.decompress(comp);
|
||||
document.write(comp + '<br>' + decomp);
|
||||
280
Task/LZW-compression/Liberty-BASIC/lzw-compression.liberty
Normal file
280
Task/LZW-compression/Liberty-BASIC/lzw-compression.liberty
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
DIM LZW(1, 1)
|
||||
DIM JDlzw(1)
|
||||
DIM JDch$(1)
|
||||
LET maxBits = 20 ' maximum bit width of the dictionary: minimum=12; maximum=21
|
||||
LET resetDictionary = 1 ' flag to reset the dictionary when it gets full: 1=TRUE; 0=FALSE
|
||||
LET printDictionary = 0 ' output encoding and decoding dictionaries to files
|
||||
LET maxChunkSize = 2 ^ 14 ' maximum size of the data buffer
|
||||
LET dSize = 2 ^ maxBits ' maximum dictionary size
|
||||
LET JDext$ = ".lzw" ' file extension used for created archives
|
||||
FILEDIALOG "Select a file to test LZW...", "*.*", inputName$
|
||||
IF inputName$ = "" THEN END
|
||||
DO ' get fullPath\ and fileName.ext
|
||||
P = X
|
||||
X = INSTR(inputName$, "\", (X + 1))
|
||||
LOOP UNTIL X = 0
|
||||
filePath$ = LEFT$(inputName$, P)
|
||||
fileName$ = MID$(inputName$, (P + 1))
|
||||
DO ' get fileName and .ext
|
||||
P = X
|
||||
X = INSTR(fileName$, ".", (X + 1))
|
||||
LOOP UNTIL X = 0
|
||||
fileExt$ = MID$(fileName$, P)
|
||||
fileName$ = LEFT$(fileName$, (P - 1))
|
||||
|
||||
GOSUB [lzwEncode]
|
||||
GOSUB [lzwDecode]
|
||||
|
||||
END
|
||||
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
' Start LZW Encoder ''''''''''''''''''''
|
||||
[lzwEncode]
|
||||
REDIM LZW(dSize, 4)
|
||||
LET EMPTY=-1:PREFIX=0:BYTE=1:FIRST=2:LESS=3:MORE=4:bmxCorrect=1
|
||||
LET bitsRemain=0:remainIndex=0:tagCount=0:currentBitSize=8:fileTag$=""
|
||||
FOR dNext = 0 TO 255 ' initialize dictionary for LZW
|
||||
' LZW(dNext, PREFIX) = EMPTY ' prefix index of '<index>' <B>
|
||||
' LZW(dNext, BYTE) = dNext ' byte value of <index> '<B>'
|
||||
LZW(dNext, FIRST) = EMPTY ' first index to use <index><B> as prefix
|
||||
' LZW(dNext, LESS) = EMPTY ' lesser index of binary search tree for <B>
|
||||
' LZW(dNext, MORE) = EMPTY ' greater index of binary search tree for <B>
|
||||
NEXT dNext
|
||||
OPEN inputName$ FOR INPUT AS #lzwIN
|
||||
IF LOF(#lzwIN) < 2 THEN
|
||||
CLOSE #lzwIN
|
||||
END
|
||||
END IF
|
||||
OPEN fileName$ + fileExt$ + JDext$ FOR OUTPUT AS #lzwOUT
|
||||
GOSUB [StartFileChunk]
|
||||
chnkPoint = 1
|
||||
IF maxBits < 12 THEN maxBits = 12
|
||||
IF maxBits > 21 THEN maxBits = 21
|
||||
settings = maxBits - 12 ' setting for dictionary size; 1st decimal +12
|
||||
IF resetDictionary THEN settings = settings + 100 ' setting for dictionary type; 2nd decimal even=static, odd=adaptive
|
||||
#lzwOUT, CHR$(settings); ' save settings as 1st byte of output
|
||||
orgIndex = ASC(LEFT$(fileChunk$, 1)) ' read 1st byte into <index>
|
||||
WHILE fileChunk$ <> "" ' while the buffer is not empty
|
||||
DO ' begin the main encoder loop
|
||||
chnkPoint = chnkPoint + 1
|
||||
savIndex = FIRST ' initialize the save-to index
|
||||
prvIndex = orgIndex ' initialize the previous index in search
|
||||
newByte = ASC(MID$(fileChunk$, chnkPoint, 1)) ' read <B>
|
||||
dSearch = LZW(orgIndex, FIRST) ' first search index for this <index> in the dictionary
|
||||
WHILE (dSearch > EMPTY) ' while <index> is present in the dictionary
|
||||
IF LZW(dSearch, BYTE) = newByte THEN EXIT WHILE ' if <index><B> is found
|
||||
IF newByte < LZW(dSearch, BYTE) THEN ' else if new <B> is less than <index><B>
|
||||
savIndex = LESS ' follow lesser binary tree
|
||||
ELSE
|
||||
savIndex = MORE ' else follow greater binary tree
|
||||
END IF
|
||||
prvIndex = dSearch ' set previous <index>
|
||||
dSearch = LZW(dSearch, savIndex) ' read next search <index> from binary tree
|
||||
WEND
|
||||
IF dSearch = EMPTY THEN ' if <index><B> was not found in the dictionary
|
||||
GOSUB [WriteIndex] ' write <index> to the output
|
||||
IF dNext < dSize THEN ' save <index><B> into the dictionary
|
||||
LZW(prvIndex, savIndex) = dNext
|
||||
LZW(dNext, PREFIX) = orgIndex
|
||||
LZW(dNext, BYTE) = newByte
|
||||
LZW(dNext, FIRST) = EMPTY
|
||||
LZW(dNext, LESS) = EMPTY
|
||||
LZW(dNext, MORE) = EMPTY
|
||||
IF dNext = (2 ^ currentBitSize) THEN currentBitSize = currentBitSize + 1
|
||||
dNext = dNext + 1
|
||||
ELSE ' else reset the dictionary... or maybe not
|
||||
IF resetDictionary THEN
|
||||
GOSUB [PrintEncode]
|
||||
REDIM LZW(dSize, 4)
|
||||
FOR dNext = 0 TO 255
|
||||
LZW(dNext, FIRST) = EMPTY
|
||||
NEXT dNext
|
||||
currentBitSize = 8
|
||||
bmxCorrect = 0
|
||||
END IF
|
||||
END IF
|
||||
orgIndex = newByte ' set <index> = <B>
|
||||
ELSE ' if <index><B> was found in the dictionary,
|
||||
orgIndex = dSearch ' then set <index> = <index><B>
|
||||
END IF
|
||||
LOOP WHILE chnkPoint < chunk ' loop until the chunk has been processed
|
||||
GOSUB [GetFileChunk] ' refill the buffer
|
||||
WEND ' loop until the buffer is empty
|
||||
GOSUB [WriteIndex]
|
||||
IF bitsRemain > 0 THEN #lzwOUT, CHR$(remainIndex);
|
||||
CLOSE #lzwOUT
|
||||
CLOSE #lzwIN
|
||||
IF bmxCorrect THEN ' correct the settings, if needed
|
||||
IF (currentBitSize < maxBits) OR resetDictionary THEN
|
||||
IF currentBitSize < 12 THEN currentBitSize = 12
|
||||
OPEN fileName$ + fileExt$ + JDext$ FOR BINARY AS #lzwOUT
|
||||
#lzwOUT, CHR$(currentBitSize - 12);
|
||||
CLOSE #lzwOUT
|
||||
END IF
|
||||
END IF
|
||||
GOSUB [PrintEncode]
|
||||
REDIM LZW(1, 1)
|
||||
RETURN
|
||||
|
||||
[WriteIndex]
|
||||
X = orgIndex ' add remaining bits to input
|
||||
IF bitsRemain > 0 THEN X = remainIndex + (X * (2 ^ bitsRemain))
|
||||
bitsRemain = bitsRemain + currentBitSize ' add current bit size to output stack
|
||||
WHILE bitsRemain > 7 ' if 8 or more bits are to be written
|
||||
#lzwOUT, CHR$(X MOD 256); ' attatch lower 8 bits to output string
|
||||
X = INT(X / 256) ' shift input value down by 2^8
|
||||
bitsRemain = bitsRemain - 8 ' adjust counters
|
||||
WEND
|
||||
remainIndex = X ' retain trailing bits for next write
|
||||
RETURN
|
||||
|
||||
' End LZW Encoder ''''''''''''''''''''''
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
[StartFileChunk]
|
||||
sizeOfFile = LOF(#lzwIN) ' set EOF marker
|
||||
bytesRemaining = sizeOfFile ' set EOF counter
|
||||
chunk = maxChunkSize ' set max buffer size
|
||||
[GetFileChunk]
|
||||
fileChunk$ = ""
|
||||
IF bytesRemaining < 1 THEN RETURN
|
||||
IF chunk > bytesRemaining THEN chunk = bytesRemaining
|
||||
bytesRemaining = bytesRemaining - chunk
|
||||
fileChunk$ = INPUT$(#lzwIN, chunk)
|
||||
chnkPoint = 0
|
||||
RETURN
|
||||
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
' Start LZW Decoder ''''''''''''''''''''
|
||||
[lzwDecode]
|
||||
LET EMPTY=-1:bitsRemain=0:tagCount=0:fileTag$=""
|
||||
OPEN fileName$ + fileExt$ + JDext$ FOR INPUT AS #lzwIN
|
||||
OPEN fileName$ + ".Copy" + fileExt$ FOR OUTPUT AS #lzwOUT
|
||||
GOSUB [StartFileChunk]
|
||||
chnkPoint = 2
|
||||
settings = ASC(fileChunk$)
|
||||
maxBits = VAL(RIGHT$(STR$(settings), 1)) + 12
|
||||
dSize = 2 ^ maxBits
|
||||
IF settings > 99 THEN resetDictionary = 1
|
||||
GOSUB [ResetLZW]
|
||||
oldIndex = orgIndex
|
||||
WHILE fileChunk$ <> ""
|
||||
' decode current index and write to file
|
||||
GOSUB [GetIndex]
|
||||
IF JDch$(orgIndex) = "" THEN
|
||||
tmpIndex = oldIndex
|
||||
tmp$ = JDch$(tmpIndex)
|
||||
WHILE JDlzw(tmpIndex) > EMPTY
|
||||
tmpIndex = JDlzw(tmpIndex)
|
||||
tmp$ = JDch$(tmpIndex) + tmp$
|
||||
WEND
|
||||
tmp$ = tmp$ + LEFT$(tmp$, 1)
|
||||
ELSE
|
||||
tmpIndex = orgIndex
|
||||
tmp$ = JDch$(tmpIndex)
|
||||
WHILE JDlzw(tmpIndex) > EMPTY
|
||||
tmpIndex = JDlzw(tmpIndex)
|
||||
tmp$ = JDch$(tmpIndex) + tmp$
|
||||
WEND
|
||||
END IF
|
||||
#lzwOUT, tmp$;
|
||||
' add next dictionary entry or reset dictionary
|
||||
IF dNext < dSize THEN
|
||||
JDlzw(dNext) = oldIndex
|
||||
JDch$(dNext) = LEFT$(tmp$, 1)
|
||||
dNext = dNext + 1
|
||||
IF dNext = (2 ^ currentBitSize) THEN
|
||||
IF maxBits > currentBitSize THEN
|
||||
currentBitSize = currentBitSize + 1
|
||||
ELSE
|
||||
IF resetDictionary THEN
|
||||
GOSUB [PrintDecode]
|
||||
GOSUB [ResetLZW]
|
||||
END IF
|
||||
END IF
|
||||
END IF
|
||||
END IF
|
||||
oldIndex = orgIndex
|
||||
WEND
|
||||
CLOSE #lzwOUT
|
||||
CLOSE #lzwIN
|
||||
GOSUB [PrintDecode]
|
||||
REDIM JDlzw(1)
|
||||
REDIM JDch$(1)
|
||||
RETURN
|
||||
|
||||
[GetIndex]
|
||||
byteCount = 0:orgIndex = 0
|
||||
bitsToGrab = currentBitSize - bitsRemain
|
||||
IF bitsRemain > 0 THEN
|
||||
orgIndex = lastByte
|
||||
byteCount = 1
|
||||
END IF
|
||||
WHILE bitsToGrab > 0
|
||||
lastByte = ASC(MID$(fileChunk$, chnkPoint, 1))
|
||||
orgIndex = orgIndex + (lastByte * (2 ^ (byteCount * 8)))
|
||||
IF chnkPoint = chunk THEN GOSUB [GetFileChunk]
|
||||
chnkPoint = chnkPoint + 1
|
||||
byteCount = byteCount + 1
|
||||
bitsToGrab = bitsToGrab - 8
|
||||
WEND
|
||||
IF bitsRemain > 0 THEN orgIndex = orgIndex / (2 ^ (8 - bitsRemain))
|
||||
orgIndex = orgIndex AND ((2 ^ currentBitSize) - 1)
|
||||
bitsRemain = bitsToGrab * (-1)
|
||||
RETURN
|
||||
|
||||
[ResetLZW]
|
||||
REDIM JDlzw(dSize)
|
||||
REDIM JDch$(dSize)
|
||||
FOR dNext = 0 TO 255
|
||||
JDlzw(dNext) = EMPTY ' Prefix index
|
||||
JDch$(dNext) = CHR$(dNext) ' New byte value
|
||||
NEXT dNext
|
||||
currentBitSize = 8
|
||||
GOSUB [GetIndex]
|
||||
#lzwOUT, JDch$(orgIndex);
|
||||
currentBitSize = 9
|
||||
RETURN
|
||||
|
||||
' End LZW Decoder ''''''''''''''''''''''
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
[PrintEncode]
|
||||
IF printDictionary < 1 THEN RETURN
|
||||
OPEN "Encode_" + fileTag$ + fileName$ + ".txt" FOR OUTPUT AS #dictOUT
|
||||
FOR X = 0 TO 255
|
||||
LZW(X, PREFIX) = EMPTY
|
||||
LZW(X, BYTE) = X
|
||||
NEXT X
|
||||
FOR X = dNext TO 0 STEP -1
|
||||
tmpIndex = X
|
||||
tmp$ = CHR$(LZW(tmpIndex, BYTE))
|
||||
WHILE LZW(tmpIndex, PREFIX) > EMPTY
|
||||
tmpIndex = LZW(tmpIndex, PREFIX)
|
||||
tmp$ = CHR$(LZW(tmpIndex, BYTE)) + tmp$
|
||||
WEND
|
||||
#dictOUT, X; ":"; tmp$
|
||||
NEXT X
|
||||
CLOSE #dictOUT
|
||||
tagCount = tagCount + 1
|
||||
fileTag$ = STR$(tagCount) + "_"
|
||||
RETURN
|
||||
|
||||
[PrintDecode]
|
||||
IF printDictionary < 1 THEN RETURN
|
||||
OPEN "Decode_" + fileTag$ + fileName$ + ".txt" FOR OUTPUT AS #dictOUT
|
||||
FOR X = dNext TO 0 STEP -1
|
||||
tmpIndex = X
|
||||
tmp$ = JDch$(tmpIndex)
|
||||
WHILE JDlzw(tmpIndex) > EMPTY
|
||||
tmpIndex = JDlzw(tmpIndex)
|
||||
tmp$ = JDch$(tmpIndex) + tmp$
|
||||
WEND
|
||||
#dictOUT, X; ":"; tmp$
|
||||
NEXT X
|
||||
CLOSE #dictOUT
|
||||
tagCount = tagCount + 1
|
||||
fileTag$ = STR$(tagCount) + "_"
|
||||
RETURN
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
|
|
@ -11,7 +11,8 @@ class LZW
|
|||
}
|
||||
for ($i = 0; $i < strlen($unc); $i++) {
|
||||
$c = $unc[$i];
|
||||
if (property_exists($dictionary, $w.$c)) {
|
||||
$wc = $w.$c;
|
||||
if (array_key_exists($w.$c, $dictionary)) {
|
||||
$w = $w.$c;
|
||||
} else {
|
||||
array_push($result,$dictionary[$w]);
|
||||
|
|
@ -22,7 +23,6 @@ class LZW
|
|||
if ($w !== "") {
|
||||
array_push($result,$dictionary[$w]);
|
||||
}
|
||||
array_shift($result);
|
||||
return implode(",",$result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,13 +27,18 @@ def compress(uncompressed):
|
|||
|
||||
def decompress(compressed):
|
||||
"""Decompress a list of output ks to a string."""
|
||||
from cStringIO import StringIO
|
||||
|
||||
# Build the dictionary.
|
||||
dict_size = 256
|
||||
dictionary = dict((chr(i), chr(i)) for i in xrange(dict_size))
|
||||
# in Python 3: dictionary = {chr(i): chr(i) for i in range(dict_size)}
|
||||
|
||||
w = result = compressed.pop(0)
|
||||
# use StringIO, otherwise this becomes O(N^2)
|
||||
# due to string concatenation in a loop
|
||||
result = StringIO()
|
||||
w = compressed.pop(0)
|
||||
result.write(w)
|
||||
for k in compressed:
|
||||
if k in dictionary:
|
||||
entry = dictionary[k]
|
||||
|
|
@ -41,14 +46,14 @@ def decompress(compressed):
|
|||
entry = w + w[0]
|
||||
else:
|
||||
raise ValueError('Bad compressed k: %s' % k)
|
||||
result += entry
|
||||
result.write(entry)
|
||||
|
||||
# Add w+entry[0] to the dictionary.
|
||||
dictionary[dict_size] = w + entry[0]
|
||||
dict_size += 1
|
||||
|
||||
w = entry
|
||||
return result
|
||||
return result.getvalue()
|
||||
|
||||
|
||||
# How to use:
|
||||
|
|
|
|||
76
Task/LZW-compression/REXX/lzw-compression.rexx
Normal file
76
Task/LZW-compression/REXX/lzw-compression.rexx
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* REXX ---------------------------------------------------------------
|
||||
* 20.07.2014 Wakter Pachl translated from Java
|
||||
* 21.07.2014 WP allow for blanks in the string
|
||||
*--------------------------------------------------------------------*/
|
||||
Parse Arg str
|
||||
default="TOBEORNOTTOBEORTOBEORNOT"
|
||||
If str='' Then
|
||||
str=default
|
||||
/* str=space(str,0) */
|
||||
Say 'str='str
|
||||
compressed = compress(str)
|
||||
Say compressed
|
||||
If str=default Then Do
|
||||
cx='[84, 79, 66, 69, 79, 82, 78, 79, 84, 256, 258, 260, 265, 259, 261, 263]'
|
||||
If cx==compressed Then Say 'compression ok'
|
||||
End
|
||||
decompressed = decompress(compressed)
|
||||
Say 'dec='decompressed
|
||||
If decompressed=str Then Say 'decompression ok'
|
||||
Exit
|
||||
|
||||
compress: Procedure
|
||||
Parse Arg uncompressed
|
||||
dict.=''
|
||||
Do i=0 To 255
|
||||
z=d2c(i)
|
||||
d.i=z
|
||||
dict.z=i
|
||||
End
|
||||
dict_size=256
|
||||
res='['
|
||||
w=''
|
||||
Do i=1 To length(uncompressed)
|
||||
c=substr(uncompressed,i,1)
|
||||
wc=w||c
|
||||
If dict.wc<>'' Then
|
||||
w=wc
|
||||
Else Do
|
||||
res=res||dict.w', '
|
||||
dict.wc=dict_size
|
||||
dict_size+=1
|
||||
w=c
|
||||
End
|
||||
End
|
||||
If w<>'' Then
|
||||
res=res||dict.w', '
|
||||
Return left(res,length(res)-2)']'
|
||||
|
||||
decompress: Procedure
|
||||
Parse Arg compressed
|
||||
compressed=space(translate(compressed,'','[],'))
|
||||
d.=''
|
||||
Do i=0 To 255
|
||||
z=d2c(i)
|
||||
d.i=z
|
||||
End
|
||||
dict_size=256
|
||||
Parse Var compressed w compressed
|
||||
res=d.w
|
||||
w=d.w
|
||||
Do i=1 To words(compressed)
|
||||
k=word(compressed,i)
|
||||
Select
|
||||
When d.k<>'' | d.k=='20'x then /* allow for blank */
|
||||
entry=d.k
|
||||
When k=dict_size Then
|
||||
entry=w||substr(w,1,1)
|
||||
Otherwise
|
||||
Say "Bad compressed k: " k
|
||||
End
|
||||
res=res||entry
|
||||
d.dict_size=w||substr(entry,1,1)
|
||||
dict_size+=1
|
||||
w=entry
|
||||
End
|
||||
Return res
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// for now, only compress
|
||||
def compress(tc:String) = {
|
||||
//initial dictionary
|
||||
val startDict = (1 to 255).map(a=>(""+a.toChar,a)).toMap
|
||||
|
|
@ -14,5 +13,33 @@ def compress(tc:String) = {
|
|||
if (remain.isEmpty) result.reverse else (fullDict(remain) :: result).reverse
|
||||
}
|
||||
|
||||
def decompress(ns: List[Int]): String = {
|
||||
val startDict = (1 to 255).map(a=>(a,""+a.toChar)).toMap
|
||||
val (_, result, _) =
|
||||
ns.foldLeft[(Map[Int, String], List[String], Option[(Int, String)])]((startDict, Nil, None)) {
|
||||
case ((dict, result, conjecture), n) => {
|
||||
dict.get(n) match {
|
||||
case Some(output) => {
|
||||
val (newDict, newCode) = conjecture match {
|
||||
case Some((code, prefix)) => ((dict + (code -> (prefix + output.head))), code + 1)
|
||||
case None => (dict, dict.size + 1)
|
||||
}
|
||||
(newDict, output :: result, Some(newCode -> output))
|
||||
}
|
||||
case None => {
|
||||
// conjecture being None would be an encoding error
|
||||
val (code, prefix) = conjecture.get
|
||||
val output = prefix + prefix.head
|
||||
(dict + (code -> output), output :: result, Some(code + 1 -> output))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.reverse.mkString("")
|
||||
}
|
||||
// test
|
||||
compress("TOBEORNOTTOBEORTOBEORNOT")
|
||||
val text = "TOBEORNOTTOBEORTOBEORNOT"
|
||||
val compressed = compress(text)
|
||||
println(compressed)
|
||||
val result = decompress(compressed)
|
||||
println(result)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue