diff --git a/src/metadata_xiph.c b/src/metadata_xiph.c index 40ef6ece..608177c0 100644 --- a/src/metadata_xiph.c +++ b/src/metadata_xiph.c @@ -10,8 +10,93 @@ #include <config.h> #endif +#include <stdlib.h> +#include <string.h> + #include "metadata_xiph.h" #include "logging.h" #define CATMODULE "metadata-xiph" +uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in) +{ + uint32_t ret = 0; + ret += in[3]; + ret <<= 8; + ret += in[2]; + ret <<= 8; + ret += in[1]; + ret <<= 8; + ret += in[0]; + return ret; +} + +bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buffer, size_t len) +{ + bool ret = true; + size_t expected_len = 8; + uint32_t vendor_len; + uint32_t count; + uint32_t i; + char *out_buffer = NULL; + size_t out_buffer_len = 0; + + if (!vc || !buffer || len < expected_len) + return false; + + /* reading vendor tag and discarding it */ + vendor_len = metadata_xiph_read_u32be_unaligned(buffer); + expected_len += vendor_len; + + if (len < expected_len) + return false; + + buffer += 4 + vendor_len; + + count = metadata_xiph_read_u32be_unaligned(buffer); + + expected_len += count * 4; + + if (len < expected_len) + return false; + + buffer += 4; + + for (i = 0; i < count; i++) { + uint32_t comment_len = metadata_xiph_read_u32be_unaligned(buffer); + + buffer += 4; + + expected_len += comment_len; + + if (len < expected_len) { + ret = false; + break; + } + + if (out_buffer_len < comment_len || !out_buffer) { + char *n_out_buffer = realloc(out_buffer, comment_len + 1); + if (!n_out_buffer) { + ret = false; + break; + } + + out_buffer = n_out_buffer; + out_buffer_len = comment_len; + } + + memcpy(out_buffer, buffer, comment_len); + out_buffer[comment_len] = 0; + buffer += comment_len; + + vorbis_comment_add(vc, out_buffer); + } + + if (!ret) { + free(out_buffer); + vorbis_comment_clear(vc); + vorbis_comment_init(vc); + } + + return ret; +} diff --git a/src/metadata_xiph.h b/src/metadata_xiph.h index 5386c1fc..a9c60806 100644 --- a/src/metadata_xiph.h +++ b/src/metadata_xiph.h @@ -9,4 +9,15 @@ #ifndef __METADATA_XIPH_H__ #define __METADATA_XIPH_H__ +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> /* for size_t */ + +#include <vorbis/codec.h> + +uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in); + +/* returns true if parsing was successful, *vc must be in inited state before and will be in inited state after (even when false is returned) */ +bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buffer, size_t len); + #endif