• UWP平台Taglib编译(2)


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


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

    #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 oolkit debuglistener.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;
      }
    }

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


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

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


    相关文章:
    【推荐】 Docker容器的原理与实践 (下)
    【推荐】 Shadowsocks原理详解(上篇)

  • 相关阅读:
    C. Shaass and Lights 解析(思維、組合)
    D. Binary String To Subsequences(队列)(贪心)
    CodeForces 1384B2. Koa and the Beach (Hard Version)(贪心)
    CodeForces 1384B1. Koa and the Beach (Easy Version)(搜索)
    CodeForces 1384C. String Transformation 1(贪心)(并查集)
    CodeForces 1384A. Common Prefixes
    POJ-2516 Minimum Cost(最小费用最大流)
    POJ3261-Milk Patterns(后缀数组)
    HDU-1300 Pearls(斜率DP)
    HDU-4528 小明系列故事-捉迷藏(BFS)
  • 原文地址:https://www.cnblogs.com/163yun/p/10063202.html
Copyright © 2020-2023  润新知