forked from ref-xx/basinc
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRLEUnit.pas
More file actions
185 lines (172 loc) · 6.2 KB
/
RLEUnit.pas
File metadata and controls
185 lines (172 loc) · 6.2 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
unit RLEUnit;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls;
Procedure BuildBinFile(Filename: String; Files: TStrings);
Function ListCompressedFiles(Filename: String): TStringList;
Function RLEPackArray(Var TempArray: Array of Byte): String;
Function RLEPackFile(Filename: String): String;
Procedure RLEUnpackFile(ArchiveName, FileName: String);
Procedure RLEUnpackToFile(ArchiveName, PackedFilename, FileName: String);
var RLEArray: Array of Byte;
implementation
Uses Filing;
Procedure BuildBinFile(Filename: String; Files: TStrings);
Var
BinFile: TFileStream;
F: integer;
Compressed, TotalFile, FName, Header: String;
FLen: DWord;
begin
Header := Chr(Files.Count);
TotalFile := '';
If GetFileAttributes(Pchar(Filename)) <> $FFFFFFFF Then DeleteFile(Filename);
BinFile := TFileStream.Create(Filename, fmCreate or fmShareDenyWrite);
For F := 0 To Files.Count -1 Do Begin
FName := ExtractFileName(Files[F]);
While Length(FName) < 10 Do FName := FName + ' ';
Compressed := RLEPackFile(Files[F]);
FLen := Length(Compressed);
Header := Header + FName + Chr(FLen and 255)+Chr((FLen Shr 8) And 255)+Chr((FLen Shr 16) And 255)+Chr((FLen Shr 24) And 255);
TotalFile := TotalFile + Compressed;
End;
TotalFile := Header+TotalFile;
BinFile.Write(TotalFile[1], Length(TotalFile));
BinFile.Free;
End;
Function RLEPackArray(Var TempArray: Array of Byte): String;
Var
MinTagCount, ArrayPos, RepeatCount, BytesRead, UnCompressedSize, PackedSize, F: DWord;
CurByte, TagByte, RepeatByte: Byte;
PossibleTags: Array[0..255] of DWord;
Begin
UnCompressedSize := Length(TempArray);
MinTagCount := $FFFFFFFF;
For F := 0 To UnCompressedSize -1 Do Inc(PossibleTags[TempArray[F]]);
For F := 0 To 255 Do If PossibleTags[F] < MinTagCount Then MinTagCount := PossibleTags[F];
F := 0; While PossibleTags[F] <> MinTagCount Do Inc(F); TagByte := F;
SetLength(RLEArray, (MinTagCount*6)+UnCompressedSize+1);
PackedSize := 1;
BytesRead := 0;
ArrayPos := 1;
RLEArray[0] := TagByte;
While BytesRead < UnCompressedSize Do Begin
CurByte := TempArray[BytesRead];
Inc(BytesRead);
RepeatByte := CurByte;
RepeatCount := 0;
While (RepeatByte = CurByte) And (BytesRead <= UnCompressedSize) Do Begin
CurByte := TempArray[BytesRead];
Inc(RepeatCount);
Inc(BytesRead);
End;
If (RepeatCount >= 6) Or (RepeatByte = TagByte) Then Begin
RLEArray[ArrayPos] := TagByte;
RLEArray[ArrayPos+1] := RepeatByte;
RLEArray[ArrayPos+2] := RepeatCount And 255;
RLEArray[ArrayPos+3] := (RepeatCount Shr 8) And 255;
RLEArray[ArrayPos+4] := (RepeatCount Shr 16) And 255;
RLEArray[ArrayPos+5] := (RepeatCount Shr 24) And 255;
Inc(ArrayPos, 6);
Inc(PackedSize, 6);
End Else Begin
For F := 1 To RepeatCount Do Begin
RLEArray[ArrayPos] := RepeatByte;
Inc(ArrayPos);
End;
Inc(PackedSize, RepeatCount);
End;
Dec(BytesRead);
End;
Result := Chr(UnCompressedSize And 255) + Chr((UnCompressedSize Shr 8) And 255) + Chr((UnCompressedSize Shr 16) And 255) + Chr((UnCompressedSize Shr 24) And 255);
For F := 0 To PackedSize -1 Do Result := Result + Chr(RLEArray[F]);
SetLength(RLEArray, 0);
End;
Function RLEPackFile(Filename: String): String;
Var
UnpackedFile: TFileStream;
UnCompressedSize: DWord;
TempArray: Array of Byte;
Begin
UnpackedFile := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone);
UnCompressedSize := UnpackedFile.Size;
SetLength(TempArray, UnCompressedSize);
UnPackedFile.Read(TempArray[0], UnCompressedSize);
UnpackedFile.Free;
Result := RLEPackArray(TempArray);
SetLength(TempArray, 0);
End;
Function ListCompressedFiles(Filename: String): TStringList;
Var
BinFile: TFileStream;
NumFiles, F: Byte;
Listname: String;
Begin
Result := TStringlist.Create;
BinFile := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone);
BinFile.Read(NumFiles, 1);
For F := 1 To NumFiles Do Begin
ListName := ' ';
BinFile.Read(Listname[1], 14);
ListName := Copy(ListName, 1, 10);
While ListName[Length(ListName)] = ' ' Do ListName := Copy(ListName, 1, Length(ListName)-1);
Result.Add(ListName);
End;
BinFile.Free;
End;
Procedure RLEUnpackFile(ArchiveName, FileName: String);
Var
BinFile: TFileStream;
F, CurByte, RepeatByte, NumFiles, TagByte: Byte;
Offset, Size, FileSize, UnpackPos, RepeatLength, BytesRead: DWord;
FName: String;
Begin
FName := ' ';
Filename := Lowercase(Filename);
BinFile := TFileStream.Create(ArchiveName, fmOpenRead or fmShareDenyNone);
BinFile.Read(NumFiles, 1);
Offset := (NumFiles*14)+1;
For F := 1 To NumFiles Do Begin
BinFile.Read(FName[1], 10);
BinFile.Read(Size, 4);
If Copy(Lowercase(FName), 1, Length(Filename)) = Filename Then Break;
Inc(Offset, Size);
End;
Dec(Size);
BinFile.Seek(Offset, soFromBeginning);
BinFile.Read(FileSize, 4);
BinFile.Read(TagByte, 1);
SetLength(RLEArray, FileSize);
UnpackPos := 0;
BytesRead := 0;
While (BytesRead < Size) and (UnpackPos < FileSize) Do Begin
BinFile.Read(CurByte, 1);
Inc(BytesRead);
If CurByte = TagByte Then Begin
BinFile.Read(RepeatByte, 1);
BinFile.Read(RepeatLength, 4);
While RepeatLength > 0 Do Begin
RLEArray[UnpackPos] := RepeatByte;
Inc(UnpackPos);
Dec(RepeatLength);
End;
Inc(BytesRead, 5);
End Else Begin
RLEArray[UnpackPos] := CurByte;
Inc(UnpackPos);
End;
End;
BinFile.Free;
End;
Procedure RLEUnpackToFile(ArchiveName, PackedFilename, FileName: String);
Var
WriteFile: TFileStream;
begin
RLEUnpackFile(ArchiveName, PackedFileName);
If GetFileAttributes(Pchar(Filename)) <> $FFFFFFFF Then DeleteFile(FileName);
If Not OpenFileStream(WriteFile, fmCreate or fmShareDenyWrite, Filename) Then Exit;
WriteFile.Write(RLEArray[0], Length(RLEArray));
WriteFile.Free;
SetLength(RLEArray, 0);
end;
end.