Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | #include "stdafx.h" |
2 | #pragma hdrstop |
||
3 | #include "zstrings.h" |
||
4 | |||
5 | //#include "dzmatch.h" |
||
6 | |||
7 | /* DZMatch.cpp * Copyright (C) 1997 Mike White, Eric W. Engler and Russell Peters |
||
8 | * Permission is granted to any individual or institution to use, copy, or |
||
9 | * redistribute this software so long as all of the original files are included, |
||
10 | * that it is not sold for profit, and that this copyright notice is retained. |
||
11 | * This version modified by Chris Vleghert BCB/Delphi Zip. |
||
12 | ** distributed under LGPL license |
||
13 | ** see license.txt for details |
||
14 | |||
15 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
16 | |||
17 | See the accompanying file LICENSE, version 2007-Mar-4 or later |
||
18 | (the contents of which are also included in zip.h) for terms of use. |
||
19 | If, for some reason, all these files are missing, the Info-ZIP license |
||
20 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
21 | |||
22 | parts Copyright (C) 1997 Mike White, Eric W. Engler |
||
23 | ************************************************************************ |
||
24 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht |
||
25 | |||
26 | This file is part of TZipMaster Version 1.9. |
||
27 | |||
28 | TZipMaster is free software: you can redistribute it and/or modify |
||
29 | it under the terms of the GNU Lesser General Public License as published by |
||
30 | the Free Software Foundation, either version 3 of the License, or |
||
31 | (at your option) any later version. |
||
32 | |||
33 | TZipMaster is distributed in the hope that it will be useful, |
||
34 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
35 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
36 | GNU Lesser General Public License for more details. |
||
37 | |||
38 | You should have received a copy of the GNU Lesser General Public License |
||
39 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
40 | |||
41 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
42 | updates: http://www.delphizip.org |
||
43 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
44 | updated 2010-AUG-22 |
||
45 | ************************************************************************/ |
||
46 | |||
47 | |||
48 | struct TBounds |
||
49 | { |
||
50 | wchar_t* Start; |
||
51 | wchar_t* Finish; |
||
52 | }; |
||
53 | |||
54 | struct TParts |
||
55 | { |
||
56 | TBounds Main; |
||
57 | TBounds Extn; |
||
58 | int MainLen; |
||
59 | int ExtnLen; |
||
60 | }; |
||
61 | |||
62 | // return <0 _ match to *, 0 _ match to end, >0 _ no match |
||
63 | static __fastcall int Wild(TBounds& bp, TBounds& bs) |
||
64 | { |
||
65 | wchar_t cp, cs; |
||
66 | // handle matching characters before wild |
||
67 | while ((bs.Start <= bs.Finish) && (bp.Start <= bp.Finish)) |
||
68 | { |
||
69 | cp = *bp.Start; |
||
70 | cs = *bs.Start; |
||
71 | if (cp != cs) |
||
72 | { |
||
73 | if (cp == '*') |
||
74 | break; // matched to * |
||
75 | // would match anything except path sep |
||
76 | if ((cp != '?') || (cs == '\\')) |
||
77 | return 1; // no match |
||
78 | } |
||
79 | // they match |
||
80 | ++bp.Start; |
||
81 | ++bs.Start; |
||
82 | } |
||
83 | // we have * or eos |
||
84 | if (bp.Start > bp.Finish && bs.Start > bs.Finish) |
||
85 | return 0; // matched to end |
||
86 | // handle matching characters from end back to * |
||
87 | while (bs.Start <= bs.Finish) |
||
88 | { |
||
89 | cp = *bp.Finish; |
||
90 | cs = *bs.Finish; |
||
91 | if (cp != cs) |
||
92 | { |
||
93 | if (cp == '*') |
||
94 | break; |
||
95 | // must not match path sep |
||
96 | if ((cp != '?') || (cs == '\\')) |
||
97 | return 1; |
||
98 | } |
||
99 | // they match |
||
100 | --bp.Finish; |
||
101 | --bs.Finish; |
||
102 | } |
||
103 | return -1; |
||
104 | } |
||
105 | |||
106 | static __fastcall int WildCmp(TBounds bp, TBounds bs) |
||
107 | { |
||
108 | // quick check for '*' |
||
109 | if ((bp.Start == bp.Finish) && (*bp.Start == '*')) |
||
110 | return 0; // matches any/none |
||
111 | // no more spec? |
||
112 | if (bs.Finish < bs.Start) |
||
113 | return (bp.Finish < bp.Start) ? 0 : 1; // empty matches empty |
||
114 | // handle matching characters before wild |
||
115 | int Result = Wild(bp, bs); |
||
116 | if (Result >= 0) |
||
117 | return Result; |
||
118 | wchar_t* pidx = bp.Start; |
||
119 | wchar_t* sidx = bs.Start; |
||
120 | if (bp.Start > bp.Finish) |
||
121 | return(sidx <= bs.Finish) ? 1 : 0; |
||
122 | // handle wild |
||
123 | if (sidx <= bs.Finish && *pidx == '*') |
||
124 | { |
||
125 | // skip multiple * |
||
126 | while (pidx < bp.Finish && *(pidx + 1) == '*' && *pidx == '*') |
||
127 | ++pidx; |
||
128 | // end of pattern? |
||
129 | if (pidx == bp.Finish) |
||
130 | return 0; // match |
||
131 | TBounds bpt, bst; |
||
132 | bpt.Start = ++pidx; |
||
133 | bpt.Finish = bp.Finish; |
||
134 | bst.Start = sidx; |
||
135 | bst.Finish = bs.Finish; |
||
136 | while (bst.Start <= bst.Finish) |
||
137 | { |
||
138 | // recursively compare sub patterns |
||
139 | int sm = WildCmp(bpt, bst); |
||
140 | if (!sm) |
||
141 | return 0; // match |
||
142 | ++bst.Start; |
||
143 | } |
||
144 | return 1; // no match |
||
145 | } |
||
146 | // end of spec - pattern must only have * |
||
147 | while ((pidx <= bp.Finish) && (*pidx == '*')) |
||
148 | ++pidx; |
||
149 | if (pidx > bp.Finish) |
||
150 | return 0; // match |
||
151 | return -1; // matched so far |
||
152 | } |
||
153 | |||
154 | // returned bit values |
||
155 | const MAIN = 0x01, // not empty |
||
156 | MAIN_WILDALL = 0x02, // is * |
||
157 | MAIN_HASWILD = 0x04, HAD_DOT = 0x08, EXTN = 0x10, EXTN_WILDALL = 0x20, |
||
158 | EXTN_HASWILD = 0x40; |
||
159 | |||
160 | static __fastcall int Decompose(wchar_t* &idx, TParts &parts) |
||
161 | { |
||
162 | int Result = 0; |
||
163 | int mwildall = 0; |
||
164 | int xwildall = 0; |
||
165 | // parts.MainLen = 0; |
||
166 | parts.ExtnLen = 0; |
||
167 | wchar_t* ExtnStart = NULL; |
||
168 | wchar_t* ExtnFinish = NULL; |
||
169 | // start of text or spec |
||
170 | wchar_t* MainStart = idx; |
||
171 | wchar_t* MainFinish; |
||
172 | bool trying = true; |
||
173 | while (trying) |
||
174 | { |
||
175 | wchar_t c = *idx; |
||
176 | // find last dot ignoring those in paths |
||
177 | switch(c) |
||
178 | { |
||
179 | case '.': |
||
180 | if (idx > MainStart) |
||
181 | { // we probably have extn |
||
182 | // if (ExtnStart) |
||
183 | mwildall += xwildall; // catch all * in main |
||
184 | xwildall = 0; |
||
185 | ExtnStart = idx + 1; |
||
186 | } |
||
187 | break; |
||
188 | case '/': |
||
189 | *idx = '\\'; // normalize path seps |
||
190 | case ':': |
||
191 | case '\\': |
||
192 | if (ExtnStart) |
||
193 | { // was false start of extn |
||
194 | ExtnStart = NULL; // no extn (yet) |
||
195 | mwildall += xwildall; |
||
196 | xwildall = 0; |
||
197 | } |
||
198 | break; |
||
199 | case ' ': |
||
200 | { |
||
201 | // space can be embedded but cannot trail |
||
202 | wchar_t* tmp = idx - 1; |
||
203 | ++idx; |
||
204 | while (*idx == ' ') |
||
205 | ++idx; |
||
206 | if (*idx < ' ' || *idx == '|') |
||
207 | { |
||
208 | if (!*idx) |
||
209 | idx--; |
||
210 | // terminate |
||
211 | MainFinish = tmp; |
||
212 | trying = false; |
||
213 | } |
||
214 | else |
||
215 | --idx; |
||
216 | } |
||
217 | break; |
||
218 | case '*': |
||
219 | if (ExtnStart) |
||
220 | ++xwildall; |
||
221 | else |
||
222 | ++mwildall; |
||
223 | break; |
||
224 | case '\0': |
||
225 | MainFinish = idx - 1; |
||
226 | trying = false; |
||
227 | --idx; |
||
228 | break; |
||
229 | case '|': |
||
230 | case '\1': |
||
231 | case '\2': |
||
232 | case '\3': |
||
233 | case '\4': |
||
234 | case '\5': |
||
235 | case '\6': |
||
236 | case '\7': |
||
237 | case '\x8': |
||
238 | case '\x9': |
||
239 | case '\x0a': |
||
240 | case '\x0b': |
||
241 | case '\x0c': |
||
242 | case '\x0d': |
||
243 | case '\x0e': |
||
244 | case '\x0f': |
||
245 | case '\x10': |
||
246 | case '\x11': |
||
247 | case '\x12': |
||
248 | case '\x13': |
||
249 | case '\x14': |
||
250 | case '\x15': |
||
251 | case '\x16': |
||
252 | case '\x17': |
||
253 | case '\x18': |
||
254 | case '\x19': |
||
255 | case '\x1a': |
||
256 | case '\x1b': |
||
257 | case '\x1c': |
||
258 | case '\x1d': |
||
259 | case '\x1e': |
||
260 | case '\x1f': |
||
261 | MainFinish = idx - 1; |
||
262 | trying = false; |
||
263 | break; |
||
264 | } |
||
265 | ++idx; |
||
266 | } |
||
267 | // was there an extension? |
||
268 | if (ExtnStart) |
||
269 | { |
||
270 | Result |= HAD_DOT; |
||
271 | if (ExtnStart <= MainFinish) |
||
272 | { // we have extn |
||
273 | ExtnFinish = MainFinish; |
||
274 | MainFinish = ExtnStart - 2; |
||
275 | parts.ExtnLen = 1 + (ExtnFinish - ExtnStart); |
||
276 | Result |= EXTN; |
||
277 | if (xwildall) |
||
278 | { |
||
279 | if (xwildall == parts.ExtnLen) |
||
280 | Result |= EXTN_WILDALL; |
||
281 | Result |= EXTN_HASWILD; |
||
282 | } |
||
283 | } |
||
284 | else |
||
285 | { |
||
286 | // dot but no extn |
||
287 | ExtnStart = NULL; |
||
288 | --MainFinish; // before dot |
||
289 | } |
||
290 | } |
||
291 | parts.MainLen = 1 + (MainFinish - MainStart); |
||
292 | if (parts.MainLen > 0) |
||
293 | { |
||
294 | Result |= MAIN; |
||
295 | if (mwildall) |
||
296 | { |
||
297 | if (mwildall == parts.MainLen) |
||
298 | Result |= MAIN_WILDALL; |
||
299 | Result |= MAIN_HASWILD; |
||
300 | } |
||
301 | } |
||
302 | // set resulting pointers |
||
303 | parts.Main.Start = MainStart; |
||
304 | parts.Main.Finish = MainFinish; |
||
305 | parts.Extn.Start = ExtnStart; |
||
306 | parts.Extn.Finish = ExtnFinish; |
||
307 | return Result; |
||
308 | } |
||
309 | |||
310 | // only gets called to compare same length names |
||
311 | int FileRCmp(TBounds& Bp, TBounds& Bs) |
||
312 | { |
||
313 | if (Bs.Start > Bs.Finish) |
||
314 | return 1; // no match |
||
315 | if ((*Bp.Start != *Bs.Start) && (*Bp.Start == '\\' || *Bp.Start != '?')) |
||
316 | return 1; // cannot match |
||
317 | ++Bs.Start; |
||
318 | ++Bp.Start; |
||
319 | while ((Bs.Start <= Bs.Finish)) |
||
320 | { |
||
321 | wchar_t cp = *Bp.Finish--; |
||
322 | wchar_t cs = *Bs.Finish--; |
||
323 | if (cp != cs) |
||
324 | { |
||
325 | // must not match path sep |
||
326 | if ((cp != '?') || (cs == '\\')) |
||
327 | return 1; // no match |
||
328 | } |
||
329 | } |
||
330 | return 0; // match |
||
331 | // return (Bs.Start < Bs.Finish && Bp.Start < Bp.Finish) ? 0 : 1; |
||
332 | } |
||
333 | |||
334 | |||
335 | class membuf |
||
336 | { |
||
337 | wchar_t *buf; |
||
338 | public: |
||
339 | membuf(const wchar_t* src); |
||
340 | ~membuf(void){delete[]buf;} |
||
341 | __property wchar_t *buffer={read=buf,write=buf}; |
||
342 | }; |
||
343 | |||
344 | membuf::membuf(const wchar_t* src) |
||
345 | { |
||
346 | int len = 0; |
||
347 | buf = NULL; |
||
348 | if (src) |
||
349 | len = wcslen(src); |
||
350 | |||
351 | if (len) |
||
352 | { |
||
353 | buf = new wchar_t[(len | 63) + 1]; |
||
354 | wcsncpy(buf, src, len); |
||
355 | buf[len] = 0; // mark end - in case |
||
356 | CharUpperBuffW(buf, len); |
||
357 | } |
||
358 | } |
||
359 | |||
360 | bool __fastcall ZMatch(const DZStrW& thePattern, const DZStrW& theSpec) |
||
361 | { |
||
362 | if (thePattern.IsEmpty() != theSpec.IsEmpty()) |
||
363 | return false; |
||
364 | membuf Pattern(thePattern.c_str()); |
||
365 | membuf Spec(theSpec.c_str()); |
||
366 | |||
367 | const FULL_WILD = MAIN_WILDALL | EXTN_WILDALL; |
||
368 | bool Result = false; |
||
369 | TParts ptn, spc, spc1; |
||
370 | // check the spec if has extension |
||
371 | wchar_t* SpecStt = Spec.buffer; |
||
372 | wchar_t* sidx = SpecStt; |
||
373 | while (*sidx <= ' ') |
||
374 | { |
||
375 | if (!(*sidx)) |
||
376 | return false; |
||
377 | ++sidx; |
||
378 | } |
||
379 | int sFlag = Decompose(sidx, spc); |
||
380 | if (!spc.Main.Finish) |
||
381 | return Result; |
||
382 | // now start processing each pattern |
||
383 | wchar_t* pidx = Pattern.buffer; |
||
384 | do |
||
385 | { |
||
386 | wchar_t ch = *pidx; |
||
387 | // skip garbage or separator |
||
388 | while ((ch <= ' ') || (ch == '|')) |
||
389 | { |
||
390 | if (!ch) |
||
391 | return false; |
||
392 | ch = *(++pidx); |
||
393 | } |
||
394 | int pFlag = Decompose(pidx, ptn); |
||
395 | // work out what we must test |
||
396 | |||
397 | if (((pFlag & FULL_WILD) == FULL_WILD) || |
||
398 | ((pFlag & (FULL_WILD | EXTN | HAD_DOT)) == MAIN_WILDALL)) |
||
399 | return true; |
||
400 | if (((pFlag & (EXTN_HASWILD | EXTN)) == EXTN) && |
||
401 | (spc.ExtnLen != ptn.ExtnLen)) |
||
402 | continue; // cannot match |
||
403 | if (!(pFlag & MAIN_HASWILD) && (spc.MainLen != ptn.MainLen)) |
||
404 | continue; // cannot match |
||
405 | int xres = -1; // not tried to match |
||
406 | // make copy of spc |
||
407 | memcpy(&spc1, &spc, sizeof(TParts)); |
||
408 | if (pFlag & EXTN_WILDALL) |
||
409 | xres = 0; // ignore extn as matched |
||
410 | else |
||
411 | { |
||
412 | // if pattern has extn, we must 'split' spec |
||
413 | if (pFlag & HAD_DOT) |
||
414 | { |
||
415 | // check special cases |
||
416 | // pattern ends with dot? |
||
417 | if (!(pFlag & EXTN)) |
||
418 | { |
||
419 | // pattern ended in dot - spec must not have extn |
||
420 | if (sFlag & EXTN) |
||
421 | continue; // spec has extn - cannot match |
||
422 | xres = 0; // no extn to check |
||
423 | } |
||
424 | else |
||
425 | { |
||
426 | // spec must have extn |
||
427 | if (!(sFlag & EXTN)) |
||
428 | continue; // no spec extn - cannot match |
||
429 | } |
||
430 | } |
||
431 | else |
||
432 | { |
||
433 | // no Pattern dot _ test fill spec |
||
434 | if (sFlag & EXTN) |
||
435 | spc1.Main.Finish = spc.Extn.Finish; // full psec |
||
436 | xres = 0; // no extn to match |
||
437 | } |
||
438 | // test extn first (if required) |
||
439 | if (xres < 0) |
||
440 | xres = WildCmp(ptn.Extn, spc1.Extn); |
||
441 | } |
||
442 | // if extn matched test main part |
||
443 | if (!xres) |
||
444 | { |
||
445 | if (!(pFlag & MAIN_WILDALL)) |
||
446 | { |
||
447 | if (pFlag & MAIN_HASWILD) |
||
448 | xres = WildCmp(ptn.Main, spc1.Main); |
||
449 | else |
||
450 | xres = FileRCmp(ptn.Main, spc1.Main); |
||
451 | } |
||
452 | } |
||
453 | // equate |
||
454 | Result = !xres; |
||
455 | // at next pattern |
||
456 | } |
||
457 | while (!Result); |
||
458 | return Result; |
||
459 | } |