diff --git a/Makefile b/Makefile index 6ba7b45..623e88f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,27 @@ +BUILDDIR=build +OBJ=$(BUILDDIR)/audioextract.o $(BUILDDIR)/wave.o $(BUILDDIR)/ogg.o +CC=gcc +CFLAGS=-Wall -std=c99 -O2 -fmessage-length=0 -g +BIN=$(BUILDDIR)/audioextract + .PHONY: all clean -all: audioextract +all: $(BIN) -audioextract: audioextract.c - gcc -Wall -std=c99 -O2 $< -o $@ +$(BIN): $(OBJ) + $(CC) $(CFLAGS) $(OBJ) -o $@ + +$(BUILDDIR)/audioextract.o: audioextract.c audioextract.h ogg.h wave.h $(BUILDDIR) + $(CC) $(CFLAGS) $< -o $@ -c + +$(BUILDDIR)/wave.o: wave.c audioextract.h wave.h $(BUILDDIR) + $(CC) $(CFLAGS) $< -o $@ -c + +$(BUILDDIR)/ogg.o: ogg.c audioextract.h ogg.h $(BUILDDIR) + $(CC) $(CFLAGS) $< -o $@ -c + +$(BUILDDIR): + mkdir -p $(BUILDDIR) clean: - rm audioextract + rm $(BIN) $(OBJ) diff --git a/audioextract.c b/audioextract.c index cce57b5..2396aa8 100644 --- a/audioextract.c +++ b/audioextract.c @@ -8,57 +8,9 @@ * Original author of oggextract: Adrian Keet */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) -#define __WINDOWS__ -#endif - -#ifndef __WINDOWS__ -#include -#endif - -#define OGG_HEADER_SIZE 27 -#define ogg_isinitial(data) ((data)[5] & 2) - -#define WAVE_HEADER_SIZE 8 - -#if defined(__WINDOWS__) || __BYTE_ORDER == __LITTLE_ENDIAN - -# define OGG_MAGIC 0x5367674f /* "OggS" (reversed) */ - -# define RIFF_MAGIC 0x46464952 /* "RIFF" (reversed) */ -# define WAVE_MAGIC 0x45564157 /* "WAVE" (reversed) */ - -# define FORM_MAGIC 0x4d524f46 /* "FORM" (reversed) */ -# define AIFF_MAGIC 0x46464941 /* "AIFF" (reversed) */ -# define AIFC_MAGIC 0x43464941 /* "AIFC" (reversed) */ - -#elif __BYTE_ORDER == __BIG_ENDIAN - -# define OGG_MAGIC 0x5367674f /* "OggS" */ - -# define RIFF_MAGIC 0x46464952 /* "RIFF" */ -# define WAVE_MAGIC 0x57415645 /* "WAVE" */ - -# define FORM_MAGIC 0x464f524d /* "FORM" */ -# define AIFF_MAGIC 0x41494646 /* "AIFF" */ -# define AIFC_MAGIC 0x41494643 /* "AIFC" */ - -#else - -#error unsupported endian - -#endif +#include "audioextract.h" +#include "wave.h" +#include "ogg.h" enum fileformat { NONE = 0, @@ -71,7 +23,8 @@ enum fileformat { int usage(int argc, char **argv) { - fprintf(stderr, "Usage: %s [ ...]\n", argc <= 0 ? "audioextract" : argv[0]); + fprintf(stderr, "Usage: %s [ ...]\n", + argc <= 0 ? "audioextract" : argv[0]); return 255; } @@ -101,101 +54,6 @@ const unsigned char *findmagic(const unsigned char *start, const unsigned char * return NULL; } -int ogg_ispage(const unsigned char *start, const unsigned char *end, size_t *lengthptr) -{ - unsigned char nsegs; - size_t length, i; - const unsigned char *segs = start + OGG_HEADER_SIZE; - - /* full header available? */ - if (end <= (unsigned char*)OGG_HEADER_SIZE || end - OGG_HEADER_SIZE < start) - return 0; - - /* capture pattern */ - if (*(const int32_t *)start != OGG_MAGIC) - return 0; - - /* stream structure version */ - if (start[4] != 0x00) - return 0; - - /* header type flag */ - if ((start[5] & ~7) != 0x00) - return 0; - - nsegs = start[26]; - length = OGG_HEADER_SIZE + nsegs; - - /* segment sizes fully available? */ - if (end <= (unsigned char*)length || end - length < start) - return 0; - - for (i = 0; i < nsegs; ++ i) - { - length += segs[i]; - } - - /* segments fully available? */ - if (end <= (unsigned char*)length || end - length < start) - return 0; - - if (lengthptr) - *lengthptr = length; - - /* I think we can reasonably assume it is a real page now */ - return 1; -} - -int wave_ischunk(const unsigned char *start, const unsigned char *end, size_t *lengthptr) -{ - size_t length; - - if (end <= (unsigned char *)WAVE_HEADER_SIZE || end - WAVE_HEADER_SIZE < start) - return 0; - - if (*(const int32_t *)start != RIFF_MAGIC) - return 0; - - length = *(const uint32_t *)(start + 4) + 8; - - if (end <= (unsigned char *)length || end - length < start) - return 0; - - if (*(const uint32_t *)(start + 8) != WAVE_MAGIC) - return 0; - - if (lengthptr) - *lengthptr = length; - - return 1; -} - -int aiff_ischunk(const unsigned char *start, const unsigned char *end, size_t *lengthptr) -{ - size_t length; - int16_t format; - - if (end <= (unsigned char *)WAVE_HEADER_SIZE || end - WAVE_HEADER_SIZE < start) - return 0; - - if (*(const int32_t *)start != FORM_MAGIC) - return 0; - - length = ntohl(*(const uint32_t *)(start + 4)) + 8; - - if (end <= (unsigned char *)length || end - length < start) - return 0; - - format = *(const uint32_t *)(start + 8); - if (format != AIFF_MAGIC && format != AIFC_MAGIC) - return 0; - - if (lengthptr) - *lengthptr = length; - - return 1; -} - const char *basename(const char *path) { const char *ptr = strrchr(path, '/'); @@ -232,21 +90,18 @@ int extract(const char *filepath, size_t *numfilesptr) if (fd < 0) { perror("open"); - success = 0; - goto exit_numfiles; + goto error; } if (fstat(fd, &statdata) < 0) { perror("stat"); - success = 0; - goto exit_fd; + goto error; } if (S_ISDIR(statdata.st_mode)) { fprintf(stderr, "error: Is a directory: %s\n", filepath); - success = 0; - goto exit_fd; + goto error; } filesize = statdata.st_size; @@ -254,16 +109,14 @@ int extract(const char *filepath, size_t *numfilesptr) if (filedata == MAP_FAILED) { perror("mmap"); - success = 0; - goto exit_fd; + goto error; } outfilename = malloc(namelen); if (outfilename == NULL) { perror("malloc"); - success = 0; - goto exit_munmap; + goto error; } #define OPEN_OUTFD(ext) \ @@ -272,8 +125,7 @@ int extract(const char *filepath, size_t *numfilesptr) if (outfd < 0) \ { \ perror("creat"); \ - success = 0; \ - goto exit_free; \ + goto error; \ } \ ++ numfiles; \ printf("Writing: %s\n", outfilename) @@ -328,16 +180,21 @@ int extract(const char *filepath, size_t *numfilesptr) ptr += 4; } -exit_free: - free(outfilename); + goto cleanup; -exit_munmap: - munmap(filedata, filesize); +error: + success = 0; -exit_fd: - close(fd); +cleanup: + if (outfilename) + free(outfilename); + + if (filedata) + munmap(filedata, filesize); + + if (fd >= 0) + close(fd); -exit_numfiles: if (numfilesptr) *numfilesptr = numfiles; diff --git a/audioextract.h b/audioextract.h new file mode 100644 index 0000000..efd8d29 --- /dev/null +++ b/audioextract.h @@ -0,0 +1,37 @@ +#ifndef AUDIOEXTRACT_H__ +#define AUDIOEXTRACT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) +#define __WINDOWS__ +#endif + +#ifndef __WINDOWS__ +#include +#endif + +#ifndef __BYTE_ORDER +# ifndef __WINDOWS__ +# error cannot detect byte order +# else + /* assume little endian byte order on windows */ +# define __LITTLE_ENDIAN 1234 +# define __BIG_ENDIAN 4321 +# define __PDP_ENDIAN 3412 +# define __BYTE_ORDER __LITTLE_ENDIAN +# endif +#elif __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN +# error unsupported byte order +#endif + +#endif /* AUDIOEXTRACT_H__ */ diff --git a/ogg.c b/ogg.c new file mode 100644 index 0000000..4fa5ebc --- /dev/null +++ b/ogg.c @@ -0,0 +1,46 @@ +#include "ogg.h" + +int ogg_ispage(const unsigned char *start, const unsigned char *end, size_t *lengthptr) +{ + unsigned char nsegs; + size_t length, i; + const unsigned char *segs = start + OGG_HEADER_SIZE; + + /* full header available? */ + if (end <= (unsigned char*)OGG_HEADER_SIZE || end - OGG_HEADER_SIZE < start) + return 0; + + /* capture pattern */ + if (*(const int32_t *)start != OGG_MAGIC) + return 0; + + /* stream structure version */ + if (start[4] != 0x00) + return 0; + + /* header type flag */ + if ((start[5] & ~7) != 0x00) + return 0; + + nsegs = start[26]; + length = OGG_HEADER_SIZE + nsegs; + + /* segment sizes fully available? */ + if (end <= (unsigned char*)length || end - length < start) + return 0; + + for (i = 0; i < nsegs; ++ i) + { + length += segs[i]; + } + + /* segments fully available? */ + if (end <= (unsigned char*)length || end - length < start) + return 0; + + if (lengthptr) + *lengthptr = length; + + /* I think we can reasonably assume it is a real page now */ + return 1; +} diff --git a/ogg.h b/ogg.h new file mode 100644 index 0000000..bad249e --- /dev/null +++ b/ogg.h @@ -0,0 +1,25 @@ +#ifndef AUDIOEXTRACT_OGG_H__ +#define AUDIOEXTRACT_OGG_H__ + +#include "audioextract.h" + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +# define OGG_MAGIC 0x5367674f /* "OggS" (reversed) */ + +#elif __BYTE_ORDER == __BIG_ENDIAN + +# define OGG_MAGIC 0x5367674f /* "OggS" */ + +#else + +# error unsupported endian + +#endif + +#define OGG_HEADER_SIZE 27 +#define ogg_isinitial(data) ((data)[5] & 2) + +int ogg_ispage(const unsigned char *start, const unsigned char *end, size_t *lengthptr); + +#endif /* AUDIOEXTRACT_OGG_H__ */ diff --git a/wave.c b/wave.c new file mode 100644 index 0000000..6d7b808 --- /dev/null +++ b/wave.c @@ -0,0 +1,51 @@ +#include "wave.h" + +int wave_ischunk(const unsigned char *start, const unsigned char *end, size_t *lengthptr) +{ + size_t length; + + if (end <= (unsigned char *)WAVE_HEADER_SIZE || end - WAVE_HEADER_SIZE < start) + return 0; + + if (*(const int32_t *)start != RIFF_MAGIC) + return 0; + + length = *(const uint32_t *)(start + 4) + 8; + + if (end <= (unsigned char *)length || end - length < start) + return 0; + + if (*(const uint32_t *)(start + 8) != WAVE_MAGIC) + return 0; + + if (lengthptr) + *lengthptr = length; + + return 1; +} + +int aiff_ischunk(const unsigned char *start, const unsigned char *end, size_t *lengthptr) +{ + size_t length; + int16_t format; + + if (end <= (unsigned char *)WAVE_HEADER_SIZE || end - WAVE_HEADER_SIZE < start) + return 0; + + if (*(const int32_t *)start != FORM_MAGIC) + return 0; + + length = ntohl(*(const uint32_t *)(start + 4)) + 8; + + if (end <= (unsigned char *)length || end - length < start) + return 0; + + format = *(const uint32_t *)(start + 8); + if (format != AIFF_MAGIC && format != AIFC_MAGIC) + return 0; + + if (lengthptr) + *lengthptr = length; + + return 1; +} diff --git a/wave.h b/wave.h new file mode 100644 index 0000000..0fdb6cb --- /dev/null +++ b/wave.h @@ -0,0 +1,35 @@ +#ifndef AUDIOEXTRACT_WAVE_H__ +#define AUDIOEXTRACT_WAVE_H__ + +#include "audioextract.h" + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +# define RIFF_MAGIC 0x46464952 /* "RIFF" (reversed) */ +# define WAVE_MAGIC 0x45564157 /* "WAVE" (reversed) */ + +# define FORM_MAGIC 0x4d524f46 /* "FORM" (reversed) */ +# define AIFF_MAGIC 0x46464941 /* "AIFF" (reversed) */ +# define AIFC_MAGIC 0x43464941 /* "AIFC" (reversed) */ + +#elif __BYTE_ORDER == __BIG_ENDIAN + +# define RIFF_MAGIC 0x46464952 /* "RIFF" */ +# define WAVE_MAGIC 0x57415645 /* "WAVE" */ + +# define FORM_MAGIC 0x464f524d /* "FORM" */ +# define AIFF_MAGIC 0x41494646 /* "AIFF" */ +# define AIFC_MAGIC 0x41494643 /* "AIFC" */ + +#else + +# error unsupported endian + +#endif + +#define WAVE_HEADER_SIZE 8 + +int wave_ischunk(const unsigned char *start, const unsigned char *end, size_t *lengthptr); +int aiff_ischunk(const unsigned char *start, const unsigned char *end, size_t *lengthptr); + +#endif /* AUDIOEXTRACT_WAVE_H__ */