+ Added support for "-i" flags and case insensitive matching
+ Renamed Expr class to DisjList, which is more descriptive as to its function + Added ' and " to the list of allowed characters in an unquoted string. + Added updated sniffer rule grammar to doxygen for the Parser class git-svn-id: file:///srv/svn/repos/haiku/trunk/current@685 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
/*!
|
||||||
|
\file sniffer/DisjList.h
|
||||||
|
Mime Sniffer Disjunction List declarations
|
||||||
|
*/
|
||||||
|
#ifndef _sk_sniffer_disj_list_h_
|
||||||
|
#define _sk_sniffer_disj_list_h_
|
||||||
|
|
||||||
|
class BPositionIO;
|
||||||
|
|
||||||
|
namespace Sniffer {
|
||||||
|
|
||||||
|
//! Abstract class defining methods acting on a list of ORed patterns
|
||||||
|
class DisjList {
|
||||||
|
public:
|
||||||
|
DisjList();
|
||||||
|
virtual ~DisjList();
|
||||||
|
virtual bool Sniff(BPositionIO *data) const = 0;
|
||||||
|
|
||||||
|
void SetCaseInsensitive(bool how);
|
||||||
|
bool IsCaseInsensitive();
|
||||||
|
protected:
|
||||||
|
bool fCaseInsensitive;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _sk_sniffer_disj_list_h_
|
||||||
@@ -23,7 +23,7 @@ class BString;
|
|||||||
namespace Sniffer {
|
namespace Sniffer {
|
||||||
|
|
||||||
class Rule;
|
class Rule;
|
||||||
class Expr;
|
class DisjList;
|
||||||
class RPattern;
|
class RPattern;
|
||||||
class Pattern;
|
class Pattern;
|
||||||
|
|
||||||
@@ -77,6 +77,7 @@ typedef enum TokenType {
|
|||||||
Colon,
|
Colon,
|
||||||
Divider,
|
Divider,
|
||||||
Ampersand,
|
Ampersand,
|
||||||
|
CaseInsensitiveFlag,
|
||||||
CharacterString,
|
CharacterString,
|
||||||
Integer,
|
Integer,
|
||||||
FloatingPoint
|
FloatingPoint
|
||||||
@@ -192,6 +193,106 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//! Handles parsing a sniffer rule, yielding either a parsed rule or a descriptive error message.
|
//! Handles parsing a sniffer rule, yielding either a parsed rule or a descriptive error message.
|
||||||
|
/*! A MIME sniffer rule is valid if it is well-formed with respect to the
|
||||||
|
following grammar and fulfills some further conditions listed thereafter:
|
||||||
|
|
||||||
|
<code>
|
||||||
|
Rule ::= LWS Priority LWS ConjList LWS
|
||||||
|
ConjList ::= DisjList (LWS DisjList)*
|
||||||
|
DisjList ::= "(" LWS PatternList LWS ")"
|
||||||
|
| "(" LWS RPatternList LWS ")"
|
||||||
|
| Range LWS "(" LWS PatternList LWS ")"
|
||||||
|
RPatternList ::= [Flag LWS] RPattern (LWS "|" LWS [Flag LWS] RPattern)*
|
||||||
|
PatternList ::= [Flag LWS] Pattern (LWS "|" LWS [Flag LWS] Pattern)*
|
||||||
|
|
||||||
|
RPattern ::= LWS Range LWS Pattern
|
||||||
|
Pattern ::= PString [ LWS "&" LWS Mask ]
|
||||||
|
Range ::= "[" LWS SDecimal [LWS ":" LWS SDecimal] LWS "]"
|
||||||
|
|
||||||
|
Priority ::= Float
|
||||||
|
Mask ::= PString
|
||||||
|
PString ::= HexLiteral | QuotedString | UnquotedString
|
||||||
|
|
||||||
|
HexLiteral ::= "0x" HexPair HexPair*
|
||||||
|
HexPair ::= HexChar HexChar
|
||||||
|
|
||||||
|
QuotedString ::= SingleQuotedString | DoubleQuotedString
|
||||||
|
SQuotedString := "'" SQChar+ "'"
|
||||||
|
DQuotedString := '"' DQChar+ '"'
|
||||||
|
|
||||||
|
UnquotedString ::= EscapedChar UChar*
|
||||||
|
EscapedChar ::= OctalEscape | HexEscape | "\" Char
|
||||||
|
OctalEscape ::= "\" [[OctHiChar] OctChar] OctChar
|
||||||
|
HexEscape ::= "\x" HexPair
|
||||||
|
|
||||||
|
Flag ::= "-i"
|
||||||
|
|
||||||
|
SDecimal ::= [Sign] Decimal
|
||||||
|
Decimal ::= DecChar DecChar*
|
||||||
|
Float ::= Fixed [("E" | "e") SDecimal]
|
||||||
|
Fixed ::= SDecimal ["." [Decimal]] | [Sign] "." Decimal
|
||||||
|
Sign ::= "+" | "-"
|
||||||
|
|
||||||
|
PunctuationChar ::= "(" | ")" | "[" | "]" | "|" | "&" | ":"
|
||||||
|
OctHiChar ::= "0" | "1" | "2" | "3"
|
||||||
|
OctChar ::= OctHiChar | "4" | "5" | "6" | "7"
|
||||||
|
DecChar ::= OctChar | "8" | "9"
|
||||||
|
HexChar ::= DecChar | "a" | "b" | "c" | "d" | "e" | "f" | "A" | "B" | "C"
|
||||||
|
| "D" | "E" | "F"
|
||||||
|
|
||||||
|
Char :: <any character>
|
||||||
|
SQChar ::= <Char except "\", "'"> | EscapedChar
|
||||||
|
DQChar ::= <Char except "\", '"'> | EscapedChar
|
||||||
|
UChar ::= <Char except "\", LWSChar, and PunctuationChar> | EscapedChar
|
||||||
|
|
||||||
|
LWS ::= LWSChar*
|
||||||
|
LWSChar ::= " " | TAB | LF
|
||||||
|
</code>
|
||||||
|
|
||||||
|
Conditions:
|
||||||
|
- If a mask is specified for a pattern, this mask must have the same
|
||||||
|
length as the pattern string.
|
||||||
|
- 0.0 <= Priority <= 1.0
|
||||||
|
- 0 <= Range begin <= Range end
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- If a case-insensitive flag ("-i") appears in front of any Pattern or RPattern
|
||||||
|
in a DisjList, case-insensitivity is applied to the entire DisjList.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- 1.0 ('ABCD')
|
||||||
|
The file must start with the string "ABCD". The priority of the rule
|
||||||
|
is 1.0 (maximal).
|
||||||
|
- 0.8 [0:3] ('ABCD' | 'abcd')
|
||||||
|
The file must contain the string "ABCD" or "abcd" starting somewhere in
|
||||||
|
the first four bytes. The rule priority is 0.8.
|
||||||
|
- 0.5 ([0:3] 'ABCD' | [0:3] 'abcd' | [13] 'EFGH')
|
||||||
|
The file must contain the string "ABCD" or "abcd" starting somewhere in
|
||||||
|
the first four bytes or the string "EFGH" at position 13. The rule
|
||||||
|
priority is 0.5.
|
||||||
|
- 0.8 [0:3] ('ABCD' & 0xff00ffff | 'abcd' & 0xffff00ff)
|
||||||
|
The file must contain the string "A.CD" or "ab.d" (whereas "." is an
|
||||||
|
arbitrary character) starting somewhere in the first four bytes. The
|
||||||
|
rule priority is 0.8.
|
||||||
|
- 0.3 [10] ('mnop') ('abc') [20] ('xyz')
|
||||||
|
The file must contain the string 'abc' at the beginning of the file,
|
||||||
|
the string 'mnop' starting at position 10, and the string 'xyz'
|
||||||
|
starting at position 20. The rule priority is 0.3.
|
||||||
|
- 200e-3 (-i 'ab')
|
||||||
|
The file must contain the string 'ab', 'aB', 'Ab', or 'AB' at the
|
||||||
|
beginning of the file. The rule priority is 0.2.
|
||||||
|
|
||||||
|
Real examples:
|
||||||
|
- 0.20 ([0]"//" | [0]"/\*" | [0:32]"#include" | [0:32]"#ifndef"
|
||||||
|
| [0:32]"#ifdef")
|
||||||
|
text/x-source-code
|
||||||
|
- 0.70 ("8BPS \000\000\000\000" & 0xffffffff0000ffffffff )
|
||||||
|
image/x-photoshop
|
||||||
|
- 0.40 [0:64]( -i "<HTML" | "<HEAD" | "<TITLE" | "<BODY"
|
||||||
|
| "<TABLE" | "<!--" | "<META" | "<CENTER")
|
||||||
|
text/html
|
||||||
|
|
||||||
|
*/
|
||||||
class Parser {
|
class Parser {
|
||||||
public:
|
public:
|
||||||
Parser();
|
Parser();
|
||||||
@@ -209,11 +310,11 @@ private:
|
|||||||
// Parsing functions
|
// Parsing functions
|
||||||
void ParseRule(Rule *result);
|
void ParseRule(Rule *result);
|
||||||
double ParsePriority();
|
double ParsePriority();
|
||||||
std::vector<Expr*>* ParseExprList();
|
std::vector<DisjList*>* ParseConjList();
|
||||||
Expr* ParseExpr();
|
DisjList* ParseDisjList();
|
||||||
Range ParseRange();
|
Range ParseRange();
|
||||||
Expr* ParsePatternList(Range range);
|
DisjList* ParsePatternList(Range range);
|
||||||
Expr* ParseRPatternList();
|
DisjList* ParseRPatternList();
|
||||||
RPattern* ParseRPattern();
|
RPattern* ParseRPattern();
|
||||||
Pattern* ParsePattern();
|
Pattern* ParsePattern();
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ public:
|
|||||||
status_t InitCheck() const;
|
status_t InitCheck() const;
|
||||||
Err* GetErr() const;
|
Err* GetErr() const;
|
||||||
|
|
||||||
bool Sniff(Range range, BPositionIO *data) const;
|
bool Sniff(Range range, BPositionIO *data, bool caseInsensitive) const;
|
||||||
|
|
||||||
status_t SetTo(const std::string &string, const std::string &mask);
|
status_t SetTo(const std::string &string, const std::string &mask);
|
||||||
private:
|
private:
|
||||||
bool Sniff(off_t start, off_t size, BPositionIO *data) const;
|
bool Sniff(off_t start, off_t size, BPositionIO *data, bool caseInsensitive) const;
|
||||||
|
|
||||||
void SetStatus(status_t status, const char *msg = NULL);
|
void SetStatus(status_t status, const char *msg = NULL);
|
||||||
void SetErrorMessage(const char *msg);
|
void SetErrorMessage(const char *msg);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#ifndef _sk_sniffer_pattern_list_h_
|
#ifndef _sk_sniffer_pattern_list_h_
|
||||||
#define _sk_sniffer_pattern_list_h_
|
#define _sk_sniffer_pattern_list_h_
|
||||||
|
|
||||||
#include <sniffer/Expr.h>
|
#include <sniffer/DisjList.h>
|
||||||
#include <sniffer/Range.h>
|
#include <sniffer/Range.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -20,8 +20,10 @@ namespace Sniffer {
|
|||||||
class Err;
|
class Err;
|
||||||
class Pattern;
|
class Pattern;
|
||||||
|
|
||||||
//! A list of patterns, all of which are to be searched over the same range.
|
/*! \brief A list of patterns, one of which must match for the list to match, all
|
||||||
class PatternList : public Expr {
|
of which are to be searched over the same range.
|
||||||
|
*/
|
||||||
|
class PatternList : public DisjList {
|
||||||
public:
|
public:
|
||||||
PatternList(Range range);
|
PatternList(Range range);
|
||||||
virtual ~PatternList();
|
virtual ~PatternList();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public:
|
|||||||
status_t InitCheck() const;
|
status_t InitCheck() const;
|
||||||
Err* GetErr() const;
|
Err* GetErr() const;
|
||||||
|
|
||||||
bool Sniff(BPositionIO *data) const;
|
bool Sniff(BPositionIO *data, bool caseInsensitive) const;
|
||||||
private:
|
private:
|
||||||
Range fRange;
|
Range fRange;
|
||||||
Pattern *fPattern;
|
Pattern *fPattern;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#ifndef _sk_sniffer_r_pattern_list_h_
|
#ifndef _sk_sniffer_r_pattern_list_h_
|
||||||
#define _sk_sniffer_r_pattern_list_h_
|
#define _sk_sniffer_r_pattern_list_h_
|
||||||
|
|
||||||
#include <sniffer/Expr.h>
|
#include <sniffer/DisjList.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class BPositionIO;
|
class BPositionIO;
|
||||||
@@ -20,7 +20,7 @@ class Err;
|
|||||||
class RPattern;
|
class RPattern;
|
||||||
|
|
||||||
//! A list of patterns, each of which is to be searched over its own specified range.
|
//! A list of patterns, each of which is to be searched over its own specified range.
|
||||||
class RPatternList : public Expr {
|
class RPatternList : public DisjList {
|
||||||
public:
|
public:
|
||||||
RPatternList();
|
RPatternList();
|
||||||
virtual ~RPatternList();
|
virtual ~RPatternList();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class BPositionIO;
|
|||||||
|
|
||||||
namespace Sniffer {
|
namespace Sniffer {
|
||||||
|
|
||||||
class Expr;
|
class DisjList;
|
||||||
|
|
||||||
/*! \brief A priority and a list of expressions to be used for sniffing out the
|
/*! \brief A priority and a list of expressions to be used for sniffing out the
|
||||||
type of an untyped file.
|
type of an untyped file.
|
||||||
@@ -34,10 +34,10 @@ private:
|
|||||||
friend class Parser;
|
friend class Parser;
|
||||||
|
|
||||||
void Unset();
|
void Unset();
|
||||||
void SetTo(double priority, std::vector<Expr*>* list);
|
void SetTo(double priority, std::vector<DisjList*>* list);
|
||||||
|
|
||||||
double fPriority;
|
double fPriority;
|
||||||
std::vector<Expr*> *fExprList;
|
std::vector<DisjList*> *fConjList; // A list of DisjLists to be ANDed
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
/*!
|
||||||
|
\file DisjList.cpp
|
||||||
|
MIME sniffer Disjunction List class implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sniffer/DisjList.h>
|
||||||
|
|
||||||
|
using namespace Sniffer;
|
||||||
|
|
||||||
|
DisjList::DisjList()
|
||||||
|
: fCaseInsensitive(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DisjList::~DisjList() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DisjList::SetCaseInsensitive(bool how) {
|
||||||
|
fCaseInsensitive = how;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DisjList::IsCaseInsensitive() {
|
||||||
|
return fCaseInsensitive;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
MIME sniffer rule parser implementation
|
MIME sniffer rule parser implementation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//#include <sniffer/Expr.h>
|
|
||||||
#include <sniffer/Parser.h>
|
#include <sniffer/Parser.h>
|
||||||
#include <sniffer/Pattern.h>
|
#include <sniffer/Pattern.h>
|
||||||
#include <sniffer/PatternList.h>
|
#include <sniffer/PatternList.h>
|
||||||
@@ -374,6 +373,7 @@ TokenStream::SetTo(const std::string &string) {
|
|||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
charStr = ch;
|
charStr = ch;
|
||||||
|
lastChar = ch;
|
||||||
state = tsssLonelyMinusOrPlus;
|
state = tsssLonelyMinusOrPlus;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -570,6 +570,9 @@ TokenStream::SetTo(const std::string &string) {
|
|||||||
} else if (ch == '.') {
|
} else if (ch == '.') {
|
||||||
charStr += ch;
|
charStr += ch;
|
||||||
state = tsssLonelyDecimalPoint;
|
state = tsssLonelyDecimalPoint;
|
||||||
|
} else if (ch == 'i' && lastChar == '-') {
|
||||||
|
AddToken(CaseInsensitiveFlag, startPos);
|
||||||
|
state = tsssStart;
|
||||||
} else
|
} else
|
||||||
throw new Err(std::string("Sniffer pattern error: incomplete signed number"), pos);
|
throw new Err(std::string("Sniffer pattern error: incomplete signed number"), pos);
|
||||||
break;
|
break;
|
||||||
@@ -615,8 +618,6 @@ TokenStream::SetTo(const std::string &string) {
|
|||||||
AddString(charStr, startPos);
|
AddString(charStr, startPos);
|
||||||
stream.Unget(); // In case it's punctuation, let tsssStart handle it
|
stream.Unget(); // In case it's punctuation, let tsssStart handle it
|
||||||
state = tsssStart;
|
state = tsssStart;
|
||||||
} else if (ch == '\'' || ch == '"') {
|
|
||||||
throw new Err(std::string("Sniffer pattern error: illegal unquoted character '") + ch + "'", pos);
|
|
||||||
} else if (ch == 0x3 && stream.IsEmpty()) {
|
} else if (ch == 0x3 && stream.IsEmpty()) {
|
||||||
AddString(charStr, startPos);
|
AddString(charStr, startPos);
|
||||||
keepLooping = false;
|
keepLooping = false;
|
||||||
@@ -976,6 +977,9 @@ Sniffer::tokenTypeToString(TokenType type) {
|
|||||||
case Ampersand:
|
case Ampersand:
|
||||||
return "Ampersand";
|
return "Ampersand";
|
||||||
break;
|
break;
|
||||||
|
case CaseInsensitiveFlag:
|
||||||
|
return "CaseInsensitiveFlag";
|
||||||
|
break;
|
||||||
case CharacterString:
|
case CharacterString:
|
||||||
return "CharacterString";
|
return "CharacterString";
|
||||||
break;
|
break;
|
||||||
@@ -1048,8 +1052,8 @@ Parser::ParseRule(Rule *result) {
|
|||||||
|
|
||||||
// Priority
|
// Priority
|
||||||
double priority = ParsePriority();
|
double priority = ParsePriority();
|
||||||
// Expression List
|
// Conjunction List
|
||||||
std::vector<Expr*>* list = ParseExprList();
|
std::vector<DisjList*>* list = ParseConjList();
|
||||||
|
|
||||||
result->SetTo(priority, list);
|
result->SetTo(priority, list);
|
||||||
}
|
}
|
||||||
@@ -1069,16 +1073,16 @@ Parser::ParsePriority() {
|
|||||||
throw new Err("Sniffer pattern error: match level expected", t->Pos()); // Same as R5
|
throw new Err("Sniffer pattern error: match level expected", t->Pos()); // Same as R5
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Expr*>*
|
std::vector<DisjList*>*
|
||||||
Parser::ParseExprList() {
|
Parser::ParseConjList() {
|
||||||
std::vector<Expr*> *list = new(nothrow) std::vector<Expr*>;
|
std::vector<DisjList*> *list = new(nothrow) std::vector<DisjList*>;
|
||||||
if (!list)
|
if (!list)
|
||||||
ThrowOutOfMemError(stream.Pos());
|
ThrowOutOfMemError(stream.Pos());
|
||||||
try {
|
try {
|
||||||
// Expr+
|
// DisjList+
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
Expr* expr = ParseExpr();
|
DisjList* expr = ParseDisjList();
|
||||||
if (!expr)
|
if (!expr)
|
||||||
break;
|
break;
|
||||||
else {
|
else {
|
||||||
@@ -1095,10 +1099,10 @@ Parser::ParseExprList() {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr*
|
DisjList*
|
||||||
Parser::ParseExpr() {
|
Parser::ParseDisjList() {
|
||||||
// If we've run out of tokens right now, it's okay, but
|
// If we've run out of tokens right now, it's okay, but
|
||||||
// we need to let ParseExprList() know what's up
|
// we need to let ParseConjList() know what's up
|
||||||
if (stream.IsEmpty())
|
if (stream.IsEmpty())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -1109,10 +1113,14 @@ Parser::ParseExpr() {
|
|||||||
// PatternList | RangeList
|
// PatternList | RangeList
|
||||||
if (t1->Type() == LeftParen) {
|
if (t1->Type() == LeftParen) {
|
||||||
const Token *t2 = stream.Get();
|
const Token *t2 = stream.Get();
|
||||||
|
// Skip the case-insensitive flag, if there is one
|
||||||
|
const Token *tokenOfInterest = (t2->Type() == CaseInsensitiveFlag) ? stream.Get() : t2;
|
||||||
|
if (t2 != tokenOfInterest)
|
||||||
|
stream.Unget(); // We called Get() three times
|
||||||
stream.Unget();
|
stream.Unget();
|
||||||
stream.Unget();
|
stream.Unget();
|
||||||
// RangeList
|
// RangeList
|
||||||
if (t2->Type() == LeftBracket) {
|
if (tokenOfInterest->Type() == LeftBracket) {
|
||||||
return ParseRPatternList();
|
return ParseRPatternList();
|
||||||
// PatternList
|
// PatternList
|
||||||
} else {
|
} else {
|
||||||
@@ -1175,7 +1183,7 @@ Parser::ParseRange() {
|
|||||||
throw range.GetErr();
|
throw range.GetErr();
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr*
|
DisjList*
|
||||||
Parser::ParsePatternList(Range range) {
|
Parser::ParsePatternList(Range range) {
|
||||||
PatternList *list = new(nothrow) PatternList(range);
|
PatternList *list = new(nothrow) PatternList(range);
|
||||||
if (!list)
|
if (!list)
|
||||||
@@ -1183,9 +1191,12 @@ Parser::ParsePatternList(Range range) {
|
|||||||
try {
|
try {
|
||||||
// LeftParen
|
// LeftParen
|
||||||
stream.Read(LeftParen);
|
stream.Read(LeftParen);
|
||||||
// Pattern, (Divider, Pattern)*
|
// [Flag] Pattern, (Divider, [Flag] Pattern)*
|
||||||
bool keepLooping = true;
|
bool keepLooping = true;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// [Flag]
|
||||||
|
if (stream.CondRead(CaseInsensitiveFlag))
|
||||||
|
list->SetCaseInsensitive(true);
|
||||||
// Pattern
|
// Pattern
|
||||||
list->Add(ParsePattern());
|
list->Add(ParsePattern());
|
||||||
// [Divider]
|
// [Divider]
|
||||||
@@ -1203,7 +1214,7 @@ Parser::ParsePatternList(Range range) {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr*
|
DisjList*
|
||||||
Parser::ParseRPatternList() {
|
Parser::ParseRPatternList() {
|
||||||
RPatternList *list = new(nothrow) RPatternList();
|
RPatternList *list = new(nothrow) RPatternList();
|
||||||
if (!list)
|
if (!list)
|
||||||
@@ -1211,9 +1222,12 @@ Parser::ParseRPatternList() {
|
|||||||
try {
|
try {
|
||||||
// LeftParen
|
// LeftParen
|
||||||
stream.Read(LeftParen);
|
stream.Read(LeftParen);
|
||||||
// RPattern, (Divider, RPattern)*
|
// [Flag] RPattern, (Divider, [Flag] RPattern)*
|
||||||
bool keepLooping = true;
|
bool keepLooping = true;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// [Flag]
|
||||||
|
if (stream.CondRead(CaseInsensitiveFlag))
|
||||||
|
list->SetCaseInsensitive(true);
|
||||||
// RPattern
|
// RPattern
|
||||||
list->Add(ParseRPattern());
|
list->Add(ParseRPattern());
|
||||||
// [Divider]
|
// [Divider]
|
||||||
|
|||||||
@@ -80,17 +80,14 @@ Pattern::SetTo(const std::string &string, const std::string &mask) {
|
|||||||
false if not.
|
false if not.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
Pattern::Sniff(Range range, BPositionIO *data) const {
|
Pattern::Sniff(Range range, BPositionIO *data, bool caseInsensitive) const {
|
||||||
// If our range contains negative values relative to the end of
|
|
||||||
// the file, convert them to positive values relative to the
|
|
||||||
// beginning of the file.
|
|
||||||
int32 start = range.Start();
|
int32 start = range.Start();
|
||||||
int32 end = range.End();
|
int32 end = range.End();
|
||||||
off_t size = data->Seek(0, SEEK_END);
|
off_t size = data->Seek(0, SEEK_END);
|
||||||
if (end >= size)
|
if (end >= size)
|
||||||
end = size-1;
|
end = size-1; // Don't bother searching beyond the end of the stream
|
||||||
for (int i = start; i <= end; i++) {
|
for (int i = start; i <= end; i++) {
|
||||||
if (Sniff(i, size, data))
|
if (Sniff(i, size, data, caseInsensitive))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -99,12 +96,12 @@ Pattern::Sniff(Range range, BPositionIO *data) const {
|
|||||||
// Assumes the BPositionIO object is in the correct
|
// Assumes the BPositionIO object is in the correct
|
||||||
// position from which to sniff
|
// position from which to sniff
|
||||||
bool
|
bool
|
||||||
Pattern::Sniff(off_t start, off_t size, BPositionIO *data) const {
|
Pattern::Sniff(off_t start, off_t size, BPositionIO *data, bool caseInsensitive) const {
|
||||||
off_t len = fString.length();
|
off_t len = fString.length();
|
||||||
char *buffer = new(nothrow) char[len+1];
|
char *buffer = new(nothrow) char[len+1];
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
ssize_t bytesRead = data->ReadAt(start, buffer, len);
|
ssize_t bytesRead = data->ReadAt(start, buffer, len);
|
||||||
// /todo If there are fewer bytes left in the data stream
|
// \todo If there are fewer bytes left in the data stream
|
||||||
// from the given position than the length of our data
|
// from the given position than the length of our data
|
||||||
// string, should we just return false (which is what we're
|
// string, should we just return false (which is what we're
|
||||||
// doing now), or should we compare as many bytes as we
|
// doing now), or should we compare as many bytes as we
|
||||||
@@ -113,10 +110,28 @@ Pattern::Sniff(off_t start, off_t size, BPositionIO *data) const {
|
|||||||
return false;
|
return false;
|
||||||
else {
|
else {
|
||||||
bool result = true;
|
bool result = true;
|
||||||
for (int i = 0; i < len; i++) {
|
if (caseInsensitive) {
|
||||||
if ((fString[i] & fMask[i]) != (buffer[i] & fMask[i])) {
|
for (int i = 0; i < len; i++) {
|
||||||
result = false;
|
char secondChar;
|
||||||
break;
|
if ('A' <= fString[i] && fString[i] <= 'Z')
|
||||||
|
secondChar = 'a' + (fString[i] - 'A'); // Also check lowercase
|
||||||
|
else if ('a' <= fString[i] && fString[i] <= 'z')
|
||||||
|
secondChar = 'A' + (fString[i] - 'a'); // Also check uppercase
|
||||||
|
else
|
||||||
|
secondChar = fString[i]; // Check the same char twice as punishment for doing a case insensitive search ;-)
|
||||||
|
if (((fString[i] & fMask[i]) != (buffer[i] & fMask[i]))
|
||||||
|
&& ((secondChar & fMask[i]) != (buffer[i] & fMask[i])))
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if ((fString[i] & fMask[i]) != (buffer[i] & fMask[i])) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -16,7 +16,8 @@
|
|||||||
using namespace Sniffer;
|
using namespace Sniffer;
|
||||||
|
|
||||||
PatternList::PatternList(Range range)
|
PatternList::PatternList(Range range)
|
||||||
: fRange(range)
|
: DisjList()
|
||||||
|
, fRange(range)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ PatternList::Sniff(BPositionIO *data) const {
|
|||||||
std::vector<Pattern*>::const_iterator i;
|
std::vector<Pattern*>::const_iterator i;
|
||||||
for (i = fList.begin(); i != fList.end(); i++) {
|
for (i = fList.begin(); i != fList.end(); i++) {
|
||||||
if (*i)
|
if (*i)
|
||||||
result |= (*i)->Sniff(fRange, data);
|
result |= (*i)->Sniff(fRange, data, fCaseInsensitive);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ RPattern::~RPattern() {
|
|||||||
|
|
||||||
//! Sniffs the given data stream over the object's range for the object's pattern
|
//! Sniffs the given data stream over the object's range for the object's pattern
|
||||||
bool
|
bool
|
||||||
RPattern::Sniff(BPositionIO *data) const {
|
RPattern::Sniff(BPositionIO *data, bool caseInsensitive) const {
|
||||||
if (!data || InitCheck() != B_OK)
|
if (!data || InitCheck() != B_OK)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return fPattern->Sniff(fRange, data);
|
return fPattern->Sniff(fRange, data, caseInsensitive);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
using namespace Sniffer;
|
using namespace Sniffer;
|
||||||
|
|
||||||
RPatternList::RPatternList()
|
RPatternList::RPatternList()
|
||||||
|
: DisjList()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ RPatternList::Sniff(BPositionIO *data) const {
|
|||||||
std::vector<RPattern*>::const_iterator i;
|
std::vector<RPattern*>::const_iterator i;
|
||||||
for (i = fList.begin(); i != fList.end(); i++) {
|
for (i = fList.begin(); i != fList.end(); i++) {
|
||||||
if (*i)
|
if (*i)
|
||||||
result |= (*i)->Sniff(data);
|
result |= (*i)->Sniff(data, fCaseInsensitive);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sniffer/Err.h>
|
#include <sniffer/Err.h>
|
||||||
#include <sniffer/Expr.h>
|
#include <sniffer/DisjList.h>
|
||||||
#include <sniffer/Rule.h>
|
#include <sniffer/Rule.h>
|
||||||
#include <DataIO.h>
|
#include <DataIO.h>
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ using namespace Sniffer;
|
|||||||
|
|
||||||
Rule::Rule()
|
Rule::Rule()
|
||||||
: fPriority(0.0)
|
: fPriority(0.0)
|
||||||
, fExprList(NULL)
|
, fConjList(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ Rule::~Rule() {
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
Rule::InitCheck() const {
|
Rule::InitCheck() const {
|
||||||
return fExprList ? B_OK : B_NO_INIT;
|
return fConjList ? B_OK : B_NO_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the priority of the rule. 0.0 <= priority <= 1.0.
|
//! Returns the priority of the rule. 0.0 <= priority <= 1.0.
|
||||||
@@ -42,8 +42,8 @@ Rule::Sniff(BPositionIO *data) const {
|
|||||||
return false;
|
return false;
|
||||||
else {
|
else {
|
||||||
bool result = true;
|
bool result = true;
|
||||||
std::vector<Expr*>::const_iterator i;
|
std::vector<DisjList*>::const_iterator i;
|
||||||
for (i = fExprList->begin(); i != fExprList->end(); i++) {
|
for (i = fConjList->begin(); i != fConjList->end(); i++) {
|
||||||
if (*i)
|
if (*i)
|
||||||
result &= (*i)->Sniff(data);
|
result &= (*i)->Sniff(data);
|
||||||
}
|
}
|
||||||
@@ -53,21 +53,21 @@ Rule::Sniff(BPositionIO *data) const {
|
|||||||
|
|
||||||
void
|
void
|
||||||
Rule::Unset() {
|
Rule::Unset() {
|
||||||
if (fExprList){
|
if (fConjList){
|
||||||
delete fExprList;
|
delete fConjList;
|
||||||
fExprList = NULL;
|
fConjList = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Called by Parser::Parse() after successfully parsing a sniffer rule.
|
//! Called by Parser::Parse() after successfully parsing a sniffer rule.
|
||||||
void
|
void
|
||||||
Rule::SetTo(double priority, std::vector<Expr*>* list) {
|
Rule::SetTo(double priority, std::vector<DisjList*>* list) {
|
||||||
Unset();
|
Unset();
|
||||||
if (0.0 <= priority && priority <= 1.0)
|
if (0.0 <= priority && priority <= 1.0)
|
||||||
fPriority = priority;
|
fPriority = priority;
|
||||||
else
|
else
|
||||||
throw new Err("Sniffer pattern error: invalid priority", -1);
|
throw new Err("Sniffer pattern error: invalid priority", -1);
|
||||||
fExprList = list;
|
fConjList = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user