move the main loop to ot::process

This commit is contained in:
Frédéric Mangano-Tarumi 2018-11-14 19:56:23 -05:00
parent 8a5b80e075
commit 22bfd05b36
3 changed files with 134 additions and 118 deletions

View File

@ -198,3 +198,132 @@ std::list<std::string> ot::read_comments(FILE* input)
}
return comments;
}
/**
* Parse the packet as an OpusTags comment header, apply the user's modifications, and write the new
* packet to the writer.
*/
static ot::status process_tags(const ogg_packet& packet, const ot::options& opt, ot::ogg_writer& writer)
{
ot::opus_tags tags;
if(ot::parse_tags((char*) packet.packet, packet.bytes, &tags) != ot::status::ok)
return ot::status::bad_comment_header;
if (opt.delete_all) {
tags.comments.clear();
} else {
for (const std::string& name : opt.to_delete)
ot::delete_tags(&tags, name.c_str());
}
if (opt.set_all)
tags.comments = ot::read_comments(stdin);
for (const std::string& comment : opt.to_add)
tags.comments.emplace_back(comment);
if (writer.file) {
auto packet = ot::render_tags(tags);
if(ogg_stream_packetin(&writer.stream, &packet) == -1)
return ot::status::libogg_error;
} else {
ot::print_comments(tags.comments, stdout);
}
return ot::status::ok;
}
/**
* Main loop of opustags. Read the packets from the reader, and forwards them to the writer.
* Transform the OpusTags packet on the fly.
*/
ot::status ot::process(ogg_reader& reader, ogg_writer& writer, const ot::options &opt)
{
const char *error = nullptr;
int packet_count = -1;
while (error == nullptr) {
// Read the next page.
ot::status rc = reader.read_page();
if (rc == ot::status::end_of_file) {
break;
} else if (rc != ot::status::ok) {
if (rc == ot::status::standard_error)
error = strerror(errno);
else
error = "error reading the next ogg page";
break;
}
// Short-circuit when the relevant packets have been read.
if (packet_count >= 2 && writer.file) {
if (ot::write_page(&reader.page, writer.file) == -1) {
error = "write_page: fwrite error";
break;
}
continue;
}
// Initialize the streams from the first page.
if (packet_count == -1) {
if (ogg_stream_init(&reader.stream, ogg_page_serialno(&reader.page)) == -1) {
error = "ogg_stream_init: couldn't create a decoder";
break;
}
if (writer.file) {
if (ogg_stream_init(&writer.stream, ogg_page_serialno(&reader.page)) == -1) {
error = "ogg_stream_init: couldn't create an encoder";
break;
}
}
packet_count = 0;
}
if (ogg_stream_pagein(&reader.stream, &reader.page) == -1) {
error = "ogg_stream_pagein: invalid page";
break;
}
// Read all the packets.
while (ogg_stream_packetout(&reader.stream, &reader.packet) == 1) {
packet_count++;
if (packet_count == 1) { // Identification header
rc = ot::validate_identification_header(reader.packet);
if (rc != ot::status::ok) {
error = ot::error_message(rc);
break;
}
} else if (packet_count == 2) { // Comment header
rc = process_tags(reader.packet, opt, writer);
if (rc != ot::status::ok) {
error = ot::error_message(rc);
break;
}
if (!writer.file)
break; /* nothing else to do */
else
continue; /* process_tags wrote the new packet */
}
if (writer.file) {
if (ogg_stream_packetin(&writer.stream, &reader.packet) == -1) {
error = "ogg_stream_packetin: internal error";
break;
}
}
}
if (ogg_stream_check(&reader.stream) != 0) {
error = "ogg_stream_check: internal error (decoder)";
break;
}
// Write the page.
if (writer.file) {
ogg_page page;
ogg_stream_flush(&writer.stream, &page);
if (ot::write_page(&page, writer.file) == -1)
error = "write_page: fwrite error";
else if (ogg_stream_check(&writer.stream) != 0)
error = "ogg_stream_check: internal error (encoder)";
}
}
if (!error && packet_count < 2)
error = "opustags: invalid file";
if (error != nullptr) {
fprintf(stderr, "%s\n", error);
return ot::status::exit_now;
}
return ot::status::ok;
}

View File

@ -26,38 +26,8 @@ static bool same_file(const std::string& path_in, const std::string& path_out)
}
/**
* Parse the packet as an OpusTags comment header, apply the user's modifications, and write the new
* packet to the writer.
* Open the input and output streams, then call #ot::process.
*/
static ot::status process_tags(const ogg_packet& packet, const ot::options& opt, ot::ogg_writer& writer)
{
ot::opus_tags tags;
if(ot::parse_tags((char*) packet.packet, packet.bytes, &tags) != ot::status::ok)
return ot::status::bad_comment_header;
if (opt.delete_all) {
tags.comments.clear();
} else {
for (const std::string& name : opt.to_delete)
ot::delete_tags(&tags, name.c_str());
}
if (opt.set_all)
tags.comments = ot::read_comments(stdin);
for (const std::string& comment : opt.to_add)
tags.comments.emplace_back(comment);
if (writer.file) {
auto packet = ot::render_tags(tags);
if(ogg_stream_packetin(&writer.stream, &packet) == -1)
return ot::status::libogg_error;
} else {
ot::print_comments(tags.comments, stdout);
}
return ot::status::ok;
}
static int run(ot::options& opt)
{
if (!opt.path_out.empty() && same_file(opt.path_in, opt.path_out)) {
@ -97,96 +67,11 @@ static int run(ot::options& opt)
}
}
}
const char *error = NULL;
int packet_count = -1;
while(error == NULL){
// Read the next page.
ot::status rc = reader.read_page();
if (rc == ot::status::end_of_file) {
break;
} else if (rc != ot::status::ok) {
if (rc == ot::status::standard_error)
error = strerror(errno);
else
error = "error reading the next ogg page";
break;
}
// Short-circuit when the relevant packets have been read.
if(packet_count >= 2 && writer.file){
if(ot::write_page(&reader.page, writer.file) == -1){
error = "write_page: fwrite error";
break;
}
continue;
}
// Initialize the streams from the first page.
if(packet_count == -1){
if(ogg_stream_init(&reader.stream, ogg_page_serialno(&reader.page)) == -1){
error = "ogg_stream_init: couldn't create a decoder";
break;
}
if(writer.file){
if(ogg_stream_init(&writer.stream, ogg_page_serialno(&reader.page)) == -1){
error = "ogg_stream_init: couldn't create an encoder";
break;
}
}
packet_count = 0;
}
if(ogg_stream_pagein(&reader.stream, &reader.page) == -1){
error = "ogg_stream_pagein: invalid page";
break;
}
// Read all the packets.
while(ogg_stream_packetout(&reader.stream, &reader.packet) == 1){
packet_count++;
if (packet_count == 1) { // Identification header
rc = ot::validate_identification_header(reader.packet);
if (rc != ot::status::ok) {
error = ot::error_message(rc);
break;
}
} else if (packet_count == 2) { // Comment header
rc = process_tags(reader.packet, opt, writer);
if (rc != ot::status::ok) {
error = ot::error_message(rc);
break;
}
if (!writer.file)
break; /* nothing else to do */
else
continue; /* process_tags wrote the new packet */
}
if(writer.file){
if(ogg_stream_packetin(&writer.stream, &reader.packet) == -1){
error = "ogg_stream_packetin: internal error";
break;
}
}
}
if(error != NULL)
break;
if(ogg_stream_check(&reader.stream) != 0)
error = "ogg_stream_check: internal error (decoder)";
// Write the page.
if(writer.file){
ogg_page page;
ogg_stream_flush(&writer.stream, &page);
if(ot::write_page(&page, writer.file) == -1)
error = "write_page: fwrite error";
else if(ogg_stream_check(&writer.stream) != 0)
error = "ogg_stream_check: internal error (encoder)";
}
else if(packet_count >= 2) // Read-only mode
break;
}
ot::status rc = process(reader, writer, opt);
fclose(reader.file);
if(writer.file)
fclose(writer.file);
if(!error && packet_count < 2)
error = "opustags: invalid file";
if(error){
fprintf(stderr, "%s\n", error);
if (rc != ot::status::ok) {
if (!opt.path_out.empty() && writer.file != stdout)
remove(opt.path_out.c_str());
return EXIT_FAILURE;

View File

@ -256,6 +256,8 @@ status process_options(int argc, char** argv, options& opt);
void print_comments(const std::list<std::string>& comments, FILE* output);
std::list<std::string> read_comments(FILE* input);
ot::status process(ogg_reader& reader, ogg_writer& writer, const ot::options &opt);
/** \} */
}