美文网首页
UWP平台Taglib编译(2)

UWP平台Taglib编译(2)

作者: 43ce3d72fadb | 来源:发表于2018-12-04 11:40 被阅读10次

    此文已由作者郑博授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验

    #endif  // _WIN32
    }
    
    class FileStream::FileStreamPrivate
    {
    public:
      FileStreamPrivate(const FileName &fileName)
        : file(InvalidFileHandle)
        , name(fileName)
        , readOnly(true)
      {
      }
    
      FileHandle file;
      FileNameHandle name;
      bool readOnly;
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    // public members
    ////////////////////////////////////////////////////////////////////////////////
    
    FileStream::FileStream(FileName fileName, bool openReadOnly)
      : d(new FileStreamPrivate(fileName))
    {
      // First try with read / write mode, if that fails, fall back to read only.
    
      if(!openReadOnly)
        d->file = openFile(fileName, false);
    
      if(d->file != InvalidFileHandle)
        d->readOnly = false;
      else
        d->file = openFile(fileName, true);
    
      if(d->file == InvalidFileHandle)
      {
    # ifdef _WIN32
        debug("Could not open file " + fileName.toString());
    # else
        debug("Could not open file " + String(static_cast(d->name)));
    # endif
      }
    }
    
    FileStream::~FileStream()
    {
      if(isOpen())
        closeFile(d->file);
    
      delete d;
    }
    
    FileName FileStream::name() const
    {
      return d->name;
    }
    
    ByteVector FileStream::readBlock(ulong length)
    {
      if(!isOpen()) {
        debug("FileStream::readBlock() -- invalid file.");
        return ByteVector::null;
      }
    
      if(length == 0)
        return ByteVector::null;
    
      const ulong streamLength = static_cast(FileStream::length());
      if(length > bufferSize() && length > streamLength)
        length = streamLength;
    
      ByteVector buffer(static_cast(length));
    
      const size_t count = readFile(d->file, buffer);
      buffer.resize(static_cast(count));
    
      return buffer;
    }
    
    void FileStream::writeBlock(const ByteVector &data)
    {
      if(!isOpen()) {
        debug("FileStream::writeBlock() -- invalid file.");
        return;
      }
    
      if(readOnly()) {
        debug("FileStream::writeBlock() -- read only file.");
        return;
      }
    
      writeFile(d->file, data);
    }
    
    void FileStream::insert(const ByteVector &data, ulong start, ulong replace)
    {
      if(!isOpen()) {
        debug("FileStream::insert() -- invalid file.");
        return;
      }
    
      if(readOnly()) {
        debug("FileStream::insert() -- read only 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 = data;
      ByteVector aboutToOverwrite(static_cast(bufferLength));
    
      while(true)
      {
        // Seek to the current read position and read the data that we're about
        // to overwrite.  Appropriately increment the readPosition.
    
        seek(readPosition);
        const size_t bytesRead = readFile(d->file, aboutToOverwrite);
        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(bytesRead < bufferLength)
          clear();
    
        // Seek to the write position and write our buffer.  Increment the
        // writePosition.
    
        seek(writePosition);
        writeBlock(buffer);
    
        // We hit the end of the file.
    
        if(bytesRead == 0)
          break;
    
        writePosition += buffer.size();
    
        // Make the current buffer the data that we read in the beginning.
    
        buffer = aboutToOverwrite;
      }
    }
    
    void FileStream::removeBlock(ulong start, ulong length)
    {
      if(!isOpen()) {
        debug("FileStream::removeBlock() -- invalid file.");
        return;
      }
    
      ulong bufferLength = bufferSize();
    
      long readPosition = start + length;
      long writePosition = start;
    
      ByteVector buffer(static_cast(bufferLength));
    
      for(size_t bytesRead = -1; bytesRead != 0;)
      {
        seek(readPosition);
        bytesRead = readFile(d->file, buffer);
        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 < buffer.size()) {
          clear();
          buffer.resize(bytesRead);
        }
    
        seek(writePosition);
        writeFile(d->file, buffer);
    
        writePosition += bytesRead;
      }
    
      truncate(writePosition);
    }
    
    bool FileStream::readOnly() const
    {
      return d->readOnly;
    }
    
    bool FileStream::isOpen() const
    {
      return (d->file != InvalidFileHandle);
    }
    
    void FileStream::seek(long offset, Position p)
    {
      if(!isOpen()) {
        debug("FileStream::seek() -- invalid file.");
        return;
      }
    
    #ifdef _WIN32
    
      DWORD whence;
      switch(p) {
      case Beginning:
        whence = FILE_BEGIN;
        break;
      case Current:
        whence = FILE_CURRENT;
        break;
      case End:
        whence = FILE_END;
        break;
      default:
        debug("FileStream::seek() -- Invalid Position value.");
        return;
      }
    
    #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
      LARGE_INTEGER distance = { 0 };
      distance.QuadPart = offset;
    
      if (!SetFilePointerEx(d->file, distance, NULL, whence))
    #else
      SetLastError(NO_ERROR);
      SetFilePointer(d->file, offset, NULL, whence);
    
      const int lastError = GetLastError();
      if(lastError != NO_ERROR && lastError != ERROR_NEGATIVE_SEEK)
    #endif
        debug("FileStream::seek() -- Failed to set the file pointer.");
    
    #else
    
      int whence;
      switch(p) {
      case Beginning:
        whence = SEEK_SET;
        break;
      case Current:
        whence = SEEK_CUR;
        break;
      case End:
        whence = SEEK_END;
        break;
      default:
        debug("FileStream::seek() -- Invalid Position value.");
        return;
      }
    
      fseek(d->file, offset, whence);
    
    #endif
    }
    
    void FileStream::clear()
    {
    #ifdef _WIN32
    
      // NOP
    
    #else
    
      clearerr(d->file);
    
    #endif
    }
    
    long FileStream::tell() const
    {
    #ifdef _WIN32
    
    #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
      LARGE_INTEGER distance = { 0 };
      LARGE_INTEGER position = { 0 };
      if (SetFilePointerEx(d->file, distance, &position, FILE_CURRENT)) {
        return static_cast(position.QuadPart);
      }
    #else
      SetLastError(NO_ERROR);
      const DWORD position = SetFilePointer(d->file, 0, NULL, FILE_CURRENT);
      if(GetLastError() == NO_ERROR) {
        return static_cast(position);
      }
    #endif
      else {
        debug("FileStream::tell() -- Failed to get the file pointer.");
        return 0;
      }
    
    #else
    
      return ftell(d->file);
    
    #endif
    }
    
    long FileStream::length()
    {
      if(!isOpen()) {
        debug("FileStream::length() -- invalid file.");
        return 0;
      }
    
    #ifdef _WIN32
    
    #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
      LARGE_INTEGER fileSize = { 0 };
    
      if (GetFileSizeEx(d->file, &fileSize)) {
    	  return static_cast(fileSize.QuadPart);
      }
    #else
      SetLastError(NO_ERROR);
      const DWORD fileSize = GetFileSize(d->file, NULL);
    
      if (GetLastError() == NO_ERROR) {
    	  return static_cast(fileSize);
      }
    #endif
      else {
    	  debug("FileStream::length() -- Failed to get the file size.");
    	  return 0;
      }
    
    #else
    
      const long curpos = tell();
    
      seek(0, End);
      const long endpos = tell();
    
      seek(curpos, Beginning);
    
      return endpos;
    
    #endif
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    // protected members
    ////////////////////////////////////////////////////////////////////////////////
    
    void FileStream::truncate(long length)
    {
    #ifdef _WIN32
    
      const long currentPos = tell();
    
      seek(length);
    
      SetLastError(NO_ERROR);
      SetEndOfFile(d->file);
      if(GetLastError() != NO_ERROR) {
        debug("FileStream::truncate() -- Failed to truncate the file.");
      }
    
      seek(currentPos);
    
    #else
    
      const int error = ftruncate(fileno(d->file), length);
      if(error != 0) {
        debug("FileStream::truncate() -- Coundn't truncate the file.");
      }
    
    #endif
    }
    
    TagLib::uint FileStream::bufferSize()
    {
      return 1024;
    }

    为了便于调试,还需要修改taglib\toolkit\tdebuglistener.cpp,以便在调试直接在Output窗口输出调试信息,完整代码如下:

    /***************************************************************************
        copyright            : (C) 2013 by Tsuda Kageyu
        email                : tsuda.kageyu@gmail.com
     ***************************************************************************/
    
    /***************************************************************************
     *   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., 51 Franklin Street, Fifth Floor, Boston, MA         *
     *   02110-1301  USA                                                       *
     *                                                                         *
     *   Alternatively, this file is available under the Mozilla Public        *
     *   License Version 1.1.  You may obtain a copy of the License at         *
     *   http://www.mozilla.org/MPL/                                           *
     ***************************************************************************/
    
    #include "tdebuglistener.h"
    
    #include 
    #include 
    
    #ifdef _WIN32
    # include 
    #endif
    
    using namespace TagLib;
    
    namespace
    {
      class DefaultListener : public DebugListener
      {
      public:
        virtual void printMessage(const String &msg)
        {
    #ifdef _WIN32
    
          const wstring wstr = msg.toWString();
    #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
    	  OutputDebugStringW(wstr.c_str());
    #else
          const int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
          if(len != 0) {
            std::vector buf(len);
            WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &buf[0], len, NULL, NULL);
    
            std::cerr << std::string(&buf[0]);
          }
    #endif
    
    #else
    
          std::cerr << msg;
    
    #endif 
        }
      };
    
      DefaultListener defaultListener;
    }
    
    namespace TagLib
    {
      DebugListener *debugListener = &defaultListener;
    
      DebugListener::DebugListener()
      {
      }
    
      DebugListener::~DebugListener()
      {
      }
    
      void setDebugListener(DebugListener *listener)
      {
        if(listener)
          debugListener = listener;
        else
          debugListener = &defaultListener;
      }
    }

    最后,编译吧,骚年!!!

    免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

    更多网易技术、产品、运营经验分享请点击

    相关文章:
    【推荐】 dubbo心跳机制 (3)
    【推荐】 Android标题栏(2)
    【推荐】 云计算的前世今生(下)

    相关文章

      网友评论

          本文标题:UWP平台Taglib编译(2)

          本文链接:https://www.haomeiwen.com/subject/pirmcqtx.html