input/InputStream: migrate from class Error to C++ exceptions
This commit is contained in:
@@ -21,10 +21,9 @@
|
||||
#include "Aiff.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
#include "system/ByteOrder.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -45,33 +44,27 @@ aiff_seek_id3(InputStream &is)
|
||||
{
|
||||
/* seek to the beginning and read the AIFF header */
|
||||
|
||||
Error error;
|
||||
if (!is.Rewind(error)) {
|
||||
LogError(error, "Failed to seek");
|
||||
return 0;
|
||||
}
|
||||
is.Rewind();
|
||||
|
||||
aiff_header header;
|
||||
if (!is.ReadFull(&header, sizeof(header), IgnoreError()) ||
|
||||
memcmp(header.id, "FORM", 4) != 0 ||
|
||||
is.ReadFull(&header, sizeof(header));
|
||||
if (memcmp(header.id, "FORM", 4) != 0 ||
|
||||
(is.KnownSize() && FromLE32(header.size) > is.GetSize()) ||
|
||||
(memcmp(header.format, "AIFF", 4) != 0 &&
|
||||
memcmp(header.format, "AIFC", 4) != 0))
|
||||
/* not a AIFF file */
|
||||
return 0;
|
||||
throw std::runtime_error("Not an AIFF file");
|
||||
|
||||
while (true) {
|
||||
/* read the chunk header */
|
||||
|
||||
aiff_chunk_header chunk;
|
||||
if (!is.ReadFull(&chunk, sizeof(chunk), IgnoreError()))
|
||||
return 0;
|
||||
is.ReadFull(&chunk, sizeof(chunk));
|
||||
|
||||
size_t size = FromBE32(chunk.size);
|
||||
if (size > size_t(std::numeric_limits<int>::max()))
|
||||
/* too dangerous, bail out: possible integer
|
||||
underflow when casting to off_t */
|
||||
return 0;
|
||||
throw std::runtime_error("AIFF chunk is too large");
|
||||
|
||||
if (memcmp(chunk.id, "ID3 ", 4) == 0)
|
||||
/* found it! */
|
||||
@@ -81,7 +74,6 @@ aiff_seek_id3(InputStream &is)
|
||||
/* pad byte */
|
||||
++size;
|
||||
|
||||
if (!is.Skip(size, IgnoreError()))
|
||||
return 0;
|
||||
is.Skip(size);
|
||||
}
|
||||
}
|
||||
|
@@ -32,9 +32,10 @@ class InputStream;
|
||||
/**
|
||||
* Seeks the AIFF file to the ID3 chunk.
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param is a locked #InputStream
|
||||
* @return the size of the ID3 chunk on success, or 0 if this is not a
|
||||
* AIFF file or no ID3 chunk was found
|
||||
* @return the size of the ID3 chunk
|
||||
*/
|
||||
size_t
|
||||
aiff_seek_id3(InputStream &is);
|
||||
|
@@ -50,9 +50,10 @@ try {
|
||||
|
||||
/* determine if file has an apeV2 tag */
|
||||
ApeFooter footer;
|
||||
if (!is.Seek(is.GetSize() - sizeof(footer), IgnoreError()) ||
|
||||
!is.ReadFull(&footer, sizeof(footer), IgnoreError()) ||
|
||||
memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
|
||||
is.Seek(is.GetSize() - sizeof(footer));
|
||||
is.ReadFull(&footer, sizeof(footer));
|
||||
|
||||
if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
|
||||
FromLE32(footer.version) != 2000)
|
||||
return false;
|
||||
|
||||
@@ -60,17 +61,17 @@ try {
|
||||
size_t remaining = FromLE32(footer.length);
|
||||
if (remaining <= sizeof(footer) + 10 ||
|
||||
/* refuse to load more than one megabyte of tag data */
|
||||
remaining > 1024 * 1024 ||
|
||||
!is.Seek(is.GetSize() - remaining, IgnoreError()))
|
||||
remaining > 1024 * 1024)
|
||||
return false;
|
||||
|
||||
is.Seek(is.GetSize() - remaining);
|
||||
|
||||
/* read tag into buffer */
|
||||
remaining -= sizeof(footer);
|
||||
assert(remaining > 10);
|
||||
|
||||
std::unique_ptr<char[]> buffer(new char[remaining]);
|
||||
if (!is.ReadFull(buffer.get(), remaining, IgnoreError()))
|
||||
return false;
|
||||
is.ReadFull(buffer.get(), remaining);
|
||||
|
||||
/* read tags */
|
||||
unsigned n = FromLE32(footer.count);
|
||||
|
@@ -38,8 +38,11 @@ ScanGenericTags(InputStream &is, const TagHandler &handler, void *ctx)
|
||||
return true;
|
||||
|
||||
#ifdef ENABLE_ID3TAG
|
||||
if (!is.LockRewind(IgnoreError()))
|
||||
try {
|
||||
is.LockRewind();
|
||||
} catch (const std::runtime_error &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tag_id3_scan(is, handler, ctx);
|
||||
#else
|
||||
|
@@ -19,8 +19,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Id3Load.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "Riff.hxx"
|
||||
#include "Aiff.hxx"
|
||||
@@ -31,8 +29,6 @@
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
static constexpr Domain id3_domain("id3");
|
||||
|
||||
static constexpr size_t ID3V1_SIZE = 128;
|
||||
|
||||
gcc_pure
|
||||
@@ -46,11 +42,8 @@ static long
|
||||
get_id3v2_footer_size(InputStream &is, offset_type offset)
|
||||
try {
|
||||
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
||||
if (!is.Seek(offset, IgnoreError()))
|
||||
return 0;
|
||||
|
||||
if (!is.ReadFull(buf, sizeof(buf), IgnoreError()))
|
||||
return 0;
|
||||
is.Seek(offset);
|
||||
is.ReadFull(buf, sizeof(buf));
|
||||
|
||||
return id3_tag_query(buf, sizeof(buf));
|
||||
} catch (const std::runtime_error &) {
|
||||
@@ -61,8 +54,7 @@ static UniqueId3Tag
|
||||
ReadId3Tag(InputStream &is)
|
||||
try {
|
||||
id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
|
||||
if (!is.ReadFull(query_buffer, sizeof(query_buffer), IgnoreError()))
|
||||
return nullptr;
|
||||
is.ReadFull(query_buffer, sizeof(query_buffer));
|
||||
|
||||
/* Look for a tag header */
|
||||
long tag_size = id3_tag_query(query_buffer, sizeof(query_buffer));
|
||||
@@ -82,9 +74,7 @@ try {
|
||||
|
||||
/* now read the remaining bytes */
|
||||
const size_t remaining = tag_size - sizeof(query_buffer);
|
||||
const size_t nbytes = is.Read(end, remaining, IgnoreError());
|
||||
if (nbytes != remaining)
|
||||
return nullptr;
|
||||
is.ReadFull(end, remaining);
|
||||
|
||||
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
||||
} catch (const std::runtime_error &) {
|
||||
@@ -94,8 +84,7 @@ try {
|
||||
static UniqueId3Tag
|
||||
ReadId3Tag(InputStream &is, offset_type offset)
|
||||
try {
|
||||
if (!is.Seek(offset, IgnoreError()))
|
||||
return nullptr;
|
||||
is.Seek(offset);
|
||||
|
||||
return ReadId3Tag(is);
|
||||
} catch (const std::runtime_error &) {
|
||||
@@ -106,9 +95,7 @@ static UniqueId3Tag
|
||||
ReadId3v1Tag(InputStream &is)
|
||||
try {
|
||||
id3_byte_t buffer[ID3V1_SIZE];
|
||||
|
||||
if (is.Read(buffer, ID3V1_SIZE, IgnoreError()) != ID3V1_SIZE)
|
||||
return nullptr;
|
||||
is.ReadFull(buffer, ID3V1_SIZE);
|
||||
|
||||
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
||||
} catch (const std::runtime_error &) {
|
||||
@@ -118,9 +105,7 @@ try {
|
||||
static UniqueId3Tag
|
||||
ReadId3v1Tag(InputStream &is, offset_type offset)
|
||||
try {
|
||||
if (!is.Seek(offset, IgnoreError()))
|
||||
return nullptr;
|
||||
|
||||
is.Seek(offset);
|
||||
return ReadId3v1Tag(is);
|
||||
} catch (const std::runtime_error &) {
|
||||
return nullptr;
|
||||
@@ -203,21 +188,19 @@ try {
|
||||
static UniqueId3Tag
|
||||
tag_id3_riff_aiff_load(InputStream &is)
|
||||
try {
|
||||
size_t size = riff_seek_id3(is);
|
||||
if (size == 0)
|
||||
size_t size;
|
||||
try {
|
||||
size = riff_seek_id3(is);
|
||||
} catch (const std::runtime_error &) {
|
||||
size = aiff_seek_id3(is);
|
||||
if (size == 0)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (size > 4 * 1024 * 1024)
|
||||
/* too large, don't allocate so much memory */
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]);
|
||||
if (!is.ReadFull(buffer.get(), size, IgnoreError())) {
|
||||
LogWarning(id3_domain, "Failed to read RIFF chunk");
|
||||
return nullptr;
|
||||
}
|
||||
is.ReadFull(buffer.get(), size);
|
||||
|
||||
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
||||
} catch (const std::runtime_error &) {
|
||||
|
@@ -21,10 +21,9 @@
|
||||
#include "Riff.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
#include "system/ByteOrder.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -45,31 +44,25 @@ riff_seek_id3(InputStream &is)
|
||||
{
|
||||
/* seek to the beginning and read the RIFF header */
|
||||
|
||||
Error error;
|
||||
if (!is.Rewind(error)) {
|
||||
LogError(error, "Failed to seek");
|
||||
return 0;
|
||||
}
|
||||
is.Rewind();
|
||||
|
||||
riff_header header;
|
||||
if (!is.ReadFull(&header, sizeof(header), IgnoreError()) ||
|
||||
memcmp(header.id, "RIFF", 4) != 0 ||
|
||||
is.ReadFull(&header, sizeof(header));
|
||||
if (memcmp(header.id, "RIFF", 4) != 0 ||
|
||||
(is.KnownSize() && FromLE32(header.size) > is.GetSize()))
|
||||
/* not a RIFF file */
|
||||
return 0;
|
||||
throw std::runtime_error("Not a RIFF file");
|
||||
|
||||
while (true) {
|
||||
/* read the chunk header */
|
||||
|
||||
riff_chunk_header chunk;
|
||||
if (!is.ReadFull(&chunk, sizeof(chunk), IgnoreError()))
|
||||
return 0;
|
||||
is.ReadFull(&chunk, sizeof(chunk));
|
||||
|
||||
size_t size = FromLE32(chunk.size);
|
||||
if (size > size_t(std::numeric_limits<int>::max()))
|
||||
/* too dangerous, bail out: possible integer
|
||||
underflow when casting to off_t */
|
||||
return 0;
|
||||
throw std::runtime_error("RIFF chunk is too large");
|
||||
|
||||
if (memcmp(chunk.id, "id3 ", 4) == 0 ||
|
||||
memcmp(chunk.id, "ID3 ", 4) == 0)
|
||||
@@ -80,7 +73,6 @@ riff_seek_id3(InputStream &is)
|
||||
/* pad byte */
|
||||
++size;
|
||||
|
||||
if (!is.Skip(size, IgnoreError()))
|
||||
return 0;
|
||||
is.Skip(size);
|
||||
}
|
||||
}
|
||||
|
@@ -32,9 +32,10 @@ class InputStream;
|
||||
/**
|
||||
* Seeks the RIFF file to the ID3 chunk.
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param is a locked #InputStream
|
||||
* @return the size of the ID3 chunk on success, or 0 if this is not a
|
||||
* RIFF file or no ID3 chunk was found
|
||||
* @return the size of the ID3 chunk
|
||||
*/
|
||||
size_t
|
||||
riff_seek_id3(InputStream &is);
|
||||
|
Reference in New Issue
Block a user