#include <new>
#include "Err.h"
#include "Pattern.h"
#include "Data.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;
}
bool
Pattern::Sniff(Range range, const Data& data, bool caseInsensitive) const
{
int32 start = range.Start();
int32 end = range.End();
if ((size_t)end >= data.length)
end = data.length - 1;
for (int i = start; i <= end; i++) {
if (Sniff(i, data, caseInsensitive))
return true;
}
return false;
}
ssize_t
Pattern::BytesNeeded() const
{
ssize_t result = InitCheck();
if (result == B_OK)
result = fString.length();
return result;
}
bool
Pattern::Sniff(off_t start, const Data& data, bool caseInsensitive) const
{
off_t len = fString.length();
if ((data.length - start) < (size_t)len)
return false;
const uint8* string = (const uint8*)fString.data();
const uint8* mask = (const uint8*)fMask.data();
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 (((string[i] & mask[i]) != (data.buffer[start + i] & mask[i]))
&& ((secondChar & mask[i]) != (data.buffer[start + i] & mask[i]))) {
result = false;
break;
}
}
} else {
for (int i = 0; i < len; i++) {
if ((string[i] & mask[i]) != (data.buffer[start + i] & mask[i])) {
result = false;
break;
}
}
}
return result;
}
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);
}