-
Notifications
You must be signed in to change notification settings - Fork 1
/
FileContainer.pas
181 lines (151 loc) · 3.86 KB
/
FileContainer.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
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
{******************************************************************************
This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
one at https://mozilla.org/MPL/2.0/.
*******************************************************************************}
unit FileContainer;
interface
uses
System.SysUtils, System.Classes;
type
TFileContainer = class(TComponent)
protected {private}
fCompressed: Boolean;
fData: TBytes;
function GetData: TBytes;
procedure SetData(const Value: TBytes);
procedure ReadCompressedData(aStream: TStream);
procedure WriteCompressedData(aStream: TStream);
protected {private}
procedure DefineProperties(Filer: TFiler); override;
public
constructor Create(aOwner: TComponent); override;
procedure LoadFromFile(const aFileName: string);
procedure LoadFromStream(aStream: TStream);
procedure SaveToFile(const aFileName: string);
procedure SaveToStream(aStream: TStream);
function CreateReadStream: TStream;
property Data: TBytes
read GetData //returns a copy
write SetData;
published
property Compressed: Boolean
read fCompressed
write fCompressed;
end;
function SameBytes(const a,b: TBytes): Boolean;
implementation
uses
zlib;
function SameBytes(const a,b: TBytes): Boolean;
var
i: Integer;
begin
Result := Length(a) = Length(b);
if Result then
for i := Low(a) to High(a) do
if a[i] <> b[i] then
Exit(False);
end;
{ TFileContainer }
constructor TFileContainer.Create(aOwner: TComponent);
begin
fCompressed := True;
inherited;
end;
function TFileContainer.CreateReadStream: TStream;
begin
Result := TBytesStream.Create(GetData);
end;
procedure TFileContainer.DefineProperties(Filer: TFiler);
function DoWrite: Boolean;
begin
if Assigned(Filer.Ancestor) then begin
Result := True;
if Filer.Ancestor is TFileContainer then
Result := not SameBytes(TFileContainer(Filer.Ancestor).fData, fData);
end else
Result := Length(fData) > 0;
end;
begin
inherited;
Filer.DefineBinaryProperty('Data', LoadFromStream, SaveToStream, not fCompressed and DoWrite);
Filer.DefineBinaryProperty('CompressedData', ReadCompressedData, WriteCompressedData, fCompressed and DoWrite);
end;
function TFileContainer.GetData: TBytes;
begin
Result := Copy(fData);
end;
procedure TFileContainer.LoadFromFile(const aFileName: string);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(aFileName, fmOpenRead);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TFileContainer.LoadFromStream(aStream: TStream);
var
l : Int64;
Bytes : TBytes;
begin
l := aStream.Size;
Bytes := nil;
SetLength(Bytes, l);
aStream.Position := 0;
if l > 0 then
aStream.Read(Bytes, l);
fData := Bytes;
end;
procedure TFileContainer.ReadCompressedData(aStream: TStream);
var
Stream: TBytesStream;
begin
Stream := TBytesStream.Create;
try
ZDecompressStream(aStream, Stream);
fData := Copy(Stream.Bytes);
if Length(fData) > Stream.Size then
SetLength(fData, Stream.Size);
finally
Stream.Free;
end;
end;
procedure TFileContainer.SaveToFile(const aFileName: string);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(aFileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
procedure TFileContainer.SaveToStream(aStream: TStream);
var
l: Int64;
begin
l := Length(fData);
if l > 0 then
aStream.Write(fData, l);
end;
procedure TFileContainer.SetData(const Value: TBytes);
begin
fData := Copy(Value);
end;
procedure TFileContainer.WriteCompressedData(aStream: TStream);
var
Stream: TStream;
begin
Stream := CreateReadStream;
try
ZCompressStream(Stream, aStream);
finally
Stream.Free;
end;
end;
end.