Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View 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;
}

View 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

View 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

View 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;
};

View 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

View 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;
}
}

View 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);
}

View file

@ -0,0 +1 @@
void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase, long lSize, unsigned char *pHash);

View 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;
}

View 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__

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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_

File diff suppressed because it is too large Load diff

View 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_

View 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;
}

View 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);
};

View 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;
}
};

View 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

View 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

View 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>

View 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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

View 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);
}
*/

View 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);

View 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

View 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);
}
}

View 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_