Initial community commit
149
Src/Plugins/Portable/pmp_ipod/SysInfoXML.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include <windows.h>
|
||||
#include <stddef.h> // for offsetof
|
||||
#include <winioctl.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
UCHAR ScsiStatus;
|
||||
UCHAR PathId;
|
||||
UCHAR TargetId;
|
||||
UCHAR Lun;
|
||||
UCHAR CdbLength;
|
||||
UCHAR SenseInfoLength;
|
||||
UCHAR DataIn;
|
||||
ULONG DataTransferLength;
|
||||
ULONG TimeOutValue;
|
||||
PVOID DataBuffer;
|
||||
ULONG SenseInfoOffset;
|
||||
UCHAR Cdb[16];
|
||||
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
|
||||
|
||||
|
||||
typedef struct {
|
||||
SCSI_PASS_THROUGH_DIRECT spt;
|
||||
ULONG Filler;
|
||||
UCHAR ucSenseBuf[32];
|
||||
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
|
||||
|
||||
|
||||
|
||||
#define IOCTL_SCSI_BASE 0x00000004
|
||||
|
||||
/*
|
||||
* constants for DataIn member of SCSI_PASS_THROUGH* structures
|
||||
*/
|
||||
#define SCSI_IOCTL_DATA_OUT 0
|
||||
#define SCSI_IOCTL_DATA_IN 1
|
||||
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
|
||||
|
||||
/*
|
||||
* Standard IOCTL define
|
||||
*/
|
||||
#define CTL_CODE( DevType, Function, Method, Access ) ( \
|
||||
((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
|
||||
)
|
||||
|
||||
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||||
#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||||
#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
|
||||
#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS
|
||||
|
||||
static bool scsi_inquiry(HANDLE deviceHandle, UCHAR page, UCHAR *inqbuf, size_t &buf_len)
|
||||
{
|
||||
char buf[2048] = {0};
|
||||
BOOL status;
|
||||
PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER pswb;
|
||||
|
||||
DWORD length=0, returned=0;
|
||||
|
||||
/*
|
||||
* Get the drive inquiry data
|
||||
*/
|
||||
ZeroMemory( &buf, 2048 );
|
||||
ZeroMemory( inqbuf, buf_len );
|
||||
pswb = (PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)buf;
|
||||
pswb->spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
|
||||
pswb->spt.CdbLength = 6;
|
||||
pswb->spt.SenseInfoLength = 32;
|
||||
pswb->spt.DataIn = SCSI_IOCTL_DATA_IN;
|
||||
pswb->spt.DataTransferLength = buf_len;
|
||||
pswb->spt.TimeOutValue = 2;
|
||||
pswb->spt.DataBuffer = inqbuf;
|
||||
pswb->spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
|
||||
pswb->spt.Cdb[0] = 0x12;
|
||||
pswb->spt.Cdb[1] = 0x1;
|
||||
pswb->spt.Cdb[2] = page;
|
||||
pswb->spt.Cdb[4] = (UCHAR)buf_len;
|
||||
|
||||
length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
|
||||
status = DeviceIoControl( deviceHandle,
|
||||
IOCTL_SCSI_PASS_THROUGH_DIRECT,
|
||||
pswb,
|
||||
length,
|
||||
pswb,
|
||||
length,
|
||||
&returned,
|
||||
NULL );
|
||||
|
||||
|
||||
if (status && returned >3)
|
||||
{
|
||||
buf_len=returned;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf_len=0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool AddPagetoXML(HANDLE dev, char *&dest, size_t &destlen, UCHAR page)
|
||||
{
|
||||
UCHAR buf[256] = {0};
|
||||
size_t buflen=255;
|
||||
if (scsi_inquiry(dev, page, buf, buflen))
|
||||
{
|
||||
size_t len = buf[3];
|
||||
StringCchCopyNExA(dest, destlen, (char *)buf+4, len, &dest, &destlen, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool BuildXML(HANDLE dev, char *xml, size_t xmllen)
|
||||
{
|
||||
*xml=0;
|
||||
UCHAR pages[255] = {0};
|
||||
size_t pageslen=255;
|
||||
if (scsi_inquiry(dev, 0xc0, pages, pageslen) && pageslen>3)
|
||||
{
|
||||
unsigned char numPages=pages[3];
|
||||
if (numPages+4 <= 255)
|
||||
{
|
||||
for (int i=0;i<numPages;i++)
|
||||
{
|
||||
if (!AddPagetoXML(dev, xml, xmllen, pages[i+4]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseSysInfoXML(wchar_t drive_letter, char * xml, int xmllen)
|
||||
{
|
||||
wchar_t fn[MAX_PATH] = {0};
|
||||
StringCchPrintf(fn, MAX_PATH, L"\\\\.\\%c:", drive_letter);
|
||||
HANDLE hfile = CreateFileW(fn, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
|
||||
if (hfile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
bool ret = BuildXML(hfile, xml, xmllen);
|
||||
CloseHandle(hfile);
|
||||
return ret;
|
||||
}
|
||||
return false;
|
||||
}
|
30
Src/Plugins/Portable/pmp_ipod/api.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef NULLSOFT_PMP_IPOD_API_H
|
||||
#define NULLSOFT_PMP_IPOD_API_H
|
||||
|
||||
#include <api/memmgr/api_memmgr.h>
|
||||
extern api_memmgr *memmgr;
|
||||
#define WASABI_API_MEMMGR memmgr
|
||||
|
||||
#include "../Agave/AlbumArt/api_albumart.h"
|
||||
extern api_albumart *albumArtApi;
|
||||
#define AGAVE_API_ALBUMART albumArtApi
|
||||
|
||||
#include "../Agave/Config/api_config.h"
|
||||
extern api_config *agaveConfigApi;
|
||||
#define AGAVE_API_CONFIG agaveConfigApi
|
||||
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
#include "../nu/threadpool/api_threadpool.h"
|
||||
extern api_threadpool *threadPoolApi;
|
||||
#define WASABI_API_THREADPOOL threadPoolApi
|
||||
|
||||
#include <api/application/api_application.h>
|
||||
extern api_application *applicationApi;
|
||||
#define WASABI_API_APP applicationApi
|
||||
|
||||
#include "../devices/api_devicemanager.h"
|
||||
extern api_devicemanager *deviceManagerApi;
|
||||
#define AGAVE_API_DEVICEMANAGER deviceManagerApi
|
||||
|
||||
#endif
|
343
Src/Plugins/Portable/pmp_ipod/deviceprovider.cpp
Normal file
|
@ -0,0 +1,343 @@
|
|||
#include "api.h"
|
||||
#include "./deviceprovider.h"
|
||||
#include "../devices/api_devicemanager.h"
|
||||
|
||||
extern PMPDevicePlugin plugin;
|
||||
bool ConnectDrive(wchar_t drive, bool connect);
|
||||
|
||||
static size_t tlsIndex = (size_t)-1;
|
||||
|
||||
static BOOL
|
||||
DiscoveryProvider_RegisterCancelSwitch(BOOL *cancelSwitch)
|
||||
{
|
||||
if ((size_t)-1 != tlsIndex &&
|
||||
NULL != WASABI_API_APP)
|
||||
{
|
||||
WASABI_API_APP->SetThreadStorage(tlsIndex, cancelSwitch);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
DiscoveryProvider_GetCancelSwitchOn()
|
||||
{
|
||||
if ((size_t)-1 != tlsIndex &&
|
||||
NULL != WASABI_API_APP)
|
||||
{
|
||||
BOOL *cancelSwitch = (BOOL*)WASABI_API_APP->GetThreadStorage(tlsIndex);
|
||||
if (NULL != cancelSwitch &&
|
||||
FALSE != *cancelSwitch)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
DeviceProvider_DriverEnumCb(wchar_t drive, unsigned int type)
|
||||
{
|
||||
if (DRIVE_REMOVABLE == type &&
|
||||
FALSE == DiscoveryProvider_GetCancelSwitchOn())
|
||||
{
|
||||
ConnectDrive(drive,true);
|
||||
}
|
||||
}
|
||||
|
||||
DeviceProvider::DeviceProvider()
|
||||
: ref(1), activity(0), manager(NULL), readyEvent(NULL), cancelDiscovery(FALSE)
|
||||
{
|
||||
InitializeCriticalSection(&lock);
|
||||
enumerator = (ENUMDRIVES)SendMessageW(plugin.hwndPortablesParent,
|
||||
WM_PMP_IPC, 0, PMP_IPC_ENUM_ACTIVE_DRIVES);
|
||||
}
|
||||
|
||||
DeviceProvider::~DeviceProvider()
|
||||
{
|
||||
CancelDiscovery();
|
||||
|
||||
if (NULL != readyEvent)
|
||||
CloseHandle(readyEvent);
|
||||
|
||||
DeleteCriticalSection(&lock);
|
||||
}
|
||||
|
||||
HRESULT DeviceProvider::CreateInstance(DeviceProvider **instance)
|
||||
{
|
||||
if (NULL == instance)
|
||||
return E_POINTER;
|
||||
|
||||
*instance = new DeviceProvider();
|
||||
|
||||
if (NULL == *instance)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
size_t DeviceProvider::AddRef()
|
||||
{
|
||||
return InterlockedIncrement((LONG*)&ref);
|
||||
}
|
||||
|
||||
size_t DeviceProvider::Release()
|
||||
{
|
||||
if (0 == ref)
|
||||
return ref;
|
||||
|
||||
LONG r = InterlockedDecrement((LONG*)&ref);
|
||||
if (0 == r)
|
||||
delete(this);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int DeviceProvider::QueryInterface(GUID interface_guid, void **object)
|
||||
{
|
||||
if (NULL == object)
|
||||
return E_POINTER;
|
||||
|
||||
if (IsEqualIID(interface_guid, IFC_DeviceProvider))
|
||||
*object = static_cast<ifc_deviceprovider*>(this);
|
||||
else
|
||||
{
|
||||
*object = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
if (NULL == *object)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void DeviceProvider::Lock()
|
||||
{
|
||||
EnterCriticalSection(&lock);
|
||||
}
|
||||
|
||||
void DeviceProvider::Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&lock);
|
||||
}
|
||||
|
||||
DWORD DeviceProvider::DiscoveryThread()
|
||||
{
|
||||
IncrementActivity();
|
||||
|
||||
if (NULL != enumerator &&
|
||||
FALSE == cancelDiscovery)
|
||||
{
|
||||
DiscoveryProvider_RegisterCancelSwitch(&cancelDiscovery);
|
||||
|
||||
enumerator(DeviceProvider_DriverEnumCb);
|
||||
|
||||
DiscoveryProvider_RegisterCancelSwitch(NULL);
|
||||
}
|
||||
|
||||
DecrementActivity();
|
||||
|
||||
Lock();
|
||||
|
||||
if (NULL != readyEvent)
|
||||
SetEvent(readyEvent);
|
||||
|
||||
Unlock();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user, intptr_t id)
|
||||
{
|
||||
DeviceProvider *self;
|
||||
DWORD result;
|
||||
|
||||
self = (DeviceProvider*)user;
|
||||
|
||||
if (NULL != self)
|
||||
result = self->DiscoveryThread();
|
||||
else
|
||||
result = -2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DeviceProvider::BeginDiscovery(api_devicemanager *manager)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (NULL == enumerator)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
Lock();
|
||||
|
||||
if (NULL != readyEvent &&
|
||||
WAIT_TIMEOUT == WaitForSingleObject(readyEvent, 0))
|
||||
{
|
||||
hr = E_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = S_OK;
|
||||
|
||||
if (NULL == readyEvent)
|
||||
{
|
||||
readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
if (NULL == readyEvent)
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
if ((size_t)-1 == tlsIndex &&
|
||||
NULL != WASABI_API_APP)
|
||||
{
|
||||
tlsIndex = WASABI_API_APP->AllocateThreadStorage();
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
||||
cancelDiscovery = FALSE;
|
||||
ResetEvent(readyEvent);
|
||||
|
||||
if (0 != WASABI_API_THREADPOOL->RunFunction(0, DeviceProvider_DiscoveryThreadStarter,
|
||||
this, 0, api_threadpool::FLAG_LONG_EXECUTION))
|
||||
{
|
||||
|
||||
SetEvent(readyEvent);
|
||||
hr = E_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT DeviceProvider::CancelDiscovery()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = S_FALSE;
|
||||
|
||||
Lock();
|
||||
|
||||
if (NULL != readyEvent)
|
||||
{
|
||||
cancelDiscovery = TRUE;
|
||||
if (WAIT_OBJECT_0 == WaitForSingleObject(readyEvent, 0))
|
||||
hr = S_OK;
|
||||
|
||||
cancelDiscovery = FALSE;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT DeviceProvider::GetActive()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
Lock();
|
||||
|
||||
if (0 != activity)
|
||||
hr = S_OK;
|
||||
else
|
||||
hr = S_FALSE;
|
||||
|
||||
Unlock();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT DeviceProvider::Register(api_devicemanager *manager)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (NULL != this->manager)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
if (NULL == manager)
|
||||
return E_POINTER;
|
||||
|
||||
hr = manager->RegisterProvider(this);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
this->manager = manager;
|
||||
manager->AddRef();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT DeviceProvider::Unregister()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (NULL == manager)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
hr = manager->UnregisterProvider(this);
|
||||
manager->Release();
|
||||
manager = NULL;
|
||||
return hr;
|
||||
}
|
||||
|
||||
size_t DeviceProvider::IncrementActivity()
|
||||
{
|
||||
size_t a;
|
||||
|
||||
Lock();
|
||||
|
||||
activity++;
|
||||
if (1 == activity &&
|
||||
NULL != manager)
|
||||
{
|
||||
manager->SetProviderActive(this, TRUE);
|
||||
}
|
||||
|
||||
a = activity;
|
||||
|
||||
Unlock();
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t DeviceProvider::DecrementActivity()
|
||||
{
|
||||
size_t a;
|
||||
|
||||
Lock();
|
||||
|
||||
if (0 != activity)
|
||||
{
|
||||
activity--;
|
||||
if (0 == activity &&
|
||||
NULL != manager)
|
||||
{
|
||||
manager->SetProviderActive(this, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
a = activity;
|
||||
|
||||
Unlock();
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
#define CBCLASS DeviceProvider
|
||||
START_DISPATCH;
|
||||
CB(ADDREF, AddRef)
|
||||
CB(RELEASE, Release)
|
||||
CB(QUERYINTERFACE, QueryInterface)
|
||||
CB(API_BEGINDISCOVERY, BeginDiscovery)
|
||||
CB(API_CANCELDISCOVERY, CancelDiscovery)
|
||||
CB(API_GETACTIVE, GetActive)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
50
Src/Plugins/Portable/pmp_ipod/deviceprovider.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include <wtypes.h>
|
||||
#include "../devices/ifc_deviceprovider.h"
|
||||
#include "..\..\Library\ml_pmp/pmp.h"
|
||||
|
||||
class DeviceProvider : public ifc_deviceprovider
|
||||
{
|
||||
protected:
|
||||
DeviceProvider();
|
||||
~DeviceProvider();
|
||||
|
||||
public:
|
||||
static HRESULT CreateInstance(DeviceProvider **instance);
|
||||
|
||||
public:
|
||||
/* Dispatchable */
|
||||
size_t AddRef();
|
||||
size_t Release();
|
||||
int QueryInterface(GUID interface_guid, void **object);
|
||||
|
||||
/* ifc_deviceprovider */
|
||||
HRESULT BeginDiscovery(api_devicemanager *manager);
|
||||
HRESULT CancelDiscovery();
|
||||
HRESULT GetActive();
|
||||
|
||||
public:
|
||||
HRESULT Register(api_devicemanager *manager);
|
||||
HRESULT Unregister();
|
||||
size_t IncrementActivity();
|
||||
size_t DecrementActivity();
|
||||
|
||||
private:
|
||||
void Lock();
|
||||
void Unlock();
|
||||
DWORD DiscoveryThread();
|
||||
friend static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user_data, intptr_t id);
|
||||
|
||||
protected:
|
||||
size_t ref;
|
||||
size_t activity;
|
||||
CRITICAL_SECTION lock;
|
||||
api_devicemanager *manager;
|
||||
ENUMDRIVES enumerator;
|
||||
HANDLE readyEvent;
|
||||
BOOL cancelDiscovery;
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
357
Src/Plugins/Portable/pmp_ipod/eject.cpp
Normal file
|
@ -0,0 +1,357 @@
|
|||
// this file almost totally copied from MSDN
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#define LOCK_TIMEOUT 3000 // 10 Seconds
|
||||
#define LOCK_RETRIES 20
|
||||
|
||||
#if 1 // old way
|
||||
static HANDLE OpenVolume(TCHAR cDriveLetter)
|
||||
{
|
||||
HANDLE hVolume;
|
||||
UINT uDriveType;
|
||||
wchar_t szVolumeName[8] = {0};
|
||||
wchar_t szRootName[5] = {0};
|
||||
DWORD dwAccessFlags = 0;
|
||||
cDriveLetter &= ~0x20; // capitalize
|
||||
wsprintf(szRootName, L"%c:\\", cDriveLetter);
|
||||
|
||||
uDriveType = GetDriveType(szRootName);
|
||||
switch(uDriveType) {
|
||||
case DRIVE_REMOVABLE:
|
||||
dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
dwAccessFlags = GENERIC_READ;
|
||||
break;
|
||||
default:
|
||||
printf("Cannot eject. Drive type is incorrect.\n");
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
wsprintf(szVolumeName, L"\\\\.\\%c:", cDriveLetter);
|
||||
|
||||
hVolume = CreateFile( szVolumeName,
|
||||
dwAccessFlags,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL );
|
||||
|
||||
if (hVolume == INVALID_HANDLE_VALUE)
|
||||
printf("CreateFile error %d\n", GetLastError());
|
||||
return hVolume;
|
||||
}
|
||||
|
||||
static BOOL CloseVolume(HANDLE hVolume)
|
||||
{
|
||||
return CloseHandle(hVolume);
|
||||
}
|
||||
|
||||
static BOOL LockVolume(HANDLE hVolume)
|
||||
{
|
||||
DWORD dwBytesReturned;
|
||||
DWORD dwSleepAmount;
|
||||
int nTryCount;
|
||||
|
||||
dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
|
||||
|
||||
// Do this in a loop until a timeout period has expired
|
||||
for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
|
||||
if (DeviceIoControl(hVolume,
|
||||
FSCTL_LOCK_VOLUME,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
&dwBytesReturned,
|
||||
NULL))
|
||||
return TRUE;
|
||||
|
||||
Sleep(dwSleepAmount);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL DismountVolume(HANDLE hVolume)
|
||||
{
|
||||
DWORD dwBytesReturned;
|
||||
|
||||
return DeviceIoControl( hVolume,
|
||||
FSCTL_DISMOUNT_VOLUME,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
|
||||
{
|
||||
DWORD dwBytesReturned;
|
||||
PREVENT_MEDIA_REMOVAL PMRBuffer;
|
||||
|
||||
PMRBuffer.PreventMediaRemoval = fPreventRemoval;
|
||||
|
||||
return DeviceIoControl( hVolume,
|
||||
IOCTL_STORAGE_MEDIA_REMOVAL,
|
||||
&PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
|
||||
NULL, 0,
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int AutoEjectVolume(HANDLE hVolume)
|
||||
{
|
||||
DWORD dwBytesReturned;
|
||||
|
||||
return DeviceIoControl( hVolume,
|
||||
IOCTL_STORAGE_EJECT_MEDIA,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
&dwBytesReturned,
|
||||
NULL);
|
||||
}
|
||||
|
||||
BOOL EjectVolume(TCHAR cDriveLetter)
|
||||
{
|
||||
HANDLE hVolume;
|
||||
|
||||
BOOL fAutoEject = FALSE;
|
||||
|
||||
hVolume = OpenVolume(cDriveLetter);
|
||||
if (hVolume == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
// Lock and dismount the volume.
|
||||
if (LockVolume(hVolume) && DismountVolume(hVolume)) {
|
||||
// Set prevent removal to false and eject the volume.
|
||||
if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume))
|
||||
fAutoEject = TRUE;
|
||||
}
|
||||
|
||||
// Close the volume so other processes can use the drive.
|
||||
if (!CloseVolume(hVolume))
|
||||
return FALSE;
|
||||
|
||||
if (fAutoEject) return TRUE;
|
||||
else return FALSE;
|
||||
}
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <Setupapi.h>
|
||||
#include <winioctl.h>
|
||||
#include <winioctl.h>
|
||||
#include <cfgmgr32.h>
|
||||
#pragma comment(lib, "setupapi.lib")
|
||||
//-------------------------------------------------
|
||||
//----------------------------------------------------------------------
|
||||
// returns the device instance handle of a storage volume or 0 on error
|
||||
//----------------------------------------------------------------------
|
||||
static DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, const wchar_t* szDosDeviceName)
|
||||
{
|
||||
bool IsFloppy = (wcsstr(szDosDeviceName, L"\\Floppy") != NULL); // who knows a better way?
|
||||
|
||||
GUID* guid;
|
||||
|
||||
switch (DriveType) {
|
||||
case DRIVE_REMOVABLE:
|
||||
if ( IsFloppy ) {
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
|
||||
} else {
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
|
||||
}
|
||||
break;
|
||||
case DRIVE_FIXED:
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get device interface info set handle for all devices attached to system
|
||||
HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
|
||||
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Retrieve a context structure for a device interface of a device information set
|
||||
DWORD dwIndex = 0;
|
||||
long res;
|
||||
|
||||
BYTE Buf[1024] = {0};
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
|
||||
SP_DEVICE_INTERFACE_DATA spdid;
|
||||
SP_DEVINFO_DATA spdd;
|
||||
DWORD dwSize;
|
||||
|
||||
spdid.cbSize = sizeof(spdid);
|
||||
|
||||
while ( true ) {
|
||||
res = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);
|
||||
if ( !res ) {
|
||||
break;
|
||||
}
|
||||
|
||||
dwSize = 0;
|
||||
SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); // check the buffer size
|
||||
|
||||
if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
|
||||
|
||||
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
|
||||
|
||||
ZeroMemory(&spdd, sizeof(spdd));
|
||||
spdd.cbSize = sizeof(spdd);
|
||||
|
||||
long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
|
||||
if ( res ) {
|
||||
|
||||
// in case you are interested in the USB serial number:
|
||||
// the device id string contains the serial number if the device has one,
|
||||
// otherwise a generated id that contains the '&' char...
|
||||
/*
|
||||
DEVINST DevInstParent = 0;
|
||||
CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);
|
||||
char szDeviceIdString[MAX_PATH] = {0};
|
||||
CM_Get_Device_ID(DevInstParent, szDeviceIdString, MAX_PATH, 0);
|
||||
printf("DeviceId=%s\n", szDeviceIdString);
|
||||
*/
|
||||
|
||||
// open the disk or cdrom or floppy
|
||||
HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if ( hDrive != INVALID_HANDLE_VALUE ) {
|
||||
// get its device number
|
||||
STORAGE_DEVICE_NUMBER sdn;
|
||||
DWORD dwBytesReturned = 0;
|
||||
res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
|
||||
if ( res ) {
|
||||
if ( DeviceNumber == (long)sdn.DeviceNumber ) { // match the given device number with the one of the current device
|
||||
CloseHandle(hDrive);
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return spdd.DevInst;
|
||||
}
|
||||
}
|
||||
CloseHandle(hDrive);
|
||||
}
|
||||
}
|
||||
}
|
||||
dwIndex++;
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
BOOL EjectVolume(TCHAR DriveLetter)
|
||||
{
|
||||
DriveLetter &= ~0x20; // uppercase
|
||||
|
||||
if ( DriveLetter < 'A' || DriveLetter > 'Z' ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wchar_t szRootPath[] = L"X:\\"; // "X:\" -> for GetDriveType
|
||||
szRootPath[0] = DriveLetter;
|
||||
|
||||
wchar_t szDevicePath[] = L"X:"; // "X:" -> for QueryDosDevice
|
||||
szDevicePath[0] = DriveLetter;
|
||||
|
||||
wchar_t szVolumeAccessPath[] = L"\\\\.\\X:"; // "\\.\X:" -> to open the volume
|
||||
szVolumeAccessPath[4] = DriveLetter;
|
||||
|
||||
long DeviceNumber = -1;
|
||||
|
||||
// open the storage volume
|
||||
HANDLE hVolume = CreateFileW(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
|
||||
if (hVolume == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get the volume's device number
|
||||
STORAGE_DEVICE_NUMBER sdn;
|
||||
DWORD dwBytesReturned = 0;
|
||||
long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
|
||||
if ( res ) {
|
||||
DeviceNumber = sdn.DeviceNumber;
|
||||
}
|
||||
CloseHandle(hVolume);
|
||||
|
||||
if ( DeviceNumber == -1 ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get the drive type which is required to match the device numbers correctely
|
||||
UINT DriveType = GetDriveType(szRootPath);
|
||||
|
||||
// get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
|
||||
wchar_t szDosDeviceName[MAX_PATH] = {0};
|
||||
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
|
||||
if ( !res ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
|
||||
DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName);
|
||||
|
||||
if ( DevInst == 0 ) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
|
||||
wchar_t VetoNameW[MAX_PATH] = {0};
|
||||
bool bSuccess = false;
|
||||
|
||||
// get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
|
||||
DEVINST DevInstParent = 0;
|
||||
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
|
||||
|
||||
for ( long tries=1; tries<=3; tries++ ) { // sometimes we need some tries...
|
||||
|
||||
VetoNameW[0] = 0;
|
||||
|
||||
// CM_Query_And_Remove_SubTree doesn't work for restricted users
|
||||
//res = CM_Query_And_Remove_SubTreeW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K!
|
||||
//res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART); // with messagebox (W2K, Vista) or balloon (XP)
|
||||
|
||||
res = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0);
|
||||
//res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP)
|
||||
|
||||
bSuccess = (res==CR_SUCCESS && VetoType==PNP_VetoTypeUnknown);
|
||||
if ( bSuccess ) {
|
||||
break;
|
||||
}
|
||||
|
||||
Sleep(500); // required to give the next tries a chance!
|
||||
}
|
||||
|
||||
if ( bSuccess ) {
|
||||
printf("Success\n\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
printf("failed\n");
|
||||
|
||||
printf("Result=0x%2X\n", res);
|
||||
|
||||
if ( VetoNameW[0] ) {
|
||||
printf("VetoName=%ws)\n\n", VetoNameW);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
//-----------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#endif
|
69
Src/Plugins/Portable/pmp_ipod/filecopy.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "api.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include "resource.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
typedef struct CopyData
|
||||
{
|
||||
void * callbackContext;
|
||||
void (*callback)(void * callbackContext, wchar_t * status);
|
||||
} CopyData;
|
||||
|
||||
DWORD CALLBACK CopyToIpodProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,
|
||||
LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred,
|
||||
DWORD dwStreamNumber,
|
||||
DWORD dwCallbackReason,
|
||||
HANDLE hSourceFile, HANDLE hDestinationFile,
|
||||
LPVOID lpData)
|
||||
{
|
||||
CopyData *inst = (CopyData *)lpData;
|
||||
if (inst && inst->callback)
|
||||
{
|
||||
wchar_t status[100] = {0};
|
||||
wchar_t langtemp[100] = {0};
|
||||
StringCbPrintf(status, sizeof(status), WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFERRING_PERCENT, langtemp, 100), (int)(100ULL * TotalBytesTransferred.QuadPart / (TotalFileSize.QuadPart)));
|
||||
inst->callback(inst->callbackContext,status);
|
||||
}
|
||||
return PROGRESS_CONTINUE;
|
||||
}
|
||||
|
||||
int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch)
|
||||
{
|
||||
wchar_t langtemp[100] = {0};
|
||||
|
||||
CopyData c;
|
||||
c.callback = callback;
|
||||
c.callbackContext = callbackContext;
|
||||
|
||||
if (CopyFileEx(infile, outfile, CopyToIpodProgressRoutine, &c, killswitch,0))
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_DONE, langtemp, 100));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(GetLastError())
|
||||
{
|
||||
case ERROR_REQUEST_ABORTED:
|
||||
DeleteFile(outfile);
|
||||
if (callback)
|
||||
{
|
||||
callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLED, langtemp, 100));
|
||||
}
|
||||
|
||||
default:
|
||||
if (callback)
|
||||
{
|
||||
callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFER_FAILED, langtemp, 100));
|
||||
}
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
154
Src/Plugins/Portable/pmp_ipod/hash58.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
#include "sha1.h"
|
||||
#include <memory.h>
|
||||
#include <algorithm>
|
||||
|
||||
unsigned char invTable[256] = {
|
||||
0x74, 0x85, 0x96, 0xA7, 0xB8, 0xC9, 0xDA, 0xEB, 0xFC, 0x0D, 0x1E, 0x2F, 0x40, 0x51, 0x62, 0x73,
|
||||
0x84, 0x95, 0xA6, 0xB7, 0xC8, 0xD9, 0xEA, 0xFB, 0x0C, 0x1D, 0x2E, 0x3F, 0x50, 0x61, 0x72, 0x83,
|
||||
0x94, 0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C, 0x2D, 0x3E, 0x4F, 0x60, 0x71, 0x82, 0x93,
|
||||
0xA4, 0xB5, 0xC6, 0xD7, 0xE8, 0xF9, 0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F, 0x70, 0x81, 0x92, 0xA3,
|
||||
0xB4, 0xC5, 0xD6, 0xE7, 0xF8, 0x09, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F, 0x80, 0x91, 0xA2, 0xB3,
|
||||
0xC4, 0xD5, 0xE6, 0xF7, 0x08, 0x19, 0x2A, 0x3B, 0x4C, 0x5D, 0x6E, 0x7F, 0x90, 0xA1, 0xB2, 0xC3,
|
||||
0xD4, 0xE5, 0xF6, 0x07, 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x8F, 0xA0, 0xB1, 0xC2, 0xD3,
|
||||
0xE4, 0xF5, 0x06, 0x17, 0x28, 0x39, 0x4A, 0x5B, 0x6C, 0x7D, 0x8E, 0x9F, 0xB0, 0xC1, 0xD2, 0xE3,
|
||||
0xF4, 0x05, 0x16, 0x27, 0x38, 0x49, 0x5A, 0x6B, 0x7C, 0x8D, 0x9E, 0xAF, 0xC0, 0xD1, 0xE2, 0xF3,
|
||||
0x04, 0x15, 0x26, 0x37, 0x48, 0x59, 0x6A, 0x7B, 0x8C, 0x9D, 0xAE, 0xBF, 0xD0, 0xE1, 0xF2, 0x03,
|
||||
0x14, 0x25, 0x36, 0x47, 0x58, 0x69, 0x7A, 0x8B, 0x9C, 0xAD, 0xBE, 0xCF, 0xE0, 0xF1, 0x02, 0x13,
|
||||
0x24, 0x35, 0x46, 0x57, 0x68, 0x79, 0x8A, 0x9B, 0xAC, 0xBD, 0xCE, 0xDF, 0xF0, 0x01, 0x12, 0x23,
|
||||
0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9A, 0xAB, 0xBC, 0xCD, 0xDE, 0xEF, 0x00, 0x11, 0x22, 0x33,
|
||||
0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x10, 0x21, 0x32, 0x43,
|
||||
0x54, 0x65, 0x76, 0x87, 0x98, 0xA9, 0xBA, 0xCB, 0xDC, 0xED, 0xFE, 0x0F, 0x20, 0x31, 0x42, 0x53,
|
||||
0x64, 0x75, 0x86, 0x97, 0xA8, 0xB9, 0xCA, 0xDB, 0xEC, 0xFD, 0x0E, 0x1F, 0x30, 0x41, 0x52, 0x63
|
||||
};
|
||||
|
||||
unsigned char table1[256] = {
|
||||
0x3A, 0x3F, 0x3E, 0x72, 0xBD, 0xA2, 0xD6, 0xB4, 0x63, 0xC0, 0x6E, 0x62, 0x59, 0x1E, 0xE2, 0x71,
|
||||
0xB5, 0x0D, 0xE8, 0x0C, 0x25, 0x38, 0xCE, 0x23, 0x7C, 0xB7, 0xAD, 0x16, 0xDF, 0x47, 0x3D, 0xB3,
|
||||
0x7E, 0x8C, 0xAA, 0x61, 0x31, 0x66, 0xBE, 0x4F, 0x97, 0x14, 0x54, 0xF0, 0x70, 0xEB, 0x30, 0xC4,
|
||||
0x27, 0x4E, 0xFA, 0x1A, 0x2B, 0x11, 0xF4, 0x45, 0x8E, 0x5D, 0x73, 0xED, 0x22, 0x2E, 0x7D, 0xA4,
|
||||
0x28, 0xDA, 0x2F, 0xC5, 0x92, 0x09, 0x05, 0x13, 0x9D, 0x32, 0x51, 0x4A, 0xC8, 0xBA, 0x96, 0xA7,
|
||||
0x6A, 0x50, 0xF3, 0xBC, 0x93, 0xBF, 0xB0, 0xD2, 0xD5, 0x82, 0x19, 0x98, 0x35, 0xCF, 0x6B, 0xB6,
|
||||
0x83, 0x56, 0x15, 0xF2, 0x9A, 0x9C, 0xCA, 0x74, 0x34, 0x58, 0x8D, 0xA6, 0x03, 0xFF, 0x46, 0x7B,
|
||||
0xD0, 0x7A, 0x33, 0x76, 0xDD, 0xAC, 0xCB, 0x24, 0x7F, 0xB1, 0x85, 0x60, 0xC3, 0x26, 0x8A, 0x1D,
|
||||
0x1C, 0x8F, 0x2A, 0xEF, 0x06, 0xDE, 0x67, 0x5E, 0xE7, 0xAE, 0xD9, 0xCC, 0x07, 0x6C, 0xF8, 0x0A,
|
||||
0xD3, 0x40, 0x36, 0x1F, 0x2D, 0x95, 0x43, 0xDB, 0x01, 0x89, 0x4B, 0xF7, 0xB9, 0x39, 0xC2, 0x52,
|
||||
0x53, 0xFD, 0x65, 0xF5, 0x68, 0xC1, 0xC7, 0x9F, 0x4D, 0xEA, 0xAF, 0x6D, 0x10, 0x44, 0x87, 0xD8,
|
||||
0xEE, 0x1B, 0xFE, 0x3C, 0xDC, 0x84, 0x69, 0x48, 0x6F, 0xD1, 0x57, 0x55, 0xD4, 0xA5, 0x49, 0x5B,
|
||||
0xE5, 0x0B, 0x94, 0xC9, 0x5F, 0xE1, 0x17, 0x81, 0xBB, 0xEC, 0xD7, 0xC6, 0x02, 0x4C, 0x42, 0x75,
|
||||
0xA3, 0x99, 0xE4, 0xA1, 0x9B, 0x5A, 0xF1, 0x29, 0xA0, 0x64, 0x9E, 0x18, 0x41, 0x80, 0x2C, 0x79,
|
||||
0x20, 0x8B, 0xAB, 0x90, 0x08, 0xB8, 0xA9, 0x77, 0x12, 0xF9, 0x0E, 0x88, 0xE9, 0x04, 0xFB, 0x86,
|
||||
0x0F, 0xE0, 0xA8, 0x5C, 0xE6, 0x21, 0xCD, 0x3B, 0x00, 0x78, 0xFC, 0xF6, 0xE3, 0x37, 0xB2, 0x91
|
||||
};
|
||||
|
||||
unsigned char table2[256] = {
|
||||
0xF3, 0xE4, 0x1B, 0x38, 0xE5, 0x6F, 0xE8, 0x9D, 0x3E, 0x55, 0xBA, 0xC7, 0xAC, 0xEA, 0x66, 0xA2,
|
||||
0xB9, 0x7A, 0x34, 0x43, 0x02, 0x4E, 0xFE, 0x36, 0x41, 0x57, 0x1A, 0xB1, 0x31, 0x87, 0x04, 0x52,
|
||||
0x21, 0x22, 0xE1, 0x13, 0x7F, 0x03, 0x3A, 0x90, 0xF7, 0x69, 0x78, 0x12, 0x83, 0x0B, 0x9A, 0x97,
|
||||
0x4D, 0xB7, 0x8C, 0xBF, 0x2D, 0x94, 0xD1, 0x93, 0x2F, 0x42, 0x23, 0xA4, 0xE0, 0x92, 0xDC, 0x68,
|
||||
0xD3, 0xDD, 0xAF, 0x91, 0x9F, 0xED, 0x3D, 0x8F, 0xA1, 0x51, 0xD9, 0xE9, 0x70, 0x28, 0xEF, 0xB3,
|
||||
0x49, 0xA5, 0x0D, 0xC5, 0xD0, 0x60, 0xB4, 0x2B, 0x07, 0xF8, 0xDF, 0xE6, 0x16, 0xC0, 0x30, 0x71,
|
||||
0x85, 0xFD, 0x72, 0x95, 0x29, 0x79, 0x0A, 0x7B, 0x46, 0x11, 0x7D, 0x88, 0x1D, 0x2A, 0x48, 0x1F,
|
||||
0x45, 0x89, 0x47, 0xEE, 0xBB, 0xBE, 0x6E, 0xC3, 0x6C, 0xCE, 0x10, 0x5A, 0x2C, 0xCA, 0xFB, 0xB2,
|
||||
0xCB, 0x1C, 0x9C, 0xEC, 0x2E, 0x56, 0x59, 0x9B, 0xA6, 0x53, 0xAE, 0x17, 0x25, 0xC1, 0x3F, 0x6A,
|
||||
0x0F, 0x09, 0x01, 0xA3, 0xD6, 0xA0, 0xD8, 0x08, 0xE3, 0x74, 0x06, 0x6D, 0x19, 0x98, 0x1E, 0x77,
|
||||
0x76, 0xBC, 0xEB, 0x3C, 0xB0, 0xC4, 0xC8, 0x64, 0x0E, 0x86, 0x63, 0xD7, 0xDB, 0xBD, 0xA7, 0x82,
|
||||
0x39, 0x4F, 0x27, 0xD2, 0x5F, 0x73, 0xF4, 0x75, 0x6B, 0xC2, 0xD5, 0x67, 0x5D, 0x80, 0xAB, 0x81,
|
||||
0xDE, 0xF0, 0xAD, 0xAA, 0xCD, 0xB6, 0xF6, 0x7C, 0xFC, 0x33, 0x05, 0x14, 0x96, 0x15, 0xC9, 0x9E,
|
||||
0x35, 0x5C, 0x7E, 0x44, 0x54, 0x58, 0x3B, 0x40, 0x20, 0xA8, 0x8B, 0x5E, 0x4A, 0x24, 0x99, 0x8E,
|
||||
0xF5, 0xB5, 0x62, 0x00, 0x37, 0x5B, 0x18, 0x65, 0x8D, 0x32, 0xE2, 0xF9, 0xDA, 0x8A, 0xD4, 0xCC,
|
||||
0x26, 0xF2, 0xF1, 0xE7, 0x4B, 0xC6, 0xCF, 0xFF, 0x4C, 0x84, 0x61, 0xFA, 0xB8, 0x0C, 0xA9, 0x50
|
||||
};
|
||||
|
||||
unsigned char fixed[18] = {
|
||||
0x67, 0x23, 0xFE, 0x30, 0x45, 0x33, 0xF8, 0x90, 0x99, 0x21, 0x07, 0xC1, 0xD0, 0x12, 0xB2, 0xA1, 0x07, 0x81
|
||||
};
|
||||
|
||||
int GCD(int a, int b){
|
||||
while( 1 )
|
||||
{
|
||||
a = a % b;
|
||||
if( a == 0 )
|
||||
return b;
|
||||
b = b % a;
|
||||
if( b == 0 )
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
int LCM(int a, int b)
|
||||
{
|
||||
if(a==0 || b==0)
|
||||
return 1;
|
||||
|
||||
return (a*b)/GCD(a,b);
|
||||
}
|
||||
|
||||
|
||||
//pFWID -> 8 bytes
|
||||
//pKey -> 64 byte buffer
|
||||
void GenerateKey(unsigned char *pFWID, unsigned char *pKey){
|
||||
memset(pKey,0, 64);
|
||||
|
||||
int i;
|
||||
unsigned char y[16] = {0};
|
||||
//take LCM of each two bytes in the FWID in turn
|
||||
for(i=0;i<4;i++){
|
||||
int a=pFWID[i*2];
|
||||
int b=pFWID[i*2+1];
|
||||
int lcm = LCM(a,b);
|
||||
|
||||
unsigned char hi = (lcm & 0xFF00) >> 8;
|
||||
unsigned char lo = lcm & 0xFF;
|
||||
|
||||
y[i*4] = ((table1[hi] * 0xB5) - 3);
|
||||
y[i*4 + 1] = ((table2[hi] * 0xB7) + 0x49);
|
||||
y[i*4 + 2] = ((table1[lo] * 0xB5) - 3);
|
||||
y[i*4 + 3] = ((table2[lo] * 0xB7) + 0x49);
|
||||
}
|
||||
|
||||
//convert y
|
||||
for(i=0;i<16;i++){
|
||||
y[i] = invTable[y[i]];
|
||||
}
|
||||
|
||||
//hash
|
||||
SHA1_CTX context;
|
||||
SHA1Init(&context);
|
||||
SHA1Update(&context, fixed, 18);
|
||||
SHA1Update(&context, y, 16);
|
||||
SHA1Final(pKey, &context);
|
||||
}
|
||||
|
||||
//pDataBase -> iTunesDB
|
||||
//pFWID -> 8 bytes
|
||||
//pHash -> 20 byte buffer
|
||||
void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase0, long lSize, unsigned char *pHash)
|
||||
{
|
||||
unsigned char *pDataBase = (unsigned char*)malloc(lSize);
|
||||
memcpy(pDataBase,pDataBase0,lSize);
|
||||
//generate invtable
|
||||
unsigned char key[64] = {0};
|
||||
GenerateKey(pFWID, key);
|
||||
|
||||
//hmac sha1
|
||||
int i;
|
||||
for (i=0; i < 64; i++)
|
||||
key[i] ^= 0x36;
|
||||
|
||||
SHA1_CTX context;
|
||||
|
||||
SHA1Init(&context);
|
||||
SHA1Update(&context, key, 64);
|
||||
SHA1Update(&context, pDataBase, lSize);
|
||||
SHA1Final(pHash, &context);
|
||||
|
||||
for (i=0; i < 64; i++)
|
||||
key[i] ^= 0x36 ^ 0x5c;
|
||||
|
||||
SHA1Init(&context);
|
||||
SHA1Update(&context, key, 64);
|
||||
SHA1Update(&context, pHash, 20);
|
||||
SHA1Final(pHash, &context);
|
||||
|
||||
free(pDataBase);
|
||||
}
|
1
Src/Plugins/Portable/pmp_ipod/hash58.h
Normal file
|
@ -0,0 +1 @@
|
|||
void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase, long lSize, unsigned char *pHash);
|
914
Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.cpp
Normal file
|
@ -0,0 +1,914 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2007 Will Fisher (will.fisher@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iPodArtworkDB.h"
|
||||
#include <algorithm>
|
||||
#include <strsafe.h>
|
||||
|
||||
//utilities
|
||||
#define SAFEDELETE(x) {if(x) delete (x); (x)=0;}
|
||||
#define SAFEFREE(x) {if(x) free(x); (x)=0;}
|
||||
|
||||
static __forceinline unsigned short rev1(const BYTE *data)
|
||||
{
|
||||
return ((unsigned short) data[0]);
|
||||
}
|
||||
|
||||
static __forceinline unsigned short rev1i(const BYTE *data, int &ptr)
|
||||
{
|
||||
unsigned short ret = rev1(data+ptr);
|
||||
ptr+=1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __forceinline unsigned short rev2(const BYTE *data)
|
||||
{
|
||||
unsigned short ret;
|
||||
ret = ((unsigned short) data[1]) << 8;
|
||||
ret += ((unsigned short) data[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __forceinline unsigned short rev2i(const BYTE *data, int &ptr)
|
||||
{
|
||||
unsigned short ret = rev2(data+ptr);
|
||||
ptr+=2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// get 4 bytes from data, reversed
|
||||
static __forceinline unsigned int rev4(const BYTE * data)
|
||||
{
|
||||
unsigned int ret;
|
||||
ret = ((unsigned long) data[3]) << 24;
|
||||
ret += ((unsigned long) data[2]) << 16;
|
||||
ret += ((unsigned long) data[1]) << 8;
|
||||
ret += ((unsigned long) data[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __forceinline unsigned int rev4i(const BYTE * data, int &ptr)
|
||||
{
|
||||
unsigned int ret = rev4(data+ptr);
|
||||
ptr+=4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// get 4 bytes from data
|
||||
static __forceinline unsigned long get4(const unsigned char * data)
|
||||
{
|
||||
unsigned long ret;
|
||||
ret = ((unsigned long) data[0]) << 24;
|
||||
ret += ((unsigned long) data[1]) << 16;
|
||||
ret += ((unsigned long) data[2]) << 8;
|
||||
ret += ((unsigned long) data[3]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __forceinline unsigned long get4i(const unsigned char * data, int &ptr)
|
||||
{
|
||||
unsigned long ret = get4(data+ptr);
|
||||
ptr+=4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// get 8 bytes from data
|
||||
static __forceinline unsigned __int64 get8(const unsigned char * data)
|
||||
{
|
||||
unsigned __int64 ret;
|
||||
ret = get4(data);
|
||||
ret = ret << 32;
|
||||
ret+= get4(data+4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// get 8 bytes from data
|
||||
static __forceinline unsigned __int64 get8i(const unsigned char * data, int &ptr)
|
||||
{
|
||||
unsigned __int64 ret = get8(data+ptr);
|
||||
ptr+=8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// reverse 8 bytes in place
|
||||
static __forceinline unsigned __int64 rev8(unsigned __int64 number)
|
||||
{
|
||||
unsigned __int64 ret;
|
||||
ret = (number&0x00000000000000FF) << 56;
|
||||
ret+= (number&0x000000000000FF00) << 40;
|
||||
ret+= (number&0x0000000000FF0000) << 24;
|
||||
ret+= (number&0x00000000FF000000) << 8;
|
||||
ret+= (number&0x000000FF00000000) >> 8;
|
||||
ret+= (number&0x0000FF0000000000) >> 24;
|
||||
ret+= (number&0x00FF000000000000) >> 40;
|
||||
ret+= (number&0xFF00000000000000) >> 56;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __forceinline void putmh(const char* x, BYTE *data, int &ptr) {
|
||||
data[0+ptr]=x[0];
|
||||
data[1+ptr]=x[1];
|
||||
data[2+ptr]=x[2];
|
||||
data[3+ptr]=x[3];
|
||||
ptr+=4;
|
||||
}
|
||||
|
||||
|
||||
//write 4 bytes reversed
|
||||
static __forceinline void rev4(const unsigned long number, unsigned char * data)
|
||||
{
|
||||
data[3] = (unsigned char)(number >> 24) & 0xff;
|
||||
data[2] = (unsigned char)(number >> 16) & 0xff;
|
||||
data[1] = (unsigned char)(number >> 8) & 0xff;
|
||||
data[0] = (unsigned char)number & 0xff;
|
||||
}
|
||||
|
||||
static __forceinline void rev4i(const unsigned int number, BYTE* data, int &ptr)
|
||||
{
|
||||
rev4(number,data+ptr);
|
||||
ptr+=4;
|
||||
}
|
||||
|
||||
static __forceinline void rev2(const unsigned short number, unsigned char * data)
|
||||
{
|
||||
data[1] = (unsigned char)(number >> 8) & 0xff;
|
||||
data[0] = (unsigned char)number & 0xff;
|
||||
}
|
||||
|
||||
static __forceinline void rev2i(const unsigned short number, BYTE* data, int &ptr)
|
||||
{
|
||||
rev2(number,data+ptr);
|
||||
ptr+=2;
|
||||
}
|
||||
|
||||
static __forceinline void rev1(const unsigned char number, unsigned char * data)
|
||||
{
|
||||
data[0] = number;
|
||||
}
|
||||
|
||||
static __forceinline void rev1i(const unsigned char number, BYTE* data, int &ptr)
|
||||
{
|
||||
rev1(number,data+ptr);
|
||||
ptr+=1;
|
||||
}
|
||||
|
||||
// write 8 bytes normal
|
||||
static __forceinline void put8(unsigned __int64 number, unsigned char * data)
|
||||
{
|
||||
data[0] = (unsigned char)(number >> 56) & 0xff;
|
||||
data[1] = (unsigned char)(number >> 48) & 0xff;
|
||||
data[2] = (unsigned char)(number >> 40) & 0xff;
|
||||
data[3] = (unsigned char)(number >> 32) & 0xff;
|
||||
data[4] = (unsigned char)(number >> 24) & 0xff;
|
||||
data[5] = (unsigned char)(number >> 16) & 0xff;
|
||||
data[6] = (unsigned char)(number >> 8) & 0xff;
|
||||
data[7] = (unsigned char)number & 0xff;
|
||||
}
|
||||
|
||||
static __forceinline void put8i(unsigned __int64 number, unsigned char * data, int &ptr) {
|
||||
put8(number,data+ptr);
|
||||
ptr+=8;
|
||||
}
|
||||
|
||||
static __forceinline void pad(BYTE * data, int endpoint, int& startpoint) {
|
||||
if(endpoint == startpoint) return;
|
||||
ZeroMemory(data+startpoint, endpoint - startpoint);
|
||||
startpoint = endpoint;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtDB
|
||||
|
||||
ArtDB::ArtDB() :
|
||||
headerlen(0x84),
|
||||
totallen(0),
|
||||
unk1(0),
|
||||
unk2(2),
|
||||
unk3(0),
|
||||
nextid(0x40),
|
||||
unk5(0),
|
||||
unk6(0),
|
||||
unk7(0),
|
||||
unk8(0),
|
||||
unk9(0),
|
||||
unk10(0),
|
||||
unk11(0),
|
||||
imageListDS(0),
|
||||
albumListDS(0),
|
||||
fileListDS(0)
|
||||
{
|
||||
}
|
||||
|
||||
ArtDB::~ArtDB() {
|
||||
SAFEDELETE(imageListDS);
|
||||
SAFEDELETE(albumListDS);
|
||||
SAFEDELETE(fileListDS);
|
||||
}
|
||||
|
||||
int ArtDB::parse(BYTE * data, int len, wchar_t drive) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhfd",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x84) return -1;
|
||||
totallen = rev4i(data,ptr);
|
||||
unk1 = rev4i(data,ptr);
|
||||
unk2 = rev4i(data,ptr);
|
||||
int numchildren = rev4i(data,ptr);
|
||||
unk3 = rev4i(data,ptr);
|
||||
nextid = rev4i(data,ptr);
|
||||
unk5 = rev8(get8i(data,ptr));
|
||||
unk6 = rev8(get8i(data,ptr));
|
||||
unk7 = rev4i(data,ptr);
|
||||
unk8 = rev4i(data,ptr);
|
||||
unk9 = rev4i(data,ptr);
|
||||
unk10 = rev4i(data,ptr);
|
||||
unk11 = rev4i(data,ptr);
|
||||
|
||||
ptr=headerlen;
|
||||
|
||||
for(int i=0; i<numchildren; i++) {
|
||||
ArtDataSet * d = new ArtDataSet;
|
||||
int p = d->parse(data+ptr,len-ptr);
|
||||
if(p == -1) return -1;
|
||||
switch(d->index) {
|
||||
case 1: imageListDS = d; break;
|
||||
case 2: albumListDS = d; break;
|
||||
case 3: fileListDS = d; break;
|
||||
default: delete d;
|
||||
}
|
||||
ptr+=p;
|
||||
}
|
||||
if(!imageListDS) imageListDS = new ArtDataSet(1);
|
||||
if(!albumListDS) albumListDS = new ArtDataSet(2);
|
||||
if(!fileListDS) fileListDS = new ArtDataSet(3);
|
||||
|
||||
for(ArtImageList::ArtImageMapIterator i = imageListDS->imageList->images.begin(); i!=imageListDS->imageList->images.end(); i++) {
|
||||
if(i->second) {
|
||||
for(auto j = i->second->dataobjs.begin(); j != i->second->dataobjs.end(); j++) {
|
||||
if((*j)->image) {
|
||||
ArtFile *f = fileListDS->fileList->getFile((*j)->image->corrid);
|
||||
if(!f) {
|
||||
f = new ArtFile();
|
||||
f->corrid = (*j)->image->corrid;
|
||||
fileListDS->fileList->files.push_back(f);
|
||||
}
|
||||
f->images.push_back(new ArtFileImage((*j)->image->ithmboffset,(*j)->image->imagesize,1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto i = fileListDS->fileList->files.begin(); i!=fileListDS->fileList->files.end(); i++) {
|
||||
wchar_t file[MAX_PATH] = {0};
|
||||
StringCchPrintfW(file, MAX_PATH, L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,(*i)->corrid);
|
||||
(*i)->file = _wcsdup(file);
|
||||
(*i)->sortImages();
|
||||
}
|
||||
|
||||
return totallen;
|
||||
}
|
||||
|
||||
int ArtDB::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhfd",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(0,data,ptr); // fill total len here later
|
||||
rev4i(unk1,data,ptr);
|
||||
rev4i(unk2,data,ptr); // always seems to be "2" when iTunes writes it
|
||||
rev4i(3,data,ptr); // num children
|
||||
rev4i(unk3,data,ptr);
|
||||
rev4i(nextid,data,ptr);
|
||||
put8i(rev8(unk5),data,ptr);
|
||||
put8i(rev8(unk6),data,ptr);
|
||||
rev4i(unk7,data,ptr);
|
||||
rev4i(unk8,data,ptr);
|
||||
rev4i(unk9,data,ptr);
|
||||
rev4i(unk10,data,ptr);
|
||||
rev4i(unk11,data,ptr);
|
||||
|
||||
pad(data,headerlen,ptr);
|
||||
|
||||
// write out children
|
||||
int p;
|
||||
p = imageListDS->write(data+ptr,len-ptr);
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
|
||||
p = albumListDS->write(data+ptr,len-ptr);
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
|
||||
p = fileListDS->write(data+ptr,len-ptr);
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
|
||||
rev4(ptr,&data[8]); // fill in total length
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ArtDB::makeEmptyDB(wchar_t drive) {
|
||||
imageListDS = new ArtDataSet(1);
|
||||
albumListDS = new ArtDataSet(2);
|
||||
fileListDS = new ArtDataSet(3);
|
||||
|
||||
for(auto i = fileListDS->fileList->files.begin(); i!=fileListDS->fileList->files.end(); i++) {
|
||||
wchar_t file[MAX_PATH] = {0};
|
||||
StringCchPrintfW(file, MAX_PATH, L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,(*i)->corrid);
|
||||
(*i)->file = _wcsdup(file);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtDatSet
|
||||
|
||||
ArtDataSet::ArtDataSet() :
|
||||
headerlen(0x60),
|
||||
totallen(0),
|
||||
index(0),
|
||||
imageList(0),
|
||||
albumList(0),
|
||||
fileList(0)
|
||||
{
|
||||
}
|
||||
|
||||
ArtDataSet::ArtDataSet(int idx) :
|
||||
headerlen(0x60),
|
||||
totallen(0),
|
||||
index(idx),
|
||||
imageList(0),
|
||||
albumList(0),
|
||||
fileList(0)
|
||||
{
|
||||
switch(idx) {
|
||||
case 1: imageList = new ArtImageList; break;
|
||||
case 2: albumList = new ArtAlbumList; break;
|
||||
case 3: fileList = new ArtFileList; break;
|
||||
default: index=0;
|
||||
}
|
||||
}
|
||||
|
||||
ArtDataSet::~ArtDataSet() {
|
||||
SAFEDELETE(imageList);
|
||||
SAFEDELETE(albumList);
|
||||
SAFEDELETE(fileList);
|
||||
}
|
||||
|
||||
int ArtDataSet::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhsd",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x60) return -1;
|
||||
totallen = rev4i(data,ptr);
|
||||
index = rev4i(data,ptr);
|
||||
|
||||
ptr=headerlen;
|
||||
|
||||
int p=0;
|
||||
switch(index) {
|
||||
case 1: imageList = new ArtImageList; p = imageList->parse(data+ptr, len-ptr); break;
|
||||
case 2: albumList = new ArtAlbumList; p = albumList->parse(data+ptr, len-ptr); break;
|
||||
case 3: fileList = new ArtFileList; p = fileList->parse(data+ptr, len-ptr); break;
|
||||
}
|
||||
|
||||
if(p < 0) return -1;
|
||||
return totallen;
|
||||
}
|
||||
|
||||
int ArtDataSet::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhsd",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(0,data,ptr); // fill total len here later
|
||||
rev4i(index,data,ptr);
|
||||
pad(data,headerlen,ptr);
|
||||
int p=0;
|
||||
switch(index) {
|
||||
case 1: p=imageList->write(data+ptr, len-ptr); break;
|
||||
case 2: p=albumList->write(data+ptr, len-ptr); break;
|
||||
case 3: p=fileList->write(data+ptr, len-ptr); break;
|
||||
}
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
|
||||
rev4(ptr,&data[8]); // fill in total length
|
||||
return ptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtImageList
|
||||
ArtImageList::ArtImageList() :
|
||||
headerlen(0x5c)
|
||||
{
|
||||
}
|
||||
|
||||
ArtImageList::~ArtImageList() {
|
||||
for(ArtImageMapIterator f = images.begin(); f != images.end(); f++)
|
||||
delete f->second;
|
||||
images.clear();
|
||||
}
|
||||
|
||||
int ArtImageList::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhli",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x5c) return -1;
|
||||
int children = rev4i(data,ptr);
|
||||
|
||||
ptr=headerlen;
|
||||
|
||||
for(int i=0; i<children; i++) {
|
||||
ArtImage * f = new ArtImage;
|
||||
int p = f->parse(data+ptr,len-ptr);
|
||||
if(p<0) {delete f; return -1;}
|
||||
ptr+=p;
|
||||
images.insert(ArtImageMapPair(f->songid,f));
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int ArtImageList::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhli",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(images.size(),data,ptr);
|
||||
pad(data,headerlen,ptr);
|
||||
|
||||
for(ArtImageMapIterator f = images.begin(); f != images.end(); f++) {
|
||||
int p = f->second->write(data+ptr,len-ptr);
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtImage
|
||||
ArtImage::ArtImage() :
|
||||
headerlen(0x98),
|
||||
totallen(0),
|
||||
id(0),
|
||||
songid(0),
|
||||
unk4(0),
|
||||
rating(0),
|
||||
unk6(0),
|
||||
originalDate(0),
|
||||
digitizedDate(0),
|
||||
srcImageSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
ArtImage::~ArtImage()
|
||||
{
|
||||
for (auto obj : dataobjs)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
dataobjs.clear();
|
||||
}
|
||||
|
||||
int ArtImage::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhii",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x98) return -1;
|
||||
totallen = rev4i(data,ptr);
|
||||
int numchildren = rev4i(data,ptr);
|
||||
id = rev4i(data,ptr);
|
||||
songid = rev8(get8i(data,ptr));
|
||||
unk4 = rev4i(data,ptr);
|
||||
rating = rev4i(data,ptr);
|
||||
unk6 = rev4i(data,ptr);
|
||||
originalDate = rev4i(data,ptr);
|
||||
digitizedDate = rev4i(data,ptr);
|
||||
srcImageSize = rev4i(data,ptr);
|
||||
|
||||
ptr = headerlen;
|
||||
for(int i=0; i<numchildren; i++) {
|
||||
ArtDataObject *d = new ArtDataObject;
|
||||
int p = d->parse(data+ptr,len-ptr);
|
||||
if(p<0) { delete d; return -1; }
|
||||
ptr+=p;
|
||||
// fuck with d. ugh.
|
||||
if((d->type == 2 || d->type == 5) && d->data) { // this is a container mhod
|
||||
d->image = new ArtImageName;
|
||||
int p2 = d->image->parse(d->data,d->datalen);
|
||||
if(p2>0) {
|
||||
SAFEFREE(d->data);
|
||||
d->datalen=0;
|
||||
} else SAFEDELETE(d->image);
|
||||
}
|
||||
dataobjs.push_back(d);
|
||||
}
|
||||
return totallen;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BYTE *expandMemWrite(T * x, int &len, int maxsize=1024000) {
|
||||
int s = 1024;
|
||||
for(;;) {
|
||||
BYTE *r = (BYTE*)malloc(s);
|
||||
int p = x->write(r,s);
|
||||
if(p>0) {
|
||||
len=p;
|
||||
return r;
|
||||
}
|
||||
free(r);
|
||||
s = s+s;
|
||||
if(s > maxsize) break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ArtImage::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhii",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(0,data,ptr); // fill in total length later
|
||||
rev4i(dataobjs.size(),data,ptr);
|
||||
rev4i(id,data,ptr);
|
||||
put8i(rev8(songid),data,ptr);
|
||||
rev4i(unk4,data,ptr);
|
||||
rev4i(rating,data,ptr);
|
||||
rev4i(unk6,data,ptr);
|
||||
rev4i(originalDate,data,ptr);
|
||||
rev4i(digitizedDate,data,ptr);
|
||||
rev4i(srcImageSize,data,ptr);
|
||||
pad(data,headerlen,ptr);
|
||||
|
||||
for(auto f = dataobjs.begin(); f != dataobjs.end(); f++) {
|
||||
if((*f)->image) {
|
||||
int len=0;
|
||||
BYTE *b = expandMemWrite((*f)->image,len);
|
||||
if(!b) return -1;
|
||||
(*f)->data = b;
|
||||
(*f)->datalen = len;
|
||||
}
|
||||
int p = (*f)->write(data+ptr,len-ptr);
|
||||
if((*f)->image) {
|
||||
SAFEFREE((*f)->data);
|
||||
(*f)->datalen=0;
|
||||
}
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
}
|
||||
rev4(ptr,&data[8]); // fill in total length
|
||||
return ptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtDataObj
|
||||
|
||||
ArtDataObject::ArtDataObject() :
|
||||
headerlen(0x18),
|
||||
type(0),
|
||||
data(0),
|
||||
datalen(0),
|
||||
image(0),
|
||||
unk1(0)
|
||||
{
|
||||
}
|
||||
|
||||
ArtDataObject::~ArtDataObject() {
|
||||
SAFEDELETE(image);
|
||||
SAFEFREE(data);
|
||||
}
|
||||
|
||||
int ArtDataObject::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhod",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x18) return -1;
|
||||
int totallen = rev4i(data,ptr);
|
||||
if(len < totallen) return -1;
|
||||
type = rev2i(data,ptr);
|
||||
unk1 = (unsigned char)rev1i(data,ptr);
|
||||
short padding = rev1i(data,ptr);
|
||||
ptr = headerlen;
|
||||
if(type == 3 && rev2(&data[totallen-2]) == 0)
|
||||
datalen = wcslen((wchar_t*)(data+ptr+12))*sizeof(wchar_t) + 12;
|
||||
else
|
||||
datalen = totallen - headerlen - padding;
|
||||
if(datalen > 0x400 || datalen < 0) return -1;
|
||||
this->data = (BYTE*)malloc(datalen);
|
||||
memcpy(this->data,data+ptr,datalen);
|
||||
|
||||
return totallen;
|
||||
}
|
||||
|
||||
int ArtDataObject::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhod",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
short padding = (4 - ((headerlen + datalen) % 4));// % 4;
|
||||
if(padding == 4) padding = 0;
|
||||
rev4i(headerlen+datalen+padding,data,ptr);
|
||||
rev2i(type,data,ptr);
|
||||
rev1i(unk1,data,ptr);
|
||||
rev1i((unsigned char)padding,data,ptr);
|
||||
pad(data,headerlen,ptr);
|
||||
//write data
|
||||
memcpy(data+ptr,this->data,datalen);
|
||||
ptr+=datalen;
|
||||
//add padding...
|
||||
pad(data,ptr+padding,ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ArtDataObject::GetString(wchar_t * str, int len) {
|
||||
if(rev4(data+4) != 2) { str[0]=0; return; }//not utf-16!
|
||||
int l = (rev4(data)/sizeof(wchar_t));
|
||||
StringCchCopyN(str, len, (wchar_t*)&data[12], l);
|
||||
//lstrcpyn(str,(wchar_t*)&data[12],min(l,len));
|
||||
}
|
||||
|
||||
void ArtDataObject::SetString(wchar_t * str) {
|
||||
SAFEFREE(data);
|
||||
datalen = wcslen(str)*sizeof(wchar_t) + 12;
|
||||
data = (BYTE*)malloc(datalen);
|
||||
rev4(wcslen(str)*sizeof(wchar_t),data);
|
||||
rev4(2,data+4); //type 2 means utf-16
|
||||
rev4(0,data+8); //unk
|
||||
memcpy(data+12,str,wcslen(str)*sizeof(wchar_t));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtImageName
|
||||
ArtImageName::ArtImageName() :
|
||||
headerlen(0x4c),
|
||||
totallen(0),
|
||||
corrid(0),
|
||||
ithmboffset(0),
|
||||
imagesize(0),
|
||||
vpad(0),
|
||||
hpad(0),
|
||||
imgh(0),
|
||||
imgw(0),
|
||||
filename(0)
|
||||
{
|
||||
}
|
||||
|
||||
ArtImageName::~ArtImageName() {
|
||||
SAFEDELETE(filename);
|
||||
}
|
||||
|
||||
int ArtImageName::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhni",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x4c) return -1;
|
||||
totallen = rev4i(data,ptr);
|
||||
int children = rev4i(data,ptr);
|
||||
corrid = rev4i(data,ptr);
|
||||
ithmboffset = rev4i(data,ptr);
|
||||
imagesize = rev4i(data,ptr);
|
||||
vpad = (short)rev2i(data,ptr);
|
||||
hpad = (short)rev2i(data,ptr);
|
||||
imgw = rev2i(data,ptr);
|
||||
imgh = rev2i(data,ptr);
|
||||
|
||||
ptr = headerlen;
|
||||
|
||||
if(children) {
|
||||
filename = new ArtDataObject();
|
||||
int p = filename->parse(data+ptr,len-ptr);
|
||||
if(p<0) SAFEDELETE(filename);
|
||||
}
|
||||
return totallen;
|
||||
}
|
||||
|
||||
int ArtImageName::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhni",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(0,data,ptr); // fill in totallen later
|
||||
rev4i(filename?1:0,data,ptr); //num children
|
||||
rev4i(corrid,data,ptr);
|
||||
rev4i(ithmboffset,data,ptr);
|
||||
rev4i(imagesize,data,ptr);
|
||||
rev2i(vpad,data,ptr);
|
||||
rev2i(hpad,data,ptr);
|
||||
rev2i(imgw,data,ptr);
|
||||
rev2i(imgh,data,ptr);
|
||||
pad(data,headerlen,ptr);
|
||||
if(filename) {
|
||||
int p = filename->write(data+ptr,len-ptr);
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
}
|
||||
rev4(ptr,&data[8]); // fill in totallen
|
||||
return ptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtAlbumList
|
||||
ArtAlbumList::ArtAlbumList() :
|
||||
headerlen(0x5c)
|
||||
{
|
||||
}
|
||||
|
||||
ArtAlbumList::~ArtAlbumList() {}
|
||||
|
||||
int ArtAlbumList::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhla",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x5c) return -1;
|
||||
int children = rev4i(data,ptr);
|
||||
|
||||
if(children != 0) return -1;
|
||||
|
||||
return headerlen;
|
||||
}
|
||||
|
||||
int ArtAlbumList::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhla",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(0,data,ptr); // num children
|
||||
pad(data,headerlen,ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtFileList
|
||||
ArtFileList::ArtFileList() :
|
||||
headerlen(0x5c)
|
||||
{
|
||||
}
|
||||
|
||||
ArtFileList::~ArtFileList()
|
||||
{
|
||||
for (auto file : files)
|
||||
{
|
||||
delete file;
|
||||
}
|
||||
files.clear();
|
||||
}
|
||||
|
||||
int ArtFileList::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhlf",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x5c) return -1;
|
||||
int children = rev4i(data,ptr);
|
||||
|
||||
ptr = headerlen;
|
||||
|
||||
for(int i=0; i<children; i++) {
|
||||
ArtFile * f = new ArtFile;
|
||||
int p = f->parse(data+ptr,len-ptr);
|
||||
if(p<0) { delete f; return -1; }
|
||||
ptr+=p;
|
||||
files.push_back(f);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int ArtFileList::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhlf",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(files.size(),data,ptr); // num children
|
||||
pad(data,headerlen,ptr);
|
||||
|
||||
for(auto f = files.begin(); f != files.end(); f++) {
|
||||
int p = (*f)->write(data+ptr,len-ptr);
|
||||
if(p<0) return -1;
|
||||
ptr+=p;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ArtFile * ArtFileList::getFile(int corrid) {
|
||||
for(auto i = files.begin(); i!=files.end(); i++) {
|
||||
if((*i)->corrid == corrid) return *i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ArtFile
|
||||
ArtFile::ArtFile() :
|
||||
headerlen(0x7c),
|
||||
corrid(0),
|
||||
imagesize(0),
|
||||
file(0)
|
||||
{
|
||||
}
|
||||
|
||||
ArtFile::~ArtFile() {
|
||||
SAFEFREE(file);
|
||||
}
|
||||
|
||||
int ArtFile::parse(BYTE *data, int len) {
|
||||
int ptr=4;
|
||||
if(len < headerlen) return -1;
|
||||
if (_strnicmp((char *)data,"mhif",4)) return -1;
|
||||
headerlen = rev4i(data,ptr);
|
||||
if(headerlen < 0x7c) return -1;
|
||||
int totallen = rev4i(data,ptr);
|
||||
rev4i(data,ptr); // might not be numchildren, it's really unk1
|
||||
corrid = rev4i(data,ptr);
|
||||
imagesize = rev4i(data,ptr);
|
||||
|
||||
return totallen;
|
||||
}
|
||||
|
||||
int ArtFile::write(BYTE *data, int len) {
|
||||
int ptr=0;
|
||||
if(headerlen > len) return -1;
|
||||
putmh("mhif",data,ptr);
|
||||
rev4i(headerlen,data,ptr);
|
||||
rev4i(0,data,ptr); // total len, fill in later
|
||||
rev4i(0,data,ptr); // numchildren/unk1
|
||||
rev4i(corrid,data,ptr);
|
||||
rev4i(imagesize,data,ptr);
|
||||
pad(data,headerlen,ptr);
|
||||
// write children, if we had any...
|
||||
rev4(ptr,&data[8]); // fill in total len
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct ArtFileImageSort {
|
||||
bool operator()(ArtFileImage*& ap,ArtFileImage*& bp) {
|
||||
return ap->start < bp->start;
|
||||
}
|
||||
};
|
||||
|
||||
void ArtFile::sortImages() {
|
||||
std::sort(images.begin(),images.end(),ArtFileImageSort());
|
||||
for(size_t i = 1; i != images.size(); i++)
|
||||
{
|
||||
if(images[i]->start == images[i-1]->start)
|
||||
{
|
||||
images.erase(images.begin() + i);
|
||||
i--;
|
||||
images[i]->refcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t ArtFile::getNextHole(size_t size) {
|
||||
size_t s=0;
|
||||
for(auto i = images.begin(); i!=images.end(); i++) {
|
||||
if((*i)->start - s >= size) return s;
|
||||
s = (*i)->start + (*i)->len;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool writeDataToThumb(wchar_t *file, unsigned short * data, int len) {
|
||||
FILE * f = _wfopen(file,L"ab");
|
||||
if(!f) return false;
|
||||
fwrite(data,len,sizeof(short),f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
232
Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.h
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2007 Will Fisher (will.fisher@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __IPODARTDB_H__
|
||||
#define __IPODARTDB_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
class ArtDB;
|
||||
class ArtDataSet;
|
||||
class ArtImageList;
|
||||
class ArtImage;
|
||||
class ArtImageName;
|
||||
class ArtDataObject;
|
||||
class ArtAlbumList;
|
||||
class ArtFileList;
|
||||
class ArtFile;
|
||||
class ArtFileImage;
|
||||
|
||||
// this contains our whole art database
|
||||
class ArtDB { //mhfd
|
||||
public:
|
||||
int headerlen; //0x84
|
||||
int totallen;
|
||||
int unk1;
|
||||
int unk2; // must be 2
|
||||
// numchildren // should be 3
|
||||
int unk3;
|
||||
uint32_t nextid; // for ArtImage ids, starts at 0x40
|
||||
__int64 unk5;
|
||||
__int64 unk6;
|
||||
int unk7; // 2
|
||||
int unk8; // 0
|
||||
int unk9; // 0
|
||||
int unk10;
|
||||
int unk11;
|
||||
ArtDataSet * imageListDS;
|
||||
ArtDataSet * albumListDS;
|
||||
ArtDataSet * fileListDS;
|
||||
|
||||
ArtDB();
|
||||
~ArtDB();
|
||||
int parse(BYTE * data, int len, wchar_t drive);
|
||||
int write(BYTE * data, int len);
|
||||
|
||||
void makeEmptyDB(wchar_t drive);
|
||||
};
|
||||
|
||||
class ArtDataSet { //mhsd
|
||||
public:
|
||||
int headerlen; //0x60
|
||||
int totallen;
|
||||
int index; // 1=image list, 2=album list, 3=file list
|
||||
ArtImageList * imageList;
|
||||
ArtAlbumList * albumList;
|
||||
ArtFileList * fileList;
|
||||
|
||||
ArtDataSet();
|
||||
ArtDataSet(int idx);
|
||||
~ArtDataSet();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
};
|
||||
|
||||
// contains a list of images
|
||||
class ArtImageList { //mhli
|
||||
public:
|
||||
typedef std::map<uint64_t ,ArtImage*> ArtImageMap;
|
||||
typedef ArtImageMap::iterator ArtImageMapIterator;
|
||||
typedef ArtImageMap::value_type ArtImageMapPair;
|
||||
|
||||
int headerlen; //0x5c
|
||||
//int numchildren;
|
||||
ArtImageMap images;
|
||||
|
||||
ArtImageList();
|
||||
~ArtImageList();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
};
|
||||
|
||||
// contains a reference to an image within an .ithmb file
|
||||
class ArtImage { //mhii
|
||||
public:
|
||||
int headerlen; //0x98
|
||||
int totallen;
|
||||
//int numchildren;
|
||||
uint32_t id;
|
||||
uint64_t songid;
|
||||
int32_t unk4;
|
||||
int32_t rating;
|
||||
int32_t unk6;
|
||||
uint32_t originalDate; //0
|
||||
uint32_t digitizedDate; //0
|
||||
uint32_t srcImageSize; // in bytes
|
||||
std::vector<ArtDataObject*> dataobjs;
|
||||
|
||||
ArtImage();
|
||||
~ArtImage();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
};
|
||||
|
||||
class ArtDataObject { //mhod
|
||||
public:
|
||||
int headerlen; //0x18
|
||||
// total length
|
||||
short type;
|
||||
unsigned char unk1;
|
||||
// unsigned char padding; // must pad to a multiple of 4 bytes! this is usually 2, but can be 0,1,2 or 3
|
||||
BYTE * data;
|
||||
int datalen;
|
||||
ArtImageName * image;
|
||||
|
||||
ArtDataObject();
|
||||
~ArtDataObject();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
|
||||
void GetString(wchar_t * str, int len);
|
||||
void SetString(wchar_t * str);
|
||||
};
|
||||
|
||||
class ArtImageName { //mhni
|
||||
public:
|
||||
int headerlen; //0x4c
|
||||
int totallen;
|
||||
//num children = 1
|
||||
unsigned int corrid;
|
||||
unsigned int ithmboffset;
|
||||
unsigned int imagesize; // in bytes
|
||||
short vpad;
|
||||
short hpad;
|
||||
unsigned short imgh;
|
||||
unsigned short imgw;
|
||||
ArtDataObject* filename;
|
||||
|
||||
ArtImageName();
|
||||
~ArtImageName();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
};
|
||||
|
||||
// this is only used in photo databases (which we don't care about) so it's only a stub
|
||||
class ArtAlbumList { //mhla
|
||||
public:
|
||||
int headerlen; //0x5c
|
||||
//num children, should be 0 for artwork db
|
||||
ArtAlbumList();
|
||||
~ArtAlbumList();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
};
|
||||
|
||||
// this contains the list of .ithmb files
|
||||
class ArtFileList { //mhlf
|
||||
public:
|
||||
int headerlen; //0x5c
|
||||
// num children
|
||||
std::vector<ArtFile*> files;
|
||||
|
||||
ArtFileList();
|
||||
~ArtFileList();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
ArtFile * getFile(int corrid);
|
||||
};
|
||||
|
||||
// this talks about a .ithmb file
|
||||
class ArtFile { //mhif
|
||||
public:
|
||||
int headerlen; //0x7c
|
||||
unsigned int corrid;
|
||||
unsigned int imagesize; // bytes
|
||||
|
||||
ArtFile();
|
||||
~ArtFile();
|
||||
int parse(BYTE *data, int len);
|
||||
int write(BYTE *data, int len);
|
||||
|
||||
std::vector<ArtFileImage*> images;
|
||||
wchar_t * file;
|
||||
void sortImages();
|
||||
size_t getNextHole(size_t size);
|
||||
};
|
||||
|
||||
class ArtFileImage {
|
||||
public:
|
||||
size_t start;
|
||||
size_t len;
|
||||
int refcount;
|
||||
ArtFileImage(size_t start, size_t len, int refcount) : start(start), len(len), refcount(refcount) {}
|
||||
};
|
||||
|
||||
bool writeDataToThumb(wchar_t *file, unsigned short * data, int len);
|
||||
|
||||
#endif //__IPODARTDB_H__
|
4807
Src/Plugins/Portable/pmp_ipod/iPodDB.cpp
Normal file
1256
Src/Plugins/Portable/pmp_ipod/iPodDB.h
Normal file
1795
Src/Plugins/Portable/pmp_ipod/iPodDevice.cpp
Normal file
142
Src/Plugins/Portable/pmp_ipod/iPodDevice.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
#ifndef _IPODDEVICE_H_
|
||||
#define _IPODDEVICE_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <stdio.h>
|
||||
#include <shlobj.h>
|
||||
#include <time.h>
|
||||
#include "..\..\General\gen_ml/ml.h"
|
||||
#include "..\..\Library\ml_pmp/pmp.h"
|
||||
#include "..\..\Library\ml_pmp/transcoder.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "../winamp/ipc_pe.h"
|
||||
#include "iPodDB.h"
|
||||
#include "resource.h"
|
||||
#include "..\..\General\gen_ml/itemlist.h"
|
||||
#include "yail.h"
|
||||
#include "iPodArtworkDB.h"
|
||||
#include "iPodInfo.h"
|
||||
#include <vector>
|
||||
|
||||
class iPodDevice : public Device {
|
||||
public:
|
||||
HWND gapscanner;
|
||||
C_ItemList playlists; // list of iPod_mhyp*
|
||||
Transcoder * transcoder;
|
||||
iPod_mhbd * db;
|
||||
char drive;
|
||||
wchar_t driveW;
|
||||
int dirnum;
|
||||
__int64 transferQueueLength;
|
||||
|
||||
int image16;
|
||||
int image160;
|
||||
|
||||
ArtDB * artdb;
|
||||
std::vector<const ArtworkFormat*> thumbs;
|
||||
uint8_t *fwid;
|
||||
const iPodInfo *info;
|
||||
iPodDevice(char drive);
|
||||
virtual ~iPodDevice();
|
||||
virtual int parseiTunesDB(bool parseArt);
|
||||
virtual int writeiTunesDB();
|
||||
virtual void getFilename(char * buf, int len, songid_t song);
|
||||
virtual void getFilename(wchar_t *buf, int len, songid_t song);
|
||||
virtual __int64 getDeviceCapacityAvailable(); // in bytes
|
||||
virtual __int64 getDeviceCapacityTotal(); // in bytes
|
||||
|
||||
virtual void Eject(); // if you ejected successfully, you MUST call plugin.deviceDisconnected(this) and delete this;
|
||||
virtual void Close(); // save any changes, and call plugin.deviceDisconnected(this) AND delete this;
|
||||
|
||||
// return 0 for success, -1 for failed or cancelled
|
||||
virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
|
||||
void * callbackContext, //pass this to the callback
|
||||
void (*callback)(void * callbackContext, wchar_t * status), // call this with stats every so often so the GUI can be updated
|
||||
songid_t * songid, // fill in the songid when you are finished
|
||||
int * killswitch); // if this gets set to 1, the transfer has been cancelled by the user
|
||||
virtual int trackAddedToTransferQueue(const itemRecordW *track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
|
||||
virtual void trackRemovedFromTransferQueue(const itemRecordW *track);
|
||||
virtual __int64 getTrackSizeOnDevice(const itemRecordW *track); // return the amount of space taken up on the device by the track, or 0 for incompatable (usually the filesize, unless you are transcoding)
|
||||
|
||||
virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
|
||||
|
||||
virtual void commitChanges(){writeiTunesDB();} // optional. Will be called at a good time to save changes
|
||||
|
||||
virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
|
||||
// PlaylistName(0) should return the name of the device.
|
||||
virtual void getPlaylistName(int playlistnumber, wchar_t *buf, int len);
|
||||
virtual int getPlaylistLength(int playlistnumber);
|
||||
virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
|
||||
|
||||
virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // with playlistnumber==0, set the name of the device.
|
||||
virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
|
||||
virtual void sortPlaylist(int playlistnumber, int sortBy);
|
||||
virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
|
||||
virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
|
||||
|
||||
virtual void deletePlaylist(int playlistnumber);
|
||||
virtual int newPlaylist(const wchar_t *name); // create empty playlist, returns playlistnumber
|
||||
|
||||
virtual void getTrackArtist(songid_t songid, wchar_t *buf, int len);
|
||||
virtual void getTrackAlbum(songid_t songid, wchar_t *buf, int len);
|
||||
virtual void getTrackTitle(songid_t songid, wchar_t *buf, int len);
|
||||
virtual int getTrackTrackNum(songid_t songid);
|
||||
virtual int getTrackDiscNum(songid_t songid);
|
||||
virtual void getTrackGenre(songid_t songid, wchar_t *buf, int len);
|
||||
virtual int getTrackYear(songid_t songid);
|
||||
virtual __int64 getTrackSize(songid_t songid); // in bytes
|
||||
virtual int getTrackLength(songid_t songid); // in millisecs
|
||||
virtual int getTrackBitrate(songid_t songid); // in kbps
|
||||
virtual int getTrackPlayCount(songid_t songid);
|
||||
virtual int getTrackRating(songid_t songid); //0-5
|
||||
virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
|
||||
virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
|
||||
virtual void getTrackAlbumArtist(songid_t songid, wchar_t * buf, int len);
|
||||
virtual void getTrackComposer(songid_t songid, wchar_t * buf, int len);
|
||||
virtual int getTrackType(songid_t songid);
|
||||
virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t * buf, int len); //optional
|
||||
|
||||
// feel free to ignore any you don't support
|
||||
virtual void setTrackArtist(intptr_t songid, const wchar_t *value);
|
||||
virtual void setTrackAlbum(intptr_t songid, const wchar_t *value);
|
||||
virtual void setTrackTitle(intptr_t songid, const wchar_t *value);
|
||||
virtual void setTrackTrackNum(intptr_t songid, int value);
|
||||
virtual void setTrackDiscNum(intptr_t songid, int value);
|
||||
virtual void setTrackGenre(intptr_t songid, const wchar_t *value);
|
||||
virtual void setTrackYear(intptr_t songid, int year);
|
||||
virtual void setTrackPlayCount(intptr_t songid, int value);
|
||||
virtual void setTrackRating(intptr_t songid, int value);
|
||||
virtual void setTrackLastPlayed(intptr_t songid, __time64_t value); // in unix time format
|
||||
virtual void setTrackLastUpdated(intptr_t songid, __time64_t value); // in unix time format
|
||||
virtual void setTrackAlbumArtist(songid_t songid, const wchar_t *value);
|
||||
virtual void setTrackComposer(songid_t songid, const wchar_t *value);
|
||||
virtual void setTrackExtraInfo(intptr_t songid, const wchar_t *field, const wchar_t *value) {}; //optional
|
||||
|
||||
virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue); // return false if unsupported
|
||||
|
||||
virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4); // This does nothing yet. For future use.
|
||||
|
||||
virtual bool copyToHardDriveSupported() {return true;}
|
||||
|
||||
virtual __int64 songSizeOnHardDrive(songid_t song) {return getTrackSize(song);} // how big a song will be when copied back. Return -1 for not supported.
|
||||
|
||||
virtual int copyToHardDrive(songid_t song, // the song to copy
|
||||
wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
|
||||
void * callbackContext, //pass this to the callback
|
||||
void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
|
||||
int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
|
||||
); // -1 for failed/not supported. 0 for success.
|
||||
|
||||
// art functions
|
||||
virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
|
||||
virtual pmpart_t getArt(songid_t songid);
|
||||
virtual void releaseArt(pmpart_t art);
|
||||
virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
|
||||
virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
|
||||
virtual void setArtNaturalSize(pmpart_t art, int w, int h);
|
||||
virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
|
||||
virtual bool artIsEqual(pmpart_t a, pmpart_t b);
|
||||
};
|
||||
|
||||
#endif // _IPODDEVICE_H_
|
1040
Src/Plugins/Portable/pmp_ipod/iPodInfo.cpp
Normal file
97
Src/Plugins/Portable/pmp_ipod/iPodInfo.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
#ifndef _IPOD_INFO_H_
|
||||
#define _IPOD_INFO_H_
|
||||
|
||||
#define RGB_565 0
|
||||
#define RGB_555 1
|
||||
#define RGB_555_REC 2
|
||||
typedef enum {
|
||||
THUMB_INVALID = -1,
|
||||
THUMB_COVER_SMALL,
|
||||
THUMB_COVER_MEDIUM1,
|
||||
THUMB_COVER_MEDIUM2,
|
||||
THUMB_COVER_MEDIUM3,
|
||||
THUMB_COVER_MEDIUM4,
|
||||
THUMB_COVER_LARGE,
|
||||
THUMB_PHOTO_SMALL,
|
||||
THUMB_PHOTO_LARGE,
|
||||
THUMB_PHOTO_FULL_SCREEN,
|
||||
THUMB_PHOTO_TV_SCREEN,
|
||||
} ThumbType;
|
||||
|
||||
typedef enum {
|
||||
IPOD_COLOR_WHITE,
|
||||
IPOD_COLOR_BLACK,
|
||||
IPOD_COLOR_SILVER,
|
||||
IPOD_COLOR_BLUE,
|
||||
IPOD_COLOR_PINK,
|
||||
IPOD_COLOR_GREEN,
|
||||
IPOD_COLOR_ORANGE,
|
||||
IPOD_COLOR_GOLD,
|
||||
IPOD_COLOR_RED,
|
||||
IPOD_COLOR_U2,
|
||||
} iPodColor;
|
||||
|
||||
typedef enum {
|
||||
IPOD_MODEL_INVALID=0,
|
||||
IPOD_MODEL_COLOR=1,
|
||||
IPOD_MODEL_REGULAR=2,
|
||||
IPOD_MODEL_MINI=3,
|
||||
IPOD_MODEL_SHUFFLE=4,
|
||||
IPOD_MODEL_VIDEO=5,
|
||||
IPOD_MODEL_NANO=6,
|
||||
IPOD_MODEL_CLASSIC=7,
|
||||
IPOD_MODEL_FATNANO=8,
|
||||
IPOD_MODEL_TOUCH=9,
|
||||
} iPodModel;
|
||||
|
||||
typedef struct {
|
||||
ThumbType type;
|
||||
int width;
|
||||
int height;
|
||||
int correlation_id;
|
||||
int format;
|
||||
int row_align;
|
||||
int image_align;
|
||||
} ArtworkFormat;
|
||||
|
||||
struct iPodModelInfo
|
||||
{
|
||||
// model_number is abbreviated: if the first character is not numeric, it is ommited. e.g. "MA350 -> A350", "M9829 -> 9829"
|
||||
const wchar_t *model_number;
|
||||
iPodModel model;
|
||||
iPodColor color;
|
||||
int image16;
|
||||
int image160;
|
||||
};
|
||||
|
||||
class iPodInfo
|
||||
{
|
||||
public:
|
||||
iPodInfo(const iPodModelInfo *model);
|
||||
~iPodInfo();
|
||||
void SetFWID(const uint8_t *new_fwid);
|
||||
int family_id;
|
||||
wchar_t *model_number;
|
||||
iPodModel model;
|
||||
iPodColor color;
|
||||
int image16;
|
||||
int image160;
|
||||
// Store the supported artwork formats if we
|
||||
// can dynamically read it from the extended sysinfo xml
|
||||
ArtworkFormat* supportedArtworkFormats;
|
||||
size_t numberOfSupportedFormats;
|
||||
unsigned char *fwid;
|
||||
unsigned int shadow_db_version;
|
||||
};
|
||||
|
||||
struct _iPodSerialToModel {
|
||||
const wchar_t *serial;
|
||||
const wchar_t *model_number;
|
||||
};
|
||||
typedef struct _iPodSerialToModel iPodSerialToModel;
|
||||
|
||||
iPodInfo *GetiPodInfo(wchar_t drive);
|
||||
|
||||
const ArtworkFormat* GetArtworkFormats(const iPodInfo* info);
|
||||
|
||||
#endif //_IPOD_INFO_H_
|
523
Src/Plugins/Portable/pmp_ipod/iPodSD.cpp
Normal file
|
@ -0,0 +1,523 @@
|
|||
#include "iPodSD.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
// get 3 bytes from data (used in iTunesSD1)
|
||||
static __forceinline unsigned long get3(const uint8_t * data)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
ret += ((unsigned long) data[0]) << 16;
|
||||
ret += ((unsigned long) data[1]) << 8;
|
||||
ret += ((unsigned long) data[2]);
|
||||
return ret;
|
||||
}
|
||||
//write 3 bytes normal (used in iTunesSD1)
|
||||
static __forceinline void put3(const unsigned long number, uint8_t * data)
|
||||
{
|
||||
data[0] = (uint8_t)(number >> 16) & 0xff;
|
||||
data[1] = (uint8_t)(number >> 8) & 0xff;
|
||||
data[2] = (uint8_t)number & 0xff;
|
||||
}
|
||||
|
||||
// pass data and ptr, updates ptr automatically (by reference)
|
||||
static __forceinline void write_uint64_t(uint8_t *data, size_t &offset, uint64_t value)
|
||||
{
|
||||
memcpy(&data[offset], &value, 8);
|
||||
offset+=8;
|
||||
}
|
||||
|
||||
// pass data and ptr, updates ptr automatically (by reference)
|
||||
static __forceinline void write_uint32_t(uint8_t *data, size_t &offset, uint32_t value)
|
||||
{
|
||||
memcpy(&data[offset], &value, 4);
|
||||
offset+=4;
|
||||
}
|
||||
|
||||
// pass data and ptr, updates ptr automatically (by reference)
|
||||
static __forceinline void write_uint16_t(uint8_t *data, size_t &offset, uint16_t value)
|
||||
{
|
||||
memcpy(&data[offset], &value, 2);
|
||||
offset+=2;
|
||||
}
|
||||
|
||||
|
||||
// pass data and ptr, updates ptr automatically (by reference)
|
||||
static __forceinline void write_uint8_t(uint8_t *data, size_t &offset, uint8_t value)
|
||||
{
|
||||
data[offset++] = value;
|
||||
}
|
||||
|
||||
// pass data and ptr, updates ptr automatically (by reference)
|
||||
static __forceinline void write_header(uint8_t *data, size_t &offset, const char *header)
|
||||
{
|
||||
data[offset++] = header[0];
|
||||
data[offset++] = header[1];
|
||||
data[offset++] = header[2];
|
||||
data[offset++] = header[3];
|
||||
}
|
||||
|
||||
|
||||
// Case insensitive version of wcsstr
|
||||
static wchar_t *wcsistr (const wchar_t *s1, const wchar_t *s2)
|
||||
{
|
||||
wchar_t *cp = (wchar_t*) s1;
|
||||
wchar_t *s, *t, *endp;
|
||||
wchar_t l, r;
|
||||
|
||||
endp = (wchar_t*)s1 + ( lstrlen(s1) - lstrlen(s2)) ;
|
||||
while (cp && *cp && (cp <= endp))
|
||||
{
|
||||
s = cp;
|
||||
t = (wchar_t*)s2;
|
||||
while (s && *s && t && *t)
|
||||
{
|
||||
l = towupper(*s);
|
||||
r = towupper(*t);
|
||||
if (l != r)
|
||||
break;
|
||||
s++, t++;
|
||||
}
|
||||
|
||||
if (*t == 0)
|
||||
return cp;
|
||||
|
||||
cp = CharNext(cp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// iTunesSD1 - Classes for dealing with the iPodShuffle
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
iTunesSD1::iTunesSD1()
|
||||
{
|
||||
}
|
||||
|
||||
iTunesSD1::~iTunesSD1()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
long iTunesSD1::write(const iPod_mhlt::mhit_map_t *songs, unsigned char * data, const unsigned long datasize)
|
||||
{
|
||||
#ifdef IPODDB_PROFILER
|
||||
profiler(iPodDB__iTunesSD_write);
|
||||
#endif
|
||||
|
||||
const unsigned int numsongs = songs->size();
|
||||
const unsigned int total_size = 18 + (numsongs * 558);
|
||||
ASSERT(datasize >= total_size);
|
||||
if(datasize < total_size)
|
||||
return(-1);
|
||||
|
||||
long ptr=0;
|
||||
|
||||
put3(numsongs, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
put3(0x010600, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
put3(0x12, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
iPod_mhlt::mhit_map_t::const_iterator begin = songs->begin();
|
||||
iPod_mhlt::mhit_map_t::const_iterator end = songs->end();
|
||||
for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
|
||||
{
|
||||
iPod_mhit *m = ((*it).second);
|
||||
iTunesSD_Song song(m);
|
||||
long ret = song.write(&data[ptr], datasize - ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ptr += ret;
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
iTunesSD_Song::iTunesSD_Song(const iPod_mhit *m) : size_total(0x22e), starttime(0), stoptime(0), volume(0x64), filetype(0), playflags(iTunesSD_Song::SHUFFLE)
|
||||
{
|
||||
memset(filename, 0, (SDSONG_FILENAME_LEN + 1) * sizeof(wchar_t));
|
||||
|
||||
|
||||
iPod_mhod *mhod = m->FindString(MHOD_LOCATION);
|
||||
ASSERT(mhod);
|
||||
if(mhod)
|
||||
{
|
||||
// Convert from HFS format (:iPod_Control:Music:F00:filename) to quasi-FAT format (/iPod_Control/Music/F00/filename) filepaths
|
||||
SetFilename(mhod->str);
|
||||
wchar_t *w = filename;
|
||||
while(w && *w != '\0')
|
||||
{
|
||||
if(*w == ':')
|
||||
*w = '/';
|
||||
|
||||
w = CharNext(w);
|
||||
}
|
||||
|
||||
|
||||
SetStartTime(m->starttime);
|
||||
SetStopTime(m->stoptime);
|
||||
|
||||
int volume = (int)m->volume;
|
||||
|
||||
// If Sound Check information is present, use that instead of volume
|
||||
if(m->soundcheck != 0)
|
||||
{
|
||||
// This code converts SoundCheck back into a gain value, then into a -255 to 255 mhit::volume value
|
||||
const double gain = -10.0 * log10(m->soundcheck / 1000.0);
|
||||
volume = (int)(gain * 12.75); // XXX - this might not be the best way to convert the gain value...
|
||||
}
|
||||
|
||||
if(volume < -255)
|
||||
volume = -255;
|
||||
else if(volume > 255)
|
||||
volume = 255;
|
||||
|
||||
// Convert the volume value into a percentage for SetVolume
|
||||
SetVolume((int)((double)volume / 2.55));
|
||||
|
||||
|
||||
// To determine the filetype, first check the MHOD_FILETYPE type. If that isn't available, fallback to file extension
|
||||
iPod_mhod *mtype = m->FindString(MHOD_FILETYPE);
|
||||
if(mtype != NULL)
|
||||
{
|
||||
if(wcsistr(mtype->str, L"MPEG") != NULL || wcsistr(mtype->str, L"MP3") != NULL)
|
||||
filetype = iTunesSD_Song::MP3;
|
||||
else if(wcsistr(mtype->str, L"AAC") != NULL)
|
||||
filetype = iTunesSD_Song::AAC;
|
||||
else if(wcsistr(mtype->str, L"WAV") != NULL)
|
||||
filetype = iTunesSD_Song::WAV;
|
||||
}
|
||||
if(filetype == 0)
|
||||
{
|
||||
if(wcsistr(mhod->str, L".mp3") != NULL)
|
||||
filetype = iTunesSD_Song::MP3;
|
||||
else if(wcsistr(mhod->str, L".m4a") != NULL || wcsistr(mhod->str, L".m4b") != NULL || wcsistr(mhod->str, L".m4p") != NULL)
|
||||
filetype = iTunesSD_Song::AAC;
|
||||
else if(wcsistr(mhod->str, L".wav") != NULL)
|
||||
filetype = iTunesSD_Song::WAV;
|
||||
}
|
||||
ASSERT(filetype != 0);
|
||||
if(filename == 0)
|
||||
filetype = iTunesSD_Song::MP3; // Default to mp3
|
||||
|
||||
|
||||
if(wcsistr(mhod->str, L".m4b") != NULL)
|
||||
playflags = iTunesSD_Song::BOOKMARKABLE; // Only playback in normal mode
|
||||
else
|
||||
playflags = iTunesSD_Song::SHUFFLE; // Playable in normal/shuffle modes, but not bookmarkable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long iTunesSD_Song::write(unsigned char * data, const unsigned long datasize)
|
||||
{
|
||||
#ifdef IPODDB_PROFILER
|
||||
profiler(iPodDB__iTunesSD_Song_write);
|
||||
#endif
|
||||
long ptr=0;
|
||||
|
||||
ASSERT(size_total == 0x22e);
|
||||
ASSERT(filetype != 0);
|
||||
|
||||
put3(size_total, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
put3(0x005aa501, &data[ptr]);
|
||||
|
||||
ptr+=3;
|
||||
put3(starttime, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(stoptime, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(volume, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(filetype, &data[ptr]);
|
||||
ptr+=3;
|
||||
put3(0x200, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
const unsigned int bufSize = (SDSONG_FILENAME_LEN + 1) * sizeof(wchar_t);
|
||||
memcpy(&data[ptr], filename, bufSize);
|
||||
ptr+=bufSize;
|
||||
|
||||
put3(playflags, &data[ptr]);
|
||||
ptr+=3;
|
||||
|
||||
ASSERT(size_total == ptr);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
void iTunesSD_Song::SetFilename(const wchar_t *filename)
|
||||
{
|
||||
#ifdef IPODDB_PROFILER
|
||||
profiler(iPodDB__iTunesStats_SetFilename);
|
||||
#endif
|
||||
|
||||
ASSERT(filename != NULL);
|
||||
if(filename == NULL)
|
||||
return;
|
||||
|
||||
if(filename)
|
||||
{
|
||||
lstrcpyn(this->filename, filename, SDSONG_FILENAME_LEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(this->filename, 0, SDSONG_FILENAME_LEN * sizeof(wchar_t));
|
||||
}
|
||||
}
|
||||
|
||||
// Accepts values from -100 to 100, with 0 meaning no volume change
|
||||
void iTunesSD_Song::SetVolume(const int percent)
|
||||
{
|
||||
int p = percent;
|
||||
if(p > 100)
|
||||
p = 100;
|
||||
else if(p < -100)
|
||||
p = -100;
|
||||
|
||||
// Volume ranges from 0 (-100%) to 100 (0%) to 200 (100%)
|
||||
volume = (unsigned int)(percent + 100);
|
||||
}
|
||||
|
||||
|
||||
/* Shadow DB version 2 */
|
||||
long iTunesSD2::write(const iPod_mhlt *songs, const iPod_mhlp *playlists, unsigned char * data, const unsigned long datasize)
|
||||
{
|
||||
uint32_t numsongs = songs->GetChildrenCount();
|
||||
uint32_t numplaylists = playlists->GetChildrenCount();
|
||||
size_t offset=0;
|
||||
size_t ptr=0;
|
||||
|
||||
if (datasize < 64)
|
||||
return -1;
|
||||
|
||||
write_header(data, ptr, "bdhs");
|
||||
write_uint32_t(data, ptr, 0x02000003); /* also have seen 0x02010001, perhaps a DB version number? */
|
||||
write_uint32_t(data, ptr, 64); /* length of header */
|
||||
write_uint32_t(data, ptr, numsongs);
|
||||
write_uint32_t(data, ptr, numplaylists); /* number of playlists */
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint8_t(data, ptr, 0); /* volume limit */
|
||||
write_uint8_t(data, ptr, 1); /* voiceover */
|
||||
write_uint16_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, numsongs); /* TODO number of tracks w/o podcasts and audiobooks*/
|
||||
write_uint32_t(data, ptr, 64); /* track header offset */
|
||||
write_uint32_t(data, ptr, 64+20 + numsongs*4+iTunesSD2_Song::header_size*numsongs); /* playlist header offset */
|
||||
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
offset = 64;
|
||||
|
||||
uint32_t hths_header_size = 20+numsongs*4;
|
||||
if (datasize - ptr < hths_header_size)
|
||||
return -1;
|
||||
write_header(data, ptr, "hths");
|
||||
write_uint32_t(data, ptr, hths_header_size); /* header length */
|
||||
write_uint32_t(data, ptr, numsongs);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
offset += hths_header_size;
|
||||
/* positions for each track */
|
||||
for (size_t i=0;i<numsongs;i++)
|
||||
{
|
||||
write_uint32_t(data, ptr, offset + iTunesSD2_Song::header_size * i);
|
||||
}
|
||||
|
||||
/* write tracks */
|
||||
for (uint32_t i=0;i<numsongs;i++)
|
||||
{
|
||||
iPod_mhit *m = songs->GetTrack(i);
|
||||
long ret = iTunesSD2_Song::write(m, &data[ptr], datasize - ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ptr += ret;
|
||||
offset += ret;
|
||||
}
|
||||
|
||||
uint32_t podcast_playlist_count=0;
|
||||
for (size_t i=0;i<numplaylists;i++)
|
||||
{
|
||||
iPod_mhyp *p = playlists->GetPlaylist(i);
|
||||
if (p->podcastflag)
|
||||
podcast_playlist_count++;
|
||||
}
|
||||
|
||||
uint32_t hphs_header_size = 20 + numplaylists*4;
|
||||
if (datasize - ptr < hphs_header_size)
|
||||
return -1;
|
||||
|
||||
write_header(data, ptr, "hphs");
|
||||
write_uint32_t(data, ptr, hphs_header_size); /* header length */
|
||||
write_uint32_t(data, ptr, numplaylists);
|
||||
write_uint16_t(data, ptr, 0);
|
||||
write_uint16_t(data, ptr, numplaylists-podcast_playlist_count); /* non-podcast playlists */
|
||||
write_uint16_t(data, ptr, 1); /* master playlists */
|
||||
write_uint16_t(data, ptr, numplaylists); /* non-audiobook playlists */
|
||||
offset += hphs_header_size;
|
||||
|
||||
/* write offsets for each track */
|
||||
for (size_t i=0;i<numplaylists;i++)
|
||||
{
|
||||
iPod_mhyp *p = playlists->GetPlaylist(i);
|
||||
write_uint32_t(data, ptr, offset);
|
||||
offset += p->GetMhipChildrenCount()*4 + 44;
|
||||
}
|
||||
|
||||
iPod_mhyp *master_playlist = playlists->GetPlaylist(0);
|
||||
/* write playlists */
|
||||
for (size_t i=0;i<numplaylists;i++)
|
||||
{
|
||||
iPod_mhyp *p = playlists->GetPlaylist(i);
|
||||
long ret = iTunesSD2_Playlist::write(master_playlist, p, &data[ptr], datasize - ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ptr += ret;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
uint32_t iTunesSD2_Song::header_size = 372;
|
||||
|
||||
long iTunesSD2_Song::write(const iPod_mhit *mhit, unsigned char *data, const unsigned long datasize)
|
||||
{
|
||||
if (datasize < header_size)
|
||||
return -1;
|
||||
|
||||
size_t ptr=0;
|
||||
write_header(data, ptr, "rths");
|
||||
write_uint32_t(data, ptr, header_size); /* length of header */
|
||||
write_uint32_t(data, ptr, mhit->starttime); /* start time, in milliseconds */
|
||||
write_uint32_t(data, ptr, mhit->stoptime); /* stop time, in milliseconds */
|
||||
write_uint32_t(data, ptr, mhit->volume); /* volume */
|
||||
switch(mhit->filetype)
|
||||
{
|
||||
case FILETYPE_WAV:
|
||||
write_uint32_t(data, ptr, iTunesSD_Song::WAV); /* file type */
|
||||
break;
|
||||
case FILETYPE_M4A:
|
||||
case 0x4d344220:
|
||||
case 0x4d345020:
|
||||
write_uint32_t(data, ptr, iTunesSD_Song::AAC); /* file type */
|
||||
break;
|
||||
case FILETYPE_MP3:
|
||||
default:
|
||||
write_uint32_t(data, ptr, iTunesSD_Song::MP3); /* file type */
|
||||
break;
|
||||
}
|
||||
|
||||
iPod_mhod *mhod = mhit->FindString(MHOD_LOCATION);
|
||||
|
||||
char filename[256] = {0};
|
||||
int converted = WideCharToMultiByte(CP_UTF8, 0, mhod->str, -1, filename, 256, 0, 0);
|
||||
for (int i=0;i<converted;i++)
|
||||
{
|
||||
if (filename[i] == ':')
|
||||
filename[i] = '/';
|
||||
}
|
||||
memcpy(&data[ptr], filename, converted);
|
||||
ptr+=converted;
|
||||
memset(&data[ptr], 0, 256-converted);
|
||||
ptr+=256-converted;
|
||||
|
||||
write_uint32_t(data, ptr, mhit->bookmarktime); /* bookmark time */
|
||||
write_uint8_t(data, ptr, 0); /* skip flag */
|
||||
write_uint8_t(data, ptr, mhit->rememberPosition); /* remember playback position */
|
||||
write_uint8_t(data, ptr, 0); /* part of gapless album */
|
||||
write_uint8_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, mhit->pregap); /* pre-gap */
|
||||
write_uint32_t(data, ptr, mhit->postgap); /* post-gap */
|
||||
write_uint64_t(data, ptr, mhit->samplecount); /* number of samples */
|
||||
write_uint32_t(data, ptr, mhit->gaplessData); /* gapless data */
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, mhit->album_id); /* album ID */
|
||||
write_uint16_t(data, ptr, mhit->tracknum); /* track number */
|
||||
write_uint16_t(data, ptr, mhit->cdnum); /* disc number */
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint64_t(data, ptr, mhit->dbid); /* dbid */
|
||||
write_uint32_t(data, ptr, 0); /* artist ID */
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
long iTunesSD2_Playlist::write(const iPod_mhyp *master_playlist, const iPod_mhyp *playlist, unsigned char * data, const unsigned long datasize)
|
||||
{
|
||||
size_t ptr=0;
|
||||
uint32_t tracks = playlist->GetMhipChildrenCount();
|
||||
uint32_t header_size = 44 + tracks*4;
|
||||
if (datasize < header_size)
|
||||
return -1;
|
||||
|
||||
write_header(data, ptr, "lphs");
|
||||
write_uint32_t(data, ptr, header_size); /* header length */
|
||||
write_uint32_t(data, ptr, tracks); /* number of tracks */
|
||||
|
||||
/* number of music tracks TODO: special handling for master playlist */
|
||||
if (playlist->podcastflag)
|
||||
write_uint32_t(data, ptr, 0);
|
||||
else
|
||||
write_uint32_t(data, ptr, tracks);
|
||||
|
||||
write_uint64_t(data, ptr, playlist->playlistID); /* playlist ID */
|
||||
|
||||
/* playlist type */
|
||||
if (playlist->podcastflag)
|
||||
write_uint32_t(data, ptr, 3); /* podcast */
|
||||
else if (playlist->hidden)
|
||||
write_uint32_t(data, ptr, 1); /* master playlist */
|
||||
else
|
||||
write_uint32_t(data, ptr, 2); /* normal */
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
write_uint32_t(data, ptr, 0);
|
||||
if (master_playlist == playlist)
|
||||
{
|
||||
for (uint32_t i=0;i<tracks;i++)
|
||||
{
|
||||
write_uint32_t(data, ptr, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i=0;i<tracks;i++)
|
||||
{
|
||||
iPod_mhip *item = playlist->GetPlaylistEntry(i);
|
||||
uint32_t master_index = master_playlist->FindPlaylistEntry(item->songindex);
|
||||
assert(master_index != -1);
|
||||
write_uint32_t(data, ptr, master_index);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
78
Src/Plugins/Portable/pmp_ipod/iPodSD.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
#include <bfc/platform/types.h>
|
||||
#include "iPodDB.h"
|
||||
/* iPod shuffle Shadow Database code */
|
||||
|
||||
// iTunesSD (iPod Shuffle) Database Classes
|
||||
class iTunesSD_Song;
|
||||
class iTunesSD2_Song;
|
||||
|
||||
|
||||
class iTunesSD1
|
||||
{
|
||||
public:
|
||||
iTunesSD1();
|
||||
~iTunesSD1();
|
||||
|
||||
long write(const iPod_mhlt::mhit_map_t *mhit, unsigned char * data, const unsigned long datasize);
|
||||
};
|
||||
|
||||
class iTunesSD2
|
||||
{
|
||||
public:
|
||||
long write(const iPod_mhlt *mhit, const iPod_mhlp *playlists, unsigned char * data, const unsigned long datasize);
|
||||
};
|
||||
|
||||
#define SDSONG_FILENAME_LEN 260
|
||||
|
||||
|
||||
class iTunesSD_Song
|
||||
{
|
||||
public:
|
||||
iTunesSD_Song(const iPod_mhit *mhit);
|
||||
enum FileType
|
||||
{
|
||||
MP3 = 0x01,
|
||||
AAC = 0x02,
|
||||
WAV = 0x04
|
||||
};
|
||||
|
||||
enum PlayFlags
|
||||
{
|
||||
UNKNOWN = 0x000001, // Might do something special, but nothing has been observed so far
|
||||
BOOKMARKABLE = 0x000100, // Any song that has flag is bookmarked
|
||||
SHUFFLE = 0x010000 // Only songs that have this flag are available in shuffle playback mode
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
long write(unsigned char * data, const unsigned long datasize);
|
||||
|
||||
void SetFilename(const wchar_t *filename);
|
||||
void SetStartTime(const double milliseconds) { starttime = (unsigned int)(milliseconds / 256.0); }
|
||||
void SetStopTime(const double milliseconds) { stoptime = (unsigned int)(milliseconds / 256.0); }
|
||||
void SetVolume(const int percent);
|
||||
|
||||
// These are also only 3 byte values
|
||||
uint32_t size_total;
|
||||
uint32_t starttime;
|
||||
uint32_t stoptime;
|
||||
uint32_t volume; // -100% = 0x0, 0% = 0x64 (100), 100% = 0xc8 (200)
|
||||
uint32_t filetype; // 0x01 = MP3, 0x02 = AAC, 0x04 = WAV
|
||||
wchar_t filename[SDSONG_FILENAME_LEN + 1]; // Equal to Windows' MAX_PATH, plus the trailing NULL (261 wide chars = 522 bytes)
|
||||
unsigned int playflags;
|
||||
};
|
||||
|
||||
class iTunesSD2_Song
|
||||
{
|
||||
public:
|
||||
static long write(const iPod_mhit *mhit, unsigned char * data, const unsigned long datasize);
|
||||
static uint32_t header_size;
|
||||
};
|
||||
|
||||
class iTunesSD2_Playlist
|
||||
{
|
||||
public:
|
||||
static long write(const iPod_mhyp *master_playlist, const iPod_mhyp *playlist, unsigned char * data, const unsigned long datasize);
|
||||
};
|
336
Src/Plugins/Portable/pmp_ipod/main.cpp
Normal file
|
@ -0,0 +1,336 @@
|
|||
//#define PLUGIN_NAME "Nullsoft iPod Plug-in"
|
||||
#define PLUGIN_VERSION L"0.91"
|
||||
|
||||
#include "iPodDevice.h"
|
||||
#include <Dbt.h>
|
||||
#include "..\..\General\gen_ml/itemlist.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include "api.h"
|
||||
#include "../nu/autoLock.h"
|
||||
#include "deviceprovider.h"
|
||||
#include <tataki/export.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
int init();
|
||||
void quit();
|
||||
intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
|
||||
|
||||
extern PMPDevicePlugin plugin = {PMPHDR_VER,0,init,quit,MessageProc};
|
||||
|
||||
static DWORD WINAPI ThreadFunc_DeviceChange(LPVOID lpParam);
|
||||
|
||||
bool g_detectAll=false;
|
||||
|
||||
std::vector<iPodDevice*> iPods;
|
||||
|
||||
api_config *AGAVE_API_CONFIG=0;
|
||||
api_memmgr *WASABI_API_MEMMGR=0;
|
||||
api_albumart *AGAVE_API_ALBUMART=0;
|
||||
api_threadpool *WASABI_API_THREADPOOL=0;
|
||||
api_application *WASABI_API_APP=0;
|
||||
api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
|
||||
|
||||
// wasabi based services for localisation support
|
||||
api_language *WASABI_API_LNG = 0;
|
||||
|
||||
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
||||
|
||||
static Nullsoft::Utility::LockGuard connect_guard;
|
||||
static DeviceProvider *deviceProvider = NULL;
|
||||
static bool loading_devices[26] = {0,};
|
||||
|
||||
template <class api_T>
|
||||
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
|
||||
{
|
||||
if (plugin.service)
|
||||
{
|
||||
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
|
||||
if (factory)
|
||||
api_t = reinterpret_cast<api_T *>( factory->getInterface() );
|
||||
}
|
||||
}
|
||||
|
||||
template <class api_T>
|
||||
void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
|
||||
{
|
||||
if (plugin.service && api_t)
|
||||
{
|
||||
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
|
||||
if (factory)
|
||||
factory->releaseInterface(api_t);
|
||||
}
|
||||
api_t = NULL;
|
||||
}
|
||||
|
||||
static bool createBlankDatabase(wchar_t drive) {
|
||||
wchar_t ipodtest[]={drive,L":\\iPod_Control\\iTunes\\iTunesDB"};
|
||||
iPod_mhbd db;
|
||||
BYTE data[4096] = {0};
|
||||
long l = db.write(data,sizeof(data));
|
||||
if(l <= 0) return false;
|
||||
FILE* fh=_wfopen(ipodtest,L"wb");
|
||||
if(!fh) return false;
|
||||
if(fwrite(data,l,1,fh))
|
||||
{
|
||||
wchar_t ipodtest2[]={drive,L":\\iPod_Control\\iTunes\\firsttime"};
|
||||
_wunlink(ipodtest2);
|
||||
}
|
||||
fclose(fh);
|
||||
wchar_t music[] = {drive,L":\\iPod_Control\\Music"};
|
||||
CreateDirectoryW(music,NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ConnectDrive(wchar_t drive, bool connect)
|
||||
{
|
||||
bool result;
|
||||
size_t index;
|
||||
iPodDevice *device;
|
||||
|
||||
Nullsoft::Utility::AutoLock connect_lock(connect_guard);
|
||||
|
||||
// capitalize
|
||||
if (drive >= L'a' && drive <= L'z')
|
||||
drive = drive - 32;
|
||||
|
||||
// reject invalid drive letters
|
||||
if (drive < L'A' || drive > L'Z')
|
||||
return false;
|
||||
|
||||
if (false != loading_devices[drive-'A'])
|
||||
return false;
|
||||
|
||||
|
||||
loading_devices[drive-'A'] = true;
|
||||
|
||||
if (false != connect)
|
||||
{
|
||||
result = true;
|
||||
|
||||
char ipodtest[]= {(char)drive,":\\iPod_Control\\iTunes\\iTunesDB"};
|
||||
if (GetFileAttributes(ipodtest) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
char ipodtest2[]={(char)drive,":\\iPod_Control\\iTunes\\firsttime"};
|
||||
if (GetFileAttributes(ipodtest2) == INVALID_FILE_ATTRIBUTES ||
|
||||
false == createBlankDatabase(drive))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (false != result)
|
||||
{
|
||||
index = iPods.size();
|
||||
while(index--)
|
||||
{
|
||||
device = iPods[index];
|
||||
if(device->drive == drive)
|
||||
break;
|
||||
}
|
||||
|
||||
if((size_t)-1 == index)
|
||||
{
|
||||
iPodDevice *d = new iPodDevice((char)drive);
|
||||
}
|
||||
else
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
|
||||
index = iPods.size();
|
||||
while(index--)
|
||||
{
|
||||
device = iPods.at(index);
|
||||
if (device->drive == drive)
|
||||
{
|
||||
SendNotifyMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)device,PMP_IPC_DEVICEDISCONNECTED);
|
||||
iPods.erase(iPods.begin() + index);
|
||||
delete device;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loading_devices[drive-'A'] = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void autoDetectCallback(wchar_t driveW, UINT type)
|
||||
{
|
||||
if(false == g_detectAll && DRIVE_REMOVABLE != type)
|
||||
return;
|
||||
|
||||
ConnectDrive(driveW, true);
|
||||
}
|
||||
|
||||
int init()
|
||||
{
|
||||
wchar_t mlipod[MAX_PATH] = {0};
|
||||
PathCombineW(mlipod, (LPCWSTR)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORYW), L"ml_ipod.dll");
|
||||
FILE * f = _wfopen(mlipod, L"rb");
|
||||
if (f) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Tataki::Init(plugin.service);
|
||||
|
||||
ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
|
||||
ServiceBuild(WASABI_API_LNG, languageApiGUID);
|
||||
ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
|
||||
ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
|
||||
ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
|
||||
ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
|
||||
ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
|
||||
|
||||
// need to have this initialised before we try to do anything with localisation features
|
||||
WASABI_API_START_LANG(plugin.hDllInstance,PmpIPODLangGUID);
|
||||
|
||||
static wchar_t szDescription[256];
|
||||
swprintf(szDescription, ARRAYSIZE(szDescription),
|
||||
WASABI_API_LNGSTRINGW(IDS_NULLSOFT_IPOD_PLUGIN), PLUGIN_VERSION);
|
||||
plugin.description = szDescription;
|
||||
|
||||
if (NULL != AGAVE_API_DEVICEMANAGER &&
|
||||
NULL == deviceProvider)
|
||||
{
|
||||
if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
|
||||
FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
|
||||
{
|
||||
deviceProvider->Release();
|
||||
deviceProvider = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Our device shows up as a normal drive */
|
||||
if (NULL == deviceProvider ||
|
||||
FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
|
||||
{
|
||||
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
ServiceRelease(AGAVE_API_CONFIG, AgaveConfigGUID);
|
||||
ServiceRelease(WASABI_API_LNG, languageApiGUID);
|
||||
ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
|
||||
ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
|
||||
ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
|
||||
ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
|
||||
ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
|
||||
|
||||
Tataki::Quit();
|
||||
}
|
||||
|
||||
static char FirstDriveFromMask(ULONG unitmask) {
|
||||
char i;
|
||||
for(i=0; i<26; ++i) {
|
||||
if(unitmask & 0x1) break;
|
||||
unitmask = unitmask >> 1;
|
||||
}
|
||||
return (i+'A');
|
||||
}
|
||||
|
||||
|
||||
int wmDeviceChange(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if(wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||
{
|
||||
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
|
||||
if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
|
||||
{ // its a volume
|
||||
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
|
||||
if(0 == ((DBTF_MEDIA | DBTF_NET) & lpdbv->dbcv_flags) || g_detectAll)
|
||||
{ // its not a network drive or a CD/floppy, game on!
|
||||
unsigned long unitmask = lpdbv->dbcv_unitmask;
|
||||
for (int i = 0; i < 26; i++)
|
||||
{
|
||||
if (0 != (0x1 & unitmask))
|
||||
{
|
||||
int p = (int)('A' + i);
|
||||
if (DBT_DEVICEARRIVAL == wParam)
|
||||
p += 0x10000;
|
||||
|
||||
ThreadFunc_DeviceChange((void*)(intptr_t)p);
|
||||
|
||||
unitmask = unitmask >> 1;
|
||||
if (0 == unitmask)
|
||||
break;
|
||||
}
|
||||
else
|
||||
unitmask = unitmask >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI ThreadFunc_DeviceChange(LPVOID lpParam)
|
||||
{
|
||||
int p = (int)lpParam;
|
||||
bool connect = p > 0x10000;
|
||||
|
||||
if(connect)
|
||||
p -= 0x10000;
|
||||
|
||||
char drive = (char)p;
|
||||
if(drive == 0)
|
||||
return 0;
|
||||
|
||||
if(connect)
|
||||
{ // something plugged in
|
||||
ConnectDrive(drive, connect);
|
||||
}
|
||||
else
|
||||
{ //something removed
|
||||
size_t index;
|
||||
|
||||
index = iPods.size();
|
||||
while(index--)
|
||||
{
|
||||
iPodDevice *device = iPods.at(index);
|
||||
if (device->drive == drive)
|
||||
{
|
||||
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)device,PMP_IPC_DEVICEDISCONNECTED);
|
||||
iPods.erase(iPods.begin() + index);
|
||||
delete device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
|
||||
switch(msg) {
|
||||
case PMP_DEVICECHANGE:
|
||||
return wmDeviceChange(param1,param2);
|
||||
case PMP_NO_CONFIG:
|
||||
return TRUE;
|
||||
case PMP_CONFIG:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
__declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
|
||||
__declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
|
||||
int i = iPods.size();
|
||||
while(i-- > 0) iPods[i]->Close();
|
||||
return PMP_PLUGIN_UNINSTALL_NOW;
|
||||
}
|
||||
};
|
194
Src/Plugins/Portable/pmp_ipod/pmp_ipod.rc
Normal file
|
@ -0,0 +1,194 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""version.rc2""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PNG
|
||||
//
|
||||
|
||||
IDB_CLASSIC_16 PNG "resources\\apple_ipod_classic_16.png"
|
||||
IDB_NANO1G_16 PNG "resources\\apple_ipod_nano_1g_16.png"
|
||||
IDB_NANO2G_16 PNG "resources\\apple_ipod_nano_2g_16.png"
|
||||
IDB_NANO3G_16 PNG "resources\\apple_ipod_nano_3g_16.png"
|
||||
IDB_NANO4G_16 PNG "resources\\apple_ipod_nano_4g_16.png"
|
||||
IDB_NANO5G_16 PNG "resources\\apple_ipod_nano_5g_16.png"
|
||||
IDB_SHUFFLE1G_16 PNG "resources\\apple_ipod_shuffle_1g_16.png"
|
||||
IDB_SHUFFLE2G_16 PNG "resources\\apple_ipod_shuffle_2g_16.png"
|
||||
IDB_SHUFFLE3G_16 PNG "resources\\apple_ipod_shuffle_3g_16.png"
|
||||
IDB_CLASSIC_160 PNG "resources\\apple_ipod_classic.png"
|
||||
IDB_NANO1G_160 PNG "resources\\apple_ipod_nano_1g.png"
|
||||
IDB_NANO2G_160 PNG "resources\\apple_ipod_nano_2g.png"
|
||||
IDB_NANO3G_160 PNG "resources\\apple_ipod_nano_3g.png"
|
||||
IDB_NANO4G_160 PNG "resources\\apple_ipod_nano_4g.png"
|
||||
IDB_NANO5G_160 PNG "resources\\apple_ipod_nano_5g.png"
|
||||
IDB_SHUFFLE1G_160 PNG "resources\\apple_ipod_shuffle_1g.png"
|
||||
IDB_SHUFFLE2G_160 PNG "resources\\apple_ipod_shuffle_2g.png"
|
||||
IDB_SHUFFLE3G_160 PNG "resources\\apple_ipod_shuffle_3g.png"
|
||||
IDB_SHUFFLE4G_160 PNG "resources\\apple_ipod_shuffle_4g.png"
|
||||
IDB_SHUFFLE4G_16 PNG "resources\\apple_ipod_shuffle_4g_16.png"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_CONFIG DIALOGEX 0, 0, 264, 226
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
GROUPBOX "Gapless Playback",IDC_STATIC,4,3,255,44
|
||||
LTEXT "Some iPods support the gapless playback of files.\nTo enable this, Winamp needs to scan the files on your iPod. Click ""Scan"" to begin this process.",IDC_STATIC,12,14,179,24
|
||||
PUSHBUTTON "Scan",IDC_SCAN,201,19,50,14
|
||||
GROUPBOX "Album Art",IDC_STATIC_ARTGROUP,4,54,255,30,NOT WS_VISIBLE
|
||||
CONTROL "Add album art to tracks during transfer",IDC_CHECK_USEART,
|
||||
"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,9,67,141,10
|
||||
END
|
||||
|
||||
IDD_GAPSCAN DIALOGEX 0, 0, 186, 55
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Scanning for gapless playback information"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
LTEXT "Scanning...",IDC_CAPTION,7,7,172,8
|
||||
CONTROL "",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,7,17,172,14
|
||||
PUSHBUTTON "Scan in Background",IDC_BG,21,34,69,14
|
||||
PUSHBUTTON "Stop Scan",IDCANCEL,95,34,50,14
|
||||
END
|
||||
|
||||
IDD_SELECTIPODTYPE DIALOGEX 0, 0, 186, 140
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_TOPMOST | WS_EX_APPWINDOW
|
||||
CAPTION "Select iPod Type"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
LTEXT "In order to support some new features, we need to know which iPod model you have.",IDC_STATIC,7,7,172,17
|
||||
LTEXT "My iPod model is:",IDC_IPODINFO,7,27,172,8
|
||||
CONTROL "iPod Touch",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON,7,40,51,10
|
||||
CONTROL "iPod Classic",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON,7,50,53,10
|
||||
CONTROL "iPod Nano (widescreen)",IDC_RADIO8,"Button",BS_AUTORADIOBUTTON,7,59,91,10
|
||||
CONTROL "iPod Shuffle",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,7,69,54,10
|
||||
CONTROL "iPod Photo",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,7,79,50,10
|
||||
CONTROL "iPod Video",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,7,89,49,10
|
||||
CONTROL "iPod Nano",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,7,99,48,10
|
||||
CONTROL "Other",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,7,109,35,10
|
||||
DEFPUSHBUTTON "OK",IDOK,67,119,50,14,WS_DISABLED
|
||||
PUSHBUTTON "Cancel",IDCANCEL,127,119,52,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_GAPSCAN, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 179
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 48
|
||||
END
|
||||
|
||||
IDD_SELECTIPODTYPE, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 179
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 133
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_NULLSOFT_IPOD_PLUGIN "Nullsoft iPod Device Plug-in v%s"
|
||||
65535 "{C2EE3DA5-B29B-42a0-AB5E-B202393435D6}"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CANNOT_OPEN_FILE "Cannot open file"
|
||||
IDS_CANNOT_CREATE_FILE "Cannot create file"
|
||||
IDS_TRANSFERRING_PERCENT "Transferring %d%%"
|
||||
IDS_CANCELLED "Cancelled"
|
||||
IDS_DONE "Done"
|
||||
IDS_TRANSFER_FAILED "Transfer failed"
|
||||
IDS_IPOD_LOADING "iPod Loading..."
|
||||
IDS_FAILED_TO_EJECT_IPOD
|
||||
"Failed to Eject iPod. Is something else using it?"
|
||||
IDS_ERROR "Error"
|
||||
IDS_INVALID_TRACK "Invalid Track"
|
||||
IDS_SCANNING "Scanning..."
|
||||
IDS_ADVANCED "Advanced"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
75
Src/Plugins/Portable/pmp_ipod/pmp_ipod.sln
Normal file
|
@ -0,0 +1,75 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29424.173
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_ipod", "pmp_ipod.vcxproj", "{54C393C2-5A0A-497F-930B-DA5316351B00}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1} = {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625} = {5ED1729B-EA41-4163-9506-741A8B76F625}
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909} = {255B68B5-7EF8-45EF-A675-2D6B88147909}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plist", "..\plist\plist.vcxproj", "{5ED1729B-EA41-4163-9506-741A8B76F625}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "..\tataki\tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|x64.Build.0 = Debug|x64
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Release|Win32.Build.0 = Release|Win32
|
||||
{54C393C2-5A0A-497F-930B-DA5316351B00}.Release|x64.ActiveCfg = Release|x64
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|Win32.Build.0 = Release|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|x64.ActiveCfg = Release|x64
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
|
||||
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
|
||||
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
355
Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj
Normal file
|
@ -0,0 +1,355 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{54C393C2-5A0A-497F-930B-DA5316351B00}</ProjectGuid>
|
||||
<RootNamespace>pmp_ipod</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>false</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4018;4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x040c</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<GenerateMapFile>false</GenerateMapFile>
|
||||
<MapExports>false</MapExports>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4018;4244;4302;4311;4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x040c</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<GenerateMapFile>false</GenerateMapFile>
|
||||
<MapExports>false</MapExports>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>true</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>true</DataExecutionPrevention>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4018;4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x040c</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
|
||||
<ObjectFileName>$(IntDir)</ObjectFileName>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4018;4244;4302;4311;4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Culture>0x040c</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\plist\plist.vcxproj">
|
||||
<Project>{5ed1729b-ea41-4163-9506-741a8b76f625}</Project>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\tataki\tataki.vcxproj">
|
||||
<Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\Wasabi\bfc\bfc.vcxproj">
|
||||
<Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
|
||||
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\General\gen_ml\itemlist.cpp" />
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
|
||||
<ClCompile Include="deviceprovider.cpp" />
|
||||
<ClCompile Include="eject.cpp" />
|
||||
<ClCompile Include="filecopy.cpp" />
|
||||
<ClCompile Include="hash58.cpp" />
|
||||
<ClCompile Include="iPodArtworkDB.cpp" />
|
||||
<ClCompile Include="iPodDB.cpp" />
|
||||
<ClCompile Include="iPodDevice.cpp" />
|
||||
<ClCompile Include="iPodInfo.cpp" />
|
||||
<ClCompile Include="iPodSD.cpp" />
|
||||
<ClCompile Include="main.cpp">
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">WIN64;_DEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">WIN64;NDEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sha1.c" />
|
||||
<ClCompile Include="SysInfoXML.cpp" />
|
||||
<ClCompile Include="yail.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\General\gen_ml\itemlist.h" />
|
||||
<ClInclude Include="..\..\General\gen_ml\ml.h" />
|
||||
<ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
|
||||
<ClInclude Include="..\..\..\nu\Map.h" />
|
||||
<ClInclude Include="api.h" />
|
||||
<ClInclude Include="deviceprovider.h" />
|
||||
<ClInclude Include="hash58.h" />
|
||||
<ClInclude Include="iPodArtworkDB.h" />
|
||||
<ClInclude Include="iPodDB.h" />
|
||||
<ClInclude Include="iPodDevice.h" />
|
||||
<ClInclude Include="iPodInfo.h" />
|
||||
<ClInclude Include="iPodSD.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="sha1.h" />
|
||||
<ClInclude Include="yail.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="pmp_ipod.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
113
Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj.filters
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="deviceprovider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="eject.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="filecopy.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hash58.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="iPodArtworkDB.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="iPodDB.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="iPodDevice.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="iPodInfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="iPodSD.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sha1.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SysInfoXML.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="yail.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\itemlist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="deviceprovider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hash58.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="iPodArtworkDB.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="iPodDB.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="iPodDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="iPodInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="iPodSD.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sha1.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="yail.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\General\gen_ml\itemlist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\Map.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\General\gen_ml\ml.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Library\ml_pmp\pmp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{8a27dfc8-8c21-4608-a4b0-2de0009d3411}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{72f38cc1-6101-41e6-a08e-3583fa56c3ba}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{b8889dfc-5b23-471a-821f-74e6540a3df2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="pmp_ipod.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
71
Src/Plugins/Portable/pmp_ipod/resource.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by pmp_ipod1.rc
|
||||
//
|
||||
#define IDS_CANNOT_OPEN_FILE 1
|
||||
#define IDS_CANNOT_CREATE_FILE 2
|
||||
#define IDS_TRANSFERRING_PERCENT 3
|
||||
#define IDS_CANCELLED 4
|
||||
#define IDS_DONE 5
|
||||
#define IDS_TRANSFER_FAILED 6
|
||||
#define IDS_IPOD_LOADING 7
|
||||
#define IDS_FAILED_TO_EJECT_IPOD 8
|
||||
#define IDS_ERROR 9
|
||||
#define IDS_INVALID_TRACK 10
|
||||
#define IDS_SCANNING 11
|
||||
#define IDS_STRING12 12
|
||||
#define IDS_ADVANCED 12
|
||||
#define IDD_CONFIG 102
|
||||
#define IDD_GAPSCAN 103
|
||||
#define IDD_DIALOG1 106
|
||||
#define IDD_SELECTIPODTYPE 106
|
||||
#define IDB_CLASSIC_16 110
|
||||
#define IDB_NANO1G_16 111
|
||||
#define IDB_NANO2G_16 112
|
||||
#define IDB_NANO3G_16 113
|
||||
#define IDB_NANO4G_16 114
|
||||
#define IDB_NANO5G_16 115
|
||||
#define IDB_SHUFFLE1G_16 116
|
||||
#define IDB_SHUFFLE2G_16 117
|
||||
#define IDB_SHUFFLE3G_16 118
|
||||
#define IDB_CLASSIC_160 119
|
||||
#define IDB_NANO1G_160 120
|
||||
#define IDB_NANO2G_160 121
|
||||
#define IDB_NANO3G_160 122
|
||||
#define IDB_NANO4G_160 123
|
||||
#define IDB_NANO5G_160 124
|
||||
#define IDB_SHUFFLE1G_160 125
|
||||
#define IDB_SHUFFLE2G_160 126
|
||||
#define IDB_PNG9 127
|
||||
#define IDB_SHUFFLE3G_160 127
|
||||
#define IDB_SHUFFLE4G_160 128
|
||||
#define IDB_PNG1 129
|
||||
#define IDB_SHUFFLE4G_16 129
|
||||
#define IDC_SCAN 1001
|
||||
#define IDC_PROGRESS1 1002
|
||||
#define IDC_CAPTION 1003
|
||||
#define IDC_BUTTON1 1004
|
||||
#define IDC_BG 1004
|
||||
#define IDC_RADIO1 1005
|
||||
#define IDC_RADIO2 1006
|
||||
#define IDC_RADIO3 1007
|
||||
#define IDC_RADIO4 1008
|
||||
#define IDC_IPODINFO 1009
|
||||
#define IDC_RADIO5 1010
|
||||
#define IDC_CHECK_USEART 1011
|
||||
#define IDC_RADIO6 1011
|
||||
#define IDC_RADIO7 1012
|
||||
#define IDC_STATIC_ARTGROUP 1013
|
||||
#define IDC_RADIO8 1013
|
||||
#define IDS_NULLSOFT_IPOD_PLUGIN 65534
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 131
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1014
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
BIN
Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 199 B |
BIN
Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 192 B |
BIN
Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 195 B |
BIN
Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 186 B |
BIN
Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 193 B |
BIN
Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 187 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 182 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 230 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 119 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 233 B |
240
Src/Plugins/Portable/pmp_ipod/sha1.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
|
||||
Test Vectors (from FIPS PUB 180-1)
|
||||
"abc"
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
A million repetitions of "a"
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#define LITTLE_ENDIAN /* This should be #define'd if true. */
|
||||
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned long state[5];
|
||||
unsigned long count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
|
||||
void SHA1Init(SHA1_CTX* context);
|
||||
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
|
||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
#ifdef LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
#else
|
||||
#define blk0(i) block->l[i]
|
||||
#endif
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
|
||||
{
|
||||
unsigned long a, b, c, d, e;
|
||||
typedef union {
|
||||
unsigned char c[64];
|
||||
unsigned long l[16];
|
||||
} CHAR64LONG16;
|
||||
CHAR64LONG16* block;
|
||||
|
||||
/*
|
||||
printf("SHA1Transform:\n");
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
printf("%02X", buffer[k*16+i*4+j]);
|
||||
}
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
printf("SHA1Transform (translated):\n");
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
long x = buffer[k*16+i*4+j] & 0xFF;
|
||||
printf("%02X", cryptTable[x] & 0xFF);
|
||||
}
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef SHA1HANDSOFF
|
||||
static unsigned char workspace[64];
|
||||
block = (CHAR64LONG16*)workspace;
|
||||
memcpy(block, buffer, 64);
|
||||
#else
|
||||
block = (CHAR64LONG16*)buffer;
|
||||
#endif
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
void SHA1Init(SHA1_CTX* context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
j = (context->count[0] >> 3) & 63;
|
||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
if ((j + len) > 63) {
|
||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(context->state, context->buffer);
|
||||
for ( ; i + 63 < len; i += 64) {
|
||||
SHA1Transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
|
||||
{
|
||||
unsigned long i, j;
|
||||
unsigned char finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
SHA1Update(context, (unsigned char *)"\200", 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
SHA1Update(context, (unsigned char *)"\0", 1);
|
||||
}
|
||||
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++) {
|
||||
digest[i] = (unsigned char)
|
||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
/* Wipe variables */
|
||||
i = j = 0;
|
||||
memset(context->buffer, 0, 64);
|
||||
memset(context->state, 0, 20);
|
||||
memset(context->count, 0, 8);
|
||||
memset(&finalcount, 0, 8);
|
||||
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
|
||||
SHA1Transform(context->state, context->buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
/*
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i, j;
|
||||
SHA1_CTX context;
|
||||
unsigned char digest[20], buffer[16384];
|
||||
FILE* file;
|
||||
|
||||
if (argc > 2) {
|
||||
puts("Public domain SHA-1 implementation - by Steve Reid <steve@edmweb.com>");
|
||||
puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
|
||||
exit(0);
|
||||
}
|
||||
if (argc < 2) {
|
||||
file = stdin;
|
||||
}
|
||||
else {
|
||||
if (!(file = fopen(argv[1], "rb"))) {
|
||||
fputs("Unable to open file.", stderr);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
SHA1Init(&context);
|
||||
while (!feof(file)) { /* note: what if ferror(file)
|
||||
i = fread(buffer, 1, 16384, file);
|
||||
SHA1Update(&context, buffer, i);
|
||||
}
|
||||
SHA1Final(digest, &context);
|
||||
fclose(file);
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
printf("%02X", digest[i*4+j]);
|
||||
}
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
exit(0);
|
||||
}
|
||||
*/
|
9
Src/Plugins/Portable/pmp_ipod/sha1.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
typedef struct {
|
||||
unsigned long state[5];
|
||||
unsigned long count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
extern "C" void SHA1Init(SHA1_CTX* context);
|
||||
extern "C" void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
|
||||
extern "C" void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
|
39
Src/Plugins/Portable/pmp_ipod/version.rc2
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
#include "../../../Winamp/buildType.h"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,91,0,0
|
||||
PRODUCTVERSION WINAMP_PRODUCTVER
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Winamp SA"
|
||||
VALUE "FileDescription", "Winamp Portable Device Plug-in"
|
||||
VALUE "FileVersion", "0,91,0,0"
|
||||
VALUE "InternalName", "Nullsoft iPod Device"
|
||||
VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA"
|
||||
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
|
||||
VALUE "OriginalFilename", "pmp_ipod.dll"
|
||||
VALUE "ProductName", "Winamp"
|
||||
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
114
Src/Plugins/Portable/pmp_ipod/yail.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include "iPodDevice.h"
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/svcs/svc_imgload.h>
|
||||
#include "api.h"
|
||||
#include <tataki/export.h>
|
||||
|
||||
#include "yail.h"
|
||||
|
||||
extern PMPDevicePlugin plugin;
|
||||
static void recTransform (RGB565 *destination, RGB565 *source, int width, int height, int row_stride);
|
||||
|
||||
static __forceinline ARGB32 pixto32bit(RGB565 pix0, int format) {
|
||||
unsigned long pix = pix0;
|
||||
if(format == RGB_565)
|
||||
return (ARGB32)(((pix & 0x001F) << 3) | ((pix & 0x07E0) << 5) | ((pix & 0xF800) << 8) | 0xff000000);
|
||||
else // format == RGB_555. Ignore alpha channel.
|
||||
return (ARGB32)(((pix & 0x001F) << 3) | ((pix & 0x03E0) << 6) | ((pix & 0x7C00) << 9) | 0xff000000);
|
||||
}
|
||||
|
||||
static __forceinline RGB565 pixto16bit(ARGB32 pix, int format) {
|
||||
// 10987654321098765432109876543210
|
||||
// ARGB32 is AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
|
||||
// RGB565 is RRRRRGGGGGGBBBBB
|
||||
// RGB555 is ARRRRRGGGGGBBBBB
|
||||
if(format == RGB_565)
|
||||
return (RGB565)( ((pix >> 8) & 0xF800) | ((pix >> 5) & 0x07E0) | ((pix >> 3) & 0x001F) );
|
||||
else // format == RGB_555. set A to 1 for now.
|
||||
return (RGB565)( 0x8000 | ((pix >> 9) & 0x7C00) | ((pix >> 6) & 0x03E0) | ((pix >> 3) & 0x001F) );
|
||||
}
|
||||
|
||||
Image::Image(const ARGB32 * d, int w, int h) : width(w), height(h) {
|
||||
int size = sizeof(ARGB32)*w*h;
|
||||
data = (ARGB32*)calloc(size,1);
|
||||
memcpy(data,d,size);
|
||||
}
|
||||
|
||||
#define ALIGN(size, boundary) ((((boundary) - ((size) % (boundary))) % (boundary)) + (size))
|
||||
|
||||
Image::Image(const RGB565 * d, int w, int h, int format, int alignRowBytes, int alignImageBytes) : width(w), height(h) {
|
||||
data = (ARGB32*)calloc(w*h*sizeof(ARGB32),1);
|
||||
int rowgap = (ALIGN(sizeof(RGB565) * width, alignRowBytes) / sizeof(RGB565)) - width;
|
||||
int p=0, q=0;
|
||||
for(int j=0; j<height; j++)
|
||||
{
|
||||
for(int i=0; i<width; i++)
|
||||
{
|
||||
data[p++] = pixto32bit(d[q++], format);
|
||||
}
|
||||
q += rowgap;
|
||||
}
|
||||
}
|
||||
|
||||
Image::~Image() {
|
||||
if(data) free(data); data=0;
|
||||
}
|
||||
|
||||
void Image::exportToRGB565(RGB565* d_, int format, int alignRowBytes, int alignImageBytes) const {
|
||||
int p=0, q=0;
|
||||
int rowgap = (ALIGN(sizeof(RGB565) * width, alignRowBytes) / sizeof(RGB565)) - width;
|
||||
|
||||
RGB565* d;
|
||||
if(format == RGB_555_REC)
|
||||
{
|
||||
int l = get16BitSize(width, height, alignRowBytes, alignImageBytes);
|
||||
d = (RGB565*)calloc(l, 1);
|
||||
}
|
||||
else
|
||||
d = d_;
|
||||
|
||||
for(int j=0; j<height; j++)
|
||||
{
|
||||
for(int i=0; i<width; i++)
|
||||
{
|
||||
d[p++] = pixto16bit(data[q++], format);
|
||||
}
|
||||
p += rowgap;
|
||||
}
|
||||
|
||||
if(format == RGB_555_REC)
|
||||
{ // do wierd transform
|
||||
recTransform(d_, d, width, height, width + rowgap);
|
||||
free(d);
|
||||
}
|
||||
}
|
||||
|
||||
void Image::exportToARGB32(ARGB32* d) const {
|
||||
memcpy(d,data,sizeof(ARGB32)*width*height);
|
||||
}
|
||||
|
||||
int Image::get16BitSize(int width, int height, int alignRowBytes, int alignImageBytes) {
|
||||
int rowSize = ALIGN(sizeof(RGB565) * width, alignRowBytes);
|
||||
return ALIGN(rowSize * height, alignImageBytes);
|
||||
}
|
||||
|
||||
|
||||
static void recTransform (RGB565 *destination, RGB565 *source, int width, int height, int row_stride)
|
||||
{
|
||||
if (width == 1)
|
||||
{
|
||||
*destination = *source;
|
||||
}
|
||||
else
|
||||
{
|
||||
recTransform(destination, source, width/2, height/2, row_stride);
|
||||
|
||||
recTransform(destination + (width/2)*(height/2), source + (height/2)*row_stride, width/2, height/2, row_stride);
|
||||
|
||||
recTransform(destination + 2*(width/2)*(height/2), source + width/2, width/2, height/2, row_stride);
|
||||
|
||||
recTransform(destination + 3*(width/2)*(height/2), source + (height/2)*row_stride + width/2, width/2, height/2, row_stride);
|
||||
}
|
||||
}
|
25
Src/Plugins/Portable/pmp_ipod/yail.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef _YAIL_H_
|
||||
#define _YAIL_H_
|
||||
|
||||
// yet another image library. Because everything else SUCKS. Fact.
|
||||
|
||||
typedef unsigned short RGB565;
|
||||
|
||||
class Image {
|
||||
public:
|
||||
Image(const ARGB32 * data, int w, int h);
|
||||
Image(const RGB565 * data, int w, int h, int format, int alignRowBytes, int alignImageBytes);
|
||||
~Image();
|
||||
void exportToRGB565(RGB565* data, int format, int alignRowBytes, int alignImageBytes) const;
|
||||
void exportToARGB32(ARGB32* data) const;
|
||||
ARGB32 * getData() {return data;}
|
||||
int getWidth() const {return width;}
|
||||
int getHeight() const {return height;}
|
||||
int get16BitSize(int alignRowBytes, int alignImageBytes) { return get16BitSize(width,height,alignRowBytes, alignImageBytes); }
|
||||
static int get16BitSize(int width, int height, int alignRowBytes, int alignImageBytes);
|
||||
protected:
|
||||
ARGB32 *data;
|
||||
int width,height;
|
||||
};
|
||||
|
||||
#endif //_YAIL_H_
|