changeset 2065:598564ddc4e9 trunk

[svn] - no, this is not going to work
author nenolod
date Thu, 07 Dec 2006 00:22:55 -0800
parents 230e36118438
children 4f750b8d0127
files ChangeLog taglib-vfs/Makefile taglib-vfs/tvfsfile.cxx taglib-vfs/tvfsfile.h
diffstat 4 files changed, 10 insertions(+), 780 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Dec 07 00:12:31 2006 -0800
+++ b/ChangeLog	Thu Dec 07 00:22:55 2006 -0800
@@ -1,3 +1,13 @@
+2006-12-07 08:12:31 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [3131]
+  - add work in progress TagLib::TagVFSFile class.
+  
+  trunk/taglib-vfs/Makefile     |   32 ++
+  trunk/taglib-vfs/tvfsfile.cxx |  501 ++++++++++++++++++++++++++++++++++++++++++
+  trunk/taglib-vfs/tvfsfile.h   |  247 ++++++++++++++++++++
+  3 files changed, 780 insertions(+)
+
+
 2006-12-06 11:41:04 +0000  William Pitcock <nenolod@nenolod.net>
   revision [3129]
   - playlist_scan_thread_is_going should not be TRUE if the playlist is 
--- a/taglib-vfs/Makefile	Thu Dec 07 00:12:31 2006 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-include ../mk/rules.mk
-include ../mk/init.mk
-
-beepincludedir = $(includedir)/audacious
-
-OBJECTIVE_LIBS = libtagvfs.so
-
-LDFLAGS += $(AUDLDFLAGS)
-
-CXXFLAGS += $(LIBLDFLAGS) \
-	$(GTK_CFLAGS)      \
-	$(LIBGLADE_CFLAGS) \
-	$(BEEP_DEFINES)    \
-	$(ARCH_DEFINES)    \
-	-D_AUDACIOUS_CORE \
-	-I..    \
-	-I../intl \
-	-I/usr/include/taglib
-
-HEADERS = \
-	tvfsfile.h
-
-SOURCES = tvfsfile.cxx
-
-OBJECTS = ${SOURCES:.cxx=.o}
-
-beepinclude_HEADERS = plugin.h output.h input.h
-
-desktop_DATA = audacious.desktop
-desktopdir = $(datadir)/applications
-
-include ../mk/objective.mk
--- a/taglib-vfs/tvfsfile.cxx	Thu Dec 07 00:12:31 2006 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,501 +0,0 @@
-/***************************************************************************
-    copyright            : (C) 2002, 2003 by Scott Wheeler
-    email                : wheeler@kde.org
- ***************************************************************************/
-
-/***************************************************************************
- *   This library is free software; you can redistribute it and/or modify  *
- *   it  under the terms of the GNU Lesser General Public License version  *
- *   2.1 as published by the Free Software Foundation.                     *
- *                                                                         *
- *   This library is distributed in the hope that it will be useful, but   *
- *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
- *   Lesser General Public License for more details.                       *
- *                                                                         *
- *   You should have received a copy of the GNU Lesser General Public      *
- *   License along with this library; if not, write to the Free Software   *
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
- *   USA                                                                   *
- ***************************************************************************/
-
-#include "tvfsfile.h"
-#include "tstring.h"
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "libaudacious/vfs.h"
-
-using namespace TagLib;
-
-class TagVFSFile::TagVFSFilePrivate
-{
-public:
-  TagVFSFilePrivate(const char *fileName) :
-    file(0),
-    name(fileName),
-    readOnly(true),
-    valid(true),
-    size(0)
-    {}
-
-  ~TagVFSFilePrivate()
-  {
-    free((void *)name);
-  }
-
-  VFSFile *file;
-  const char *name;
-  bool readOnly;
-  bool valid;
-  ulong size;
-  static const uint bufferSize = 1024;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// public members
-////////////////////////////////////////////////////////////////////////////////
-
-TagVFSFile::TagVFSFile(const char *file)
-{
-  d = new TagVFSFilePrivate(::strdup(file));
-
-  d->readOnly = !isWritable(file);
-  d->file = vfs_fopen(file, d->readOnly ? "r" : "r+");
-
-#if 0
-  if(!d->file)
-    puts("Could not open file " + String(file));
-#endif
-}
-
-TagVFSFile::~TagVFSFile()
-{
-  if(d->file)
-    vfs_fclose(d->file);
-  delete d;
-}
-
-const char *TagVFSFile::name() const
-{
-  return d->name;
-}
-
-ByteVector TagVFSFile::readBlock(ulong length)
-{
-  if(!d->file) {
-    puts("File::readBlock() -- Invalid File");
-    return ByteVector::null;
-  }
-
-  if(length > TagVFSFilePrivate::bufferSize &&
-     length > ulong(TagVFSFile::length()))
-  {
-    length = TagVFSFile::length();
-  }
-
-  ByteVector v(static_cast<uint>(length));
-  const int count = vfs_fread(v.data(), sizeof(char), length, d->file);
-  v.resize(count);
-  return v;
-}
-
-void TagVFSFile::writeBlock(const ByteVector &data)
-{
-  if(!d->file)
-    return;
-
-  if(d->readOnly) {
-    puts("File::writeBlock() -- attempted to write to a file that is not writable");
-    return;
-  }
-
-  vfs_fwrite(data.data(), sizeof(char), data.size(), d->file);
-}
-
-long TagVFSFile::find(const ByteVector &pattern, long fromOffset, const ByteVector &before)
-{
-  if(!d->file || pattern.size() > d->bufferSize)
-      return -1;
-
-  // The position in the file that the current buffer starts at.
-
-  long bufferOffset = fromOffset;
-  ByteVector buffer;
-
-  // These variables are used to keep track of a partial match that happens at
-  // the end of a buffer.
-
-  int previousPartialMatch = -1;
-  int beforePreviousPartialMatch = -1;
-
-  // Save the location of the current read pointer.  We will restore the
-  // position using seek() before all returns.
-
-  long originalPosition = tell();
-
-  // Start the search at the offset.
-
-  seek(fromOffset);
-
-  // This loop is the crux of the find method.  There are three cases that we
-  // want to account for:
-  //
-  // (1) The previously searched buffer contained a partial match of the search
-  // pattern and we want to see if the next one starts with the remainder of
-  // that pattern.
-  //
-  // (2) The search pattern is wholly contained within the current buffer.
-  //
-  // (3) The current buffer ends with a partial match of the pattern.  We will
-  // note this for use in the next itteration, where we will check for the rest
-  // of the pattern.
-  //
-  // All three of these are done in two steps.  First we check for the pattern
-  // and do things appropriately if a match (or partial match) is found.  We
-  // then check for "before".  The order is important because it gives priority
-  // to "real" matches.
-
-  for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {
-
-    // (1) previous partial match
-
-    if(previousPartialMatch >= 0 && int(d->bufferSize) > previousPartialMatch) {
-      const int patternOffset = (d->bufferSize - previousPartialMatch);
-      if(buffer.containsAt(pattern, 0, patternOffset)) {
-        seek(originalPosition);
-        return bufferOffset - d->bufferSize + previousPartialMatch;
-      }
-    }
-
-    if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(d->bufferSize) > beforePreviousPartialMatch) {
-      const int beforeOffset = (d->bufferSize - beforePreviousPartialMatch);
-      if(buffer.containsAt(before, 0, beforeOffset)) {
-        seek(originalPosition);
-        return -1;
-      }
-    }
-
-    // (2) pattern contained in current buffer
-
-    long location = buffer.find(pattern);
-    if(location >= 0) {
-      seek(originalPosition);
-      return bufferOffset + location;
-    }
-
-    if(!before.isNull() && buffer.find(before) >= 0) {
-      seek(originalPosition);
-      return -1;
-    }
-
-    // (3) partial match
-
-    previousPartialMatch = buffer.endsWithPartialMatch(pattern);
-
-    if(!before.isNull())
-      beforePreviousPartialMatch = buffer.endsWithPartialMatch(before);
-
-    bufferOffset += d->bufferSize;
-  }
-
-  // Since we hit the end of the file, reset the status before continuing.
-
-  clear();
-
-  seek(originalPosition);
-
-  return -1;
-}
-
-
-long TagVFSFile::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before)
-{
-  if(!d->file || pattern.size() > d->bufferSize)
-      return -1;
-
-  // The position in the file that the current buffer starts at.
-
-  ByteVector buffer;
-
-  // These variables are used to keep track of a partial match that happens at
-  // the end of a buffer.
-
-  /*
-  int previousPartialMatch = -1;
-  int beforePreviousPartialMatch = -1;
-  */
-
-  // Save the location of the current read pointer.  We will restore the
-  // position using seek() before all returns.
-
-  long originalPosition = tell();
-
-  // Start the search at the offset.
-
-  long bufferOffset;
-  if(fromOffset == 0) {
-    seek(-1 * int(d->bufferSize), End);
-    bufferOffset = tell();
-  }
-  else {
-    seek(fromOffset + -1 * int(d->bufferSize), Beginning);
-    bufferOffset = tell();    
-  }
-
-  // See the notes in find() for an explanation of this algorithm.
-
-  for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {
-
-    // TODO: (1) previous partial match
-
-    // (2) pattern contained in current buffer
-
-    long location = buffer.rfind(pattern);
-    if(location >= 0) {
-      seek(originalPosition);
-      return bufferOffset + location;
-    }
-
-    if(!before.isNull() && buffer.find(before) >= 0) {
-      seek(originalPosition);
-      return -1;
-    }
-
-    // TODO: (3) partial match
-
-    bufferOffset -= d->bufferSize;
-    seek(bufferOffset);
-  }
-
-  // Since we hit the end of the file, reset the status before continuing.
-
-  clear();
-
-  seek(originalPosition);
-
-  return -1;
-}
-
-void TagVFSFile::insert(const ByteVector &data, ulong start, ulong replace)
-{
-  if(!d->file)
-    return;
-
-  if(data.size() == replace) {
-    seek(start);
-    writeBlock(data);
-    return;
-  }
-  else if(data.size() < replace) {
-      seek(start);
-      writeBlock(data);
-      removeBlock(start + data.size(), replace - data.size());
-      return;
-  }
-
-  // Woohoo!  Faster (about 20%) than id3lib at last.  I had to get hardcore
-  // and avoid TagLib's high level API for rendering just copying parts of
-  // the file that don't contain tag data.
-  //
-  // Now I'll explain the steps in this ugliness:
-
-  // First, make sure that we're working with a buffer that is longer than
-  // the *differnce* in the tag sizes.  We want to avoid overwriting parts
-  // that aren't yet in memory, so this is necessary.
-
-  ulong bufferLength = bufferSize();
-  while(data.size() - replace > bufferLength)
-    bufferLength += bufferSize();
-
-  // Set where to start the reading and writing.
-
-  long readPosition = start + replace;
-  long writePosition = start;
-
-  ByteVector buffer;
-  ByteVector aboutToOverwrite(static_cast<uint>(bufferLength));
-
-  // This is basically a special case of the loop below.  Here we're just
-  // doing the same steps as below, but since we aren't using the same buffer
-  // size -- instead we're using the tag size -- this has to be handled as a
-  // special case.  We're also using File::writeBlock() just for the tag.
-  // That's a bit slower than using char *'s so, we're only doing it here.
-
-  seek(readPosition);
-  int bytesRead = vfs_fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
-  readPosition += bufferLength;
-
-  seek(writePosition);
-  writeBlock(data);
-  writePosition += data.size();
-
-  buffer = aboutToOverwrite;
-
-  // Ok, here's the main loop.  We want to loop until the read fails, which
-  // means that we hit the end of the file.
-
-  while(bytesRead != 0) {
-
-    // Seek to the current read position and read the data that we're about
-    // to overwrite.  Appropriately increment the readPosition.
-
-    seek(readPosition);
-    bytesRead = vfs_fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
-    aboutToOverwrite.resize(bytesRead);
-    readPosition += bufferLength;
-
-    // Check to see if we just read the last block.  We need to call clear()
-    // if we did so that the last write succeeds.
-
-    if(ulong(bytesRead) < bufferLength)
-      clear();
-
-    // Seek to the write position and write our buffer.  Increment the
-    // writePosition.
-
-    seek(writePosition);
-    vfs_fwrite(buffer.data(), sizeof(char), bufferLength, d->file);
-    writePosition += bufferLength;
-
-    // Make the current buffer the data that we read in the beginning.
-
-    buffer = aboutToOverwrite;
-
-    // Again, we need this for the last write.  We don't want to write garbage
-    // at the end of our file, so we need to set the buffer size to the amount
-    // that we actually read.
-
-    bufferLength = bytesRead;
-  }
-}
-
-void TagVFSFile::removeBlock(ulong start, ulong length)
-{
-  if(!d->file)
-    return;
-
-  ulong bufferLength = bufferSize();
-
-  long readPosition = start + length;
-  long writePosition = start;
-
-  ByteVector buffer(static_cast<uint>(bufferLength));
-
-  ulong bytesRead = true;
-
-  while(bytesRead != 0) {
-    seek(readPosition);
-    bytesRead = vfs_fread(buffer.data(), sizeof(char), bufferLength, d->file);
-    buffer.resize(bytesRead);
-    readPosition += bytesRead;
-
-    // Check to see if we just read the last block.  We need to call clear()
-    // if we did so that the last write succeeds.
-
-    if(bytesRead < bufferLength)
-      clear();
-
-    seek(writePosition);
-    vfs_fwrite(buffer.data(), sizeof(char), bytesRead, d->file);
-    writePosition += bytesRead;
-  }
-  truncate(writePosition);
-}
-
-bool TagVFSFile::readOnly() const
-{
-  return d->readOnly;
-}
-
-bool TagVFSFile::isReadable(const char *file)
-{
-  return access(file, R_OK) == 0;
-}
-
-bool TagVFSFile::isOpen() const
-{
-  return d->file;
-}
-
-bool TagVFSFile::isValid() const
-{
-  return d->file && d->valid;
-}
-
-void TagVFSFile::seek(long offset, Position p)
-{
-  if(!d->file) {
-    puts("File::seek() -- trying to seek in a file that isn't opened.");
-    return;
-  }
-
-  switch(p) {
-  case Beginning:
-    vfs_fseek(d->file, offset, SEEK_SET);
-    break;
-  case Current:
-    vfs_fseek(d->file, offset, SEEK_CUR);
-    break;
-  case End:
-    vfs_fseek(d->file, offset, SEEK_END);
-    break;
-  }
-}
-
-void TagVFSFile::clear()
-{
-  // don't do anything here at the moment
-}
-
-long TagVFSFile::tell() const
-{
-  return vfs_ftell(d->file);
-}
-
-long TagVFSFile::length()
-{
-  // Do some caching in case we do multiple calls.
-
-  if(d->size > 0)
-    return d->size;
-
-  if(!d->file)
-    return 0;
-
-  long curpos = tell();
-  
-  seek(0, End);
-  long endpos = tell();
-  
-  seek(curpos, Beginning);
-
-  d->size = endpos;
-  return endpos;
-}
-
-bool TagVFSFile::isWritable(const char *file)
-{
-  return access(file, W_OK) == 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// protected members
-////////////////////////////////////////////////////////////////////////////////
-
-void TagVFSFile::setValid(bool valid)
-{
-  d->valid = valid;
-}
-
-void TagVFSFile::truncate(long length)
-{
-  vfs_truncate(d->file, length);
-}
-
-TagLib::uint TagVFSFile::bufferSize()
-{
-  return TagVFSFilePrivate::bufferSize;
-}
--- a/taglib-vfs/tvfsfile.h	Thu Dec 07 00:12:31 2006 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/***************************************************************************
-    copyright            : (C) 2002, 2003 by Scott Wheeler
-    email                : wheeler@kde.org
- ***************************************************************************/
-
-/***************************************************************************
- *   This library is free software; you can redistribute it and/or modify  *
- *   it  under the terms of the GNU Lesser General Public License version  *
- *   2.1 as published by the Free Software Foundation.                     *
- *                                                                         *
- *   This library is distributed in the hope that it will be useful, but   *
- *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
- *   Lesser General Public License for more details.                       *
- *                                                                         *
- *   You should have received a copy of the GNU Lesser General Public      *
- *   License along with this library; if not, write to the Free Software   *
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
- *   USA                                                                   *
- ***************************************************************************/
-
-#ifndef TAGLIB_VFSFILE_H
-#define TAGLIB_VFSFILE_H
-
-#include "taglib.h"
-#include "tbytevector.h"
-#include "tfile.h"
-
-#ifndef _AUDACIOUS_CORE
-# include <audacious/vfs.h>
-#else
-# include "libaudacious/vfs.h"
-#endif
-
-namespace TagLib {
-
-  class String;
-  class Tag;
-  class AudioProperties;
-
-  //! A file class with some useful methods for tag manipulation
-
-  /*!
-   * This class is a basic file class with some methods that are particularly
-   * useful for tag editors.  It has methods to take advantage of
-   * ByteVector and a binary search method for finding patterns in a file.
-   */
-
-  class TagVFSFile
-  {
-  public:
-    /*!
-     * Position in the file used for seeking.
-     */
-    enum Position {
-      //! Seek from the beginning of the file.
-      Beginning,
-      //! Seek from the current position in the file.
-      Current,
-      //! Seek from the end of the file.
-      End
-    };
-
-    /*!
-     * Destroys this File instance.
-     */
-    virtual ~TagVFSFile();
-
-    /*!
-     * Returns the file name in the local file system encoding.
-     */
-    const char *name() const;
-
-    /*!
-     * Returns a pointer to this file's tag.  This should be reimplemented in
-     * the concrete subclasses.
-     */
-    virtual Tag *tag() const = 0;
-
-    /*!
-     * Returns a pointer to this file's audio properties.  This should be
-     * reimplemented in the concrete subclasses.  If no audio properties were
-     * read then this will return a null pointer.
-     */
-    virtual AudioProperties *audioProperties() const = 0;
-
-    /*!
-     * Save the file and its associated tags.  This should be reimplemented in
-     * the concrete subclasses.  Returns true if the save succeeds.
-     */
-    virtual bool save() = 0;
-
-    /*!
-     * Reads a block of size \a length at the current get pointer.
-     */
-    ByteVector readBlock(ulong length);
-
-    /*!
-     * Attempts to write the block \a data at the current get pointer.  If the
-     * file is currently only opened read only -- i.e. readOnly() returns true --
-     * this attempts to reopen the file in read/write mode.
-     *
-     * \note This should be used instead of using the streaming output operator
-     * for a ByteVector.  And even this function is significantly slower than
-     * doing output with a char[].
-     */
-    void writeBlock(const ByteVector &data);
-
-    /*!
-     * Returns the offset in the file that \a pattern occurs at or -1 if it can
-     * not be found.  If \a before is set, the search will only continue until the
-     * pattern \a before is found.  This is useful for tagging purposes to search
-     * for a tag before the synch frame.
-     *
-     * Searching starts at \a fromOffset, which defaults to the beginning of the
-     * file.
-     *
-     * \note This has the practial limitation that \a pattern can not be longer
-     * than the buffer size used by readBlock().  Currently this is 1024 bytes.
-     */
-    long find(const ByteVector &pattern,
-              long fromOffset = 0,
-              const ByteVector &before = ByteVector::null);
-
-    /*!
-     * Returns the offset in the file that \a pattern occurs at or -1 if it can
-     * not be found.  If \a before is set, the search will only continue until the
-     * pattern \a before is found.  This is useful for tagging purposes to search
-     * for a tag before the synch frame.
-     *
-     * Searching starts at \a fromOffset and proceeds from the that point to the
-     * beginning of the file and defaults to the end of the file.
-     *
-     * \note This has the practial limitation that \a pattern can not be longer
-     * than the buffer size used by readBlock().  Currently this is 1024 bytes.
-     */
-    long rfind(const ByteVector &pattern,
-               long fromOffset = 0,
-               const ByteVector &before = ByteVector::null);
-
-    /*!
-     * Insert \a data at position \a start in the file overwriting \a replace
-     * bytes of the original content.
-     *
-     * \note This method is slow since it requires rewriting all of the file
-     * after the insertion point.
-     */
-    void insert(const ByteVector &data, ulong start = 0, ulong replace = 0);
-
-    /*!
-     * Removes a block of the file starting a \a start and continuing for
-     * \a length bytes.
-     *
-     * \note This method is slow since it involves rewriting all of the file
-     * after the removed portion.
-     */
-    void removeBlock(ulong start = 0, ulong length = 0);
-
-    /*!
-     * Returns true if the file is read only (or if the file can not be opened).
-     */
-    bool readOnly() const;
-
-    /*!
-     * Since the file can currently only be opened as an argument to the
-     * constructor (sort-of by design), this returns if that open succeeded.
-     */
-    bool isOpen() const;
-
-    /*!
-     * Returns true if the file is open and readble and valid information for
-     * the Tag and / or AudioProperties was found.
-     */
-    bool isValid() const;
-
-    /*!
-     * Move the I/O pointer to \a offset in the file from position \a p.  This
-     * defaults to seeking from the beginning of the file.
-     *
-     * \see Position
-     */
-    void seek(long offset, Position p = Beginning);
-
-    /*!
-     * Reset the end-of-file and error flags on the file.
-     */
-    void clear();
-
-    /*!
-     * Returns the current offset withing the file.
-     */
-    long tell() const;
-
-    /*!
-     * Returns the length of the file.
-     */
-    long length();
-
-    /*!
-     * Returns true if \a file can be opened for reading.  If the file does not
-     * exist, this will return false.
-     */
-    static bool isReadable(const char *file);
-
-    /*!
-     * Returns true if \a file can be opened for writing.
-     */
-    static bool isWritable(const char *name);
-
-  protected:
-    /*!
-     * Construct a File object and opens the \a file.  \a file should be a
-     * be a C-string in the local file system encoding.
-     *
-     * \note Constructor is protected since this class should only be
-     * instantiated through subclasses.
-     */
-    TagVFSFile(const char *file);
-
-    /*!
-     * Marks the file as valid or invalid.
-     *
-     * \see isValid()
-     */
-    void setValid(bool valid);
-
-    /*!
-     * Truncates the file to a \a length.
-     */
-    void truncate(long length);
-
-    /*!
-     * Returns the buffer size that is used for internal buffering.
-     */
-    static uint bufferSize();
-
-  private:
-    TagVFSFile(const TagVFSFile &);
-    TagVFSFile &operator=(TagVFSFile &);
-
-    class TagVFSFilePrivate;
-    TagVFSFilePrivate *d;
-  };
-
-}
-
-#endif