343 lines
8.3 KiB
C++
343 lines
8.3 KiB
C++
/** (c) Nullsoft, Inc. C O N F I D E N T I A L
|
|
** Filename:
|
|
** Project:
|
|
** Description:
|
|
** Author: Ben Allison benski@nullsoft.com
|
|
** Created:
|
|
**/
|
|
#include "main.h"
|
|
#include "tagz.h"
|
|
#include "../tagz/ifc_tagprovider.h"
|
|
#include "../tagz/ifc_tagparams.h"
|
|
#include "api.h"
|
|
#include "TagProvider.h"
|
|
#include "../nu/AutoWide.h"
|
|
#include "../nu/AutoChar.h"
|
|
#include "../nu/ns_wc.h"
|
|
extern "C"
|
|
{
|
|
typedef char * (*GetTagFunc)(const char * tag, void * p);
|
|
typedef void (*FreeTagFunc)(char * tag,void * p);
|
|
typedef wchar_t * (*GetTagFuncW)(const wchar_t * tag, void * p);
|
|
typedef void (*FreeTagFuncW)(wchar_t * tag,void * p);
|
|
}
|
|
|
|
class TagParameters : public ifc_tagparams
|
|
{
|
|
public:
|
|
TagParameters(const wchar_t *_filename) :filename(_filename){}
|
|
void *GetParameter(const GUID *parameterID)
|
|
{
|
|
if (*parameterID == filenameParameterID)
|
|
return (void *)filename;
|
|
return 0;
|
|
}
|
|
protected:
|
|
RECVS_DISPATCH;
|
|
private:
|
|
const wchar_t *filename;
|
|
};
|
|
|
|
class ExternalTagProvider : public ifc_tagprovider
|
|
{
|
|
public:
|
|
ExternalTagProvider(GetTagFunc getter, FreeTagFunc freer, void *context);
|
|
wchar_t *GetTag(const wchar_t *name, ifc_tagparams *parameters);
|
|
void FreeTag(wchar_t *Tag);
|
|
protected:
|
|
RECVS_DISPATCH;
|
|
private:
|
|
GetTagFunc externalGetTag;
|
|
FreeTagFunc externalFreeTag;
|
|
void *externalContext;
|
|
};
|
|
|
|
class ExtendedTagProvider : public ifc_tagprovider
|
|
{
|
|
public:
|
|
ExtendedTagProvider(const wchar_t *_filename, GetTagFuncW getter, FreeTagFuncW freer, void *context, bool _useExtendedInfo);
|
|
wchar_t *GetTag(const wchar_t *name, ifc_tagparams *parameters);
|
|
void FreeTag(char *Tag);
|
|
protected:
|
|
RECVS_DISPATCH;
|
|
private:
|
|
GetTagFuncW externalGetTag;
|
|
FreeTagFuncW externalFreeTag;
|
|
void *externalContext;
|
|
const wchar_t *filename;
|
|
bool useExtendedInfo;
|
|
};
|
|
|
|
static void CleanupTitle(char *title)
|
|
{
|
|
while (title && *title)
|
|
{
|
|
if (*title == '\n' || *title == '\r')
|
|
*title = ' ';
|
|
title = CharNextA(title);
|
|
}
|
|
}
|
|
|
|
static void CleanupTitleW(wchar_t *title)
|
|
{
|
|
while (title && *title)
|
|
{
|
|
if (*title == L'\n' || *title == L'\r')
|
|
*title = L' ';
|
|
title = CharNextW(title);
|
|
}
|
|
}
|
|
|
|
void FormatTitle(waFormatTitle *format)
|
|
{
|
|
AutoWide wideSpec(format->spec);
|
|
wchar_t *spec = (format->spec ? wideSpec : config_titlefmt);
|
|
|
|
if (format->out && format->out_len)
|
|
{
|
|
memset(format->out, 0, format->out_len);
|
|
if (WINAMP5_API_TAGZ)
|
|
{
|
|
if (format->TAGFUNC)
|
|
{
|
|
ExternalTagProvider provider(format->TAGFUNC, format->TAGFREEFUNC, format->p);
|
|
wchar_t *tempOut = (wchar_t *)calloc(format->out_len, sizeof(wchar_t));
|
|
if (tempOut)
|
|
{
|
|
WINAMP5_API_TAGZ->format(spec, tempOut, format->out_len, &provider, 0 /*¶meters*/);
|
|
WideCharToMultiByteSZ(CP_ACP, 0, tempOut, -1, format->out, format->out_len, 0, 0);
|
|
free(tempOut);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AutoWide wideFn((char *)format->p); // we'd better hope it's the filename!
|
|
TagParameters parameters(wideFn);
|
|
wchar_t *tempOut = (wchar_t *)calloc(format->out_len, sizeof(wchar_t));
|
|
if (tempOut)
|
|
{
|
|
WINAMP5_API_TAGZ->format(spec, tempOut, format->out_len, tagProvider, ¶meters);
|
|
WideCharToMultiByteSZ(CP_ACP, 0, tempOut, -1, format->out, format->out_len, 0, 0);
|
|
free(tempOut);
|
|
}
|
|
}
|
|
CleanupTitle(format->out);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FormatTitleExtended(waFormatTitleExtended *format)
|
|
{
|
|
if (!format->filename || format->filename && !*format->filename) return;
|
|
|
|
const wchar_t *spec = (format->spec ? format->spec : config_titlefmt);
|
|
if (format->out && format->out_len)
|
|
{
|
|
if (WINAMP5_API_TAGZ)
|
|
{
|
|
ExtendedTagProvider provider(format->filename, format->TAGFUNC, format->TAGFREEFUNC, format->p, !!format->useExtendedInfo);
|
|
WINAMP5_API_TAGZ->format(spec, format->out, format->out_len, &provider, 0 /*¶meters*/);
|
|
CleanupTitleW(format->out);
|
|
}
|
|
else
|
|
{
|
|
lstrcpynW(format->out, format->filename, format->out_len);
|
|
PathStripPathW(format->out);
|
|
}
|
|
}
|
|
}
|
|
|
|
int FormatTitle(waHookTitleStructW *hts)
|
|
{
|
|
if (hts && hts->title &&
|
|
((hts->force_useformatting&1) || !(PathIsURLW(hts->filename) && StrCmpNIW(hts->filename, L"cda://", 6))))
|
|
{
|
|
wchar_t buf[32] = {0};
|
|
wchar_t buf2[32] = {0};
|
|
hts->length = -1;
|
|
hts->title[0] = 0;
|
|
if (in_get_extended_fileinfoW(hts->filename, L"length", buf, 32) ||
|
|
in_get_extended_fileinfoW(hts->filename, L"type", buf2, 32))
|
|
{
|
|
hts->length = StrToIntW(buf);
|
|
if (hts->length <= 0)
|
|
hts->length = -1;
|
|
else
|
|
hts->length /= 1000;
|
|
if (WINAMP5_API_TAGZ)
|
|
{
|
|
TagParameters parameters(hts->filename);
|
|
|
|
WINAMP5_API_TAGZ->format(config_titlefmt, hts->title, 2048, tagProvider, ¶meters);
|
|
}
|
|
CleanupTitleW(hts->title);
|
|
if (hts->title[0]) return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
namespace Winamp
|
|
{
|
|
/* our tag getting functions */
|
|
wchar_t *GetTag(const wchar_t *tag, const wchar_t *filename) // for simple tags
|
|
{
|
|
if (!_wcsicmp(tag, L"filename"))
|
|
return _wcsdup(filename);
|
|
|
|
else if (!_wcsicmp(tag, L"folder"))
|
|
{
|
|
wchar_t *folder = (wchar_t *)calloc(MAX_PATH, sizeof(wchar_t));
|
|
if (folder)
|
|
{
|
|
lstrcpynW(folder, filename, MAX_PATH);
|
|
PathRemoveFileSpecW(folder);
|
|
PathRemoveBackslashW(folder);
|
|
PathStripPathW(folder);
|
|
return folder;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
wchar_t *GetExtendedTag(const wchar_t *tag, const wchar_t *filename) //return 0 if not found
|
|
{
|
|
wchar_t buf[1024] = {0};
|
|
|
|
if (!_wcsicmp(tag, L"tracknumber"))
|
|
tag = L"track";
|
|
|
|
#if 0
|
|
if (in_get_extended_fileinfo(filename, tag, buf, sizeof(buf)) && buf[0])
|
|
return _strdup(buf);
|
|
#else
|
|
extendedFileInfoStructW s = {filename, tag, buf, 1024};
|
|
if (SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&s, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE) && buf[0])
|
|
return _wcsdup(buf);
|
|
#endif
|
|
return 0;
|
|
}
|
|
} // namespace Winamp
|
|
|
|
/* --- ExternalTagProvider ---
|
|
|
|
maybe we'll move this to a separate file once it's done
|
|
*/
|
|
ExternalTagProvider::ExternalTagProvider(GetTagFunc getter, FreeTagFunc freer, void *context)
|
|
: externalGetTag(getter), externalFreeTag(freer), externalContext(context)
|
|
{
|
|
}
|
|
|
|
wchar_t *ExternalTagProvider::GetTag(const wchar_t *name, ifc_tagparams *parameters)
|
|
{
|
|
if (externalGetTag)
|
|
{
|
|
char *tag = externalGetTag(AutoChar(name), externalContext);
|
|
if (tag == reinterpret_cast<char *>(-1))
|
|
return 0;
|
|
|
|
int size = MultiByteToWideChar(CP_ACP, 0, tag, -1, 0, 0);
|
|
if (!size)
|
|
{
|
|
if (externalFreeTag)
|
|
externalFreeTag(tag, externalContext);
|
|
return 0;
|
|
}
|
|
|
|
wchar_t *wide = (wchar_t *)calloc(size, sizeof(wchar_t));
|
|
if (!MultiByteToWideChar(CP_ACP, 0, tag, -1, wide, size))
|
|
{
|
|
if (wide) free(wide);
|
|
if (externalFreeTag)
|
|
externalFreeTag(tag, externalContext);
|
|
return 0;
|
|
}
|
|
|
|
if (externalFreeTag)
|
|
externalFreeTag(tag, externalContext);
|
|
return wide;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ExternalTagProvider::FreeTag(wchar_t *tag)
|
|
{
|
|
if (tag) free(tag);
|
|
}
|
|
|
|
#ifdef CBCLASS
|
|
#undef CBCLASS
|
|
#endif
|
|
|
|
#define CBCLASS ExternalTagProvider
|
|
START_DISPATCH;
|
|
CB(IFC_TAGPROVIDER_GET_TAG, GetTag);
|
|
VCB(IFC_TAGPROVIDER_FREE_TAG, FreeTag);
|
|
END_DISPATCH;
|
|
#undef CBCLASS
|
|
|
|
|
|
/* --- ExtendedTagProvider ---
|
|
|
|
maybe we'll move this to a separate file once it's done
|
|
*/
|
|
ExtendedTagProvider::ExtendedTagProvider(const wchar_t *_filename, GetTagFuncW getter, FreeTagFuncW freer, void *context, bool _useExtendedInfo)
|
|
: externalGetTag(getter), externalFreeTag(freer), externalContext(context), filename(_filename), useExtendedInfo(_useExtendedInfo)
|
|
{
|
|
}
|
|
|
|
wchar_t *ExtendedTagProvider::GetTag(const wchar_t *name, ifc_tagparams *parameters)
|
|
{
|
|
wchar_t *tag=0;
|
|
if (externalGetTag)
|
|
tag=externalGetTag(name, externalContext);
|
|
|
|
if (tag) // if we got a tag, we'll need to make a copy, because we won't be able to tell where it came from when it's time to free it
|
|
{
|
|
if (tag == reinterpret_cast<wchar_t *>(-1))
|
|
return 0;
|
|
wchar_t *temp = *tag?_wcsdup(tag):0;
|
|
if (externalFreeTag)
|
|
externalFreeTag(tag, externalContext);
|
|
return temp;
|
|
}
|
|
else
|
|
{
|
|
tag = Winamp::GetTag(name, filename);
|
|
if (tag == reinterpret_cast<wchar_t *>(-1))
|
|
return 0;
|
|
if (!tag && useExtendedInfo)
|
|
tag = Winamp::GetExtendedTag(name, filename);
|
|
if (tag == reinterpret_cast<wchar_t *>(-1))
|
|
return 0;
|
|
return tag;
|
|
}
|
|
}
|
|
|
|
void ExtendedTagProvider::FreeTag(char *tag)
|
|
{
|
|
if (tag) free(tag);
|
|
}
|
|
|
|
#ifdef CBCLASS
|
|
#undef CBCLASS
|
|
#endif
|
|
|
|
#define CBCLASS ExtendedTagProvider
|
|
START_DISPATCH;
|
|
CB(IFC_TAGPROVIDER_GET_TAG, GetTag);
|
|
VCB(IFC_TAGPROVIDER_FREE_TAG, FreeTag);
|
|
END_DISPATCH;
|
|
#undef CBCLASS
|
|
|
|
#ifdef CBCLASS
|
|
#undef CBCLASS
|
|
#endif
|
|
|
|
#define CBCLASS TagParameters
|
|
START_DISPATCH;
|
|
CB(IFC_TAGPARAMS_GETPARAMETER, GetParameter);
|
|
END_DISPATCH;
|
|
#undef CBCLASS |