Subversion Repositories autosfx

Rev

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
}