This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new e2fd85f94a TIKA-5029 (#3533)
e2fd85f94a is described below

commit e2fd85f94a01b22d3e45bb078ee6a502e9f3aaed
Author: Tim Allison <[email protected]>
AuthorDate: Fri Nov 6 13:18:48 2026 -0500

    TIKA-5029 (#3533)
    
    * TIKA-5029: fail the mime-types load on a duplicate definition; merge 
tika-mimetypes.xml duplicates
    * TIKA-5029: detect WOFF, SquashFS, ASE, PalmDOC and binary OpenPGP 
signatures by content
    * TIKA-5029: detect FEC filings, gettext catalogs, Garmin GDB, MPQ/Warcraft 
III, VCDIFF, Xdelta and PSP by content
    * TIKA-5029: detect HTML that opens with a fragment, and ASX without an XML 
declaration
    
    * TIKA-5029: fail the build on mime-type rules that can never match; fix 
SubRip CRLF
    * TIKA-5029: detect Elasto Mania, PGP keys, StuffIt, MPEG-TS, Symbian 9, 
FLC/FLI, MS Reader, lrzip, Glulx, S3M and APE
    
    * TIKA-5029: detect niche formats and DER CRLs, certificates and time-stamp 
replies by content
    * TIKA-5029: detect glTF, Blender, FBX, Jw_cad, FastCAD, Source maps, 
Unreal UZ, SoundFont, zsync and WFDB by content
    * TIKA-5029: detect printer jobs, MO:DCA, Windows dumps, StarView metafiles 
and four crawl clusters by content
    * TIKA-5029: detect gcov, Python bytecode and pickles, Lucene indexes, git 
packs, ACPI tables, TZif, mozLz4 and JPEG XR by content
    * TIKA-5029: let a .xml name pick xml over the html-fragment magic
    * TIKA-5029: detect Python 3.14+ bytecode and Blender 5 files; use 
established MIME names; drop shared globs
    * TIKA-5029: detect new-format OpenPGP packets, v1 CRLs, gettext revision 1 
and SDCH VCDIFF; cite evidence for crawl-derived rules
    * TIKA-5029: tighten Python 3 bytecode magic; gate new regex rules behind 
literal prefixes
    * TIKA-5029: choose the PJL job's language by literal ENTER LANGUAGE 
matches over 8K instead of a 1K regex
    * TIKA-5029: more from recent cc detect NEXRAD Level III, UCSC 
bigBed/bigWig/2bit, BAM/BAI, OSM PBF, LIGO frames, qcow, ImageDisk, MAME CHD, 
devicetree/FIT, U-Boot, UBI, Amiga hunk executables, DDS, YM, VST presets and 
older Jw_cad
    
    ---------
    
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 CHANGES.txt                                        |   80 ++
 .../java/org/apache/tika/mime/MimeTypesReader.java |   14 +
 .../org/apache/tika/mime/tika-mimetypes.xml        | 1085 ++++++++++++++++++--
 .../org/apache/tika/mime/MimeDetectionTest.java    |  210 ++++
 .../org/apache/tika/mime/MimeTypesLintTest.java    |  167 +++
 .../org/apache/tika/mime/MimeTypesReaderTest.java  |   35 +
 .../apache/tika/mime/NicheFormatDetectionTest.java |  364 +++++++
 .../org/apache/tika/parser/ParsingReaderTest.java  |    2 +-
 .../tika-parser-cad-module/pom.xml                 |    9 +
 9 files changed, 1897 insertions(+), 69 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 70246f11e1..866d6b1430 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -22,6 +22,14 @@ Release 4.3.0 - ???
      the forks never saw such a fetcher, so every fetch through it failed. Use 
file or
      ignite (TIKA-5001).
 
+   * A mime-types XML file that defines the same type twice, directly or 
through an
+     alias, fails to load with "Duplicate definition of ..."; the second 
definition's
+     magic and globs were silently added to the first, so tightening a rule in 
one copy
+     had no effect. A custom-mimetypes.xml that repeats a type within itself 
now stops
+     Tika from loading its types; merge the repeated blocks into one. A custom 
file may
+     still add globs or magic to a type defined in tika-mimetypes.xml. The 
eleven
+     duplicates in tika-mimetypes.xml are merged; detection is unchanged 
(TIKA-5029).
+
    * 3MF packages are detected as model/3mf, their IANA type, instead of
      application/vnd.ms-package.3dmanufacturing-3dmodel+xml, which is the 
content type of
      the model part inside the package. The old name is an alias, so it still 
resolves as
@@ -81,6 +89,78 @@ Release 4.3.0 - ???
 
   EXTRACTION AND FORMATS
 
+   * WOFF and WOFF2 fonts (font/woff, font/woff2), SquashFS images
+     (application/vnd.squashfs), Adobe Swatch Exchange files, PalmDOC e-books 
and binary
+     OpenPGP signatures (application/pgp-signature) are detected by content; 
they were
+     application/octet-stream. Together they are about a sixth of the Common 
Crawl files
+     Tika could not identify. MXF and Java serialization streams are detected 
by content
+     too (they had globs only), EOT fonts of version 0x00010000 and 0x00020001 
are
+     detected (only 0x00020002 was), and torrent files whose first key is not 
"announce"
+     are detected (TIKA-5029).
+
+   * US FEC electronic filings (application/x-fec, a kind of text/plain, so 
their text is
+     extracted), gettext message catalogs, Garmin MapSource databases, 
Blizzard MPQ
+     archives and Warcraft III maps and replays, VCDIFF and Xdelta patches and 
Paint Shop
+     Pro images are detected by content; they were application/octet-stream. 
SID tunes
+     in RSID format are detected, and PSID needs a valid version after the 
magic
+     (TIKA-5029).
+
+   * HTML that opens with a fragment instead of <html> (a <meta>, <script>, 
<p>, <br>,
+     <table> or similar tag, as in pages that start with PHP warnings) is 
detected as
+     text/html, and Windows Media playlists without an XML declaration are 
detected as
+     application/x-ms-asx; they were application/octet-stream or text/plain. A 
PDF or
+     XHTML document with such a fragment in front keeps its type (TIKA-5029).
+
+   * A new test fails the build on tika-mimetypes.xml rules that load but can 
never
+     match as written (TIKA-5029).
+
+   * Elasto Mania levels, binary OpenPGP keys, StuffIt (SIT!) archives, MPEG 
transport
+     streams (video/mp2t, now also *.m2ts and *.m2t), Symbian 9 installers, 
FLC and FLI
+     animations, Microsoft Reader e-books, lrzip archives, Glulx games, Scream 
Tracker 3
+     modules and Monkey's Audio files are detected by content, and so are MARC 
records
+     with a blank bibliographic level; they were application/octet-stream 
(TIKA-5029).
+
+   * NoteWorthy Composer songs, Finale (Enigma binary) scores, ReCycle REX2 
loops, i-mode
+     MFi melodies, TrackMania/ManiaPlanet GameBox files, PlayStation 3 
packages and themes,
+     Trainz content packages, ZX Spectrum RZX recordings, Quake and Half-Life 
sprites,
+     NuFX (ShrinkIt) and Amiga LZX archives, MikroTik RouterOS packages and 
ClamAV
+     signature databases and updates, and Casio FX-Interface files are 
detected by
+     content; they were application/octet-stream (TIKA-5029).
+
+   * DER certificate revocation lists (application/pkix-crl), DER X.509 
certificates
+     signed with any algorithm (only some RSA, DSA and ECDSA ones were 
matched, so SM2
+     and Ed25519 certificates were missed) and RFC 3161 time-stamp replies are 
detected
+     by content; they were application/octet-stream (TIKA-5029).
+
+   * glTF binary models, Blender scenes, Autodesk FBX (binary), Jw_cad and 
FastCAD drawings,
+     Valve Source maps, Unreal Tournament compressed packages, SoundFont 2 
banks, zsync
+     control files and PhysioNet WFDB annotations are detected by content; 
they were
+     application/octet-stream in a recent Common Crawl sample (TIKA-5029).
+
+   * NEXRAD Level III radar products, UCSC bigBed, bigWig and 2bit files, 
uncompressed BAM
+     and BAM indexes, OpenStreetMap PBF, LIGO/Virgo frame files, QEMU qcow 
disks, ImageDisk
+     floppy images, MAME CHD, devicetree blobs and FIT images, U-Boot legacy 
images, UBI
+     images, AmigaOS executables, DirectDraw Surface images 
(image/vnd.ms-dds), YM chiptunes,
+     VST presets and older Jw_cad drawings are detected by content; they were
+     application/octet-stream in a recent Common Crawl sample (TIKA-5029).
+
+   * HP printer jobs are detected by content: PJL jobs by the language they 
enter (PCL,
+     PCL XL or PostScript), and raw PCL5 and PCL XL streams. So are IBM MO:DCA 
(AFP)
+     documents, Windows minidumps and kernel dumps, StarView metafiles, Lotus 
1-2-3 files
+     with format version 0x1005, Promethean ActivInspire flipcharts, Casio 
calculator
+     (g1m family) files, Haihaisoft DRM-X protected files and Navitel maps; 
they were
+     application/octet-stream (TIKA-5029).
+
+   * gcov coverage data and notes, Python bytecode and pickles, Apache Lucene 
index files,
+     git packfiles, ACPI tables, TZif time zone files (application/tzif), 
Firefox mozLz4
+     files and JPEG XR images (image/jxr) are detected by content; they were
+     application/octet-stream (TIKA-5029).
+
+   * More variants are detected by content: OpenPGP keys and signatures in 
new-format
+     packets (as written for RFC 9580 v6 keys), v1 DER certificate revocation 
lists (no
+     version field), gettext catalogs with minor revision 1 and VCDIFF deltas 
in
+     open-vcdiff's SDCH format; they were application/octet-stream (TIKA-5029).
+
    * EpubParser resolves manifest hrefs as URI references relative to the OPF: 
a '+' is
      no longer read as a space, and '../' is followed, so such chapters and 
images are no
      longer skipped. encryption.xml URIs are resolved the same way. The new
diff --git a/tika-core/src/main/java/org/apache/tika/mime/MimeTypesReader.java 
b/tika-core/src/main/java/org/apache/tika/mime/MimeTypesReader.java
index a350939f32..7bc318ae8c 100644
--- a/tika-core/src/main/java/org/apache/tika/mime/MimeTypesReader.java
+++ b/tika-core/src/main/java/org/apache/tika/mime/MimeTypesReader.java
@@ -22,7 +22,9 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -139,6 +141,9 @@ public class MimeTypesReader extends DefaultHandler 
implements MimeTypesReaderMe
     protected StringBuilder characters = null;
     private ClauseRecord current = new ClauseRecord(null);
 
+    // per document: a later file (custom-mimetypes.xml) may extend a type, 
one file may not repeat it
+    private final Set<MediaType> definedInDocument = new HashSet<>();
+
     protected MimeTypesReader(MimeTypes types) {
         this.types = types;
     }
@@ -253,6 +258,11 @@ public class MimeTypesReader extends DefaultHandler 
implements MimeTypesReaderMe
         return new 
InputSource(UnsynchronizedByteArrayInputStream.nullInputStream());
     }
 
+    @Override
+    public void startDocument() {
+        definedInDocument.clear();
+    }
+
     @Override
     public void startElement(String uri, String localName, String qName, 
Attributes attributes)
             throws SAXException {
@@ -264,6 +274,10 @@ public class MimeTypesReader extends DefaultHandler 
implements MimeTypesReaderMe
                 try {
                     type = types.forName(name);
                     type.setInterpreted(interpreted);
+                    if (!definedInDocument.add(type.getType())) {
+                        throw new MimeTypeException(
+                                "Duplicate definition of " + type.getType() + 
" (as " + name + ")");
+                    }
                 } catch (MimeTypeException e) {
                     handleMimeError(name, e, qName, attributes);
                 }
diff --git 
a/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml 
b/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml
index 0d3d07e5ec..36badd6abc 100644
--- a/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml
+++ b/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml
@@ -383,6 +383,10 @@
   <mime-type type="application/x-tika-unix-dump"/>
 
   <mime-type type="application/java-serialized-object">
+    <magic priority="50">
+      <!-- STREAM_MAGIC, STREAM_VERSION 5, then a TC_* (0x70-0x7E) -->
+      <match value="0xACED000570" mask="0xFFFFFFFFF0" type="string" 
offset="0"/>
+    </magic>
     <glob pattern="*.ser"/>
   </mime-type>
 
@@ -544,6 +548,14 @@
     </magic>
   </mime-type>
 
+  <mime-type type="application/x-mame-chd">
+    <_comment>MAME compressed hunks of data</_comment>
+    <magic priority="50">
+      <match value="MComprHD" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.chd"/>
+  </mime-type>
+
   <mime-type type="application/x-java-jnilib">
     <_comment>Java Native Library for OSX</_comment>
     <glob pattern="*.jnilib"/>
@@ -594,7 +606,8 @@
       <match value="[0-9]{5,5}" type="regex" offset="0">
         <match value="45" type="string" offset="20">
           <!-- bibliographic -->
-          <match value="[acdnp][acdefgijkmoprt][abcdims]" type="regex" 
offset="5"/>
+          <!-- leader/07 is often left blank -->
+          <match value="[acdnp][acdefgijkmoprt][abcdims ]" type="regex" 
offset="5"/>
           <!-- authority-->
           <match value="[acdnosx]z" type="regex" offset="5"/>
           <!-- holdings -->
@@ -678,11 +691,6 @@
   <mime-type type="application/mediaservercontrol+xml">
     <glob pattern="*.mscml"/>
   </mime-type>
-  <mime-type type="application/vnd.mif">
-    <_comment>Adobe MIF File</_comment>
-    <glob pattern="*.mif"/>
-    <sub-class-of type="text/plain"/>
-  </mime-type>
   <mime-type type="application/mikey"/>
   <mime-type type="application/moss-keys"/>
   <mime-type type="application/moss-signature"/>
@@ -748,6 +756,10 @@
   </mime-type>
 
   <mime-type type="application/mxf">
+    <magic priority="50">
+      <!-- SMPTE 377 header partition pack key -->
+      <match value="0x060E2B34020501010D0102010102" type="string" offset="0"/>
+    </magic>
     <glob pattern="*.mxf"/>
   </mime-type>
   <mime-type type="application/nasdata"/>
@@ -899,9 +911,73 @@
     <glob pattern="*.gpg"/>
   </mime-type>
 
-  <mime-type type="application/pgp-keys"/>
+  <mime-type type="application/pgp-keys">
+    <magic priority="50">
+      <!-- binary old-format v4 key packet (RFC 4880 5.5): public (tag 6) or 
secret (tag 5)
+           key with a 1- or 2-byte length, version, 4-byte time, then 
RSA/DSA/Elgamal/ECDH/ECDSA/EdDSA -->
+      <match value="0x94" type="string" offset="0">
+        <match value="0x04" type="string" offset="2">
+          <match value="0x01" type="string" offset="7"/>
+          <match value="0x11" mask="0xFE" type="string" offset="7"/>
+          <match value="0x12" mask="0xFE" type="string" offset="7"/>
+          <match value="0x16" type="string" offset="7"/>
+        </match>
+      </match>
+      <match value="0x98" type="string" offset="0">
+        <match value="0x04" type="string" offset="2">
+          <match value="0x01" type="string" offset="7"/>
+          <match value="0x11" mask="0xFE" type="string" offset="7"/>
+          <match value="0x12" mask="0xFE" type="string" offset="7"/>
+          <match value="0x16" type="string" offset="7"/>
+        </match>
+      </match>
+      <match value="0x95" type="string" offset="0">
+        <match value="0x04" type="string" offset="3">
+          <match value="0x01" type="string" offset="8"/>
+          <match value="0x11" mask="0xFE" type="string" offset="8"/>
+          <match value="0x12" mask="0xFE" type="string" offset="8"/>
+          <match value="0x16" type="string" offset="8"/>
+        </match>
+      </match>
+      <match value="0x99" type="string" offset="0">
+        <match value="0x04" type="string" offset="3">
+          <match value="0x01" type="string" offset="8"/>
+          <match value="0x11" mask="0xFE" type="string" offset="8"/>
+          <match value="0x12" mask="0xFE" type="string" offset="8"/>
+          <match value="0x16" type="string" offset="8"/>
+        </match>
+      </match>
+      <!-- new-format secret (0xC5) or public (0xC6) key packet (RFC 9580 4.2, 
5.5.2): 1- or 2-byte
+           length, v4 or v6, 4-byte time, then a known public-key algorithm -->
+      <match value="0xC4" mask="0xFC" type="string" offset="0">
+        <match 
value="(?s)[\\xc5\\xc6](?:[\\x00-\\xbf]|[\\xc0-\\xdf].)[\\x04\\x06]....[\\x01\\x10-\\x13\\x16\\x19-\\x1c]"
 type="regex" offset="0"/>
+      </match>
+    </magic>
+  </mime-type>
 
   <mime-type type="application/pgp-signature">
+    <magic priority="50">
+      <!-- binary old-format signature packet (RFC 4880 5.2): tag 2 with a 1- 
or 2-byte
+           length, then v4 + binary/text sig type + RSA/DSA/ECDSA/EdDSA, or v3 
+ hashed length 5 -->
+      <match value="0x88" type="string" offset="0">
+        <match value="0x040001" mask="0xFFFEFF" type="string" offset="2"/>
+        <match value="0x040011" mask="0xFFFEFF" type="string" offset="2"/>
+        <match value="0x040013" mask="0xFFFEFF" type="string" offset="2"/>
+        <match value="0x040016" mask="0xFFFEFF" type="string" offset="2"/>
+        <match value="0x030500" mask="0xFFFFFE" type="string" offset="2"/>
+      </match>
+      <match value="0x89" type="string" offset="0">
+        <match value="0x040001" mask="0xFFFEFF" type="string" offset="3"/>
+        <match value="0x040011" mask="0xFFFEFF" type="string" offset="3"/>
+        <match value="0x040013" mask="0xFFFEFF" type="string" offset="3"/>
+        <match value="0x040016" mask="0xFFFEFF" type="string" offset="3"/>
+        <match value="0x030500" mask="0xFFFFFE" type="string" offset="3"/>
+      </match>
+      <!-- new-format signature packet (0xC2): v4 or v6, binary/text sig type, 
known algorithm -->
+      <match value="0xC2" type="string" offset="0">
+        <match 
value="(?s)\\xc2(?:[\\x00-\\xbf]|[\\xc0-\\xdf].)[\\x04\\x06][\\x00\\x01][\\x01\\x11\\x13\\x16\\x1b\\x1c]"
 type="regex" offset="0"/>
+      </match>
+    </magic>
     <glob pattern="*.asc"/>
     <glob pattern="*.sig"/>
   </mime-type>
@@ -965,6 +1041,20 @@
   </mime-type>
   <mime-type type="application/pkix-crl">
     <glob pattern="*.crl"/>
+    <magic priority="50">
+      <!-- DER v2 CertificateList: SEQUENCE { SEQUENCE { INTEGER 1, 
AlgorithmIdentifier { OID ...
+           any signature algorithm; long-form outer length, short or long 
inner.
+           A v1 certificate with serial 1 starts the same way; its validity 
SEQUENCE { Time, Time }
+           (never in a CRL) rules it out -->
+      <match value="0x3080" mask="0xFFFC" type="string" offset="0">
+        <match 
value="(?s)\\x30(?:\\x81.|\\x82..|\\x83...)\\x30(?:[\\x00-\\x7f]|\\x81.|\\x82..|\\x83...)\\x02\\x01\\x01\\x30[\\x00-\\x7f]\\x06(?!.{0,512}?\\x30(?:\\x1e\\x17\\x0d|\\x20(?:\\x17\\x0d|\\x18\\x0f)|\\x22\\x18\\x0f))"
 type="regex" offset="0"/>
+      </match>
+      <!-- DER v1 CertificateList, no version: SEQUENCE { SEQUENCE { 
AlgorithmIdentifier, issuer Name
+           (SEQUENCE { SET ...), then thisUpdate. A certificate's TBS opens 
with [0] or an INTEGER -->
+      <match value="0x3080" mask="0xFFFC" type="string" offset="0">
+        <match 
value="(?s)\\x30(?:\\x81.|\\x82..|\\x83...)\\x30(?:[\\x00-\\x7f]|\\x81.|\\x82..|\\x83...)\\x30[\\x00-\\x7f]\\x06[\\x03-\\x0f].{3,20}?\\x30(?:[\\x00-\\x7f]|\\x81.|\\x82..)\\x31.{0,1024}?(?:\\x17\\x0d[0-9]{12}Z|\\x18\\x0f[0-9]{14}Z)"
 type="regex" offset="0"/>
+      </match>
+    </magic>
   </mime-type>
   <mime-type type="application/pkix-pkipath">
     <glob pattern="*.pkipath"/>
@@ -979,6 +1069,13 @@
 
   <mime-type type="application/postscript">
     <_comment>PostScript</_comment>
+    <magic priority="60">
+      <!-- PJL job that switches to PostScript; driver headers put the command 
up to ~2K in -->
+      <match value="\x1b%-12345X" type="stringignorecase" offset="0">
+        <match value="ENTER LANGUAGE=POSTSCRIPT" type="stringignorecase" 
offset="0:8192"/>
+        <match value="ENTER LANGUAGE = POSTSCRIPT" type="stringignorecase" 
offset="0:8192"/>
+      </match>
+    </magic>
     <magic priority="50">
       <match value="%!" type="string" offset="0" />
       <match value="\004%!" type="string" offset="0" />
@@ -1186,8 +1283,26 @@
     <glob pattern="*.ssml"/>
   </mime-type>
   <mime-type type="application/timestamp-query"/>
-  <mime-type type="application/timestamp-reply"/>
+  <mime-type type="application/timestamp-reply">
+    <magic priority="50">
+      <!-- RFC 3161 TimeStampResp: SEQUENCE { PKIStatusInfo { INTEGER status, 
... },
+           then the token, a CMS signedData ContentInfo -->
+      <match value="0x3080" mask="0xFFFC" type="string" offset="0">
+        <match 
value="(?s)\\x30(?:\\x81.|\\x82..|\\x83...)\\x30[\\x03-\\x7f]\\x02\\x01[\\x00-\\x05].{0,160}?\\x06\\x09\\x2a\\x86\\x48\\x86\\xf7\\x0d\\x01\\x07\\x02"
 type="regex" offset="0"/>
+      </match>
+    </magic>
+    <glob pattern="*.tsr"/>
+  </mime-type>
   <mime-type type="application/tve-trigger"/>
+  <mime-type type="application/tzif">
+    <_comment>Time Zone Information Format (RFC 8536)</_comment>
+    <magic priority="50">
+      <match value="TZif\x00" type="string" offset="0"/>
+      <match value="TZif2" type="string" offset="0"/>
+      <match value="TZif3" type="string" offset="0"/>
+      <match value="TZif4" type="string" offset="0"/>
+    </magic>
+  </mime-type>
   <mime-type type="application/ulpfec"/>
   <mime-type type="application/vemmi"/>
   <mime-type type="application/vividence.scriptfile"/>
@@ -1413,6 +1528,20 @@
     <_comment>frictionless data package zip package</_comment>
     <sub-class-of type="application/zip"/>
   </mime-type>
+
+  <mime-type type="application/x-vst-preset">
+    <_comment>VST plug-in preset or bank</_comment>
+    <magic priority="50">
+      <match value="CcnK" type="string" offset="0">
+        <match value="FxCk" type="string" offset="8"/>
+        <match value="FPCh" type="string" offset="8"/>
+        <match value="FxBk" type="string" offset="8"/>
+        <match value="FBCh" type="string" offset="8"/>
+      </match>
+    </magic>
+    <glob pattern="*.fxp"/>
+    <glob pattern="*.fxb"/>
+  </mime-type>
   <mime-type type="application/x-ipynb+json">
     <_comment>Jupyter Notebook</_comment>
     
<tika:link>https://nbformat.readthedocs.io/en/latest/format_description.html</tika:link>
@@ -1724,10 +1853,36 @@
     <glob pattern="*.jlt"/>
   </mime-type>
   <mime-type type="application/vnd.hp-pcl">
+    <magic priority="55">
+      <!-- PJL job (UEL, then @PJL commands) that switches to PCL; below PCL 
XL, whose command
+           this prefix also matches -->
+      <match value="\x1b%-12345X" type="stringignorecase" offset="0">
+        <match value="ENTER LANGUAGE=PCL" type="stringignorecase" 
offset="0:8192"/>
+        <match value="ENTER LANGUAGE = PCL" type="stringignorecase" 
offset="0:8192"/>
+      </match>
+    </magic>
+    <magic priority="50">
+      <!-- UEL straight into PCL, or a raw PCL5 stream: reset, then a 
parameterized command -->
+      <match value="\x1b%-12345X\x1bE" type="string" offset="0"/>
+      <match value="\x1bE\x1b" type="string" offset="0">
+        <match value="\x1bE\x1b[&amp;*(%]" type="regex" offset="0"/>
+      </match>
+    </magic>
     <glob pattern="*.pcl"/>
   </mime-type>
   <mime-type type="application/vnd.hp-pclxl">
+    <magic priority="60">
+      <match value="\x1b%-12345X" type="stringignorecase" offset="0">
+        <match value="ENTER LANGUAGE=PCLXL" type="stringignorecase" 
offset="0:8192"/>
+        <match value="ENTER LANGUAGE = PCLXL" type="stringignorecase" 
offset="0:8192"/>
+      </match>
+    </magic>
+    <magic priority="50">
+      <!-- stream header, e.g. ") HP-PCL XL;3;0;" -->
+      <match value=") HP-PCL XL;" type="string" offset="0"/>
+    </magic>
     <glob pattern="*.pclxl"/>
+    <glob pattern="*.pxl"/>
   </mime-type>
   <mime-type type="application/vnd.httphone"/>
   <mime-type type="application/vnd.hydrostatix.sof-data">
@@ -1742,6 +1897,12 @@
     <glob pattern="*.mpy"/>
   </mime-type>
   <mime-type type="application/vnd.ibm.modcap">
+    <magic priority="50">
+      <!-- MO:DCA structured field: 5A, 2-byte length, D3 class, A8 = Begin 
(document, resource group, ...) -->
+      <match value="0x5A" type="string" offset="0">
+        <match value="0xD3A8" type="string" offset="3"/>
+      </match>
+    </magic>
     <glob pattern="*.afp"/>
     <glob pattern="*.listafp"/>
     <glob pattern="*.list3820"/>
@@ -1960,6 +2121,9 @@
     <magic priority="50">
       <match value="0x00001A0003100400" type="string" offset="0">
       </match>
+      <!-- 0x1005: not in PRONOM; seen in .123 attachments to LibreOffice bugs 
53713, 54655, 55066
+           and 114000 and OpenOffice bugs 79309 and 122841 -->
+      <match value="0x00001A0005100400" type="string" offset="0"/>
     </magic>
     <glob pattern="*.123"/>
   </mime-type>
@@ -2023,6 +2187,7 @@
     <_comment>FrameMaker Interchange Format</_comment>
     <alias type="application/x-mif"/>
     <alias type="application/x-frame"/>
+    <sub-class-of type="text/plain"/>
     <magic priority="50">
       <match value="&lt;MakerFile" type="string" offset="0" />
       <match value="&lt;MIFFile" type="string" offset="0" />
@@ -2213,6 +2378,13 @@
 
   <mime-type type="application/vnd.ms-fontobject">
     <magic priority="50">
+      <!-- version 0x00010000, 0x00020001 or 0x00020002, then the "LP" magic 
-->
+      <match value="\x00\x00\x01\x00" type="string" offset="8">
+        <match value="\x4C\x50" type="string" offset="34"/>
+      </match>
+      <match value="\x01\x00\x02\x00" type="string" offset="8">
+        <match value="\x4C\x50" type="string" offset="34"/>
+      </match>
       <match value="\x02\x00\x02\x00" type="string" offset="8">
         <match value="\x4C\x50" type="string" offset="34"/>
       </match>
@@ -2824,6 +2996,15 @@
     <glob pattern="*.pqa"/>
     <glob pattern="*.oprc"/>
   </mime-type>
+  <mime-type type="application/x-aportisdoc">
+    <_comment>PalmDOC (AportisDoc) e-book</_comment>
+    <alias type="application/x-palmdoc"/>
+    <sub-class-of type="application/vnd.palm"/>
+    <magic priority="60">
+      <!-- Palm database type + creator -->
+      <match value="TEXtREAd" type="string" offset="60"/>
+    </magic>
+  </mime-type>
 
   <mime-type type="application/vnd.paos.xml"/>
   <mime-type type="application/vnd.pg.format">
@@ -3030,10 +3211,6 @@
     <sub-class-of type="text/plain"/>
   </mime-type>
   
-  <mime-type type="application/vnd.sun.xml.writer">
-    <sub-class-of type="application/zip"/>
-    <glob pattern="*.sxw"/>
-  </mime-type>
   <!-- can't currently find any diff in contents btwn writer
     and template. Must rely on extension -->
   <mime-type type="application/vnd.sun.xml.writer.template">
@@ -3058,21 +3235,12 @@
   </mime-type>
 
   <mime-type type="application/vnd.street-stream"/>
-  <mime-type type="application/vnd.sun.xml.calc">
-    <glob pattern="*.sxc"/>
-  </mime-type>
   <mime-type type="application/vnd.sun.xml.calc.template">
     <glob pattern="*.stc"/>
   </mime-type>
-  <mime-type type="application/vnd.sun.xml.draw">
-    <glob pattern="*.sxd"/>
-  </mime-type>
   <mime-type type="application/vnd.sun.xml.draw.template">
     <glob pattern="*.std"/>
   </mime-type>
-  <mime-type type="application/vnd.sun.xml.impress">
-    <glob pattern="*.sxi"/>
-  </mime-type>
   <mime-type type="application/vnd.sun.xml.impress.template">
     <glob pattern="*.sti"/>
   </mime-type>
@@ -3083,6 +3251,7 @@
   <mime-type type="application/vnd.sun.xml.writer">
     <alias type="application/x-vnd.sun.xml.writer"/>
     <_comment>OpenOffice v1.0: Writer Document</_comment>
+    <sub-class-of type="application/zip"/>
     <magic>
       <match type="string" offset="0" value="PK">
         <match type="string" offset="30"
@@ -3095,9 +3264,6 @@
   <mime-type type="application/vnd.sun.xml.writer.global">
     <glob pattern="*.sxg"/>
   </mime-type>
-  <mime-type type="application/vnd.sun.xml.writer.template">
-    <glob pattern="*.stw"/>
-  </mime-type>
   <mime-type type="application/vnd.sun.wadl+xml"/>
   <mime-type type="application/vnd.sus-calendar">
     <glob pattern="*.sus"/>
@@ -3111,6 +3277,8 @@
   <mime-type type="application/vnd.symbian.install">
     <magic priority="50">
       <match value="0x10000419" type="little32" offset="8" />
+      <!-- SIS 9.x (sisx): UID1 -->
+      <match value="0x10201A7A" type="little32" offset="0" />
     </magic>
     <glob pattern="*.sis"/>
     <glob pattern="*.sisx"/>
@@ -3451,6 +3619,13 @@
     <glob pattern="*.wspolicy"/>
   </mime-type>
   
+  <mime-type type="image/x-svm">
+    <_comment>StarView Metafile</_comment>
+    <magic priority="50">
+      <match value="VCLMTF" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.svm"/>
+  </mime-type>
   <mime-type type="image/x-tga">
      <alias type="image/x-targa"/>
      <_comment>Targa image data</_comment>
@@ -3532,6 +3707,17 @@
   <mime-type type="application/x-ace-compressed">
     <glob pattern="*.ace"/>
   </mime-type>
+  <mime-type type="application/x-intel-aml">
+    <_comment>ACPI table (DSDT, SSDT, FACP, APIC, ...)</_comment>
+    <alias type="application/x-acpi-table"/>
+    <magic priority="50">
+      <!-- signature, 4-byte length, revision, checksum, then a printable 
6-byte OEM ID -->
+      <match value="0x00" mask="0xF8" type="string" offset="8">
+        <match 
value="(?s)(?:DSDT|SSDT|FACP|APIC|HPET|MCFG|SLIC|BERT|WAET)....[\\x00-\\x06].[\\x20-\\x7e]{6}"
 type="regex" offset="0"/>
+      </match>
+    </magic>
+    <glob pattern="*.aml"/>
+  </mime-type>
   <mime-type type="application/x-activemime">
     <magic priority="60">
       <!-- ActiveMime\u0000\u0000 -->
@@ -3569,6 +3755,31 @@
     </magic>
   </mime-type>
 
+  <mime-type type="application/x-bam">
+    <_comment>Sequence Alignment/Map, binary (BGZF-decompressed)</_comment>
+    <magic priority="50">
+      <match value="BAM\x01" type="string" offset="0"/>
+    </magic>
+  </mime-type>
+
+  <mime-type type="application/x-bam-index">
+    <_comment>BAM index</_comment>
+    <magic priority="50">
+      <match value="BAI\x01" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.bai"/>
+  </mime-type>
+
+
+  <mime-type type="application/x-adobe-swatch-exchange">
+    <acronym>ASE</acronym>
+    <_comment>Adobe Swatch Exchange</_comment>
+    <!-- no *.ase glob: Aseprite uses it too -->
+    <magic priority="50">
+      <match value="ASEF\x00\x01\x00\x00" type="string" offset="0"/>
+    </magic>
+  </mime-type>
+
   <mime-type type="application/x-adobe-indesign">
     <acronym>INDD</acronym>
     <_comment>Adobe InDesign document</_comment>
@@ -3851,19 +4062,53 @@
     <sub-class-of type="text/plain"/>
   </mime-type>
 
+  <mime-type type="application/x-bigbed">
+    <_comment>UCSC bigBed track</_comment>
+    <magic priority="50">
+      <!-- 0x8789F2EB in either byte order, then version 1-5 -->
+      <match value="(?s)\\xeb\\xf2\\x89\\x87[\\x01-\\x05]\\x00" type="regex" 
offset="0"/>
+      <match value="(?s)\\x87\\x89\\xf2\\xeb\\x00[\\x01-\\x05]" type="regex" 
offset="0"/>
+    </magic>
+    <glob pattern="*.bigbed"/>
+  </mime-type>
+
+  <mime-type type="application/x-bigwig">
+    <_comment>UCSC bigWig track</_comment>
+    <magic priority="50">
+      <!-- 0x888FFC26 in either byte order, then version 1-5 -->
+      <match value="(?s)\\x26\\xfc\\x8f\\x88[\\x01-\\x05]\\x00" type="regex" 
offset="0"/>
+      <match value="(?s)\\x88\\x8f\\xfc\\x26\\x00[\\x01-\\x05]" type="regex" 
offset="0"/>
+    </magic>
+    <glob pattern="*.bigwig"/>
+  </mime-type>
+
+
   <mime-type type="application/x-bittorrent">
     <magic priority="50">
+      <!-- bencoded dict; keys are sorted, so the first is one of these -->
       <match value="d8:announce" type="string" offset="0"/>
+      <match value="d13:announce-list" type="string" offset="0"/>
+      <match value="d7:comment" type="string" offset="0"/>
+      <match value="d10:created by" type="string" offset="0"/>
+      <match value="d13:creation date" type="string" offset="0"/>
+      <match value="d8:encoding" type="string" offset="0"/>
+      <match value="d4:infod" type="string" offset="0"/>
     </magic>
     <glob pattern="*.torrent"/>
   </mime-type>
-
   <mime-type type="application/x-blender">
     <acronym>Blend</acronym>
     <_comment>Blender scene</_comment>
     <tika:link>https://www.blender.org/</tika:link>
     <magic priority="50">
-      <match value="BLENDER" type="string" offset="0"/>
+      <!-- then pointer size (_ 32-bit, - 64-bit), endianness, version -->
+      <match value="BLENDER" type="string" offset="0">
+        <match value="BLENDER[_-][vV][0-9]" type="regex" offset="0"/>
+      </match>
+      <!-- 5.0+: header size, pointer size, format version, endianness, 
4-digit version -->
+      <match value="BLENDER" type="string" offset="0">
+        <match value="BLENDER[0-9]{2}[_-][0-9]{2}[vV][0-9]{4}" type="regex" 
offset="0"/>
+      </match>
     </magic>
     <glob pattern="*.blend"/>
     <glob pattern="*.blender"/>
@@ -3898,6 +4143,26 @@
     <sub-class-of type="application/xml"/>
   </mime-type>
 
+  <mime-type type="application/x-casio-fxi">
+    <_comment>Casio calculator data (Yellow Computing FX-Interface)</_comment>
+    <magic priority="50">
+      <!-- "FX-INTERFACE" XOR 0xE7 -->
+      <match value="0xA1BFCAAEA9B3A2B5A1A6A4A2" type="string" offset="3"/>
+    </magic>
+    <glob pattern="*.fxi"/>
+  </mime-type>
+  <mime-type type="application/x-casio-g1m">
+    <_comment>Casio calculator file (g1m family)</_comment>
+    <magic priority="50">
+      <!-- "USBPower", bitwise inverted -->
+      <match value="0xAAACBDAF90889A8D" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.g1m"/>
+    <glob pattern="*.g1r"/>
+    <glob pattern="*.g2m"/>
+    <glob pattern="*.g2r"/>
+    <glob pattern="*.g3m"/>
+  </mime-type>
   <mime-type type="application/x-cdf">
     <_comment>CD Audio</_comment>
     <magic priority="50">
@@ -3905,6 +4170,76 @@
       <glob pattern="*.cda"/>
     </magic>
   </mime-type>
+  <mime-type type="application/x-fec">
+    <_comment>US Federal Election Commission electronic filing</_comment>
+    
<tika:link>https://www.fec.gov/help-candidates-and-committees/filing-reports/fecfile-software/</tika:link>
+    <sub-class-of type="text/plain"/>
+    <magic priority="50">
+      <!-- header record, fields separated by FS (0x1C) -->
+      <match value="HDR\x1cFEC\x1c" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.fec"/>
+  </mime-type>
+  <mime-type type="application/x-garmin-gdb">
+    <_comment>Garmin MapSource GPS database</_comment>
+    <!-- no *.gdb glob: InterBase/Firebird and others use it -->
+    <magic priority="50">
+      <match value="MsRcf\x00" type="string" offset="0"/>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-gbx">
+    <_comment>Nadeo GameBox (TrackMania, ManiaPlanet)</_comment>
+    <magic priority="50">
+      <!-- version 3-6, then format and compression flags -->
+      <match value="GBX" type="string" offset="0">
+        <match value="GBX[\x03-\x06]\x00[BT][UC][UC]" type="regex" offset="0"/>
+      </match>
+    </magic>
+    <glob pattern="*.gbx"/>
+  </mime-type>
+  <mime-type type="application/x-gcov-data">
+    <_comment>gcov coverage data</_comment>
+    <magic priority="50">
+      <!-- "gcda" in either byte order, then a 4-character version -->
+      <match value="adcg" type="string" offset="0">
+        <match value="[0-9A-Z*]{4}" type="regex" offset="4"/>
+      </match>
+      <match value="gcda" type="string" offset="0">
+        <match value="[0-9A-Z*]{4}" type="regex" offset="4"/>
+      </match>
+    </magic>
+    <glob pattern="*.gcda"/>
+  </mime-type>
+  <mime-type type="application/x-gcov-notes">
+    <_comment>gcov notes</_comment>
+    <magic priority="50">
+      <match value="oncg" type="string" offset="0">
+        <match value="[0-9A-Z*]{4}" type="regex" offset="4"/>
+      </match>
+      <match value="gcno" type="string" offset="0">
+        <match value="[0-9A-Z*]{4}" type="regex" offset="4"/>
+      </match>
+    </magic>
+    <glob pattern="*.gcno"/>
+  </mime-type>
+  <mime-type type="application/x-gettext-translation">
+    <_comment>GNU gettext message catalog</_comment>
+    <magic priority="50">
+      <!-- magic in either byte order, then major revision 0, minor 0 or 1 
(system-dependent strings) -->
+      <match value="0xDE12049500000000" mask="0xFFFFFFFFFEFFFFFF" 
type="string" offset="0"/>
+      <match value="0x950412DE00000000" mask="0xFFFFFFFFFFFFFFFE" 
type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.mo"/>
+    <glob pattern="*.gmo"/>
+  </mime-type>
+  <mime-type type="application/x-git-pack">
+    <_comment>git packfile</_comment>
+    <alias type="application/x-git"/>
+    <magic priority="50">
+      <match value="PACK\x00\x00\x00\x02" type="string" offset="0"/>
+      <match value="PACK\x00\x00\x00\x03" type="string" offset="0"/>
+    </magic>
+  </mime-type>
   <mime-type type="application/x-gtar">
     <_comment>GNU tar Compressed File Archive (GNU Tape Archive)</_comment>
     <magic priority="50">
@@ -3940,6 +4275,14 @@
     </magic>
   </mime-type>
 
+  <mime-type type="application/x-amiga-executable">
+    <_comment>AmigaOS hunk executable</_comment>
+    <magic priority="50">
+      <!-- HUNK_HEADER, no resident libraries, then a nonzero hunk table size 
-->
+      <match value="(?s)\\x00\\x00\\x03\\xf3\\x00{7}[\\x01-\\xff]" 
type="regex" offset="0"/>
+    </magic>
+  </mime-type>
+
   <mime-type type="application/x-brotli">
     <glob pattern="*.br" />
     <glob pattern="*.brotli" />
@@ -3986,6 +4329,22 @@
     </magic>
     <glob pattern="*.crx"/>
   </mime-type>
+  <mime-type type="application/x-clamav-database">
+    <_comment>ClamAV signature database</_comment>
+    <alias type="application/x-clamav"/>
+    <magic priority="50">
+      <match value="ClamAV-VDB:" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.cvd"/>
+    <glob pattern="*.cld"/>
+  </mime-type>
+  <mime-type type="application/x-clamav-diff">
+    <_comment>ClamAV signature database update</_comment>
+    <magic priority="50">
+      <match value="ClamAV-Diff:" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.cdiff"/>
+  </mime-type>
 
   <mime-type type="application/x-compress">
     <magic priority="50">
@@ -4027,6 +4386,18 @@
     <glob pattern="*.udeb"/>
   </mime-type>
 
+  <mime-type type="application/x-device-tree-blob">
+    <_comment>Flattened devicetree (DTB, U-Boot FIT image)</_comment>
+    <magic priority="50">
+      <!-- magic, then version 16 or 17 at offset 20 -->
+      <match value="0xD00DFEED" type="string" offset="0">
+        <match value="0x00000010" mask="0xFFFFFFFE" type="string" offset="20"/>
+      </match>
+    </magic>
+    <glob pattern="*.dtbo"/>
+    <glob pattern="*.itb"/>
+  </mime-type>
+
   <mime-type type="application/x-dex">
     <acronym>DEX</acronym>
     <_comment>Dalvik Executable Format</_comment>
@@ -4076,6 +4447,14 @@
     <glob pattern="*.dvi"/>
   </mime-type>
 
+  <mime-type type="application/x-elasto-mania-level">
+    <_comment>Elasto Mania level</_comment>
+    <magic priority="50">
+      <!-- Elma; POT06 is Across -->
+      <match value="POT14" type="string" offset="0"/>
+      <match value="POT06" type="string" offset="0"/>
+    </magic>
+  </mime-type>
   <mime-type type="application/x-elc">
     <_comment>Emacs Lisp bytecode</_comment>
     <magic priority="50">
@@ -4143,6 +4522,13 @@
       </match>
     </magic>
   </mime-type>
+  <mime-type type="application/x-fbx">
+    <_comment>Autodesk FBX (binary)</_comment>
+    <magic priority="50">
+      <match value="Kaydara FBX Binary  \x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.fbx"/>
+  </mime-type>
 
   <mime-type type="application/x-killustrator">
     <_comment>KIllustrator File</_comment>
@@ -4170,6 +4556,17 @@
     <glob pattern="*.scad"/>
     <sub-class-of type="text/plain"/>
   </mime-type>
+
+  <mime-type type="application/x-osm-pbf">
+    <_comment>OpenStreetMap PBF</_comment>
+    <magic priority="50">
+      <!-- big-endian BlobHeader length, then BlobHeader.type "OSMHeader" -->
+      <match value="0x0A094F534D486561646572" type="string" offset="4">
+        <match value="0x0000" type="string" offset="0"/>
+      </match>
+    </magic>
+    <glob pattern="*.osm.pbf"/>
+  </mime-type>
   <mime-type type="application/x-extension-fcstd">
     <_comment>FreeCAD document</_comment>
     <tika:link>https://wiki.freecad.org/File_Format_FCStd</tika:link>
@@ -4186,6 +4583,13 @@
       </match>
     </magic>
   </mime-type>
+  <mime-type type="application/x-fastcad">
+    <_comment>FastCAD drawing</_comment>
+    <magic priority="50">
+      <match value="FCW (FastCAD for Windows)" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.fcw"/>
+  </mime-type>
   <mime-type type="application/x-sharedlib">
     <sub-class-of type="application/x-elf"/>
     <magic priority="50">
@@ -4214,6 +4618,20 @@
     </magic>
     <!-- too rare to use? <glob pattern="*.mmm"/> -->
   </mime-type>
+  <mime-type type="application/x-dmp">
+    <_comment>Windows minidump</_comment>
+    <magic priority="50">
+      <match value="MDMP\x93\xa7" type="string" offset="0"/>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-windows-kernel-dump">
+    <_comment>Windows kernel memory dump</_comment>
+    <alias type="application/x-ms-dmp"/>
+    <magic priority="50">
+      <match value="PAGEDUMP" type="string" offset="0"/>
+      <match value="PAGEDU64" type="string" offset="0"/>
+    </magic>
+  </mime-type>
   <mime-type type="application/x-dosexec">
     <_comment>DOS/Windows executable (EXE)</_comment>
     <!-- magic is MZ at offset=0, but that may not be unique enough -->
@@ -4238,6 +4656,12 @@
     </magic>
     <glob pattern="*.fp7" />
   </mime-type>
+  <mime-type type="application/x-finale">
+    <_comment>Finale notation (Enigma binary)</_comment>
+    <magic priority="50">
+      <match value="ENIGMA BINARY FILE" type="string" offset="0"/>
+    </magic>
+  </mime-type>
 
   <mime-type type="application/x-font-bdf">
     <glob pattern="*.bdf"/>
@@ -4328,6 +4752,14 @@
     <glob pattern="*.spl"/>
   </mime-type>
 
+  <mime-type type="application/x-glulx">
+    <_comment>Glulx game</_comment>
+    <magic priority="50">
+      <match value="Glul\x00\x02" type="string" offset="0"/>
+      <match value="Glul\x00\x03" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.ulx"/>
+  </mime-type>
   <mime-type type="application/x-gnucash">
     <glob pattern="*.gnucash" />
   </mime-type>
@@ -4386,6 +4818,15 @@
     <sub-class-of type="application/x-tika-msoffice"/>
     <glob pattern="*.lyr"/>
   </mime-type>
+  <mime-type type="application/x-haihaisoft-drm">
+    <_comment>Haihaisoft DRM-X protected file</_comment>
+    <magic priority="50">
+      <!-- the <XDRMHEADER> that follows names its license server at drm-x.com 
-->
+      <match value="XDRM" type="string" offset="0">
+        <match value="HEAD" type="string" offset="10"/>
+      </match>
+    </magic>
+  </mime-type>
   <mime-type type="application/x-hdf">
     <_comment>Hierarchical Data Format File</_comment>
     <magic priority="50">
@@ -4437,6 +4878,13 @@
       <match value="0x535200040000000A000004" type="string" offset="0"/>
     </magic>
   </mime-type>
+
+  <mime-type type="application/x-imagedisk">
+    <_comment>ImageDisk floppy image</_comment>
+    <magic priority="50">
+      <match value="IMD [0-9]\\.[0-9]{2}: " type="regex" offset="0"/>
+    </magic>
+  </mime-type>
   <mime-type type="application/x-internet-archive">
     <acronym>ARC</acronym>
     <_comment>ARC</_comment>
@@ -4517,6 +4965,18 @@
       <match value="JigsawDownload template" offset="0"/>
     </magic>
   </mime-type>
+  <mime-type type="application/x-jw-cad">
+    <_comment>Jw_cad drawing</_comment>
+    <magic priority="50">
+      <match value="JwwData." type="string" offset="0"/>
+      <match value="JwsData." type="string" offset="0"/>
+      <!-- older JWC drawings and symbols -->
+      <match value="jw_cad(c)" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.jww"/>
+    <glob pattern="*.jwc"/>
+    <glob pattern="*.jws"/>
+  </mime-type>
   <mime-type type="application/x-kdelnk">
     <magic priority="50">
       <match value="[KDE\ Desktop\ Entry]" type="string" offset="0"/>
@@ -4555,7 +5015,31 @@
       <match value="-lz5-" type="string" offset="2"/>
     </magic>
   </mime-type>
+
+  <mime-type type="application/x-ligo-frame">
+    <_comment>LIGO/Virgo gravitational-wave frame file</_comment>
+    <magic priority="50">
+      <match value="IGWD\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.gwf"/>
+  </mime-type>
   
+  <mime-type type="application/x-lrzip">
+    <_comment>Long Range ZIP</_comment>
+    <magic priority="50">
+      <match value="LRZI\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.lrz"/>
+  </mime-type>
+  <mime-type type="application/x-lucene-index">
+    <_comment>Apache Lucene index file</_comment>
+    <magic priority="50">
+      <!-- CodecUtil header: magic 0x3FD76C17, then the codec name (length 
byte + ASCII) -->
+      <match value="0x3FD76C17" type="string" offset="0">
+        <match value="(?s)\\x3f\\xd7\\x6c\\x17[\\x02-\\x40][A-Za-z]" 
type="regex" offset="0"/>
+      </match>
+    </magic>
+  </mime-type>
   <mime-type type="application/x-lz4">
      <_comment>First match LZ4 Frame</_comment>
      <_comment>Second match Legacy Frame</_comment>
@@ -4578,6 +5062,13 @@
     <_comment>LZMA compressed archive</_comment>
     <glob pattern="*.lzma"/>
   </mime-type>
+  <mime-type type="application/x-lzx">
+    <_comment>Amiga LZX archive</_comment>
+    <magic priority="50">
+      <match value="LZX\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.lzx"/>
+  </mime-type>
   <mime-type type="application/x-mach-o">
     <_comment>Mach-O</_comment>
     <tika:link>https://www.nationalarchives.gov.uk/PRONOM/fmt/692</tika:link>
@@ -4781,6 +5272,14 @@
     <sub-class-of type="application/x-bplist"/>
     <glob pattern="*.memgraph"/>
   </mime-type>
+  <mime-type type="application/x-mikrotik-npk">
+    <_comment>MikroTik RouterOS package</_comment>
+    <magic priority="50">
+      <match value="0x1EF1D0BA" type="string" offset="0"/>
+      <match value="0xFB0F10A1" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.npk"/>
+  </mime-type>
 
   <mime-type type="application/x-mobipocket-ebook">
     <acronym>MOBI</acronym>
@@ -4847,6 +5346,19 @@
     <glob pattern="*.clp"/>
   </mime-type>
 
+  <mime-type type="application/x-mpq">
+    <_comment>Blizzard MPQ archive</_comment>
+    <magic priority="50">
+      <!-- archive header with its v1-v4 header size, or the user-data header 
that precedes one -->
+      <match value="MPQ\x1a\x20\x00\x00\x00" type="string" offset="0"/>
+      <match value="MPQ\x1a\x2c\x00\x00\x00" type="string" offset="0"/>
+      <match value="MPQ\x1a\x44\x00\x00\x00" type="string" offset="0"/>
+      <match value="MPQ\x1a\xd0\x00\x00\x00" type="string" offset="0"/>
+      <match value="MPQ\x1b" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.mpq"/>
+  </mime-type>
+
   <mime-type type="application/x-msdownload">
     <glob pattern="*.dll"/>
     <glob pattern="*.com"/>
@@ -5029,6 +5541,42 @@
       <match value="0x43444601" type="string" offset="0"/>
     </magic>
   </mime-type>
+
+  <mime-type type="application/x-nexrad-level3">
+    <_comment>NEXRAD Level III radar product</_comment>
+    <magic priority="50">
+      <!-- WMO abbreviated heading for radar data (SDUSii CCCC YYGGgg), then 
the AWIPS id -->
+      <match value="SDUS" type="string" offset="0">
+        <match value="SDUS[0-9]{2} [A-Z]{4} [0-9]{6}(?: 
[A-Z]{3})?\\r\\r\\n[A-Z0-9]{4,6}\\r\\r\\n" type="regex" offset="0"/>
+      </match>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-navitel-map">
+    <_comment>Navitel Navigator map</_comment>
+    <magic priority="50">
+      <!-- crawl files name their source "OpenStreetMap (converted by 
KonTur)", a Navitel OSM map series -->
+      <match value="PMGC\x05\x00" type="string" offset="0">
+        <match value="0x8400000084000000" type="string" offset="20"/>
+      </match>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-nufx">
+    <_comment>NuFX (ShrinkIt) archive</_comment>
+    <magic priority="50">
+      <match value="0x4EF546E96CE5" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.shk"/>
+  </mime-type>
+  <mime-type type="application/x-nwc">
+    <_comment>NoteWorthy Composer song</_comment>
+    <magic priority="50">
+      <!-- compressed: zlib stream follows -->
+      <match value="[NWZ]\x00\x78" type="string" offset="0"/>
+      <match value="[NoteWorthy ArtWare]" type="string" offset="0"/>
+      <match value="[NoteWorthy Composer]" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.nwc"/>
+  </mime-type>
   <mime-type type="application/x-parquet">
     <glob pattern="*.parquet"/>
     <magic priority="50">
@@ -5074,6 +5622,80 @@
       <match value="0M3C" type="string" offset="8" />
     </magic>
   </mime-type>
+  <mime-type type="application/x-promethean-flipchart">
+    <_comment>Promethean ActivInspire flipchart</_comment>
+    <!-- " Bamboo " is the container; its zlib members carry the 
prometheanworld.com/Inspire XML namespace -->
+    <magic priority="50">
+      <match value=" Bamboo " type="string" offset="0"/>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-ps3-package">
+    <_comment>PlayStation 3/PSP package</_comment>
+    <magic priority="50">
+      <!-- then package type: 0x80000001 retail, 0x00000001 debug -->
+      <match value="0x7F504B4700000001" mask="0xFFFFFFFF7FFFFFFF" 
type="string" offset="0"/>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-ps3-theme">
+    <_comment>PlayStation 3 theme</_comment>
+    <magic priority="50">
+      <match value="P3TF\x00\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.p3t"/>
+  </mime-type>
+  <mime-type type="application/x-python-bytecode">
+    <_comment>Python bytecode</_comment>
+    <magic priority="50">
+      <!-- 2.3-2.7 magic numbers, then CR LF -->
+      <match value="0x3BF20D0A" type="string" offset="0"/>
+      <match value="0x6DF20D0A" type="string" offset="0"/>
+      <match value="0xB3F20D0A" type="string" offset="0"/>
+      <match value="0xD1F20D0A" type="string" offset="0"/>
+      <match value="0x03F30D0A" type="string" offset="0"/>
+      <!-- 3.x: a little-endian magic (3.0 is 3131, 3.14 is 3627), then CR LF. 
Text whose first line is
+           one character with CR CR LF endings looks the same, so also check 
the rest of the header -->
+      <match value="0x0D0A" type="string" offset="2">
+        <!-- 3.0-3.4: the code object after the 8- or 12-byte header -->
+        <match value="0x0C" type="string" offset="1">
+          <match value="c" type="string" offset="8"/>
+          <match value="c" type="string" offset="12"/>
+          <match value="0xE3" type="string" offset="12"/>
+        </match>
+        <!-- 3.5-3.6: a code object at 12; 3.7+: PEP 552 flags 0-3 -->
+        <match value="0x0D" type="string" offset="1">
+          <match value="0xE3" type="string" offset="12"/>
+          <match value="0x00000000" mask="0xFCFFFFFF" type="string" 
offset="4"/>
+        </match>
+        <match value="0x0E" type="string" offset="1">
+          <match value="0x00000000" mask="0xFCFFFFFF" type="string" 
offset="4"/>
+        </match>
+      </match>
+    </magic>
+    <glob pattern="*.pyc"/>
+    <glob pattern="*.pyo"/>
+  </mime-type>
+  <mime-type type="application/x-python-pickle">
+    <_comment>Python pickle</_comment>
+    <magic priority="50">
+      <!-- protocol 2-3, then a dict/list/mark/global opcode; protocol 4-5 
start with FRAME -->
+      <match value="0x80" type="string" offset="0">
+        <match value="(?s)\\x80[\\x02\\x03][}\\](c]" type="regex" offset="0"/>
+        <match value="(?s)\\x80[\\x04\\x05]\\x95" type="regex" offset="0"/>
+      </match>
+    </magic>
+    <glob pattern="*.pkl"/>
+    <glob pattern="*.pickle"/>
+  </mime-type>
+
+  <mime-type type="application/x-qemu-disk">
+    <_comment>QEMU copy-on-write disk image</_comment>
+    <magic priority="50">
+      <!-- qcow version 1, 2 or 3 -->
+      <match value="(?s)QFI\\xfb\\x00\\x00\\x00[\\x01-\\x03]" type="regex" 
offset="0"/>
+    </magic>
+    <glob pattern="*.qcow"/>
+    <glob pattern="*.qcow2"/>
+  </mime-type>
 
   <mime-type type="application/x-quattro-pro">
     <_comment>
@@ -5357,6 +5979,22 @@
     </magic>
     <glob pattern="*.sz"/>
   </mime-type>
+  <mime-type type="application/x-source-bsp">
+    <_comment>Valve Source engine map</_comment>
+    <magic priority="50">
+      <!-- then version 0x10-0x1f (Half-Life 2 .. CS:GO use 19-21) -->
+      <match value="VBSP" type="string" offset="0">
+        <match value="0x11" mask="0xF0" type="string" offset="4"/>
+      </match>
+    </magic>
+  </mime-type>
+  <mime-type type="application/x-spectrum-rzx">
+    <_comment>ZX Spectrum input recording (RZX)</_comment>
+    <magic priority="50">
+      <match value="RZX!\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.rzx"/>
+  </mime-type>
 
   <mime-type type="application/x-sfdu">
     <_comment>Standard Formatted Data Units (SFDUs) data</_comment>
@@ -5409,14 +6047,6 @@
     </magic>
     <sub-class-of type="application/x-sqlite3"/>
   </mime-type>
-  <mime-type type="application/x-fossil-checkout">
-    <magic priority="60">
-      <match value="SQLite format 3\x00" type="string" offset="0">
-        <match value="0x0f055112" type="string" offset="68"/>
-      </match>
-    </magic>
-    <sub-class-of type="application/x-sqlite3"/>
-  </mime-type>
   <mime-type type="application/x-fossil-global-conf">
     <magic priority="60">
       <match value="SQLite format 3\x00" type="string" offset="0">
@@ -5457,6 +6087,16 @@
     </magic>
     <sub-class-of type="application/x-sqlite3"/>
   </mime-type>
+  <mime-type type="application/x-mozlz4">
+    <_comment>Mozilla LZ4 (Firefox jsonlz4/mozlz4)</_comment>
+    <alias type="application/x-lz4+json"/>
+    <magic priority="50">
+      <match value="mozLz40\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.jsonlz4"/>
+    <glob pattern="*.mozlz4"/>
+    <glob pattern="*.baklz4"/>
+  </mime-type>
   <mime-type type="application/x-esri-spatially-enabled-db">
     <magic priority="60">
       <match value="SQLite format 3\x00" type="string" offset="0">
@@ -5481,6 +6121,26 @@
     </magic>
     <sub-class-of type="application/x-sqlite3"/>
   </mime-type>
+
+  <mime-type type="application/vnd.squashfs">
+    <alias type="application/x-squashfs"/>
+    <_comment>SquashFS filesystem image</_comment>
+    <magic priority="50">
+      <!-- superblock magic, then s_major (2-4) at offset 28 in the same byte 
order -->
+      <match value="hsqs" type="string" offset="0">
+        <match value="0x0400" type="string" offset="28"/>
+        <match value="0x0300" type="string" offset="28"/>
+        <match value="0x0200" type="string" offset="28"/>
+      </match>
+      <match value="sqsh" type="string" offset="0">
+        <match value="0x0004" type="string" offset="28"/>
+        <match value="0x0003" type="string" offset="28"/>
+        <match value="0x0002" type="string" offset="28"/>
+      </match>
+    </magic>
+    <glob pattern="*.sqsh"/>
+    <glob pattern="*.squashfs"/>
+  </mime-type>
   <mime-type type="application/x-stata-do">
     <_comment>Stata DTA Script</_comment>
     <acronym>DO</acronym>
@@ -5536,6 +6196,9 @@
   <mime-type type="application/x-stuffit">
     <magic priority="50">
       <match value="StuffIt" type="string" offset="0"/>
+      <match value="SIT!" type="string" offset="0">
+        <match value="rLau" type="string" offset="10"/>
+      </match>
     </magic>
     <glob pattern="*.sit"/>
   </mime-type>
@@ -5610,6 +6273,32 @@
     </magic>
     <!-- do we want to use this for such a rare format?   <glob 
pattern="*.rpy"/> -->
   </mime-type>
+  <mime-type type="application/x-trainz-cdp">
+    <_comment>Trainz content package</_comment>
+    <magic priority="50">
+      <match value="ACS$\x01\x00\x00\x00\x00\x00\x00\x00" type="string" 
offset="0"/>
+    </magic>
+    <glob pattern="*.cdp"/>
+  </mime-type>
+
+  <mime-type type="application/x-ubi-image">
+    <_comment>UBI flash image</_comment>
+    <magic priority="50">
+      <!-- erase-count header, version 1 -->
+      <match value="UBI#\x01" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.ubi"/>
+  </mime-type>
+
+  <mime-type type="application/x-uboot-image">
+    <_comment>U-Boot legacy image</_comment>
+    <magic priority="50">
+      <!-- magic, then OS, architecture, image type and compression codes at 
offset 28 -->
+      <match value="0x27051956" type="string" offset="0">
+        <match 
value="(?s).{28}[\\x00-\\x18][\\x00-\\x1a][\\x00-\\x18][\\x00-\\x05]" 
type="regex" offset="0"/>
+      </match>
+    </magic>
+  </mime-type>
 
   <!-- =================================================================== -->
   <!-- Microsoft Office binary file formats                                -->
@@ -5689,6 +6378,30 @@
     </magic>
     <glob pattern="*.uc2"/>
   </mime-type>
+
+  <mime-type type="application/x-ucsc-2bit">
+    <_comment>UCSC 2bit sequence</_comment>
+    <magic priority="50">
+      <!-- 0x1A412743 in either byte order, then version 0 or 1 (64-bit 
offsets) -->
+      <match value="0x4327411A00000000" mask="0xFFFFFFFFFEFFFFFF" 
type="string" offset="0"/>
+      <match value="0x1A41274300000000" mask="0xFFFFFFFFFFFFFFFE" 
type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.2bit"/>
+  </mime-type>
+  <mime-type type="application/x-unreal-uz">
+    <_comment>Unreal Tournament compressed package</_comment>
+    <magic priority="50">
+      <!-- UZ (1234) or UZ2 (5678), then the original file name: compact 
length, name, NUL -->
+      <match value="0xD2040000" type="string" offset="0">
+        <match value="(?s)[\\x02-\\x3f][\\x20-\\x7e]{1,63}\\.u[a-z]{0,2}\\x00" 
type="regex" offset="4"/>
+      </match>
+      <match value="0x2E160000" type="string" offset="0">
+        <match value="(?s)[\\x02-\\x3f][\\x20-\\x7e]{1,63}\\.u[a-z]{0,2}\\x00" 
type="regex" offset="4"/>
+      </match>
+    </magic>
+    <glob pattern="*.uz"/>
+    <glob pattern="*.uz2"/>
+  </mime-type>
   <mime-type type="application/x-ustar">
     <glob pattern="*.ustar"/>
   </mime-type>
@@ -5716,6 +6429,15 @@
     <sub-class-of type="application/x-bplist"/>
     <glob pattern="*.webarchive"/>
   </mime-type>
+  <mime-type type="application/x-wfdb-annotation">
+    <_comment>PhysioNet WFDB annotation</_comment>
+    <magic priority="50">
+      <!-- NOTE annotation (type 22) carrying the "## time resolution" aux 
string -->
+      <match value="0x0058" type="string" offset="0">
+        <match value="## time resolution: " type="string" offset="4"/>
+      </match>
+    </magic>
+  </mime-type>
 
   <mime-type type="application/x-x509-cert">
     <alias type="application/x-x509-ca-cert"/>
@@ -5732,6 +6454,13 @@
   <mime-type type="application/x-x509-cert;format=der">
     <sub-class-of type="application/x-x509-cert"/>
     <glob pattern="*.der"/>
+    <magic priority="50">
+      <!-- Certificate { TBSCertificate { [0] version v1-v3, serialNumber 
INTEGER ...
+           any signature algorithm (SM2, Ed25519, ...) -->
+      <match value="0x3080" mask="0xFFFC" type="string" offset="0">
+        <match 
value="(?s)\\x30(?:\\x81.|\\x82..|\\x83...)\\x30(?:\\x81.|\\x82..|\\x83...)\\xa0\\x03\\x02\\x01[\\x00-\\x02]\\x02"
 type="regex" offset="0"/>
+      </match>
+    </magic>
     <magic priority="50">
       <match value="0x3080" type="string"
               mask="0xFFF8" offset="0">
@@ -5814,6 +6543,39 @@
 <!-- <glob pattern="*.xmap"/> -->
   </mime-type>
 
+  <mime-type type="application/x-vcdiff">
+    <_comment>VCDIFF delta (RFC 3284)</_comment>
+    <magic priority="50">
+      <!-- header bytes, version 0, then Hdr_Indicator with only its low 3 
bits defined -->
+      <match value="0xD6C3C40000" mask="0xFFFFFFFFF8" type="string" 
offset="0"/>
+      <!-- open-vcdiff's SDCH interleaved format puts 'S' in the version byte 
-->
+      <match value="0xD6C3C45300" mask="0xFFFFFFFFF8" type="string" 
offset="0"/>
+    </magic>
+    <glob pattern="*.vcdiff"/>
+  </mime-type>
+  <mime-type type="application/x-warcraft3-map">
+    <_comment>Warcraft III map</_comment>
+    <sub-class-of type="application/x-mpq"/>
+    <magic priority="50">
+      <match value="HM3W\x00\x00\x00\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.w3m"/>
+    <glob pattern="*.w3x"/>
+  </mime-type>
+  <mime-type type="application/x-warcraft3-replay">
+    <_comment>Warcraft III replay</_comment>
+    <magic priority="50">
+      <match value="Warcraft III recorded game\x1a" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.w3g"/>
+  </mime-type>
+  <mime-type type="application/x-xdelta">
+    <_comment>Xdelta 1 patch</_comment>
+    <magic priority="50">
+      <match value="%XDZ00" type="string" offset="0"/>
+    </magic>
+  </mime-type>
+
   <mime-type type="application/x-xz">
     <glob pattern="*.xz"/>
     <magic priority="50">
@@ -5833,6 +6595,13 @@
     </magic>
     <glob pattern="*.zoo"/>
   </mime-type>
+  <mime-type type="application/x-zsync">
+    <_comment>zsync control file</_comment>
+    <magic priority="50">
+      <match value="zsync: " type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.zsync"/>
+  </mime-type>
 
   <mime-type type="application/x400-bp"/>
   <mime-type type="application/xcap-att+xml"/>
@@ -5883,6 +6652,12 @@
     <magic priority="30">
       <match value="&lt;!--" type="string" offset="0"/>
     </magic>
+    <!-- ties the text/html fragment rule (which sorts first) so a .xml name 
can pick XML -->
+    <magic priority="15">
+      <match value="&lt;" type="string" offset="0">
+        <match 
value="(?i)&lt;/?(meta|script|p|br|table|font|center|small|img|a|b)[\\s>/]" 
type="regex" offset="0"/>
+      </match>
+    </magic>
     <glob pattern="*.xml"/>
     <glob pattern="*.xsl"/>
     <glob pattern="*.xsd"/>
@@ -6245,6 +7020,24 @@
     <glob pattern="*.gslib"/>
     <glob pattern="*.minigsf"/>
   </mime-type>
+  <mime-type type="audio/x-rex2">
+    <_comment>Propellerhead ReCycle REX2 loop</_comment>
+    <magic priority="50">
+      <match value="CAT " type="string" offset="0">
+        <match value="REX2HEAD" type="string" offset="8"/>
+      </match>
+    </magic>
+    <glob pattern="*.rx2"/>
+  </mime-type>
+  <mime-type type="audio/x-s3m">
+    <_comment>Scream Tracker 3 module</_comment>
+    <magic priority="50">
+      <match value="0x1A10" type="string" offset="28">
+        <match value="SCRM" type="string" offset="44"/>
+      </match>
+    </magic>
+    <glob pattern="*.s3m"/>
+  </mime-type>
   <mime-type type="audio/x-sap">
     <_comment>Slight Atari Player</_comment>
     <tika:link>https://asap.sourceforge.net/sap-format.html</tika:link>
@@ -6253,6 +7046,32 @@
     </magic>
     <glob pattern="*.sap"/>
   </mime-type>
+  <mime-type type="audio/x-soundfont">
+    <_comment>SoundFont 2 bank</_comment>
+    <alias type="audio/x-sfbk"/>
+    <magic priority="50">
+      <match value="RIFF" type="string" offset="0">
+        <match value="sfbk" type="string" offset="8"/>
+      </match>
+    </magic>
+    <glob pattern="*.sf2"/>
+  </mime-type>
+
+  <mime-type type="audio/x-ym">
+    <_comment>YM Atari ST / Amstrad CPC chiptune</_comment>
+    <magic priority="50">
+      <match value="LeOnArD!" type="string" offset="4">
+        <match value="YM4!" type="string" offset="0"/>
+        <match value="YM5!" type="string" offset="0"/>
+        <match value="YM6!" type="string" offset="0"/>
+      </match>
+      <!-- older raw register dumps have no signature -->
+      <match value="YM2!" type="string" offset="0"/>
+      <match value="YM3!" type="string" offset="0"/>
+      <match value="YM3b" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.ym"/>
+  </mime-type>
   <mime-type type="audio/x-oggflac">
     <_comment>Ogg Packaged Free Lossless Audio Codec</_comment>
     <alias type="audio/x-ogg-flac"/>
@@ -6309,9 +7128,19 @@
   <mime-type type="audio/pcmu"/>
 
   <mime-type type="audio/prs.sid">
+    <_comment>Commodore 64 SID tune</_comment>
     <magic priority="50">
-      <match value="PSID" type="string" offset="0"/>
+      <!-- PSID/RSID, then version 1-4 -->
+      <match value="PSID\x00\x01" type="string" offset="0"/>
+      <match value="PSID\x00\x02" type="string" offset="0"/>
+      <match value="PSID\x00\x03" type="string" offset="0"/>
+      <match value="PSID\x00\x04" type="string" offset="0"/>
+      <match value="RSID\x00\x02" type="string" offset="0"/>
+      <match value="RSID\x00\x03" type="string" offset="0"/>
+      <match value="RSID\x00\x04" type="string" offset="0"/>
     </magic>
+    <glob pattern="*.sid"/>
+    <glob pattern="*.psid"/>
   </mime-type>
 
   <mime-type type="audio/qcelp"/>
@@ -6383,6 +7212,17 @@
   <mime-type type="audio/vnd.sealedmedia.softseal.mpeg"/>
   <mime-type type="audio/vnd.vmx.cvsd"/>
   <mime-type type="audio/vorbis-config"/>
+  <mime-type type="audio/x-ape">
+    <_comment>Monkey's Audio</_comment>
+    <magic priority="50">
+      <!-- then format version 3.80-4.xx -->
+      <match value="MAC " type="string" offset="0">
+        <match value="0x0E" type="string" offset="5"/>
+        <match value="0x0F" type="string" offset="5"/>
+      </match>
+    </magic>
+    <glob pattern="*.ape"/>
+  </mime-type>
   <mime-type type="audio/x-aac">
     <alias type="audio/aac"/>
     <glob pattern="*.aac"/>
@@ -6566,6 +7406,36 @@
   <mime-type type="chemical/x-xyz">
     <glob pattern="*.xyz"/>
   </mime-type>
+
+  <mime-type type="font/woff">
+    <alias type="application/font-woff"/>
+    <alias type="application/x-font-woff"/>
+    <acronym>WOFF</acronym>
+    <_comment>Web Open Font Format</_comment>
+    <tika:link>https://www.w3.org/TR/WOFF/</tika:link>
+    <magic priority="50">
+      <match value="wOFF" type="string" offset="0">
+        <match value="0x00010000" type="string" offset="4"/>
+        <match value="OTTO" type="string" offset="4"/>
+        <match value="true" type="string" offset="4"/>
+      </match>
+    </magic>
+    <glob pattern="*.woff"/>
+  </mime-type>
+  <mime-type type="font/woff2">
+    <alias type="application/font-woff2"/>
+    <acronym>WOFF2</acronym>
+    <_comment>Web Open Font Format 2</_comment>
+    <tika:link>https://www.w3.org/TR/WOFF2/</tika:link>
+    <magic priority="50">
+      <match value="wOF2" type="string" offset="0">
+        <match value="0x00010000" type="string" offset="4"/>
+        <match value="OTTO" type="string" offset="4"/>
+        <match value="true" type="string" offset="4"/>
+      </match>
+    </magic>
+    <glob pattern="*.woff2"/>
+  </mime-type>
   <mime-type type="image/x-3ds">
     <_comment>3D Studio (V1)</_comment>
     <magic priority="50">
@@ -6755,6 +7625,7 @@
   </mime-type>
   <mime-type type="image/heif-sequence">
     <_comment>HEIF Sequence - High Efficiency Image Sequence</_comment>
+    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
     <magic priority="60">
       <match value="ftypmsf1" type="string" offset="4"/>
     </magic>
@@ -6765,6 +7636,7 @@
     <alias   type="image/hevc"/>
     <_comment>HEIF Image using HEVC Codec</_comment>
     <acronym>HEIC</acronym>
+    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
     <magic priority="60">
       <match value="ftypheic" type="string" offset="4"/>
       <match value="ftypheix" type="string" offset="4"/>
@@ -6776,6 +7648,7 @@
     <alias   type="image/hevc-sequence"/>
     <_comment>HEIF Sequence using HEVC Codec</_comment>
     <acronym>HEVC</acronym>
+    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
     <magic priority="60">
       <match value="ftyphevc" type="string" offset="4"/>
       <match value="ftyphevx" type="string" offset="4"/>
@@ -7076,6 +7949,16 @@
   </mime-type>
 
   <mime-type type="image/vnd.mix"/>
+
+  <mime-type type="image/vnd.ms-dds">
+    <alias type="image/x-dds"/>
+    <_comment>DirectDraw Surface</_comment>
+    <magic priority="50">
+      <!-- magic, then the 124-byte header size -->
+      <match value="DDS \x7c\x00\x00\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.dds"/>
+  </mime-type>
   <mime-type type="image/vnd.ms-modi">
        <glob pattern="*.mdi"/>
        <_comment>Microsoft Document Imaging</_comment>
@@ -7136,38 +8019,6 @@
     <glob pattern="*.webp"/>
   </mime-type>
 
-  <mime-type type="image/heic">
-    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
-    <magic priority="50">
-      <match value="ftypheic" type="string" offset="4"/>
-      <match value="ftypheix" type="string" offset="4"/>
-    </magic>
-    <glob pattern="*.heic"/>
-  </mime-type>
-
-  <mime-type type="image/heif">
-    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
-    <magic priority="50">
-      <match value="ftypmif1" type="string" offset="4"/>
-    </magic>
-    <glob pattern="*.heif"/>
-  </mime-type>
-
-  <mime-type type="image/heif-sequence">
-    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
-    <magic priority="50">
-      <match value="ftypmsf1" type="string" offset="4"/>
-    </magic>
-  </mime-type>
-
-  <mime-type type="image/heic-sequence">
-    
<tika:link>https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format</tika:link>
-    <magic priority="50">
-      <match value="ftyphevc" type="string" offset="4"/>
-      <match value="ftyphevx" type="string" offset="4"/>
-    </magic>
-  </mime-type>
-
   <mime-type type="image/wmf">
     <alias type="image/x-wmf"/>
     <alias type="application/x-msmetafile"/>
@@ -7258,6 +8109,15 @@
     </magic>
     <glob pattern="*.jxl"/>
   </mime-type>
+  <mime-type type="image/jxr">
+    <_comment>JPEG XR (HD Photo)</_comment>
+    <magic priority="50">
+      <match value="0x4949BC01" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.jxr"/>
+    <glob pattern="*.wdp"/>
+    <glob pattern="*.hdp"/>
+  </mime-type>
 
   <mime-type type="image/x-niff">
     <_comment>Navy Interchange File Format</_comment>
@@ -7266,6 +8126,14 @@
     </magic>
   </mime-type>
 
+  <mime-type type="image/x-paintshoppro">
+    <_comment>Paint Shop Pro image</_comment>
+    <magic priority="50">
+      <match value="Paint Shop Pro Image File\x0a\x1a" type="string" 
offset="0"/>
+    </magic>
+    <glob pattern="*.pspimage"/>
+  </mime-type>
+
   <mime-type type="image/x-pict">
     <_comment>Apple Macintosh QuickDraw/PICT Format</_comment>
     <magic priority="50">
@@ -7338,6 +8206,14 @@
     </magic>
     <glob pattern="*.ppm"/>
   </mime-type>
+  <mime-type type="image/x-quake-sprite">
+    <_comment>Quake (v1) / Half-Life (v2) sprite</_comment>
+    <magic priority="50">
+      <match value="IDSP\x01\x00\x00\x00" type="string" offset="0"/>
+      <match value="IDSP\x02\x00\x00\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.spr"/>
+  </mime-type>
   <mime-type type="image/x-portable-arbitrarymap">
     <sub-class-of type="image/x-portable-anymap"/>
     <acronym>PAM</acronym>
@@ -7767,6 +8643,13 @@
     <glob pattern="*.e57"/>
   </mime-type>
   <mime-type type="model/example"/>
+  <mime-type type="model/gltf-binary">
+    <_comment>glTF binary</_comment>
+    <magic priority="50">
+      <match value="glTF\x02\x00\x00\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.glb"/>
+  </mime-type>
   <mime-type type="model/iges">
     <_comment>Initial Graphics Exchange Specification Format</_comment>
     <glob pattern="*.igs"/>
@@ -8006,6 +8889,13 @@
       <match value="(?i)&lt;(html|head|body|title|div)[ >]" type="regex" 
offset="0"/>
       <match value="(?i)&lt;h[123][ >]" type="regex" offset="0"/>
     </magic>
+    <!-- fragments served as pages: meta-first, PHP warnings, partials; below 
the weak
+         %PDF-/xhtml matches so a PDF or XHTML with a junk HTML prefix keeps 
its type -->
+    <magic priority="15">
+      <match value="&lt;" type="string" offset="0">
+        <match 
value="(?i)&lt;/?(meta|script|p|br|table|font|center|small|img|a|b)[\\s>/]" 
type="regex" offset="0"/>
+      </match>
+    </magic>
     <!-- The magic priority needs to be lower than that of -->
     <!--  files which contain HTML within them, eg mime emails -->
     <magic priority="40">
@@ -8967,7 +9857,32 @@
 
   <mime-type type="video/mp1s"/>
   <mime-type type="video/mp2p"/>
-  <mime-type type="video/mp2t"/>
+  <mime-type type="video/mp2t">
+    <magic priority="50">
+      <!-- sync byte on five consecutive 188-byte packets, or 192-byte M2TS 
packets -->
+      <match value="0x47" type="string" offset="0">
+        <match value="0x47" type="string" offset="188">
+          <match value="0x47" type="string" offset="376">
+            <match value="0x47" type="string" offset="564">
+              <match value="0x47" type="string" offset="752"/>
+            </match>
+          </match>
+        </match>
+      </match>
+      <match value="0x47" type="string" offset="4">
+        <match value="0x47" type="string" offset="196">
+          <match value="0x47" type="string" offset="388">
+            <match value="0x47" type="string" offset="580">
+              <match value="0x47" type="string" offset="772"/>
+            </match>
+          </match>
+        </match>
+      </match>
+    </magic>
+    <!-- not *.ts (TypeScript) or *.mts (model/vnd.mts) -->
+    <glob pattern="*.m2ts"/>
+    <glob pattern="*.m2t"/>
+  </mime-type>
 
   <mime-type type="video/mp4">
     <magic priority="60">
@@ -9150,10 +10065,21 @@
   </mime-type>
 
   <mime-type type="video/x-flc">
+    <magic priority="50">
+      <!-- frame type, then 8-bit depth -->
+      <match value="0xAF12" type="little16" offset="4">
+        <match value="0x0008" type="little16" offset="12"/>
+      </match>
+    </magic>
     <glob pattern="*.flc"/>
   </mime-type>
 
   <mime-type type="video/x-fli">
+    <magic priority="50">
+      <match value="0xAF11" type="little16" offset="4">
+        <match value="0x0008" type="little16" offset="12"/>
+      </match>
+    </magic>
     <glob pattern="*.fli"/>
   </mime-type>
 
@@ -9194,11 +10120,24 @@
        <match value="0x3026b275" type="big32" offset="0" />
     </magic>
   </mime-type>
+  <mime-type type="application/x-ms-reader">
+    <_comment>Microsoft Reader eBook</_comment>
+    <magic priority="50">
+      <match value="ITOLITLS\x01\x00\x00\x00" type="string" offset="0"/>
+    </magic>
+    <glob pattern="*.lit"/>
+  </mime-type>
   <mime-type type="application/x-ms-asx">
     <_comment>Windows Media Metafile</_comment>
     <glob pattern="*.asx"/>
     <root-XML localName="asx"/>
     <root-XML localName="ASX"/>
+    <!-- often no XML declaration -->
+    <magic priority="50">
+      <match value="&lt;" type="string" offset="0">
+        <match value="(?i)&lt;asx[\\s>]" type="regex" offset="0"/>
+      </match>
+    </magic>
     <sub-class-of type="application/xml"/>
   </mime-type>
   <mime-type type="video/x-ms-wm">
@@ -9264,6 +10203,16 @@
     <sub-class-of type="application/x-matroska"/>
     <glob pattern="*.mka" />
   </mime-type>
+  <mime-type type="audio/x-mfi">
+    <_comment>i-mode MFi melody</_comment>
+    <magic priority="50">
+      <!-- then lengths, types, track count and the first chunk name -->
+      <match value="melo" type="string" offset="0">
+        <match value="[a-z]{4}" type="regex" offset="13"/>
+      </match>
+    </magic>
+    <glob pattern="*.mld"/>
+  </mime-type>
 
   <mime-type type="video/webm">
     <sub-class-of type="application/x-matroska"/>
diff --git 
a/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java 
b/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
index 7dd0178127..3c9d3a3e11 100644
--- a/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
+++ b/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
@@ -204,6 +204,216 @@ public class MimeDetectionTest {
         assertEquals(ani, detect(acon, "pointer.cur"));
     }
 
+    @Test
+    public void testWoffDetection() throws Exception {
+        assertDetected(MediaType.parse("font/woff"), header(0, 
"wOFF\u0000\u0001\u0000\u0000"));
+        assertDetected(MediaType.parse("font/woff"), header(0, "wOFFOTTO"));
+        assertDetected(MediaType.parse("font/woff2"), header(0, 
"wOF2\u0000\u0001\u0000\u0000"));
+        assertDetected(MediaType.OCTET_STREAM, header(0, "wOFFxxxx"));
+    }
+
+    @Test
+    public void testSquashfsDetection() throws Exception {
+        MediaType squashfs = MediaType.application("vnd.squashfs");
+        byte[] le = header(0, "hsqs");
+        le[28] = 4;
+        assertDetected(squashfs, le);
+        byte[] be = header(0, "sqsh");
+        be[29] = 3;
+        assertDetected(squashfs, be);
+        // no plausible major version
+        assertDetected(MediaType.OCTET_STREAM, header(0, "hsqs"));
+    }
+
+    @Test
+    public void testAdobeSwatchExchangeDetection() throws Exception {
+        assertDetected(MediaType.application("x-adobe-swatch-exchange"),
+                header(0, "ASEF\u0000\u0001\u0000\u0000"));
+        assertDetected(MediaType.OCTET_STREAM, header(0, 
"ASEF\u0000\u0002\u0000\u0000"));
+    }
+
+    @Test
+    public void testPalmDocDetection() throws Exception {
+        assertDetected(MediaType.application("x-aportisdoc"), header(60, 
"TEXtREAd"));
+        assertDetected(MediaType.application("x-mobipocket-ebook"), header(60, 
"BOOKMOBI"));
+    }
+
+    @Test
+    public void testBinaryPgpSignatureDetection() throws Exception {
+        MediaType sig = MediaType.application("pgp-signature");
+        // v4, binary sig type, RSA, SHA-256; 2-byte length
+        assertDetected(sig, bytes(0x89, 0x01, 0x1c, 0x04, 0x00, 0x01, 0x08, 
0x00));
+        // v4, text sig type, EdDSA; 1-byte length
+        assertDetected(sig, bytes(0x88, 0x75, 0x04, 0x01, 0x16, 0x08, 0x00));
+        // v3, hashed length 5
+        assertDetected(sig, bytes(0x88, 0x3f, 0x03, 0x05, 0x00, 0x3f, 0xc0));
+        // unknown public-key algorithm
+        assertDetected(MediaType.OCTET_STREAM, bytes(0x89, 0x01, 0x1c, 0x04, 
0x00, 0x07, 0x08));
+        // new-format packets (RFC 9580 4.2): v6 Ed25519 SHA-512 with a 4-byte 
hashed length; v4 RSA
+        assertDetected(sig, bytes(0xc2, 0x75, 0x06, 0x00, 0x1b, 0x0a, 0x00, 
0x00, 0x00, 0x29));
+        assertDetected(sig, bytes(0xc2, 0xc0, 0x1c, 0x04, 0x00, 0x01, 0x08, 
0x00));
+        // direct-key self-signature, not a detached one
+        assertDetected(MediaType.OCTET_STREAM, bytes(0xc2, 0x75, 0x06, 0x1f, 
0x1b, 0x0a, 0x00));
+        assertDetected(MediaType.image("png"),
+                bytes(0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 
0x0d, 'I', 'H', 'D', 'R'));
+    }
+
+    @Test
+    public void testEmbeddedOpenTypeVersions() throws Exception {
+        MediaType eot = MediaType.application("vnd.ms-fontobject");
+        for (int[] version : new int[][]{{0, 0, 1, 0}, {1, 0, 2, 0}, {2, 0, 2, 
0}}) {
+            byte[] b = header(34, "LP");
+            for (int i = 0; i < 4; i++) {
+                b[8 + i] = (byte) version[i];
+            }
+            assertDetected(eot, b);
+        }
+    }
+
+    @Test
+    public void testBitTorrentFirstKeys() throws Exception {
+        MediaType torrent = MediaType.application("x-bittorrent");
+        assertDetected(torrent, 
"d8:announce35:udp://tracker".getBytes(US_ASCII));
+        assertDetected(torrent, 
"d13:announce-listll35:udp".getBytes(US_ASCII));
+        assertDetected(torrent, "d7:comment5:hello4:infod".getBytes(US_ASCII));
+        assertDetected(torrent, "d4:infod6:lengthi1024e".getBytes(US_ASCII));
+    }
+
+    @Test
+    public void testMxfDetection() throws Exception {
+        assertDetected(MediaType.application("mxf"),
+                bytes(0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0d, 
0x01, 0x02, 0x01,
+                        0x01, 0x02, 0x04, 0x00));
+    }
+
+    @Test
+    public void testJavaSerializationDetection() throws Exception {
+        MediaType ser = MediaType.application("java-serialized-object");
+        assertDetected(ser, bytes(0xac, 0xed, 0x00, 0x05, 0x73, 0x72, 0x00, 
0x10));
+        assertDetected(ser, bytes(0xac, 0xed, 0x00, 0x05, 0x77, 0x04));
+        assertDetected(MediaType.OCTET_STREAM, bytes(0xac, 0xed, 0x53, 0xab, 
0x49));
+    }
+
+    @Test
+    public void testHtmlFragmentDetection() throws Exception {
+        for (String s : new String[]{
+                "<meta http-equiv=\"Content-Type\" content=\"text/html\">",
+                "<br />\n<b>Warning</b>:  filesize()",
+                "<p><a href='http://example.com'>x</a>",
+                "</b> <br>\n<font face=Arial>",
+                "<script type='text/javascript'>\nvar x = 1;",
+                "<SMALL>x</SMALL>"}) {
+            assertDetected(MediaType.TEXT_HTML, s.getBytes(US_ASCII));
+        }
+        assertDetected(MediaType.TEXT_PLAIN, "<abbr 
title=x>".getBytes(US_ASCII));
+        assertDetected(MediaType.TEXT_PLAIN, "<bread> and 
butter".getBytes(US_ASCII));
+        // injected analytics in front of a real document
+        assertDetected(MediaType.application("pdf"),
+                "<script>\n  
(function(i,s,o,g,r,a,m){})\n</script>\n%PDF-1.4\n".getBytes(US_ASCII));
+        assertDetected(MediaType.application("xhtml+xml"),
+                ("<script src=\"urchin.js\"></script>\n" + "<!-- x 
-->\n".repeat(12)
+                        + "<html 
xmlns=\"http://www.w3.org/1999/xhtml\";>").getBytes(US_ASCII));
+        // a .xml name still picks XML, except for roots text/html claims 
(TIKA-377)
+        byte[] table = "<table name=\"t\"><row 
id=\"1\"/></table>".getBytes(US_ASCII);
+        assertEquals(MediaType.APPLICATION_XML, detect(table, "test.xml"));
+        assertEquals(MediaType.TEXT_HTML, detect(table, "test.html"));
+        assertEquals(MediaType.TEXT_HTML, detect(table, null));
+        assertEquals(MediaType.TEXT_HTML, 
detect("<p>x</p>".getBytes(US_ASCII), "test.xml"));
+        assertEquals(MediaType.TEXT_HTML,
+                detect("<br />\n<b>Warning</b>: x".getBytes(US_ASCII), 
"test.php"));
+    }
+
+    @Test
+    public void testAsxWithoutXmlDeclaration() throws Exception {
+        MediaType asx = MediaType.application("x-ms-asx");
+        assertDetected(asx, "<ASX version = 
\"3.0\">\n<Entry>".getBytes(US_ASCII));
+        assertDetected(asx, "<Asx Version=\"3.0\"><Entry>".getBytes(US_ASCII));
+    }
+
+    @Test
+    public void testMpegTransportStream() throws Exception {
+        MediaType ts = MediaType.video("mp2t");
+        assertDetected(ts, packets(0, 188, 5));
+        assertDetected(ts, packets(4, 192, 5));
+        assertDetected(MediaType.OCTET_STREAM, packets(0, 188, 4));
+    }
+
+    @Test
+    public void testMarcWithBlankBibliographicLevel() throws Exception {
+        assertDetected(MediaType.application("marc"),
+                "01252na  a2200325   4500001001300000".getBytes(US_ASCII));
+    }
+
+    @Test
+    public void testDerCrlAndCertificateAnySignatureAlgorithm() throws 
Exception {
+        // v2 CRL signed with SM2 (OID 1.2.156.10197.1.501), long and short 
inner lengths
+        assertDetected(MediaType.application("pkix-crl"), bytes(0x30, 0x82, 
0x01, 0x17, 0x30, 0x81, 0xbe,
+                0x02, 0x01, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x81, 0x1c, 
0xcf, 0x55, 0x01, 0x83, 0x75));
+        assertDetected(MediaType.application("pkix-crl"), bytes(0x30, 0x81, 
0xa0, 0x30, 0x48,
+                0x02, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70));
+        // v1 CRL (no version field) from openssl ca -gencrl, 
ecdsa-with-SHA256, issuer CN=T
+        byte[] crlV1 = new byte[64];
+        byte[] crlHead = {0x30, (byte) 0x81, (byte) 0x91, 0x30, 0x38, 0x30, 
0x0a, 0x06, 0x08, 0x2a,
+                (byte) 0x86, 0x48, (byte) 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 
0x0c, 0x31, 0x0a, 0x30, 0x08,
+                0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x01, 0x54, 0x17, 0x0d};
+        System.arraycopy(crlHead, 0, crlV1, 0, crlHead.length);
+        System.arraycopy("261105180134Z".getBytes(US_ASCII), 0, crlV1, 
crlHead.length, 13);
+        assertDetected(MediaType.application("pkix-crl"), crlV1);
+        // v3 certificate, then serialNumber
+        assertDetected(MediaType.parse("application/x-x509-cert;format=der"), 
bytes(0x30, 0x82, 0x0a, 0x5d,
+                0x30, 0x82, 0x0a, 0x0c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 
0x11, 0x00));
+        // v1 certificate with serial 1 opens like a v2 CRL; its validity 
tells them apart
+        byte[] v1 = new byte[128];
+        byte[] head = {0x30, (byte) 0x82, 0x02, 0x7c, 0x30, (byte) 0x81, 
(byte) 0xe5, 0x02, 0x01, 0x01,
+                0x30, 0x0d, 0x06, 0x09, 0x2a, (byte) 0x86, 0x48, (byte) 0x86, 
(byte) 0xf7, 0x0d, 0x01, 0x01,
+                0x0b, 0x05, 0x00, 0x30, 0x0b, 0x31, 0x09, 0x30, 0x07, 0x06, 
0x03, 0x55, 0x04, 0x03, 0x0c, 0x00,
+                0x30, 0x1e, 0x17, 0x0d};
+        System.arraycopy(head, 0, v1, 0, head.length);
+        
System.arraycopy("250101000000Z\u0017\r260101000000Z".getBytes(US_ASCII), 0, 
v1, head.length, 28);
+        assertDetected(MediaType.parse("application/x-x509-cert;format=der"), 
v1);
+        // RFC 3161 reply: granted, "Operation Okay", then the signedData token
+        byte[] tsr = bytes(0x30, 0x82, 0x0a, 0xb5, 0x30, 0x15, 0x02, 0x01, 
0x00, 0x30, 0x10, 0x0c, 0x0e);
+        System.arraycopy("Operation Okay".getBytes(US_ASCII), 0, tsr, 13, 14);
+        byte[] token = {0x30, (byte) 0x82, 0x0a, (byte) 0x9a, 0x06, 0x09, 
0x2a, (byte) 0x86, 0x48, (byte) 0x86,
+                (byte) 0xf7, 0x0d, 0x01, 0x07, 0x02};
+        System.arraycopy(token, 0, tsr, 27, token.length);
+        assertDetected(MediaType.application("timestamp-reply"), tsr);
+        // PKCS#10 request: version 0, then a Name, not an AlgorithmIdentifier
+        assertDetected(MediaType.OCTET_STREAM, bytes(0x30, 0x82, 0x01, 0x0a, 
0x30, 0x81, 0xb1,
+                0x02, 0x01, 0x00, 0x30, 0x46, 0x31, 0x0b));
+    }
+
+    private static byte[] packets(int first, int size, int count) {
+        byte[] b = new byte[1024];
+        for (int i = 0; i < count; i++) {
+            b[first + i * size] = 0x47;
+        }
+        return b;
+    }
+
+    @Test
+    public void testSubRipLineEndings() throws Exception {
+        MediaType srt = MediaType.application("x-subrip");
+        for (String eol : new String[]{"\n", "\r", "\r\n"}) {
+            assertDetected(srt, ("1" + eol + "00:00:01,000 --> 00:00:02,000" + 
eol + "Hi").getBytes(US_ASCII));
+        }
+    }
+
+    private static byte[] header(int offset, String ascii) {
+        byte[] header = new byte[128];
+        byte[] value = ascii.getBytes(US_ASCII);
+        System.arraycopy(value, 0, header, offset, value.length);
+        return header;
+    }
+
+    private static byte[] bytes(int... values) {
+        byte[] bytes = new byte[64];
+        for (int i = 0; i < values.length; i++) {
+            bytes[i] = (byte) values[i];
+        }
+        return bytes;
+    }
+
     private static byte[] tgaHeader(int idLength, int colourMapType, int 
imageType,
                                     int colourMapEntrySize, int pixelDepth) {
         byte[] header = new byte[64];
diff --git 
a/tika-core/src/test/java/org/apache/tika/mime/MimeTypesLintTest.java 
b/tika-core/src/test/java/org/apache/tika/mime/MimeTypesLintTest.java
new file mode 100644
index 0000000000..43e225bec2
--- /dev/null
+++ b/tika-core/src/test/java/org/apache/tika/mime/MimeTypesLintTest.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.mime;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.apache.tika.utils.XMLReaderUtils;
+
+/**
+ * Rules in tika-mimetypes.xml that load fine but can never match as written.
+ * Checks the raw XML: once decoded, a mistyped value is indistinguishable 
from an intended one.
+ */
+public class MimeTypesLintTest {
+
+    @Test
+    public void testDefaultMimeTypes() throws Exception {
+        try (InputStream is = 
MimeTypesReader.class.getResourceAsStream("tika-mimetypes.xml")) {
+            List<String> problems = lint(is);
+            assertTrue(problems.isEmpty(), String.join("\n", problems));
+        }
+    }
+
+    @Test
+    public void testLintCatchesEachProblem() throws Exception {
+        String xml = "<mime-info>" +
+                "<mime-type type=\"application/x-a\"><magic>" +
+                "<match value=\"0x310D0A13030\" type=\"string\" 
offset=\"0\"/>" +
+                "<match value=\"0x31zz\" type=\"string\" offset=\"0\"/>" +
+                "<match value=\"(?i)&lt;html[\\s&gt;]\" type=\"regex\" 
offset=\"0\"/>" +
+                "<match value=\"a\\db\" type=\"string\" offset=\"0\"/>" +
+                "<match value=\"0x0102\" mask=\"0xFF\" type=\"string\" 
offset=\"0\"/>" +
+                "<match value=\"x\" type=\"string\" offset=\"8:4\"/>" +
+                "<match value=\"x\" type=\"string\" offset=\"0:65536\"/>" +
+                "<match value=\"\\xd2\\x04\" type=\"regex\" offset=\"0\"/>" +
+                "</magic><sub-class-of 
type=\"application/x-undefined\"/></mime-type>" +
+                "<mime-type type=\"application/x-b\">" +
+                "<alias type=\"application/x-b-alias\"/><magic>" +
+                "<match value=\"(?i)&lt;html[\\\\s&gt;]\" type=\"regex\" 
offset=\"0\"/>" +
+                "<match value=\"\\\\xd2\\x04\" type=\"regex\" offset=\"0\"/>" +
+                "<match value=\"\\x00\\n\\\\a\\101\" type=\"string\" 
offset=\"0\"/>" +
+                "</magic><sub-class-of type=\"application/x-a\"/></mime-type>" 
+
+                "<mime-type type=\"application/x-c\"><sub-class-of 
type=\"application/x-b-alias\"/>" +
+                "</mime-type></mime-info>";
+        List<String> problems = lint(new 
ByteArrayInputStream(xml.getBytes(UTF_8)));
+        assertEquals(9, problems.size(), String.join("\n", problems));
+        for (String p : problems) {
+            assertTrue(p.startsWith("application/x-a "), p);
+        }
+    }
+
+    static List<String> lint(InputStream is) throws Exception {
+        Document doc = XMLReaderUtils.buildDOM(is);
+        NodeList types = doc.getElementsByTagName("mime-type");
+        Set<String> defined = new HashSet<>();
+        for (int i = 0; i < types.getLength(); i++) {
+            Element type = (Element) types.item(i);
+            defined.add(type.getAttribute("type").toLowerCase(Locale.ROOT));
+            for (Element alias : children(type, "alias")) {
+                
defined.add(alias.getAttribute("type").toLowerCase(Locale.ROOT));
+            }
+        }
+        List<String> problems = new ArrayList<>();
+        for (int i = 0; i < types.getLength(); i++) {
+            Element type = (Element) types.item(i);
+            String name = type.getAttribute("type");
+            for (Element parent : children(type, "sub-class-of")) {
+                String p = parent.getAttribute("type");
+                if (!defined.contains(p.toLowerCase(Locale.ROOT))) {
+                    problems.add(name + " sub-class-of undefined type " + p);
+                }
+            }
+            NodeList matches = type.getElementsByTagName("match");
+            for (int j = 0; j < matches.getLength(); j++) {
+                lintMatch(name, (Element) matches.item(j), problems);
+            }
+        }
+        return problems;
+    }
+
+    private static void lintMatch(String name, Element match, List<String> 
problems) {
+        String kind = match.hasAttribute("type") ? match.getAttribute("type") 
: "string";
+        String value = match.getAttribute("value");
+        String mask = match.getAttribute("mask");
+        String where = name + " match '" + value + "': ";
+        boolean bytewise = kind.startsWith("string") || kind.equals("regex");
+        if (value.startsWith("0x")) {
+            String hex = value.substring(2);
+            if (!hex.matches("[0-9A-Fa-f]*")) {
+                problems.add(where + "non-hex digit");
+            } else if (bytewise && hex.length() % 2 != 0) {
+                // decoding takes digit pairs and drops the last one
+                problems.add(where + "odd number of hex digits");
+            }
+            if (mask.startsWith("0x") && mask.length() != value.length()) {
+                problems.add(where + "mask and value differ in length");
+            }
+        } else {
+            for (int k = 0; k + 1 < value.length(); k++) {
+                if (value.charAt(k) != '\\') {
+                    continue;
+                }
+                char c = value.charAt(++k);
+                if (c == 'x' && kind.equals("regex") && k + 2 < value.length()
+                        && Integer.parseInt(value.substring(k + 1, k + 3), 16) 
>= 0x80) {
+                    // the pattern is compiled from UTF-8, so a raw high byte 
becomes U+FFFD
+                    problems.add(where + "\\x" + value.substring(k + 1, k + 3) 
+ " in a regex needs \\\\x");
+                }
+                if (c == '\\' || c == 'x' || c == 'n' || c == 'r' || c == 't' 
|| Character.isDigit(c)) {
+                    continue;
+                }
+                // the decoder keeps only c: "\s" is "s", "\." is "."; regex 
escapes need "\\"
+                if (kind.equals("regex") || Character.isLetter(c)) {
+                    problems.add(where + "escape \\" + c + " decodes to a bare 
'" + c + "'");
+                }
+            }
+        }
+        String offset = match.getAttribute("offset");
+        if (!offset.isEmpty()) {
+            String[] range = offset.split(":");
+            int start = Integer.parseInt(range[0].trim());
+            int end = range.length > 1 ? Integer.parseInt(range[1].trim()) : 
start;
+            if (end < start) {
+                problems.add(where + "offset range ends before it starts");
+            } else if (end >= 64 * 1024) {
+                problems.add(where + "offset beyond the bytes MimeTypes 
reads");
+            }
+        }
+    }
+
+    private static List<Element> children(Element parent, String tag) {
+        List<Element> out = new ArrayList<>();
+        NodeList nodes = parent.getElementsByTagName(tag);
+        for (int i = 0; i < nodes.getLength(); i++) {
+            out.add((Element) nodes.item(i));
+        }
+        return out;
+    }
+}
diff --git 
a/tika-core/src/test/java/org/apache/tika/mime/MimeTypesReaderTest.java 
b/tika-core/src/test/java/org/apache/tika/mime/MimeTypesReaderTest.java
index 6dd4d5d624..cee8d0497a 100644
--- a/tika-core/src/test/java/org/apache/tika/mime/MimeTypesReaderTest.java
+++ b/tika-core/src/test/java/org/apache/tika/mime/MimeTypesReaderTest.java
@@ -426,6 +426,41 @@ public class MimeTypesReaderTest {
         assertThrows(IllegalArgumentException.class, () -> 
MimeTypes.getDefaultMimeTypes(new CustomClassLoader()));
     }
 
+    @Test
+    public void testDuplicateDefinitionFailsLoad() {
+        String dup = "<mime-info><mime-type type=\"application/x-dup\"><glob 
pattern=\"*.dup\"/>"
+                + "</mime-type><mime-type 
type=\"application/x-dup\"/></mime-info>";
+        MimeTypeException e = assertThrows(MimeTypeException.class,
+                () -> MimeTypesFactory.create(stream(dup)));
+        assertTrue(e.getCause().getMessage().contains("application/x-dup"), 
e.getCause().getMessage());
+
+        // a second definition through an alias is the same type
+        String viaAlias = "<mime-info><mime-type type=\"application/x-dup\">"
+                + "<alias type=\"application/x-dup-alias\"/></mime-type>"
+                + "<mime-type type=\"application/x-dup-alias\"/></mime-info>";
+        assertThrows(MimeTypeException.class, () -> 
MimeTypesFactory.create(stream(viaAlias)));
+    }
+
+    @Test
+    public void testLaterFileMayExtendType() throws Exception {
+        String core = "<mime-info><mime-type type=\"application/x-dup\"><glob 
pattern=\"*.dup\"/>"
+                + "</mime-type></mime-info>";
+        String custom = "<mime-info><mime-type 
type=\"application/x-dup\"><glob pattern=\"*.dup2\"/>"
+                + "</mime-type></mime-info>";
+        MimeTypes types = MimeTypesFactory.create(stream(core), 
stream(custom));
+        assertEquals(List.of(".dup", ".dup2"), 
types.forName("application/x-dup").getExtensions());
+    }
+
+    @Test
+    public void testDefaultMimeTypesHaveNoDuplicates() throws Exception {
+        // fails the load, so reaching here is the assertion
+        assertNotNull(MimeTypesFactory.create("tika-mimetypes.xml"));
+    }
+
+    private static ByteArrayInputStream stream(String xml) {
+        return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+    }
+
     private static class CustomClassLoader extends ClassLoader {
     }
 }
diff --git 
a/tika-core/src/test/java/org/apache/tika/mime/NicheFormatDetectionTest.java 
b/tika-core/src/test/java/org/apache/tika/mime/NicheFormatDetectionTest.java
new file mode 100644
index 0000000000..cac379a631
--- /dev/null
+++ b/tika-core/src/test/java/org/apache/tika/mime/NicheFormatDetectionTest.java
@@ -0,0 +1,364 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.mime;
+
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.ParseContext;
+
+/**
+ * Formats found as application/octet-stream in Common Crawl; headers are 
synthesized
+ * from the shapes seen there.
+ */
+public class NicheFormatDetectionTest {
+
+    private static final MimeTypes MIME_TYPES = 
MimeTypes.getDefaultMimeTypes();
+
+    @Test
+    public void testFec() throws Exception {
+        MediaType fec = MediaType.application("x-fec");
+        assertDetected(fec, "HDR\u001cFEC\u001c8.3\u001cCMDI CRIMSON 
FILER\u001c5.0\u001c\u001c\n");
+        assertTrue(MIME_TYPES.getMediaTypeRegistry().isSpecializationOf(fec, 
MediaType.TEXT_PLAIN));
+    }
+
+    @Test
+    public void testGarminGdb() throws Exception {
+        assertDetected(MediaType.application("x-garmin-gdb"),
+                "MsRcf\u0000\u0002\u0000\u0000\u0000Dm\u0000");
+    }
+
+    @Test
+    public void testGettextCatalog() throws Exception {
+        MediaType mo = MediaType.application("x-gettext-translation");
+        assertDetected(mo, 
"Þ\u0012\u0004\u0095\u0000\u0000\u0000\u0000\u008e\u0005\u0000\u0000");
+        assertDetected(mo, 
"\u0095\u0004\u0012Þ\u0000\u0000\u0000\u0000\u0000\u0000\u0005\u008e");
+        // minor revision 1: msgfmt output with system-dependent strings
+        assertDetected(mo, "Þ\u0012\u0004\u0095\u0001\u0000\u0000\u0000");
+        assertDetected(mo, "\u0095\u0004\u0012Þ\u0000\u0000\u0000\u0001");
+        // unknown revision
+        assertDetected(MediaType.OCTET_STREAM, 
"Þ\u0012\u0004\u0095\u0000\u0007\u0000\u0000");
+    }
+
+    @Test
+    public void testMpqAndWarcraft() throws Exception {
+        MediaType mpq = MediaType.application("x-mpq");
+        assertDetected(mpq, "MPQ\u001a \u0000\u0000\u0000");
+        assertDetected(mpq, "MPQ\u001b\u0000\u0002\u0000\u0000");
+        assertDetected(MediaType.OCTET_STREAM, 
"MPQ\u001a\u0099\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-warcraft3-map"), 
"HM3W\u0000\u0000\u0000\u0000Map");
+        assertDetected(MediaType.application("x-warcraft3-replay"),
+                "Warcraft III recorded game\u001a\u0000");
+    }
+
+    @Test
+    public void testBinaryDiffs() throws Exception {
+        MediaType vcdiff = MediaType.application("x-vcdiff");
+        assertDetected(vcdiff, "ÖÃÄ\u0000\u0005");
+        assertDetected(vcdiff, "ÖÃÄ\u0000\u0000");
+        // open-vcdiff SDCH interleaved format
+        assertDetected(vcdiff, "ÖÃÄS\u0000");
+        // undefined Hdr_Indicator bits
+        assertDetected(MediaType.OCTET_STREAM, "ÖÃÄ\u0000\u0010");
+        assertDetected(MediaType.application("x-xdelta"), 
"%XDZ004%\u0000\u0000");
+    }
+
+    @Test
+    public void testSid() throws Exception {
+        MediaType sid = MediaType.audio("prs.sid");
+        assertDetected(sid, "RSID\u0000\u0002\u0000|");
+        assertDetected(sid, "PSID\u0000\u0001\u0000v");
+        assertDetected(MediaType.OCTET_STREAM, "PSID\u0000\t\u0000v");
+    }
+
+    @Test
+    public void testPaintShopPro() throws Exception {
+        assertDetected(MediaType.image("x-paintshoppro"),
+                "Paint Shop Pro Image 
File\n\u001a\u0000\u0000\u0000\u0000\u0000");
+    }
+
+    @Test
+    public void testElastoManiaLevel() throws Exception {
+        MediaType lev = MediaType.application("x-elasto-mania-level");
+        assertDetected(lev, "POT14\u0000\u0000");
+        assertDetected(lev, "POT06\u0000\u0000");
+    }
+
+    @Test
+    public void testBinaryPgpKeys() throws Exception {
+        MediaType keys = MediaType.application("pgp-keys");
+        // public key, 2-byte length, RSA
+        assertDetected(keys, "\u0099\u0001\r\u0004ABCD\u0001");
+        // secret key, 1-byte length, EdDSA
+        assertDetected(keys, "\u0094X\u0004ABCD\u0016");
+        assertDetected(MediaType.OCTET_STREAM, 
"\u0099\u0001\r\u0004ABCD\u0007");
+        // new-format v6 Ed25519 public and secret keys, as in RFC 9580 A.3 
and A.4
+        assertDetected(keys, "Æ*\u0006c\u0087\u007fã\u001b\u0000\u0000\u0000 
");
+        assertDetected(keys, "ÅK\u0006c\u0087\u007fã\u001b\u0000\u0000\u0000 
");
+        // new-format v4 RSA public key, 2-byte length
+        assertDetected(keys, "ÆÁ\r\u0004ABCD\u0001");
+        assertDetected(MediaType.OCTET_STREAM, "Æ*\u0006c\u0087\u007fã\u0007");
+    }
+
+    @Test
+    public void testRetroArchivesAndGames() throws Exception {
+        assertDetected(MediaType.application("x-stuffit"), 
"SIT!\u0000\u0003\u0000$abrLau");
+        assertDetected(MediaType.application("vnd.symbian.install"), "z\u001a 
\u0010\u0000\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-ms-reader"), 
"ITOLITLS\u0001\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-lrzip"), "LRZI\u0000\u0006");
+        assertDetected(MediaType.application("x-glulx"), 
"Glul\u0000\u0003\u0001\u0000");
+        assertDetected(MediaType.video("x-flc"), 
"abcd\u0012¯\u0016\u0000ABCD\b\u0000");
+        assertDetected(MediaType.video("x-fli"), 
"abcd\u0011¯\u0016\u0000ABCD\b\u0000");
+    }
+
+    @Test
+    public void testAudioModulesAndApe() throws Exception {
+        assertDetected(MediaType.audio("x-ape"), "MAC \u0096\u000f4\u0000");
+        assertDetected(MediaType.audio("x-s3m"), "unknown" + 
"\u0000".repeat(21) + "\u001a\u0010"
+                + "\u0000".repeat(14) + "SCRM");
+    }
+
+    @Test
+    public void testMusicAndAudioFormats() throws Exception {
+        assertDetected(MediaType.application("x-nwc"), "[NWZ]\u0000xÚ");
+        assertDetected(MediaType.application("x-nwc"), "[NoteWorthy 
ArtWare]\u0000");
+        assertDetected(MediaType.application("x-finale"), "ENIGMA BINARY 
FILE\u0000");
+        assertDetected(MediaType.audio("x-rex2"), "CAT 
\u0000\t\u0000\u0000REX2HEAD");
+        assertDetected(MediaType.audio("x-mfi"), 
"melo\u0000\u0000\u0011#\u0000]\u0001\u0001\u0004vers");
+        assertDetected(MediaType.OCTET_STREAM, 
"melody\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000");
+    }
+
+    @Test
+    public void testGameAndConsoleFormats() throws Exception {
+        assertDetected(MediaType.application("x-gbx"), "GBX\u0006\u0000BUCR");
+        assertDetected(MediaType.application("x-gbx"), "GBX\u0003\u0000BUC");
+        assertDetected(MediaType.OCTET_STREAM, "GBX\t\u0000BUCR");
+        assertDetected(MediaType.application("x-ps3-package"), 
"\u007fPKG\u0080\u0000\u0000\u0001");
+        assertDetected(MediaType.application("x-ps3-package"), 
"\u007fPKG\u0000\u0000\u0000\u0001");
+        assertDetected(MediaType.application("x-ps3-theme"), 
"P3TF\u0000\u0000\u0001\u0010");
+        assertDetected(MediaType.application("x-trainz-cdp"), 
"ACS$\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-spectrum-rzx"), 
"RZX!\u0000\f");
+        assertDetected(MediaType.image("x-quake-sprite"), 
"IDSP\u0002\u0000\u0000\u0000");
+    }
+
+    @Test
+    public void testArchivesAndPackages() throws Exception {
+        assertDetected(MediaType.application("x-nufx"), "NõFélå§³");
+        assertDetected(MediaType.application("x-lzx"), 
"LZX\u0000\f\u0000\n\u0004");
+        assertDetected(MediaType.application("x-mikrotik-npk"), "\u001eñк");
+        assertDetected(MediaType.application("x-clamav-diff"), 
"ClamAV-Diff:119:526:");
+        assertDetected(MediaType.application("x-clamav-database"), 
"ClamAV-VDB:01 Jan 2020");
+    }
+
+    @Test
+    public void testCasioFxInterface() throws Exception {
+        StringBuilder fxi = new StringBuilder("20");
+        for (char c : "\u001fFX-INTERFACE - YELLOW COMPUTING".toCharArray()) {
+            fxi.append((char) (c ^ 0xe7));
+        }
+        assertDetected(MediaType.application("x-casio-fxi"), fxi.toString());
+    }
+
+    @Test
+    public void testModelAndCadFormats() throws Exception {
+        assertDetected(MediaType.parse("model/gltf-binary"), 
"glTF\u0002\u0000\u0000\u0000ð@\u001c\u0000");
+        assertDetected(MediaType.application("x-blender"), "BLENDER-v300REND");
+        assertDetected(MediaType.application("x-blender"), "BLENDER_v244REND");
+        // 5.0 header layout
+        assertDetected(MediaType.application("x-blender"), 
"BLENDER17-01v0500REND");
+        assertDetected(MediaType.application("x-fbx"), "Kaydara FBX Binary  
\u0000\u001a\u0000");
+        assertDetected(MediaType.application("x-jw-cad"), 
"JwwData.¼\u0002\u0000\u0000");
+        assertDetected(MediaType.application("x-fastcad"), "FCW (FastCAD for 
Windows) 6.20.0\r\n\u001a");
+        assertDetected(MediaType.application("x-source-bsp"), 
"VBSP\u0014\u0000\u0000\u0000");
+        assertDetected(MediaType.OCTET_STREAM, "VBSP\u0002\u0000\u0000\u0000");
+    }
+
+    @Test
+    public void testGameAudioAndDataFormats() throws Exception {
+        assertDetected(MediaType.application("x-unreal-uz"),
+                "Ò\u0004\u0000\u0000\u0011FCommandoReg.utx\u0000¡É");
+        assertDetected(MediaType.audio("x-soundfont"), 
"RIFF\u0000\u0010\u0000\u0000sfbkLIST");
+        assertDetected(MediaType.application("x-zsync"), "zsync: 
0.6.2\nFilename: x.tcz\n");
+        assertDetected(MediaType.application("x-wfdb-annotation"),
+                "\u0000X\u0017ü## time resolution: 250\u0000\u0000");
+    }
+
+    @Test
+    public void testPrinterJobs() throws Exception {
+        MediaType pcl = MediaType.application("vnd.hp-pcl");
+        MediaType pclxl = MediaType.application("vnd.hp-pclxl");
+        assertDetected(pclxl, "\u001b%-12345X@PJL COMMENT x\r\n@PJL ENTER 
LANGUAGE = PCLXL\r\n");
+        assertDetected(pclxl, ") HP-PCL XL;3;0;Comment");
+        assertDetected(pcl, "\u001b%-12345X@PJL JOB\r\n@PJL ENTER 
LANGUAGE=PCL\r\n\u001bE");
+        assertDetected(pcl, "\u001b%-12345X@PJL ENTER 
LANGUAGE=PCL\u001bE\u001b&l0O");
+        // driver headers can put the command past 1K
+        String longJob = "\u001b%-12345X" + "@PJL COMMENT 
padding\r\n".repeat(80) + "@PJL ENTER LANGUAGE=PCLXL\r\n";
+        try (TikaInputStream tis = 
TikaInputStream.get(longJob.getBytes(ISO_8859_1))) {
+            assertEquals(pclxl, MIME_TYPES.detect(tis, new Metadata(), new 
ParseContext()));
+        }
+        assertDetected(pcl, "\u001b%-12345X\u001bE\u001b&u600D");
+        assertDetected(pcl, "\u001bE\u001b&l0O\u001b&l0H");
+        assertDetected(MediaType.application("postscript"),
+                "\u001b%-12345X@PJL\r\n@PJL ENTER LANGUAGE = 
POSTSCRIPT\r\n%!PS");
+    }
+
+    @Test
+    public void testAfpDumpsAndMetafiles() throws Exception {
+        assertDetected(MediaType.application("vnd.ibm.modcap"), 
"Z\u0000\u0010\u0000\u0000");
+        assertDetected(MediaType.application("x-dmp"), 
"MDMP\u0093§\u0000\u0000");
+        assertDetected(MediaType.application("x-windows-kernel-dump"), 
"PAGEDU64DU64");
+        assertDetected(MediaType.image("x-svm"), "VCLMTF\u0001\u0000");
+        
assertDetected(MediaType.parse("application/vnd.lotus-1-2-3;version=97+9.x"),
+                "\u0000\u0000\u001a\u0000\u0005\u0010\u0004\u0000");
+    }
+
+    @Test
+    public void testIdentifiedCrawlClusters() throws Exception {
+        assertDetected(MediaType.application("x-promethean-flipchart"),
+                " Bamboo 
\u0007\u0000\u0006\u0000\u0000\u00001\u0000.\u00000\u0000");
+        StringBuilder casio = new StringBuilder();
+        for (char c : "USBPower1\u0000\u0010\u0000\u0010\u0000".toCharArray()) 
{
+            casio.append((char) (~c & 0xff));
+        }
+        assertDetected(MediaType.application("x-casio-g1m"), casio.toString());
+        assertDetected(MediaType.application("x-haihaisoft-drm"),
+                
"XDRM\u0000\u0000\u0000\n\u0000\u0003HEAD\u0000\u0000\u0000Ñ\u0000\u0003<XDRMHEADER>");
+        assertDetected(MediaType.application("x-navitel-map"),
+                
"PMGC\u0005\u0000Ò\u000f\u0004\u0000\f\u0000\u0000\u0000\u0000\u0000"
+                        + 
"\u0084Sÿ\u0018\u0084\u0000\u0000\u0000\u0084\u0000\u0000\u0000");
+    }
+
+    @Test
+    public void testDeveloperArtifacts() throws Exception {
+        assertDetected(MediaType.application("x-gcov-data"), 
"adcg*504qc\u0000\u0000");
+        assertDetected(MediaType.application("x-gcov-notes"), 
"oncg*204\u0000\u0000");
+        assertDetected(MediaType.application("x-python-bytecode"), 
"\u0003ó\r\nSc\u0000\u0000");
+        assertDetected(MediaType.application("x-python-bytecode"), 
"U\r\r\n\u0000\u0000\u0000\u0000");
+        // CPython magic numbers: 3.0 is 3131, 3.14 is 3627, 3.15 starts at 
3650
+        // 3.0: mtime, then the code object; 3.6: mtime and source size, then 
a FLAG_REF code object
+        assertDetected(MediaType.application("x-python-bytecode"), 
";\f\r\nABCDc\u0000\u0000");
+        assertDetected(MediaType.application("x-python-bytecode"), 
"3\r\r\nABCD\u0010\u0000\u0000\u0000ã");
+        // text with a one-character first line and CR CR LF endings
+        assertDetected(MediaType.OCTET_STREAM, " \r\r\n      \r\r\n");
+        assertDetected(MediaType.application("x-python-bytecode"), 
"+\u000e\r\n\u0000\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-python-bytecode"), 
"B\u000e\r\n\u0000\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-python-pickle"), 
"\u0080\u0002}q\u0000(U\tcollector");
+        assertDetected(MediaType.application("x-python-pickle"), 
"\u0080\u0004\u0095\u0010\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-lucene-index"), 
"?×l\u0017\u0013Lucene62SegmentInfo");
+        assertDetected(MediaType.application("x-git-pack"), 
"PACK\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0003");
+        assertDetected(MediaType.OCTET_STREAM, 
"PACK\u0000\u0000\u0000\u0001\u0000\u0000\u0002-");
+    }
+
+    @Test
+    public void testSystemDataFormats() throws Exception {
+        assertDetected(MediaType.application("tzif"), 
"TZif2\u0000\u0000\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-mozlz4"), 
"mozLz40\u0000]\u0000\u0000\u0000{\"type\"");
+        assertDetected(MediaType.image("jxr"), "II¼\u0001 \u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-intel-aml"),
+                "SSDTÈ\u0000\u0000\u0000\u0001\u008eBOCHS BXPCSSDT");
+    }
+
+    @Test
+    public void testScienceFormats() throws Exception {
+        assertDetected(MediaType.application("x-nexrad-level3"),
+                "SDUS63 KSGF 280002\r\r\nDODSGF\r\r\n\u0000®L­");
+        assertDetected(MediaType.OCTET_STREAM, "SDUS63 KSGF 
280002\r\nDODSGF\r\n");
+        assertDetected(MediaType.application("x-bigbed"), 
"ëò\u0089\u0087\u0004\u0000\b\u0000");
+        assertDetected(MediaType.application("x-bigwig"), 
"&ü\u008f\u0088\u0004\u0000\n\u0000");
+        assertDetected(MediaType.OCTET_STREAM, 
"&ü\u008f\u0088\t\u0000\n\u0000");
+        assertDetected(MediaType.application("x-ucsc-2bit"), 
"C'A\u001a\u0000\u0000\u0000\u0000î");
+        assertDetected(MediaType.application("x-ucsc-2bit"), 
"C'A\u001a\u0001\u0000\u0000\u0000s");
+        assertDetected(MediaType.application("x-bam"), 
"BAM\u0001j\u0006\u0000\u0000@HD\tVN:1.0");
+        assertDetected(MediaType.application("x-bam-index"), 
"BAI\u0001\u0016\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-osm-pbf"), 
"\u0000\u0000\u0000\u000e\n\tOSMHeader\u0018");
+        assertDetected(MediaType.application("x-ligo-frame"), 
"IGWD\u0000\b\u0001\u0002");
+    }
+
+    @Test
+    public void testDiskAndFirmwareImages() throws Exception {
+        assertDetected(MediaType.application("x-qemu-disk"), 
"QFIû\u0000\u0000\u0000\u0003");
+        assertDetected(MediaType.OCTET_STREAM, "QFIû\u0000\u0000\u0000\u0007");
+        assertDetected(MediaType.application("x-imagedisk"), "IMD 1.18: 
12/07/2013  8:49:58\r\n\u001a");
+        assertDetected(MediaType.application("x-mame-chd"), 
"MComprHD\u0000\u0000\u0000|\u0000\u0000\u0000\u0005");
+        assertDetected(MediaType.application("x-device-tree-blob"),
+                
"Ð\rþí\u0000µCè\u0000\u0000\u00008\u0000µ?ü\u0000\u0000\u0000(\u0000\u0000\u0000\u0011");
+        assertDetected(MediaType.OCTET_STREAM,
+                
"Ð\rþí\u0000µCè\u0000\u0000\u00008\u0000µ?ü\u0000\u0000\u0000(\u0000\u0000\u0000\u0002");
+        StringBuilder uimage = new StringBuilder("'\u0005\u0019V");
+        
uimage.append("\u0000".repeat(24)).append("\u0005\u0002\u0002\u0003DD-WRT");
+        assertDetected(MediaType.application("x-uboot-image"), 
uimage.toString());
+        assertDetected(MediaType.application("x-ubi-image"), 
"UBI#\u0001\u0000\u0000\u0000");
+        assertDetected(MediaType.application("x-amiga-executable"),
+                
"\u0000\u0000\u0003ó\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0000\u0000\u0000");
+    }
+
+    @Test
+    public void testMediaFormats() throws Exception {
+        assertDetected(MediaType.image("vnd.ms-dds"), "DDS 
|\u0000\u0000\u0000\u0007\u0010\n\u0000");
+        assertDetected(MediaType.audio("x-ym"), 
"YM6!LeOnArD!\u0000\u0000\u001b§");
+        assertDetected(MediaType.audio("x-ym"), "YM3!\u0000\u0000\u0001@");
+        assertDetected(MediaType.application("x-vst-preset"), 
"CcnK\u0000\u0000\u0000dFxCk\u0000\u0000\u0000\u0001");
+        assertDetected(MediaType.OCTET_STREAM, "CcnK\u0000\u0000\u0000dABCD");
+        assertDetected(MediaType.application("x-jw-cad"), "jw_cad(c)data....");
+    }
+
+    @Test
+    public void testEstablishedNamesAreAliases() throws Exception {
+        String[][] pairs = {
+                {"application/x-palmdoc", "application/x-aportisdoc"},
+                {"application/x-acpi-table", "application/x-intel-aml"},
+                {"audio/x-sfbk", "audio/x-soundfont"},
+                {"application/x-ms-dmp", "application/x-windows-kernel-dump"},
+                {"application/x-lz4+json", "application/x-mozlz4"},
+                {"application/x-git", "application/x-git-pack"},
+                {"application/x-clamav", "application/x-clamav-database"},
+                {"image/x-dds", "image/vnd.ms-dds"}};
+        for (String[] pair : pairs) {
+            assertEquals(MediaType.parse(pair[1]), 
MIME_TYPES.forName(pair[0]).getType(), pair[0]);
+        }
+    }
+
+    @Test
+    public void testSharedExtensionsAreNotClaimed() throws Exception {
+        // .atr Atari disks, .bsp Quake/GoldSrc maps, .lev other games, 
.flipchart Wacom
+        String[][] cases = {
+                {"x.atr", "application/x-wfdb-annotation"},
+                {"x.bsp", "application/x-source-bsp"},
+                {"x.lev", "application/x-elasto-mania-level"},
+                {"x.flipchart", "application/x-promethean-flipchart"}};
+        for (String[] c : cases) {
+            assertNotEquals(MediaType.parse(c[1]), 
MIME_TYPES.getMimeType(c[0]).getType(), c[0]);
+        }
+    }
+
+    private static void assertDetected(MediaType expected, String latin1) 
throws IOException {
+        byte[] bytes = new byte[64];
+        byte[] header = latin1.getBytes(ISO_8859_1);
+        System.arraycopy(header, 0, bytes, 0, header.length);
+        try (TikaInputStream tis = TikaInputStream.get(bytes)) {
+            assertEquals(expected, MIME_TYPES.detect(tis, new Metadata(), new 
ParseContext()));
+        }
+    }
+}
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/ParsingReaderTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/ParsingReaderTest.java
index 81b159d431..7f5ec8dcdf 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/ParsingReaderTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/ParsingReaderTest.java
@@ -56,7 +56,7 @@ public class ParsingReaderTest extends TikaTest {
 
     @Test
     public void testXML() throws Exception {
-        String data = "<p>test <span>content</span></p>";
+        String data = "<doc>test <span>content</span></doc>";
         InputStream stream = new ByteArrayInputStream(data.getBytes(UTF_8));
         Reader reader = new ParsingReader(stream, "test.xml");
         assertEquals(' ', (char) reader.read());
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/pom.xml
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/pom.xml
index 6df15881e4..3fa98cf50b 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/pom.xml
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-cad-module/pom.xml
@@ -54,6 +54,15 @@
 
   <build>
     <plugins>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <inputExcludes>
+            <inputExclude>src/test/resources/test-documents/*</inputExclude>
+          </inputExcludes>
+        </configuration>
+      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>

Reply via email to