added AVIF and HEIF support

This commit is contained in:
Mathias Panzenböck 2024-04-20 18:57:31 +02:00
parent 23e0b8fdc8
commit 16c70d299d
8 changed files with 249 additions and 145 deletions

View File

@ -29,6 +29,7 @@ OBJ=\
$(BUILDDIR)/bmp.o \
$(BUILDDIR)/png.o \
$(BUILDDIR)/jpg.o \
$(BUILDDIR)/avif.o \
$(BUILDDIR)/gif.o \
$(BUILDDIR)/mpeg.o \
$(BUILDDIR)/text.o
@ -38,6 +39,13 @@ CFLAGS+= -Wall -Werror -Wextra -std=gnu99 -O2 -g $(INCLUDE) $(LIBDIRS) -D_FILE_O
WINDOWS_LIBS=-lws2_32
APPNAME=mediaextract
BIN=$(BUILDDIR)/$(APPNAME)
RELEASE=0
ifeq ($(RELEASE),1)
CFLAGS+=-O3
else
CFLAGS+=-g
endif
ifeq ($(TARGET),win32)
PLATFORM=windows
@ -105,6 +113,7 @@ $(BUILDDIR)/mediaextract.o: src/mediaextract.c \
src/bmp.h \
src/png.h \
src/jpg.h \
src/avif.h \
src/gif.h \
src/mpeg.h \
src/text.h
@ -116,80 +125,17 @@ $(BUILDDIR)/mediaextract_$(PLATFORM).o: src/mediaextract_$(PLATFORM).c src/media
$(BUILDDIR)/formatstring.o: src/formatstring.c src/formatstring.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/riff.o: src/riff.c src/mediaextract.h src/riff.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/aiff.o: src/aiff.c src/mediaextract.h src/aiff.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/ogg.o: src/ogg.c src/mediaextract.h src/ogg.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/mpg123.o: src/mpg123.c src/mediaextract.h src/mpg123.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/mp4.o: src/mp4.c src/mediaextract.h src/mp4.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/id3.o: src/id3.c src/mediaextract.h src/id3.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/midi.o: src/midi.c src/mediaextract.h src/midi.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/xmidi.o: src/xmidi.c src/mediaextract.h src/xmidi.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/mod.o: src/mod.c src/mediaextract.h src/mod.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/s3m.o: src/s3m.c src/mediaextract.h src/s3m.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/xm.o: src/xm.c src/mediaextract.h src/xm.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/it.o: src/it.c src/mediaextract.h src/it.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/asf.o: src/asf.c src/mediaextract.h src/asf.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/bink.o: src/bink.c src/mediaextract.h src/bink.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/au.o: src/au.c src/mediaextract.h src/au.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/smk.o: src/smk.c src/mediaextract.h src/smk.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/bmp.o: src/bmp.c src/mediaextract.h src/bmp.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/png.o: src/png.c src/mediaextract.h src/png.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/jpg.o: src/jpg.c src/mediaextract.h src/jpg.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/gif.o: src/gif.c src/mediaextract.h src/gif.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/mpeg.o: src/mpeg.c src/mediaextract.h src/mpeg.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
$(BUILDDIR)/text.o: src/text.c src/mediaextract.h src/text.h
$(BUILDDIR)/%.o: src/%.c src/mediaextract.h src/riff.h
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
ifeq ($(PLATFORM),posix)
install: $(PREFIX)/bin/$(APPNAME) $(PREFIX)/share/man/man1/$(MANPAGE)
$(BUILDDIR)/$(MANPAGE):src/ManPageIncludeFile
$(BUILDDIR)/$(MANPAGE): src/ManPageIncludeFile
help2man $(BIN) --no-discard-stderr --no-info -n "extracts media files that are embedded within other files" -S "Mathias Panzenböck" -i src/ManPageIncludeFile|sed '/the default set of formats/s/^/.TP\n/'|sed '/the default set of formats/{N;s/.TP//}'|sed -r '/([)]|files)$ /a .TP' >$(BUILDDIR)/$(APPNAME).1
gzip -kf $(BUILDDIR)/$(APPNAME).1
$(PREFIX)/share/man/man1/$(MANPAGE):$(BUILDDIR)/$(APPNAME).1
$(PREFIX)/share/man/man1/$(MANPAGE): $(BUILDDIR)/$(APPNAME).1
mkdir -p "$(PREFIX)/share/man/man1/"
install $(BUILDDIR)/$(MANPAGE) "$@"

View File

@ -14,11 +14,10 @@ for target in linux32 linux64 win32 win64; do
if [[ -d "$builddir" ]]; then
mkdir "$pkg/$builddir"
if [[ -f "$builddir/mediaextract" ]]; then
cp "$builddir/mediaextract" "$pkg/$builddir"
elif [ -f "$builddir/mediaextract.exe" ]; then
cp "$builddir/mediaextract.exe" "$pkg/$builddir"
fi
suffix=
case "$target" in win*) suffix=.exe;; esac
cp "$builddir/mediaextract$suffix" "$pkg/$builddir"
fi
done
zip -r9 "$pkg.zip" "$pkg"

107
src/avif.c Normal file
View File

@ -0,0 +1,107 @@
/* Copyright (c) 2024 Mathias Panzenböck
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "avif.h"
#include <string.h>
#include <stdint.h>
#define READ_U32_BE(PTR) (((PTR)[0] << 24) | ((PTR)[1] << 16) | ((PTR)[2] << 8) | (PTR)[3])
enum BoxType {
META = 1 << 0,
MOOV = 1 << 1,
MDAT = 1 << 2,
};
int avif_isfile(const uint8_t *data, size_t input_len, file_format formats, struct file_info *info_ptr)
{
if (input_len <= AVIF_HEADER_SIZE)
return 0;
uint32_t box_size = READ_U32_BE(data);
const char *ext = NULL;
if (box_size < AVIF_HEADER_SIZE || memcmp(data + 4, "ftyp", 4) != 0)
return 0;
if ((formats & AVIF) && memcmp(data + 8, "avif", 4) == 0)
{
ext = "avif";
}
else if ((formats & HEIF) && memcmp(data + 8, "heic", 4) == 0)
{
ext = "heif";
}
else
{
return 0;
}
int boxes = 0;
size_t length = (size_t) box_size;
for (;;)
{
const uint8_t *ptr = data + length;
box_size = READ_U32_BE(ptr);
if (box_size < 8 || (size_t) box_size > SIZE_MAX - length)
{
if (boxes & (MOOV | MDAT))
break;
return 0;
}
ptr += 4;
if (memcmp(ptr, "meta", 4) == 0)
{
boxes |= META;
}
else if (memcmp(ptr, "mdat", 4) == 0)
{
boxes |= MDAT;
}
else if (memcmp(ptr, "moov", 4) == 0)
{
boxes |= MOOV;
}
else if (boxes & (MOOV | MDAT))
{
break;
}
else{
return 0;
}
length += (size_t) box_size;
}
if (info_ptr)
{
info_ptr->length = length;
info_ptr->ext = ext;
}
return 1;
}

33
src/avif.h Normal file
View File

@ -0,0 +1,33 @@
/* Copyright (c) 2024 Mathias Panzenböck
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MEDIAEXTRACT_AVIF_H__
#define MEDIAEXTRACT_AVIF_H__
#pragma once
#include "mediaextract.h"
#define AVIF_HEADER_SIZE 12
#define AVIF_MIN_SIZE (AVIF_HEADER_SIZE + 8)
int avif_isfile(const uint8_t *data, size_t input_len, file_format formats, struct file_info *info_ptr);
#endif /* MEDIAEXTRACT_AVIF_H__ */

View File

@ -61,6 +61,7 @@
#include "bmp.h"
#include "png.h"
#include "jpg.h"
#include "avif.h"
#include "gif.h"
#include "mpeg.h"
#include "text.h"
@ -81,17 +82,17 @@
#define SEE_HELP "See --help for usage information.\n"
#define TRACKER_FORMATS (MOD | S3M | IT | XM)
#define AUDIO_FORMATS (OGG | RIFF | AIFF | MPG123 | MP4 | ID3v2 | MIDI | XMIDI | MOD | S3M | IT | XM | ASF | AU)
#define AUDIO_FORMATS (OGG | RIFF | AIFF | MPG123 | MP4 | ID3v2 | MIDI | XMIDI | TRACKER_FORMATS | ASF | AU)
#define VIDEO_FORMATS (MP4 | RIFF | ASF | BINK | SMK | MPEGPS | MPEGVS | MPEGTS)
#define MPEG_FORMATS (MPEG1 | MPEGPS | MPEGVS | ID3v2)
#define IMAGE_FORMATS (BMP | PNG | JPEG | GIF)
#define IMAGE_FORMATS (AVIF | HEIF | BMP | PNG | GIF | JPEG)
#define TEXT_FORMATS (UTF_8 | UTF_16LE | UTF_16BE | UTF_32LE | UTF_32BE)
#define ALL_FORMATS (OGG | RIFF | AIFF | MPG123 | MP4 | ID3v2 | MIDI | XMIDI | MOD | S3M | IT | XM | ASF | BINK | AU | SMK | BMP | PNG | JPEG | GIF | MPEG1 | MPEGPS | MPEGVS | MPEGTS | TEXT_FORMATS)
#define DEFAULT_FORMATS (OGG | RIFF | AIFF | MP4 | ID3v2 | MIDI | XMIDI | S3M | IT | XM | ASF | BINK | AU | SMK | BMP | PNG | JPEG | GIF | MPEG1 | MPEGPS | MPEGVS)
#define ALL_FORMATS (TRACKER_FORMATS | AUDIO_FORMATS | VIDEO_FORMATS | MPEG_FORMATS | IMAGE_FORMATS | TEXT_FORMATS | ASCII)
#define DEFAULT_FORMATS (OGG | RIFF | AIFF | MP4 | ID3v2 | MIDI | XMIDI | S3M | IT | XM | ASF | BINK | AU | SMK | BMP | PNG | JPEG | GIF | MPEG1 | MPEGPS | MPEGVS | AVIF | HEIF)
static int usage(int argc, char **argv);
static const char *basename(const char *path);
static int parse_formats(const char *sformats, int *formats);
static int parse_formats(const char *sformats, file_format *formats);
static int parse_size_p(const char *str, uint64_t *size);
static int parse_size(const char *str, size_t *size);
static int parse_offset(const char *str, uint64_t *size);
@ -172,18 +173,19 @@ static int usage(int argc, char **argv)
"\n"
" Supported formats:\n"
" all all supported formats\n"
" default the default set of formats (AIFF, ASF, AU, BINK, BMP,\n"
" GIF, ID3v2, IT, JPEG, MPEG 1, MPEG PS, MIDI, MP4, Ogg,\n"
" PNG, RIFF, S3M, SMK, XM, XMIDI)\n"
" default the default set of formats (AIFF, ASF, AU, AVIF, BINK,\n"
" BMP, GIF, HEIF, ID3v2, IT, JPEG, MPEG 1, MPEG PS,\n"
" MIDI, MP4, Ogg, PNG, RIFF, S3M, SMK, XM, XMIDI)\n"
" audio all audio files (AIFF, ASF, AU, ID3v2, IT, MIDI, MP4,\n"
" Ogg, RIFF, S3M, XM, XMIDI)\n"
" text all text files (ASCII, UTF-8, UTF-16LE, UTF-16BE,\n"
" UTF-32LE, UTF-32BE)\n"
" image all image files (BMP, PNG, JPEG, GIF)\n"
" image all image files (BMP, PNG, JPEG, GIF, AVIF, HEIF)\n"
" mpeg all safe mpeg files (MPEG 1, MPEG PS, ID3v2)\n"
" tracker all tracker files (MOD, S3M, IT, XM)\n"
" video all video files (ASF, BINK, MP4, RIFF, SMK)\n"
"\n"
" avif AVIF image files\n"
" aiff big-endian (Apple) wave files\n"
" ascii 7-bit ASCII files (only printable characters)\n"
" asf Advanced Systems Format files (also WMA and WMV)\n"
@ -191,6 +193,7 @@ static int usage(int argc, char **argv)
" bink BINK files\n"
" bmp Windows Bitmap files\n"
" gif Graphics Interchange Format files\n"
" heif HEIF images files\n"
" id3v2 MPEG layer 1/2/3 files with ID3v2 tags\n"
" it ImpulseTracker files\n"
" jpeg JPEG Interchange Format files\n"
@ -321,7 +324,7 @@ int write_file(const uint8_t *data, size_t length, const struct extract_options
int do_extract(const uint8_t *filedata, size_t filesize, const struct extract_options *options, size_t *numfilesptr, size_t *sumsizeptr)
{
const uint8_t *ptr = NULL, *end = NULL;
enum fileformat format = NONE;
file_format format = NONE;
size_t sumsize = 0;
size_t length = 0;
@ -539,11 +542,18 @@ int do_extract(const uint8_t *filedata, size_t filesize, const struct extract_op
if (formats & JPEG && IS_JPG_MAGIC(magic) && jpg_isfile(ptr, input_len, &length))
{
WRITE_FILE(ptr, length, "jpg");
WRITE_FILE(ptr, length, "jpeg");
ptr += length;
continue;
}
if (formats & (AVIF | HEIF) && input_len >= AVIF_MIN_SIZE && avif_isfile(ptr, input_len, formats, &info))
{
WRITE_FILE(ptr, info.length, info.ext);
ptr += info.length;
continue;
}
if (formats & BINK && IS_BINK_MAGIC(magic) && bink_isfile(ptr, input_len, &length))
{
WRITE_FILE(ptr, length, "bik");
@ -650,7 +660,7 @@ cleanup:
return success;
}
int parse_formats(const char *sformats, int *formats)
int parse_formats(const char *sformats, file_format *formats)
{
unsigned int parsed = NONE;
const char *start = sformats;
@ -743,6 +753,10 @@ int parse_formats(const char *sformats, int *formats)
{
mask = JPEG;
}
else if (strncasecmp("avif", start, len) == 0)
{
mask = AVIF;
}
else if (strncasecmp("mpeg1", start, len) == 0)
{
mask = MPEG1;
@ -1063,7 +1077,7 @@ int main(int argc, char **argv)
.filename = "{filename}_{offset}.{ext}",
.minsize = 0,
.maxsize = SIZE_MAX,
.length = (SIZE_MAX>>1),
.length = (SIZE_MAX >> 1),
.formats = DEFAULT_FORMATS,
.quiet = false,
.simulate = false

View File

@ -178,39 +178,44 @@
#endif
enum fileformat {
NONE = 0,
OGG = 1 << 0,
RIFF = 1 << 1,
AIFF = 1 << 2,
MPG123 = 1 << 3,
ID3v2 = 1 << 4,
MP4 = 1 << 5,
MIDI = 1 << 6,
XMIDI = 1 << 7,
MOD = 1 << 8,
S3M = 1 << 9,
IT = 1 << 10,
XM = 1 << 11,
ASF = 1 << 12,
BINK = 1 << 13,
AU = 1 << 14,
SMK = 1 << 15,
BMP = 1 << 16,
PNG = 1 << 17,
JPEG = 1 << 18,
GIF = 1 << 19,
MPEG1 = 1 << 20,
MPEGPS = 1 << 21,
MPEGVS = 1 << 22, // TODO
MPEGTS = 1 << 23, // TODO
ASCII = 1 << 24,
UTF_8 = 1 << 25,
UTF_16LE = 1 << 26,
UTF_16BE = 1 << 27,
UTF_32LE = 1 << 28,
UTF_32BE = 1 << 29
};
typedef uint64_t file_format;
#define NONE ((uint64_t) 0)
#define OGG ((uint64_t)1 << 0)
#define RIFF ((uint64_t)1 << 1)
#define AIFF ((uint64_t)1 << 2)
#define MPG123 ((uint64_t)1 << 3)
#define ID3v2 ((uint64_t)1 << 4)
#define MP4 ((uint64_t)1 << 5)
#define MIDI ((uint64_t)1 << 6)
#define XMIDI ((uint64_t)1 << 7)
#define MOD ((uint64_t)1 << 8)
#define S3M ((uint64_t)1 << 9)
#define IT ((uint64_t)1 << 10)
#define XM ((uint64_t)1 << 11)
#define ASF ((uint64_t)1 << 12)
#define BINK ((uint64_t)1 << 13)
#define AU ((uint64_t)1 << 14)
#define SMK ((uint64_t)1 << 15)
#define BMP ((uint64_t)1 << 16)
#define PNG ((uint64_t)1 << 17)
#define JPEG ((uint64_t)1 << 18)
#define GIF ((uint64_t)1 << 19)
#define MPEG1 ((uint64_t)1 << 20)
#define MPEGPS ((uint64_t)1 << 21)
#define MPEGVS ((uint64_t)1 << 22) // TODO
#define MPEGTS ((uint64_t)1 << 23)
#define ASCII ((uint64_t)1 << 24)
#define UTF_8 ((uint64_t)1 << 25)
#define UTF_16LE ((uint64_t)1 << 26)
#define UTF_16BE ((uint64_t)1 << 27)
#define UTF_32LE ((uint64_t)1 << 28)
#define UTF_32BE ((uint64_t)1 << 29)
#define AVIF ((uint64_t)1 << 30)
#define HEIF ((uint64_t)1 << 31)
// TODO: look into these formats:
// VTF, PSD, XCF, ICO, OpenEXR, PCX, JPEG 2000, TIFF
struct file_info {
size_t length;
@ -226,7 +231,7 @@ struct extract_options {
uint64_t offset;
size_t length;
size_t index;
int formats;
file_format formats;
bool quiet;
bool simulate;
};

View File

@ -47,7 +47,7 @@ static size_t mpeg_ispacket(const uint8_t *data, size_t input_len)
return length;
}
static size_t mpeg_ispack(const uint8_t *data, size_t input_len, enum fileformat *format)
static size_t mpeg_ispack(const uint8_t *data, size_t input_len, file_format *format)
{
if (input_len < 12 || MAGIC(data) != MPEG_MAGIC)
return 0;
@ -99,7 +99,7 @@ static size_t mpeg_ispack(const uint8_t *data, size_t input_len, enum fileformat
static size_t mpeg_ispacks(const uint8_t *data, size_t input_len, int formats)
{
enum fileformat format = NONE;
file_format format = NONE;
size_t length = mpeg_ispack(data, input_len, &format);
if (length == 0 || (format & formats) == 0)
@ -121,7 +121,7 @@ static size_t mpeg_ispacks(const uint8_t *data, size_t input_len, int formats)
break;
length = i - 2;
enum fileformat nextformat = NONE;
file_format nextformat = NONE;
size_t nextlen = mpeg_ispack(data + length, input_len - length, &nextformat);
if (nextlen == 0 || nextformat != format)

View File

@ -27,7 +27,7 @@
#define CHUNK_SPEC(metatype,c1,c2,c3,c4,body,required) { (metatype), CMAGIC(c1,c2,c3,c4), (body), (required) }
#define LIST(c1,c2,c3,c4,body,required) CHUNK_SPEC(CMAGIC('L','I','S','T'),c1,c2,c3,c4,body,required)
#define FORM(c1,c2,c3,c4,body,required) CHUNK_SPEC(CMAGIC('R','I','F','F'),c1,c2,c3,c4,body,required)
#define RIFF(c1,c2,c3,c4,body) FORM(c1,c2,c3,c4,body,1)
#define RIFF_FORM(c1,c2,c3,c4,body) FORM(c1,c2,c3,c4,body,1)
#define CHUNK(c1,c2,c3,c4,required) CHUNK_SPEC(0,c1,c2,c3,c4,0,required)
#define END { 0, 0, 0, 0 }
#define BODY(...) { __VA_ARGS__, END }
@ -241,29 +241,29 @@ static const struct riff_chunk_spec riff_webp_body[] = BODY(
CHUNK_SPEC_COUNT(riff_webp_body)))))))))))))))))))))
static const struct riff_file_spec riff_file_specs[] = {
{ RIFF('W','A','V','E', riff_wav_body ), "wav" },
{ RIFF('A','V','I',' ', riff_avi_body ), "avi" },
{ RIFF('A','C','O','N', riff_ani_body ), "ani" },
{ RIFF('R','M','I','D', 0 ), "rmi" },
{ RIFF('P','A','L',' ', riff_pal_body ), "pal" },
{ RIFF('R','D','I','B', 0 ), "rdi" },
{ RIFF('R','M','M','P', 0 ), "mmm" },
{ RIFF('D','M','A','P', riff_aud_body ), "aud" },
{ RIFF('D','M','B','D', riff_dmbd_body), "riff" },
{ RIFF('D','M','P','R', riff_dmpr_body), "cdm" },
{ RIFF('D','M','C','N', riff_dmcn_body), "riff" },
{ RIFF('D','S','B','C', riff_dsbc_body), "riff" },
{ RIFF('D','S','F','X', riff_dsfx_body), "riff" },
{ RIFF('D','M','S','C', riff_dmsc_body), "riff" },
{ RIFF('D','M','S','G', riff_sgt_body ), "sgt" },
{ RIFF('D','M','S','T', riff_sty_body ), "sty" },
{ RIFF('D','M','T','L', riff_dmtl_body), "riff" },
{ RIFF('D','M','T','G', riff_dmtg_body), "riff" },
{ RIFF('D','M','T','K', riff_dmtk_body), "riff" },
{ RIFF('D','M','B','T', riff_dmbt_body), "riff" },
{ RIFF('D','M','P','T', riff_dmpt_body), "riff" },
{ RIFF('W','E','B','P', riff_webp_body), "webp" },
{ RIFF('M','T','D','F', 0 ), "mtd" },
{ RIFF_FORM('W','A','V','E', riff_wav_body ), "wav" },
{ RIFF_FORM('A','V','I',' ', riff_avi_body ), "avi" },
{ RIFF_FORM('A','C','O','N', riff_ani_body ), "ani" },
{ RIFF_FORM('R','M','I','D', 0 ), "rmi" },
{ RIFF_FORM('P','A','L',' ', riff_pal_body ), "pal" },
{ RIFF_FORM('R','D','I','B', 0 ), "rdi" },
{ RIFF_FORM('R','M','M','P', 0 ), "mmm" },
{ RIFF_FORM('D','M','A','P', riff_aud_body ), "aud" },
{ RIFF_FORM('D','M','B','D', riff_dmbd_body), "riff" },
{ RIFF_FORM('D','M','P','R', riff_dmpr_body), "cdm" },
{ RIFF_FORM('D','M','C','N', riff_dmcn_body), "riff" },
{ RIFF_FORM('D','S','B','C', riff_dsbc_body), "riff" },
{ RIFF_FORM('D','S','F','X', riff_dsfx_body), "riff" },
{ RIFF_FORM('D','M','S','C', riff_dmsc_body), "riff" },
{ RIFF_FORM('D','M','S','G', riff_sgt_body ), "sgt" },
{ RIFF_FORM('D','M','S','T', riff_sty_body ), "sty" },
{ RIFF_FORM('D','M','T','L', riff_dmtl_body), "riff" },
{ RIFF_FORM('D','M','T','G', riff_dmtg_body), "riff" },
{ RIFF_FORM('D','M','T','K', riff_dmtk_body), "riff" },
{ RIFF_FORM('D','M','B','T', riff_dmbt_body), "riff" },
{ RIFF_FORM('D','M','P','T', riff_dmpt_body), "riff" },
{ RIFF_FORM('W','E','B','P', riff_webp_body), "webp" },
{ RIFF_FORM('M','T','D','F', 0 ), "mtd" },
{ END, 0 }
};