diff --git a/headers/private/storage/sniffer/DisjList.h b/headers/private/storage/sniffer/DisjList.h index f4bdd1e1ac..8f1841fa6f 100644 --- a/headers/private/storage/sniffer/DisjList.h +++ b/headers/private/storage/sniffer/DisjList.h @@ -9,6 +9,8 @@ #ifndef _SNIFFER_DISJ_LIST_H #define _SNIFFER_DISJ_LIST_H +#include + class BPositionIO; namespace BPrivate { @@ -20,7 +22,9 @@ class DisjList { public: DisjList(); virtual ~DisjList(); + virtual bool Sniff(BPositionIO *data) const = 0; + virtual ssize_t BytesNeeded() const = 0; void SetCaseInsensitive(bool how); bool IsCaseInsensitive(); diff --git a/headers/private/storage/sniffer/Pattern.h b/headers/private/storage/sniffer/Pattern.h index 97be4a4ce2..595ffb9c61 100644 --- a/headers/private/storage/sniffer/Pattern.h +++ b/headers/private/storage/sniffer/Pattern.h @@ -33,6 +33,7 @@ public: Err* GetErr() const; bool Sniff(Range range, BPositionIO *data, bool caseInsensitive) const; + ssize_t BytesNeeded() const; status_t SetTo(const std::string &string, const std::string &mask); private: diff --git a/headers/private/storage/sniffer/PatternList.h b/headers/private/storage/sniffer/PatternList.h index fef4efa7eb..faa6683e8b 100644 --- a/headers/private/storage/sniffer/PatternList.h +++ b/headers/private/storage/sniffer/PatternList.h @@ -34,6 +34,8 @@ public: Err* GetErr() const; virtual bool Sniff(BPositionIO *data) const; + virtual ssize_t BytesNeeded() const; + void Add(Pattern *pattern); private: std::vector fList; diff --git a/headers/private/storage/sniffer/RPattern.h b/headers/private/storage/sniffer/RPattern.h index 807430b1f3..13f7b171f6 100644 --- a/headers/private/storage/sniffer/RPattern.h +++ b/headers/private/storage/sniffer/RPattern.h @@ -30,6 +30,7 @@ public: Err* GetErr() const; bool Sniff(BPositionIO *data, bool caseInsensitive) const; + ssize_t BytesNeeded() const; private: Range fRange; Pattern *fPattern; diff --git a/headers/private/storage/sniffer/RPatternList.h b/headers/private/storage/sniffer/RPatternList.h index c828968b21..0ac67b9de8 100644 --- a/headers/private/storage/sniffer/RPatternList.h +++ b/headers/private/storage/sniffer/RPatternList.h @@ -31,6 +31,7 @@ public: Err* GetErr() const; virtual bool Sniff(BPositionIO *data) const; + virtual ssize_t BytesNeeded() const; void Add(RPattern *rpattern); private: std::vector fList; diff --git a/headers/private/storage/sniffer/Rule.h b/headers/private/storage/sniffer/Rule.h index adf08e51ff..b90fc7fc91 100644 --- a/headers/private/storage/sniffer/Rule.h +++ b/headers/private/storage/sniffer/Rule.h @@ -10,6 +10,8 @@ #define _SNIFFER_RULE_H #include + +#include #include class BPositionIO; @@ -28,10 +30,10 @@ public: Rule(); ~Rule(); - status_t InitCheck() const; - + status_t InitCheck() const; double Priority() const; bool Sniff(BPositionIO *data) const; + ssize_t BytesNeeded() const; private: friend class Parser; diff --git a/src/kits/storage/sniffer/Pattern.cpp b/src/kits/storage/sniffer/Pattern.cpp index bfb55005f4..f570152f6c 100644 --- a/src/kits/storage/sniffer/Pattern.cpp +++ b/src/kits/storage/sniffer/Pattern.cpp @@ -94,8 +94,21 @@ Pattern::Sniff(Range range, BPositionIO *data, bool caseInsensitive) const { return false; } -// Assumes the BPositionIO object is in the correct -// position from which to sniff +// BytesNeeded +/*! \brief Returns the number of bytes needed to perform a complete sniff, or an error + code if something goes wrong. +*/ +ssize_t +Pattern::BytesNeeded() const +{ + ssize_t result = InitCheck(); + if (result == B_OK) + result = fString.length(); + return result; +} + +//#define OPTIMIZATION_IS_FOR_CHUMPS +#if OPTIMIZATION_IS_FOR_CHUMPS bool Pattern::Sniff(off_t start, off_t size, BPositionIO *data, bool caseInsensitive) const { off_t len = fString.length(); @@ -140,6 +153,52 @@ Pattern::Sniff(off_t start, off_t size, BPositionIO *data, bool caseInsensitive) } else return false; } +#else +bool +Pattern::Sniff(off_t start, off_t size, BPositionIO *data, bool caseInsensitive) const { + off_t len = fString.length(); + char *buffer = new(nothrow) char[len+1]; + if (buffer) { + ssize_t bytesRead = data->ReadAt(start, buffer, len); + // \todo If there are fewer bytes left in the data stream + // from the given position than the length of our data + // string, should we just return false (which is what we're + // doing now), or should we compare as many bytes as we + // can and return true if those match? + if (bytesRead < len) + return false; + else { + bool result = true; + if (caseInsensitive) { + for (int i = 0; i < len; i++) { + char secondChar; + 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; + } + } else + return false; +} +#endif void Pattern::SetStatus(status_t status, const char *msg) { diff --git a/src/kits/storage/sniffer/PatternList.cpp b/src/kits/storage/sniffer/PatternList.cpp index 8aebf5ad01..b3f066a469 100644 --- a/src/kits/storage/sniffer/PatternList.cpp +++ b/src/kits/storage/sniffer/PatternList.cpp @@ -56,6 +56,41 @@ PatternList::Sniff(BPositionIO *data) const { } } +/*! \brief Returns the number of bytes needed to perform a complete sniff, or an error + code if something goes wrong. +*/ +ssize_t +PatternList::BytesNeeded() const +{ + ssize_t result = InitCheck(); + + // Find the number of bytes needed to sniff any of our + // patterns from a single location in a data stream + if (result == B_OK) { + result = 0; // I realize it already *is* zero if it == B_OK, but just in case that changes... + std::vector::const_iterator i; + for (i = fList.begin(); i != fList.end(); i++) { + if (*i) { + ssize_t bytes = (*i)->BytesNeeded(); + if (bytes >= 0) { + if (bytes > result) + result = bytes; + } else { + result = bytes; + break; + } + } + } + } + + // Now add on the number of bytes needed to get to the + // furthest allowed starting point + if (result >= 0) + result += fRange.End(); + + return result; +} + void PatternList::Add(Pattern *pattern) { if (pattern) diff --git a/src/kits/storage/sniffer/RPattern.cpp b/src/kits/storage/sniffer/RPattern.cpp index 95a8c449de..02678823d7 100644 --- a/src/kits/storage/sniffer/RPattern.cpp +++ b/src/kits/storage/sniffer/RPattern.cpp @@ -23,15 +23,12 @@ RPattern::RPattern(Range range, Pattern *pattern) status_t RPattern::InitCheck() const { - if (fRange.InitCheck() != B_OK) - return fRange.InitCheck(); - else if (fPattern) { - if (fPattern->InitCheck() != B_OK) - return fPattern->InitCheck(); - else - return B_OK; - } else - return B_BAD_VALUE; + status_t err = fRange.InitCheck(); + if (!err) + err = fPattern ? B_OK : B_BAD_VALUE; + if (!err) + err = fPattern->InitCheck(); + return err; } Err* @@ -60,5 +57,18 @@ RPattern::Sniff(BPositionIO *data, bool caseInsensitive) const { return fPattern->Sniff(fRange, data, caseInsensitive); } +/*! \brief Returns the number of bytes needed to perform a complete sniff, or an error + code if something goes wrong. +*/ +ssize_t +RPattern::BytesNeeded() const +{ + ssize_t result = InitCheck(); + if (result == B_OK) + result = fPattern->BytesNeeded(); + if (result >= 0) + result += fRange.End(); + return result; +} diff --git a/src/kits/storage/sniffer/RPatternList.cpp b/src/kits/storage/sniffer/RPatternList.cpp index 00d3329413..38a86dbfbf 100644 --- a/src/kits/storage/sniffer/RPatternList.cpp +++ b/src/kits/storage/sniffer/RPatternList.cpp @@ -55,6 +55,34 @@ RPatternList::Sniff(BPositionIO *data) const { return result; } } + +/*! \brief Returns the number of bytes needed to perform a complete sniff, or an error + code if something goes wrong. +*/ +ssize_t +RPatternList::BytesNeeded() const +{ + ssize_t result = InitCheck(); + + // Tally up the BytesNeeded() values for all the RPatterns and return the largest. + if (result == B_OK) { + result = 0; // Just to be safe... + std::vector::const_iterator i; + for (i = fList.begin(); i != fList.end(); i++) { + if (*i) { + ssize_t bytes = (*i)->BytesNeeded(); + if (bytes >= 0) { + if (bytes > result) + result = bytes; + } else { + result = bytes; + break; + } + } + } + } + return result; +} void RPatternList::Add(RPattern *rpattern) { diff --git a/src/kits/storage/sniffer/Rule.cpp b/src/kits/storage/sniffer/Rule.cpp index 81f265d6a8..6b0dd4ef0a 100644 --- a/src/kits/storage/sniffer/Rule.cpp +++ b/src/kits/storage/sniffer/Rule.cpp @@ -11,9 +11,13 @@ #include #include #include +#include using namespace BPrivate::Storage::Sniffer; +/*! \brief Creates an unitialized Sniffer::Rule object. To initialize it, you + must pass a pointer to the object to Sniffer::parse(). +*/ Rule::Rule() : fPriority(0.0) , fConjList(NULL) @@ -51,6 +55,35 @@ Rule::Sniff(BPositionIO *data) const { } } +/*! \brief Returns the number of bytes needed for this rule to perform a complete sniff, + or an error code if something goes wrong. +*/ +ssize_t +Rule::BytesNeeded() const +{ + ssize_t result = InitCheck(); + + // Tally up the BytesNeeded() values for all the DisjLists and return the largest. + if (result == B_OK) { + result = 0; // Just to be safe... + std::vector::const_iterator i; + for (i = fConjList->begin(); i != fConjList->end(); i++) { + if (*i) { + ssize_t bytes = (*i)->BytesNeeded(); + if (bytes >= 0) { + if (bytes > result) + result = bytes; + } else { + result = bytes; + break; + } + } + } + } + return result; +} + + void Rule::Unset() { if (fConjList){