winamp/Src/Plugins/Portable/pmp_ipod/SysInfoXML.cpp

150 lines
4.0 KiB
C++

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