MIME Sniffer: Use memmem() to speed up matching.

This is now a POSIX method which was widely supported even before
its addition to POSIX, so using it here (including on the build
platform) should be OK.

This takes mimeset -F of the whole src/ hierarchy from around 2.8
seconds to around 2.1 (user time goes from ~1.2s to ~0.6s.) It seems
I/O is a lot of the remainder now.

Also drop the TODO comment; we don't want partial matching like that,
as the sniffing rules would not expect it.

All tests still pass.

Change-Id: Ibb190f6f9f5e73ed027e052ef665b177d3fd6f86
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10688
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Augustin Cavalier
2026-04-10 08:28:40 +00:00
committed by Adrien Destugues
parent 14ea42a871
commit 64d96af568
2 changed files with 26 additions and 19 deletions
+25 -18
View File
@@ -129,12 +129,17 @@ Pattern::GetErr() const
bool
Pattern::Sniff(Range range, const Data& data) const
{
int32 start = range.Start();
int32 end = range.End();
if ((size_t)end >= data.length)
end = data.length - 1; // Don't bother searching beyond the end of the stream
for (int i = start; i <= end; i++) {
if (Sniff(i, data))
int32 firstStart = range.Start();
int32 lastStart = range.End();
int32 searchEnd = lastStart + fStringLength;
if ((size_t)searchEnd > data.length) {
// Don't search beyond the end of the stream
searchEnd = data.length;
lastStart = searchEnd - fStringLength;
}
for (off_t start = firstStart; start <= lastStart; start++) {
if (_SniffNext(start, searchEnd, data))
return true;
}
return false;
@@ -155,28 +160,30 @@ Pattern::BytesNeeded() const
bool
Pattern::Sniff(off_t start, const Data& data) const
Pattern::_SniffNext(off_t& start, off_t end, const Data& data) const
{
int32 len = fStringLength;
// \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 ((data.length - start) < (size_t)len)
return false;
const uint8* string = fData;
const uint8* buffer = data.buffer + start;
// Compare the "unmasked" portion of the pattern.
// Try to find a start point using the "unmasked" portion of the pattern.
if (fUnmaskedStartLength != 0) {
if (memcmp(string, buffer, fUnmaskedStartLength) != 0)
void* strStart = memmem(buffer, end - start, string, fUnmaskedStartLength);
if (strStart == NULL) {
start = end;
return false;
}
if (fUnmaskedStartLength == fStringLength)
return true;
buffer = (uint8*)strStart;
start = buffer - data.buffer;
}
// See if the buffer is still long enough for a match.
int32 len = fStringLength;
if ((data.length - start) < (size_t)len)
return false;
// Compare the remainder.
string += fUnmaskedStartLength;
buffer += fUnmaskedStartLength;
+1 -1
View File
@@ -50,7 +50,7 @@ protected:
Pattern(bool caseInsensitive, const std::string& string, std::string mask);
private:
bool Sniff(off_t start, const Data& data) const;
bool _SniffNext(off_t& start, off_t end, const Data& data) const;
void SetStatus(status_t status, const char *msg = NULL);
void SetErrorMessage(const char *msg);