Skip to content

Make magic-byte detection allow a variable-size gap. - #2580

Open
lrhn wants to merge 1 commit into
mainfrom
magic-bytes
Open

lrhn wants to merge 1 commit into
mainfrom
magic-bytes

Conversation

@lrhn

@lrhn lrhn commented Sep 1, 2026

Copy link
Copy Markdown
Member

A byte above 0xFF in the numbers list makes the matching try to continue at each of the next byte-0xFF positions. (It searches efficiently for the following byte, then recursively checks the rest of the pattern if finding that byte.)

Add magic-byte recognition for video/webv and video/x-matroska, using this format, and remove the match for audio/weba (which is an extension for audio/webm, which isn't disitinguishable from video/webm without checking whether it contains any non-audio streams.)

A byte above 0xFF in the numbers list makes the matching
try to continue at each of the next `byte-0xFF` positions.
(It searches efficiently for the following byte, then recursively
checks the rest of the pattern if finding that byte.)

Add magic-byte recognition for `video/webv` and `video/x-matroska`,
using this format, and remove the match for `audio/weba` (which is
an extension for `audio/webm`, which isn't disitinguishable from
`video/webm` without checking whether it contains any non-audio
streams.)
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Package publishing

If you have publishing permissions, you can use the links below to publish the changes after merging this PR.

Package Version Status Publish tag (post-merge)
package:mime 2.1.0 already published at pub.dev
package:test_reflective_loader 0.6.0 ready to publish test_reflective_loader-v0.6.0
  • 23 already published.
  • 17 WIP (no publish necessary).

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

PR Health

Unused Dependencies ✔️
Package Status
mime ✔️ All dependencies utilized correctly.

For details on how to fix these, see dependency_validator.

This check can be disabled by tagging the PR with skip-unused-dependencies-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
mime None 2.1.0 2.1.0 2.1.0 ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check.

License Headers ✔️
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/html/test/differential_test.dart
pkgs/html/test/dom_parsing_test.dart
pkgs/html/test/mxss_test.dart
pkgs/html/test/noah_ark_clause_limit_test.dart

This check can be disabled by tagging the PR with skip-license-check.

Coverage ⚠️
File Coverage
pkgs/mime/lib/src/magic_number.dart 💔 94 % ⬇️ 6 %
pkgs/mime/lib/src/mime_type.dart 💚 91 % ⬆️ 1 %

This check for test coverage is informational (issues shown here will not fail the PR).

This check can be disabled by tagging the PR with skip-coverage-check.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for magic byte patterns with variable-width gaps (wildcards) in MagicNumber matching, allowing the library to distinguish between video/webm and video/x-matroska files. Feedback on these changes highlights a contradiction in the wildcard mask validation logic, recommends using isNotEmpty instead of checking length > 0 per Effective Dart guidelines, suggests adding explicit parentheses around bitwise operations to improve readability, and corrects several instances of the typo 'EBMF' to 'EBML'.

Comment on lines +42 to +43
// Make sure masks has same value at that position.
if (masks != null && mask != number) return false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The check if (masks != null && mask != number) return false; requires that the masks string contains the exact same wildcard character (which is > 0xFF) at the wildcard's position.

However, this directly contradicts the documentation for masks on line 17:
/// Optional string containing code points in the 0..255 range to mask with.

Since the wildcard character is not a byte to be matched (it only specifies a lookahead length), there is no functional need to enforce that the mask matches the wildcard character. Enforcing this requires users to put non-byte values (values > 255) into the masks string, which is counter-intuitive and violates the documented contract.

We should remove this check entirely since the mask at a wildcard position is never used for matching anyway.


const MagicNumber(this.mimeType, this.numbers, [this.masks]);
const MagicNumber(this.mimeType, this.numbers, [this.masks])
: assert(numbers.length > 0),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to Effective Dart (referenced in the repository style guide), we should prefer using isNotEmpty instead of checking length > 0 for strings and collections.

Suggested change
: assert(numbers.length > 0),
: assert(numbers.isNotEmpty),
References
  1. Prefer using .isEmpty and .isNotEmpty to check for empty collections/strings. (link)

var number = numbers.codeUnitAt(patternCursor);
if (masks != null) mask = masks.codeUnitAt(patternCursor);
if (number <= 0xFF) {
if ((number ^ header[byteCursor]) & mask != 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve readability and prevent potential operator precedence confusion (especially for developers coming from languages like C/C++ or Java where equality has higher precedence than bitwise operators), please add explicit parentheses around the bitwise operations.

Suggested change
if ((number ^ header[byteCursor]) & mask != 0) {
if (((number ^ header[byteCursor]) & mask) != 0) {

}
for (var i = 0; i < lookaheadLength; i++) {
// Quick scan for first byte to match, before recursing.
if ((number ^ header[byteCursor + i]) & mask == 0 &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve readability and prevent potential operator precedence confusion (especially for developers coming from languages like C/C++ or Java where equality has higher precedence than bitwise operators), please add explicit parentheses around the bitwise operations.

Suggested change
if ((number ^ header[byteCursor + i]) & mask == 0 &&
if (((number ^ header[byteCursor + i]) & mask) == 0 &&

'\x00\x00\x00\x00\x66\x74\x79\x70\x6D\x70\x34\x32',
'\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF',
),
// Look for EBMF DocType header within the next 64 bytes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo: "EBMF" should be "EBML" (Extensible Binary Meta Language).

Suggested change
// Look for EBMF DocType header within the next 64 bytes.
// Look for EBML DocType header within the next 64 bytes.

Comment thread pkgs/mime/CHANGELOG.md
The pattern entry limits how far ahead it can look.

* Recognize `video/webm` and `video/x-matroska` by magic numbers,
and no longer detects all EBMF files as `audio/weba`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo: "EBMF" should be "EBML" (Extensible Binary Meta Language).

Suggested change
and no longer detects all EBMF files as `audio/weba`.
and no longer detects all EBML files as `audio/weba`.

0x00
]);
_expectMimeType('file', 'video/webm', headerBytes: [
0x1A, 0x45, 0xDF, 0xA3, // EBMF header

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo: "EBMF" should be "EBML" (Extensible Binary Meta Language).

Suggested change
0x1A, 0x45, 0xDF, 0xA3, // EBMF header
0x1A, 0x45, 0xDF, 0xA3, // EBML header

0x42, // Anything
]);
_expectMimeType('file', 'video/x-matroska', headerBytes: [
0x1A, 0x45, 0xDF, 0xA3, // EBMF header

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo: "EBMF" should be "EBML" (Extensible Binary Meta Language).

Suggested change
0x1A, 0x45, 0xDF, 0xA3, // EBMF header
0x1A, 0x45, 0xDF, 0xA3, // EBML header

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant