summaryrefslogtreecommitdiff
path: root/plugins/vorbis/vcedit.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/vorbis/vcedit.c')
-rw-r--r--plugins/vorbis/vcedit.c289
1 files changed, 0 insertions, 289 deletions
diff --git a/plugins/vorbis/vcedit.c b/plugins/vorbis/vcedit.c
deleted file mode 100644
index 2f30aeb6..00000000
--- a/plugins/vorbis/vcedit.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- This file is part of Deadbeef Player source code
- http://deadbeef.sourceforge.net
-
- Ogg Vorbis plugin Ogg edit functions
-
- Copyright (C) 2014 Ian Nartowicz <deadbeef@nartowicz.co.uk>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <sys/stat.h>
-#include <ogg/ogg.h>
-#include <deadbeef.h>
-#include "vcedit.h"
-
-#define VORBISNAME "Vorbis"
-#define TAGMAGIC "\3vorbis"
-#define CODEMAGIC "\5vorbis"
-
-#define CHUNKSIZE 4096
-#define MAXOGGPAGE 65536
-
-static const char *ogg_codec(ogg_page *og)
-{
- typedef struct {
- const char *magic;
- const size_t length;
- const char *codec;
- } codec_t;
- const codec_t codecs[] = {
- {.codec = "Opus", .length = 19, .magic = "OpusHead"},
- {.codec = "Vorbis", .length = 30, .magic = "\1vorbis"},
- {.codec = "Flac", .length = 47, .magic = "\177FLAC"},
- {.codec = "Speex", .length = 80, .magic = "Speex "},
- {.codec = "Celt", .length = 80, .magic = "CELT"}, // obsolete
- {.codec = "MIDI", .length = 13, .magic = "OggMIDI\0"},
- {.codec = "PCM", .length = 28, .magic = "PCM "},
- {.codec = "Theora", .length = 42, .magic = "\200theora"},
- {.codec = "Daala", .length = 38, .magic = "\200daala"},
- {.codec = "Dirac", .length = 5, .magic = "BBCD\0"},
- {.codec = "Skeleton", .length = 80, .magic = "fishead\0"},
- {.codec = "Kate", .length = 64, .magic = "\200kate\0\0\0"},
- {.codec = "CMML", .length = 29, .magic = "CMML\0\0\0\0"},
- {.codec = "YUV4MPEG", .length = 8, .magic = "YUV4Mpeg"},
- {.codec = "UVS", .length = 48, .magic = "UVS "},
- {.codec = "YUV", .length = 32, .magic = "\0YUV"},
- {.codec = "RGB", .length = 24, .magic = "\0RGB"},
- {.codec = "JNG", .length = 48, .magic = "\213JNG\r\n\032\n"},
- {.codec = "MNG", .length = 48, .magic = "\212MNG\r\n\032\n"},
- {.codec = "PNG", .length = 48, .magic = "\211PNG\r\n\032\n"},
- {.codec = "Spots", .length = 52, .magic = "SPOTS\0\0\0"},
- {.codec = NULL}
- };
-
- for (const codec_t *match = codecs; match->codec; match++)
- if ((size_t)og->body_len >= match->length && !memcmp(og->body, match->magic, strlen(match->codec)))
- return match->codec;
-
- return "unknown";
-}
-
-static void _oggpack_chars(oggpack_buffer *opb, const char *s, size_t length)
-{
- while (length--)
- oggpack_write(opb, *s++, 8);
-}
-
-static void _oggpack_string(oggpack_buffer *opb, const char *s)
-{
- oggpack_write(opb, strlen(s), 32);
- _oggpack_chars(opb, s, strlen(s));
-}
-
-static int get_page(DB_FILE *in, ogg_sync_state *oy, ogg_page *og, char **lasterror)
-{
- uint16_t chunks_left = MAXOGGPAGE / CHUNKSIZE;
- while (ogg_sync_pageout(oy, og) != 1) {
- char *buffer = ogg_sync_buffer(oy, CHUNKSIZE);
- if (!in || !buffer || !chunks_left--) {
- *lasterror = "can't find Ogg bitstream.";
- return -1;
- }
-
- const size_t bytes = in->vfs->read(buffer, 1, CHUNKSIZE, in);
- if (!bytes) {
- *lasterror = "unexpected EOF.";
- return 0;
- }
-
- ogg_sync_wrote(oy, bytes);
- }
-
- return ogg_page_serialno(og);
-}
-
-static bool write_page(FILE *out, ogg_page *og)
-{
- return fwrite(og->header, 1, og->header_len, out) != (size_t)og->header_len ||
- fwrite(og->body, 1, og->body_len, out) != (size_t)og->body_len;
-}
-
-static int write_page_and_get_next(DB_FILE *in, FILE *out, ogg_sync_state *oy, ogg_page *og, char **lasterror)
-{
- if (write_page(out, og))
- return -1;
-
- return get_page(in, oy, og, lasterror);
-}
-
-static bool write_vorbis_tags(FILE *out, const int serial, const char *vendor, const size_t num_tags, char **tags, ogg_packet *codebooks)
-{
- oggpack_buffer opb;
- oggpack_writeinit(&opb);
- _oggpack_chars(&opb, TAGMAGIC, strlen(TAGMAGIC));
- _oggpack_string(&opb, vendor);
- oggpack_write(&opb, num_tags, 32);
- for (size_t i = 0; i < num_tags; i++)
- _oggpack_string(&opb, tags[i]);
- oggpack_write(&opb, 1, 1);
- oggpack_writealign(&opb);
-
-
- ogg_stream_state os;
- ogg_stream_init(&os, serial);
- os.b_o_s = 1;
- os.pageno = 1;
- ogg_packet op;
- memset(&op, '\0', sizeof(op));
- op.packet = oggpack_get_buffer(&opb);
- op.bytes = oggpack_bytes(&opb);
- ogg_stream_packetin(&os, &op);
- oggpack_writeclear(&opb);
- ogg_stream_packetin(&os, codebooks);
-
- ogg_page og;
- while (ogg_stream_flush(&os, &og))
- if (write_page(out, &og))
- return true;
-
- return ogg_stream_check(&os) || ogg_stream_clear(&os);
-}
-
-static int extract_codebooks(DB_FILE *in, ogg_sync_state *oy, ogg_page *og, int serial, ogg_packet *codebooks, char **lasterror)
-{
- memset(codebooks, '\0', sizeof(codebooks));
- ogg_stream_state os;
- if (ogg_stream_init(&os, serial)) {
- *lasterror = "cannot init Ogg stream.";
- return -1;
- }
- os.pageno = 1;
- os.b_o_s = 1;
-
- ogg_packet op;
- ogg_stream_pagein(&os, og);
- do {
- while (ogg_stream_packetpeek(&os, NULL) == 0) {
- if ((serial = get_page(in, oy, og, lasterror)) <= 0)
- goto cleanup;
- fprintf(stderr, "Serial: %d, %ld bytes (%s)\n", serial, og->header_len + og->body_len, og->body);
- if (ogg_stream_pagein(&os, og)) {
- *lasterror = "failed to stream page for codebooks packet.";
- goto cleanup;
- }
- }
- } while (ogg_stream_packetout(&os, &op) != 1 || op.bytes < strlen(CODEMAGIC) || memcmp(op.packet, CODEMAGIC, strlen(CODEMAGIC)));
-
- if (!(codebooks->packet = malloc(op.bytes))) {
- *lasterror = "cannot allocate codebooks packet.";
- goto cleanup;
- }
- codebooks->bytes = op.bytes;
- memcpy(codebooks->packet, op.packet, op.bytes);
-
-cleanup:
- ogg_stream_clear(&os);
-
- return codebooks->packet ? serial : -1;
-}
-
-off_t vcedit_write_metadata(DB_FILE *in, const char *fname, int link, const char *vendor, const int num_tags, char **tags, char **lasterror)
-{
- off_t file_size = 0;
- ogg_page og;
- ogg_sync_state oy;
- ogg_sync_init(&oy);
-
- char outname[PATH_MAX];
- snprintf(outname, PATH_MAX, "%s.temp", fname);
- FILE *out = fopen(outname, "w+b");
- if (!out) {
- *lasterror = "unable to open temporary file for writing.";
- goto cleanup;
- }
- if (!in) {
- *lasterror = "file not opened for reading.";
- goto cleanup;
- }
- struct stat stat_struct;
- if (!stat(fname, &stat_struct))
- chmod(outname, stat_struct.st_mode);
-
- /* Copy through pages until we reach the right info header */
- int codec_serial = 0;
- int serial = get_page(in, &oy, &og, lasterror);
- while (serial > 0 && !codec_serial) {
- while (serial > 0 && !ogg_page_bos(&og))
- serial = write_page_and_get_next(in, out, &oy, &og, lasterror);
-
- while (serial > 0 && ogg_page_bos(&og)) {
- if (link < 1 && !strcmp(ogg_codec(&og), VORBISNAME)) {
- codec_serial = serial;
- }
- serial = write_page_and_get_next(in, out, &oy, &og, lasterror);
- }
- link--;
- }
-
- /* Copy additional pages up to our comment header */
- while (serial > 0 && serial != codec_serial)
- serial = write_page_and_get_next(in, out, &oy, &og, lasterror);
- if (serial <= 0)
- goto cleanup;
-
- /* Add the codebook packet to our comment header and save it */
- ogg_packet codebooks;
- if ((serial = extract_codebooks(in, &oy, &og, codec_serial, &codebooks, lasterror)) <= 0)
- goto cleanup;
- const bool write_tags = write_vorbis_tags(out, codec_serial, vendor, num_tags, tags, &codebooks);
- ogg_packet_clear(&codebooks);
- if (write_tags) {
- *lasterror = "internal error writing Vorbis comment header packet.";
- goto cleanup;
- }
-
- /* Blindly copy through the remaining pages */
- serial = get_page(in, &oy, &og, lasterror);
- while (serial > 0)
- serial = write_page_and_get_next(in, out, &oy, &og, lasterror);
- if (serial < 0)
- goto cleanup;
-
- fseeko(out, 0, SEEK_END);
- file_size = ftello(out);
-
-cleanup:
- if (in)
- in->vfs->close(in);
-
- if (out)
- fclose(out);
-
- ogg_sync_clear(&oy);
-
- if (file_size <= 0) {
- unlink(outname);
- if (!*lasterror)
- *lasterror = "error writing new file, changes backed out.";
- return -1;
- }
-
- rename(outname, fname);
- return file_size;
-}