PNG support
This commit is contained in:
parent
834328808e
commit
afefa5d7b2
9
Makefile
9
Makefile
|
@ -24,7 +24,8 @@ OBJ=\
|
|||
$(BUILDDIR)/bink.o \
|
||||
$(BUILDDIR)/au.o \
|
||||
$(BUILDDIR)/smk.o \
|
||||
$(BUILDDIR)/bmp.o
|
||||
$(BUILDDIR)/bmp.o \
|
||||
$(BUILDDIR)/png.o
|
||||
CC=gcc
|
||||
LD=$(CC)
|
||||
COMMON_CFLAGS=-Wall -Werror -Wextra -std=gnu99 -O2 -g $(INCLUDE) $(LIBDIRS) -D_FILE_OFFSET_BITS=64
|
||||
|
@ -92,7 +93,8 @@ $(BUILDDIR)/audioextract.o: src/audioextract.c \
|
|||
src/bink.h \
|
||||
src/au.h \
|
||||
src/smk.h \
|
||||
src/bmp.h
|
||||
src/bmp.h \
|
||||
src/png.h
|
||||
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
|
||||
|
||||
$(BUILDDIR)/audioextract_$(PLATFORM).o: src/audioextract_$(PLATFORM).c src/audioextract.h
|
||||
|
@ -146,6 +148,9 @@ $(BUILDDIR)/smk.o: src/smk.c src/audioextract.h src/smk.h
|
|||
$(BUILDDIR)/bmp.o: src/bmp.c src/audioextract.h src/bmp.h
|
||||
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
|
||||
|
||||
$(BUILDDIR)/png.o: src/png.c src/audioextract.h src/png.h
|
||||
$(CC) $(CFLAGS) $< -o $@ -c $(LIBS)
|
||||
|
||||
ifeq ($(PLATFORM),posix)
|
||||
install: $(PREFIX)/bin/$(APPNAME)
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ files.
|
|||
mpg123 MPEG layer 1/2/3 files (MP1, MP2, MP3)
|
||||
mp4 MP4 files (M4A, M4V, 3GPP etc.)
|
||||
ogg Ogg files (Vorbis, Opus, Theora, etc.)
|
||||
png Portable Network Graphics file
|
||||
riff Resource Interchange File Format files (ANI, AVI, MMM,
|
||||
PAL, RDI, RMI, WAV)
|
||||
s3m ScreamTracker III files
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "au.h"
|
||||
#include "smk.h"
|
||||
#include "bmp.h"
|
||||
#include "png.h"
|
||||
|
||||
#if defined(__WINDOWS__) && !defined(__CYGWIN__)
|
||||
# ifdef _WIN64
|
||||
|
@ -48,27 +49,28 @@
|
|||
#define SEE_HELP "See --help for usage information.\n"
|
||||
|
||||
enum fileformat {
|
||||
NONE = 0x0,
|
||||
OGG = 0x1,
|
||||
RIFF = 0x2,
|
||||
AIFF = 0x4,
|
||||
MPG123 = 0x8,
|
||||
ID3v2 = 0x10,
|
||||
MP4 = 0x20,
|
||||
MIDI = 0x40,
|
||||
MOD = 0x80,
|
||||
S3M = 0x100,
|
||||
IT = 0x200,
|
||||
XM = 0x400,
|
||||
ASF = 0x800,
|
||||
BINK = 0x1000,
|
||||
AU = 0x2000,
|
||||
SMK = 0x4000,
|
||||
BMP = 0x8000
|
||||
NONE = 0x0,
|
||||
OGG = 0x1,
|
||||
RIFF = 0x2,
|
||||
AIFF = 0x4,
|
||||
MPG123 = 0x8,
|
||||
ID3v2 = 0x10,
|
||||
MP4 = 0x20,
|
||||
MIDI = 0x40,
|
||||
MOD = 0x80,
|
||||
S3M = 0x100,
|
||||
IT = 0x200,
|
||||
XM = 0x400,
|
||||
ASF = 0x800,
|
||||
BINK = 0x1000,
|
||||
AU = 0x2000,
|
||||
SMK = 0x4000,
|
||||
BMP = 0x8000,
|
||||
PNG = 0x10000
|
||||
};
|
||||
|
||||
#define ALL_FORMATS (OGG | RIFF | AIFF | MPG123 | MP4 | ID3v2 | MIDI | MOD | S3M | IT | XM | ASF | BINK | AU | SMK | BMP)
|
||||
#define DEFAULT_FORMATS (OGG | RIFF | AIFF | MP4 | ID3v2 | MIDI | S3M | IT | XM | ASF | BINK | AU | SMK | BMP)
|
||||
#define ALL_FORMATS (OGG | RIFF | AIFF | MPG123 | MP4 | ID3v2 | MIDI | MOD | S3M | IT | XM | ASF | BINK | AU | SMK | BMP | PNG)
|
||||
#define DEFAULT_FORMATS (OGG | RIFF | AIFF | MP4 | ID3v2 | MIDI | S3M | IT | XM | ASF | BINK | AU | SMK | BMP | PNG)
|
||||
#define TRACKER_FORMATS (MOD | S3M | IT | XM)
|
||||
|
||||
static int usage(int argc, char **argv);
|
||||
|
@ -154,6 +156,7 @@ static int usage(int argc, char **argv)
|
|||
" mpg123 MPEG layer 1/2/3 files (MP1, MP2, MP3)\n"
|
||||
" mp4 MP4 files (M4A, M4V, 3GPP etc.)\n"
|
||||
" ogg Ogg files (Vorbis, Opus, Theora, etc.)\n"
|
||||
" png Portable Network Graphics file\n"
|
||||
" riff Resource Interchange File Format files (ANI, AVI, MMM,\n"
|
||||
" PAL, RDI, RMI, WAV)\n"
|
||||
" s3m ScreamTracker III files\n"
|
||||
|
@ -425,6 +428,14 @@ int do_extract(const uint8_t *filedata, size_t filesize, const struct extract_op
|
|||
continue;
|
||||
}
|
||||
|
||||
if (magic == PNG_MAGIC) printf("has png magic!\n");
|
||||
if (formats & PNG && magic == PNG_MAGIC && png_isfile(ptr, input_len, &length))
|
||||
{
|
||||
WRITE_FILE(ptr, length, "png");
|
||||
ptr += length;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (formats & BINK && IS_BINK_MAGIC(magic) && bink_isfile(ptr, input_len, &length))
|
||||
{
|
||||
WRITE_FILE(ptr, length, "bik");
|
||||
|
@ -577,6 +588,10 @@ int parse_formats(const char *formats)
|
|||
{
|
||||
mask = BMP;
|
||||
}
|
||||
else if (strncasecmp("png", start, len) == 0)
|
||||
{
|
||||
mask = PNG;
|
||||
}
|
||||
else if (strncasecmp("tracker", start, len) == 0)
|
||||
{
|
||||
mask = TRACKER_FORMATS;
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
#include "png.h"
|
||||
|
||||
// See: http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html
|
||||
|
||||
#define IS_PNG_MAGIC_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
#define IS_PNG_CHUNK_MAGIC(m) \
|
||||
(IS_PNG_MAGIC_CHAR((m)[0]) && \
|
||||
IS_PNG_MAGIC_CHAR((m)[1]) && \
|
||||
IS_PNG_MAGIC_CHAR((m)[2]) && \
|
||||
IS_PNG_MAGIC_CHAR((m)[3]))
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct png_chunk_header {
|
||||
uint32_t size;
|
||||
uint32_t magic;
|
||||
};
|
||||
|
||||
struct png_ihdr_chunk {
|
||||
uint32_t size;
|
||||
uint32_t magic;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t bitdepth;
|
||||
uint8_t colortype;
|
||||
uint8_t compression;
|
||||
uint8_t filter;
|
||||
uint8_t interlace;
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
struct png_iend_header {
|
||||
uint32_t size;
|
||||
uint32_t magic;
|
||||
uint32_t crc;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
int png_isfile(const uint8_t *data, size_t input_len, size_t *lengthptr)
|
||||
{
|
||||
if (input_len < PNG_MIN_SIZE || memcmp(data, PNG_SIGNATURE, PNG_SIGNATURE_SIZE) != 0)
|
||||
return 0;
|
||||
|
||||
const struct png_ihdr_chunk *ihdr = (const struct png_ihdr_chunk *)(data + PNG_SIGNATURE_SIZE);
|
||||
|
||||
uint32_t size = be32toh(ihdr->size);
|
||||
uint32_t width = be32toh(ihdr->width);
|
||||
uint32_t height = be32toh(ihdr->height);
|
||||
uint8_t bitdepth = ihdr->bitdepth;
|
||||
uint8_t colortype = ihdr->colortype;
|
||||
uint8_t compression = ihdr->compression;
|
||||
uint8_t filter = ihdr->filter;
|
||||
uint8_t interlace = ihdr->interlace;
|
||||
|
||||
if (ihdr->magic != PNG_IHDR_MAGIC || size != 13)
|
||||
return 0;
|
||||
|
||||
if (width > INT32_MAX || height > INT32_MAX)
|
||||
return 0;
|
||||
|
||||
if (bitdepth != 1 && bitdepth != 2 && bitdepth != 4 && bitdepth != 8 && bitdepth != 16)
|
||||
return 0;
|
||||
|
||||
if (colortype != 0 && colortype != 2 && colortype != 3 && colortype != 4 && colortype != 6)
|
||||
return 0;
|
||||
|
||||
if (compression != 0 || filter != 0)
|
||||
return 0;
|
||||
|
||||
if (interlace != 0 && interlace != 1)
|
||||
return 0;
|
||||
|
||||
size_t length = PNG_HEADER_SIZE;
|
||||
|
||||
for (;;) {
|
||||
const struct png_chunk_header *chunk = (const struct png_chunk_header *)(data + length);
|
||||
|
||||
if (input_len - 12 < length)
|
||||
return 0;
|
||||
|
||||
size_t chunksize = be32toh(chunk->size);
|
||||
union {
|
||||
uint32_t number;
|
||||
uint8_t chars[4];
|
||||
} magic = { .number = chunk->magic };
|
||||
|
||||
if (chunksize > INT32_MAX || SIZE_MAX - (chunksize + 12) < length)
|
||||
return 0;
|
||||
|
||||
if (!IS_PNG_CHUNK_MAGIC(magic.chars))
|
||||
return 0;
|
||||
|
||||
length += chunksize + 12;
|
||||
|
||||
if (chunk->magic == PNG_IEND_MAGIC)
|
||||
{
|
||||
uint32_t crc = be32toh(((const struct png_iend_header *)chunk)->crc);
|
||||
if (chunksize != 0 || crc != 0xAE426082)
|
||||
return 0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lengthptr)
|
||||
*lengthptr = length;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef AUDIOEXTRACT_PNG_H__
|
||||
#define AUDIOEXTRACT_PNG_H__
|
||||
|
||||
#include "audioextract.h"
|
||||
|
||||
#define PNG_SIGNATURE "\x89PNG\r\n\x1a\n"
|
||||
#define PNG_MAGIC MAGIC(PNG_SIGNATURE)
|
||||
#define PNG_SIGNATURE_SIZE 8
|
||||
|
||||
#define PNG_IHDR_MAGIC MAGIC("IHDR")
|
||||
#define PNG_IEND_MAGIC MAGIC("IEND")
|
||||
|
||||
#define PNG_HEADER_SIZE 33
|
||||
#define PNG_MIN_SIZE 45
|
||||
|
||||
int png_isfile(const uint8_t *data, size_t input_len, size_t *lengthptr);
|
||||
|
||||
#endif /* AUDIOEXTRACT_PNG_H__ */
|
Loading…
Reference in New Issue