Quellcode durchsuchen

Merge upstream version 5.47

Christoph Biedl vor 3 Tagen
Ursprung
Commit
9b19684ea8
82 geänderte Dateien mit 2042 neuen und 595 gelöschten Zeilen
  1. 33 0
      ChangeLog
  2. 1 1
      config.sub
  3. 10 10
      configure
  4. 1 1
      configure.ac
  5. 4 4
      doc/file.man
  6. 20 10
      doc/magic.man
  7. 6 4
      magic/Magdir/amigaos
  8. 18 15
      magic/Magdir/animation
  9. 15 5
      magic/Magdir/apache
  10. 143 74
      magic/Magdir/archive
  11. 12 2
      magic/Magdir/audio
  12. 9 0
      magic/Magdir/bgcode
  13. 14 5
      magic/Magdir/blender
  14. 11 4
      magic/Magdir/bytecode
  15. 29 13
      magic/Magdir/c-lang
  16. 6 1
      magic/Magdir/cisco
  17. 41 21
      magic/Magdir/commands
  18. 91 1
      magic/Magdir/console
  19. 26 0
      magic/Magdir/creativeassembly
  20. 101 1
      magic/Magdir/database
  21. 26 5
      magic/Magdir/filesystems
  22. 140 5
      magic/Magdir/firmware
  23. 7 7
      magic/Magdir/fonts
  24. 54 10
      magic/Magdir/games
  25. 23 0
      magic/Magdir/gguf
  26. 7 1
      magic/Magdir/ibm370
  27. 45 2
      magic/Magdir/images
  28. 5 1
      magic/Magdir/intel
  29. 31 1
      magic/Magdir/linux
  30. 2 1
      magic/Magdir/lua
  31. 2 2
      magic/Magdir/mail.news
  32. 8 1
      magic/Magdir/measure
  33. 15 48
      magic/Magdir/msdos
  34. 12 10
      magic/Magdir/msooxml
  35. 44 1
      magic/Magdir/music
  36. 25 5
      magic/Magdir/os2
  37. 2 2
      magic/Magdir/pdf
  38. 69 4
      magic/Magdir/pgp
  39. 21 8
      magic/Magdir/python
  40. 86 0
      magic/Magdir/r
  41. 9 3
      magic/Magdir/riff
  42. 6 1
      magic/Magdir/rtf
  43. 112 0
      magic/Magdir/sf3
  44. 18 9
      magic/Magdir/sgml
  45. 6 3
      magic/Magdir/sniffer
  46. 19 2
      magic/Magdir/sql
  47. 37 0
      magic/Magdir/syd
  48. 29 0
      magic/Magdir/tapebackup
  49. 16 1
      magic/Magdir/tex
  50. 6 1
      magic/Magdir/ti-8x
  51. 16 7
      magic/Magdir/varied.script
  52. 5 1
      magic/Magdir/virtual
  53. 5 4
      magic/Magdir/webassembly
  54. 21 21
      magic/Magdir/windows
  55. 12 12
      magic/Magdir/xilinx
  56. 5 4
      magic/Magdir/xwindows
  57. 7 2
      magic/Magdir/zip
  58. 8 1
      magic/Makefile.am
  59. 8 1
      magic/Makefile.in
  60. 3 1
      python/magic.py
  61. 48 18
      src/apprentice.c
  62. 4 5
      src/apptype.c
  63. 5 1
      src/buffer.c
  64. 6 6
      src/cdf.c
  65. 1 0
      src/cdf.h
  66. 7 3
      src/encoding.c
  67. 10 3
      src/file.h
  68. 77 26
      src/funcs.c
  69. 12 4
      src/is_simh.c
  70. 24 22
      src/magic.c
  71. 6 2
      src/print.c
  72. 41 21
      src/readcdf.c
  73. 108 95
      src/readelf.c
  74. 14 5
      src/seccomp.c
  75. 61 21
      src/softmagic.c
  76. 26 1
      tests/Makefile.am
  77. 26 1
      tests/Makefile.in
  78. 1 1
      tests/arj.result
  79. 1 0
      tests/bgcode.result
  80. BIN
      tests/bgcode.testfile
  81. 1 0
      tests/efi-signature-list-sha256.result
  82. BIN
      tests/efi-signature-list-sha256.testfile

+ 33 - 0
ChangeLog

@@ -1,3 +1,36 @@
+2026-02-26  11:32  Christos Zoulas <christos@zoulas.com>
+
+	* release 5.47
+
+2026-02-04  09:54  Christos Zoulas <christos@zoulas.com>
+	* Better multi-compound document identification by following the
+	  order of the directories entries. (Thomas Ledoux)
+
+2026-01-19  14:00  Christos Zoulas <christos@zoulas.com>
+	* if stat fails, don't attempt to restore times (Steven Grubb)
+
+2025-05-28  15:20  Christos Zoulas <christos@zoulas.com>
+
+	PR/622: Odd_Bloke: Handle negative offsets in file_buffer(),
+	when fd is not available.
+
+2025-05-28  12:50  Christos Zoulas <christos@zoulas.com>
+
+	* PR/655: jsummers: Obey str_flags in strings like we do for search
+	  and regex
+	* PR/659: Pitzl: Apply MAGIC_CONTINUE to annotations; i.e. print
+	  only the first, unless -k is specified.
+	
+2024-12-19  14:44  Christos Zoulas <christos@zoulas.com>
+
+	* PR/592: allow + in format strings
+	* PR/592: signed operations should be done in signed context
+
+2024-12-05  13:50 Christos Zoulas <christos@zoulas.com>
+
+	* PR/578: jsummers: Don't crash on cygwin when tm_mon == -1
+	* PR/579: net147: Fix stack overrun.
+
 2024-11-27  14:44  Christos Zoulas <christos@zoulas.com>
 
 	* release 5.46

+ 1 - 1
config.sub

@@ -1724,7 +1724,7 @@ case $os in
 	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
 	     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \
 	     | hiux* | abug | nacl* | netware* | windows* \
-	     | os9* | macos* | osx* | ios* \
+	     | os9* | macos* | osx* | ios* | illumos* \
 	     | mpw* | magic* | mmixware* | mon960* | lnews* \
 	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
 	     | aos* | aros* | cloudabi* | sortix* | twizzler* \

+ 10 - 10
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for file 5.46.
+# Generated by GNU Autoconf 2.72 for file 5.47.
 #
 # Report bugs to <christos@astron.com>.
 #
@@ -614,8 +614,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='file'
 PACKAGE_TARNAME='file'
-PACKAGE_VERSION='5.46'
-PACKAGE_STRING='file 5.46'
+PACKAGE_VERSION='5.47'
+PACKAGE_STRING='file 5.47'
 PACKAGE_BUGREPORT='christos@astron.com'
 PACKAGE_URL=''
 
@@ -1370,7 +1370,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures file 5.46 to adapt to many kinds of systems.
+'configure' configures file 5.47 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1441,7 +1441,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of file 5.46:";;
+     short | recursive ) echo "Configuration of file 5.47:";;
    esac
   cat <<\_ACEOF
 
@@ -1567,7 +1567,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-file configure 5.46
+file configure 5.47
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -2153,7 +2153,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by file $as_me 5.46, which was
+It was created by file $as_me 5.47, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3452,7 +3452,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='file'
- VERSION='5.46'
+ VERSION='5.47'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -16880,7 +16880,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by file $as_me 5.46, which was
+This file was extended by file $as_me 5.47, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -16948,7 +16948,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-file config.status 5.46
+file config.status 5.47
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 

+ 1 - 1
configure.ac

@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT([file],[5.46],[christos@astron.com])
+AC_INIT([file],[5.47],[christos@astron.com])
 AM_INIT_AUTOMAKE([subdir-objects foreign])
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 

+ 4 - 4
doc/file.man

@@ -1,5 +1,5 @@
-.\" $File: file.man,v 1.151 2024/04/07 21:27:35 christos Exp $
-.Dd April 7, 2024
+.\" $File: file.man,v 1.153 2025/07/23 18:52:08 christos Exp $
+.Dd June 17, 2025
 .Dt FILE __CSECTION__
 .Os
 .Sh NAME
@@ -173,7 +173,7 @@ Causes the
 command to output the file type and creator code as
 used by older MacOS versions.
 The code consists of eight letters,
-the first describing the file type, the latter the creator.
+the first four describing the file type, the latter four the creator.
 This option works properly only for file formats that have the
 apple-style output defined.
 .It Fl b , Fl Fl brief
@@ -348,7 +348,7 @@ Set various parameter limits.
 .It Li elf_shsize Ta 128MB Ta max ELF section size processed
 .It Li encoding Ta 65K Ta max number of bytes to determine encoding
 .It Li indir Ta 50 Ta recursion limit for indirect magic
-.It Li name Ta 100 Ta use count limit for name/use magic
+.It Li name Ta 150 Ta use count limit for name/use magic
 .It Li regex Ta 8K Ta length limit for regex searches
 .El
 .It Fl r , Fl Fl raw

+ 20 - 10
doc/magic.man

@@ -1,5 +1,5 @@
-.\" $File: magic.man,v 1.110 2024/11/27 15:37:00 christos Exp $
-.Dd November 27, 2024
+.\" $File: magic.man,v 1.115 2025/11/24 15:45:00 christos Exp $
+.Dd November 24, 2025
 .Dt MAGIC __FSECTION__
 .Os
 .\" install as magic.4 on USG, magic.5 on V7, Berkeley and Linux systems.
@@ -73,7 +73,8 @@ A 64-bit double precision IEEE floating point number in this machine's native by
 .It Dv string
 A string of bytes.
 The string type specification can be optionally followed by a /<width> 
-option and optionally followed by a set of flags /[bCcftTtWw]*.
+option and optionally followed by a set of flags [bCcftTtWw]*.
+Slash characters can be used to separate options for readability.
 The width limits the number of characters to be copied.
 Zero means all characters.
 The following flags are supported:
@@ -85,24 +86,31 @@ Use upper case insensitive matching: upper case
 characters in the magic match both lower and upper case characters in the
 target, whereas lower case characters in the magic only match upper case
 characters in the target.
+(not valid for regex)
 .It c
 Use lower case insensitive matching: lower case
 characters in the magic match both lower and upper case characters in the
 target, whereas upper case characters in the magic only match upper case
 characters in the target.
+(not valid for regex)
 To do a complete case insensitive match, specify both
 .Dq c
 and
 .Dq C .
 .It f
 Require that the matched string is a full word, not a partial word match.
+.It s
+Don't include the match length in the offset computation.
+(only valid for search and regex)
 .It T
 Trim the string, i.e. leading and trailing whitespace
+is deleted before the string is printed.
 .It t
 Force text file test.
 .It W
 Compact whitespace in the target, which must
 contain at least one whitespace character.
+(not valid for regex)
 If the magic has
 .Dv n
 consecutive blanks, the target needs at least
@@ -110,7 +118,7 @@ consecutive blanks, the target needs at least
 consecutive blanks to match.
 .It w
 Treat every blank in the magic as an optional blank.
-is deleted before the string is printed.
+(not valid for regex)
 .El
 .It Dv pstring
 A Pascal-style string where the first byte/short/int is interpreted as the
@@ -221,10 +229,10 @@ than UTC.
 An eight-byte value in little-endian byte order,
 interpreted as a Windows-style date.
 .It Dv lemsdosdate
-A two-byte value in big-endian byte order,
+A two-byte value in little-endian byte order,
 interpreted as FAT/DOS-style date.
 .It Dv lemsdostime
-A two-byte value in big-endian byte order,
+A two-byte value in little-endian byte order,
 interpreted as FAT/DOS-style time.
 .It Dv lestring16
 A two-byte unicode (UCS16) string in little-endian byte order.
@@ -253,7 +261,8 @@ magic entry, like a subroutine call.
 Named instance direct magic offsets are relative to the offset of the
 previous matched entry, but indirect offsets are relative to the beginning
 of the file as usual.
-Named magic entries always match.
+Named magic entries return true if there was a match in the evaluation
+of the entry, or if there was a previous existing match.
 .It Dv use
 Recursively call the named magic starting from the current offset.
 If the name of the referenced begins with a
@@ -459,11 +468,12 @@ matching a file, binary patterns are tried first; if no match is
 found, and the file looks like text, then its encoding is determined
 and the text patterns are tried.
 .Pp
-The numeric types may optionally be followed by
-.Dv \*[Am]
+The numeric types may optionally be followed by an operand
 and a numeric value,
-to specify that the value is to be AND'ed with the
+to specify that the value is to be modified according to the operand and the
 numeric value before any comparisons are done.
+The following operands are supported:
+.Dv \*[Am], \*[Ba], \*[ua], +, -, \&*, /, %.
 Prepending a
 .Dv u
 to the type indicates that ordered comparisons should be unsigned.

+ 6 - 4
magic/Magdir/amigaos

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: amigaos,v 1.20 2021/09/20 00:42:19 christos Exp $
+# $File: amigaos,v 1.23 2026/02/05 18:49:06 christos Exp $
 # amigaos:  file(1) magic for AmigaOS binary formats:
 
 #
@@ -36,7 +36,6 @@
 0	string		COSO\0		Hippel-COSO Module sound file
 # Too simple (short, pure ASCII, deep), MPi
 #26	string		V.3		Brian Postma's Soundmon Module sound file v3
-#26	string		BPSM		Brian Postma's Soundmon Module sound file v3
 #26	string		V.2		Brian Postma's Soundmon Module sound file v2
 
 # The following are from: "Stefan A. Haubenthal" <polluks@web.de>
@@ -195,8 +194,7 @@
 0	string		LZX		LZX compressed archive (Amiga)
 
 # From: Przemek Kramarczyk <pkramarczyk@gmail.com>
-0	string 		.KEY		AmigaDOS script
-0	string 		.key		AmigaDOS script
+0	string/c	.key		AmigaDOS script
 
 # AMOS Basic file formats
 # https://www.exotica.org.uk/wiki/AMOS_file_formats
@@ -216,3 +214,7 @@
 >12	regex		.{8}			\b, type %s
 0	string		AmBs			AMOS Basic memory banks
 >4	beshort		x			\b, %d banks
+
+
+# https://github.com/alb42/Leu/blob/master/TCDReaderUnit.pas
+3	string		TURBOCALC		TurboCalc spreadsheet

+ 18 - 15
magic/Magdir/animation

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: animation,v 1.98 2024/09/01 15:51:51 christos Exp $
+# $File: animation,v 1.101 2025/05/28 19:54:08 christos Exp $
 # animation:  file(1) magic for animation/movie formats
 #
 # animation formats
@@ -542,20 +542,23 @@
 >>2	byte&0xF0	!0xF0		MPEG ADTS, layer III, v1
 !:strength +20
 !:mime	audio/mpeg
->>>2	byte&0xF0	0x10		\b, 32 kbps
->>>2	byte&0xF0	0x20		\b, 40 kbps
->>>2	byte&0xF0	0x30		\b, 48 kbps
->>>2	byte&0xF0	0x40		\b, 56 kbps
->>>2	byte&0xF0	0x50		\b, 64 kbps
->>>2	byte&0xF0	0x60		\b, 80 kbps
->>>2	byte&0xF0	0x70		\b, 96 kbps
->>>2	byte&0xF0	0x80		\b, 112 kbps
->>>2	byte&0xF0	0x90		\b, 128 kbps
->>>2	byte&0xF0	0xA0		\b, 160 kbps
->>>2	byte&0xF0	0xB0		\b, 192 kbps
->>>2	byte&0xF0	0xC0		\b, 224 kbps
->>>2	byte&0xF0	0xD0		\b, 256 kbps
->>>2	byte&0xF0	0xE0		\b, 320 kbps
+>>>2	search/100	Xing		\b, variable bitrate
+>>>2	search/100	VBRI		\b, variable bitrate
+>>>2	default		x
+>>>>2	byte&0xF0	0x10		\b, 32 kbps
+>>>>2	byte&0xF0	0x20		\b, 40 kbps
+>>>>2	byte&0xF0	0x30		\b, 48 kbps
+>>>>2	byte&0xF0	0x40		\b, 56 kbps
+>>>>2	byte&0xF0	0x50		\b, 64 kbps
+>>>>2	byte&0xF0	0x60		\b, 80 kbps
+>>>>2	byte&0xF0	0x70		\b, 96 kbps
+>>>>2	byte&0xF0	0x80		\b, 112 kbps
+>>>>2	byte&0xF0	0x90		\b, 128 kbps
+>>>>2	byte&0xF0	0xA0		\b, 160 kbps
+>>>>2	byte&0xF0	0xB0		\b, 192 kbps
+>>>>2	byte&0xF0	0xC0		\b, 224 kbps
+>>>>2	byte&0xF0	0xD0		\b, 256 kbps
+>>>>2	byte&0xF0	0xE0		\b, 320 kbps
 # timing
 >>>2	byte&0x0C	0x00		\b, 44.1 kHz
 >>>2	byte&0x0C	0x04		\b, 48 kHz

+ 15 - 5
magic/Magdir/apache

@@ -1,18 +1,28 @@
 
 #------------------------------------------------------------------------------
-# $File: apache,v 1.1 2017/04/11 14:52:15 christos Exp $
+# $File: apache,v 1.3 2025/05/30 13:25:13 christos Exp $
 # apache: file(1) magic for Apache Big Data formats
 
 # Avro files
-0	string		Obj		Apache Avro
->3	byte		x		version %d
+0	string		Obj\001		Apache Avro, version 1
 
 # ORC files
 # Important information is in file footer, which we can't index to :(
 0	string		ORC		Apache ORC
 
-# Parquet files
-0	string		PAR1		Apache Parquet
+# Apache arrow file format
+# MIME: https://www.iana.org/assignments/media-types/application/vnd.apache.arrow.stream
+# Description: https://arrow.apache.org/docs/format/Columnar.html
+0	string		ARROW1		Apache Arrow columnar file
+!:mime application/vnd.apache.arrow.file
+!:ext arrow/feather
+
+# Apache parquet file format
+# MIME: https://www.iana.org/assignments/media-types/application/vnd.apache.parquet
+# Description: https://parquet.apache.org/docs/file-format/
+0	string		PAR1		Apache Parquet file
+!:mime application/vnd.apache.parquet
+!:ext parquet
 
 # Hive RC files
 0	string		RCF		Apache Hive RC file

+ 143 - 74
magic/Magdir/archive

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: archive,v 1.207 2024/11/27 15:37:46 christos Exp $
+# $File: archive,v 1.218 2026/01/10 16:16:27 christos Exp $
 # archive:  file(1) magic for archive formats (see also "msdos" for self-
 #           extracting compressed archives)
 #
@@ -689,7 +689,7 @@
 # TODO: idarc says "bytes 0-2 == bytes 3-5"
 # TTComp
 # URL: http://fileformats.archiveteam.org/wiki/TTComp_archive
-# Update: Joerg Jenderek
+# Update: Joerg Jenderek, A Iooss
 # GRR: line below is too general as it matches also Panorama database "TCDB 2003-10 demo.pan", others
 0	string	\0\6
 # look for first keyword of Panorama database *.pan
@@ -735,8 +735,27 @@
 #>-4	ubelong		x	LAST_BYTES=%8.8x
 >-4	ubelong&0x00FFffFF	!0
 >>0	use	ttcomp
-#	display information of TTComp archive
+# match end of TTComp to reduce false positives
+# see https://mark0.net/forum/index.php?topic=848
 0	name	ttcomp
+>-2	string	\x01\xff
+>>+0	use	ttcomp-display
+>-2	string	\x80\x7f
+>>+0	use	ttcomp-display
+>-2	string	\xc0\x3f
+>>+0	use	ttcomp-display
+>-2	string	\xe0\x1f
+>>+0	use	ttcomp-display
+>-2	string	\xf0\x0f
+>>+0	use	ttcomp-display
+>-2	string	\xf8\x07
+>>+0	use	ttcomp-display
+>-2	string	\xfc\x03
+>>+0	use	ttcomp-display
+>-2	string	\xfe\x01
+>>+0	use	ttcomp-display
+# display information of TTComp archive
+0	name	ttcomp-display
 # (version 5.25) labeled the entry as "TTComp archive data"
 >0	ubyte	x	TTComp archive data
 !:mime	application/x-compress-ttcomp
@@ -746,23 +765,10 @@
 >0	ubyte	0	\b, binary
 >0	ubyte	1	\b, ASCII
 # size of the dictionary:  4~1024 bytes 5~2048 bytes 6~4096 bytes 
->1	ubyte	4	\b, 1K
->1	ubyte	5	\b, 2K
->1	ubyte	6	\b, 4K
->1	ubyte	x	dictionary
-#	https://mark0.net/forum/index.php?topic=848
-# last 3 bytes probably have only 8 possible bit sequences
-# xxxxxxxx 0000000x 11111111	____FFh
-# xxxxxxxx 10000000 01111111	__807Fh	
-# 0xxxxxxx 11000000 00111111	__C03Fh
-# 00xxxxxx 11100000 00011111	__E01Fh
-# 000xxxxx 11110000 00001111	__F00Fh
-# 0000xxxx 11111000 00000111	__F807h
-# 00000xxx 11111100 00000011	__FC03h
-# 000000xx 11111110 00000001	__FE01h
-# but for quickgif.__d 0A7DD4h
-#>-3	ubyte		x	\b, last 3 bytes 0x%2.2x
-#>-2	ubeshort	x	\b%4.4x
+>1	ubyte	4	\b, 1K dictionary
+>1	ubyte	5	\b, 2K dictionary
+>1	ubyte	6	\b, 4K dictionary
+
 # From:		Joerg Jenderek
 # URL:		https://en.wikipedia.org/wiki/Disk_Copy
 # reference:	http://nulib.com/library/FTN.e00005.htm
@@ -1231,6 +1237,8 @@
 #>0x200	ubequad	x	\b, at 0x200 %#16.16llx
 # cab_descriptor_size like: 0 (*.cab) BD5 C8B DA5 E2A E36 116C 251D 4DA9 56F0 5CC2 6E4B 777D 779E 1F7C2
 >16	ulelong	!0	\b, descriptor size %#x
+>(12.l+40)      lelong  x               ]b, %u files
+
 # TOP4
 0	string	T4\x1a TOP4 archive data
 # BatComp left out: sig looks like COM executable
@@ -1491,22 +1499,18 @@
 >>9	ubyte		!2		\b, security version %u
 # file type; 2 in main header; 0~binary 1~7-bitText 2~comment 3~directory 4~VolumeLabel 5=ChapterLabel
 >0xA	ubyte		!2		\b, file type %u
-# date+time when original archive was created in MS-DOS format via ./msdos
->0xC	ulelong		x		\b, created
->0xC	use		dos-date
-# or date and time by new internal function
-#>0xE	lemsdosdate	x		%s
-#>0xC	lemsdostime	x		%s
+# date+time when original archive was created in MS-DOS format
+>0xE	lemsdosdate	x		\b, created %s
+>0xC	lemsdostime	x		%s
+# Archive mod time, added in format v6 (ARJ 2.39c)
+>5	ubyte		>5
+>>0x10	ulelong		>0		\b, modified
+>>>0x12	lemsdosdate	x		%s
+>>>0x10	lemsdostime	x		%s
+
 # FOR DEBUGGING
 #>0x12	uleshort	x		RAW DATE %#4.4x
 #>0x10	uleshort	x		RAW TIME %#4.4x
-# date+time when archive was last modified; sometimes nil or
-# maybe wrong like in HP4DRVR.ARJ
-#>0x10	ulelong		>0		\b, modified
-#>>0x10	use		dos-date
-# or date and time by new internal function
-#>>0x12	lemsdosdate	x		%s
-#>>0x10	lemsdostime	x		%s
 # archive size (currently used only for secured archives); MAYBE?
 #>0x14	ulelong		!0		\b, file size %u
 # security envelope file position; MAYBE?
@@ -1795,6 +1799,51 @@
 !:ext zip/cbz
 
 
+# Generic zip archives (Greg Roelofs, c/o zip-bugs@wkuvx1.wku.edu)
+#   Next line excludes specialized formats:
+0	name	zipgeneric
+>4	beshort		x			Zip archive data, at least
+!:mime	application/zip
+>4	use		zipversion
+>4	beshort		x			to extract
+>8	beshort		x			\b, compression method=
+>8	use		zipcompression
+>0x161	string		WINZIP		\b, WinZIP self-extracting
+
+# Zip archives that can be either APK or JAR. Checks for resources.arsc, classes.dex, etc.
+0	name	apk_or_jar
+# Contains resources.arsc (near the end, in the central directory)
+>-512	search	resources.arsc	Android package (APK), with MANIFEST.MF and resources.arsc
+!:mime	application/vnd.android.package-archive
+!:ext	apk
+>>-22	string	PK\005\006
+>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
+>-512	default x
+# Contains classes.dex (near the end, in the central directory)
+>>-512	search	classes.dex	Android package (APK), with MANIFEST.MF and classes.dex
+!:mime	application/vnd.android.package-archive
+!:ext	apk
+>>>-22	string	PK\005\006
+>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
+>>-512	default x
+# Contains lib/armeabi (near the end, in the central directory)
+>>>-512	search	lib/armeabi	Android package (APK), with MANIFEST.MF and armeabi lib
+!:mime	application/vnd.android.package-archive
+!:ext	apk
+>>>>-22	string	PK\005\006
+>>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
+>>>-512	default x
+# Contains drawables (near the end, in the central directory)
+>>>>-512	search	res/drawable	Android package (APK), with MANIFEST.MF and drawables
+!:mime	application/vnd.android.package-archive
+!:ext	apk
+>>>>>-22	string	PK\005\006
+>>>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
+# It may or may not be an APK file, but it's definitely a Java JAR file
+>>>>-512	default x	Java archive data (JAR)
+!:mime	application/java-archive
+!:ext	jar
+
 0	string		PK\003\004
 !:strength +1
 # IOS/IPadOS IPA file (Zip archive)
@@ -1830,40 +1879,14 @@
 >>>-22	string	PK\005\006
 >>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
 # Starts with META-INF/MANIFEST.MF (file name length = 20)
-# NB: checks for resources.arsc, classes.dex, etc. as well to avoid matching JAR files
 >26	uleshort	20
 >>30	string	META-INF/MANIFEST.MF
-# Contains resources.arsc (near the end, in the central directory)
->>>-512	search	resources.arsc	Android package (APK), with MANIFEST.MF and resources.arsc
-!:mime	application/vnd.android.package-archive
-!:ext	apk
->>>>-22	string	PK\005\006
->>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
->>>-512	default x
-# Contains classes.dex (near the end, in the central directory)
->>>>-512	search	classes.dex	Android package (APK), with MANIFEST.MF and classes.dex
-!:mime	application/vnd.android.package-archive
-!:ext	apk
->>>>>-22	string	PK\005\006
->>>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
->>>>-512	default x
-# Contains lib/armeabi (near the end, in the central directory)
->>>>>-512	search	lib/armeabi	Android package (APK), with MANIFEST.MF and armeabi lib
-!:mime	application/vnd.android.package-archive
-!:ext	apk
->>>>>>-22	string	PK\005\006
->>>>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
->>>>>-512	default x
-# Contains drawables (near the end, in the central directory)
->>>>>>-512	search	res/drawable	Android package (APK), with MANIFEST.MF and drawables
-!:mime	application/vnd.android.package-archive
-!:ext	apk
->>>>>>>-22	string	PK\005\006
->>>>>>>>(-6.l-16)	string	APK\x20Sig\x20Block\x2042	\b, with APK Signing Block
-# It may or may not be an APK file, but it's definitely a Java JAR file
->>>>>>-512	default x	Java archive data (JAR)
-!:mime	application/java-archive
-!:ext	jar
+>>>0	use		apk_or_jar
+# Starts with META-INF/ folder (file name length = 9)
+>26	uleshort	9
+>>30	string	META-INF/
+>>>0	use		apk_or_jar
+
 # Starts with zipflinger virtual entry (28 + 104 = 132 bytes)
 # See https://github.com/obfusk/apksigcopier/blob/666f5b7/apksigcopier/__init__.py#L230
 >4	string	\x00\x00\x00\x00\x00\x00
@@ -2132,17 +2155,11 @@
 >>>>>>(-6.l)	search/9000	kmp.json	Keyman Compiled Package File
 !:mime	application/vnd.keyman.kmp+zip
 !:ext kmp
+>>>>>+4	default		x
+>>>>>>0	use		zipgeneric
 
-# Generic zip archives (Greg Roelofs, c/o zip-bugs@wkuvx1.wku.edu)
-#   Next line excludes specialized formats:
 >>>>+4	default		x
->>>>>4	beshort		x			Zip archive data, at least
-!:mime	application/zip
->>>>>4	use		zipversion
->>>>>4	beshort		x			to extract
->>>>>8	beshort		x			\b, compression method=
->>>>>8	use		zipcompression
->>>>>0x161	string		WINZIP		\b, WinZIP self-extracting
+>>>>>0	use		zipgeneric
 
 # Zip archives (Greg Roelofs, c/o zip-bugs@wkuvx1.wku.edu)
 0	string		PK\005\006	Zip archive data (empty)
@@ -2810,3 +2827,55 @@
 >>37	byte		x	\b:%02d
 >>38	byte		x	\b:%02d
 >>56	ulelong		x	\b, size: %u bytes
+
+# Stone archive file - Serpent OS moss package manager's native format
+# https://github.com/serpent-os/tools,
+# (Ikey Doherty)
+0	string	\0mos	Stone archive
+>28	belong	1	(format v%d)
+>>27	byte	1	binary package
+!:mime	application/x-stone-binary
+!:ext	stone
+>>27	byte	2	delta package
+!:mime	application/x-stone-delta
+!:ext	stone
+>>27	byte	3	repository index
+!:mime	application/x-stone-repository
+!:ext	index
+>>27	byte	4	build manifest
+!:mime	application/x-stone-manifest
+!:ext	bin
+
+# * VOS <file_name> <sequential|relative|fixed|stream> <record_size> ,
+# * [encapsulated|not_encapsulated] =
+# * [encoded|not_encoded|seq_encoded|base64_encoded]
+0	string		VOS\040	Stratus OpenVOS EFV archive
+>4	regex	[^[:space:]]+ 	\b, (%s)
+>>&0	regex	[^[:space:]]+	\b, %s
+>>>&0	regex	[^[:space:]]+	\b, record_size=%s
+>>>>&0	regex	[^[:space:]]+	\b, %s
+>>>>>&0	regex	[^[:space:]]+	\b, %s
+
+
+# https://www.vm.ibm.com/devpages/bkw/vmarc.html magic in EBCDIC
+0	string	\x7a\xc3\xc6\xc6\x40\x40\x40\x40	VM Archive
+
+# https://pbs.proxmox.com/docs/file-formats.html
+0	string	\x42\xab\x38\x07\xbe\x83\x70\xa1 Proxmox Backup Server unencrypted uncompressed blob
+
+0	string	\x31\xb9\x58\x42\x6f\xb6\xa3\x7f Proxmox Backup Server unencrypted compressed blob
+
+0	string	\x7b\x67\x85\xbe\x22\x2d\x4c\xf0 Proxmox Backup Server encrypted uncompressed blob
+
+0	string	\xe6\x59\x1b\xbf\x0b\xbf\xd8\x0b Proxmox Backup Server encrypted compressed blob
+
+0	string	\x2f\x7f\x41\xed\x91\xfd\x0f\xcd Proxmox Backup Server fixed index
+
+0	string	\x1c\x91\x4e\xa5\x19\xba\xb3\xcd Proxmox Backup Server dynamic index
+
+0	string	\xef\xac\x88\xe5\x74\x64\x95\xd5 Proxmox File Archive Format v1 / pxar
+
+0	string	\x0d\xa4\x16\xdf\x75\x6c\x0f\x73\x18\x00\x00\x00\x00\x00\x00\x00\x02 Proxmox File Archive Format v2+ / mpxar
+
+0	string	\xd2\x4e\x4a\x19\xc2\x68\x4c\x83\x10 Proxmox File Archive Format payload stream / ppxar
+

+ 12 - 2
magic/Magdir/audio

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: audio,v 1.133 2024/09/04 19:07:20 christos Exp $
+# $File: audio,v 1.136 2026/01/23 17:02:27 christos Exp $
 # audio:  file(1) magic for sound formats (see also "iff")
 #
 # Jan Nicolai Langfeldt (janl@ifi.uio.no), Dan Quinlan (quinlan@yggdrasil.com),
@@ -957,7 +957,7 @@
 >>3		byte		4	(With no LAME header)
 >>3		byte		5	Version 2.4
 
-0		string		ADRVPACK	AProSys	module
+0		string		ADRVPACK	AProSys module
 
 # ftp://ftp.modland.com/pub/documents/format_documentation/\
 # Art%20Of%20Noise%20(.aon).txt
@@ -1199,6 +1199,13 @@
 >4	beshort		0xFEFF
 >>0	use		\^nintendo-3ds-bcwav-fields
 
+
+# QOA Quite Okay Audio format
+# https://qoaformat.org/qoa-specification.pdf
+# added by alex myczko <tar@debian.org>
+0	string	qoaf	QOA audio data
+>4	belong	x	\b, %d samples per channel
+
 # Philips DSDIFF audio format (Direct Stream Digital Interchange File Format)
 # Used for DSD audio recordings and Super Audio CD (SACD) mastering annotations
 # https://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
@@ -1338,3 +1345,6 @@
 >50	leshort	x		\b, scaleX %d
 >52	byte	0		\b, percussive
 >52	byte	1		\b, melodic
+
+# https://pbat.ch/proj/protrekkr/
+0	string	PROTREKT	Protrekkr Module

+ 9 - 0
magic/Magdir/bgcode

@@ -0,0 +1,9 @@
+#------------------------------------------------------------------------------
+# $File: bgcode,v 1.1 2025/03/10 21:02:05 christos Exp $
+
+# BGCode
+0	string		GCDE	Binary G-code
+!:ext bgcode,bgc
+>4	ulelong		x		Version %u
+>>8 uleshort	0		\b, no checksum
+>>8 uleshort	1		\b, CRC32 checksum

+ 14 - 5
magic/Magdir/blender

@@ -1,6 +1,5 @@
-
 #------------------------------------------------------------------------------
-# $File: blender,v 1.9 2022/12/21 15:53:27 christos Exp $
+# $File: blender,v 1.10 2026/01/10 14:38:14 christos Exp $
 # blender: file(1) magic for Blender 3D related files
 #
 # Native format rule v1.2. For questions use the developers list
@@ -13,13 +12,13 @@
 #		http://formats.kaitai.io/blender_blend/index.html
 # Note:		called "Blender 3D data" by TrID
 #		and gzip compressed variant handled by ./compress
-0		string	=BLENDER	Blender3D,
+0		string	=BLENDER	Blender3D
 #!:mime		application/octet-stream
 !:mime		application/x-blender
 !:ext		blend
 # no sample found with extension blender
 #!:ext		blend/blender
->7		string	=_		saved as 32-bits
+>7		string	=_		pre-v5, saved as 32-bits
 >>8		string	=v		little endian
 >>>9		byte	x		with version %c.
 >>>10		byte	x		\b%c
@@ -32,7 +31,7 @@
 >>>11		byte	x		\b%c
 >>>0x40		string	=GLOB		\b.
 >>>>0x58	beshort	x		\b%.4d
->7		string	=-		saved as 64-bits
+>7		string	=-		pre-v5, saved as 64-bits
 >>8		string	=v		little endian
 >>9		byte	x		with version %c.
 >>10		byte	x		\b%c
@@ -46,5 +45,15 @@
 >>>0x44		string	=GLOB		\b.
 >>>>0x60	beshort	x		\b%.4d
 
+# Blender 5.0+
+>7		string =17    v5+,
+>>10		byte	x		format version %c
+>>>11		byte	x		\b%c
+>>>>13		byte	x		app version %c
+>>>>>14		byte	x		\b%c
+>>>>>>15		byte	x		\b%c
+>>>>>>>16		byte	x		\b%c
+#
+
 # Scripts that run in the embedded Python interpreter
 0		string	#!BPY		Blender3D BPython script

+ 11 - 4
magic/Magdir/bytecode

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------
-# $File: bytecode,v 1.5 2023/02/20 16:25:05 christos Exp $
+# $File: bytecode,v 1.6 2026/02/16 14:39:53 christos Exp $
 # magic for various bytecodes
 
 # From: Mikhail Gusarov <dottedmag@dottedmag.net>
@@ -34,8 +34,15 @@
 # https://racket-lang.org/
 # https://github.com/racket/racket/blob/master/racket/src/expander/compile/write-linklet.rkt
 0	string	#~
->&0	pstring	x
->>&0	pstring	racket
+>&0	pstring x
+>>&0	pstring racket
 >>>0	string	#~	Racket bytecode
->>>>&0	pstring	x       (version %s)
+>>>>&0	pstring x	(version %s)
+
+
+# From: Marc Chantreux <mc@unistra.fr>
+# [MoarVM](https://www.moarvm.org/) bytecode file
+0	string	MOARVM\x0d\x0a	MoarVM bytecode
+!:ext	mbc
+>0x9	short	>0	\b, version %u
 

+ 29 - 13
magic/Magdir/c-lang

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: c-lang,v 1.32 2023/06/16 19:57:19 christos Exp $
+# $File: c-lang,v 1.38 2025/05/30 13:36:08 christos Exp $
 # c-lang:  file(1) magic for C and related languages programs
 #
 # The strength is to beat standard HTML
@@ -17,7 +17,7 @@
 >>0	regex	\^class[[:space:]]+
 >>>&0	regex 	\\{[\.\*]\\}(;)?$			\b++
 >>&0	clear	x				source text
-!:strength + 15
+!:strength + 30
 !:mime	text/x-c
 0	search/8192	pragma
 >0	regex	\^#[[:space:]]*pragma	C source text
@@ -27,8 +27,7 @@
 >>&0	regex	\^#[[:space:]]*endif$	C source text
 !:mime	text/x-c
 0	search/8192	define
->0	regex	\^#[[:space:]]*(if\|ifn)def
->>&0	regex	\^#[[:space:]]*define	C source text
+>0	regex	\^#[[:space:]]*define	C source text
 !:mime	text/x-c
 0	search/8192	char
 >0	regex	\^[[:space:]]*char(\ \\*|\\*)(.+)(=.*)?;[[:space:]]*$			C source text
@@ -58,21 +57,21 @@
 # C++
 # The strength of these rules is increased so they beat the C rules above
 0	search/8192	namespace
->0	regex	\^namespace[[:space:]]+[_[:alpha:]]{1,30}[[:space:]]*\\{	C++ source text
-!:strength + 30
+>0	regex	\^namespace[[:space:]]+[_[:alpha:]]{1,20}[[:space:]]*\\{	C++ source text
+!:strength + 45
 !:mime	text/x-c++
 # using namespace [namespace] or using std::[lib]
 0	search/8192	using
 >0	regex	\^using[[:space:]]+(namespace\ )?std(::)?[[:alpha:]]*[[:space:]]*;		C++ source text
-!:strength + 30
+!:strength + 45
 !:mime	text/x-c++
 0	search/8192	template
 >0	regex	\^[[:space:]]*template[[:space:]]*<.*>[[:space:]]*$	C++ source text
-!:strength + 30
+!:strength + 45
 !:mime	text/x-c++
 0	search/8192	virtual
 >0	regex	\^[[:space:]]*virtual[[:space:]]+.*[};][[:space:]]*$		C++ source text
-!:strength + 30
+!:strength + 45
 !:mime	text/x-c++
 # But class alone is reduced to avoid beating php (Jens Schleusener)
 0	search/8192	class
@@ -81,15 +80,15 @@
 !:mime	text/x-c++
 0	search/8192	public
 >0	regex	\^[[:space:]]*public:		C++ source text
-!:strength + 30
+!:strength + 45
 !:mime	text/x-c++
 0	search/8192	private
 >0	regex	\^[[:space:]]*private:		C++ source text
-!:strength + 30
+!:strength + 45
 !:mime	text/x-c++
 0	search/8192	protected
 >0	regex	\^[[:space:]]*protected:	C++ source text
-!:strength + 30
+!:strength + 45
 !:mime	text/x-c++
 
 # Objective-C
@@ -98,13 +97,30 @@
 !:strength + 25
 !:mime	text/x-objective-c
 
+
+# Typst
+# https://github.com/typst/typst
+0 regex \^[[:space:]]*#(import|include)[[:space:]]+"@[[:alnum:]-]+    Typst source text
+!:strength + 45
+!:mime	text/vnd.typst
+!:ext typ
+0 regex \^[[:space:]]*#(import|include)[[:space:]]+"[[:alnum:]]+.typ"    Typst source text
+!:strength + 45
+!:mime	text/vnd.typst
+!:ext typ
+0 regex \^[[:space:]]*#(set|show|let)    Typst source text
+!:strength + 45
+!:mime	text/vnd.typst
+!:ext typ
+
+
 # From: Mikhail Teterin <mi@aldan.algebra.com>
 0	string		cscope		cscope reference data
 >7	string		x		version %.2s
 # We skip the path here, because it is often long (so file will
 # truncate it) and mostly redundant.
 # The inverted index functionality was added some time between
-# versions 11 and 15, so look for -q if version is above 14:
+# versions 11 and 30, so look for -q if version is above 14:
 >7	string		>14
 >>10	search/100	\ -q\ 		with inverted index
 >10	search/100	\ -c\ 		text (non-compressed)

+ 6 - 1
magic/Magdir/cisco

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: cisco,v 1.4 2009/09/19 16:28:08 christos Exp $
+# $File: cisco,v 1.5 2025/05/28 14:02:37 christos Exp $
 # cisco:  file(1) magic for cisco Systems routers
 #
 # Most cisco file-formats are covered by the generic elf code
@@ -10,3 +10,8 @@
 >7	string		>\0		    for '%s'
 0	belong&0xffffff00	0x8501cb00  cisco IOS experimental microcode
 >7	string		>\0		    for '%s'
+
+0	string/b	MZIP	Cisco IOS mzip compressed data
+>0x4	belong 		x	\b, version %d
+>0x8 	belong		x 	\b, entry point %#x
+!:ext 	bin

+ 41 - 21
magic/Magdir/commands

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: commands,v 1.77 2024/11/10 16:55:15 christos Exp $
+# $File: commands,v 1.82 2026/02/16 14:39:53 christos Exp $
 # commands:  file(1) magic for various shells and interpreters
 #
 #0	string/w	:			shell archive or script for antique kernel text
@@ -20,13 +20,13 @@
 0	string/fwb	#!\ /bin/ksh		Korn shell script executable (binary data)
 !:mime	text/x-shellscript
 
-0	string/fwt 	#!\ /bin/tcsh		Tenex C shell script text executable
+0	string/fwt	#!\ /bin/tcsh		Tenex C shell script text executable
 !:mime	text/x-shellscript
 0	string/fwt	#!\ /usr/bin/tcsh	Tenex C shell script text executable
 !:mime	text/x-shellscript
-0	string/fwt 	#!\ /usr/local/tcsh	Tenex C shell script text executable
+0	string/fwt	#!\ /usr/local/tcsh	Tenex C shell script text executable
 !:mime	text/x-shellscript
-0	string/fwt	#!\ /usr/local/bin/tcsh	Tenex C shell script text executable
+0	string/fwt	#!\ /usr/local/bin/tcsh Tenex C shell script text executable
 !:mime	text/x-shellscript
 
 #
@@ -52,13 +52,13 @@
 !:mime	text/x-nawk
 0	string/fwt	#!\ /usr/bin/nawk	new awk script text executable
 !:mime	text/x-nawk
-0	string/fwt	#!\ /usr/local/bin/nawk	new awk script text executable
+0	string/fwt	#!\ /usr/local/bin/nawk new awk script text executable
 !:mime	text/x-nawk
 0	string/fwt	#!\ /bin/gawk		GNU awk script text executable
 !:mime	text/x-gawk
 0	string/wt	#!\ /usr/bin/gawk	GNU awk script text executable
 !:mime	text/x-gawk
-0	string/fwt	#!\ /usr/local/bin/gawk	GNU awk script text executable
+0	string/fwt	#!\ /usr/local/bin/gawk GNU awk script text executable
 !:mime	text/x-gawk
 #
 0	string/fwt	#!\ /bin/awk		awk script text executable
@@ -67,6 +67,15 @@
 !:mime	text/x-awk
 0	regex/4096	=^[\040\t\f\r\n]{0,100}BEGIN[\040\t\f\r\n]{0,100}[{]	awk or perl script text
 
+0	string/fwt	#!\ /bin/lua		Lua script text executable
+!:mime	text/x-lua
+0	string/fwt	#!\ /usr/bin/lua	Lua script text executable
+!:mime	text/x-lua
+0	string/fwt	#!\ /usr/bin/env\ lua	Lua script text executable
+!:mime	text/x-lua
+0	string/fwt	#!\ /bin/env\ lua	Lua script text executable
+!:mime	text/x-lua
+
 # AT&T Bell Labs' Plan 9 shell
 0	string/fwt	#!\ /bin/rc	Plan 9 rc shell script text executable
 
@@ -83,9 +92,9 @@
 !:mime	text/x-shellscript
 0	string/fwb	#!\ /usr/local/bash	Bourne-Again shell script executable (binary data)
 !:mime	text/x-shellscript
-0	string/fwt	#!\ /usr/local/bin/bash	Bourne-Again shell script text executable
+0	string/fwt	#!\ /usr/local/bin/bash Bourne-Again shell script text executable
 !:mime	text/x-shellscript
-0	string/fwb	#!\ /usr/local/bin/bash	Bourne-Again shell script executable (binary data)
+0	string/fwb	#!\ /usr/local/bin/bash Bourne-Again shell script executable (binary data)
 !:mime	text/x-shellscript
 0	string/fwt	#!\ /usr/bin/env\ bash	Bourne-Again shell script text executable
 !:mime	text/x-shellscript
@@ -107,22 +116,33 @@
 !:mime	text/x-shellscript
 
 0	search/1/fwt	#!\ /usr/bin/tclsh	Tcl/Tk script text executable
-!:mime  text/x-tcl
+!:mime	text/x-tcl
 
 0	search/1/fwt	#!\ /usr/bin/texlua	LuaTex script text executable
 !:mime	text/x-luatex
+0	search/1/fwt	#!\ /usr/bin/env\ texlua	LuaTex script text executable
+!:mime	text/x-luatex
+0	search/1/fwt	#!\ /bin/env\ texlua	LuaTex script text executable
+!:mime	text/x-luatex
 
 0	search/1/fwt	#!\ /usr/bin/luatex	LuaTex script text executable
 !:mime	text/x-luatex
 
 0	search/1/fwt	#!\ /usr/bin/stap	Systemtap script text executable
-!:mime  text/x-systemtap
+!:mime	text/x-systemtap
 0	search/1/fwt	#!\ /sbin/openrc-run	OpenRC script text executable
-!:mime  text/x-shellscript
+!:mime	text/x-shellscript
+
+# From: Marc Chantreux <mc@unistra.fr>
+# [Raku](https://raku.org/) script
+0	string/fwt	#!\ /bin/raku		Raku (http://raku.org) script
+!:mime	text/x-raku
+0	string/fwt	#!\ /usr/bin/raku	Raku (http://raku.org) script
+!:mime	text/x-raku
 
 # From: Kylie McClain <kylie@somas.is>
 # Type: execline scripts
-# URL:  https://skarnet.org/software/execline/
+# URL:	https://skarnet.org/software/execline/
 0	string/fwt	#!\ /command/execlineb		execline script text executable
 !:mime	text/x-execline
 0	string/fwt	#!\ /bin/execlineb		execline script text executable
@@ -142,17 +162,17 @@
 # PHP scripts
 # Ulf Harnhammar <ulfh@update.uu.se>
 0	search/1/c	=<?php			PHP script text
-!:strength + 30
+!:strength + 55
 !:mime	text/x-php
 0	search/1	=<?\n			PHP script text
 !:mime	text/x-php
 0	search/1	=<?\r			PHP script text
 !:mime	text/x-php
 0	search/1/w	#!\ /usr/local/bin/php	PHP script text executable
-!:strength + 10
+!:strength + 55
 !:mime	text/x-php
 0	search/1/w	#!\ /usr/bin/php	PHP script text executable
-!:strength + 10
+!:strength + 55
 !:mime	text/x-php
 # Smarty compiled template, https://www.smarty.net/
 # Elan Ruusamae <glen@delfi.ee>
@@ -193,21 +213,21 @@
 0	string/t	$!			DCL command file
 
 # Type: Pdmenu
-# URL:  https://packages.debian.org/pdmenu
+# URL:	https://packages.debian.org/pdmenu
 # From: Edward Betts <edward@debian.org>
 0	string		#!/usr/bin/pdmenu	Pdmenu configuration file text
 
 # From Danny Weldon
 0	string	\x0b\x13\x08\x00
->0x04   uleshort	<4      ksh byte-code version %d
+>0x04	uleshort	<4	ksh byte-code version %d
 
 # From: arno <arenevier@fdn.fr>
 # mozilla xpconnect typelib
 # see https://www.mozilla.org/scriptable/typelib_file.html
-0	string 		XPCOM\nTypeLib\r\n\032		XPConnect Typelib
->0x10  byte        x       version %d
->>0x11 byte        x      \b.%d
+0	string		XPCOM\nTypeLib\r\n\032		XPConnect Typelib
+>0x10  byte	   x	   version %d
+>>0x11 byte	   x	  \b.%d
 
 0	string/fwt	#!\ /usr/bin/env\ runghc	GHC script executable
 0	string/fwt	#!\ /usr/bin/env\ runhaskell	Haskell script executable
-0	string/fwt	#!\ /usr/bin/env\ julia	Julia script executable
+0	string/fwt	#!\ /usr/bin/env\ julia Julia script executable

+ 91 - 1
magic/Magdir/console

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: console,v 1.80 2024/11/09 23:55:02 christos Exp $
+# $File: console,v 1.81 2026/01/31 15:44:17 christos Exp $
 # Console game magic
 # Toby Deshane <hac@shoelace.digivill.net>
 
@@ -1376,3 +1376,93 @@
 >0x20	ubelong	1		PowerPC
 >>0xA4	ubelong	0x11		\b, Wii U mode
 >>0xA4	ubelong	0x12		\b, Wii mode
+
+# Type: WonderSwan raw ROM format
+# (Also covers the WonderSwan WSR sound format, which is an extension thereof)
+# From: Adrian Siekierka <kontakt@asie.pl>
+# Reference: https://ws.nesdev.org/wiki/ROM_header
+0	name	wonderswan-maintenance
+>0	ubyte&0x80	=128	\b, custom splash screen bypassed
+
+0	name	wonderswan-version
+>0	ubyte&0x7F	x	\b, rev. %d
+>0	ubyte&0x80	=128	\b, internal EEPROM unlocked
+
+0	name	wonderswan-rom-size
+>0	byte	0x00	\b, ROM: 1Mbit
+>0	byte	0x01	\b, ROM: 2Mbit
+>0	byte	0x02	\b, ROM: 4Mbit
+>0	byte	0x03	\b, ROM: 8Mbit
+>0	byte	0x04	\b, ROM: 16Mbit
+>0	byte	0x05	\b, ROM: 24Mbit
+>0	byte	0x06	\b, ROM: 32Mbit
+>0	byte	0x07	\b, ROM: 48Mbit
+>0	byte	0x08	\b, ROM: 64Mbit
+>0	byte	0x09	\b, ROM: 128Mbit
+>0	byte	0x0A	\b, ROM: 256Mbit
+>0	byte	0x0B	\b, ROM: 512Mbit
+
+0	name	wonderswan-save-type
+>0	ubyte&0x0F	=1	\b, RAM: 256Kbit
+>0	ubyte&0x0F	=2	\b, RAM: 256Kbit
+>0	ubyte&0x0F	=3	\b, RAM: 1Mbit
+>0	ubyte&0x0F	=4	\b, RAM: 2Mbit
+>0	ubyte&0x0F	=5	\b, RAM: 4Mbit
+>0	ubyte&0xF0	=16	\b, EEPROM: 1Kbit
+>0	ubyte&0xF0	=32	\b, EEPROM: 16Kbit
+>0	ubyte&0xF0	=80	\b, EEPROM: 8Kbit
+
+0	name	wonderswan-flags
+>0	ubyte&0x01	=0	\b, orientation: horizontal
+>0	ubyte&0x01	=1	\b, orientation: vertical
+
+0	name	wonderswan-rom-flags
+>0	ubyte&0x04	=0	\b, bus: 8-bit
+>0	ubyte&0x04	=4	\b, bus: 16-bit
+>0	ubyte&0x08	=8	\b, slow
+
+0	name	wonderswan-mapper
+>0	ubyte&0x0F	=0	\b, mapper: 2001
+>0	ubyte&0x0F	=1	\b, mapper: 2003
+
+-16	ubyte	0xEA
+>-32	string	WSRF\x00	WonderSwan WSR sound file, based on
+>-11	ubyte&0x0F	=0
+>>-9	ubyte&0x01	=0	WonderSwan ROM image
+!:ext	ws/pc2
+>>-9	ubyte&0x01	=1	WonderSwan Color ROM image
+!:ext	wsc
+>>-11	use	wonderswan-maintenance
+>>-7	use	wonderswan-version
+>>-7	use	wonderswan-rom-size
+>>-4	use	wonderswan-rom-flags
+>>-7	use	wonderswan-save-type
+>>-4	use	wonderswan-flags
+>>-3	use	wonderswan-mapper
+
+# Type: WonderWitch transfer file
+# From: Adrian Siekierka <kontakt@asie.pl>
+# Reference: https://ws.nesdev.org/wiki/WonderWitch_.fx_files
+0	string	#!ws\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff	WonderWitch transfer file
+!:ext	fx/il
+>64	string/16	x	\b, name "%s"
+>80	string/24	x	\b, info "%s"
+>108	ulelong		x	\b, %u bytes
+>112	uleshort	x	\b (%d blocks)
+>114	uleshort	>0	\b, mode "
+>>114	uleshort&0x80	>0	\bd
+>>114	uleshort&0x40	>0	\bl
+>>114	uleshort&0x20	>0	\bi
+>>114	uleshort&0x10	>0	\bs
+>>114	uleshort&0x08	>0	\bm
+>>114	uleshort&0x04	>0	\br
+>>114	uleshort&0x02	>0	\bw
+>>114	uleshort&0x01	>0	\bx
+>>114	uleshort	>0	\b"
+>124	lelong		>0	\b, resource data after %d bytes
+
+# Type: Aquaplus P/ECE executable format
+# From: Adrian Siekierka <kontakt@asie.pl>
+0		uleshort	0x0258	P/ECE executable
+>(0x04.s)	string		x	\b: "%s"
+!:ext	pex

+ 26 - 0
magic/Magdir/creativeassembly

@@ -0,0 +1,26 @@
+
+#--------------------------------------------------------------
+# $File: creativeassembly,v 1.1 2026/02/01 16:25:09 christos Exp $
+# creativeassembly: file(1) magic for various Creative Assembly files
+#
+# Community file formats documentation: 
+# 	<https://github.com/TotalWar-Modding/docs>
+
+# Benedikt Radtke <benediktradtke@gmail.com>
+# PFH4 Archive
+0	lelong		0x34484650	Creative Assembly Archive version 4
+
+# Benedikt Radtke <benediktradtke@gmail.com>
+# PFH5 Archive
+0	lelong		0x35484650	Creative Assembly Archive version 5
+>&0	lelong&0xf	0x00		\b, boot archive
+>&0	lelong&0xf	0x01		\b, release archive
+>&0	lelong&0xf	0x02		\b, patch archive
+>&0	lelong&0xf	0x03		\b, mod archive
+>&0	lelong&0xf	0x04		\b, movie archive
+>&0	lelong&0x10	0x10		\b, data encrypted
+>&0	lelong&0x40	0x40		\b, timestamped files
+>&0	lelong&0x80	0x80		\b, index encrypted
+>&0	lelong&0x100	0x100		\b, big header
+>&0x0c	lelong		x		\b, %d files
+#>0x14	ledate		x		\b, created on %s

+ 101 - 1
magic/Magdir/database

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: database,v 1.73 2024/11/09 19:54:36 christos Exp $
+# $File: database,v 1.75 2025/11/10 16:06:19 christos Exp $
 # database:  file(1) magic for various databases
 #
 # extracted from header/code files by Graeme Wilford (eep2gw@ee.surrey.ac.uk)
@@ -909,3 +909,103 @@
 # so we check both to detect them also on hosts with differnet endianess
 16      lelong    0xED0CDAED      BoltDB database
 16      belong    0xED0CDAED      BoltDB database, big-endian
+
+# https://en.wikipedia.org/wiki/HCL_Notes
+0	string	\x1A\x00\x00\x03\x00\x00	Notes Storage Facility database
+
+# PostgreSQL WAL segment
+# repo: https://git.postgresql.org/gitweb/?p=postgresql.git;a=summary
+# file: src/include/access/xlog_internal.h
+# header structure is XLogPageHeaderData+XLogLongPageHeaderData
+# magic header numbers are defined in XLOG_PAGE_MAGIC
+# The magic number is too short to safely identify a file; but since the
+# WAL log pages repeat in a file, we can test the magic number on the
+# headers of more than one page to make a safer match. Two is ok for now.
+
+0        short 0xd118
+(0x24.l) short 0xd118 PostgreSQL 18 
+>0 use pgwal
+
+0        short 0xd116
+(0x24.l) short 0xd116 PostgreSQL 17 
+>0 use pgwal
+
+0        short 0xd113
+(0x24.l) short 0xd113 PostgreSQL 16 
+>0 use pgwal
+
+0        short 0xd110
+(0x24.l) short 0xd110 PostgreSQL 15 
+>0 use pgwal
+
+0        short 0xd10d
+(0x24.l) short 0xd10d PostgreSQL 14 
+>0 use pgwal
+
+0        short 0xd106
+(0x24.l) short 0xd106 PostgreSQL 13 
+>0 use pgwal
+
+0        short 0xd101
+(0x24.l) short 0xd101 PostgreSQL 12 
+>0 use pgwal
+
+0        short 0xd098
+(0x24.l) short 0xd098 PostgreSQL 11 
+>0 use pgwal
+
+0        short 0xd097
+(0x24.l) short 0xd097 PostgreSQL 10 
+>0 use pgwal
+
+0        short 0xd093
+(0x24.l) short 0xd093 PostgreSQL 9.6 
+>0 use pgwal
+
+0        short 0xd087
+(0x24.l) short 0xd087 PostgreSQL 9.5 
+>0 use pgwal
+
+0        short 0xd07e
+(0x24.l) short 0xd07e PostgreSQL 9.4 
+>0 use pgwal
+
+0        short 0xd075
+(0x24.l) short 0xd075 PostgreSQL 9.3 
+>0 use pgwal
+
+0        short 0xd071
+(0x24.l) short 0xd071 PostgreSQL 9.2 
+>0 use pgwal
+
+0        short 0xd066
+(0x24.l) short 0xd066 PostgreSQL 9.1 
+>0 use pgwal
+
+0        short 0xd064
+(0x24.l) short 0xd064 PostgreSQL 9.0 
+>0 use pgwal
+
+0        short 0xd063
+(0x24.l) short 0xd063 PostgreSQL 8.4 
+>0 use pgwal
+
+0        short 0xd062
+(0x24.l) short 0xd062 PostgreSQL 8.3 
+>0 use pgwal
+
+0        short 0xd05e
+(0x24.l) short 0xd05e PostgreSQL 8.2 
+>0 use pgwal
+
+0        short 0xd05d
+(0x24.l) short 0xd05d PostgreSQL 8.1 
+>0 use pgwal
+
+0        short 0xd05c
+(0x24.l) short 0xd05c PostgreSQL 8.0 
+>0 use pgwal
+
+0     name  pgwal     WAL segment file
+>0x18 quad  x         (System ID %lld,
+>0x04 long  x         Timeline %d)

+ 26 - 5
magic/Magdir/filesystems

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: filesystems,v 1.165 2024/09/01 15:51:51 christos Exp $
+# $File: filesystems,v 1.169 2025/12/27 15:29:44 christos Exp $
 # filesystems:  file(1) magic for different filesystems
 #
 0	name	partid
@@ -1950,8 +1950,23 @@
 >36865	string    BEA01     +
 >>36864	use       extendedarea
 
-37633	string    CD001     ISO 9660 CD-ROM filesystem data (raw 2352 byte sectors)
-!:mime	application/x-iso9660-image
+# ISO 9660 as part of various raw CD-ROM image formats.
+# Usually the BIN file of a CUE/BIN pair or the IMG of a CCD/IMG/SUB triplet.
+
+# MODE1/2352 (2352*16 + 16 + 1)
+37649	string    CD001     ISO 9660 CD-ROM filesystem data
+>0	default	x	(CD-ROM Mode 1 image, 2352 byte sectors)
+!:ext	bin/img
+
+# MODE2/2352 (2352*16 + 24 + 1)
+37657	string    CD001     ISO 9660 CD-ROM filesystem data
+>0	default	x	(CD-ROM XA Mode 2 image, 2352 byte sectors)
+!:ext	bin/img
+
+# MODE2/2336 (2336*16 + 8 + 1)
+37385	string    CD001     ISO 9660 CD-ROM filesystem data
+>0	default	x	(CD-ROM XA Mode 2 image, 2336 byte sectors)
+!:ext	bin
 
 # URL:		http://fileformats.archiveteam.org/wiki/High_Sierra
 # Update:	Joerg Jenderek
@@ -2607,7 +2622,7 @@
 >12	use next
 
 # bcachefs
-# From: Thomas Weißschuh <thomas@t-8ch.de>
+# From: Thomas Weissschuh <thomas@t-8ch.de>
 
 0	name	bcachefs-uuid
 >0	ubelong		x	\b%08x
@@ -2654,7 +2669,8 @@
 #>1060		lelong		x		\b, blocks=%d
 #>1064		lelong		x		\b, metadata@%#x
 #>1068		lelong		x		\b, xattr@%#x
->1072		guid		x		\b, uuid=%s
+>1072		guid		x		\b, uuid=
+>1072		use		bcachefs-uuid
 >1088		string		>0		\b, name=%s
 >1104		lelong		>0		\b, incompat:
 >>1104		lelong		&1		LZ4_0PADDING
@@ -2763,3 +2779,8 @@
 0x0		string	\x10\x00\x4e\x57\x20
 >0x10000	string	\x4e\x57\x00\x00\x01
 >0x100A2	string	\x4C\x00\x40 EldOS Corporation SolidFS, 64KiB page size
+
+# YBLOB mini object storage
+# PIN-protected storage format based on the PIV application
+# https://github.com/douzebis/yb
+0    lelong    0xF2ED5F0B    yblob object store image data

+ 140 - 5
magic/Magdir/firmware

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: firmware,v 1.13 2024/09/04 19:04:03 christos Exp $
+# $File: firmware,v 1.17 2025/04/06 18:37:40 christos Exp $
 # firmware:  file(1) magic for firmware files
 #
 
@@ -110,7 +110,7 @@
 >>28	ulelong&0x1	1		\b, encrypted
 
 # ESP-IDF application image
-# From: Alexandre Iooss <erdnaxe@crans.org>
+# From: A. Iooss <aiooss@crans.org>
 # Update:	Joerg Jenderek
 # URL: https://github.com/espressif/esp-idf/blob/v5.0/components/bootloader_support/include/esp_app_format.h
 # Reference:	https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/app_image_format.html
@@ -134,13 +134,34 @@
 >>12	uleshort	0x000D		for ESP32-C6
 >>12	uleshort	0x000E		for ESP32-H2 Beta2
 >>12	uleshort	0x0010		for ESP32-H2
->>80	string/32	x		\b, project name: "%s"
->>48	string/32	x		\b, version %s
+>>80	byte		!0
+>>>80	string/32	x		\b, project name: "%s"
+>>48	byte		!0
+>>>48	string/32	x		\b, version %s
 >>128	string/16	x		\b, compiled on %s
 >>>112	string/16	x		%s
 >>144	string/32	x		\b, IDF version: %s
 >>4	ulelong		x		\b, entry address: 0x%08X
 
+# ESP8266/ESP32 firmware image
+# Note: contain partition table entries and ESP-IDF application image
+# From: A. Iooss <aiooss@crans.org>
+# Reference: https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/firmware-image-format.html
+0	byte		0xE9
+>2	byte		<4
+>>7	byte		0x40		ESP firmware image
+# ESP8266 does not have Extended File Header
+>>>12	uleshort	0x0000		for ESP32
+>>>12	uleshort	0x0002		for ESP32-S2
+>>>12	uleshort	0x0005		for ESP32-C3
+>>>12	uleshort	0x0009		for ESP32-S3
+>>>12	uleshort	0x000A		for ESP32-H2 Beta1
+>>>12	uleshort	0x000C		for ESP32-C2
+>>>12	uleshort	0x000D		for ESP32-C6
+>>>12	uleshort	0x000E		for ESP32-H2 Beta2
+>>>12	uleshort	0x0010		for ESP32-H2
+>>>4	ulelong		x		\b, entry point 0x%08X
+
 # AVR firmware
 # From: Alexandre Iooss <erdnaxe@crans.org>
 # URL: https://microchipdeveloper.com/8avr:int
@@ -174,7 +195,7 @@
 # Reference:	http://www.piclist.com/techref/fileext/hex/intel.htm
 #		http://mark0.net/download/triddefs_xml.7z/defs/h/hex-intel.trid.xml
 # From:		Joerg Jenderek
-# Note:		called "Intel Hexadecimal object format" by TrID, "Intel® hexadecimal object file" on Linux
+# Note:		called "Intel Hexadecimal object format" by TrID, "Intel(R) hexadecimal object file" on Linux
 #		and "Intel HEX binary data" by Notepad++
 # look for start code; 1 character, an ASCII colon ':'; all characters preceding this symbol should be ignored
 0	ubyte		0x3A
@@ -275,3 +296,117 @@
 >-10	string		\x1A\x01UFD
 >>-12	uleshort	x		\b, for device %04X:
 >>-14	uleshort	x		\b%04X
+
+# Allwinner eGON Boot Image
+# Reference: https://linux-sunxi.org/EGON
+
+0	name	egon-details
+# ARM b instruction
+>0	ulelong&0xff000000	0xea000000	(ARM)
+# RISC-V jal instruction
+>0	ulelong&0x00000fff	0x0000006f	(RISC-V)
+>16	ulelong	x	\b, size %u
+
+4	string	eGON.BT0	Allwinner eGON.BT0 Boot Image
+>0	use	egon-details
+
+4	string	eGON.BT1	Allwinner eGON.BT1 Boot Image
+>0	use	egon-details
+
+# Allwinner TOC0 Boot Image
+# Reference: https://linux-sunxi.org/TOC0
+0	name	toc0-item
+>0	ulelong	0x010101	certificate
+>0	ulelong	0x010202	firmware
+>0	ulelong	0x010303	key
+>4	ulelong	x	(offset 0x%x
+>8	ulelong	x	\b, size 0x%x)
+
+8	ulelong	0x89119800	Allwinner TOC0 Boot Image
+>24	ulelong	x	with %u items
+# each item is 32 bytes
+# item 0
+>24	ulelong	>0	\b:
+>>48	use	toc0-item
+# item 1
+>24	ulelong	>1	\b,
+>>80	use	toc0-item
+# item 2
+>24	ulelong	>2	\b,
+>>112	use	toc0-item
+# item 3
+>24	ulelong	>3	\b,
+>>144	use	toc0-item
+# item 4
+>24	ulelong	>4	\b,
+>>176	use	toc0-item
+# item 5+
+>24	ulelong	>5	\b, ...
+
+# Allwinner TOC1 Boot Image
+# Reference: https://lore.kernel.org/all/20211015040811.56856-2-samuel@sholland.org/T/
+0	name	toc1-item
+>0	string/64/T	x	%s
+>64	ulelong	x	(offset 0x%x
+>68	ulelong	x	\b, size 0x%x)
+
+16	ulelong	0x89119800	Allwinner TOC1 Boot Image
+>0	string/16/T	>\0	(name "%s")
+>32	ulelong	x	with %u items
+# each item is 368 bytes
+# item 0
+>32	ulelong	>0	\b:
+>>64	use	toc1-item
+# item 1
+>32	ulelong	>1	\b,
+>>432	use	toc1-item
+# item 2
+>32	ulelong	>2	\b,
+>>800	use	toc1-item
+# item 3
+>32	ulelong	>3	\b,
+>>1168	use	toc1-item
+# item 4
+>32	ulelong	>4	\b,
+>>1536	use	toc1-item
+# item 5+
+>32	ulelong	>5	\b, ...
+
+# https://github.com/o-gs/dji-firmware-tools/blob/master/dji_imah_fwsig.py#L404
+0	string		IM*H	DJI firmware update
+>40	string/4	>\0	(auth %s,
+>44	string/4	>\0	enc %s)
+>44	string/4	=\0	no enc)
+
+# NXP i.MX RT firmware image
+# From: A. Iooss <aiooss@crans.org>
+# Reference: Table 8-2 in MCU_Flashloader_Reference_Manual.pdf
+# URL: https://github.com/tock/tock/blob/master/boards/teensy40/layout.ld
+# Image starts with a NOR FlexSPI Configuration Block (FCB) of 3kB or 4kB
+0		string			FCFB
+>7		string			V		NXP i.MX RT bootable image
+!:ext		bin
+>>6		byte			x		\b, version %d
+>>5		byte			x		\b.%d
+>>4		byte			x		\b.%d
+# then a Image Vector Table of 4kB
+>>3072		ulelong&0xFCFFFFFF	0x402000D1
+>>>7168		use			flexspi-fw
+>>4096		ulelong&0xFDFFFFFF	0x402000D1
+>>>5120		use			flexspi-fw
+>>4096		ulelong&0xFDFFFFFF	0x412000D1
+>>>8192		use			flexspi-fw
+# then maybe a ARM Cortex-M program, but with vector table pointing to peripheral memory
+0		name			flexspi-fw
+>3		byte			0x20
+>>4		ulelong&1		1
+>>>8		ulelong&1		1
+>>>>12		ulelong&1		1
+>>>>>44		ulelong&1		1
+>>>>>>56	ulelong&1		1		\b, ARM Cortex-M
+>>>>>>>0	ulelong			>0		\b, initial SP at 0x%08x
+>>>>>>>4	ulelong^1		x		\b, reset at 0x%08x
+>>>>>>>8	ulelong^1		x		\b, NMI at 0x%08x
+>>>>>>>12	ulelong^1		x		\b, HardFault at 0x%08x
+>>>>>>>44	ulelong^1		x		\b, SVCall at 0x%08x
+>>>>>>>56	ulelong^1		x		\b, PendSV at 0x%08x

+ 7 - 7
magic/Magdir/fonts

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: fonts,v 1.52 2024/11/09 23:52:53 christos Exp $
+# $File: fonts,v 1.54 2025/02/10 22:01:36 rrt Exp $
 # fonts:  file(1) magic for font data
 #
 0	search/1	FONT		ASCII vfont text
@@ -276,14 +276,14 @@
 # maximal 27 tables found like in Skia.ttf
 # 46 different table names mentioned on Apple specification
 # skip 1st sequence of DOS 2 backup with path separator (\~92 or /~47) misinterpreted as table number
->4	ubeshort	<47		
+>4	ubeshort	<48
 # skip bad examples with garbage table names like in a5.show HYPERC MAC
 # tag names consist of up to four characters padded with spaces at end like
-# BASE DSIG OS/2 Zapf acnt glyf cvt vmtx xref ...
->>12	regex/4l	\^[A-Za-z][A-Za-z][A-Za-z/][A-Za-z2\ ]	
+# BASE C2PA DSIG OS/2 Zapf acnt glyf cvt vmtx xref ...
+>>12	regex/4l	\^[A-Za-z][A-Za-z2][A-Za-z/][A-Za-z2\ ]	
 #>>>0	ubelong	x	\b, sfnt version %#x
 >>>0	ubelong	!0x4f54544f	TrueType
-!:mime	font/sfnt
+!:mime	font/ttf
 !:apple	????tfil
 # .ttf for TrueType font
 # EUDC.tte created by privat character editor %WINDIR%\system32\eudcedit.exe
@@ -295,8 +295,8 @@
 !:ext	otf
 >>>0	ubelong	x		Font data
 # DSIG=44454947h table name implies a digitally signed font
-# search range = number of tables * 16 =< maximal number of tables * 16 = 27 * 16 = 432
->>>12	search/432	DSIG		\b, digitally signed
+# search range = number of tables * 16 =< maximal number of tables * 16 = 28 * 16 = 432
+>>>12	search/448	DSIG		\b, digitally signed
 >>>4	ubeshort	x		\b, %d tables
 # minimal 9 tables found like in NISC18030.ttf
 #>>>4	ubeshort	<10		TMIN

+ 54 - 10
magic/Magdir/games

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: games,v 1.35 2024/11/09 23:04:46 christos Exp $
+# $File: games,v 1.38 2025/05/31 15:42:06 christos Exp $
 # games:  file(1) for games
 
 # Fabio Bonelli <fabiobonelli@libero.it>
@@ -245,14 +245,14 @@
 # Type:	SGF Smart Game Format
 # URL:	https://www.red-bean.com/sgf/
 # From:	Eduardo Sabbatella <eduardo_sabbatella@yahoo.com.ar>
-2	regex/c	\\(;.*GM\\[[0-9]{1,2}\\]	Smart Game Format
->2	regex/c	GM\\[1\\]			- Go Game
->2	regex/c	GM\\[6\\]			- BackGammon Game
->2	regex/c	GM\\[11\\]			- Hex Game
->2	regex/c	GM\\[18\\]			- Amazons Game
->2	regex/c	GM\\[19\\]			- Octi Game
->2	regex/c	GM\\[20\\]			- Gess Game
->2	regex/c	GM\\[21\\]			- twix Game
+2	regex	\\(;.*GM\\[[0-9]{1,2}\\]	Smart Game Format
+>2	regex	GM\\[1\\]			- Go Game
+>2	regex	GM\\[6\\]			- BackGammon Game
+>2	regex	GM\\[11\\]			- Hex Game
+>2	regex	GM\\[18\\]			- Amazons Game
+>2	regex	GM\\[19\\]			- Octi Game
+>2	regex	GM\\[20\\]			- Gess Game
+>2	regex	GM\\[21\\]			- twix Game
 
 # Epic Games/Unreal Engine Package
 # URL: https://docs.unrealengine.com/udk/Three/ContentCooking.html
@@ -436,7 +436,7 @@
 0	uleshort	0x0469    	GTA2 binary mission script (SCR), Industrial area (bil)
 
 0	string   	v9.6\0\0 	GTA2 replay file (REP),
->8	regex/30c	[a-z0-9:\ ]+\0\0	created on %s
+>8	regex/30	[a-z0-9:\ ]+\0\0	created on %s
 
 # GTA 3D-Era (III/VC/SA/LCS/VCS) - used by the RenderWare engine by Criterion Games
 
@@ -664,3 +664,47 @@
 >122	ubyte		0x01	pcxLib archive
 >>144	uleshort	0	\b, uncompressed
 >>144	uleshort	!0	\b, compressed
+
+# RGSSAD asset archive used in RPG Maker XP, VX and VX Ace
+0	string	RGSSAD\0
+>7	byte	x	RPG Maker RGSSAD asset archive. version %u
+!:ext rgssad/rgss2a/rgss3a
+
+# Panda3D BAM model format
+# From: Derzsi Daniel <daniel@tohka.us>
+# URL:  https://gist.github.com/rdb/13cb936f41e0339a9a9cf9651ea2b09f
+0	string	pbj\0\n\r	Panda3D BAM file
+>10	ubyte	x	version %u
+>12	ubyte	x	\b.%u
+# Version >= 5.0 has little-endian and big-endian formats
+>10	ubyte	>4
+>>14	ubyte	0	\b, big-endian vertex data
+>>14	ubyte	1	\b, little-endian vertex data
+>10	ubyte	<5	\b, little-endian vertex data
+# Version >= 6.27 has single-precision and double-precision floats
+>10	ubyte	=6
+>>12	ubyte	>26
+>>>15	ubyte	0	\b, single-precision floats
+>>>15	ubyte	1	\b, double-precision floats
+>>12	ubyte	<27	\b, single-precision floats
+>10	ubyte	>6
+>>15	ubyte	0	\b, single-precision floats
+>>15	ubyte	1	\b, double-precision floats
+>10	ubyte	<6	\b, single-precision floats
+
+# Panda3D Multifile archive format
+# From: Derzsi Daniel <daniel@tohka.us>
+# URL:  https://tohka.us/p/exploring-encrypted-multifiles-a-technical-overview
+0	string	pmf\0\n\r	Panda3D Multifile archive
+>6	uleshort	x	version %u
+>8	uleshort	x	\b.%u
+# Version >= 1.1 has creation date information, missing if set to zero
+>6	uleshort	=1
+>>8	uleshort	>0
+>>>14	uledate	=0	\b, unknown creation date
+>>>14	uledate	!0	\b, created: %s
+>>8	uleshort	<1	\b, unknown creation date
+>6	uleshort	>1
+>>14	uledate	=0	\b, unknown creation date
+>>14	uledate	!0	\b, created: %s
+>6	uleshort	<1	\b, unknown creation date

+ 23 - 0
magic/Magdir/gguf

@@ -0,0 +1,23 @@
+
+#------------------------------------------------------------------------------
+# $File: gguf,v 1.2 2025/03/10 20:50:40 christos Exp $
+# 
+#
+# GGUF: magic file for GGUF-models
+# URL:  https://github.com/ggml-org/ggml/
+# From: Noah Peterson <noahbpeterson1997@gmail.com>
+
+0          string      GGUF               GGUF file format
+>4         byte        x                  version %d
+>8         quad        x                  \b, %llu tensors
+>16        quad        >0                 \b, %llu metadata entries
+>&8        search/256  general.architecture    
+>>&12      regex       ([A-Za-z0-9-]+)   \b, Architecture: %s
+>&8        search/256  general.name    
+>>&12      regex       ([A-Za-z0-9\ -]+) \b, Name: %s
+>&0        search/512  .block_count
+>>&4       long        x                  \b, Block Count: %u
+>&0        search/512  context_length
+>>&4       long        x                  \b, Context Length: %u
+>&0        search/512  embedding_length
+>>&4       long        x                  \b, Embedding Length: %u

+ 7 - 1
magic/Magdir/ibm370

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: ibm370,v 1.13 2024/06/19 16:52:57 christos Exp $
+# $File: ibm370,v 1.14 2026/01/10 15:49:11 christos Exp $
 # ibm370:  file(1) magic for IBM 370 and compatibles.
 #
 # "ibm370" said that 0x15d == 0535 was "ibm 370 pure executable".
@@ -56,3 +56,9 @@
 # to 8 bytes. According to https://www.ibm.com/support/pages/apar/PK91585
 # IEWPLMH is eyecatcher for "Binder Program Load Module Header" control block
 0	string   	\xc9\xc5\xe6\xd7\xd3\xd4\xc8\x40	z/OS Program Object executable
+
+
+# https://www.cbttape.org/awstape.htm
+0	leshort	>0
+>2	leshort	0x0000
+>>4	leshort	0x00a0	IBM AWS file

+ 45 - 2
magic/Magdir/images

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: images,v 1.263 2024/11/10 20:44:30 christos Exp $
+# $File: images,v 1.267 2025/11/24 14:22:31 christos Exp $
 # images:  file(1) magic for image formats (see also "iff", and "c-lang" for
 # XPM bitmaps)
 #
@@ -644,7 +644,8 @@
 # GRR: with --keep-going option the line above gives duplicate messages
 0	search/1/ts	#FIG
 >&0	use		image-xfig
-# binary data variant with non ASCII text characters like Control-A or °C in thermostat.fig
+#                                                                     o
+# binary data variant with non ASCII text characters like Control-A or C in thermostat.fig
 0	search/1/bs	#FIG
 >&0	use		image-xfig
 #	display XFIG image describing text, mime type, file name extension and version
@@ -4565,6 +4566,7 @@
 >24		ulelong		0
 >>4		uleshort	0xA5E0	Aseprite asset file
 !:ext	aseprite
+!:mime	image/x-aseprite
 >>>0		ulelong		x	\b, size %u
 >>>6		uleshort	x	\b, frames %u
 >>>8		uleshort	x	\b, size %ux
@@ -4582,3 +4584,44 @@
 >>>38		leshort		x	\b%d)
 >>>40		uleshort	x	\b, grid size %dx
 >>>42		uleshort	x	\b%d
+
+# Type: CIS/COD Bitmaps
+# Documentation: https://cod.igada.de/ and http://fileformats.archiveteam.org/wiki/Lightning_Strike
+# From: Robert Jäschke <robert.jaeschke at hu-berlin.de>
+0           string/b  CIS
+>4          ubyte     0x2e
+>>3         ubyte     >0x31
+>>>3        ubyte     <0x34     CIS/COD image data
+!:mime  image/cis-cod
+!:ext   cod
+
+# versions 2.3 to 2.5 are different to version 3.0
+>>>>3       regex/4   2\\.[345] \b, version %s
+>>>>>16     uleshort  x         \b, %u x
+>>>>>18     uleshort  x         %u
+
+# so far we know more about version 3.0
+>>>>3       string/3  3.0       \b, version %s
+# width and height
+>>>>>16     uleshort  x         \b, %u x
+>>>>>18     uleshort  x         %u x
+>>>>>20     ubyte     x         %u
+
+# gray vs. color
+>>>>>21     byte      0         \b, gray
+>>>>>21     byte      1         \b, color
+# encoder type
+>>>>>24     byte      1         \b, lossy arithmetic encoder
+>>>>>24     byte      2         \b, lossless arithmetic encoder
+# compression type
+>>>>>25     byte      1         \b, bi-wavelet compression
+# quantizer type
+>>>>>26     byte      1         \b, table quantization
+# scb
+>>>>>27     byte      1         \b, SISD
+# color space
+>>>>>28     byte      1         \b, YIQ RGB
+>>>>>28     byte      2         \b, YUV RGB
+>>>>>28     byte      3         \b, YCbCr RGB
+# wavelet levels
+>>>>>29     ubyte     x         \b, %u wavelet levels

+ 5 - 1
magic/Magdir/intel

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: intel,v 1.23 2022/10/31 13:22:26 christos Exp $
+# $File: intel,v 1.24 2025/01/30 19:02:08 christos Exp $
 # intel:  file(1) magic for x86 Unix
 #
 # Various flavors of x86 UNIX executable/object (other than Xenix, which
@@ -308,3 +308,7 @@
 # revision number of the ASL Compiler like: 20051117 20140724 20190703 20200110 ...
 >>>32	ulelong		x	%x
 
+# data that can be parsed by dmidecode(8) from a dump
+# or extracted from a bios image
+0	string		_SM3_
+>0x5	byte		<0x3	SMBIOS 3.x file

+ 31 - 1
magic/Magdir/linux

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: linux,v 1.91 2024/11/09 21:15:48 christos Exp $
+# $File: linux,v 1.95 2025/07/12 14:30:14 christos Exp $
 # linux:  file(1) magic for Linux files
 #
 # Values for Linux/i386 binaries, from Daniel Quinlan <quinlan@yggdrasil.com>
@@ -456,6 +456,8 @@
 ############################################################################
 # Linux S390 kernel image
 # Created by: Jan Kaluza <jkaluza@redhat.com>
+# Update: Jens Remus <jremus@linux.ibm.com> based on Vasily Gorbik <gor@linux.ibm.com>
+# Linux kernel: arch/s390/boot/head.S and arch/s390/include/asm/setup.h
 8 string \x02\x00\x00\x18\x60\x00\x00\x50\x02\x00\x00\x68\x60\x00\x00\x50\x40\x40\x40\x40\x40\x40\x40\x40 Linux S390
 >0x00010000 search/b/4096 \x00\x0a\x00\x00\x8b\xad\xcc\xcc
 # 64bit
@@ -468,6 +470,12 @@
 >>&0 string \x81\x00\xc8\x80\x00\x00\x00\x00 Z9-109 32bit kernel
 >>&0 string \x80\x00\x20\x00\x00\x00\x00\x00 Z990 32bit kernel
 >>&0 string \x80\x00\x00\x00\x00\x00\x00\x00 Z900 32bit kernel
+# Linux kernel v3.2+
+>0x10008	string		S390EP
+# Linux kernel v5.3+
+>>0x10428	ubequad		>0
+>>>(0x10428.Q)	string		>\0	\b, version %s
+
 
 ############################################################################
 # Linux ARM compressed kernel image
@@ -522,6 +530,17 @@
 >0x18   lelong  &6          \b, 32K pages
 
 ############################################################################
+# Linux kernel (arm64/riscv/loongarch) EFI executable (zstd/gzip) compressed zboot Image
+# from: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/efi/libstub/zboot-header.S
+0	string	MZ\0\0zimg
+>0x40   string	PE\0\0		Linux kernel
+>>&0	leshort	0xAA64		ARM64 EFI executable
+>>&0	leshort	0x5032          RISC-V32 EFI executable
+>>&0	leshort	0x5064          RISC-V64 EFI executable
+>>&0	leshort	0x6264          LoongArch64 EFI executable
+>>0x18 string	>0		%s compressed zboot Image
+
+############################################################################
 # Linux RISC-V kernel image
 0x38	string	RSC\05		Linux kernel RISC-V boot executable Image
 >0x18	lelong	^1		\b, little-endian
@@ -968,3 +987,14 @@
 0	lequad		0x32454c4946524550	Linux perf recording, version 2. little endian
 
 0	bequad		0x32454c4946524550	Linux perf recording, version 2. big endian
+
+# perf(1) (Performance analysis tools) command
+#
+# For file format details, see:
+#
+# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/\
+# tools/perf/Documentation/perf.data-file-format.txt
+
+# The file is normally called 'perf.data' but can take any name,
+# so only check the eye catcher value.
+0	string		PERFILE2	perf(1) data

+ 2 - 1
magic/Magdir/lua

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: lua,v 1.8 2020/10/08 23:23:56 christos Exp $
+# $File: lua,v 1.9 2026/01/25 16:07:06 christos Exp $
 # lua:  file(1) magic for Lua scripting language
 # URL:  https://www.lua.org/
 # From: Reuben Thomas <rrt@sc3d.org>, Seo Sanghyeon <tinuviel@sparcs.kaist.ac.kr>
@@ -29,3 +29,4 @@
 >4	byte		0x52			version 5.2
 >4	byte		0x53			version 5.3
 >4	byte		0x54			version 5.4
+>4	byte		0x55			version 5.5

+ 2 - 2
magic/Magdir/mail.news

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: mail.news,v 1.32 2024/11/10 16:59:38 christos Exp $
+# $File: mail.news,v 1.33 2025/02/28 19:28:01 christos Exp $
 # mail.news:  file(1) magic for mail and news
 #
 # Unfortunately, saved netnews also has From line added in some news software.
@@ -32,7 +32,7 @@
 !:mime	message/rfc822
 0	string/t		To:		news or mail text
 !:mime	message/rfc822
-0	string/t		Article 	saved news text
+0	regex/t			Article:[[:space:]]+[0-9]+  	saved news text
 !:mime	message/news
 # Reference:	http://quimby.gnus.org/notes/BABYL
 # Update:	Joerg Jenderek

+ 8 - 1
magic/Magdir/measure

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: measure,v 1.3 2021/03/25 17:30:10 christos Exp $
+# $File: measure,v 1.4 2026/01/23 16:41:32 christos Exp $
 # measure: file(1) magic for measurement data
 
 # DIY-Thermocam raw data
@@ -42,3 +42,10 @@
 (0x02.l)	string	*IDENTIFICATION		Becker & Hickl PMS Data File
 >0x12		short	x			(%d data blocks)
 !:ext sdt
+
+# https://www.asam.net/standards/detail/mdf/
+0	string	MDF\x20\x20\x20\x20\x20	ASAM/MDF measurement file Version
+>8	regex	.\\...			%s
+>12	string	\x20\x20\x20\x20
+>62	byte	!0			(unfinalized)
+>64	string	##HD

+ 15 - 48
magic/Magdir/msdos

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: msdos,v 1.208 2024/08/27 18:50:57 christos Exp $
+# $File: msdos,v 1.214 2025/09/06 17:00:32 christos Exp $
 # msdos:  file(1) magic for MS-DOS files
 #
 
@@ -24,9 +24,9 @@
 # OS/2 batch files are REXX. the second regex is a bit generic, oh well
 # the matched commands seem to be common in REXX and uncommon elsewhere
 100	search/0xffff   rxfuncadd
->100	regex/c =^[\ \t]{0,10}call[\ \t]{1,10}rxfunc	OS/2 REXX batch file text
+>100	regex	=^[\ \t]{0,10}call[\ \t]{1,10}rxfunc	OS/2 REXX batch file text
 100	search/0xffff   say
->100	regex/c =^[\ \t]{0,10}say\ ['"]			OS/2 REXX batch file text
+>100	regex/	=^[\ \t]{0,10}say\ ['"]			OS/2 REXX batch file text
 
 
 # Tests for various EXE types.
@@ -510,7 +510,7 @@
 >>>>>>>(0x3c.l+0x2a)	default		x
 # Binaries with KERNEL, USER or GDI import library are for Windows
 # FIXME: names are prefixed by its length, but regex type does not support binary bytes
->>>>>>>>&(&0.s-0x29)	regex/512/C	KERNEL|USER|GDI for MS Windows 1.x/2.x
+>>>>>>>>&(&0.s-0x29)	regex/512	KERNEL|USER|GDI for MS Windows 1.x/2.x
 >>>>>>>>>(0x3c.l+0x37)	byte&0x04	0	(real mode only)
 >>>>>>>>>(0x3c.l+0x37)	byte&0x04	!0	(real+protected mode)
 # Binaries without any of those import library can be for any OS
@@ -772,7 +772,13 @@
 >>>0x40			search/0x80	STUB/32C \b, DOS/32A DOS extender (configurable stub)
 >>>0x40			search/0x80	DOS/32A \b, DOS/32A DOS extender (embedded)
 
-# PX\0\0 signature for 32bit DOS Applications in DOS-PE Format (https://www.japheth.de/HX.html)
+# PL\0\0 signature for 32-bit DOS Applications in Phar Lap TNT PE/PL Format
+# Binaries can be created by TNT MARKPHAR.EXE or by 386LINK.EXE -markphar switch
+# FULLSCR.EXE, GDEMO.EXE, MOUSE.EXE from MSVC32s SDK and from Phar Lap TNT SDK
+>(0x3c.l)	string		PL\0\0	\b, PE32 executable for MS-DOS
+>>(8.s*16)	search/0x50	Phar\ Lap\ Software,\ Inc.	\b, Phar Lap TNT DOS extender
+
+# PX\0\0 signature for 32/64-bit DOS Applications in DOS-PE Format (https://www.japheth.de/HX.html)
 # SHDPMI.EXE, DOSTEST.EXE, GETVMODE.EXE, RMINT.EXE
 >(0x3c.l)	string		PX\0\0	\b, PE32
 >>(0x3c.l+24)	leshort		0x020b	\b+
@@ -793,6 +799,7 @@
 # Skip already parsed binary types
 # If magic in the branch is not parsed then always jumps to mz-unrecognized
 >(0x3c.l)	string	PE\0\0
+>(0x3c.l)	string	PL\0\0
 >(0x3c.l)	string	PX\0\0
 >(0x3c.l)	string	LX
 >(0x3c.l)	string	NE
@@ -2108,9 +2115,9 @@
 #	display shared information of cursor or icon entry
 0		name		cur-ico-entry
 >0		byte		=0		\b, 256x
->0		byte		!0		\b, %dx
+>0		ubyte		!0		\b, %dx
 >1		byte        	=0		\b256
->1		byte        	!0		\b%d
+>1		ubyte        	!0		\b%d
 # number of colors in palette
 >2		ubyte		!0		\b, %d colors
 # reserved 0 FFh
@@ -2516,7 +2523,7 @@
 # URL:		https://en.wikipedia.org/wiki/Microsoft_OneNote#File_format
 #		http://fileformats.archiveteam.org/wiki/OneNote
 # Reference:	https://mark0.net/download/triddefs_xml.7z/defs/o/onepkg.trid.xml
-# 1st member name like: "Class Notes.one" "test-onenote.one" "Open Notebook.onetoc2" "Editor Öffnen.onetoc2"
+# 1st member name like: "Class Notes.one" "test-onenote.one" "Open Notebook.onetoc2" "Editor offnen.onetoc2"
 >>>>>&0	string/c	one		\b, OneNote Package
 !:mime	application/msonenote
 !:ext	onepkg
@@ -2681,12 +2688,6 @@
 # next archive member name if more files
 #>>&17	string		>\0		\b, NEXT NAME %-.50s
 
-# InstallShield Cabinet files
-0	string/b	ISc(		InstallShield Cabinet archive data
->5	byte&0xf0	=0x60		version 6,
->5	byte&0xf0	!0x60		version 4/5,
->(12.l+40)	lelong	x		%u files
-
 # Windows CE package files
 0	string/b	MSCE\0\0\0\0	Microsoft WinCE install header
 >20	lelong		0		\b, architecture-independent
@@ -2821,40 +2822,6 @@
 # NB: The BACKUP.nnn files consist of the files backed up,
 # concatenated.
 
-# From:		Joerg Jenderek
-# URL:		http://fileformats.archiveteam.org/wiki/MS-DOS_date/time
-# Reference:	https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-dosdatetimetofiletime
-# Note:		DOS date+time format is different from formats such as Unix epoch
-#		bit encoded; uses year values relative to 1980 and 2 second precision
-0	name		dos-date
-# HHHHHMMMMMMSSSSS bit encoded Hour (0-23) Minute (0-59) SecondPart (*2)
-#>0	uleshort	x	RAW TIME [%#4.4x]
-# hour part
-#>0	uleshort/2048	x	hour [%u]
-# YYYYYMMMMDDDDD bit encoded YearPart (+1980) Month (1-12) Day (1-31)
-#>2	uleshort	x	RAW DATE [%#4.4x]
-# day part
->2	uleshort&0x001F	x	%u
-#>2	uleshort/16	x	MONTH PART [%#x]
-# GRR: not working
-#>2	uleshort/16	&0x000F	MONTH [%u]
-#>2	uleshort&0x01E0	x	MONTH PART [%#4.4x]
->2	uleshort&0x01E0	=0x0020	jan
->2	uleshort&0x01E0	=0x0040	feb
->2	uleshort&0x01E0	=0x0060	mar
->2	uleshort&0x01E0	=0x0080	apr
->2	uleshort&0x01E0	=0x00A0	may
->2	uleshort&0x01E0	=0x00C0	jun
->2	uleshort&0x01E0	=0x00E0	jul
->2	uleshort&0x01E0	=0x0100	aug
->2	uleshort&0x01E0	=0x0120	sep
->2	uleshort&0x01E0	=0x0140	oct
->2	uleshort&0x01E0	=0x0160	nov
->2	uleshort&0x01E0	=0x0180	dec
-# year part
->2	uleshort/512	x	1980+%u
-#
-
 # ExcelBIFF2-8BOF.magic - Excel Binary Interchange File Format versions 2-8
 # Beginning of File records
 # See https://www.gaia-gis.it/gaia-sins/freexl-1.0.6-doxy-doc/html/Format.html

+ 12 - 10
magic/Magdir/msooxml

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: msooxml,v 1.23 2024/07/19 18:48:23 christos Exp $
+# $File: msooxml,v 1.24 2025/05/29 15:03:04 christos Exp $
 # msooxml:  file(1) magic for Microsoft Office XML
 # From: Ralf Brown <ralf.brown@gmail.com>
 
@@ -26,6 +26,8 @@
 !:mime application/vnd.ms-visio.drawing.main+xml
 >0		string		AppManifest.xaml	Microsoft Silverlight Application
 !:mime application/x-silverlight-app
+>0		search/100	.nuspec		NuGet package
+!:mime application/vnd.nuget.package
 
 # start by checking for ZIP local file header signature
 0		string		PK\003\004
@@ -33,30 +35,30 @@
 # make sure the first file is correct
 >0x1E		use		msooxml
 >0x1E		default		x
->>0x1E		regex		\\[Content_Types\\]\\.xml|_rels/\\.rels|docProps|customXml
+>>0x1E		regex		\\[Content_Types\\]\\.xml|_rels/\\.rels|docProps|customXml|.*\\.md|.*\\.png
 # skip to the second local file header
 # since some documents include a 520-byte extra field following the file
 # header, we need to scan for the next header
->>>(18.l+49)	search/6000	PK\003\004
+>>>&26		search/10000	PK\003\004
 >>>>&26		use		msooxml
 >>>>&26		default		x
 # now skip to the *third* local file header; again, we need to scan due to a
 # 520-byte extra field following the file header
->>>>>&26	search/6000	PK\003\004
+>>>>>&26	search/10000	PK\003\004
 # and check the subdirectory name to determine which type of OOXML
 # file we have.	 Correct the mimetype with the registered ones:
 # https://technet.microsoft.com/en-us/library/cc179224.aspx
 >>>>>>&26	use		msooxml
 >>>>>>&26	default		x
 # OpenOffice/Libreoffice orders ZIP entry differently, so check the 4th file
->>>>>>>&26	search/6000	PK\003\004
+>>>>>>>&26	search/10000	PK\003\004
 >>>>>>>>&26	use		msooxml
 # Some OOXML generators add an extra customXml directory. Check another file.
 >>>>>>>>&26	default		x
->>>>>>>>>&26	search/6000	PK\003\004
+>>>>>>>>>&26	search/10000	PK\003\004
 >>>>>>>>>>&26	use		msooxml
 >>>>>>>>>>&26	default		x
->>>>>>>>>>>&26	search/6000	PK\003\004
+>>>>>>>>>>>&26	search/10000	PK\003\004
 >>>>>>>>>>>>&26	use		msooxml
 >>>>>>>>>>>>&26	default		x		Microsoft OOXML
 >>>>>>>>>>>&26	default		x		Microsoft OOXML
@@ -66,11 +68,11 @@
 >>>>>>>&26	default		x		Microsoft OOXML
 >>>>>>&26	default		x		Microsoft OOXML
 >>0x1E		regex		\\[trash\\]
->>>&26		search/6000	PK\003\004
->>>>&26		search/6000	PK\003\004
+>>>&26		search/10000	PK\003\004
+>>>>&26		search/10000	PK\003\004
 >>>>>&26	use		msooxml
 >>>>>&26	default		x
->>>>>>&26	search/6000	PK\003\004
+>>>>>>&26	search/10000	PK\003\004
 >>>>>>>&26	use		msooxml
 >>>>>>>&26	default		x		Microsoft OOXML
 >>>>>>&26	default		x		Microsoft OOXML

+ 44 - 1
magic/Magdir/music

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: music,v 1.2 2024/06/10 23:09:52 christos Exp $
+# $File: music,v 1.4 2026/02/07 21:56:41 rrt Exp $
 # music:  file(1) magic for music formats
 
 # BWW format used by Bagpipe Music Writer Gold by Robert MacNeil Musicworks
@@ -15,3 +15,46 @@
 >>>25	string		:
 >>>>26	string		>\0		(version %.3s)
 
+# Bars & Pipes Professional
+# https://wiki.amigaos.net/wiki/Bars_and_Pipes_Professional
+#
+0	string		BRPP		Bars & Pipes Professional
+
+# Sibelius music notation software (published by Sibelius Software, then Avid)
+# http://fileformats.archiveteam.org/wiki/Sibelius
+#
+# These patterns cover the Windows and macOS versions of the software, not
+# the older (confusingly-named) Sibelius 6 & 7 for Acorn RISC PC.
+0	string		\x0fSIBELIUS	Sibelius
+!:mime application/x-sibelius-score
+>10     string          \x00\x00\x00\x0e (version 1.2)
+>10     string          \x00\x08         (version 2.x)
+>10     string          \x00\x0a         (version 3.x)
+>10     string          \x00\x1b         (version 4.x)
+>10     string          \x00\x2d\x00\x03 (version 5.0)
+>10     string          \x00\x2d\x00\x0d (version 5.1)
+>10     string          \x00\x2d\x00\x10 (version 5.2)
+>10     string          \x00\x36\x00\x01 (version 6.0)
+>10     string          \x00\x36\x00\x17 (version 6.1)
+>10     string          \x00\x36\x00\x1e (version 6.2)
+>10     string          \x00\x39\x00\x0c (version 7.0)
+>10     string          \x00\x39\x00\x0e (version 7.0.1-7.0.2)
+>10     string          \x00\x39\x00\x13 (version 7.0.3)
+>10     string          \x00\x39\x00\x15 (version 7.1.0)
+>10     string          \x00\x39\x00\x16 (version 7.1.2-7.1.3)
+>10     string          \x00\x3d\x00\x0e (version 7.5)
+>10     string          \x00\x3d\x00\x10 (version 8.0)
+>10     string          \x00\x3e\x00\x00 (version 8.1)
+>10     string          \x00\x3e\x00\x01 (version 8.2)
+>10     string          \x00\x3e\x00\x02 (version 8.3)
+>10     string          \x00\x3e\x00\x06 (version 8.4)
+>10     string          \x00\x3e\x00\x07 (version 8.5)
+>10     string          \x00\x3f\x00\x00 (version 8.6-8.7.1)
+>10     string          \x00\x3f\x00\x01 (version 8.7.2)
+>10     string          \x00\x3f\x00     (version 8.8-2019.12)
+>10     string          \x00\x3f\x00\x0b (version 2020.1)
+>10     string          \x00\x40\x00     (version 2020.3-2022.5)
+>10     string          \x00\x41\x00     (version 2022.7-2022.11)
+>10     string          \x00\x42\x00     (version 2022.12-2023.3)
+>10     string          \x00\x43\x00     (version 2023.5-2023.8)
+>10     string          \x00\x44\x00     (version 2024)

+ 25 - 5
magic/Magdir/os2

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: os2,v 1.14 2022/03/21 21:25:50 christos Exp $
+# $File: os2,v 1.16 2024/12/26 19:34:28 christos Exp $
 # os2:  file(1) magic for OS/2 files
 #
 
@@ -167,20 +167,40 @@
 !:mime	application/x-os2-ini
 !:ext	ini
 
+# archive for the OS/2 WarpIN package manager
 # From:		Joerg Jenderek
 # URL:		http://warpin.netlabs.org/
 # Reference:    http://mark0.net/download/triddefs_xml.7z/defs/a/ark-wpi.trid.xml
 # Note:		called by TrID "WarpIN Installer"
-# probably magic at the beginning
-0	ubelong		=0x770402BE	WarpIN Installer
+# Revised by:	Anton Monroe December 2024
+# Reference:	http://trac.netlabs.org/warpin/browser/trunk/include/wiarchive/wiarchive.h
+# magic is 4 bytes at the beginning
+0	ubelong		=0x770402BE	OS/2 WarpIN Archive
 #>4	ubelong		=0x03000000
 #!:mime	application/octet-stream
 !:mime	application/x-os2-wpi
 !:ext	wpi
-# creator program name like: "reserved" or "WIC x.y.z"
->0x106	string		x		\b, created by %s
+# The compiler that created the archive: "WicPM" or "WIC <version>".
+# A few early archives say "reserved" or "Test application"
+>0x106	string		x		\b, created with %s
 # name like: "reserved" or "OS/2 Netlabs"
 >0x146	string		x		\b, '%s'
 # name like: "N/A" "http://warpin.netlabs.org"
 >0x186	string		x		\b, URL %s
 
+# self-extracting archive for the OS/2 WarpIN package manager
+# From:		Anton Monroe December 2024
+# Reference:	http://trac.netlabs.org/warpin/browser/trunk/include/wiarchive/wiarchive.h
+# look for "WarpIN self-extracting archive EXE stub" which is
+# usually somewhere between offset 40000 and 45000, but one was at 62000
+0		string/b	MZ
+>40000		search/25000	WarpIN\ self-extracting\ archive\ EXE\ stub
+>>&3		ubelong		=0x770402BE	OS/2 WarpIN self-extracting archive
+!:ext exe
+>>>&0x102	string		x		\b, created with %s
+
+# EXTPROC script
+# "extproc" is the OS/2 version of Unix "#!"
+0	string/tc	extproc\x20	EXTPROC script
+>&0	string		x		executed by %s
+!:ext cmd

+ 2 - 2
magic/Magdir/pdf

@@ -1,12 +1,12 @@
 
 #------------------------------------------------------------------------------
-# $File: pdf,v 1.18 2023/07/17 15:57:18 christos Exp $
+# $File: pdf,v 1.20 2025/11/22 20:59:37 christos Exp $
 # pdf:  file(1) magic for Portable Document Format
 #
 
 0	name	pdf
 >8	search		/Count
->>&0	regex		[0-9]+		\b, %s page(s)
+>>&0	regex		[1-9]([0-9]+)?		\b, %s page(s)
 >8	search/512	/Filter/FlateDecode/	(zip deflate encoded)
 
 0	string		%PDF-		PDF document

+ 69 - 4
magic/Magdir/pgp

@@ -1,8 +1,15 @@
 
 #------------------------------------------------------------------------------
-# $File: pgp,v 1.26 2024/09/01 15:51:51 christos Exp $
+# $File: pgp,v 1.27 2025/12/18 18:33:33 christos Exp $
 # pgp:  file(1) magic for Pretty Good Privacy
 
+# Reference: https://www.iana.org/assignments/openpgp/openpgp.xhtml
+
+# PGP compressed data packet (RFC 4880, section 5.6)
+0	beshort		0xa301		PGP compressed data (ZIP)
+0	beshort		0xa302		PGP compressed data (ZLIB)
+0	beshort		0xa303		PGP compressed data (BZIP2)
+
 # Handling of binary PGP keys is in pgp-binary-keys.
 # see https://lists.gnupg.org/pipermail/gnupg-devel/1999-September/016052.html
 #
@@ -101,6 +108,54 @@
 #  - symmetric encrypted packet header
 #  - RSA (e=65537) secret (sub-)keys
 
+# PGP ECC encrypted data
+0	byte	0x84
+>2	byte	3
+>>11	byte	18			PGP ECDH Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+>>11	byte	19			PGP ECDSA Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+>>11	byte	22			PGP EdDSALegacy Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+>>11	byte	25			PGP X25519 Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+>>11	byte	26			PGP X448 Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+>>11	byte	27			PGP Ed25519 Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+>>11	byte	28			PGP Ed448 Public-Key Encrypted Session Key -
+>>>3	belong	x			keyid: %08X
+>>>7	belong	x			%08X
+0	byte	0x85
+>3	byte	3
+>>12	byte	18			PGP ECDH Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+>>12	byte	19			PGP ECDSA Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+>>12	byte	22			PGP EdDSALegacy Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+>>12	byte	25			PGP X25519 Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+>>12	byte	26			PGP X448 Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+>>12	byte	27			PGP Ed25519 Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+>>12	byte	28			PGP Ed448 Public-Key Encrypted Session Key -
+>>>4	belong	x			keyid: %08X
+>>>8	belong	x			%08X
+
 # 1024b RSA encrypted data
 
 0	string	\x84\x8c\x03		PGP RSA encrypted session key -
@@ -243,6 +298,9 @@
 >0	byte	0x08			AES with 192-bit key
 >0	byte	0x09			AES with 256-bit key
 >0	byte	0x0a			Twofish with 256-bit key
+>0	byte	0x0b			Camellia with 128-bit key
+>0	byte	0x0c			Camellia with 192-bit key
+>0	byte	0x0d			Camellia with 256-bit key
 
 # hash algo mapper
 
@@ -254,6 +312,8 @@
 >0	byte	0x09			SHA384
 >0	byte	0x0a			SHA512
 >0	byte	0x0b			SHA224
+>0	byte	0x0c			SHA3-256
+>0	byte	0x0e			SHA3-512
 
 # display public key algorithms as human readable text
 0	name	key_algo
@@ -263,14 +323,19 @@
 >0	byte	0x03			RSA (Sign-Only)
 >0	byte	16			ElGamal (Encrypt-Only)
 >0	byte	17			DSA
->0	byte	18			Elliptic Curve
+>0	byte	18			ECDH
 >0	byte	19			ECDSA
 >0	byte	20			ElGamal (Encrypt or Sign)
 >0	byte	21			Diffie-Hellman
+>0	byte	22			EdDSALegacy
+>0	byte	25			X25519
+>0	byte	26			X448
+>0	byte	27			Ed25519
+>0	byte	28			Ed448
 >0	default	x
->>0	ubyte	<22			unknown (pub %d)
+>>0	ubyte	<29			unknown (pub %d)
 # this should never happen
->>0	ubyte	>21			invalid (%d)
+>>0	ubyte	>28			invalid (%d)
 
 # pgp symmetric encrypted data
 

+ 21 - 8
magic/Magdir/python

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: python,v 1.47 2024/08/27 18:50:57 christos Exp $
+# $File: python,v 1.49 2025/06/17 21:14:40 christos Exp $
 # python:  file(1) magic for python
 #
 # Outlook puts """ too for urgent messages
@@ -205,7 +205,7 @@
 2		string		\x0d\x0a
 # extra check: only two bits of flag field are currently used
 >4		ulelong		<0x4
-# \x0d as part of magic should suffice till Python 3.14 (magic 3600)
+# \x0d as part of magic suffices up to Python 3.13
 >>1		ubyte		0x0d		Byte-compiled Python module for
 !:mime application/x-bytecode.python
 # now look at the magic number to determine the version
@@ -220,10 +220,17 @@
 >>>>>>>0	uleshort	<3500		CPython 3.11
 >>>>>>>0	default		x
 >>>>>>>>0	uleshort	<3550		CPython 3.12
->>>>>>>>0	default		x
->>>>>>>>>0	uleshort	<3600		CPython 3.13
->>>>>>>>>0	default		x		CPython 3.14 or newer
+>>>>>>>>0	default		x		CPython 3.13
 >>>0		use		pyc-pep552
+# \x0e means Python 3.14 or newer
+>>1		ubyte		0x0e		Byte-compiled Python module for
+!:mime application/x-bytecode.python
+>>>0	uleshort	<3650		CPython 3.14
+>>>0	default		x
+>>>>0	uleshort	<3700		CPython 3.15
+>>>>0	default		x		CPython 3.16 or newer
+>>>0		use		pyc-pep552
+# PyPy magic numbers
 >>0		uleshort	240		Byte-compiled Python module for PyPy3.7
 !:mime application/x-bytecode.python
 >>>0		use		pyc-pep552
@@ -233,15 +240,21 @@
 >>0		uleshort	336		Byte-compiled Python module for PyPy3.9
 !:mime application/x-bytecode.python
 >>>0		use		pyc-pep552
+>>0		uleshort	384		Byte-compiled Python module for PyPy3.10
+!:mime application/x-bytecode.python
+>>>0		use		pyc-pep552
+>>0		uleshort	416		Byte-compiled Python module for PyPy3.11
+!:mime application/x-bytecode.python
+>>>0		use		pyc-pep552
 
 0	search/1/w	#!\040/usr/bin/python	Python script text executable
-!:strength + 15
+!:strength + 30
 !:mime text/x-script.python
 0	search/1/w	#!\040/usr/local/bin/python	Python script text executable
-!:strength + 15
+!:strength + 30
 !:mime text/x-script.python
 0	search/10/w	#!\040/usr/bin/env\040python	Python script text executable
-!:strength + 15
+!:strength + 30
 !:mime text/x-script.python
 
 

+ 86 - 0
magic/Magdir/r

@@ -0,0 +1,86 @@
+
+#------------------------------------------------------------------------------
+# $File: r,v 1.1 2025/02/10 17:48:42 christos Exp $
+#    file(1) magic for R's RDS and RData file formats
+#    Copyright (C) 2025 Gert Hulselmans <hulselmansgert@gmail.com>
+#
+#    URLS:
+#      https://cran.r-project.org/doc/manuals/r-release/R-ints.html#Serialization-Formats
+#      https://rdata.readthedocs.io/en/latest/_modules/rdata/parser/_parser.html
+#
+#    Example files:
+#      https://github.com/vnmabus/rdata/tree/develop/rdata/tests/data
+#
+###############################################################################
+
+
+###############################################################################
+# RDS format
+###############################################################################
+
+0	name	RDS
+# Check for RDS ASCII formats.
+>0	string	A\n2\n	R RDS (ASCII format v2)
+>0	string	A\n3\n	R RDS (ASCII format v3)
+>0	string	A\r\n2\r\n	R RDS (ASCII CRLF format v2)
+>0	string	A\r\n3\r\n	R RDS (ASCII CRLF format v3)
+# Check for RDS binary formats with native word order.
+>0	string	B\n\0\0\0	R RDS (Native (big-endian) word order format
+>>0	use RDS_binary_version_info
+>0	string	B\n\2\0\0	R RDS (Native (little-endian) word order format
+>>0	use ^RDS_binary_version_info
+>0	string	B\n\3\0\0	R RDS (Native (little-endian) word order format
+>>0	use ^RDS_binary_version_info
+# Check for RDS XDR binary save format.
+>0	string	X\n\0\0\0	R RDS (XDR binary save format
+>>0	use RDS_binary_version_info
+
+
+# Parse version numbers from RDS if it was one of the binary versions.
+0	name	RDS_binary_version_info
+>2	belong	>-1	v%d)
+>6	beshort	>-1	\b, written by R v%d.
+>8	byte	>-1	\b%d.
+>9	byte	>-1	\b%d
+>10	beshort	>-1	\b, readable from R v%d.
+>12	byte	>-1	\b%d.
+>13	byte	>-1	\b%d
+>2	belong	>2
+>>14	pstring/L	x	\b, %s encoded
+
+
+# Check if file is one of the RDS ASCII formats.
+0	string	A
+>0	use RDS	not_printed
+!:ext	rds
+
+# Check if file is RDS binary native format.
+0	string	B
+>0	use RDS	not_printed
+!:ext	rds
+
+# Check if file is RDS XDR binary save format.
+0	string	X
+>0	use RDS	not_printed
+!:ext	rds
+
+
+###############################################################################
+# RData file formats: magic bytes followed by RDS container.
+###############################################################################
+
+0	string	RDA2\n	R RData version 2 (ASCII),
+!:ext	rda/rdata
+>5	use	RDS
+
+0	string	RDA3\n	R RData version 3 (ASCII),
+!:ext	rda/rdata
+>5	use	RDS
+
+0	string	RDX2\n	R RData version 2 (binary),
+!:ext	rda/rdata
+>5	use	RDS
+
+0	string	RDX3\n	R RData version 3 (binary),
+!:ext	rda/rdata
+>5	use	RDS

+ 9 - 3
magic/Magdir/riff

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: riff,v 1.50 2024/04/13 16:40:48 christos Exp $
+# $File: riff,v 1.52 2025/09/08 12:48:15 christos Exp $
 # riff:  file(1) magic for RIFF format
 # See
 #
@@ -171,8 +171,13 @@
 >>>8		byte		&0x20	\b, ICC profile
 # TODO: These two values are off-by-one, for a 64x64 WebP they contain
 # 63x63 as there can be no 0x0 file.
->>>12		lelong&0xffffff	x	\b, %d+1
->>>15		lelong&0xffffff	x	\bx%d+1
+# we only handle < 65536 so we don't have do print %d+1:
+#>>>12		ulelong&0xffffff	x	\b, %d+1
+#>>>15		ulelong&0xffffff	x	\bx%d+1
+>>>12		ulelong&0xffffff <65536
+>>>>15		ulelong&0xffffff <65536
+>>>>>12		uleshort+1 x		\b, %u
+>>>>>15		uleshort+1 x		\bx%u 
 #>0  string  x		we got %s
 #>>&(4.l+4)  use riff-walk
 
@@ -237,6 +242,7 @@
 # AVI section extended by Patrik Radman <patrik+file-magic@iki.fi>
 #
 0	string		RIFF		RIFF (little-endian) data
+!:strength +50
 # RIFF Palette format
 # Update: Joerg Jenderek
 # URL: https://en.wikipedia.org/wiki/Resource_Interchange_File_Format

+ 6 - 1
magic/Magdir/rtf

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: rtf,v 1.9 2020/12/12 20:01:47 christos Exp $
+# $File: rtf,v 1.10 2025/03/21 17:11:56 christos Exp $
 # rtf:	file(1) magic for Rich Text Format (RTF)
 #
 # Duncan P. Simpson, D.P.Simpson@dcs.warwick.ac.uk
@@ -92,3 +92,8 @@
 !:ext	pwd/psw/pwt
 >0	use		rtf-info
 
+# https://en.wikipedia.org/wiki/Rich_Text_Format_Directory
+# https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/rtfd
+0	string		rtfd\0\0\0\0		Rich Text Format Directory
+!:ext	rtfd
+

+ 112 - 0
magic/Magdir/sf3

@@ -0,0 +1,112 @@
+
+#------------------------------------------------------------------------------
+# $File: sf3,v 1.1 2025/06/27 15:13:53 christos Exp $
+# sfr: SF3 [Simple File Format Family] files
+# (Yukari Hafner, shinmera@tymoon.eu)
+# 
+# Reference: https://shirakumo.org/docs/sf3
+# Samples: https://shirakumo.org/projects/sf3/tree/master/samples/
+
+0	name		SF3-archive
+>0	ulequad		x		\b, %llu files
+!:mime	application/x.sf3-archive
+
+0	name		SF3-audio
+>0	ulelong		>1		\b, %dHz
+>4	ubyte		>0		\b, %d channels
+>5	byte		0x01	\b, A-law
+>5	byte		0x02	\b, 16-bit signed PCM
+>5	byte		0x04	\b, 32-bit signed PCM
+>5	byte		0x08	\b, 64-bit signed PCM
+>5	byte		0x11	\b, u-law
+>5	byte		0x12	\b, 16-bit unsigned PCM
+>5	byte		0x14	\b, 32-bit unsigned PCM
+>5	byte		0x18	\b, 64-bit unsigned PCM
+>5	byte		0x22	\b, half-float PCM
+>5	byte		0x24	\b, single-float PCM
+>5	byte		0x28	\b, double-float PCM
+!:mime	audio/x.sf3
+
+0	name		SF3-image
+>0	ulelong		>0		\b, %d
+>4	ulelong		>0		\bx%d
+>8	ulelong		>0		\bx%d
+>12	byte		0x01	\b, grayscale
+>12	byte		0x02	\b, grayscale-alpha
+>12	byte		0x03	\b, RGB
+>12	byte		0x04	\b, RGBA
+>12	byte		0x12	\b, grayscale-alpha
+>12	byte		0x13	\b, BGR
+>12	byte		0x14	\b, ABGR
+>12	byte		0x24	\b, ARGB
+>12	byte		0x34	\b, BGRA
+>12	byte		0x44	\b, CMYK
+>12	byte		0x54	\b, KYMC
+>13	byte		0x01	\b, 8-bit signed
+>13	byte		0x02	\b, 16-bit signed
+>13	byte		0x04	\b, 32-bit signed
+>13	byte		0x08	\b, 64-bit signed
+>13	byte		0x11	\b, 8-bit unsigned
+>13	byte		0x12	\b, 16-bit unsigned
+>13	byte		0x14	\b, 32-bit unsigned
+>13	byte		0x18	\b, 64-bit unsigned
+>13	byte		0x22	\b, half-float
+>13	byte		0x24	\b, single-float
+>13	byte		0x28	\b, double-float
+!:mime	image/x.sf3
+
+0	name		SF3-log
+>0	leqdate		x		\b, from %s
+>8	leqdate		x		\b, to %s
+>16	uleshort	x		\b, %d chunks
+!:mime	application/x.sf3-log
+
+0	name		SF3-model
+>(2.l+22)		ulelong	x	\b, %d face indices
+>>&(&-20.l*4)	ulelong	x	\b, %d vertex attributes
+!:mime	model/x.sf3
+
+0	name		SF3-physics-model
+>0	lefloat		x	\b, %f kg
+>40	uleshort	x	\b, %d shapes
+!:mime	model/x.sf3-physics
+
+0	name		SF3-table
+>0	uleshort	x	\b, %d columns
+>10	ulequad		x	\b, %llu rows
+!:mime	application/x.sf3-table
+
+0	name		SF3-text
+>8	ulelong		x	\b, %d markup options
+>(0.q+28)	ulequad	x	\b, %llu bytes of text
+!:mime	application/x.sf3-text
+
+0	name		SF3-vector-graphic
+>0	ulelong		>0	\b, %d
+>4	ulelong		>0	\bx%d
+>8	ulelong		x	\b, %d instructions
+!:mime	image/x.sf3-vector
+
+# Generic SF3 Header
+0	string		\x81SF3\x00\xE0\xD0\x0D\x0A\x0A	SF3
+>10	byte		0x01	archive
+>>16	use			SF3-archive
+>10	byte		0x02	audio file
+>>16	use			SF3-audio
+>10	byte		0x03	image file
+>>16	use			SF3-image
+>10	byte		0x04	log file
+>>16	use			SF3-log
+>10	byte		0x05	3D model
+>>16	use			SF3-model
+>10	byte		0x06	physics model
+>>16	use			SF3-physics-model
+>10	byte		0x07	table
+>>16	use			SF3-table
+>10	byte		0x08	text file
+>>16	use			SF3-text
+>10	byte		0x09	vector graphic
+>>16	use			SF3-vector-graphic
+>10	byte		>9	file of unknown type (%d)
+!:mime	application/x.sf3
+!:ext   sf3

+ 18 - 9
magic/Magdir/sgml

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: sgml,v 1.53 2024/11/10 14:48:55 christos Exp $
+# $File: sgml,v 1.55 2025/04/06 20:34:30 christos Exp $
 # Type:	SVG Vectorial Graphics
 # From:	Noel Torres <tecnico@ejerciciosresueltos.com>
 0	string/bt	\<?xml\ version=
@@ -11,11 +11,17 @@
 !:ext   svg
 >>19	search/4096	\<gnc-v2		GnuCash file
 !:mime	application/x-gnucash
+>>19	search/4096	application/x-qtskin	QuickTime5 skinned movie
+!:mime	application/x-qtskin
+
 0	string/bt	\<svg			SVG Scalable Vector Graphics image
 !:mime	image/svg+xml
 !:ext   svg
 
+0	string/t		\<?xml\ version=
+!:strength +40
 >14	regex		['"\ \t]*[0-9.]+['"\ \t]*
+
 # Sitemap file
 >>19	search/4096	\<urlset		XML Sitemap document text
 !:mime	application/xml-sitemap
@@ -26,8 +32,8 @@
 # http://files.pef-format.org/specifications/pef-2008-1/pef-specification.html
 #
 # Simon Aittamaa <simon.aittamaa@gmail.com>
->>19    search/4096	\<pef           Portable Embosser Format
-!:mime  application/x-pef+xml
+>>19	search/4096	\<pef			Portable Embosser Format
+!:mime	application/x-pef+xml
 
 # OpenStreetMap XML (.osm)
 # https://wiki.openstreetmap.org/wiki/OSM_XML
@@ -37,9 +43,7 @@
 # xhtml
 >19	search/4096/cWbt	\<!doctype\ html	XHTML document text
 >>15	string		>\0	(version %.3s)
-!:strength + 15
 !:mime	application/xhtml+xml
-
 >19	search/4096/cWbt	\<html\ xmlns=		XHTML document text
 >>15	string		>\0	(version %.3s)
 !:mime	application/xhtml+xml
@@ -57,14 +61,11 @@
 # avoid misdetection as JavaScript
 0	string/cWt	\<!doctype\ html	HTML document text
 !:mime	text/html
-!:strength + 30
 0	string/ct	\<html>	HTML document text
 !:mime	text/html
-!:strength + 30
 0	string/ct	\<!--
 >&0	search/4096/cWt	\<!doctype\ html	HTML document text
 !:mime	text/html
-!:strength + 30
 >&0	search/4096/ct	\<html>	HTML document text
 !:mime	text/html
 
@@ -127,13 +128,21 @@
 0	search/1/cwt	\<?xml			XML document text
 !:mime	text/xml
 !:strength + 30
+0	string/t		\<?xml\ version\ "	XML
+!:mime	text/xml
+!:strength + 30
 0	string/t		\<?xml\ version="	XML
 !:mime	text/xml
 !:strength + 30
 >15	string/t	>\0			%.3s document text
 >>23	search/1	\<xsl:stylesheet	(XSL stylesheet)
 >>24	search/1	\<xsl:stylesheet	(XSL stylesheet)
-
+0	string/t	\<?xml\ version='	XML
+!:mime	text/xml
+!:strength + 30
+>15	string/t	>\0			%.3s document text
+>>23	search/1	\<xsl:stylesheet	(XSL stylesheet)
+>>24	search/1	\<xsl:stylesheet	(XSL stylesheet)
 0	search/1/wt	\<?XML			broken XML document text
 !:mime	text/xml
 !:strength - 10

+ 6 - 3
magic/Magdir/sniffer

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: sniffer,v 1.36 2024/06/16 15:09:26 christos Exp $
+# $File: sniffer,v 1.39 2025/07/02 17:35:12 christos Exp $
 # sniffer:  file(1) magic for packet capture files
 #
 # From: guy@alum.mit.edu (Guy Harris)
@@ -240,7 +240,7 @@
 >20	belong&0x03FFFFFF		255		(Bluetooth Basic Rate/Enhanced Data Rate baseband packets
 >20	belong&0x03FFFFFF		256		(Bluetooth Low Energy air interface with pseudo-header
 >20	belong&0x03FFFFFF		257		(PROFIBUS data link layer
->20	belong&0x03FFFFFF		258		(Apple DLT_PKTAP
+>20	belong&0x03FFFFFF		258		(Apple PKTAP
 >20	belong&0x03FFFFFF		259		(Ethernet with 802.3 Clause 65 EPON preamble
 >20	belong&0x03FFFFFF		260		(IPMI trace packets
 >20	belong&0x03FFFFFF		261		(Z-Wave RF profile R1 and R2 packets
@@ -249,7 +249,7 @@
 >20	belong&0x03FFFFFF		264		(ISO 14443 messages
 >20	belong&0x03FFFFFF		265		(IEC 62106 Radio Data System groups
 >20	belong&0x03FFFFFF		266		(USB with Darwin header
->20	belong&0x03FFFFFF		267		(OpenBSD DLT_OPENFLOW
+>20	belong&0x03FFFFFF		267		(OpenBSD OpenFlow
 >20	belong&0x03FFFFFF		268		(IBM SDLC frames
 >20	belong&0x03FFFFFF		269		(TI LLN sniffer frames
 >20	belong&0x03FFFFFF		271		(Linux vsock
@@ -312,13 +312,16 @@
 #
 0	ubelong		0x0a0d0d0a
 >8	ubelong		0x1a2b3c4d	pcapng capture file
+!:mime	application/x-pcapng
 >>12	beshort		x		- version %d
 >>14	beshort		x		\b.%d
 0	ulelong		0x0a0d0d0a
 >8	ulelong		0x1a2b3c4d	pcapng capture file
+!:mime	application/x-pcapng
 >>12	leshort		x		- version %d
 >>14	leshort		x		\b.%d
 
+
 #
 # AIX "iptrace" capture files.
 #

+ 19 - 2
magic/Magdir/sql

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: sql,v 1.27 2023/08/19 15:33:04 christos Exp $
+# $File: sql,v 1.38 2024/12/26 19:14:32 christos Exp $
 # sql:  file(1) magic for SQL files
 #
 # From: "Marty Leisner" <mleisner@eng.mc.xerox.com>
@@ -106,7 +106,7 @@
 # at offset 68 that is preferred over "user version" for indicating the
 # associated application.
 #
-0   string  SQLite\ format\ 3
+0   string  SQLite\040format\0403\0
 # skip DROID fmt-729-signature-id-1053.sqlite by checking for valid page size
 >16 ubeshort >0                 SQLite 3.x
 # deprecated
@@ -220,9 +220,26 @@
 # AUDY	Audacity Project File
 >>>68 belong =0x41554459 (Audacity Project)
 >>>68 belong =0x6A035744 (TeXnicard card database)
+>>>68 belong =0x43455745 (Cewe Fotobuch)
+>>>68 belong =0x5E96730E (Corsair iCue package registry)
+>>>68 belong =0xF9BEB4D9 (Bitcoin wallet)
+>>>68 belong =0x56333500 (Vector35 Binary Ninja)
+>>>68 belong =0x4163726E (FlyingMeat Acorn)
+>>>68 belong =0x544f4952 (Riot Games patcher)
+>>>68 belong =0x544d5052 (Twinmotion project)
+>>>68 belong =0x43484557 (Chewing IME)
 # unknown application ID
 >>>68 default x
 >>>>68 belong !0         \b, application id %u
+>>>>68 belong 0
+>>>>>0xC70	search/0x9000	CREATE\040TABLE\040s3api_per_key_metadata\n	\b, Archive Metadata
+>>>>>0x2A0	search/0x10	CREATE\040TABLE\040version_table\040(\040version\040INTEGER\040NOT\040NULL\040PRIMARY\040KEY\040)	\b, Adobe SDE
+>>>>>0xEA0	search/0x10	CREATE\040TABLE\040version_table\040(\040version\040INTEGER\040NOT\040NULL\040PRIMARY\040KEY\040)	\b, Adobe SDE
+>>>>>0xA0	search/0x100 CREATE\040TABLE\040IPMMessage\040(	\b, Adobe IPM DB
+>>>>>0xC00	search/0x100 CREATE\040TABLE\040IPMMessage\040(	\b, Adobe IPM DB
+>>>>>0x200	search/0xFFFF	C\0R\0E\0A\0T\0E\0\040\0T\0A\0B\0L\0E\0\040\0A\0C\0T\0I\0O\0N\0R\0E\0C\0O\0R\0D\0S\0\040\0(	\b, Microsoft Store Database
+
+
 # The "user version" as read and set by the user_version pragma like:
 # 1 2 4 5 7 9 10 25 36 43 53 400 416 131073 131074 131075 50331648
 >>60 belong !0          \b, user version %d

+ 37 - 0
magic/Magdir/syd

@@ -0,0 +1,37 @@
+
+#------------------------------------------------------------------------------
+# $File: syd,v 1.1 2025/09/11 01:49:40 christos Exp $
+# syd: file(1) magic for syd(1) encrypted files
+#
+# From: Ali Polatel <alip@chesswob.org>
+# Documentation: https://man.exherbo.org/syd.7.html#Crypt_Sandboxing
+# No defined extension yet; files are recognized by magic header only.
+#
+# Layout:
+#   0..3   : "\x7fSYD"
+#   4	   : version byte (current API: 3)
+#   5..36  : HMAC (32 bytes, SHA256)
+#   37..52 : IV (16 bytes)
+#   53..   : ciphertext (AES-256-CTR)
+#------------------------------------------------------------------------------
+
+# Header and version
+0		string		\x7fSYD		SYD encrypted file
+>4		ubyte		x		\b, version %u
+# Version 3: algorithm + HMAC/IV as hex blobs + ciphertext size
+>>4		ubyte		=3		\b, AES-256-CTR; HMAC-SHA256:
+>>>5		belong		 x		\b%08x
+>>>9		belong		 x		\b%08x
+>>>13		belong		 x		\b%08x
+>>>17		belong		 x		\b%08x
+>>>21		belong		 x		\b%08x
+>>>25		belong		 x		\b%08x
+>>>29		belong		 x		\b%08x
+>>>33		belong		 x		\b%08x
+>>>37		belong		 x		\b, IV:%08x
+>>>41		belong		 x		\b%08x
+>>>45		belong		 x		\b%08x
+>>>49		belong		 x		\b%08x
+>>>-0		offset-53	 x		\b, ciphertext %llu bytes
+
+# End of syd

+ 29 - 0
magic/Magdir/tapebackup

@@ -0,0 +1,29 @@
+#------------------------------------------------------------------------------
+# $File: tapebackup,v 1.1 2026/01/10 15:45:02 christos Exp $
+# Dmitry Brant, 2026
+# tapebackup:  file(1) magic for different tape backup formats
+
+# QIC-80 tapes
+# https://www.qic.org/html/standards/8x.x/qic80n.pdf
+0	string		VTBL			QIC-80 tape volume header
+>8	string/44	x			\b, Volume label: %s
+
+0	lelong		0xaa55aa55
+>4	lelong		0x00000002		Colorado tape backup
+>>146	string/88	x			\b, Volume label: %s
+
+56	string		\<\<NoVaStOr\>\>	NovaStor tape backup
+
+0	lelong		0xdddddddd
+>512	lelong	0xabbaabba			ArcServe tape backup
+
+# IBM AS/400
+# https://www.ibm.com/docs/en/i/7.4.0?topic=ssw_ibm_i_74/cl/savlib.html
+0	belong		0xffffffff
+>4	belong		0xd8e2d9c4		AS/400 SAVLIB backup
+
+0	lelong		0x3a3a3a3a
+>12	lelong		0x3a3a3a20		TXPLUS tape backup
+
+0	lelong		0x55aa0004		Mountain FileSafe tape backup
+>93	string		x			\b, Volume label: %s

+ 16 - 1
magic/Magdir/tex

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: tex,v 1.22 2022/12/21 16:50:04 christos Exp $
+# $File: tex,v 1.24 2026/02/01 16:17:53 christos Exp $
 # tex:  file(1) magic for TeX files
 #
 # XXX - needs byte-endian stuff (big-endian and little-endian DVI?)
@@ -20,6 +20,17 @@
 0	string		\367\312
 >(2.b+11)	string	\363	TeX virtual font data
 0	search/1	This\ is\ TeX,	TeX transcript text
+0	search/1	This\ is\ pdfTeX,	pdfTeX transcript text
+0	search/1	This\ is\ XeTeX,	XeTeX transcript text
+0	search/1	This\ is\ LuaTeX,	LuaTeX transcript text
+0	search/1	This\ is\ LuaHBTeX,	LuaTeX transcript text
+0	search/1	This\ is\ LuajitTeX,	LuaTeX transcript text
+0	search/1	This\ is\ LuajitHBTeX,	LuaTeX transcript text
+0	search/1	This\ is\ pTeX,	pTeX transcript text
+0	search/1	This\ is\ e-pTeX,	e-pTeX transcript text
+0	search/1	This\ is\ upTeX,	upTeX transcript text
+0	search/1	This\ is\ e-upTeX,	e-upTeX transcript text
+0	search/1	This\ is\ HiTeX,	HiTeX transcript text
 0	search/1	This\ is\ METAFONT,	METAFONT transcript text
 
 # There is no way to detect TeX Font Metric (*.tfm) files without
@@ -38,6 +49,10 @@
 0	search/1	This\ is\ Info\ file	GNU Info text
 !:mime	text/x-info
 
+0	string		%!TEX\040root	TeX Document text
+!:mime	text/x-tex
+!:strength + 15
+
 # TeX documents, from Daniel Quinlan (quinlan@yggdrasil.com)
 0	search/4096	\\input		TeX document text
 !:mime	text/x-tex

+ 6 - 1
magic/Magdir/ti-8x

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: ti-8x,v 1.8 2020/02/12 22:13:01 christos Exp $
+# $File: ti-8x,v 1.9 2025/05/28 16:49:05 christos Exp $
 # ti-8x: file(1) magic for the TI-8x and TI-9x Graphing Calculators.
 #
 # From: Ryan McGuire (rmcguire@freenet.columbus.oh.us).
@@ -237,3 +237,8 @@
 >>7             byte            >0              \b %c
 >>9             byte            x               \b.%c
 >>10		byte		x		\b%c
+
+# Magic Numbers for the TI-99
+# https://www.ninerpedia.org/wiki/File_systems#Floppy_Disk_File_System
+#
+13		string		DSK		TI-99/4 image

+ 16 - 7
magic/Magdir/varied.script

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: varied.script,v 1.16 2024/02/04 19:26:02 christos Exp $
+# $File: varied.script,v 1.17 2025/03/10 20:41:09 christos Exp $
 # varied.script:  file(1) magic for various interpreter scripts
 
 0	string		#![	Rust Source file
@@ -15,10 +15,19 @@
 
 
 # using env
-0	string/wt	#!\ /usr/bin/env		a
->15	string/T	>\0			%s script text executable
-!:strength / 6
+0	regex/t		#![[:space:]]*/usr/bin/env[[:space:]]*	a
+>&0	string/T	>\0			%s script text executable
+!:strength / 2
 
-0	string/wb	#!\ /usr/bin/env		a
->15	string/T	>\0			%s script executable (binary data)
-!:strength / 6
+0	regex/b		#![[:space:]]*/usr/bin/env[[:space:]]*	a
+>&0	string/T	>\0			%s script executable (binary data)
+!:strength / 2
+
+# using env
+0	regex/t		#![[:space:]]*/usr/bin/env[[:space:]]*-[Si0]	a
+>&0	string/T	>\0			%s script text executable
+!:strength / 2
+
+0	regex/b		#![[:space:]]*/usr/bin/env[[:space:]]*-[Si0]	a
+>&0	string/T	>\0			%s script executable (binary data)
+!:strength / 2

+ 5 - 1
magic/Magdir/virtual

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: virtual,v 1.21 2024/09/04 19:09:00 christos Exp $
+# $File: virtual,v 1.22 2026/02/05 18:51:36 christos Exp $
 # From: James Nobis <quel@quelrod.net>
 # Microsoft hard disk images for:
 # Virtual Server
@@ -337,3 +337,7 @@
 >>>>3	byte			9		(QEMU 5.0)
 >>>>3	byte			10		(QEMU 5.1-7.0)
 >>>>3	byte			12		(QEMU 7.1+)
+
+# Parallels disk image
+0	string	WithoutFreeSpace	Parallels disk image
+0	string	WithouFreSpacExt	Parallels disk image (extended) 

+ 5 - 4
magic/Magdir/webassembly

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: webassembly,v 1.4 2022/08/16 11:16:39 christos Exp $
+# $File: webassembly,v 1.5 2025/06/08 15:37:23 christos Exp $
 # webassembly:  file(1) magic for WebAssembly modules
 #
 # WebAssembly is a virtual architecture developed by a W3C Community
@@ -10,8 +10,9 @@
 # document describing the binary format.
 # From: Pip Cet <pipcet@gmail.com> and Joel Martin
 
-0	string	\0asm	WebAssembly (wasm) binary module
->4	lelong	=1	version %#x (MVP)
+0	string	\0asm		WebAssembly (wasm) binary
+>4	lelong	>0		version %#x
+>4	lelong	=1		(MVP module)
+>4	lelong	=0x1000d	(component)
 !:mime  application/wasm
 !:ext   wasm
->4	lelong	>1	version %#x

+ 21 - 21
magic/Magdir/windows

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: windows,v 1.67 2024/11/09 22:43:01 christos Exp $
+# $File: windows,v 1.69 2025/09/06 16:58:00 christos Exp $
 # windows:  file(1) magic for Microsoft Windows
 #
 # This file is mainly reserved for files where programs
@@ -663,7 +663,7 @@
 # skip space at beginning
 >0     string		\040
 # name without extension and greater character or name with hlp extension
->>1	regex/c		\^([^\xd>]*|.*\\.hlp)	MS Windows help file Content, based "%s"
+>>1	regex		\^([^\xd>]*|.*\\.hlp)	MS Windows help file Content, based "%s"
 !:mime	text/plain
 !:apple	????TEXT
 !:ext	cnt
@@ -1106,7 +1106,7 @@
 # space after right bracket
 # or AutoRun.Amd64 for 64 bit systems
 # or only NL separator
->>&0	regex/c		\^autorun
+>>&0	regex		\^autorun
 # but sometimes total commander directory tree file "treeinfo.wc" with lines like
 # [AUTORUN]
 # [boot]
@@ -1120,56 +1120,56 @@
 !:ext	inf
 # https://msdn.microsoft.com/en-us/library/windows/hardware/ff549520(v=vs.85).aspx
 # version strings ASCII coded case-independent for Windows setup information script file
->>&0	regex/c		\^(version|strings)]				Windows setup INFormation
+>>&0	regex		\^(version|strings)]				Windows setup INFormation
 !:mime	application/x-setupscript
 #!:mime application/x-wine-extension-inf
 !:ext	inf
 # NETCRC.INF OEMCPL.INF
->>&0	regex/c		\^(WinsockCRCList|OEMCPL)]			Windows setup INFormation
+>>&0	regex		\^(WinsockCRCList|OEMCPL)]			Windows setup INFormation
 !:mime	application/x-setupscript
 !:ext	inf
 # http://www.winfaq.de/faq_html/Content/tip2500/onlinefaq.php?h=tip2653.htm
 # https://msdn.microsoft.com/en-us/library/windows/desktop/cc144102.aspx
 # .ShellClassInfo DeleteOnCopy LocalizedFileNames ASCII coded case-independent
->>&0	regex/1024c	\^(\\.ShellClassInfo|DeleteOnCopy|LocalizedFileNames)]	Windows desktop.ini
+>>&0	regex/1024	\^(\\.ShellClassInfo|DeleteOnCopy|LocalizedFileNames)]	Windows desktop.ini
 !:mime application/x-wine-extension-ini
 #!:mime text/plain
 # https://support.microsoft.com/kb/84709/
->>&0	regex/c		\^don't\ load]					Windows CONTROL.INI
+>>&0	regex		\^don't\ load]					Windows CONTROL.INI
 !:mime application/x-wine-extension-ini
 !:ext	ini
->>&0	regex/c		\^(ndishlp\\$|protman\\$|NETBEUI\\$)]		Windows PROTOCOL.INI
+>>&0	regex		\^(ndishlp\\$|protman\\$|NETBEUI\\$)]		Windows PROTOCOL.INI
 !:mime application/x-wine-extension-ini
 !:ext	ini
 # https://technet.microsoft.com/en-us/library/cc722567.aspx
 # http://www.winfaq.de/faq_html/Content/tip0000/onlinefaq.php?h=tip0137.htm
->>&0	regex/c		\^(windows|Compatibility|embedding)]		Windows WIN.INI
+>>&0	regex		\^(windows|Compatibility|embedding)]		Windows WIN.INI
 !:mime application/x-wine-extension-ini
 !:ext	ini
 # https://en.wikipedia.org/wiki/SYSTEM.INI
->>&0	regex/c		\^(boot|386enh|drivers)]			Windows SYSTEM.INI
+>>&0	regex		\^(boot|386enh|drivers)]			Windows SYSTEM.INI
 !:mime application/x-wine-extension-ini
 !:ext	ini
 # http://www.mdgx.com/newtip6.htm
->>&0	regex/c		\^SafeList]					Windows IOS.INI
+>>&0	regex		\^SafeList]					Windows IOS.INI
 !:mime application/x-wine-extension-ini
 !:ext	ini
 # https://en.wikipedia.org/wiki/NTLDR	Windows Boot Loader information
->>&0	regex/c		\^boot\x20loader]				Windows boot.ini
+>>&0	regex		\^boot\x20loader]				Windows boot.ini
 !:mime application/x-wine-extension-ini
 !:ext	ini
 # https://en.wikipedia.org/wiki/CONFIG.SYS
->>&0	regex/c		\^menu]						MS-DOS CONFIG.SYS
+>>&0	regex		\^menu]						MS-DOS CONFIG.SYS
 # @CONFIG.UI configuration file of previous DOS version saved by Caldera OPENDOS INSTALL.EXE
 # CONFIG.PSS saved version of file CONFIG.SYS created by %WINDIR%\SYSTEM\MSCONFIG.EXE
 # CONFIG.TSH renamed file CONFIG.SYS.BAT by %WINDIR%\SYSTEM\MSCONFIG.EXE
 # dos and w40 used in dual booting scene
 !:ext	sys/dos/w40
 # https://support.microsoft.com/kb/118579/
->>&0	regex/c		\^Paths]\r\n					MS-DOS MSDOS.SYS
+>>&0	regex		\^Paths]\r\n					MS-DOS MSDOS.SYS
 !:ext	sys/dos
 # http://chmspec.nongnu.org/latest/INI.html#HHP
->>&0	regex/c		\^options]\r\n					Microsoft HTML Help Project
+>>&0	regex		\^options]\r\n					Microsoft HTML Help Project
 !:mime text/plain
 !:ext	hhp
 # From:		Joerg Jenderek
@@ -1178,7 +1178,7 @@
 #		http://mark0.net/download/triddefs_xml.7z/defs/c/cpx.trid.xml
 # Note:		stored in directory %WINDIR%\SysWOW64 or %WINDIR%\system
 #		second word often Latin but sometimes Cyrillic like in 12510866.CPX
->>&0	regex/c		\^Windows\ (Latin|Cyrillic)			Windows codepage translator
+>>&0	regex		\^Windows\ (Latin|Cyrillic)			Windows codepage translator
 #!:mime	text/plain
 !:mime	text/x-ms-cpx
 # like: 12510866.CPX 
@@ -1187,7 +1187,7 @@
 # URL:		https://en.wikipedia.org/wiki/File_Explorer
 # Reference:	http://mark0.net/download/triddefs_xml.7z/defs/s/scf-exp.trid.xml,scf-exp-old.trid.xml
 # Note:		called "Windows Explorer Command Shell File" by TrID and "File Explorer Command" by Windows via SHCmdFile
->>&0	regex/c		\^Shell]\r\n					Windows Explorer Shell Command File
+>>&0	regex		\^Shell]\r\n					Windows Explorer Shell Command File
 #!:mime	text/plain
 !:mime	text/x-ms-scf
 # like: channels.scf desktop.scf explorer.scf "Desktop anzeigen.scf"
@@ -1199,7 +1199,7 @@
 # URL:		http://en.wikipedia.org/wiki/VIA_Technologies
 # Reference:	http://mark0.net/download/triddefs_xml.7z/defs/s/scf-via.trid.xml
 # Note:		called "VIA setup configuration file" by TrID
->>&0	regex/c		\^SCF]\r\n					VIA setup configuration
+>>&0	regex		\^SCF]\r\n					VIA setup configuration
 #!:mime	text/plain
 !:mime	text/x-via-scf
 # like: SETUP.SCF
@@ -1208,7 +1208,7 @@
 # URL:		https://en.wikipedia.org/wiki/InstallShield
 # Reference:	http://mark0.net/download/triddefs_xml.7z/defs/l/lid-is.trid.xml
 # Note:		contain also 3 keywords like: count Default key0
->>&0	regex/c		\^Languages]					InstallShield Language Identifier
+>>&0	regex		\^Languages]					InstallShield Language Identifier
 #!:mime	text/plain
 !:mime	text/x-installshield-lid
 # like: SETUP.LID
@@ -1217,7 +1217,7 @@
 # URL:		https://www.file-extensions.org/tag-file-extension
 # Reference:	http://mark0.net/download/triddefs_xml.7z/defs/t/taginfo.trid.xml
 # Note:		contain also keywords like: Application Category Company Misc Version
->>&0	regex/c		\^TagInfo]					TagInfo
+>>&0	regex		\^TagInfo]					TagInfo
 #!:mime	text/plain
 #!:mime	text/prs.lines.tag
 !:mime	text/x-ms-tag
@@ -1260,7 +1260,7 @@
 >>>>>&0	ubyte				x
 # characters, digits, underscore and white space followed by right bracket
 # terminated by CR implies section line to skip BOOTLOG.TXT DETLOG.TXT
->>>>>>&-1	regex/T			\^([A-Za-z0-9_\(\)\ ]+)\]\r	Generic INItialization configuration [%-.40s
+>>>>>>&-1	regex/T			\^([A-Za-z0-9_\(\)\ ]+)\][\r\n]	Generic INItialization configuration [%-.40s
 # NETDEF.INF multiarc.ini 
 #!:mime	application/x-setupscript
 !:mime	application/x-wine-extension-ini

+ 12 - 12
magic/Magdir/xilinx

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: xilinx,v 1.12 2024/09/04 19:06:12 christos Exp $
+# $File: xilinx,v 1.13 2025/03/30 20:29:30 christos Exp $
 # This is Aaron's attempt at a MAGIC file for Xilinx .bit files.
 # Xilinx-Magic@RevRagnarok.com
 # Got the info from FPGA-FAQ 0026
@@ -14,26 +14,26 @@
 >2 	belong	=0x0ff00ff0
 >>&0	belong  =0x0ff00ff0
 >>>&0	byte    =0x00
->>>>&1   beshort =0x0001
->>>>>&3	string	a	Xilinx BIT data
+>>>&1   beshort =0x0001
+>>>&3	string	a	Xilinx BIT data
 # Next is a Pascal-style string with the NCD name. We want to capture that.
->>>>>>&0	   pstring/H	x	- from %s
+>>>>&0	   pstring/H	x	- from %s
 # And then 'b'
->>>>>>>&1    string b
+>>>>>&1    string b
 # Then the model / part number:
->>>>>>>>&0   pstring/H    x       - for %s
+>>>>>>&0   pstring/H    x       - for %s
 # Then 'c'
->>>>>>>>>&1 string c
+>>>>>>>&1 string c
 # Then the build-date
->>>>>>>>>>&0 pstring/H    x       - built %s
+>>>>>>>>&0 pstring/H    x       - built %s
 # Then 'd'
->>>>>>>>>>>&1   string d
+>>>>>>>>>&1   string d
 # Then the build-time
->>>>>>>>>>>>&0  pstring/H x        \b(%s)
+>>>>>>>>>>&0  pstring/H x        \b(%s)
 # Then 'e'
->>>>>>>>>>>>>&1  string e
+>>>>>>>>>>>&1  string e
 # And length of data
->>>>>>>>>>>>>>&0 belong x          - data length %#x
+>>>>>>>>>>>>&0 belong x          - data length %#x
 
 # Raw bitstream files
 0      long    0xffffffff

+ 5 - 4
magic/Magdir/xwindows

@@ -1,6 +1,6 @@
 
 #------------------------------------------------------------------------------
-# $File: xwindows,v 1.13 2022/03/24 15:48:58 christos Exp $
+# $File: xwindows,v 1.14 2025/04/06 19:18:03 christos Exp $
 # xwindows:  file(1) magic for various X/Window system file formats.
 
 # Compiled X Keymap
@@ -29,10 +29,11 @@
 # X11 mouse cursor format defined in libXcursor, see
 # https://www.x.org/archive/X11R6.8.1/doc/Xcursor.3.html
 # https://cgit.freedesktop.org/xorg/lib/libXcursor/tree/include/X11/Xcursor/Xcursor.h
-0	string		Xcur		Xcursor data
+0	string		Xcur
+>4	lelong		<64		Xcursor data
 !:mime	image/x-xcursor
->10	leshort		x		version %d
->>8	leshort		x		\b.%d
+>>10	leshort		x		version %d
+>>>8	leshort		x		\b.%d
 
 # X bitmap https://en.wikipedia.org/wiki/X_BitMap
 0	search/2048	#define\040

+ 7 - 2
magic/Magdir/zip

@@ -1,5 +1,5 @@
 #------------------------------------------------------------------------------
-# $File: zip,v 1.8 2021/10/24 15:53:56 christos Exp $
+# $File: zip,v 1.10 2025/10/22 19:31:31 christos Exp $
 # zip:  file(1) magic for zip files; this is not use
 # Note the version of magic in archive is currently stronger, this is
 # just an example until negative offsets are supported better
@@ -17,7 +17,6 @@
 >>6	leshort		x		\b, extract using at least
 >>6	use		zipversion
 # This is DOS date like: ledate 21:00:48 19 Dec 2001 != DOS 00:00 1 Jan 2010 ~ 0000213C
->>12	ulelong		x		\b, last modified
 >>14	lemsdosdate	x		\b, last modified %s
 >>12	lemsdostime	x		%s
 # uncompressed size of 1st entry; FFffFFff means real value stored in ZIP64 record
@@ -124,3 +123,9 @@
 #>>20	uleshort	>0		\b, comment length %u
 # archive comment
 >>20	pstring/l	>0		\b, %s
+
+# The end directory record does not work for piped input
+# so try one that looks from the beginning of the file.
+0	string		PK\003\004
+>0	search/1024	PK\001\002
+>>&-4 	use		zipcd

+ 8 - 1
magic/Makefile.am

@@ -1,5 +1,5 @@
 #
-# $File: Makefile.am,v 1.192 2024/10/02 01:45:32 christos Exp $
+# $File: Makefile.am,v 1.201 2026/02/01 16:25:09 christos Exp $
 #
 MAGIC_FRAGMENT_BASE = Magdir
 MAGIC_DIR = $(top_srcdir)/magic
@@ -41,6 +41,7 @@ $(MAGIC_FRAGMENT_DIR)/basis \
 $(MAGIC_FRAGMENT_DIR)/beetle \
 $(MAGIC_FRAGMENT_DIR)/ber \
 $(MAGIC_FRAGMENT_DIR)/bflt \
+$(MAGIC_FRAGMENT_DIR)/bgcode \
 $(MAGIC_FRAGMENT_DIR)/bhl \
 $(MAGIC_FRAGMENT_DIR)/bioinformatics \
 $(MAGIC_FRAGMENT_DIR)/biosig \
@@ -77,6 +78,7 @@ $(MAGIC_FRAGMENT_DIR)/console \
 $(MAGIC_FRAGMENT_DIR)/convex \
 $(MAGIC_FRAGMENT_DIR)/coverage \
 $(MAGIC_FRAGMENT_DIR)/cracklib \
+$(MAGIC_FRAGMENT_DIR)/creativeassembly \
 $(MAGIC_FRAGMENT_DIR)/crypto \
 $(MAGIC_FRAGMENT_DIR)/ctags \
 $(MAGIC_FRAGMENT_DIR)/ctf \
@@ -124,6 +126,7 @@ $(MAGIC_FRAGMENT_DIR)/gconv \
 $(MAGIC_FRAGMENT_DIR)/gentoo \
 $(MAGIC_FRAGMENT_DIR)/geo \
 $(MAGIC_FRAGMENT_DIR)/geos \
+$(MAGIC_FRAGMENT_DIR)/gguf \
 $(MAGIC_FRAGMENT_DIR)/gimp \
 $(MAGIC_FRAGMENT_DIR)/git \
 $(MAGIC_FRAGMENT_DIR)/glibc \
@@ -262,6 +265,7 @@ $(MAGIC_FRAGMENT_DIR)/pwsafe \
 $(MAGIC_FRAGMENT_DIR)/pyramid \
 $(MAGIC_FRAGMENT_DIR)/python \
 $(MAGIC_FRAGMENT_DIR)/qt \
+$(MAGIC_FRAGMENT_DIR)/r \
 $(MAGIC_FRAGMENT_DIR)/revision \
 $(MAGIC_FRAGMENT_DIR)/ringdove \
 $(MAGIC_FRAGMENT_DIR)/riff \
@@ -280,6 +284,7 @@ $(MAGIC_FRAGMENT_DIR)/selinux \
 $(MAGIC_FRAGMENT_DIR)/sendmail \
 $(MAGIC_FRAGMENT_DIR)/sequent \
 $(MAGIC_FRAGMENT_DIR)/sereal \
+$(MAGIC_FRAGMENT_DIR)/sf3 \
 $(MAGIC_FRAGMENT_DIR)/sgi \
 $(MAGIC_FRAGMENT_DIR)/sgml \
 $(MAGIC_FRAGMENT_DIR)/sharc \
@@ -300,9 +305,11 @@ $(MAGIC_FRAGMENT_DIR)/statistics \
 $(MAGIC_FRAGMENT_DIR)/subtitle \
 $(MAGIC_FRAGMENT_DIR)/sun \
 $(MAGIC_FRAGMENT_DIR)/svf \
+$(MAGIC_FRAGMENT_DIR)/syd \
 $(MAGIC_FRAGMENT_DIR)/sylk \
 $(MAGIC_FRAGMENT_DIR)/symbos \
 $(MAGIC_FRAGMENT_DIR)/sysex \
+$(MAGIC_FRAGMENT_DIR)/tapebackup \
 $(MAGIC_FRAGMENT_DIR)/tcl \
 $(MAGIC_FRAGMENT_DIR)/teapot \
 $(MAGIC_FRAGMENT_DIR)/terminfo \

+ 8 - 1
magic/Makefile.in

@@ -279,7 +279,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
 #
-# $File: Makefile.am,v 1.192 2024/10/02 01:45:32 christos Exp $
+# $File: Makefile.am,v 1.201 2026/02/01 16:25:09 christos Exp $
 #
 MAGIC_FRAGMENT_BASE = Magdir
 MAGIC_DIR = $(top_srcdir)/magic
@@ -319,6 +319,7 @@ $(MAGIC_FRAGMENT_DIR)/basis \
 $(MAGIC_FRAGMENT_DIR)/beetle \
 $(MAGIC_FRAGMENT_DIR)/ber \
 $(MAGIC_FRAGMENT_DIR)/bflt \
+$(MAGIC_FRAGMENT_DIR)/bgcode \
 $(MAGIC_FRAGMENT_DIR)/bhl \
 $(MAGIC_FRAGMENT_DIR)/bioinformatics \
 $(MAGIC_FRAGMENT_DIR)/biosig \
@@ -355,6 +356,7 @@ $(MAGIC_FRAGMENT_DIR)/console \
 $(MAGIC_FRAGMENT_DIR)/convex \
 $(MAGIC_FRAGMENT_DIR)/coverage \
 $(MAGIC_FRAGMENT_DIR)/cracklib \
+$(MAGIC_FRAGMENT_DIR)/creativeassembly \
 $(MAGIC_FRAGMENT_DIR)/crypto \
 $(MAGIC_FRAGMENT_DIR)/ctags \
 $(MAGIC_FRAGMENT_DIR)/ctf \
@@ -402,6 +404,7 @@ $(MAGIC_FRAGMENT_DIR)/gconv \
 $(MAGIC_FRAGMENT_DIR)/gentoo \
 $(MAGIC_FRAGMENT_DIR)/geo \
 $(MAGIC_FRAGMENT_DIR)/geos \
+$(MAGIC_FRAGMENT_DIR)/gguf \
 $(MAGIC_FRAGMENT_DIR)/gimp \
 $(MAGIC_FRAGMENT_DIR)/git \
 $(MAGIC_FRAGMENT_DIR)/glibc \
@@ -540,6 +543,7 @@ $(MAGIC_FRAGMENT_DIR)/pwsafe \
 $(MAGIC_FRAGMENT_DIR)/pyramid \
 $(MAGIC_FRAGMENT_DIR)/python \
 $(MAGIC_FRAGMENT_DIR)/qt \
+$(MAGIC_FRAGMENT_DIR)/r \
 $(MAGIC_FRAGMENT_DIR)/revision \
 $(MAGIC_FRAGMENT_DIR)/ringdove \
 $(MAGIC_FRAGMENT_DIR)/riff \
@@ -558,6 +562,7 @@ $(MAGIC_FRAGMENT_DIR)/selinux \
 $(MAGIC_FRAGMENT_DIR)/sendmail \
 $(MAGIC_FRAGMENT_DIR)/sequent \
 $(MAGIC_FRAGMENT_DIR)/sereal \
+$(MAGIC_FRAGMENT_DIR)/sf3 \
 $(MAGIC_FRAGMENT_DIR)/sgi \
 $(MAGIC_FRAGMENT_DIR)/sgml \
 $(MAGIC_FRAGMENT_DIR)/sharc \
@@ -578,9 +583,11 @@ $(MAGIC_FRAGMENT_DIR)/statistics \
 $(MAGIC_FRAGMENT_DIR)/subtitle \
 $(MAGIC_FRAGMENT_DIR)/sun \
 $(MAGIC_FRAGMENT_DIR)/svf \
+$(MAGIC_FRAGMENT_DIR)/syd \
 $(MAGIC_FRAGMENT_DIR)/sylk \
 $(MAGIC_FRAGMENT_DIR)/symbos \
 $(MAGIC_FRAGMENT_DIR)/sysex \
+$(MAGIC_FRAGMENT_DIR)/tapebackup \
 $(MAGIC_FRAGMENT_DIR)/tcl \
 $(MAGIC_FRAGMENT_DIR)/teapot \
 $(MAGIC_FRAGMENT_DIR)/terminfo \

+ 3 - 1
python/magic.py

@@ -127,12 +127,14 @@ _setparam.argtypes = [magic_t, c_int, c_void_p]
 class Magic(object):
     def __init__(self, ms):
         self._magic_t = ms
+	self._close = _close
 
     def close(self):
         """
         Closes the magic database and deallocates any resources used.
         """
-        _close(self._magic_t)
+        if _close:
+            _close(self._magic_t)
 
     @staticmethod
     def __tostr(s):

+ 48 - 18
src/apprentice.c

@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: apprentice.c,v 1.356 2024/11/27 15:37:00 christos Exp $")
+FILE_RCSID("@(#)$File: apprentice.c,v 1.369 2025/10/08 16:40:52 christos Exp $")
 #endif	/* lint */
 
 #include "magic.h"
@@ -58,7 +58,7 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.356 2024/11/27 15:37:00 christos Exp $")
 #endif
 
 
-#define	EATAB {while (isascii(CAST(unsigned char, *l)) && \
+#define	EATAB {while (*l && isascii(CAST(unsigned char, *l)) && \
 		      isspace(CAST(unsigned char, *l)))  ++l;}
 #define LOWCASE(l) (isupper(CAST(unsigned char, l)) ? \
 			tolower(CAST(unsigned char, l)) : (l))
@@ -341,7 +341,11 @@ get_standard_integer_type(const char *l, const char **t)
 {
 	int type;
 
-	if (isalpha(CAST(unsigned char, l[1]))) {
+	if (l[0] == '\0')
+		return FILE_INVALID;
+	if (l[1] == '\0')
+		return FILE_INVALID;
+	else if (isalpha(CAST(unsigned char, l[1]))) {
 		switch (l[1]) {
 		case 'C':
 			/* "dC" and "uC" */
@@ -749,6 +753,7 @@ file_apprentice(struct magic_set *ms, const char *fn, int action)
 	init_file_tables();
 
 	free(ms->fnamebuf);
+	ms->file = NULL;
 	if ((ms->fnamebuf = strdup(fn)) == NULL) {
 		file_oomem(ms, strlen(fn));
 		return -1;
@@ -1148,8 +1153,10 @@ apprentice_sort(const void *a, const void *b)
 				return 0;
 			file_magwarn1("Duplicate magic entry `%s'",
 			    ma->mp->desc);
+#ifndef COMPILE_ONLY
 			file_mdump(ma->mp);
 			file_mdump(mb->mp);
+#endif
 			return 0;
 		}
 		return x > 0 ? -1 : 1;
@@ -1258,12 +1265,6 @@ set_test_type(struct magic *mstart, struct magic *m)
 	case FILE_PSTRING:
 	case FILE_BESTRING16:
 	case FILE_LESTRING16:
-		/* Allow text overrides */
-		if (mstart->str_flags & STRING_TEXTTEST)
-			mstart->flag |= TEXTTEST;
-		else
-			mstart->flag |= BINTEST;
-		break;
 	case FILE_REGEX:
 	case FILE_SEARCH:
 		/* Check for override */
@@ -1275,6 +1276,16 @@ set_test_type(struct magic *mstart, struct magic *m)
 		if (mstart->flag & (TEXTTEST|BINTEST))
 			break;
 
+		/*
+		 * XXX: Compatibility: For string types assume binary match
+		 * in reality it is better in the long term to change all
+		 * the magic to be string/b where appropriate
+		 */
+		if (m->type != FILE_REGEX && m->type != FILE_SEARCH) {
+			mstart->flag |= BINTEST;
+			break;
+		}
+
 		/* binary test if pattern is not text */
 		if (file_looks_utf8(m->value.us, CAST(size_t, m->vallen), NULL,
 		    NULL) <= 0)
@@ -1778,6 +1789,16 @@ string_modifier_check(struct magic_set *ms, struct magic *m)
 			    CHAR_COMPACT_OPTIONAL_WHITESPACE);
 			return -1;
 		}
+		if ((m->str_flags & STRING_IGNORE_LOWERCASE) != 0) {
+			file_magwarn(ms, "'/%c' not allowed on regex\n",
+			    CHAR_IGNORE_LOWERCASE);
+			return -1;
+		}
+		if ((m->str_flags & STRING_IGNORE_UPPERCASE) != 0) {
+			file_magwarn(ms, "'/%c' not allowed on regex\n",
+			    CHAR_IGNORE_UPPERCASE);
+			return -1;
+		}
 		break;
 	default:
 		file_magwarn(ms, "coding error: m->type=%d\n",
@@ -2391,11 +2412,19 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *file,
 		}
 		break;
 	}
+
+
 	/*
 	 * Grab the value part, except for an 'x' reln.
 	 */
-	if (m->reln != 'x' && getvalue(ms, m, &l, action))
+	if (m->reln != 'x') {
+		if (*l == '\0') {
+			file_magwarn(ms, "incomplete magic `%s'", line);
+			return -1;
+		}
+		if (getvalue(ms, m, &l, action))
 		return -1;
+	}
 
 	/*
 	 * TODO finish this macro and start using it!
@@ -2415,7 +2444,7 @@ parse(struct magic_set *ms, struct magic_entry *me, const char *file,
 		++l;
 		m->flag |= NOSPACE;
 	}
-	for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
+	for (i = 0; i < sizeof(m->desc) && (m->desc[i++] = *l++) != '\0';)
 		continue;
 	if (m->desc[0] == '\0') {
 		// Tuck in the filename for debugging.
@@ -2647,7 +2676,7 @@ check_format_type(const char *ptr, int type, const char **estr)
 			}
 		} else
 			h = 0;
-		while (*ptr && strchr("-.#", *ptr) != NULL)
+		while (*ptr && strchr("+-.#", *ptr) != NULL)
 			ptr++;
 #define CHECKLEN() do { \
 	for (len = cnt = 0; isdigit(CAST(unsigned char, *ptr)); ptr++, cnt++) \
@@ -2856,7 +2885,7 @@ check_format(struct magic_set *ms, struct magic *m)
  * pointer, according to the magic type.  Update the string pointer to point
  * just after the number read.  Return 0 for success, non-zero for failure.
  */
-file_private int
+file_no_overflow file_private int
 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
 {
 	char *ep;
@@ -2919,8 +2948,10 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
 			*p = ep;
 		return 0;
 	case FILE_GUID:
-		if (file_parse_guid(*p, m->value.guid) == -1)
+		if (file_parse_guid(*p, m->value.guid) == -1) {
+			file_magwarn(ms, "Error parsing guid `%s'", *p);
 			return -1;
+		}
 		*p += FILE_GUID_SIZE - 1;
 		return 0;
 	default:
@@ -3377,7 +3408,7 @@ check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname)
 	int i, needsbyteswap;
 
 	entries = CAST(uint32_t, map->len / sizeof(struct magic));
-	if (entries < MAGIC_SETS + 1) {
+	if (entries < MAGIC_SETS) {
 		file_error(ms, 0, "Too few magic entries %u in `%s'",
 		    entries, dbname);
 		return -1;
@@ -3644,15 +3675,14 @@ file_varint2uintmax_t(const unsigned char *us, int t, size_t *l)
 file_private void
 bs1(struct magic *m)
 {
-	m->cont_level = swap2(m->cont_level);
+	m->flag = swap2(m->flag);
 	m->offset = swap4(CAST(uint32_t, m->offset));
 	m->in_offset = swap4(CAST(uint32_t, m->in_offset));
 	m->lineno = swap4(CAST(uint32_t, m->lineno));
 	if (IS_STRING(m->type)) {
 		m->str_range = swap4(m->str_range);
 		m->str_flags = swap4(m->str_flags);
-	}
-	else {
+	} else {
 		m->value.q = swap8(m->value.q);
 		m->num_mask = swap8(m->num_mask);
 	}

+ 4 - 5
src/apptype.c

@@ -27,7 +27,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: apptype.c,v 1.17 2022/12/26 17:31:14 christos Exp $")
+FILE_RCSID("@(#)$File: apptype.c,v 1.18 2024/12/08 18:59:04 christos Exp $")
 #endif /* lint */
 
 #include <stdlib.h>
@@ -42,8 +42,7 @@ FILE_RCSID("@(#)$File: apptype.c,v 1.17 2022/12/26 17:31:14 christos Exp $")
 typedef ULONG   APPTYPE;
 
 file_protected int
-file_os2_apptype(struct magic_set *ms, const char *fn, const void *buf,
-    size_t nb)
+file_os2_apptype(struct magic_set *ms, const char *fn, const struct buffer *b)
 {
 	APPTYPE         rc, type;
 	char            path[_MAX_PATH], drive[_MAX_DRIVE], dir[_MAX_DIR],
@@ -69,7 +68,7 @@ file_os2_apptype(struct magic_set *ms, const char *fn, const void *buf,
 			file_error(ms, errno, "cannot open tmp file `%s'", path);
 			return -1;
 		}
-		if (fwrite(buf, 1, nb, fp) != nb) {
+		if (fwrite(b->fbuf, 1, b->flen, fp) != b->flen) {
 			file_error(ms, errno, "cannot write tmp file `%s'",
 			    path);
 			(void)fclose(fp);
@@ -129,7 +128,7 @@ file_os2_apptype(struct magic_set *ms, const char *fn, const void *buf,
 		 * ".com".
 		 */
 		if (stricmp(ext, ".com") == 0)
-			if (strncmp((const char *)buf, "MZ", 2))
+			if (strncmp((const char *)b->fbuf, "MZ", 2))
 				return (0);
 		if (file_printf(ms, "DOS executable") == -1)
 			return -1;

+ 5 - 1
src/buffer.c

@@ -27,7 +27,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: buffer.c,v 1.13 2023/07/02 12:48:39 christos Exp $")
+FILE_RCSID("@(#)$File: buffer.c,v 1.14 2025/05/28 19:22:22 christos Exp $")
 #endif	/* lint */
 
 #include "magic.h"
@@ -68,6 +68,10 @@ buffer_fill(const struct buffer *bb)
 	if (b->elen != 0)
 		return b->elen == FILE_BADSIZE ? -1 : 0;
 
+	// Nothing to refill, everything is in memory
+	if (b->fd == -1)
+		return 0;
+
 	if (!S_ISREG(b->st.st_mode))
 		goto out;
 

+ 6 - 6
src/cdf.c

@@ -35,7 +35,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.124 2024/11/25 21:24:59 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.126 2026/02/09 17:10:42 christos Exp $")
 #endif
 
 #include <assert.h>
@@ -830,7 +830,7 @@ out:
 	return 0;
 }
 
-file_private int
+file_protected int
 cdf_namecmp(const char *d, const uint16_t *s, size_t l)
 {
 	for (; l--; d++, s++)
@@ -880,12 +880,12 @@ cdf_find_stream(const cdf_dir_t *dir, const char *name, int type)
 {
 	size_t i, name_len = strlen(name) + 1;
 
-	for (i = dir->dir_len; i > 0; i--)
-		if (dir->dir_tab[i - 1].d_type == type &&
-		    cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len)
+	for (i = 1; i <= dir->dir_len; i++)
+		if (dir->dir_tab[i-1].d_type == type &&
+		    cdf_namecmp(name, dir->dir_tab[i-1].d_name, name_len)
 		    == 0)
 			break;
-	if (i > 0)
+	if (i <= dir->dir_len)
 		return CAST(int, i);
 
 	DPRINTF(("Cannot find type %d `%s'\n", type, name));

+ 1 - 0
src/cdf.h

@@ -323,6 +323,7 @@ file_protected int cdf_read_user_stream(const cdf_info_t *,
     const cdf_stream_t *, const cdf_dir_t *, const char *, cdf_stream_t *);
 file_protected int cdf_find_stream(const cdf_dir_t *, const char *, int);
 file_protected int cdf_zero_stream(cdf_stream_t *);
+file_protected int cdf_namecmp(const char *, const uint16_t *, size_t);
 file_protected int cdf_read_doc_summary_info(const cdf_info_t *,
     const cdf_header_t *, const cdf_sat_t *, const cdf_sat_t *,
     const cdf_stream_t *, const cdf_dir_t *, cdf_stream_t *);

+ 7 - 3
src/encoding.c

@@ -35,7 +35,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: encoding.c,v 1.43 2024/10/29 20:56:48 christos Exp $")
+FILE_RCSID("@(#)$File: encoding.c,v 1.44 2024/12/26 18:41:27 christos Exp $")
 #endif	/* lint */
 
 #include "magic.h"
@@ -237,11 +237,15 @@ file_encoding(struct magic_set *ms, const struct buffer *b,
 #define I 2   /* character appears in ISO-8859 text */
 #define X 3   /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
 
+/*
+ * SUB (substitute character ^Z) was used as EOF in DOS and early Windows
+ * NEL (next line 0x85) is considered in ECMAScript as whitespace
+ */
 file_private char text_chars[256] = {
 	/*                  BEL BS HT LF VT FF CR    */
 	F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F,  /* 0x0X */
-	/*                              ESC          */
-	F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  /* 0x1X */
+	/*                           SUB ESC          */
+	F, F, F, F, F, F, F, F, F, F, T, T, F, F, F, F,  /* 0x1X */
 	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x2X */
 	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x3X */
 	T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x4X */

+ 10 - 3
src/file.h

@@ -27,7 +27,7 @@
  */
 /*
  * file.h - definitions for file(1) program
- * @(#)$File: file.h,v 1.258 2024/11/27 15:37:00 christos Exp $
+ * @(#)$File: file.h,v 1.262 2025/07/23 18:52:08 christos Exp $
  */
 
 #ifndef __file_h__
@@ -202,6 +202,10 @@ struct buffer {
 };
 
 union VALUETYPE {
+	int8_t sb;
+	int16_t sh;
+	int32_t sl;
+	int64_t sq;
 	uint8_t b;
 	uint16_t h;
 	uint32_t l;
@@ -513,7 +517,7 @@ struct magic_set {
 #define	FILE_ELF_SHNUM_MAX		32768
 #define	FILE_ELF_SHSIZE_MAX		(128 * 1024 * 1024)
 #define	FILE_INDIR_MAX			50
-#define	FILE_NAME_MAX			100
+#define	FILE_NAME_MAX			150
 #define	FILE_REGEX_MAX			8192
 #define	FILE_ENCODING_MAX		(64 * 1024)
 #define	FILE_MAGWARN_MAX		64
@@ -616,7 +620,7 @@ file_protected char * file_printable(struct magic_set *, char *, size_t,
     const char *, size_t);
 #ifdef __EMX__
 file_protected int file_os2_apptype(struct magic_set *, const char *,
-    const void *, size_t);
+    const struct buffer *);
 #endif /* __EMX__ */
 file_protected int file_pipe_closexec(int *);
 file_protected int file_clear_closexec(int);
@@ -735,4 +739,7 @@ static const char *rcsid(const char *p) { \
 #define __RCSID(a)
 #endif
 
+#define file_no_overflow \
+    __attribute__((__no_sanitize__("signed-integer-overflow")))
+
 #endif /* __file_h__ */

+ 77 - 26
src/funcs.c

@@ -27,7 +27,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: funcs.c,v 1.142 2023/07/30 14:41:14 christos Exp $")
+FILE_RCSID("@(#)$File: funcs.c,v 1.148 2026/01/10 16:18:18 christos Exp $")
 #endif	/* lint */
 
 #include "magic.h"
@@ -99,8 +99,13 @@ file_checkfmt(char *msg, size_t mlen, const char *fmt)
 			continue;
 		if (*++p == '%')
 			continue;
+		if (*p == '\0') {
+			if (msg)
+				snprintf(msg, mlen, "incomplete %% format");
+			return -1;
+		}
 		// Skip uninteresting.
-		while (strchr("#0.'+- ", *p) != NULL)
+		while (*p != '\0' && strchr("#0.'+- ", *p) != NULL)
 			p++;
 		if (*p == '*') {
 			if (msg)
@@ -300,6 +305,7 @@ file_default(struct magic_set *ms, size_t nb)
 		return 1;
 	}
 	if (ms->flags & MAGIC_APPLE) {
+		// This is not a typo: Type: UNKN Creator: UNKN
 		if (file_printf(ms, "UNKNUNKN") == -1)
 			return -1;
 		return 1;
@@ -674,25 +680,31 @@ check_regex(struct magic_set *ms, const char *pat)
 	unsigned char oc = '\0';
 	const char *p;
 	unsigned long l;
+	static const char wild[] = "?*+{";
 
 	for (p = pat; *p; p++) {
 		unsigned char c = *p;
-		// Avoid repetition
-		if (c == oc && strchr("?*+{", c) != NULL) {
+		// Avoid repetition of wild characters
+		if (strchr(wild, oc) != NULL && strchr(wild, c) != NULL) {
 			size_t len = strlen(pat);
 			file_magwarn(ms,
-			    "repetition-operator operand `%c' "
-			    "invalid in regex `%s'", c,
+			    "repetition-operator operand `%c%c' "
+			    "invalid in regex `%s'", oc, c,
 			    file_printable(ms, sbuf, sizeof(sbuf), pat, len));
 			return -1;
 		}
 		if (c == '{') {
 			char *ep, *eep;
+
+			if (oc == '}') {
+				file_magwarn(ms, "cascading repetition "
+				    "operators in regex `%s'", pat);
+				return -1;
+			}
 			errno = 0;
 			l = strtoul(p + 1, &ep, 10);
 			if (ep != p + 1 && l > 1000)
 				goto bounds;
-
 			if (*ep == ',') {
 				l = strtoul(ep + 1, &eep, 10);
 				if (eep != ep + 1 && l > 1000)
@@ -858,29 +870,68 @@ struct guid {
 	uint8_t data4[8];
 };
 
+static char XDIGIT[]  = "0123456789abcdef";
+static int
+atox(const uint8_t c)
+{
+	uint8_t d = isupper(c) ? tolower(c) : c;
+	const char *q = d ? strchr(XDIGIT, isupper(c) ? tolower(c) : c) : NULL;
+	if (q == NULL)
+		return -1;
+	return q - XDIGIT;
+}
+
+static int
+getxvalue(void *p, const char *s, size_t n)
+{
+	uint64_t v = 0;
+	for (size_t i = 0; i < n; i++) {
+		int x = atox(s[i]);
+		if (x == -1)
+			return 0;
+		v = (v << 4) | x;
+	}
+	switch (n) {
+	case 8:
+		*(uint32_t *)p = v;
+		return 1;
+	case 4:
+		*(uint16_t *)p = v;
+		return 1;
+	case 2:
+		*(uint8_t *)p = v;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
 file_protected int
 file_parse_guid(const char *s, uint64_t *guid)
 {
 	struct guid *g = CAST(struct guid *, CAST(void *, guid));
-#ifndef WIN32
-	return sscanf(s,
-	    "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
-	    &g->data1, &g->data2, &g->data3, &g->data4[0], &g->data4[1],
-	    &g->data4[2], &g->data4[3], &g->data4[4], &g->data4[5],
-	    &g->data4[6], &g->data4[7]) == 11 ? 0 : -1;
-#else
-	/* MS-Windows runtime doesn't support %hhx, except under
-	   non-default __USE_MINGW_ANSI_STDIO.  */
-	uint16_t data16[8];
-	int rv = sscanf(s, "%8x-%4hx-%4hx-%2hx%2hx-%2hx%2hx%2hx%2hx%2hx%2hx",
-	    &g->data1, &g->data2, &g->data3, &data16[0], &data16[1],
-	    &data16[2], &data16[3], &data16[4], &data16[5],
-	    &data16[6], &data16[7]) == 11 ? 0 : -1;
-	int i;
-	for (i = 0; i < 8; i++)
-	    g->data4[i] = data16[i];
-	return rv;
-#endif
+
+	if (!getxvalue(&g->data1, s, 8) || s[8] != '-')
+		return -1;
+	s += 9;
+	if (!getxvalue(&g->data2, s, 4) || s[4] != '-')
+		return -1;
+	s += 5;
+	if (!getxvalue(&g->data3, s, 4) || s[4] != '-')
+		return -1;
+	s += 5;
+	if (!getxvalue(&g->data4[0], s, 2) ||
+	    !getxvalue(&g->data4[1], s + 2, 2) || s[4] != '-')
+		return -1;
+	s += 5;
+	if (!getxvalue(&g->data4[2], s, 2) ||
+	    !getxvalue(&g->data4[3], s + 2, 2) ||
+	    !getxvalue(&g->data4[4], s + 4, 2) ||
+	    !getxvalue(&g->data4[5], s + 6, 2) ||
+	    !getxvalue(&g->data4[6], s + 8, 2) ||
+	    !getxvalue(&g->data4[7], s + 10, 2))
+		return -1;
+	return 0;
 }
 
 file_protected int

+ 12 - 4
src/is_simh.c

@@ -33,7 +33,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: is_simh.c,v 1.10 2023/07/27 19:39:55 christos Exp $")
+FILE_RCSID("@(#)$File: is_simh.c,v 1.11 2025/05/31 23:31:45 christos Exp $")
 #endif
 
 #include <string.h>
@@ -91,15 +91,18 @@ swap4(uint32_t sv)
 
 
 static uint32_t
-getlen(const unsigned char **uc)
+getlen(const unsigned char **uc, int *err)
 {
 	uint32_t n;
 	memcpy(&n, *uc, sizeof(n));
+	*err = 0;
 	*uc += sizeof(n);
 	if (NEED_SWAP)
 		n = swap4(n);
 	if (n == 0xffffffff)	/* check for End of Medium */
 		return n;
+	/* Check bits 25 to 28 are not used */
+	*err = ((n & 0x00ffffff) != (n & 0x0fffffff));
 	n &= 0x00ffffff;	/* keep only the record len */
 	if (n & 1)
 		n++;
@@ -112,11 +115,14 @@ simh_parse(const unsigned char *uc, const unsigned char *ue)
 	uint32_t nbytes, cbytes;
 	const unsigned char *orig_uc = uc;
 	size_t nt = 0, nr = 0;
+	int err = 0;
 
 	(void)memcpy(simh_bo.s, "\01\02\03\04", 4);
 
 	while (ue - uc >= CAST(ptrdiff_t, sizeof(nbytes))) {
-		nbytes = getlen(&uc);
+		nbytes = getlen(&uc, &err);
+		if (err)
+			return 0;
 		if ((nt > 0 || nr > 0) && nbytes == 0xFFFFFFFF)
 			/* EOM after at least one record or tapemark */
 			break;
@@ -132,7 +138,9 @@ simh_parse(const unsigned char *uc, const unsigned char *ue)
 		uc += nbytes;
 		if (ue - uc < CAST(ptrdiff_t, sizeof(nbytes)))
 			break;
-		cbytes = getlen(&uc);
+		cbytes = getlen(&uc, &err);
+		if (err)
+			return 0;
 		if (nbytes != cbytes)
 			return 0;
 		nr++;

+ 24 - 22
src/magic.c

@@ -33,7 +33,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: magic.c,v 1.123 2023/12/29 18:04:48 christos Exp $")
+FILE_RCSID("@(#)$File: magic.c,v 1.125 2026/01/19 18:53:58 christos Exp $")
 #endif	/* lint */
 
 #include "magic.h"
@@ -205,7 +205,7 @@ get_default_magic(void)
 		}
 	}
 
-	if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0)
+	if (asprintf(&default_magic, "%s%c%s", hmagicpath, PATHSEP, MAGIC) < 0)
 		goto out;
 	free(hmagicpath);
 	return default_magic;
@@ -368,29 +368,30 @@ close_and_restore(const struct magic_set *ms, const char *name, int fd,
 		return;
 	(void) close(fd);
 
-	if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
-		/*
-		 * Try to restore access, modification times if read it.
-		 * This is really *bad* because it will modify the status
-		 * time of the file... And of course this will affect
-		 * backup programs
-		 */
+	if (sb == NULL || (ms->flags & MAGIC_PRESERVE_ATIME) == 0)
+		return;
+
+	/*
+	 * Try to restore access, modification times if read it.
+	 * This is really *bad* because it will modify the status
+	 * time of the file... And of course this will affect
+	 * backup programs
+	 */
 #ifdef HAVE_UTIMES
-		struct timeval  utsbuf[2];
-		(void)memset(utsbuf, 0, sizeof(utsbuf));
-		utsbuf[0].tv_sec = sb->st_atime;
-		utsbuf[1].tv_sec = sb->st_mtime;
+	struct timeval  utsbuf[2];
+	(void)memset(utsbuf, 0, sizeof(utsbuf));
+	utsbuf[0].tv_sec = sb->st_atime;
+	utsbuf[1].tv_sec = sb->st_mtime;
 
-		(void) utimes(name, utsbuf); /* don't care if loses */
+	(void) utimes(name, utsbuf); /* don't care if loses */
 #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
-		struct utimbuf  utbuf;
+	struct utimbuf  utbuf;
 
-		(void)memset(&utbuf, 0, sizeof(utbuf));
-		utbuf.actime = sb->st_atime;
-		utbuf.modtime = sb->st_mtime;
-		(void) utime(name, &utbuf); /* don't care if loses */
+	(void)memset(&utbuf, 0, sizeof(utbuf));
+	utbuf.actime = sb->st_atime;
+	utbuf.modtime = sb->st_mtime;
+	(void) utime(name, &utbuf); /* don't care if loses */
 #endif
-	}
 }
 
 #ifndef COMPILE_ONLY
@@ -530,7 +531,8 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
 	}
 
 	(void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
-	if (file_buffer(ms, fd, okstat ? &sb : NULL, inname, buf, CAST(size_t, nbytes)) == -1)
+	if (file_buffer(ms, fd, okstat ? &sb : NULL, inname, buf,
+	    CAST(size_t, nbytes)) == -1)
 		goto done;
 	rv = 0;
 done:
@@ -538,7 +540,7 @@ done:
 	if (fd != -1) {
 		if (pos != CAST(off_t, -1))
 			(void)lseek(fd, pos, SEEK_SET);
-		close_and_restore(ms, inname, fd, &sb);
+		close_and_restore(ms, inname, fd, okstat ? &sb : NULL);
 	}
 out:
 	return rv == 0 ? file_getbuffer(ms) : NULL;

+ 6 - 2
src/print.c

@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: print.c,v 1.106 2024/09/01 13:50:01 christos Exp $")
+FILE_RCSID("@(#)$File: print.c,v 1.110 2025/03/20 17:46:50 christos Exp $")
 #endif  /* lint */
 
 #include <string.h>
@@ -352,9 +352,13 @@ file_fmtdate(char *buf, size_t bsize, uint16_t v)
 	memset(&tm, 0, sizeof(tm));
 	tm.tm_mday = v & 0x1f;
 	tm.tm_mon = ((v >> 5) & 0xf) - 1;
+	// Sanity check because some OS's coredump with invalid values.
+	// Yes, Cygwin I am looking at you!
+	if (tm.tm_mon < 0 || tm.tm_mon > 11)
+		tm.tm_mon = 0;
 	tm.tm_year = (v >> 9) + 80;
 
-	if (strftime(buf, bsize, "%a, %b %d %Y", &tm) == 0)
+	if (strftime(buf, bsize, "%b %d %Y", &tm) == 0)
 		goto out;
 
 	return buf;

+ 41 - 21
src/readcdf.c

@@ -26,7 +26,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readcdf.c,v 1.80 2023/01/24 20:13:40 christos Exp $")
+FILE_RCSID("@(#)$File: readcdf.c,v 1.81 2026/02/04 14:56:28 christos Exp $")
 #endif
 
 #include <assert.h>
@@ -220,6 +220,11 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
 				} else if (str == NULL && info[i].pi_id ==
 				    CDF_PROPERTY_NAME_OF_APPLICATION) {
 					str = cdf_app_to_mime(vbuf, app2mime);
+#ifdef CDF_DEBUG
+					fprintf(stderr, "Found property "
+					    "application name = \"%s\" "
+					    "(mime=%s)\n", vbuf, str);
+#endif
 				}
 			}
 			break;
@@ -487,7 +492,7 @@ file_private struct sinfo {
 	},
 	{ "Microsoft PowerPoint", "vnd.ms-powerpoint",
 		{
-			"PowerPoint", NULL, NULL, NULL, NULL,
+			"PowerPoint Document", NULL, NULL, NULL, NULL,
 		},
 		{
 			CDF_DIR_TYPE_USER_STREAM,
@@ -511,28 +516,43 @@ file_private struct sinfo {
 file_private int
 cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
 {
-	size_t sd, j;
-
-	for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
-		const struct sinfo *si = &sectioninfo[sd];
-		for (j = 0; si->sections[j]; j++) {
-			if (cdf_find_stream(dir, si->sections[j], si->types[j])
-			    > 0)
-				break;
+	size_t sd, i, j;
+	uint16_t *dir_name;
+	int dir_type;
+	const char* section_name;
+
+	for (i = 0; i < dir->dir_len; i++) {
+		dir_name = dir->dir_tab[i].d_name;
+		dir_type = dir->dir_tab[i].d_type;
+
+		for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
+			const struct sinfo *si = &sectioninfo[sd];
+			for (j = 0; si->sections[j]; j++) {
+				if (si->sections[j] == NULL)
+					continue;
+				section_name = si->sections[j];
+				if (si->types[j] != dir_type ||
+				    cdf_namecmp(section_name, dir_name,
+					strlen(section_name) + 1) != 0)
+				    continue;
 #ifdef CDF_DEBUG
-			fprintf(stderr, "Can't read %s\n", si->sections[j]);
+				fprintf(stderr, "Matching directory %"
+				    SIZE_T_FORMAT
+				    "u with expected name \"%s\"\n",
+				    i, section_name);
 #endif
+				if (NOTMIME(ms)) {
+					if (file_printf(ms, "CDFV2 %s",
+					    si->name) == -1)
+						return -1;
+				} else if (ms->flags & MAGIC_MIME_TYPE) {
+					if (file_printf(ms, "application/%s",
+					    si->mime) == -1)
+						return -1;
+				}
+				return 1;
+			}
 		}
-		if (si->sections[j] == NULL)
-			continue;
-		if (NOTMIME(ms)) {
-			if (file_printf(ms, "CDFV2 %s", si->name) == -1)
-				return -1;
-		} else if (ms->flags & MAGIC_MIME_TYPE) {
-			if (file_printf(ms, "application/%s", si->mime) == -1)
-				return -1;
-		}
-		return 1;
 	}
 	return -1;
 }

+ 108 - 95
src/readelf.c

@@ -27,13 +27,14 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readelf.c,v 1.196 2024/11/11 15:49:11 christos Exp $")
+FILE_RCSID("@(#)$File: readelf.c,v 1.204 2025/06/27 16:57:44 christos Exp $")
 #endif
 
 #ifdef BUILTIN_ELF
 #include <string.h>
 #include <ctype.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -65,12 +66,25 @@ file_private uint64_t getu64(int, uint64_t);
 #define NAMEEQUALS(n, v) \
     (namesz == sizeof(v) && memcmp(n, v, namesz) == 0)
 
+__attribute__((__format__(__printf__, 2, 3)))
 file_private int
-toomany(struct magic_set *ms, const char *name, uint16_t num)
+elf_printf(struct magic_set *ms, const char *fmt, ...)
 {
+	va_list ap;
+	int rv;
+
 	if (ms->flags & MAGIC_MIME)
 		return 1;
-	if (file_printf(ms, ", too many %s (%u)", name, num) == -1)
+
+	va_start(ap, fmt);
+	rv = file_vprintf(ms, fmt, ap);
+	va_end(ap);
+	return rv;
+}
+file_private int
+toomany(struct magic_set *ms, const char *name, uint16_t num)
+{
+	if (elf_printf(ms, ", too many %s (%u)", name, num) == -1)
 		return -1;
 	return 1;
 }
@@ -363,12 +377,12 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 		return 0;
 
 	if (num == 0) {
-		if (file_printf(ms, ", no program header") == -1)
+		if (elf_printf(ms, ", no program header") == -1)
 			return -1;
 		return 0;
 	}
 	if (size != xph_sizeof) {
-		if (file_printf(ms, ", corrupted program header size") == -1)
+		if (elf_printf(ms, ", corrupted program header size") == -1)
 			return -1;
 		return 0;
 	}
@@ -379,7 +393,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 	for ( ; num; num--) {
 		if (pread(fd, xph_addr, xph_sizeof, off) <
 		    CAST(ssize_t, xph_sizeof)) {
-			if (file_printf(ms, 
+			if (elf_printf(ms, 
 			    ", can't read elf program headers at %jd",
 			    (intmax_t)off) == -1)
 				return -1;
@@ -402,7 +416,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 		len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
 		offs = xph_offset;
 		if ((bufsize = pread(fd, nbuf, len, offs)) == -1) {
-			if (file_printf(ms, " can't read note section at %jd",
+			if (elf_printf(ms, " can't read note section at %jd",
 			    (intmax_t)offs) == -1)
 				return -1;
 			return 0;
@@ -430,7 +444,7 @@ do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
 	memcpy(&desc, v, sizeof(desc));
 	desc = elf_getu32(swap, desc);
 
-	if (file_printf(ms, ", for NetBSD") == -1)
+	if (elf_printf(ms, ", for NetBSD") == -1)
 		return -1;
 	/*
 	 * The version number used to be stuck as 199905, and was thus
@@ -450,22 +464,22 @@ do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
 		uint32_t ver_min = (desc / 1000000) % 100;
 		uint32_t ver_maj = desc / 100000000;
 
-		if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
+		if (elf_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
 			return -1;
 		if (ver_maj >= 9) {
 			ver_patch += 100 * ver_rel;
 			ver_rel = 0;
 		}
 		if (ver_rel == 0 && ver_patch != 0) {
-			if (file_printf(ms, ".%u", ver_patch) == -1)
+			if (elf_printf(ms, ".%u", ver_patch) == -1)
 				return -1;
 		} else if (ver_rel != 0) {
 			while (ver_rel > 26) {
-				if (file_printf(ms, "Z") == -1)
+				if (elf_printf(ms, "Z") == -1)
 					return -1;
 				ver_rel -= 26;
 			}
-			if (file_printf(ms, "%c", 'A' + ver_rel - 1) == -1)
+			if (elf_printf(ms, "%c", 'A' + ver_rel - 1) == -1)
 				return -1;
 		}
 	}
@@ -479,7 +493,7 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
 
 	memcpy(&desc, v, sizeof(desc));
 	desc = elf_getu32(swap, desc);
-	if (file_printf(ms, ", for FreeBSD") == -1)
+	if (elf_printf(ms, ", for FreeBSD") == -1)
 		return -1;
 
 	/*
@@ -509,39 +523,39 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
 	 * was version 3.0.
 	 */
 	if (desc == 460002) {
-		if (file_printf(ms, " 4.6.2") == -1)
+		if (elf_printf(ms, " 4.6.2") == -1)
 			return -1;
 	} else if (desc < 460100) {
-		if (file_printf(ms, " %d.%d", desc / 100000,
+		if (elf_printf(ms, " %d.%d", desc / 100000,
 		    desc / 10000 % 10) == -1)
 			return -1;
 		if (desc / 1000 % 10 > 0)
-			if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
+			if (elf_printf(ms, ".%d", desc / 1000 % 10) == -1)
 				return -1;
 		if ((desc % 1000 > 0) || (desc % 100000 == 0))
-			if (file_printf(ms, " (%d)", desc) == -1)
+			if (elf_printf(ms, " (%d)", desc) == -1)
 				return -1;
 	} else if (desc < 500000) {
-		if (file_printf(ms, " %d.%d", desc / 100000,
+		if (elf_printf(ms, " %d.%d", desc / 100000,
 		    desc / 10000 % 10 + desc / 1000 % 10) == -1)
 			return -1;
 		if (desc / 100 % 10 > 0) {
-			if (file_printf(ms, " (%d)", desc) == -1)
+			if (elf_printf(ms, " (%d)", desc) == -1)
 				return -1;
 		} else if (desc / 10 % 10 > 0) {
-			if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
+			if (elf_printf(ms, ".%d", desc / 10 % 10) == -1)
 				return -1;
 		}
 	} else {
-		if (file_printf(ms, " %d.%d", desc / 100000,
+		if (elf_printf(ms, " %d.%d", desc / 100000,
 		    desc / 1000 % 100) == -1)
 			return -1;
 		if ((desc / 100 % 10 > 0) ||
 		    (desc % 100000 / 100 == 0)) {
-			if (file_printf(ms, " (%d)", desc) == -1)
+			if (elf_printf(ms, " (%d)", desc) == -1)
 				return -1;
 		} else if (desc / 10 % 10 > 0) {
-			if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
+			if (elf_printf(ms, ".%d", desc / 10 % 10) == -1)
 				return -1;
 		}
 	}
@@ -574,18 +588,18 @@ do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		    btype = "unknown";
 		    break;
 		}
-		if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
+		if (elf_printf(ms, ", BuildID[%s]=", btype) == -1)
 			return -1;
 		memcpy(desc, &nbuf[doff], descsz);
 		for (i = 0; i < descsz; i++)
-		    if (file_printf(ms, "%02x", desc[i]) == -1)
+		    if (elf_printf(ms, "%02x", desc[i]) == -1)
 			return -1;
 		return 1;
 	}
 	if (namesz == 4 && memcmp(RCAST(char *, &nbuf[noff]), "Go", 3) == 0 &&
 	    type == NT_GO_BUILD_ID && descsz < 128) {
 		char buf[256];
-		if (file_printf(ms, ", Go BuildID=%s",
+		if (elf_printf(ms, ", Go BuildID=%s",
 		    file_copystr(buf, sizeof(buf), descsz,
 		    RCAST(const char *, &nbuf[doff]))) == -1)
 			return -1;
@@ -603,7 +617,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 
 	if (NAMEEQUALS(name, "SuSE") && type == NT_GNU_VERSION && descsz == 2) {
 		*flags |= FLAGS_DID_OS_NOTE;
-		if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff],
+		if (elf_printf(ms, ", for SuSE %d.%d", nbuf[doff],
 		    nbuf[doff + 1]) == -1)
 		    return -1;
 	    return 1;
@@ -614,34 +628,34 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		memcpy(desc, &nbuf[doff], sizeof(desc));
 
 		*flags |= FLAGS_DID_OS_NOTE;
-		if (file_printf(ms, ", for GNU/") == -1)
+		if (elf_printf(ms, ", for GNU/") == -1)
 			return -1;
 		switch (elf_getu32(swap, desc[0])) {
 		case GNU_OS_LINUX:
-			if (file_printf(ms, "Linux") == -1)
+			if (elf_printf(ms, "Linux") == -1)
 				return -1;
 			break;
 		case GNU_OS_HURD:
-			if (file_printf(ms, "Hurd") == -1)
+			if (elf_printf(ms, "Hurd") == -1)
 				return -1;
 			break;
 		case GNU_OS_SOLARIS:
-			if (file_printf(ms, "Solaris") == -1)
+			if (elf_printf(ms, "Solaris") == -1)
 				return -1;
 			break;
 		case GNU_OS_KFREEBSD:
-			if (file_printf(ms, "kFreeBSD") == -1)
+			if (elf_printf(ms, "kFreeBSD") == -1)
 				return -1;
 			break;
 		case GNU_OS_KNETBSD:
-			if (file_printf(ms, "kNetBSD") == -1)
+			if (elf_printf(ms, "kNetBSD") == -1)
 				return -1;
 			break;
 		default:
-			if (file_printf(ms, "<unknown>") == -1)
+			if (elf_printf(ms, "<unknown>") == -1)
 				return -1;
 		}
-		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
+		if (elf_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
 		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
 			return -1;
 		return 1;
@@ -667,7 +681,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 	if (NAMEEQUALS(name, "OpenBSD") &&
 	    type == NT_OPENBSD_VERSION && descsz == 4) {
 		*flags |= FLAGS_DID_OS_NOTE;
-		if (file_printf(ms, ", for OpenBSD") == -1)
+		if (elf_printf(ms, ", for OpenBSD") == -1)
 			return -1;
 		/* Content of note is always 0 */
 		return 1;
@@ -677,11 +691,11 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 	    type == NT_DRAGONFLY_VERSION && descsz == 4) {
 		uint32_t desc;
 		*flags |= FLAGS_DID_OS_NOTE;
-		if (file_printf(ms, ", for DragonFly") == -1)
+		if (elf_printf(ms, ", for DragonFly") == -1)
 			return -1;
 		memcpy(&desc, &nbuf[doff], sizeof(desc));
 		desc = elf_getu32(swap, desc);
-		if (file_printf(ms, " %d.%d.%d", desc / 100000,
+		if (elf_printf(ms, " %d.%d.%d", desc / 100000,
 		    desc / 10000 % 10, desc % 10000) == -1)
 			return -1;
 		return 1;
@@ -693,7 +707,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		*flags |= FLAGS_DID_OS_NOTE;
 		memcpy(&api_level, &nbuf[doff], sizeof(api_level));
 		api_level = elf_getu32(swap, api_level);
-		if (file_printf(ms, ", for Android %d", api_level) == -1)
+		if (elf_printf(ms, ", for Android %d", api_level) == -1)
 			return -1;
 		/*
 		 * NDK r14 and later also include details of the NDK that
@@ -702,7 +716,7 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		 * are both 64-byte strings.
 		 */
 		if (descsz >= 4 + 64 + 64) {
-			if (file_printf(ms, ", built by NDK %.64s (%.64s)",
+			if (elf_printf(ms, ", built by NDK %.64s (%.64s)",
 			    &nbuf[doff + 4], &nbuf[doff + 4 + 64]) == -1)
 				return -1;
 		}
@@ -735,13 +749,13 @@ do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		memcpy(&desc, &nbuf[doff], sizeof(desc));
 		desc = elf_getu32(swap, desc);
 
-		if (desc && file_printf(ms, ", PaX: ") == -1)
+		if (desc && elf_printf(ms, ", PaX: ") == -1)
 			return -1;
 
 		for (i = 0; i < __arraycount(pax); i++) {
 			if (((1 << CAST(int, i)) & desc) == 0)
 				continue;
-			if (file_printf(ms, "%s%s", did++ ? "," : "",
+			if (elf_printf(ms, "%s%s", did++ ? "," : "",
 			    pax[i]) == -1)
 				return -1;
 		}
@@ -774,13 +788,13 @@ do_memtag_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 		memcpy(&desc, &nbuf[doff], sizeof(desc));
 		desc = elf_getu32(swap, desc);
 
-		if (desc && file_printf(ms, ", Android Memtag: ") == -1)
+		if (desc && elf_printf(ms, ", Android Memtag: ") == -1)
 			return -1;
 
 		for (i = 0; i < __arraycount(memtag); i++) {
 			if (((1 << CAST(int, i)) & desc) == 0)
 				continue;
-			if (file_printf(ms, "%s%s", did++ ? "," : "",
+			if (elf_printf(ms, "%s%s", did++ ? "," : "",
 			    memtag[i]) == -1)
 				return -1;
 		}
@@ -827,7 +841,7 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 	}
 
 	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
-		if (file_printf(ms, ", %s-style", os_style_names[os_style])
+		if (elf_printf(ms, ", %s-style", os_style_names[os_style])
 		    == -1)
 			return -1;
 		*flags |= FLAGS_DID_CORE_STYLE;
@@ -842,7 +856,7 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 			memset(&pi, 0, sizeof(pi));
 			memcpy(&pi, nbuf + doff, MIN(descsz, sizeof(pi)));
 
-			if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, "
+			if (elf_printf(ms, ", from '%.31s', pid=%u, uid=%u, "
 			    "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)",
 			    file_printable(ms, sbuf, sizeof(sbuf),
 			    RCAST(char *, pi.cpi_name), sizeof(pi.cpi_name)),
@@ -868,12 +882,12 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 				argoff = 4 + 4 + 17;
 			else
 				argoff = 4 + 4 + 8 + 17;
-			if (file_printf(ms, ", from '%.80s'", nbuf + doff +
+			if (elf_printf(ms, ", from '%.80s'", nbuf + doff +
 			    argoff) == -1)
 				return -1;
 			pidoff = argoff + 81 + 2;
 			if (doff + pidoff + 4 <= size) {
-				if (file_printf(ms, ", pid=%u",
+				if (elf_printf(ms, ", pid=%u",
 				    elf_getu32(swap, *RCAST(uint32_t *, (nbuf +
 				    doff + pidoff)))) == -1)
 					return -1;
@@ -982,7 +996,7 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 				 */
 				while (cp > cname && isspace(cp[-1]))
 					cp--;
-				if (file_printf(ms, ", from '%s'",
+				if (elf_printf(ms, ", from '%s'",
 				    file_copystr(buf, sizeof(buf),
 				    CAST(size_t, cp - cname),
 				    RCAST(char *, cname))) == -1)
@@ -1014,7 +1028,7 @@ get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
 	for ( ; num; num--) {
 		if (pread(fd, xph_addr, xph_sizeof, off) <
 		    CAST(ssize_t, xph_sizeof)) {
-			if (file_printf(ms,
+			if (elf_printf(ms,
 			    ", can't read elf program header at %jd",
 			    (intmax_t)off) == -1)
 				return -1;
@@ -1049,7 +1063,7 @@ get_string_on_virtaddr(struct magic_set *ms,
 	    fsize, virtaddr);
 	if (offset < 0 ||
 	    (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) {
-		(void)file_printf(ms, ", can't read elf string at %jd",
+		(void)elf_printf(ms, ", can't read elf string at %jd",
 		    (intmax_t)offset);
 		return 0;
 	}
@@ -1161,10 +1175,10 @@ do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
 			if (buflen == 0)
 				continue;
 
-			if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
+			if (elf_printf(ms, ", %s: '%s'", tag, buf) == -1)
 				return -1;
 		} else {
-			if (file_printf(ms, ", %s: %d", tag,
+			if (elf_printf(ms, ", %s: %d", tag,
 			    CAST(int, xauxv_val)) == -1)
 				return -1;
 		}
@@ -1251,13 +1265,13 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 	}
 
 	if (namesz & 0x80000000) {
-	    (void)file_printf(ms, ", bad note name size %#lx",
+	    (void)elf_printf(ms, ", bad note name size %#lx",
 		CAST(unsigned long, namesz));
 	    return 0;
 	}
 
 	if (descsz & 0x80000000) {
-		(void)file_printf(ms, ", bad note description size %#lx",
+		(void)elf_printf(ms, ", bad note description size %#lx",
 		    CAST(unsigned long, descsz));
 		return 0;
 	}
@@ -1341,7 +1355,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
 				return offset;
 			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
-			if (file_printf(ms, ", note=%u", xnh_type) == -1)
+			if (elf_printf(ms, ", note=%u", xnh_type) == -1)
 				return offset;
 			return offset;
 		}
@@ -1351,7 +1365,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 		str = RCAST(const char *, &nbuf[doff]);
 		descw = CAST(int, descsz);
 		*flags |= flag;
-		file_printf(ms, ", %s: %s", tag,
+		elf_printf(ms, ", %s: %s", tag,
 		    file_copystr(buf, sizeof(buf), descw, str));
 		return offset;
 	}
@@ -1429,12 +1443,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 		return 0;
 
 	if (num == 0) {
-		if (file_printf(ms, ", no section header") == -1)
+		if (elf_printf(ms, ", no section header") == -1)
 			return -1;
 		return 0;
 	}
 	if (size != xsh_sizeof) {
-		if (file_printf(ms, ", corrupted section header size") == -1)
+		if (elf_printf(ms, ", corrupted section header size") == -1)
 			return -1;
 		return 0;
 	}
@@ -1442,7 +1456,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 	/* Read offset of name section to be able to read section names later */
 	offs = CAST(off_t, (off + size * strtab));
 	if (pread(fd, xsh_addr, xsh_sizeof, offs) < CAST(ssize_t, xsh_sizeof)) {
-		if (file_printf(ms, ", missing section headers at %jd",
+		if (elf_printf(ms, ", missing section headers at %jd",
 		    (intmax_t)offs) == -1)
 			return -1;
 		return 0;
@@ -1450,7 +1464,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 	name_off = xsh_offset;
 
 	if (fsize != SIZE_UNKNOWN && fsize < name_off) {
-		if (file_printf(ms, ", too large section header offset %jd",
+		if (elf_printf(ms, ", too large section header offset %jd",
 		    (intmax_t)name_off) == -1)
 			return -1;
 		return 0;
@@ -1461,7 +1475,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 		offs = name_off + xsh_name;
 		if ((namesize = pread(fd, name, sizeof(name) - 1, offs))
 		    == -1) {
-			if (file_printf(ms, 
+			if (elf_printf(ms, 
 			    ", can't read name of elf section at %jd",
 			    (intmax_t)offs) == -1)
 				return -1;
@@ -1475,7 +1489,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 
 		if (pread(fd, xsh_addr, xsh_sizeof, off) <
 		    CAST(ssize_t, xsh_sizeof)) {
-			if (file_printf(ms, ", can't read elf section at %jd",
+			if (elf_printf(ms, ", can't read elf section at %jd",
 			    (intmax_t)off) == -1)
 				return -1;
 			return 0;
@@ -1504,7 +1518,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 		case SHT_NOTE:
 			if (CAST(uintmax_t, (xsh_size + xsh_offset)) >
 			    CAST(uintmax_t, fsize)) {
-				if (file_printf(ms,
+				if (elf_printf(ms,
 				    ", note offset/size %#" INTMAX_T_FORMAT
 				    "x+%#" INTMAX_T_FORMAT "x exceeds"
 				    " file size %#" INTMAX_T_FORMAT "x",
@@ -1529,7 +1543,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 			if (pread(fd, nbuf, xsh_size, offs) <
 			    CAST(ssize_t, xsh_size)) {
 				free(nbuf);
-				if (file_printf(ms,
+				if (elf_printf(ms,
 				    ", can't read elf note at %jd",
 				    (intmax_t)offs) == -1)
 					return -1;
@@ -1591,7 +1605,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 					p += 4;
 					len = getu32(swap, len);
 					if (memcmp("gnu", p, 3) != 0) {
-					    if (file_printf(ms,
+					    if (elf_printf(ms,
 						", unknown capability %.3s", p)
 						== -1)
 						return -1;
@@ -1603,7 +1617,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 					p += 4;
 					len = getu32(swap, len);
 					if (tag != 1) {
-					    if (file_printf(ms, ", unknown gnu"
+					    if (elf_printf(ms, ", unknown gnu"
 						" capability tag %d", tag)
 						== -1)
 						return -1;
@@ -1624,7 +1638,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 					cap_sf1 |= xcap_val;
 					break;
 				default:
-					if (file_printf(ms,
+					if (elf_printf(ms,
 					    ", with unknown capability "
 					    "%#" INT64_T_FORMAT "x = %#"
 					    INT64_T_FORMAT "x",
@@ -1633,7 +1647,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 					    == -1)
 						return -1;
 					if (nbadcap++ > 2)
-						coff = xsh_size;
+						goto skip;
 					break;
 				}
 			}
@@ -1645,10 +1659,10 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 	}
 
 	if (has_debug_info) {
-		if (file_printf(ms, ", with debug_info") == -1)
+		if (elf_printf(ms, ", with debug_info") == -1)
 			return -1;
 	}
-	if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
+	if (elf_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
 		return -1;
 	if (cap_hw1) {
 		const cap_desc_t *cdp;
@@ -1667,12 +1681,12 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 			cdp = NULL;
 			break;
 		}
-		if (file_printf(ms, ", uses") == -1)
+		if (elf_printf(ms, ", uses") == -1)
 			return -1;
 		if (cdp) {
 			while (cdp->cd_name) {
 				if (cap_hw1 & cdp->cd_mask) {
-					if (file_printf(ms,
+					if (elf_printf(ms,
 					    " %s", cdp->cd_name) == -1)
 						return -1;
 					cap_hw1 &= ~cdp->cd_mask;
@@ -1680,13 +1694,13 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 				++cdp;
 			}
 			if (cap_hw1)
-				if (file_printf(ms,
+				if (elf_printf(ms,
 				    " unknown hardware capability %#"
 				    INT64_T_FORMAT "x",
 				    CAST(unsigned long long, cap_hw1)) == -1)
 					return -1;
 		} else {
-			if (file_printf(ms,
+			if (elf_printf(ms,
 			    " hardware capability %#" INT64_T_FORMAT "x",
 			    CAST(unsigned long long, cap_hw1)) == -1)
 				return -1;
@@ -1694,7 +1708,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 	}
 	if (cap_sf1) {
 		if (cap_sf1 & SF1_SUNW_FPUSED) {
-			if (file_printf(ms,
+			if (elf_printf(ms,
 			    (cap_sf1 & SF1_SUNW_FPKNWN)
 			    ? ", uses frame pointer"
 			    : ", not known to use frame pointer") == -1)
@@ -1702,7 +1716,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
 		}
 		cap_sf1 &= ~SF1_SUNW_MASK;
 		if (cap_sf1)
-			if (file_printf(ms,
+			if (elf_printf(ms,
 			    ", with unknown software capability %#"
 			    INT64_T_FORMAT "x",
 			    CAST(unsigned long long, cap_sf1)) == -1)
@@ -1724,20 +1738,20 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 {
 	Elf32_Phdr ph32;
 	Elf64_Phdr ph64;
-	const char *linking_style;
+	const char *str;
 	unsigned char nbuf[NBUFSIZE];
-	char interp[128];
+	char interp[NBUFSIZE];
 	ssize_t bufsize;
 	size_t offset, align, need = 0;
 	int pie = 0, dynamic = 0;
 
 	if (num == 0) {
-		if (file_printf(ms, ", no program header") == -1)
+		if (elf_printf(ms, ", no program header") == -1)
 			return -1;
 		return 0;
 	}
 	if (size != xph_sizeof) {
-		if (file_printf(ms, ", corrupted program header size") == -1)
+		if (elf_printf(ms, ", corrupted program header size") == -1)
 			return -1;
 		return 0;
 	}
@@ -1747,7 +1761,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 		int doread;
 		if (pread(fd, xph_addr, xph_sizeof, off) <
 		    CAST(ssize_t, xph_sizeof)) {
-			if (file_printf(ms,
+			if (elf_printf(ms,
 			    ", can't read elf program headers at %jd",
 			    (intmax_t)off) == -1)
 				return -1;
@@ -1768,7 +1782,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 				continue;
 			if (((align = xph_align) & 0x80000000UL) != 0 ||
 			    align < 4) {
-				if (file_printf(ms,
+				if (elf_printf(ms,
 				    ", invalid note alignment %#lx",
 				    CAST(unsigned long, align)) == -1)
 					return -1;
@@ -1793,7 +1807,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 			off_t offs = xph_offset;
 			bufsize = pread(fd, nbuf, len, offs);
 			if (bufsize == -1) {
-				if (file_printf(ms,
+				if (elf_printf(ms,
 				    ", can't read section at %jd",
 				    (intmax_t)offs) == -1)
 					return -1;
@@ -1817,8 +1831,6 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 				if (offset == 0)
 					break;
 			}
-			if (ms->flags & MAGIC_MIME)
-				continue;
 			break;
 
 		case PT_INTERP:
@@ -1827,9 +1839,10 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 				continue;
 			if (bufsize && nbuf[0]) {
 				nbuf[bufsize - 1] = '\0';
-				memcpy(interp, nbuf, CAST(size_t, bufsize));
+				str = CAST(const char *, nbuf);
 			} else
-				strlcpy(interp, "*empty*", sizeof(interp));
+				str = "*empty*";
+			strlcpy(interp, str, sizeof(interp));
 			break;
 		case PT_NOTE:
 			if (ms->flags & MAGIC_MIME)
@@ -1859,17 +1872,17 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
 		return 0;
 	if (dynamic) {
 		if (pie && need == 0)
-			linking_style = "static-pie";
+			str = "static-pie";
 		else
-			linking_style = "dynamically";
+			str = "dynamically";
 	} else {
-		linking_style = "statically";
+		str = "statically";
 	}
-	if (file_printf(ms, ", %s linked", linking_style) == -1)
+	if (elf_printf(ms, ", %s linked", str) == -1)
 		return -1;
 	if (interp[0])
-		if (file_printf(ms, ", interpreter %s", file_printable(ms,
-		    CAST(char *, nbuf), sizeof(nbuf),
+		if (elf_printf(ms, ", interpreter %s", file_printable(ms,
+		    RCAST(char *, nbuf), sizeof(nbuf),
 		    interp, sizeof(interp))) == -1)
 			return -1;
 	return 0;
@@ -1956,7 +1969,7 @@ file_tryelf(struct magic_set *ms, const struct buffer *b)
 #define elfhdr elf64hdr
 #include "elfclass.h"
 	default:
-	    if (file_printf(ms, ", unknown class %d", clazz) == -1)
+	    if (elf_printf(ms, ", unknown class %d", clazz) == -1)
 		    return -1;
 	    break;
 	}

+ 14 - 5
src/seccomp.c

@@ -27,15 +27,16 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: seccomp.c,v 1.29 2024/09/29 16:49:25 christos Exp $")
+FILE_RCSID("@(#)$File: seccomp.c,v 1.36 2026/02/06 14:04:20 christos Exp $")
 #endif	/* lint */
 
 #if HAVE_LIBSECCOMP
 #include <seccomp.h> /* libseccomp */
 #include <sys/prctl.h> /* prctl */
-#include <sys/ioctl.h>
 #include <sys/socket.h>
-#include <termios.h>
+// See: https://sourceware.org/bugzilla/show_bug.cgi?id=32806
+#include <asm/termbits.h>
+#include <sys/ioctl.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -103,6 +104,11 @@ enable_sandbox(void)
 #ifdef __NR_getdents64
 	ALLOW_RULE(getdents64);
 #endif
+	ALLOW_RULE(getpid);	// Used by glibc in file_pipe2file()
+	ALLOW_RULE(getrandom);	// Used by glibc in file_pipe2file()
+#ifdef __NR_getcwd
+	ALLOW_RULE(getcwd);	// GCONV_PATH=
+#endif
 #ifdef FIONREAD
 	// called in src/compress.c under sread
 	ALLOW_IOCTL_RULE(FIONREAD);
@@ -115,6 +121,10 @@ enable_sandbox(void)
 	// glibc may call ioctl TCGETS on stdout on physical terminal
 	ALLOW_IOCTL_RULE(TCGETS);
 #endif
+#ifdef TCGETS2
+	// glibc may call ioctl TCGETS2 on stdout on physical terminal
+	ALLOW_IOCTL_RULE(TCGETS2);
+#endif
 	ALLOW_RULE(lseek);
  	ALLOW_RULE(_llseek);
 	ALLOW_RULE(lstat);
@@ -136,6 +146,7 @@ enable_sandbox(void)
 #ifdef __NR_readlinkat
 	ALLOW_RULE(readlinkat);
 #endif
+	ALLOW_RULE(rseq);	// Used by glibc to randomize malloc
 	ALLOW_RULE(rt_sigaction);
 	ALLOW_RULE(rt_sigprocmask);
 	ALLOW_RULE(rt_sigreturn);
@@ -145,8 +156,6 @@ enable_sandbox(void)
 	ALLOW_RULE(stat64);
 	ALLOW_RULE(sysinfo);
 	ALLOW_RULE(umask);	// Used in file_pipe2file()
-	ALLOW_RULE(getpid);	// Used by glibc in file_pipe2file()
-	ALLOW_RULE(getrandom);	// Used by glibc in file_pipe2file()
 	ALLOW_RULE(unlink);
 	ALLOW_RULE(utimes);
 	ALLOW_RULE(write);

+ 61 - 21
src/softmagic.c

@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef	lint
-FILE_RCSID("@(#)$File: softmagic.c,v 1.350 2024/11/27 15:37:00 christos Exp $")
+FILE_RCSID("@(#)$File: softmagic.c,v 1.359 2025/06/08 14:42:11 christos Exp $")
 #endif	/* lint */
 
 #include "magic.h"
@@ -414,6 +414,7 @@ flush:
 					*need_separator = 1;
 					*printed_something = 1;
 					*returnval = 1;
+					*firstline = 0;
 					return e;
 				}
 				if (*m->desc) {
@@ -1042,11 +1043,28 @@ cvt_flip(int type, int flip)
 		return FILE_LEDOUBLE;
 	case FILE_LEDOUBLE:
 		return FILE_BEDOUBLE;
+	case FILE_BEMSDOSDATE:
+		return FILE_LEMSDOSDATE;
+	case FILE_LEMSDOSDATE:
+		return FILE_BEMSDOSDATE;
+	case FILE_BEMSDOSTIME:
+		return FILE_LEMSDOSTIME;
+	case FILE_LEMSDOSTIME:
+		return FILE_BEMSDOSTIME;
 	default:
 		return type;
 	}
 }
-#define DO_CVT(fld, type) \
+
+/* X86 INT_MIN / -1 traps */
+#define CHECKOVFL(type, a, b, size, sign) \
+	if (size == 32 && sign && CAST(type, a) == CAST(type, 0x80000000) \
+	    && CAST(type, b) == CAST(type, -1)) \
+		return -1; \
+	if (size == 64 && sign && CAST(type, a) == CAST(type, 0x8000000000000000LL) \
+	    && CAST(type, b) == CAST(type, -1)) \
+		return -1
+#define DO_CVT1(fld, type, size, sign) \
 	if (m->num_mask) \
 		switch (m->mask_op & FILE_OPS_MASK) { \
 		case FILE_OPAND: \
@@ -1068,11 +1086,13 @@ cvt_flip(int type, int flip)
 			p->fld *= CAST(type, m->num_mask); \
 			break; \
 		case FILE_OPDIVIDE: \
+			CHECKOVFL(type, p->fld, m->num_mask, size, sign); \
 			if (CAST(type, m->num_mask) == 0) \
 				return -1; \
 			p->fld /= CAST(type, m->num_mask); \
 			break; \
 		case FILE_OPMODULO: \
+			CHECKOVFL(type, p->fld, m->num_mask, size, sign); \
 			if (CAST(type, m->num_mask) == 0) \
 				return -1; \
 			p->fld %= CAST(type, m->num_mask); \
@@ -1081,31 +1101,38 @@ cvt_flip(int type, int flip)
 	if (m->mask_op & FILE_OPINVERSE) \
 		p->fld = ~p->fld \
 
-file_private int
+#define DO_CVT(m, fld, size) \
+	if ((m)->flag & UNSIGNED) { \
+		DO_CVT1(fld, uint##size##_t, size, 0); \
+	} else { \
+		DO_CVT1(s##fld, int##size##_t, size, 1); \
+	}
+
+file_no_overflow file_private int
 cvt_8(union VALUETYPE *p, const struct magic *m)
 {
-	DO_CVT(b, uint8_t);
+	DO_CVT(m, b, 8);
 	return 0;
 }
 
-file_private int
+file_no_overflow file_private int
 cvt_16(union VALUETYPE *p, const struct magic *m)
 {
-	DO_CVT(h, uint16_t);
+	DO_CVT(m, h, 16);
 	return 0;
 }
 
-file_private int
+file_no_overflow file_private int
 cvt_32(union VALUETYPE *p, const struct magic *m)
 {
-	DO_CVT(l, uint32_t);
+	DO_CVT(m, l, 32);
 	return 0;
 }
 
-file_private int
+file_no_overflow file_private int
 cvt_64(union VALUETYPE *p, const struct magic *m)
 {
-	DO_CVT(q, uint64_t);
+	DO_CVT(m, q, 64);
 	return 0;
 }
 
@@ -1159,11 +1186,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip)
 		return 1;
 	case FILE_SHORT:
 	case FILE_MSDOSDATE:
-	case FILE_LEMSDOSDATE:
-	case FILE_BEMSDOSDATE:
 	case FILE_MSDOSTIME:
-	case FILE_LEMSDOSTIME:
-	case FILE_BEMSDOSTIME:
 		if (cvt_16(p, m) == -1)
 			goto out;
 		return 1;
@@ -1217,6 +1240,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip)
 		return 1;
 	}
 	case FILE_BESHORT:
+	case FILE_BEMSDOSDATE:
+	case FILE_BEMSDOSTIME:
 		p->h = CAST(short, BE16(p->hs));
 		if (cvt_16(p, m) == -1)
 			goto out;
@@ -1237,6 +1262,8 @@ mconvert(struct magic_set *ms, struct magic *m, int flip)
 			goto out;
 		return 1;
 	case FILE_LESHORT:
+	case FILE_LEMSDOSDATE:
+	case FILE_LEMSDOSTIME:
 		p->h = CAST(short, LE16(p->hs));
 		if (cvt_16(p, m) == -1)
 			goto out;
@@ -1305,7 +1332,7 @@ mconvert(struct magic_set *ms, struct magic *m, int flip)
 		return 0;
 	}
 out:
-	file_magerror(ms, "zerodivide in mconvert()");
+	file_magerror(ms, "zerodivide/overflow/underflow in mconvert()");
 	return 0;
 }
 
@@ -1534,10 +1561,16 @@ msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
 			    "u at level %u", o, cont_level);
 			return -1;
 		}
-		if (CAST(size_t, m->offset) > b->elen)
-			return -1;
-		buffer_init(bb, -1, NULL, b->ebuf, b->elen);
-		ms->eoffset = ms->offset = CAST(int32_t, b->elen - m->offset);
+		if (b->fd == -1) {
+			ms->eoffset = ms->offset =
+			    CAST(int32_t, b->flen - m->offset);
+		} else {
+			if (CAST(size_t, m->offset) > b->elen)
+				return -1;
+			buffer_init(bb, -1, NULL, b->ebuf, b->elen);
+			ms->eoffset = ms->offset =
+			    CAST(int32_t, b->elen - m->offset);
+		}
 	} else {
 		offset = m->offset;
 		if ((m->flag & OFFPOSITIVE) || cont_level == 0) {
@@ -1547,7 +1580,8 @@ normal:
 			ms->offset = offset;
 			ms->eoffset = 0;
 		} else {
-			ms->offset = ms->eoffset + offset;
+			if (b->fd != -1)
+				ms->offset = ms->eoffset + offset;
 		}
 	}
 	if ((ms->flags & MAGIC_DEBUG) != 0) {
@@ -1966,7 +2000,7 @@ mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
 		    *need_separator = oneed_separator;
 		ms->offset = offset;
 		ms->eoffset = eoffset;
-		return rv || *found_match;
+		return rv ? rv : *found_match;
 
 	case FILE_NAME:
 		if (ms->flags & MAGIC_NODESC)
@@ -2484,6 +2518,8 @@ file_private int
 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
 {
 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
+		if (!firstline && !(ms->flags & MAGIC_CONTINUE))
+			return 1;
 		if (print_sep(ms, firstline) == -1)
 			return -1;
 		if (file_printf(ms, "%.8s", m->apple) == -1)
@@ -2491,6 +2527,8 @@ handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
 		return 1;
 	}
 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
+		if (!firstline && !(ms->flags & MAGIC_CONTINUE))
+			return 1;
 		if (print_sep(ms, firstline) == -1)
 			return -1;
 		if (file_printf(ms, "%s", m->ext) == -1)
@@ -2500,6 +2538,8 @@ handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
 		char buf[1024];
 		const char *p;
+		if (!firstline && !(ms->flags & MAGIC_CONTINUE))
+			return 1;
 		if (print_sep(ms, firstline) == -1)
 			return -1;
 		if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)

+ 26 - 1
tests/Makefile.am

@@ -13,6 +13,31 @@ bcachefs.result \
 bcachefs.testfile \
 bcachefs2.result \
 bcachefs2.testfile \
+bgcode.result \
+bgcode.testfile \
+cl8m8ocofedso.result \
+cl8m8ocofedso.testfile \
+cmd1.result \
+cmd1.testfile \
+cmd2.result \
+cmd2.testfile \
+cmd3.result \
+cmd3.testfile \
+cmd4.result \
+cmd4.testfile \
+CVE-2014-1943.result \
+CVE-2014-1943.testfile \
+dsd64-dff.result \
+dsd64-dff.testfile \
+dsd64-dsf.result \
+dsd64-dsf.testfile \
+efi-signature-list-sha256.result \
+efi-signature-list-sha256.testfile \
+escapevel.result \
+escapevel.testfile \
+ext4.result \
+ext4.testfile \
+fit-map-data.result \
 cl8m8ocofedso.result \
 cl8m8ocofedso.testfile \
 cmd1.result \
@@ -193,7 +218,7 @@ check-local:
 				if [ -z "$$m" ]; then \
 					m=$$j; \
 				else \
-					m=$$m:$$j; \
+					m=$$m${PATH_SEPARATOR}$$j; \
 				fi \
 			fi \
 		done; \

+ 26 - 1
tests/Makefile.in

@@ -307,6 +307,31 @@ bcachefs.result \
 bcachefs.testfile \
 bcachefs2.result \
 bcachefs2.testfile \
+bgcode.result \
+bgcode.testfile \
+cl8m8ocofedso.result \
+cl8m8ocofedso.testfile \
+cmd1.result \
+cmd1.testfile \
+cmd2.result \
+cmd2.testfile \
+cmd3.result \
+cmd3.testfile \
+cmd4.result \
+cmd4.testfile \
+CVE-2014-1943.result \
+CVE-2014-1943.testfile \
+dsd64-dff.result \
+dsd64-dff.testfile \
+dsd64-dsf.result \
+dsd64-dsf.testfile \
+efi-signature-list-sha256.result \
+efi-signature-list-sha256.testfile \
+escapevel.result \
+escapevel.testfile \
+ext4.result \
+ext4.testfile \
+fit-map-data.result \
 cl8m8ocofedso.result \
 cl8m8ocofedso.testfile \
 cmd1.result \
@@ -801,7 +826,7 @@ check-local:
 				if [ -z "$$m" ]; then \
 					m=$$j; \
 				else \
-					m=$$m:$$j; \
+					m=$$m${PATH_SEPARATOR}$$j; \
 				fi \
 			fi \
 		done; \

+ 1 - 1
tests/arj.result

@@ -1 +1 @@
-ARJ archive data, v11, slash-switched, created 5 1980+48, original name: example_m0.arj, os: Unix
+ARJ archive data, v11, slash-switched, created Jan 05 2028 07:31:08, modified Jan 05 2028 07:31:08, original name: example_m0.arj, os: Unix

+ 1 - 0
tests/bgcode.result

@@ -0,0 +1 @@
+Binary G-code Version 1, CRC32 checksum

BIN
tests/bgcode.testfile


+ 1 - 0
tests/efi-signature-list-sha256.result

@@ -0,0 +1 @@
+EFI Signature List, SHA256, total size: 76 bytes

BIN
tests/efi-signature-list-sha256.testfile