tag/ApeLoader: use class InputStream instead of FILE*

Prepare for APE tag support on userspace NFS/SMB/CIFS mounts.
This commit is contained in:
Max Kellermann 2016-02-22 13:31:03 +01:00
parent 8a86460b8f
commit cc5443c38e
5 changed files with 67 additions and 14 deletions

View File

@ -1882,10 +1882,15 @@ test_read_tags_SOURCES = test/read_tags.cxx \
test_ReadApeTags_LDADD = \ test_ReadApeTags_LDADD = \
$(TAG_LIBS) \ $(TAG_LIBS) \
$(INPUT_LIBS) \
$(ARCHIVE_LIBS) \
$(FS_LIBS) \ $(FS_LIBS) \
$(ICU_LDADD) \ $(ICU_LDADD) \
libsystem.a \
libutil.a libutil.a
test_ReadApeTags_SOURCES = test/ReadApeTags.cxx test_ReadApeTags_SOURCES = \
src/Log.cxx src/LogBackend.cxx \
test/ReadApeTags.cxx
if ENABLE_ID3TAG if ENABLE_ID3TAG
test_dump_rva2_LDADD = \ test_dump_rva2_LDADD = \

View File

@ -20,12 +20,16 @@
#include "config.h" #include "config.h"
#include "ApeLoader.hxx" #include "ApeLoader.hxx"
#include "system/ByteOrder.hxx" #include "system/ByteOrder.hxx"
#include "fs/FileSystem.hxx" #include "fs/Path.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "input/InputStream.hxx"
#include "input/LocalOpen.hxx"
#include "util/StringView.hxx" #include "util/StringView.hxx"
#include "util/Error.hxx"
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include <string.h> #include <string.h>
struct ape_footer { struct ape_footer {
@ -37,13 +41,18 @@ struct ape_footer {
unsigned char reserved[8]; unsigned char reserved[8];
}; };
static bool bool
ape_scan_internal(FILE *fp, ApeTagCallback callback) tag_ape_scan(InputStream &is, ApeTagCallback callback)
{ {
const ScopeLock protect(is.mutex);
if (!is.KnownSize() || !is.CheapSeeking())
return false;
/* determine if file has an apeV2 tag */ /* determine if file has an apeV2 tag */
struct ape_footer footer; struct ape_footer footer;
if (fseek(fp, -(long)sizeof(footer), SEEK_END) || if (!is.Seek(is.GetSize() - sizeof(footer), IgnoreError()) ||
fread(&footer, 1, sizeof(footer), fp) != sizeof(footer) || !is.ReadFull(&footer, sizeof(footer), IgnoreError()) ||
memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 || memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
FromLE32(footer.version) != 2000) FromLE32(footer.version) != 2000)
return false; return false;
@ -53,7 +62,7 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
if (remaining <= sizeof(footer) + 10 || if (remaining <= sizeof(footer) + 10 ||
/* refuse to load more than one megabyte of tag data */ /* refuse to load more than one megabyte of tag data */
remaining > 1024 * 1024 || remaining > 1024 * 1024 ||
fseek(fp, -(long)remaining, SEEK_END)) !is.Seek(is.GetSize() - remaining, IgnoreError()))
return false; return false;
/* read tag into buffer */ /* read tag into buffer */
@ -61,7 +70,7 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
assert(remaining > 10); assert(remaining > 10);
char *buffer = new char[remaining]; char *buffer = new char[remaining];
if (fread(buffer, 1, remaining, fp) != remaining) { if (!is.ReadFull(buffer, remaining, IgnoreError())) {
delete[] buffer; delete[] buffer;
return false; return false;
} }
@ -104,11 +113,13 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
bool bool
tag_ape_scan(Path path_fs, ApeTagCallback callback) tag_ape_scan(Path path_fs, ApeTagCallback callback)
{ {
FILE *fp = FOpen(path_fs, PATH_LITERAL("rb")); Mutex mutex;
if (fp == nullptr) Cond cond;
std::unique_ptr<InputStream> is(OpenLocalInputStream(path_fs, mutex,
cond, IgnoreError()));
if (!is)
return false; return false;
bool success = ape_scan_internal(fp, callback); return tag_ape_scan(*is, callback);
fclose(fp);
return success;
} }

View File

@ -28,10 +28,20 @@
struct StringView; struct StringView;
class Path; class Path;
class InputStream;
typedef std::function<bool(unsigned long flags, const char *key, typedef std::function<bool(unsigned long flags, const char *key,
StringView value)> ApeTagCallback; StringView value)> ApeTagCallback;
/**
* Scans the APE tag values from a file.
*
* @return false if the file could not be opened or if no APE tag is
* present
*/
bool
tag_ape_scan(InputStream &is, ApeTagCallback callback);
/** /**
* Scans the APE tag values from a file. * Scans the APE tag values from a file.
* *

View File

@ -105,6 +105,23 @@ tag_ape_import_item(unsigned long flags,
return true; return true;
} }
bool
tag_ape_scan2(InputStream &is,
const struct tag_handler *handler, void *handler_ctx)
{
bool recognized = false;
auto callback = [handler, handler_ctx, &recognized]
(unsigned long flags, const char *key,
StringView value) {
recognized |= tag_ape_import_item(flags, key, value,
handler, handler_ctx);
return true;
};
return tag_ape_scan(is, callback) && recognized;
}
bool bool
tag_ape_scan2(Path path_fs, tag_ape_scan2(Path path_fs,
const struct tag_handler *handler, void *handler_ctx) const struct tag_handler *handler, void *handler_ctx)

View File

@ -23,10 +23,20 @@
#include "TagTable.hxx" #include "TagTable.hxx"
class Path; class Path;
class InputStream;
struct tag_handler; struct tag_handler;
extern const struct tag_table ape_tags[]; extern const struct tag_table ape_tags[];
/**
* Scan the APE tags of a stream.
*
* @param path_fs the path of the file in filesystem encoding
*/
bool
tag_ape_scan2(InputStream &is,
const tag_handler *handler, void *handler_ctx);
/** /**
* Scan the APE tags of a file. * Scan the APE tags of a file.
* *