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\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)的更多相关文章
- UWP平台Taglib编译(1)
此文已由作者郑博授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验 最近开始开发UWP平台的App,项目需要用到Taglib进行音视频文件的标签信息读写,Google并没有现成的B ...
- xamarin UWP平台线程交互问题
先吐槽一下,xamarin到现在为止,虽然开发一下应用尚可,对于一些简单的app开发使用xamarin-forms方式开发,虽然有一些优势,可以省下开发三个平台共同功能的时间,但是当我们随着项目深入的 ...
- QT全平台设置图标,全平台静态编译 good
1. 概述 当我们用QT写好了一个软件,要把你的程序分享出去的时候,不可能把编译的目录拷贝给别人去运行.编译好的程序应该是一个主程序,加一些资源文件,再加一些动态链接库,高大上一些的还可以做一个安装 ...
- [UWP]在UWP平台中使用Lottie动画
最近QQ影音久违的更新了,因为记得QQ影音之前体验还算不错(FFmepg的事另说),我也第一时间去官网下载体验了一下,结果发现一些有趣的事情. 是的,你没看错,QQ影音主界面上这个动画效果是使用Lot ...
- Unity3d依赖于平台的编译
Unity的这一功能被命名为"依赖于平台的编译". 这包括了一些预编译处理指令,让你能够专门的针对不同的平台分开编译和运行一段代码. 此外,你能够在编辑器下运行一些代码用于測试而不 ...
- webrtc所有平台下载编译步骤详细说明
webrtc所有平台下载编译步骤详细说明 1.安装depot tools Windows:国外下载:https://storage.googleapis.com/chrome-infra/depot_ ...
- DevEco Device Tool 2.1 Beta1 的Hi3861在Windows平台的编译体验
DevEco Device Tool迎来了2.1 Beta1,其中的亮点之一是:支持Hi3861开发板的源码在Windows平台编译.带着浓厚的兴趣,第一时间做了一次体验. 首先在官网下载" ...
- qml支持多平台的编译--尤其对于需要支持xp的情况
http://www.oschina.net/p/deepin-boot-maker 系统支持: Windows平台: Windows 7/ Windows 8 需要安装显卡驱动 Windows XP ...
- Lichee(两) 在sun4i_crane该平台下编译
让我们先来回顾一下编译命令 $ cd workdir/lichee $ ./build.sh -p sun4i_crane -k 3.0 lichee文件夹下的build.sh #!/bin/bas ...
随机推荐
- Delphi三层开发小技巧:TClientDataSet的Delta妙用
Delphi三层开发小技巧:TClientDataSet的Delta妙用 转载 2014年10月13日 09:41:14 标签: 三层 / ClientDataSet 318 from :http:/ ...
- DEV 打印功能
Dev13.1 用的是DocumentViewer,上面的一排按钮,是自动生成的,生成方法为:加了DocumentViewer后,控件右上角有个小三角,点一下,在弹出框中选择"Create ...
- VUE+WebPack游戏开发:神庙逃亡的游戏设计
- 【codeforces 1025E】Colored Cubes 【构造】
题意 有一个n*n的棋盘和m个棋子,每个棋子有一个初始位置和一个目标位置,每次移动只能选择一个棋子移动到他相邻的格子,并且花费一秒钟.请你找出一个移动的方法,使得在10800步内将所有棋子移动到目标位 ...
- 111. Minimum Depth of Binary Tree (Tree; DFS)
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
- 第二话:javascript中闭包的理解
闭包是什么? 通过闭包,子函数得以访问父函数的上下文环境,即使父函数已经结束执行. OK,我来简单叙述下,先上图. 都知道函数是javascript整个世界,对象是函数,方法是函数,并且js中实质性的 ...
- Web测试实践-任务进度-Day01
任务安排 说明:小组全体成员都参与了会议,对该实践进行分析以及对实践任务的拆分以及进行了任务的分配. 小组成员 华同学.郭同学.覃同学.刘同学.穆同学.沈同学 阶段划分 阶段1:评测被测系统 1.对被 ...
- 选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default
部署MVC的时候,因为服务器.NET版本是4.5.1,所以在vs将.NET版本降到4.5.1的时候发布报错. 原因:C#6降到C#5导致 解决办法:修改web.config配置 ,编译选项改为comp ...
- 在iOS中使用百度地图
就如同在百度地图的文档中所说的一样,这么来.但是,有一个小疏忽. 到添加完所需要的framework之后,一定要记得把你的(Class-Prefix)AppDelegate的后缀改成mm. 估计百度的 ...
- Android Lint——内嵌于Android Studio的代码优化工具
Android Lint工具是Android Studio 自带的静态代码工模具,Android Lint是专门针对Android 定制的检查规则,因此可以检查出很多Android特有的代码缺陷.建议 ...