////////////////////////////////////////////////////////////////////////////////
|
// This source file is part of the ZipArchive library source distribution and
|
// is Copyrighted 2000 - 2011 by Artpol Software - Tadeusz Dracz
|
//
|
// This program is free software; you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License
|
// as published by the Free Software Foundation; either version 2
|
// of the License, or (at your option) any later version.
|
//
|
// For the licensing details refer to the License.txt file.
|
//
|
// Web Site: http://www.artpol-software.com
|
////////////////////////////////////////////////////////////////////////////////
|
|
#include "stdafx.h"
|
#include "Wildcard.h"
|
|
namespace ZipArchiveLib
|
{
|
|
bool CWildcard::IsPatternValid(LPCTSTR lpszPattern, int* iErrorType)
|
{
|
try
|
{
|
/* loop through pattern to EOS */
|
while (*lpszPattern)
|
{
|
/* determine pattern type */
|
switch (*lpszPattern)
|
{
|
/* check literal escape, it cannot be at end of pattern */
|
case _T('\\'):
|
if (!*++lpszPattern)
|
throw patternEsc;
|
lpszPattern++;
|
break;
|
|
/* the [..] construct must be well formed */
|
case _T('['):
|
lpszPattern++;
|
|
/* if the next character is ']' then bad pattern */
|
if (*lpszPattern == _T(']'))
|
throw patternEmpty;
|
|
/* if end of pattern here then bad pattern */
|
if (!*lpszPattern)
|
throw patternClose;
|
|
/* loop to end of [..] construct */
|
while (*lpszPattern != _T(']'))
|
{
|
/* check for literal escape */
|
if (*lpszPattern == _T('\\'))
|
{
|
lpszPattern++;
|
|
/* if end of pattern here then bad pattern */
|
if (!*lpszPattern++)
|
throw patternEsc;
|
}
|
else lpszPattern++;
|
|
/* if end of pattern here then bad pattern */
|
if (!*lpszPattern)
|
throw patternClose;
|
|
/* if this a range */
|
if (*lpszPattern == _T('-'))
|
{
|
/* we must have an end of range */
|
if (!*++lpszPattern || *lpszPattern == ']')
|
throw patternRange;
|
else
|
{
|
|
/* check for literal escape */
|
if (*lpszPattern == _T('\\'))
|
lpszPattern++;
|
|
/* if end of pattern here
|
then bad pattern */
|
if (!*lpszPattern++)
|
throw patternEsc;
|
}
|
}
|
}
|
break;
|
|
/* all other characters are valid pattern elements */
|
case '*':
|
case '?':
|
default:
|
lpszPattern++; /* "normal" character */
|
break;
|
}
|
}
|
throw patternValid;
|
}
|
catch (int i)
|
{
|
if (iErrorType)
|
*iErrorType = i;
|
return i == patternValid;
|
}
|
|
|
}
|
|
bool CWildcard::IsPattern(LPCTSTR lpszPattern)
|
{
|
while (*lpszPattern)
|
{
|
switch (*lpszPattern++)
|
{
|
case _T('?'):
|
case _T('*'):
|
case _T('['):
|
case _T('\\'):
|
return true;
|
}
|
}
|
return false;
|
|
}
|
|
bool CWildcard::IsMatch(LPCTSTR lpszText, int *iRetCode)
|
{
|
CZipString sz;
|
if (!m_bCaseSensitive)
|
{
|
sz = lpszText;
|
sz.MakeLower();
|
lpszText = (LPCTSTR)sz;
|
}
|
int i = Match((LPCTSTR)m_szPattern, lpszText);
|
if (iRetCode)
|
*iRetCode = i;
|
return i == matchValid;
|
}
|
|
int CWildcard::MatchAfterStar(LPCTSTR p, LPCTSTR t)
|
{
|
int iMatch = matchNone;
|
TCHAR nextp;
|
|
/* pass over existing ? and * in pattern */
|
|
while ( *p == _T('?') || *p == _T('*') )
|
{
|
/* take one char for each ? and + */
|
|
if (*p == _T('?'))
|
{
|
/* if end of text then no match */
|
if (!*t++)
|
return matchAbort;
|
}
|
|
/* move to next char in pattern */
|
|
p++;
|
}
|
|
/* if end of pattern we have matched regardless of text left */
|
|
if (!*p)
|
return matchValid;
|
|
/* get the next character to match which must be a literal or '[' */
|
|
nextp = *p;
|
if (nextp == _T('\\'))
|
{
|
nextp = p[1];
|
|
/* if end of text then we have a bad pattern */
|
|
if (!nextp)
|
return matchPattern;
|
}
|
|
/* Continue until we run out of text or definite result seen */
|
|
do
|
{
|
/* a precondition for matching is that the next character
|
in the pattern match the next character in the text or that
|
the next pattern char is the beginning of a range. Increment
|
text pointer as we go here */
|
|
if (nextp == *t || nextp == _T('['))
|
iMatch = Match(p, t);
|
|
/* try finding another precondition */
|
if (iMatch == matchPattern)
|
iMatch = matchNone;
|
/* if the end of text is reached then no iMatch */
|
|
if (!*t++)
|
iMatch = matchAbort;
|
|
} while ( iMatch != matchValid &&
|
iMatch != matchAbort);
|
|
/* return result */
|
|
return iMatch;
|
}
|
|
|
int CWildcard::Match(LPCTSTR lpszPattern, LPCTSTR lpszText)
|
{
|
TCHAR range_start, range_end; /* start and end in range */
|
bool bInvert; /* is this [..] or [!..] */
|
bool bMemberMatch; /* have I matched the [..] construct? */
|
bool bLoop; /* should I terminate? */
|
|
for ( ; *lpszPattern; lpszPattern++, lpszText++)
|
{
|
/* if this is the end of the text
|
then this is the end of the match */
|
|
if (!*lpszText)
|
{
|
if ( *lpszPattern == _T('*') && *++lpszPattern == _T('\0') )
|
return matchValid;
|
else
|
return matchAbort;
|
}
|
|
/* determine and react to pattern type */
|
|
switch (*lpszPattern)
|
{
|
case _T('?'): /* single any character match */
|
break;
|
|
case _T('*'): /* multiple any character match */
|
return MatchAfterStar (lpszPattern, lpszText);
|
|
/* [..] construct, single member/exclusion character match */
|
case _T('['):
|
{
|
/* move to beginning of range */
|
|
lpszPattern++;
|
|
/* check if this is a member match or exclusion match */
|
|
bInvert = false;
|
if (*lpszPattern == _T('!') || *lpszPattern == _T('^'))
|
{
|
bInvert = true;
|
lpszPattern++;
|
}
|
|
/* if closing bracket here or at range start then we have a
|
malformed pattern */
|
|
if (*lpszPattern == _T(']'))
|
return matchPattern;
|
|
bMemberMatch = false;
|
bLoop = true;
|
|
while (bLoop)
|
{
|
/* if end of construct then bLoop is done */
|
|
if (*lpszPattern == _T(']'))
|
{
|
bLoop = false;
|
continue;
|
}
|
|
/* matching a '!', '^', '-', '\' or a ']' */
|
|
if (*lpszPattern == _T('\\'))
|
range_start = range_end = *++lpszPattern;
|
else
|
range_start = range_end = *lpszPattern;
|
|
/* if end of pattern then bad pattern (Missing ']') */
|
|
if (!*lpszPattern)
|
return matchPattern;
|
|
/* check for range bar */
|
if (*++lpszPattern == _T('-'))
|
{
|
/* get the range end */
|
|
range_end = *++lpszPattern;
|
|
/* if end of pattern or construct
|
then bad pattern */
|
|
if (range_end == _T('\0') || range_end == _T(']'))
|
return matchPattern;
|
/* special character range end */
|
if (range_end == _T('\\'))
|
{
|
range_end = *++lpszPattern;
|
|
/* if end of text then
|
we have a bad pattern */
|
if (!range_end)
|
return matchPattern;
|
}
|
|
/* move just beyond this range */
|
lpszPattern++;
|
}
|
|
/* if the text character is in range then match found.
|
make sure the range letters have the proper
|
relationship to one another before comparison */
|
|
if (range_start < range_end)
|
{
|
if (*lpszText >= range_start && *lpszText <= range_end)
|
{
|
bMemberMatch = true;
|
bLoop = false;
|
}
|
}
|
else
|
{
|
if (*lpszText >= range_end && *lpszText <= range_start)
|
{
|
bMemberMatch = true;
|
bLoop = false;
|
}
|
}
|
}
|
|
/* if there was a match in an exclusion set then no match */
|
/* if there was no match in a member set then no match */
|
|
if ((bInvert && bMemberMatch) || !(bInvert || bMemberMatch))
|
return matchRange;
|
|
/* if this is not an exclusion then skip the rest of
|
the [...] construct that already matched. */
|
|
if (bMemberMatch)
|
{
|
while (*lpszPattern != _T(']'))
|
{
|
/* bad pattern (Missing ']') */
|
if (!*lpszPattern)
|
return matchPattern;
|
|
/* skip exact match */
|
if (*lpszPattern == _T('\\'))
|
{
|
lpszPattern++;
|
|
/* if end of text then
|
we have a bad pattern */
|
|
if (!*lpszPattern)
|
return matchPattern;
|
}
|
|
/* move to next pattern char */
|
|
lpszPattern++;
|
}
|
}
|
break;
|
}
|
case _T('\\'): /* next character is quoted and must match exactly */
|
|
/* move pattern pointer to quoted char and fall through */
|
|
lpszPattern++;
|
|
/* if end of text then we have a bad pattern */
|
|
if (!*lpszPattern)
|
return matchPattern;
|
|
/* must match this character exactly */
|
|
default:
|
if (*lpszPattern != *lpszText)
|
return matchPattern;
|
}
|
}
|
/* if end of text not reached then the pattern fails */
|
|
if (*lpszText)
|
return matchEnd;
|
else
|
return matchValid;
|
}
|
|
|
} // namespace
|