Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  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. }
  460.