winamp/Src/replicant/nsid3v2/windows/frame_apic.cpp
2024-09-24 14:54:57 +02:00

170 lines
5.2 KiB
C++

#include "nsid3v2.h"
#include "nsid3v2/header.h"
#include "nsid3v2/tag.h"
#include "nsid3v2/frame_utils.h"
#include <api/memmgr/api_memmgr.h>
#include <strsafe.h>
struct ParsedPicture
{
uint8_t encoding; // 0 - iso-8859-1, 1 - UTF16LE, 2 - UTF16BE, 3 - UTF8
const char *mime_type;
size_t mime_cch;
uint8_t picture_type;
union
{
const char *as8;
const wchar_t *as16;
} description_data;
size_t description_cch;
const void *picture_data;
size_t picture_bytes;
};
static int ParsePicture(const void *data, size_t data_len, ParsedPicture &parsed)
{
const uint8_t *data8 = (const uint8_t *)data;
parsed.encoding = data8[0];
parsed.mime_type = (const char *)&data8[1];
data_len--;
ParseDescription(parsed.mime_type, data_len, parsed.mime_cch);
parsed.picture_type = data8[2+parsed.mime_cch];
data_len--;
switch(parsed.encoding)
{
case 0: // ISO-8859-1
ParseDescription(parsed.description_data.as8, parsed.description_cch, data_len);
parsed.picture_data = parsed.description_data.as8 + parsed.description_cch + 1;
parsed.picture_bytes = data_len;
return NErr_Success;
case 1: // UTF-16
ParseDescription(parsed.description_data.as16, parsed.description_cch, data_len, parsed.encoding);
parsed.picture_data = parsed.description_data.as8 + parsed.description_cch + 1;
parsed.picture_bytes = data_len;
return NErr_Success;
case 2: // UTF-16 BE
ParseDescription(parsed.description_data.as16, parsed.description_cch, data_len, parsed.encoding);
parsed.picture_data = parsed.description_data.as8 + parsed.description_cch + 1;
parsed.picture_bytes = data_len;
return NErr_Success;
case 3: // UTF-8
ParseDescription(parsed.description_data.as8, parsed.description_cch, data_len);
parsed.picture_data = parsed.description_data.as8 + parsed.description_cch + 1;
parsed.picture_bytes = data_len;
return NErr_Success;
}
return NErr_NotImplemented;
}
int NSID3v2_Tag_APIC_GetPicture(const nsid3v2_tag_t t, uint8_t picture_type, void *_memmgr, wchar_t **mime_type, void **picture_data, size_t *picture_bytes)
{
api_memmgr *memmgr = (api_memmgr *)_memmgr;
const ID3v2::Tag *tag = (const ID3v2::Tag *)t;
const ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_PICTURE);
while (frame)
{
const void *data;
size_t data_len;
ParsedPicture parsed;
if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParsePicture(data, data_len, parsed) == NErr_Success && parsed.picture_type == picture_type)
{
const char *type = strchr(parsed.mime_type, '/');
if (type && *type)
{
type++;
int typelen = MultiByteToWideChar(CP_ACP, 0, type, -1, 0, 0);
*mime_type = (wchar_t *)memmgr->sysMalloc(typelen * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, type, -1, *mime_type, typelen);
}
else
*mime_type = 0; // unknown!
*picture_bytes = parsed.picture_bytes;
*picture_data = memmgr->sysMalloc(parsed.picture_bytes);
memcpy(*picture_data, parsed.picture_data, parsed.picture_bytes);
return NErr_Success;
}
frame = tag->FindNextFrame(frame);
}
return NErr_Error;
}
int NSID3v2_Tag_APIC_GetFirstPicture(const nsid3v2_tag_t t, void *_memmgr, wchar_t **mime_type, void **picture_data, size_t *picture_bytes)
{
api_memmgr *memmgr = (api_memmgr *)_memmgr;
const ID3v2::Tag *tag = (const ID3v2::Tag *)t;
const ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_PICTURE);
while (frame)
{
const void *data;
size_t data_len;
ParsedPicture parsed;
if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParsePicture(data, data_len, parsed) == NErr_Success)
{
const char *type = strchr(parsed.mime_type, '/');
if (type && *type)
{
type++;
int typelen = MultiByteToWideChar(CP_ACP, 0, type, -1, 0, 0);
*mime_type = (wchar_t *)memmgr->sysMalloc(typelen * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, type, -1, *mime_type, typelen);
}
else
*mime_type = 0; // unknown!
*picture_bytes = parsed.picture_bytes;
*picture_data = memmgr->sysMalloc(parsed.picture_bytes);
memcpy(*picture_data, parsed.picture_data, parsed.picture_bytes);
return NErr_Success;
}
frame = tag->FindNextFrame(frame);
}
return NErr_Error;
}
int NSID3v2_Tag_APIC_GetFrame(const nsid3v2_tag_t t, uint8_t picture_type, nsid3v2_frame_t *f)
{
const ID3v2::Tag *tag = (const ID3v2::Tag *)t;
const ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_PICTURE);
while (frame)
{
const void *data;
size_t data_len;
ParsedPicture parsed;
if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParsePicture(data, data_len, parsed) == NErr_Success && parsed.picture_type == picture_type)
{
*f = (nsid3v2_frame_t)frame;
return NErr_Success;
}
frame = tag->FindNextFrame(frame);
}
return NErr_Error;
}
int NSID3v2_Tag_APIC_GetFirstFrame(const nsid3v2_tag_t t, nsid3v2_frame_t *f)
{
const ID3v2::Tag *tag = (const ID3v2::Tag *)t;
const ID3v2::Frame *frame = tag->FindFirstFrame(NSID3V2_FRAME_PICTURE);
while (frame)
{
const void *data;
size_t data_len;
ParsedPicture parsed;
if (frame->GetData(&data, &data_len) == NErr_Success && data_len > 0 && ParsePicture(data, data_len, parsed) == NErr_Success)
{
*f = (nsid3v2_frame_t)frame;
return NErr_Success;
}
frame = tag->FindNextFrame(frame);
}
return NErr_Error;
}