880 lines
20 KiB
C++
880 lines
20 KiB
C++
|
#include "main.h"
|
||
|
#include "WMInformation.h"
|
||
|
#include "resource.h"
|
||
|
#include <exception>
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
class AutoByte
|
||
|
{
|
||
|
public:
|
||
|
AutoByte(size_t bytes)
|
||
|
: data(0)
|
||
|
{
|
||
|
data = new BYTE[bytes];
|
||
|
}
|
||
|
~AutoByte()
|
||
|
{
|
||
|
if (data)
|
||
|
delete[] data;
|
||
|
data = 0;
|
||
|
}
|
||
|
operator void *()
|
||
|
{
|
||
|
return (void *)data;
|
||
|
}
|
||
|
|
||
|
BYTE *data;
|
||
|
};
|
||
|
|
||
|
static void StoreData(WMT_ATTR_DATATYPE type, BYTE *value, DWORD length, wchar_t *valueStr, size_t len)
|
||
|
{
|
||
|
switch (type)
|
||
|
{
|
||
|
case WMT_TYPE_DWORD:
|
||
|
StringCchPrintf(valueStr, len, L"%lu", *(DWORD *)value);
|
||
|
break;
|
||
|
|
||
|
case WMT_TYPE_STRING:
|
||
|
lstrcpyn(valueStr, (wchar_t *)value, len);
|
||
|
break;
|
||
|
|
||
|
case -1: // hack // if (attrName == L"WM/Text")
|
||
|
StringCchPrintf(valueStr, len, L"%s/%s", UserTextDescription(value, length), UserTextString(value, length));
|
||
|
break;
|
||
|
case WMT_TYPE_BINARY:
|
||
|
BinaryString(value, length, valueStr, len);
|
||
|
break;
|
||
|
case WMT_TYPE_BOOL:
|
||
|
if (*(BOOL *)value)
|
||
|
{
|
||
|
lstrcpyn(valueStr, L"True", len);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lstrcpyn(valueStr, L"False", len);
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_QWORD:
|
||
|
StringCchPrintf(valueStr, len, L"%I64u", *(QWORD *)value);
|
||
|
break;
|
||
|
case WMT_TYPE_WORD:
|
||
|
StringCchPrintf(valueStr, len, L"%hu", *(WORD *)value);
|
||
|
break;
|
||
|
case WMT_TYPE_GUID:
|
||
|
GuidString(*(GUID *)value, valueStr, len);
|
||
|
break;
|
||
|
default:
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_UNKNOWN,valueStr,len);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
WMInformation::WMInformation(const wchar_t *fileName, bool noBlock)
|
||
|
: editor(0), editor2(0), header(0), header3(0), reader(0), header2(0), openError(false)
|
||
|
{
|
||
|
if (fileName && fileName[0]
|
||
|
&& WMCreateEditor(&editor) == S_OK)
|
||
|
{
|
||
|
if (SUCCEEDED(editor->QueryInterface(&editor2)))
|
||
|
{
|
||
|
if (SUCCEEDED(editor2->OpenEx(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE)))
|
||
|
{
|
||
|
// good to go
|
||
|
editor2->QueryInterface(&header);
|
||
|
editor->QueryInterface(&header2);
|
||
|
editor2->QueryInterface(&header3);
|
||
|
return ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
editor2 = 0;
|
||
|
if (SUCCEEDED(editor->Open(fileName)))
|
||
|
{
|
||
|
// good to go
|
||
|
editor->QueryInterface(&header);
|
||
|
editor->QueryInterface(&header2);
|
||
|
editor->QueryInterface(&header3);
|
||
|
return ;
|
||
|
}
|
||
|
}
|
||
|
// can't open it through the metadata editor interface, let's open a reader
|
||
|
|
||
|
if (editor)
|
||
|
editor->Release();
|
||
|
editor = 0;
|
||
|
if (editor2)
|
||
|
editor2->Release();
|
||
|
editor2 = 0;
|
||
|
if (FAILED(WMCreateReader(0, WMT_RIGHT_PLAYBACK, &reader)))
|
||
|
{
|
||
|
reader = 0;
|
||
|
return ;
|
||
|
}
|
||
|
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||
|
callback >> this;
|
||
|
|
||
|
if (FAILED(reader->Open(fileName, &callback, 0)))
|
||
|
{
|
||
|
reader->Release();
|
||
|
reader = 0;
|
||
|
return ;
|
||
|
}
|
||
|
if (noBlock)
|
||
|
WaitForEvent(hEvent, INFINITE);
|
||
|
else
|
||
|
WaitForSingleObject(hEvent, INFINITE);
|
||
|
|
||
|
CloseHandle(hEvent);
|
||
|
if (openError)
|
||
|
{
|
||
|
reader->Release();
|
||
|
reader = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
reader->QueryInterface(&header);
|
||
|
reader->QueryInterface(&header2);
|
||
|
reader->QueryInterface(&header3);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WMInformation::WMInformation(IWMReader *_reader)
|
||
|
: reader(0), // reader is if we create an internal reader, we don't want to save the passed one (so we don't close it on someone else :)
|
||
|
editor(0), editor2(0), header(0),
|
||
|
header3(0), header2(0),
|
||
|
openError(false), hEvent(NULL)
|
||
|
{
|
||
|
if (FAILED(_reader->QueryInterface(&header)))
|
||
|
header = 0;
|
||
|
if (FAILED(_reader->QueryInterface(&header2)))
|
||
|
header2 = 0;
|
||
|
if (FAILED(_reader->QueryInterface(&header3)))
|
||
|
header3 = 0; // this error is OK, we can deal with it.
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
WMInformation::WMInformation(IWMSyncReader *reader)
|
||
|
: editor(0), editor2(0), header(0), header3(0)
|
||
|
{
|
||
|
reader->QueryInterface(&header);
|
||
|
reader->QueryInterface(&header3);
|
||
|
}*/
|
||
|
|
||
|
WMInformation::WMInformation(IWMMetadataEditor *_editor)
|
||
|
: editor(_editor), editor2(0), header(0),
|
||
|
header3(0), reader(0), header2(0),
|
||
|
openError(false), hEvent(NULL)
|
||
|
{
|
||
|
editor->AddRef();
|
||
|
editor->QueryInterface(&editor2);
|
||
|
editor->QueryInterface(&header);
|
||
|
editor->QueryInterface(&header2);
|
||
|
editor->QueryInterface(&header3);
|
||
|
}
|
||
|
|
||
|
|
||
|
WMInformation::~WMInformation()
|
||
|
{
|
||
|
if (editor)
|
||
|
{
|
||
|
editor->Close();
|
||
|
editor->Release();
|
||
|
editor = 0;
|
||
|
}
|
||
|
if (editor2)
|
||
|
editor2->Release();
|
||
|
editor2 = 0;
|
||
|
if (header)
|
||
|
header->Release();
|
||
|
header = 0;
|
||
|
if (header2)
|
||
|
header2->Release();
|
||
|
header2 = 0;
|
||
|
if (header3)
|
||
|
header3->Release();
|
||
|
header3 = 0;
|
||
|
if (reader)
|
||
|
{
|
||
|
reader->Close();
|
||
|
reader->Release();
|
||
|
reader = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool WMInformation::GetDataType(const wchar_t *name, WMT_ATTR_DATATYPE &type)
|
||
|
{
|
||
|
if (!name)
|
||
|
return false;
|
||
|
|
||
|
WORD stream = 0;
|
||
|
WORD dataLen = 0;
|
||
|
if (header && SUCCEEDED(header->GetAttributeByName(&stream, name, &type, 0, &dataLen)))
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
|
||
|
}
|
||
|
|
||
|
void WMInformation::DeleteAttribute(const wchar_t *attrName)
|
||
|
{
|
||
|
|
||
|
WORD indexCount = 0;
|
||
|
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, attrName, NULL, 0, &indexCount)))
|
||
|
{
|
||
|
WORD *indices = new WORD[indexCount];
|
||
|
if (SUCCEEDED(header3->GetAttributeIndices(0, attrName, NULL, indices, &indexCount)))
|
||
|
{
|
||
|
for (size_t i = 0;i != indexCount;i++)
|
||
|
{
|
||
|
header3->DeleteAttribute(0, indices[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void WMInformation::SetAttribute_BinString(const wchar_t *attrName, wchar_t *value)
|
||
|
{
|
||
|
if (!header || !attrName || !value)
|
||
|
return ;
|
||
|
|
||
|
if (!*value)
|
||
|
{
|
||
|
DeleteAttribute(attrName);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
AutoChar data(value);
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_BINARY, (BYTE *)(char *)data, (WORD)strlen(data));
|
||
|
}
|
||
|
|
||
|
void WMInformation::GetAttribute_BinString(const wchar_t attrName[], wchar_t *valueStr, size_t len)
|
||
|
{
|
||
|
if (!header)
|
||
|
{
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
WORD length = 0;
|
||
|
HRESULT hr;
|
||
|
WORD streamNum = 0;
|
||
|
if (!header || FAILED(header->GetAttributeByName(&streamNum,
|
||
|
attrName,
|
||
|
&type,
|
||
|
0,
|
||
|
&length)))
|
||
|
{
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
hr = header->GetAttributeByName(&streamNum,
|
||
|
attrName,
|
||
|
&type,
|
||
|
value,
|
||
|
&length);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
int converted = MultiByteToWideChar(CP_ACP, 0, (const char *)value, length, valueStr, len-1);
|
||
|
valueStr[converted]=0;
|
||
|
}
|
||
|
|
||
|
void WMInformation::SetAttribute(const wchar_t *attrName, wchar_t *value, WMT_ATTR_DATATYPE defaultType)
|
||
|
{
|
||
|
if (!header || !attrName || !value)
|
||
|
return ;
|
||
|
|
||
|
if (!*value)
|
||
|
{
|
||
|
DeleteAttribute(attrName);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
|
||
|
if (!GetDataType(attrName, type))
|
||
|
type = defaultType;
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
case WMT_TYPE_DWORD:
|
||
|
{
|
||
|
DWORD dwordValue = wcstoul(value, 0, 10);
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_DWORD, (BYTE *) &dwordValue, sizeof(dwordValue));
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_STRING:
|
||
|
{
|
||
|
WORD size = static_cast<WORD>((lstrlen(value) + 1) * sizeof(wchar_t));
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_STRING, (BYTE *)value, size);
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_BINARY:
|
||
|
{
|
||
|
// TODO
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_BOOL:
|
||
|
{
|
||
|
BOOL boolValue;
|
||
|
if (!_wcsicmp(L"true", value))
|
||
|
boolValue = TRUE;
|
||
|
else
|
||
|
boolValue = FALSE;
|
||
|
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_BOOL, (BYTE *)&boolValue, sizeof(boolValue));
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_QWORD:
|
||
|
{
|
||
|
{
|
||
|
QWORD qwordValue = _wcstoui64(value, 0, 10);
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_QWORD, (BYTE *) &qwordValue, sizeof(qwordValue));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_WORD:
|
||
|
{
|
||
|
{
|
||
|
WORD wordValue = static_cast<WORD>(wcstoul(value, 0, 10));
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_WORD, (BYTE *) &wordValue, sizeof(wordValue));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WMT_TYPE_GUID:
|
||
|
{
|
||
|
GUID guidValue = StringGUID(value);
|
||
|
header->SetAttribute(0, attrName, WMT_TYPE_GUID, (BYTE *) &guidValue, sizeof(guidValue));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
bool WMInformation::GetAttributeSize(const wchar_t *name, size_t &size)
|
||
|
{
|
||
|
WORD stream = 0;
|
||
|
WORD resultSize;
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
|
||
|
if (!header || FAILED(header->GetAttributeByName(&stream, name, &type, 0, &resultSize)))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
size = resultSize;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
DWORD WMInformation::GetDWORDAttr(const wchar_t name[])
|
||
|
{
|
||
|
WORD stream = 0;
|
||
|
DWORD result;
|
||
|
|
||
|
WORD resultSizeWord = sizeof(result);
|
||
|
DWORD resultSize = sizeof(result);
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_DWORD;
|
||
|
WORD count = 1;
|
||
|
WORD indices[1] = {0};
|
||
|
if ((!header3
|
||
|
|| FAILED(header3->GetAttributeIndices(0, name, NULL, indices, &count))
|
||
|
|| FAILED(header3->GetAttributeByIndexEx(0, indices[0], 0, 0, &type, NULL, (BYTE *) &result, &resultSize)))
|
||
|
&&
|
||
|
(!header || FAILED(header->GetAttributeByName(&stream, name, &type, (BYTE *)&result, &resultSizeWord))))
|
||
|
return 0;
|
||
|
else
|
||
|
return result;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
long WMInformation::GetLongAttr(const wchar_t name[])
|
||
|
{
|
||
|
WORD stream = 0;
|
||
|
long result;
|
||
|
WORD resultSize = sizeof(result);
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
|
||
|
if (!header || FAILED(header->GetAttributeByName(&stream, name, &type, (BYTE *)&result, &resultSize)))
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::GetBoolAttr(const wchar_t name[])
|
||
|
{
|
||
|
WORD stream = 0;
|
||
|
BOOL result;
|
||
|
WORD resultSize = sizeof(result);
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
|
||
|
if (!header || FAILED(header->GetAttributeByName(&stream, name, &type, (BYTE *)&result, &resultSize)))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return !!result;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::IsSeekable()
|
||
|
{
|
||
|
return GetBoolAttr(g_wszWMSeekable);
|
||
|
}
|
||
|
|
||
|
long WMInformation::GetLengthMilliseconds()
|
||
|
{
|
||
|
WORD stream = 0;
|
||
|
long long duration = 0;
|
||
|
WORD resultSize = sizeof(duration);
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
|
||
|
if (!header || FAILED(header->GetAttributeByName(&stream, g_wszWMDuration, &type, (BYTE *)&duration, &resultSize)))
|
||
|
{
|
||
|
return -1000;
|
||
|
}
|
||
|
|
||
|
duration /= 10000LL;
|
||
|
return (long)duration;
|
||
|
}
|
||
|
|
||
|
long WMInformation::GetBitrate()
|
||
|
{
|
||
|
return GetDWORDAttr(g_wszWMCurrentBitrate);
|
||
|
}
|
||
|
|
||
|
WORD WMInformation::GetNumberAttributes()
|
||
|
{
|
||
|
WORD numAttr = 0;
|
||
|
if ((!header3 || FAILED(header3->GetAttributeCountEx(0, &numAttr)))
|
||
|
&& (!header || FAILED(header->GetAttributeCount(0, &numAttr))))
|
||
|
return 0;
|
||
|
else
|
||
|
return numAttr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void WMInformation::GetAttribute(WORD index, wchar_t *attrName, size_t attrLen, wchar_t *valueStr, size_t valueStrLen)
|
||
|
{
|
||
|
wchar_t _attrName[1025] = {0};
|
||
|
WORD nameLen = sizeof(_attrName) / sizeof(_attrName[0]);
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
WORD lang;
|
||
|
WORD stream = 0;
|
||
|
DWORD length = 0;
|
||
|
WORD lengthWord = 0;
|
||
|
|
||
|
if ((!header3 || FAILED(header3->GetAttributeByIndexEx(0, index, _attrName, &nameLen, &type, &lang, 0, &length)))
|
||
|
&& (!header || FAILED(header->GetAttributeByIndex(index, &stream, _attrName, &nameLen, &type, 0, &lengthWord))))
|
||
|
{
|
||
|
attrName[0]=0;
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
if (lengthWord)
|
||
|
length = lengthWord;
|
||
|
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
lstrcpyn(attrName, _attrName, attrLen);
|
||
|
if ((!header3 || FAILED(header3->GetAttributeByIndexEx(0, index, _attrName, &nameLen, &type, &lang, value, &length)))
|
||
|
&& (!header || FAILED(header->GetAttributeByIndex(index, &stream, _attrName, &nameLen, &type, value, &lengthWord))))
|
||
|
{
|
||
|
attrName[0]=0;
|
||
|
valueStr[0]=0;
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if (attrName == L"WM/Text")
|
||
|
{
|
||
|
type = (WMT_ATTR_DATATYPE)-1; // hack
|
||
|
StringCchCat(attrName, attrLen, L":");
|
||
|
StringCchCat(attrName, attrLen, UserTextDescription(value, length));
|
||
|
}
|
||
|
StoreData(type, value, length, valueStr, valueStrLen);
|
||
|
}
|
||
|
|
||
|
void WMInformation::GetAttribute(const wchar_t attrName[], wchar_t *valueStr, size_t len)
|
||
|
{
|
||
|
if (!header)
|
||
|
{
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
WMT_ATTR_DATATYPE type;
|
||
|
WORD length = 0;
|
||
|
HRESULT hr;
|
||
|
WORD streamNum = 0;
|
||
|
if (!header || FAILED(header->GetAttributeByName(&streamNum,
|
||
|
attrName,
|
||
|
&type,
|
||
|
0,
|
||
|
&length)))
|
||
|
{
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
hr = header->GetAttributeByName(&streamNum,
|
||
|
attrName,
|
||
|
&type,
|
||
|
value,
|
||
|
&length);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
valueStr[0]=0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if (attrName == L"WM/Text")
|
||
|
type = (WMT_ATTR_DATATYPE)-1; // hack
|
||
|
StoreData(type, value, length, valueStr, len);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool WMInformation::MakeWritable(const wchar_t *fileName)
|
||
|
{
|
||
|
if (!editor || !editor2)
|
||
|
return false;
|
||
|
|
||
|
if (FAILED(editor2->OpenEx(fileName, GENERIC_READ | GENERIC_WRITE, 0)))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::Flush()
|
||
|
{
|
||
|
if (!editor2 || FAILED(editor->Flush()))
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::IsAttribute(const wchar_t attrName[])
|
||
|
{
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
|
||
|
WORD length = sizeof(BOOL);
|
||
|
WORD streamNum = 0;
|
||
|
BOOL value;
|
||
|
if (!header || FAILED(header->GetAttributeByName(&streamNum,
|
||
|
attrName,
|
||
|
&type,
|
||
|
(BYTE *)&value,
|
||
|
&length)))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return !!value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool WMInformation::IsNotAttribute(const wchar_t attrName[])
|
||
|
{
|
||
|
if (!header)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
|
||
|
WORD length = sizeof(BOOL);
|
||
|
WORD streamNum = 0;
|
||
|
BOOL value;
|
||
|
if (!header || FAILED(header->GetAttributeByName(&streamNum,
|
||
|
attrName,
|
||
|
&type,
|
||
|
(BYTE *)&value,
|
||
|
&length)))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return !value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool WMInformation::MakeReadOnly(const wchar_t *fileName)
|
||
|
{
|
||
|
if (!editor || !editor2)
|
||
|
return false;
|
||
|
|
||
|
//editor->Close();
|
||
|
if (FAILED(editor2->OpenEx(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE)))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool WMInformation::NonWritable()
|
||
|
{
|
||
|
if (!editor2)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void WMInformation::DeleteUserText(const wchar_t *description)
|
||
|
{
|
||
|
WORD indexCount = 0;
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
|
||
|
WORD nameLen = 128;
|
||
|
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, L"WM/Text", NULL, 0, &indexCount)))
|
||
|
{
|
||
|
WORD *indices = new WORD[indexCount];
|
||
|
if (SUCCEEDED(header3->GetAttributeIndices(0, L"WM/Text", NULL, indices, &indexCount)))
|
||
|
{
|
||
|
for (size_t index = 0;index != indexCount;index++)
|
||
|
{
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD lang = 0;
|
||
|
DWORD length = 0;
|
||
|
wchar_t _attrName[128] = L"WM/Text";
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
|
||
|
{
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
|
||
|
{
|
||
|
if (UserTextDescription(value, length) == description)
|
||
|
{
|
||
|
header3->DeleteAttribute(0, indices[index]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WMInformation::SetUserText(const wchar_t *description, const wchar_t *valueStr)
|
||
|
{
|
||
|
if (!header3 || !description || !valueStr)
|
||
|
return;
|
||
|
|
||
|
WM_USER_TEXT userText;
|
||
|
userText.pwszDescription = (LPWSTR)description;
|
||
|
userText.pwszText = (LPWSTR) valueStr;
|
||
|
|
||
|
WORD index;
|
||
|
header3->AddAttribute(0, L"WM/Text", &index, WMT_TYPE_BINARY, 0, (BYTE *) &userText, sizeof(userText));
|
||
|
}
|
||
|
|
||
|
void WMInformation::ClearAllAttributes()
|
||
|
{
|
||
|
WORD numAttrs;
|
||
|
header3->GetAttributeCountEx(0xFFFF, &numAttrs);
|
||
|
while (numAttrs--)
|
||
|
{
|
||
|
header3->DeleteAttribute(0xFFFF, numAttrs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool WMInformation::GetCodecName(wchar_t *storage, size_t len)
|
||
|
{
|
||
|
if (!header2)
|
||
|
return false;
|
||
|
|
||
|
DWORD codecs=0;
|
||
|
header2->GetCodecInfoCount(&codecs);
|
||
|
for (DWORD i=0;i!=codecs;i++)
|
||
|
{
|
||
|
WORD nameLen=0, descriptionLen=0, infoLen = 0;
|
||
|
WMT_CODEC_INFO_TYPE type;
|
||
|
header2->GetCodecInfo(i, &nameLen, 0, &descriptionLen, 0, &type, &infoLen, 0);
|
||
|
if (type == WMT_CODECINFO_AUDIO)
|
||
|
{
|
||
|
wchar_t *name = new wchar_t[nameLen];
|
||
|
wchar_t *description = new wchar_t[descriptionLen];
|
||
|
BYTE *info = new BYTE[infoLen];
|
||
|
header2->GetCodecInfo(i, &nameLen, name, &descriptionLen, description, &type, &infoLen, info);
|
||
|
lstrcpynW(storage, name, len);
|
||
|
delete[] name;
|
||
|
delete[]description;
|
||
|
delete[] info;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::GetPicture(void **data, size_t *len, wchar_t **mimeType, int pictype)
|
||
|
{
|
||
|
WORD indexCount = 0;
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD nameLen = 128;
|
||
|
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, 0, &indexCount)))
|
||
|
{
|
||
|
WORD *indices = new WORD[indexCount];
|
||
|
if (SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, indices, &indexCount)))
|
||
|
{
|
||
|
for (size_t index = 0;index != indexCount;index++)
|
||
|
{
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD lang = 0;
|
||
|
DWORD length = 0;
|
||
|
wchar_t _attrName[128] = {0};
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
|
||
|
{
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
|
||
|
{
|
||
|
WM_PICTURE *picture = (WM_PICTURE *)value;
|
||
|
if (picture->bPictureType == pictype)
|
||
|
{
|
||
|
*len = picture->dwDataLen;
|
||
|
*data = WASABI_API_MEMMGR->sysMalloc(*len);
|
||
|
memcpy(*data, picture->pbData, *len);
|
||
|
wchar_t *type=0;
|
||
|
if (picture->pwszMIMEType)
|
||
|
type = wcschr(picture->pwszMIMEType, L'/');
|
||
|
|
||
|
if (type && *type)
|
||
|
{
|
||
|
type++;
|
||
|
|
||
|
wchar_t *type2 = wcschr(type, L'/');
|
||
|
if (type2 && *type2) type2++;
|
||
|
else type2 = type;
|
||
|
|
||
|
size_t mimelen = wcslen(type2)+1;
|
||
|
*mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(mimelen*sizeof(wchar_t));
|
||
|
StringCchCopyW(*mimeType, mimelen, type2);
|
||
|
}
|
||
|
else
|
||
|
*mimeType = 0; // unknown!
|
||
|
delete[] indices;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
delete[] indices;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::SetPicture(void *data, size_t len, const wchar_t *mimeType, int type)
|
||
|
{
|
||
|
WM_PICTURE picture;
|
||
|
picture.bPictureType = type;
|
||
|
picture.dwDataLen = len;
|
||
|
picture.pbData = (BYTE *)data;
|
||
|
picture.pwszDescription=L"";
|
||
|
wchar_t mt[32] = {0};
|
||
|
if (wcsstr(mimeType, L"/") != 0)
|
||
|
{
|
||
|
StringCchCopyW(mt, 32, mimeType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StringCchPrintfW(mt, 32, L"image/%s", mimeType);
|
||
|
}
|
||
|
picture.pwszMIMEType = mt;
|
||
|
return SUCCEEDED(header->SetAttribute(0, g_wszWMPicture, WMT_TYPE_BINARY, (const BYTE *)&picture, sizeof(picture)));
|
||
|
}
|
||
|
|
||
|
bool WMInformation::HasPicture(int pictype)
|
||
|
{
|
||
|
WORD indexCount = 0;
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD nameLen = 128;
|
||
|
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, 0, &indexCount)))
|
||
|
{
|
||
|
WORD *indices = new WORD[indexCount];
|
||
|
if (SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, indices, &indexCount)))
|
||
|
{
|
||
|
for (size_t index = 0;index != indexCount;index++)
|
||
|
{
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD lang = 0;
|
||
|
DWORD length = 0;
|
||
|
wchar_t _attrName[128] = {0};
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
|
||
|
{
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
|
||
|
{
|
||
|
WM_PICTURE *picture = (WM_PICTURE *)value;
|
||
|
if (picture->bPictureType == pictype)
|
||
|
{
|
||
|
delete[] indices;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
delete[] indices;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool WMInformation::DeletePicture(int pictype)
|
||
|
{
|
||
|
WORD indexCount = 0;
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD nameLen = 128;
|
||
|
if (header3 && SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, 0, &indexCount)))
|
||
|
{
|
||
|
WORD *indices = new WORD[indexCount];
|
||
|
if (SUCCEEDED(header3->GetAttributeIndices(0, g_wszWMPicture, NULL, indices, &indexCount)))
|
||
|
{
|
||
|
for (size_t index = 0;index != indexCount;index++)
|
||
|
{
|
||
|
WMT_ATTR_DATATYPE type = WMT_TYPE_BINARY;
|
||
|
WORD lang = 0;
|
||
|
DWORD length = 0;
|
||
|
wchar_t _attrName[128] = {0};
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, 0, &length)))
|
||
|
{
|
||
|
AutoByte v(length);
|
||
|
BYTE *value = v.data;
|
||
|
|
||
|
if (SUCCEEDED(header3->GetAttributeByIndexEx(0, indices[index], _attrName, &nameLen, &type, &lang, value, &length)))
|
||
|
{
|
||
|
WM_PICTURE *picture = (WM_PICTURE *)value;
|
||
|
if (picture->bPictureType == pictype)
|
||
|
{
|
||
|
header3->DeleteAttribute(0, indices[index]);
|
||
|
delete[] indices;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
delete[] indices;
|
||
|
}
|
||
|
return false;
|
||
|
}
|