This allow to use these scanners for remote InputStream like SMB and NFS.
---
 src/tag/Aiff.cxx      |  29 +++++----------
 src/tag/Aiff.hxx      |   4 +-
 src/tag/ApeLoader.cxx |  43 +++++++++++++++++-----
 src/tag/ApeLoader.hxx |  11 ++++++
 src/tag/ApeTag.cxx    |  19 ++++++++++
 src/tag/ApeTag.hxx    |  10 +++++
 src/tag/Riff.cxx      |  29 +++++----------
 src/tag/Riff.hxx      |   4 +-
 src/tag/TagId3.cxx    | 100 ++++++++++++++++++++++++++++++++++----------------
 src/tag/TagId3.hxx    |  11 ++++--
 10 files changed, 172 insertions(+), 88 deletions(-)

diff --git a/src/tag/Aiff.cxx b/src/tag/Aiff.cxx
index 7235b76..c4a2315 100644
--- a/src/tag/Aiff.cxx
+++ b/src/tag/Aiff.cxx
@@ -20,6 +20,7 @@
 #include "config.h" /* must be first for large file support */
 #include "Aiff.hxx"
 #include "util/Domain.hxx"
+#include "util/Error.hxx"
 #include "system/ByteOrder.hxx"
 #include "Log.hxx"
 
@@ -43,28 +44,16 @@ struct aiff_chunk_header {
 };
 
 size_t
-aiff_seek_id3(FILE *file)
+aiff_seek_id3(InputStream &is)
 {
-       /* determine the file size */
-
-       struct stat st;
-       if (fstat(fileno(file), &st) < 0) {
-               LogErrno(aiff_domain, "Failed to stat file descriptor");
-               return 0;
-       }
-
        /* seek to the beginning and read the AIFF header */
-
-       if (fseek(file, 0, SEEK_SET) != 0) {
-               LogErrno(aiff_domain, "Failed to seek");
-               return 0;
-       }
+       is.Rewind(IgnoreError());
 
        aiff_header header;
-       size_t size = fread(&header, sizeof(header), 1, file);
-       if (size != 1 ||
+       size_t size = is.ReadFull(&header, sizeof(header), IgnoreError());
+       if (size != sizeof(header) ||
            memcmp(header.id, "FORM", 4) != 0 ||
-           FromBE32(header.size) > (uint32_t)st.st_size ||
+           FromBE32(header.size) > is.GetSize() ||
            (memcmp(header.format, "AIFF", 4) != 0 &&
             memcmp(header.format, "AIFC", 4) != 0))
                /* not a AIFF file */
@@ -74,8 +63,8 @@ aiff_seek_id3(FILE *file)
                /* read the chunk header */
 
                aiff_chunk_header chunk;
-               size = fread(&chunk, sizeof(chunk), 1, file);
-               if (size != 1)
+               size = is.ReadFull(&chunk, sizeof(chunk), IgnoreError());
+               if (size != sizeof(chunk))
                        return 0;
 
                size = FromBE32(chunk.size);
@@ -92,7 +81,7 @@ aiff_seek_id3(FILE *file)
                        /* found it! */
                        return size;
 
-               if (fseek(file, size, SEEK_CUR) != 0)
+               if (!is.Seek(size + is.GetOffset(), IgnoreError()))
                        return 0;
        }
 }
diff --git a/src/tag/Aiff.hxx b/src/tag/Aiff.hxx
index f9b11b5..238e5ba 100644
--- a/src/tag/Aiff.hxx
+++ b/src/tag/Aiff.hxx
@@ -28,6 +28,8 @@
 #include <stddef.h>
 #include <stdio.h>
 
+#include "input/InputStream.hxx"
+
 /**
  * Seeks the AIFF file to the ID3 chunk.
  *
@@ -35,6 +37,6 @@
  * AIFF file or no ID3 chunk was found
  */
 size_t
-aiff_seek_id3(FILE *file);
+aiff_seek_id3(InputStream &is);
 
 #endif
diff --git a/src/tag/ApeLoader.cxx b/src/tag/ApeLoader.cxx
index 8c89f34..4e255b6 100644
--- a/src/tag/ApeLoader.cxx
+++ b/src/tag/ApeLoader.cxx
@@ -21,6 +21,9 @@
 #include "ApeLoader.hxx"
 #include "system/ByteOrder.hxx"
 #include "fs/FileSystem.hxx"
+#include "util/Error.hxx"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
 
 #include <stdint.h>
 #include <assert.h>
@@ -36,31 +39,46 @@ struct ape_footer {
        unsigned char reserved[8];
 };
 
-static bool
-ape_scan_internal(FILE *fp, ApeTagCallback callback)
+bool
+tag_ape_scan(InputStream &is, ApeTagCallback callback)
 {
+       is.Lock();
+       if (!is.KnownSize() || !is.IsSeekable())
+       {
+               is.Unlock();
+               return false;
+       }
        /* determine if file has an apeV2 tag */
        struct ape_footer footer;
-       if (fseek(fp, -(long)sizeof(footer), SEEK_END) ||
-           fread(&footer, 1, sizeof(footer), fp) != sizeof(footer) ||
+       if (!is.Seek(is.GetSize() - (long)sizeof(footer), IgnoreError()) ||
+           is.ReadFull(&footer, sizeof(footer), IgnoreError()) != 
sizeof(footer) ||
            memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
            FromLE32(footer.version) != 2000)
+       {
+               is.Rewind(IgnoreError());
+               is.Unlock();
                return false;
+       }
 
        /* find beginning of ape tag */
        size_t remaining = FromLE32(footer.length);
        if (remaining <= sizeof(footer) + 10 ||
            /* refuse to load more than one megabyte of tag data */
            remaining > 1024 * 1024 ||
-           fseek(fp, -(long)remaining, SEEK_END))
+           !is.Seek(is.GetSize() - (long)remaining, IgnoreError())) {
+               is.Rewind(IgnoreError());
+               is.Unlock();
                return false;
+       }
 
        /* read tag into buffer */
        remaining -= sizeof(footer);
        assert(remaining > 10);
 
        char *buffer = new char[remaining];
-       if (fread(buffer, 1, remaining, fp) != remaining) {
+       if (is.ReadFull(buffer, remaining, IgnoreError()) != remaining) {
+               is.Rewind(IgnoreError());
+               is.Unlock();
                delete[] buffer;
                return false;
        }
@@ -96,6 +114,8 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
                remaining -= size;
        }
 
+       is.Rewind(IgnoreError());
+       is.Unlock();
        delete[] buffer;
        return true;
 }
@@ -103,11 +123,14 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
 bool
 tag_ape_scan(Path path_fs, ApeTagCallback callback)
 {
-       FILE *fp = FOpen(path_fs, PATH_LITERAL("rb"));
-       if (fp == nullptr)
+       Mutex mutex;
+       Cond cond;
+       InputStream *is = InputStream::OpenReady(path_fs.c_str(), mutex,
+                                                cond, IgnoreError());
+       if (is == nullptr)
                return false;
 
-       bool success = ape_scan_internal(fp, callback);
-       fclose(fp);
+       bool success = tag_ape_scan(*is, callback);
+       delete is;
        return success;
 }
diff --git a/src/tag/ApeLoader.hxx b/src/tag/ApeLoader.hxx
index 1bdfe69..34ecf4b 100644
--- a/src/tag/ApeLoader.hxx
+++ b/src/tag/ApeLoader.hxx
@@ -21,6 +21,7 @@
 #define MPD_APE_LOADER_HXX
 
 #include "check.h"
+#include "input/InputStream.hxx"
 
 #include <functional>
 
@@ -35,6 +36,16 @@ typedef std::function<bool(unsigned long flags, const char 
*key,
 /**
  * Scans the APE tag values from a file.
  *
+ * @param is the input stream to read from
+ * @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.
+ *
  * @param path_fs the path of the file in filesystem encoding
  * @return false if the file could not be opened or if no APE tag is
  * present
diff --git a/src/tag/ApeTag.cxx b/src/tag/ApeTag.cxx
index 49ae7a0..dbbd034 100644
--- a/src/tag/ApeTag.cxx
+++ b/src/tag/ApeTag.cxx
@@ -104,6 +104,25 @@ tag_ape_import_item(unsigned long flags,
 }
 
 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,
+                const char *value,
+                size_t value_length) {
+               recognized |= tag_ape_import_item(flags, key, value,
+                                                 value_length,
+                                                 handler, handler_ctx);
+               return true;
+       };
+
+       return tag_ape_scan(is, callback) && recognized;
+}
+
+bool
 tag_ape_scan2(Path path_fs,
              const struct tag_handler *handler, void *handler_ctx)
 {
diff --git a/src/tag/ApeTag.hxx b/src/tag/ApeTag.hxx
index 20d1d7b..7e5fa65 100644
--- a/src/tag/ApeTag.hxx
+++ b/src/tag/ApeTag.hxx
@@ -20,6 +20,7 @@
 #ifndef MPD_APE_TAG_HXX
 #define MPD_APE_TAG_HXX
 
+#include "input/InputStream.hxx"
 #include "TagTable.hxx"
 
 class Path;
@@ -30,6 +31,15 @@ extern const struct tag_table ape_tags[];
 /**
  * Scan the APE tags of a file.
  *
+ * @param is the locked input stream to read from
+ */
+bool
+tag_ape_scan2(InputStream &is,
+             const tag_handler *handler, void *handler_ctx);
+
+/**
+ * Scan the APE tags of a file.
+ *
  * @param path_fs the path of the file in filesystem encoding
  */
 bool
diff --git a/src/tag/Riff.cxx b/src/tag/Riff.cxx
index 7412258..1a29583 100644
--- a/src/tag/Riff.cxx
+++ b/src/tag/Riff.cxx
@@ -20,6 +20,7 @@
 #include "config.h" /* must be first for large file support */
 #include "Riff.hxx"
 #include "util/Domain.hxx"
+#include "util/Error.hxx"
 #include "system/ByteOrder.hxx"
 #include "Log.hxx"
 
@@ -43,28 +44,16 @@ struct riff_chunk_header {
 };
 
 size_t
-riff_seek_id3(FILE *file)
+riff_seek_id3(InputStream &is)
 {
-       /* determine the file size */
-
-       struct stat st;
-       if (fstat(fileno(file), &st) < 0) {
-               LogErrno(riff_domain, "Failed to stat file descriptor");
-               return 0;
-       }
-
        /* seek to the beginning and read the RIFF header */
-
-       if (fseek(file, 0, SEEK_SET) != 0) {
-               LogErrno(riff_domain, "Failed to seek");
-               return 0;
-       }
+       is.Rewind(IgnoreError());
 
        riff_header header;
-       size_t size = fread(&header, sizeof(header), 1, file);
-       if (size != 1 ||
+       size_t size = is.ReadFull(&header, sizeof(header), IgnoreError());
+       if (size != sizeof(header) ||
            memcmp(header.id, "RIFF", 4) != 0 ||
-           FromLE32(header.size) > (uint32_t)st.st_size)
+           FromLE32(header.size) > is.GetSize())
                /* not a RIFF file */
                return 0;
 
@@ -72,8 +61,8 @@ riff_seek_id3(FILE *file)
                /* read the chunk header */
 
                riff_chunk_header chunk;
-               size = fread(&chunk, sizeof(chunk), 1, file);
-               if (size != 1)
+               size = is.ReadFull(&chunk, sizeof(chunk), IgnoreError());
+               if (size != sizeof(chunk))
                        return 0;
 
                size = FromLE32(chunk.size);
@@ -91,7 +80,7 @@ riff_seek_id3(FILE *file)
                        /* found it! */
                        return size;
 
-               if (fseek(file, size, SEEK_CUR) != 0)
+               if (!is.Seek(size + is.GetOffset(), IgnoreError()))
                        return 0;
        }
 }
diff --git a/src/tag/Riff.hxx b/src/tag/Riff.hxx
index b157168..5deabcb 100644
--- a/src/tag/Riff.hxx
+++ b/src/tag/Riff.hxx
@@ -28,6 +28,8 @@
 #include <stddef.h>
 #include <stdio.h>
 
+#include "input/InputStream.hxx"
+
 /**
  * Seeks the RIFF file to the ID3 chunk.
  *
@@ -35,6 +37,6 @@
  * RIFF file or no ID3 chunk was found
  */
 size_t
-riff_seek_id3(FILE *file);
+riff_seek_id3(InputStream &is);
 
 #endif
diff --git a/src/tag/TagId3.cxx b/src/tag/TagId3.cxx
index 98f85da..32443e9 100644
--- a/src/tag/TagId3.cxx
+++ b/src/tag/TagId3.cxx
@@ -32,6 +32,8 @@
 #include "Aiff.hxx"
 #include "fs/Path.hxx"
 #include "fs/FileSystem.hxx"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
 
 #ifdef HAVE_GLIB
 #include <glib.h>
@@ -394,28 +396,46 @@ tag_id3_import(struct id3_tag *tag)
 }
 
 static size_t
-fill_buffer(void *buf, size_t size, FILE *stream, long offset, int whence)
+fill_buffer(void *buf, size_t size, InputStream &is, long offset, int whence)
 {
-       if (fseek(stream, offset, whence) != 0) return 0;
-       return fread(buf, 1, size, stream);
+       offset_type absolute_offset;
+       switch (whence)
+       {
+       case SEEK_SET:
+               absolute_offset = offset;
+               break;
+       case SEEK_CUR:
+               absolute_offset = offset + is.GetOffset();
+               break;
+       case SEEK_END:
+               absolute_offset = is.GetSize() + offset;
+               break;
+       default:
+               assert(false);
+               gcc_unreachable();
+       }
+       if (!is.Seek(absolute_offset, IgnoreError()))
+               return 0;
+
+       return is.ReadFull(buf, size, IgnoreError());
 }
 
 static long
-get_id3v2_footer_size(FILE *stream, long offset, int whence)
+get_id3v2_footer_size(InputStream &is, long offset, int whence)
 {
        id3_byte_t buf[ID3_TAG_QUERYSIZE];
-       size_t bufsize = fill_buffer(buf, ID3_TAG_QUERYSIZE, stream, offset, 
whence);
+       size_t bufsize = fill_buffer(buf, ID3_TAG_QUERYSIZE, is, offset, 
whence);
        if (bufsize == 0) return 0;
        return id3_tag_query(buf, bufsize);
 }
 
 static struct id3_tag *
-tag_id3_read(FILE *stream, long offset, int whence)
+tag_id3_read(InputStream &is, long offset, int whence)
 {
        /* It's ok if we get less than we asked for */
        id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
        size_t query_buffer_size = fill_buffer(query_buffer, ID3_TAG_QUERYSIZE,
-                                              stream, offset, whence);
+                                              is, offset, whence);
        if (query_buffer_size <= 0)
                return nullptr;
 
@@ -426,7 +446,7 @@ tag_id3_read(FILE *stream, long offset, int whence)
        /* Found a tag.  Allocate a buffer and read it in. */
        id3_byte_t *tag_buffer = new id3_byte_t[tag_size];
        int tag_buffer_size = fill_buffer(tag_buffer, tag_size,
-                                         stream, offset, whence);
+                                         is, offset, whence);
        if (tag_buffer_size < tag_size) {
                delete[] tag_buffer;
                return nullptr;
@@ -438,9 +458,9 @@ tag_id3_read(FILE *stream, long offset, int whence)
 }
 
 static struct id3_tag *
-tag_id3_find_from_beginning(FILE *stream)
+tag_id3_find_from_beginning(InputStream &is)
 {
-       id3_tag *tag = tag_id3_read(stream, 0, SEEK_SET);
+       id3_tag *tag = tag_id3_read(is, 0, SEEK_SET);
        if (!tag) {
                return nullptr;
        } else if (tag_is_id3v1(tag)) {
@@ -458,7 +478,7 @@ tag_id3_find_from_beginning(FILE *stream)
                        break;
 
                /* Get the tag specified by the SEEK frame */
-               id3_tag *seektag = tag_id3_read(stream, seek, SEEK_CUR);
+               id3_tag *seektag = tag_id3_read(is, seek, SEEK_CUR);
                if (!seektag || tag_is_id3v1(seektag))
                        break;
 
@@ -471,18 +491,18 @@ tag_id3_find_from_beginning(FILE *stream)
 }
 
 static struct id3_tag *
-tag_id3_find_from_end(FILE *stream)
+tag_id3_find_from_end(InputStream &is)
 {
        /* Get an id3v1 tag from the end of file for later use */
-       id3_tag *v1tag = tag_id3_read(stream, -128, SEEK_END);
+       id3_tag *v1tag = tag_id3_read(is, -128, SEEK_END);
 
        /* Get the id3v2 tag size from the footer (located before v1tag) */
-       int tagsize = get_id3v2_footer_size(stream, (v1tag ? -128 : 0) - 10, 
SEEK_END);
+       int tagsize = get_id3v2_footer_size(is, (v1tag ? -128 : 0) - 10, 
SEEK_END);
        if (tagsize >= 0)
                return v1tag;
 
        /* Get the tag which the footer belongs to */
-       id3_tag *tag = tag_id3_read(stream, tagsize, SEEK_CUR);
+       id3_tag *tag = tag_id3_read(is, tagsize, SEEK_CUR);
        if (!tag)
                return v1tag;
 
@@ -493,11 +513,11 @@ tag_id3_find_from_end(FILE *stream)
 }
 
 static struct id3_tag *
-tag_id3_riff_aiff_load(FILE *file)
+tag_id3_riff_aiff_load(InputStream &is)
 {
-       size_t size = riff_seek_id3(file);
+       size_t size = riff_seek_id3(is);
        if (size == 0)
-               size = aiff_seek_id3(file);
+               size = aiff_seek_id3(is);
        if (size == 0)
                return nullptr;
 
@@ -506,8 +526,8 @@ tag_id3_riff_aiff_load(FILE *file)
                return nullptr;
 
        id3_byte_t *buffer = new id3_byte_t[size];
-       size_t ret = fread(buffer, size, 1, file);
-       if (ret != 1) {
+       size_t ret = is.ReadFull(buffer, size, IgnoreError());
+       if (ret != size) {
                LogWarning(id3_domain, "Failed to read RIFF chunk");
                delete[] buffer;
                return nullptr;
@@ -519,31 +539,31 @@ tag_id3_riff_aiff_load(FILE *file)
 }
 
 struct id3_tag *
-tag_id3_load(Path path_fs, Error &error)
+tag_id3_load(InputStream &is, Error &error)
 {
-       FILE *file = FOpen(path_fs, PATH_LITERAL("rb"));
-       if (file == nullptr) {
-               error.FormatErrno("Failed to open file %s", path_fs.c_str());
+       is.Lock();
+       if (!is.KnownSize() || !is.IsSeekable())
+       {
+               is.Unlock();
                return nullptr;
        }
-
-       struct id3_tag *tag = tag_id3_find_from_beginning(file);
+       struct id3_tag *tag = tag_id3_find_from_beginning(is);
        if (tag == nullptr) {
-               tag = tag_id3_riff_aiff_load(file);
+               tag = tag_id3_riff_aiff_load(is);
                if (tag == nullptr)
-                       tag = tag_id3_find_from_end(file);
+                       tag = tag_id3_find_from_end(is);
        }
-
-       fclose(file);
+       is.Rewind(error);
+       is.Unlock();
        return tag;
 }
 
 bool
-tag_id3_scan(Path path_fs,
+tag_id3_scan(InputStream &is,
             const struct tag_handler *handler, void *handler_ctx)
 {
        Error error;
-       struct id3_tag *tag = tag_id3_load(path_fs, error);
+       struct id3_tag *tag = tag_id3_load(is, error);
        if (tag == nullptr) {
                if (error.IsDefined())
                        LogError(error);
@@ -555,3 +575,19 @@ tag_id3_scan(Path path_fs,
        id3_tag_delete(tag);
        return true;
 }
+
+bool
+tag_id3_scan(Path path_fs,
+            const struct tag_handler *handler, void *handler_ctx)
+{
+    Mutex mutex;
+    Cond cond;
+    InputStream *is = InputStream::OpenReady(path_fs.c_str(), mutex,
+                                             cond, IgnoreError());
+    if (is == nullptr)
+            return false;
+
+    bool success = tag_id3_scan(*is, handler, handler_ctx);
+    delete is;
+    return success;
+}
diff --git a/src/tag/TagId3.hxx b/src/tag/TagId3.hxx
index 94dfb17..d3b987b 100644
--- a/src/tag/TagId3.hxx
+++ b/src/tag/TagId3.hxx
@@ -22,6 +22,7 @@
 
 #include "check.h"
 #include "Compiler.h"
+#include "input/InputStream.hxx"
 
 class Path;
 struct tag_handler;
@@ -32,6 +33,10 @@ class Error;
 #ifdef ENABLE_ID3TAG
 
 bool
+tag_id3_scan(InputStream &is,
+            const tag_handler *handler, void *handler_ctx);
+
+bool
 tag_id3_scan(Path path_fs,
             const tag_handler *handler, void *handler_ctx);
 
@@ -46,7 +51,7 @@ tag_id3_import(id3_tag *);
  * Error will be set)
  */
 struct id3_tag *
-tag_id3_load(Path path_fs, Error &error);
+tag_id3_load(InputStream &is, Error &error);
 
 /**
  * Import all tags from the provided id3_tag *tag
@@ -58,10 +63,8 @@ scan_id3_tag(id3_tag *tag,
 
 #else
 
-#include "fs/Path.hxx"
-
 static inline bool
-tag_id3_scan(gcc_unused Path path_fs,
+tag_id3_scan(gcc_unused InputStream &is,
             gcc_unused const tag_handler *handler,
             gcc_unused void *handler_ctx)
 {
-- 
2.1.4

_______________________________________________
mpd-devel mailing list
mpd-devel@musicpd.org
http://mailman.blarg.de/listinfo/mpd-devel

Reply via email to