\file Pattern.cpp
MIME sniffer pattern implementation
*/
#include <sniffer/Err.h>
#include <sniffer/Pattern.h>
#include <DataIO.h>
#include <stdio.h>
#include <new>
#include <AutoDeleter.h>
using namespace BPrivate::Storage::Sniffer;
Pattern::Pattern(const std::string &string, const std::string &mask)
: fCStatus(B_NO_INIT)
, fErrorMessage(NULL)
{
SetTo(string, mask);
}
Pattern::Pattern(const std::string &string)
: fCStatus(B_NO_INIT)
, fErrorMessage(NULL)
{
std::string mask = "";
for (uint i = 0; i < string.length(); i++)
mask += (char)0xFF;
SetTo(string, mask);
}
Pattern::~Pattern() {
delete fErrorMessage;
}
status_t
Pattern::InitCheck() const {
return fCStatus;
}
Err*
Pattern::GetErr() const {
if (fCStatus == B_OK)
return NULL;
else
return new(std::nothrow) Err(*fErrorMessage);
}
void dumpStr(const std::string &string, const char *label = NULL) {
if (label)
printf("%s: ", label);
for (uint i = 0; i < string.length(); i++)
printf("%x ", string[i]);
printf("\n");
}
status_t
Pattern::SetTo(const std::string &string, const std::string &mask) {
fString = string;
if (fString.length() == 0) {
SetStatus(B_BAD_VALUE, "Sniffer pattern error: illegal empty pattern");
} else {
fMask = mask;
if (fString.length() != fMask.length()) {
SetStatus(B_BAD_VALUE, "Sniffer pattern error: pattern and mask lengths do not match");
} else {
SetStatus(B_OK);
}
}
return fCStatus;
}
each offset withing the given range. Returns true is a match is found,
false if not.
*/
bool
Pattern::Sniff(Range range, BPositionIO *data, bool caseInsensitive) const {
int32 start = range.Start();
int32 end = range.End();
off_t size = data->Seek(0, SEEK_END);
if (end >= size)
end = size-1;
for (int i = start; i <= end; i++) {
if (Sniff(i, size, data, caseInsensitive))
return true;
}
return false;
}
code if something goes wrong.
*/
ssize_t
Pattern::BytesNeeded() const
{
ssize_t result = InitCheck();
if (result == B_OK)
result = fString.length();
return result;
}
#if OPTIMIZATION_IS_FOR_CHUMPS
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) {
ArrayDeleter<char> _(buffer);
ssize_t bytesRead = data->ReadAt(start, buffer, len);
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');
else if ('a' <= fString[i] && fString[i] <= 'z')
secondChar = 'A' + (fString[i] - 'a');
else
secondChar = fString[i];
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;
}
#else
bool
Pattern::Sniff(off_t start, off_t size, BPositionIO *data, bool caseInsensitive) const {
off_t len = fString.length();
char *buffer = new(std::nothrow) char[len+1];
if (buffer) {
ArrayDeleter<char> _(buffer);
ssize_t bytesRead = data->ReadAt(start, buffer, len);
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');
else if ('a' <= fString[i] && fString[i] <= 'z')
secondChar = 'A' + (fString[i] - 'a');
else
secondChar = fString[i];
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) {
fCStatus = status;
if (status == B_OK)
SetErrorMessage(NULL);
else {
if (msg)
SetErrorMessage(msg);
else {
SetErrorMessage("Sniffer parser error: Pattern::SetStatus() -- NULL msg with non-B_OK status.\n"
"(This is officially the most helpful error message you will ever receive ;-)");
}
}
}
void
Pattern::SetErrorMessage(const char *msg) {
delete fErrorMessage;
fErrorMessage = (msg) ? (new(std::nothrow) Err(msg, -1)) : (NULL);
}