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 ...
随机推荐
- 关于LOH(Large Object Heap)及内存泄漏
关于LOH(Large Object Heap)的. .NET CLR中对于大于85000字节的内存既不像引用类型那样分配到普通堆上,也不像值类型那样分配到栈上,而是分配到了一个特殊的称为LOH的内部 ...
- jxl导出excel的问题
jxl导出excel,通常浏览器会提示excel导出完成情况及默认保存路径,或让用户自定义选择保存路径,要达到这种效果,有些要做下修改,如:response是jsp的内置对象,在jsp中使用时不用声明 ...
- flask 常见关系模板代码
以下罗列了使用关系型数据库中常见关系定义模板代码 一对多示例场景:用户与其发布的帖子(用户表与帖子表)角色与所属于该角色的用户(角色表与多用户表)示例代码class Role(db.Model): & ...
- Java Socket编程之TCP
基于TCP的Socket通信: 服务器端: 创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 调用accept()方法开始监听,等待客户端的连接 连接建立后,通过 ...
- 117 FP页面无法查看 此错误是JDK8.0.0.0版本的一个BUG,会导致工单重复回写,
用户表示117 FP页面无法查看,提示如下错误: 跟进: 1.进入FP服务器可看到以下错误 这个错误的框就表示FP的一个进程报错,自动断掉了,需要重新跑一次EXIT,INIT,PLAN,EXPORT, ...
- centos7 更新源 安装ifconfig
centos7最小化安装后,ifconfig是不可用的,可以使用ip addr或ip link查看网络信息. 更新源之前,先确定网络是否连通.我用的虚拟机,因为桥接受公司ip限制,换成了NAT模式,确 ...
- OSG QT
https://blog.csdn.net/a_Treasure/article/details/82152245 https://www.bbsmax.com/A/kPzOQ4oo5x/ https ...
- Mosquitto 单向SSL配置
Mosquitto 单向SSL配置 摘自:https://blog.csdn.net/a_bcd_123/article/details/70167833 2017年04月14日 06:56:06 s ...
- Web测试实践--Rec 2
累计完成任务情况: 阶段内容 参与人 进行用户调研 小熊 开会学习作业要求,取得共识 全体 注: 1."阶段内容"划斜线表示完成.2.采用倒序. 具体情况: 小熊主要围绕以下几方面 ...
- Typora的图片根目录设置,
需求:使Typora的图片,设置到指定的文件里. 方便上传与转移. 步骤: 1 位置: 编辑 ->图片工具->设置图片根目录. 2 .Preference -> Editor -&g ...