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

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

#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;
  }
}

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

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

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

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

UWP平台Taglib编译(2)的更多相关文章

  1. UWP平台Taglib编译(1)

    此文已由作者郑博授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验 最近开始开发UWP平台的App,项目需要用到Taglib进行音视频文件的标签信息读写,Google并没有现成的B ...

  2. xamarin UWP平台线程交互问题

    先吐槽一下,xamarin到现在为止,虽然开发一下应用尚可,对于一些简单的app开发使用xamarin-forms方式开发,虽然有一些优势,可以省下开发三个平台共同功能的时间,但是当我们随着项目深入的 ...

  3. QT全平台设置图标,全平台静态编译 good

    1.  概述 当我们用QT写好了一个软件,要把你的程序分享出去的时候,不可能把编译的目录拷贝给别人去运行.编译好的程序应该是一个主程序,加一些资源文件,再加一些动态链接库,高大上一些的还可以做一个安装 ...

  4. [UWP]在UWP平台中使用Lottie动画

    最近QQ影音久违的更新了,因为记得QQ影音之前体验还算不错(FFmepg的事另说),我也第一时间去官网下载体验了一下,结果发现一些有趣的事情. 是的,你没看错,QQ影音主界面上这个动画效果是使用Lot ...

  5. Unity3d依赖于平台的编译

    Unity的这一功能被命名为"依赖于平台的编译". 这包括了一些预编译处理指令,让你能够专门的针对不同的平台分开编译和运行一段代码. 此外,你能够在编辑器下运行一些代码用于測试而不 ...

  6. webrtc所有平台下载编译步骤详细说明

    webrtc所有平台下载编译步骤详细说明 1.安装depot tools Windows:国外下载:https://storage.googleapis.com/chrome-infra/depot_ ...

  7. DevEco Device Tool 2.1 Beta1 的Hi3861在Windows平台的编译体验

    DevEco Device Tool迎来了2.1 Beta1,其中的亮点之一是:支持Hi3861开发板的源码在Windows平台编译.带着浓厚的兴趣,第一时间做了一次体验. 首先在官网下载" ...

  8. qml支持多平台的编译--尤其对于需要支持xp的情况

    http://www.oschina.net/p/deepin-boot-maker 系统支持: Windows平台: Windows 7/ Windows 8 需要安装显卡驱动 Windows XP ...

  9. Lichee(两) 在sun4i_crane该平台下编译

    让我们先来回顾一下编译命令 $ cd workdir/lichee $ ./build.sh -p sun4i_crane -k 3.0  lichee文件夹下的build.sh #!/bin/bas ...

随机推荐

  1. 关于LOH(Large Object Heap)及内存泄漏

    关于LOH(Large Object Heap)的. .NET CLR中对于大于85000字节的内存既不像引用类型那样分配到普通堆上,也不像值类型那样分配到栈上,而是分配到了一个特殊的称为LOH的内部 ...

  2. jxl导出excel的问题

    jxl导出excel,通常浏览器会提示excel导出完成情况及默认保存路径,或让用户自定义选择保存路径,要达到这种效果,有些要做下修改,如:response是jsp的内置对象,在jsp中使用时不用声明 ...

  3. flask 常见关系模板代码

    以下罗列了使用关系型数据库中常见关系定义模板代码 一对多示例场景:用户与其发布的帖子(用户表与帖子表)角色与所属于该角色的用户(角色表与多用户表)示例代码class Role(db.Model): & ...

  4. Java Socket编程之TCP

    基于TCP的Socket通信: 服务器端: 创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 调用accept()方法开始监听,等待客户端的连接 连接建立后,通过 ...

  5. 117 FP页面无法查看 此错误是JDK8.0.0.0版本的一个BUG,会导致工单重复回写,

    用户表示117 FP页面无法查看,提示如下错误: 跟进: 1.进入FP服务器可看到以下错误 这个错误的框就表示FP的一个进程报错,自动断掉了,需要重新跑一次EXIT,INIT,PLAN,EXPORT, ...

  6. centos7 更新源 安装ifconfig

    centos7最小化安装后,ifconfig是不可用的,可以使用ip addr或ip link查看网络信息. 更新源之前,先确定网络是否连通.我用的虚拟机,因为桥接受公司ip限制,换成了NAT模式,确 ...

  7. OSG QT

    https://blog.csdn.net/a_Treasure/article/details/82152245 https://www.bbsmax.com/A/kPzOQ4oo5x/ https ...

  8. Mosquitto 单向SSL配置

    Mosquitto 单向SSL配置 摘自:https://blog.csdn.net/a_bcd_123/article/details/70167833 2017年04月14日 06:56:06 s ...

  9. Web测试实践--Rec 2

    累计完成任务情况: 阶段内容 参与人 进行用户调研 小熊 开会学习作业要求,取得共识 全体 注: 1."阶段内容"划斜线表示完成.2.采用倒序. 具体情况: 小熊主要围绕以下几方面 ...

  10. Typora的图片根目录设置,

    需求:使Typora的图片,设置到指定的文件里. 方便上传与转移. 步骤: 1 位置: 编辑 ->图片工具->设置图片根目录. 2 .Preference -> Editor -&g ...