-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathSqueeze.pas
154 lines (125 loc) · 2.79 KB
/
Squeeze.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
unit Squeeze;
{$mode objfpc}{$H+}
//PV Unpack
//https://github.com/PascalVault
//Based on usq by Dick Greenlaw (~1983)
//Licence: MIT
//Last update: 2023-11-12
interface
uses
Classes, SysUtils;
const
numvals = 257; //max size of tree + 1
speof = 256; //marker for end of file
dle: char = #$90;
type
tree = array[0..255, 0..1] of Int16;
type
{ TSqueeze }
TSqueeze = class
private
dnode: tree;
curin, bpos, repct, numnodes: int16;
c, lastchar: ansichar;
DataEnd: Boolean;
FInStream: TStream;
FOutStream: TStream;
function ReadChar: Int16;
function ReadWord: Int16;
procedure WriteChar(ch: ansichar);
function Unhuff: ansichar;
function DecodeChar: ansichar;
public
constructor Create(InStream, OutStream: TStream);
procedure Decode(PackedSize: Int64);
end;
implementation
constructor TSqueeze.Create(InStream, OutStream: TStream);
begin
FInStream := InStream;
FOutStream := OutStream;
end;
function TSqueeze.ReadChar: Int16;
var tmp: byte;
begin
FInStream.Read(tmp, 1);
result := tmp;
end;
function TSqueeze.ReadWord: Int16;
var tmp: Word;
begin
FInStream.Read(tmp, 2);
result := tmp;
end;
procedure TSqueeze.WriteChar(ch: ansichar);
var tmp: Byte;
begin
tmp := ord(ch);
FOutStream.Write(tmp, 1);
end;
function TSqueeze.Unhuff: ansichar;
var i: Int16;
begin
i := 0;
repeat
inc(bpos);
if bpos > 7 then begin
curin := ReadChar;
bpos := 0;
i := ord(dnode[i,ord(1 and curin)]);
end
else begin
curin := curin shr 1;
i := ord(dnode[i,ord(1 and curin)]);
end;
until (i < 0);
i := -(i + 1);
if i = speof then begin
DataEnd := true;
result := chr(26)
end
else result := chr(i);
end;
function TSqueeze.DecodeChar: ansichar;
var ch: ansichar;
begin
if repct > 0 then begin
dec(repct);
exit(lastchar);
end;
ch := Unhuff;
if ch <> dle then begin
result := ch;
lastchar := ch;
exit;
end;
repct := ord(Unhuff);
if repct = 0 then exit(dle);
dec(repct, 2);
result := lastchar;
end;
procedure TSqueeze.Decode(PackedSize: Int64);
var i: Integer;
begin
repct := 0;
bpos := 99;
DataEnd := false;
numnodes := ReadWord;
if (numnodes < 0) or (numnodes >= numvals) then begin
raise Exception.Create('Invalid number of nodes');
Exit;
end;
dnode[0,0] := -(speof+1);
dnode[0,1] := -(speof+1);
numnodes := numnodes-1;
for i:=0 to numnodes do begin
dnode[i,0] := ReadWord;
dnode[i,1] := ReadWord;
end;
while FInStream.Position < FInStream.Size do begin
c := DecodeChar;
if DataEnd then break;
WriteChar(c);
end;
end;
end.