PNG support

This commit is contained in:
Mathias Panzenböck 2013-01-11 03:25:29 +01:00
parent 834328808e
commit afefa5d7b2
5 changed files with 168 additions and 21 deletions

View File

@ -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)

View File

@ -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

View File

@ -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;

108
src/png.c Normal file
View File

@ -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;
}

18
src/png.h Normal file
View File

@ -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__ */