forked from zertovitch/zip-ada
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfind_zip.adb
232 lines (208 loc) · 6.84 KB
/
find_zip.adb
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
------------------------------------------------------------------------------
-- File: Find_Zip.adb
-- Description: Search a text string in files packed in a zip archive.
-- Author: Gautier de Montmollin
------------------------------------------------------------------------------
with Ada.Calendar,
Ada.Characters.Handling,
Ada.Command_Line,
Ada.Integer_Text_IO,
Ada.Streams,
Ada.Strings.Fixed,
Ada.Text_IO;
with Zip;
with UnZip.Streams;
with Show_License;
procedure Find_Zip is
max : constant := 2**10; -- 1024
str : String (1 .. max); -- str(1..stl) = string to search
stl : Natural; -- string length
l : Character; -- last character of the search string
z : Zip.Zip_Info;
ignore_case : constant Boolean := True;
use Ada.Characters.Handling, Ada.Integer_Text_IO, Ada.Text_IO;
use UnZip.Streams;
procedure Search_1_file_using_output_stream (file_name : String) is
occ : Natural := 0;
-- Define a circular buffer
siz : constant := max;
type Buffer_range is mod siz;
buf : array (Buffer_range) of Character := (others => ' ');
bup : Buffer_range := 0;
--
-- We define a local, ad-hoc stream type.
--
type Search_stream is new Ada.Streams.Root_Stream_Type with null record;
--
overriding procedure Read
(Self : in out Search_stream;
Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset) is null; -- Not used.
overriding procedure Write
(Self : in out Search_stream;
Item : in Ada.Streams.Stream_Element_Array);
-- Implementation of Write:
overriding procedure Write
(Self : in out Search_stream;
Item : in Ada.Streams.Stream_Element_Array)
is
pragma Unreferenced (Self);
c : Character;
i : Buffer_range := 0;
j : Natural;
begin
for sei in Item'Range loop
c := Character'Val (Item (sei));
if ignore_case then
c := To_Upper (c);
end if;
if c = l then -- last character do match, search further...
i := bup;
j := stl;
match : loop
i := i - 1; -- this loops modulo max: 3, 2, 1, 0, max-1, max-2, ...
j := j - 1;
if j = 0 then -- we survived the whole search string
occ := occ + 1;
exit match;
end if;
exit match when str (j) /= buf (i);
end loop match;
end if;
buf (bup) := c;
bup := bup + 1;
end loop;
end Write;
sst : Search_stream;
begin
Extract (
Destination => sst,
Archive_Info => z,
Entry_Name => file_name,
Ignore_Directory => False
);
if occ > 0 then
Put (occ, 5);
Put_Line (" in [" & To_Lower (file_name) & "]'s contents");
end if;
end Search_1_file_using_output_stream;
-- Old variant using an input stream (memory footprint is uncompressed
-- size plus fixed amounts: can be large!)
procedure Search_1_file_using_input_stream (file_name : String) is
f : Zipped_File_Type;
s : Stream_Access;
c : Character;
occ : Natural := 0;
-- Define a circular buffer
siz : constant := max;
type Buffer_range is mod siz;
buf : array (Buffer_range) of Character := (others => ' ');
i, bup : Buffer_range := 0;
j : Natural;
begin
Open (f, z, file_name);
s := Stream (f);
while not End_Of_File (f) loop
Character'Read (s, c);
if ignore_case then
c := To_Upper (c);
end if;
if c = l then -- last character do match, search further...
i := bup;
j := stl;
match : loop
i := i - 1; -- this loops modulo max: 3, 2, 1, 0, max-1, max-2, ...
j := j - 1;
if j = 0 then -- we survived the whole search string
occ := occ + 1;
exit match;
end if;
exit match when str (j) /= buf (i);
end loop match;
end if;
buf (bup) := c;
bup := bup + 1;
end loop;
Close (f);
if occ > 0 then
Put (occ, 5);
Put_Line (" in [" & To_Lower (file_name) & "] (inward stream method)");
end if;
end Search_1_file_using_input_stream;
pragma Unreferenced (Search_1_file_using_input_stream);
procedure Search_all_files is new Zip.Traverse (Search_1_file_using_output_stream);
procedure Search_in_entry_name (file_name : String) is
un : String := file_name;
begin
if ignore_case then
un := To_Upper (un);
end if;
if Ada.Strings.Fixed.Index (un, str (1 .. stl)) > 0 then
Put_Line (" Found in [" & To_Lower (file_name) & "]'s entry name");
end if;
end Search_in_entry_name;
procedure Search_all_file_names is new Zip.Traverse (Search_in_entry_name);
function Try_with_zip (file_name : String) return String is
begin
if Zip.Exists (file_name) then
return file_name;
else
return file_name & ".zip";
-- Maybe the file doesn't exist, but we tried our best...
end if;
end Try_with_zip;
use Ada.Command_Line;
procedure Load_Archive_Catalogue is
n : constant String := Try_with_zip (Argument (1));
begin
Zip.Load (z, n);
exception
when Zip.Archive_open_error =>
Put ("Can't open archive [" & n & ']'); raise;
when UnZip.Wrong_password =>
Put ("Archive has a password"); raise;
end Load_Archive_Catalogue;
procedure Prepare_Search_String is
s : String := Argument (2);
begin
Put_Line ("Searching string [" & s & "]");
if ignore_case then
s := To_Upper (s);
end if;
stl := s'Length;
if stl > str'Length then
raise Constraint_Error;
end if;
str (1 .. stl) := s;
l := str (stl);
end Prepare_Search_String;
procedure Blurb is
begin
Put_Line ("Find_Zip * Search a text string in files packed in a zip archive.");
Put_Line ("Demo for the Zip-Ada library, by G. de Montmollin");
Put_Line ("Library version " & Zip.version & " dated " & Zip.reference);
Put_Line ("URL: " & Zip.web);
Show_License (Current_Output, "zip.ads");
Put_Line ("Usage: find_zip archive[.zip] [""]text[""]");
New_Line;
Put ("Press Return");
Skip_Line;
end Blurb;
T0, T1, T2 : Ada.Calendar.Time;
use Ada.Calendar;
begin
if Argument_Count < 2 then
Blurb;
return;
end if;
T0 := Clock;
Load_Archive_Catalogue;
Prepare_Search_String;
T1 := Clock;
Search_all_files (z);
Search_all_file_names (z);
T2 := Clock;
Put_Line
("Time elapsed :" & Duration'Image (T2 - T0) &
" seconds (loading catalogue: " & Duration'Image (T1 - T0) & ").");
end Find_Zip;