-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPV_Arc.pas
123 lines (95 loc) · 2.46 KB
/
PV_Arc.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
unit PV_Arc;
{$mode objfpc}{$H+}
//PV Pack
//https://github.com/PascalVault
//Licence: MIT
//Last update: 2023-10-06
//SEA .ARC, spec 6.02
interface
uses
Classes, SysUtils, StrUtils, Dialogs, CRC16_ARC, PV_Pack;
type
{ TArc }
TArc = class(TPack)
private
FStream: TStream;
FComment: String;
public
constructor Create(Str: TStream); override;
destructor Destroy; override;
function AddFile(Str: TStream; Name: String): Boolean; override;
procedure SetComment(Comment: String); override;
end;
implementation
{ TArc }
constructor TArc.Create(Str: TStream);
begin
FStream := Str;
end;
destructor TArc.Destroy;
var FootMagic: Word;
begin
FootMagic := $001A;
FStream.Write(FootMagic, 2);
end;
function TArc.AddFile(Str: TStream; Name: String): Boolean;
const BufLen = 4096;
type TEntry = packed record
Magic: Byte; //1A
Method: Byte;
FName: array[0..12] of Char; //max 12 bytes+null
PackedSize: Cardinal;
FileTime: Word;
FileDate: Word;
CRC16: Word;
UnpackedSize: Cardinal;
end;
var Entry: TEntry;
HeadLen: Integer;
HeadOffset: Integer;
DataOffset: Integer;
PackSize: Cardinal;
Hasher: TCRC16_ARC;
Buf: array of Byte;
ReadLen: Integer;
FinalOffset: Cardinal;
CRC: Cardinal;
Null: Byte;
begin
HeadLen := SizeOf(Entry);
//skip head for now
HeadOffset := FStream.Position;
DataOffset := HeadOffset + HeadLen;
FStream.Position := DataOffset;
//copy data and calculate checksum
Hasher := TCRC16_ARC.Create;
SetLength(Buf, BufLen);
while Str.Position < Str.Size do begin
ReadLen := Str.Read(Buf[0], BufLen);
Hasher.Update(@Buf[0], ReadLen);
FStream.Write(Buf[0], ReadLen);
end;
PackSize := FStream.Position - DataOffset;
FinalOffset := FStream.Position;
//rewind to write head
FStream.Position := HeadOffset;
CRC := Hasher.Final;
Hasher.Free;
with Entry do begin
Magic := $1A;
Method := 2; //2=store (ARC 3.1+)
FName := Name;
PackedSize := PackSize;
FileTime := DosTime;
FileDate := DosDate;
CRC16 := CRC;
UnpackedSize := Str.Size;
end;
FStream.Write(Entry, SizeOf(Entry));
FStream.Position := FinalOffset;
end;
procedure TArc.SetComment(Comment: String);
begin
FComment := Comment;
end;
end.