RAII interface for dynamic ogg packets

This commit is contained in:
Frédéric Mangano-Tarumi 2018-11-13 20:46:30 -05:00
parent 82ff7f7751
commit e41cf918d1
4 changed files with 43 additions and 34 deletions

View File

@ -86,39 +86,38 @@ ot::status ot::parse_tags(const char *data, long len, opus_tags *tags)
return status::ok;
}
int ot::render_tags(opus_tags *tags, ogg_packet *op)
ot::dynamic_ogg_packet ot::render_tags(const opus_tags& tags)
{
// Note: op->packet must be manually freed.
op->b_o_s = 0;
op->e_o_s = 0;
op->granulepos = 0;
op->packetno = 1;
long len = 8 + 4 + tags->vendor.size() + 4;
for (const std::string& comment : tags->comments)
len += 4 + comment.size();
len += tags->extra_data.size();
op->bytes = len;
char *data = static_cast<char*>(malloc(len));
if (!data)
return -1;
op->packet = (unsigned char*) data;
size_t size = 8 + 4 + tags.vendor.size() + 4;
for (const std::string& comment : tags.comments)
size += 4 + comment.size();
size += tags.extra_data.size();
dynamic_ogg_packet op(size);
op.b_o_s = 0;
op.e_o_s = 0;
op.granulepos = 0;
op.packetno = 1;
unsigned char* data = op.packet;
uint32_t n;
memcpy(data, "OpusTags", 8);
n = htole32(tags->vendor.size());
n = htole32(tags.vendor.size());
memcpy(data+8, &n, 4);
memcpy(data+12, tags->vendor.data(), tags->vendor.size());
data += 12 + tags->vendor.size();
n = htole32(tags->comments.size());
memcpy(data+12, tags.vendor.data(), tags.vendor.size());
data += 12 + tags.vendor.size();
n = htole32(tags.comments.size());
memcpy(data, &n, 4);
data += 4;
for (const std::string& comment : tags->comments) {
for (const std::string& comment : tags.comments) {
n = htole32(comment.size());
memcpy(data, &n, 4);
memcpy(data+4, comment.data(), comment.size());
data += 4 + comment.size();
}
memcpy(data, tags->extra_data.data(), tags->extra_data.size());
return 0;
memcpy(data, tags.extra_data.data(), tags.extra_data.size());
return op;
}
/**

View File

@ -131,11 +131,9 @@ static int run(ot::options& opt)
for (const std::string& comment : opt.to_add)
tags.comments.emplace_back(comment);
if(writer.file){
ogg_packet packet;
ot::render_tags(&tags, &packet);
auto packet = ot::render_tags(tags);
if(ogg_stream_packetin(&writer.stream, &packet) == -1)
error = "ogg_stream_packetin: internal error";
free(packet.packet);
}
else
ot::print_comments(tags.comments, stdout);

View File

@ -9,6 +9,7 @@
#include <cstdio>
#include <cstring>
#include <list>
#include <memory>
#include <string>
#include <vector>
@ -158,6 +159,23 @@ struct ogg_writer {
int write_page(ogg_page *og, FILE *stream);
/**
* Ogg packet with dynamically allocated data.
*
* Provides a wrapper around libogg's ogg_packet with RAII.
*/
struct dynamic_ogg_packet : ogg_packet {
/** Construct an ogg_packet of the given size. */
explicit dynamic_ogg_packet(size_t size) {
bytes = size;
data = std::make_unique<unsigned char[]>(size);
packet = data.get();
}
private:
/** Owning reference to the data. Use the packet field from ogg_packet instead. */
std::unique_ptr<unsigned char[]> data;
};
/** \} */
/**
@ -206,7 +224,7 @@ struct opus_tags {
status validate_identification_header(const ogg_packet& packet);
status parse_tags(const char *data, long len, opus_tags *tags);
int render_tags(opus_tags *tags, ogg_packet *op);
dynamic_ogg_packet render_tags(const opus_tags& tags);
void delete_tags(opus_tags *tags, const char *field);
/** \} */

View File

@ -110,9 +110,7 @@ static void recode_standard()
auto rc = ot::parse_tags(standard_OpusTags, sizeof(standard_OpusTags) - 1, &tags);
if (rc != ot::status::ok)
throw failure("ot::parse_tags did not return ok");
ogg_packet packet;
if (ot::render_tags(&tags, &packet) != 0)
throw failure("ot::render_tags did not return 0");
auto packet = ot::render_tags(tags);
if (packet.b_o_s != 0)
throw failure("b_o_s should not be set");
if (packet.e_o_s != 0)
@ -125,7 +123,6 @@ static void recode_standard()
throw failure("the packet is not the right size");
if (memcmp(packet.packet, standard_OpusTags, packet.bytes) != 0)
throw failure("the rendered packet is not what we expected");
free(packet.packet);
}
static void recode_padding()
@ -140,16 +137,13 @@ static void recode_padding()
if (tags.extra_data != "\0hello"s)
throw failure("corrupted extra data");
// recode the packet and ensure it's exactly the same
ogg_packet packet;
if (ot::render_tags(&tags, &packet) != 0)
throw failure("ot::render_tags did not return 0");
auto packet = ot::render_tags(tags);
if (static_cast<size_t>(packet.bytes) < padded_OpusTags.size())
throw failure("the packet was truncated");
if (static_cast<size_t>(packet.bytes) > padded_OpusTags.size())
throw failure("the packet got too big");
if (memcmp(packet.packet, padded_OpusTags.data(), packet.bytes) != 0)
throw failure("the rendered packet is not what we expected");
free(packet.packet);
}
int main()