From: <ny...@us...> - 2007-02-27 14:18:07
|
Revision: 398 http://svn.sourceforge.net/pmplib/?rev=398&view=rev Author: nyaochi Date: 2007-02-27 06:15:54 -0800 (Tue, 27 Feb 2007) Log Message: ----------- Automatic detection of iPod player by issuing SCSI INQUIRY commands to the device. The detection mechanism is based on the information available at: http://www.ipodlinux.org/Device_Information This code might not work with iPod generation 3 or earlier. The routine to manipulate SCSI devices uses SPTI WinNT API (for Windows 2000/XP/Vista). This code will not run on Win9x environments. The source code "ipodprop_win32spti.c" requires Windows DDK to be compiled; I generated ipodprop_win32spti.lib for those who do not install DDK. Modified Paths: -------------- trunk/pmplib/lib/pmp_ipod/ipod.c trunk/pmplib/lib/pmp_ipod/ipod.h trunk/pmplib/lib/pmp_ipod/pmp_ipod.c trunk/pmplib/lib/pmp_ipod/pmp_ipod.vcproj Added Paths: ----------- trunk/pmplib/lib/pmp_ipod/ipodprop.h trunk/pmplib/lib/pmp_ipod/win32spti/ trunk/pmplib/lib/pmp_ipod/win32spti/README.txt trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.c trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.lib trunk/pmplib/lib/pmp_ipod/win32spti/makefile trunk/pmplib/lib/pmp_ipod/win32spti/sources Modified: trunk/pmplib/lib/pmp_ipod/ipod.c =================================================================== --- trunk/pmplib/lib/pmp_ipod/ipod.c 2007-02-27 09:45:39 UTC (rev 397) +++ trunk/pmplib/lib/pmp_ipod/ipod.c 2007-02-27 14:15:54 UTC (rev 398) @@ -37,6 +37,7 @@ #include "serialize.h" #include "util.h" #include "ipod.h" +#include "ipodprop.h" #include "itunesdb.h" #define COMP(a, b) ((a)>(b))-((a)<(b)) @@ -60,8 +61,66 @@ }, }; -const ipod_descriptor_t* ipod_detect(const ucs2char_t* path_to_device, const char *id) +static int get_string_value(const char *xml, const char *key, char *value, size_t size) { + char *p, *q, *r; + char *keystr = (char*)alloca(strlen(key) + 5 + 6 + 1); + static const char *xeo_string = "<string>"; + static const char *xee_string = "</string>"; + + sprintf(keystr, "<key>%s</key>", key); + p = strstr(xml, keystr); + if (p) { + q = strstr(p += strlen(keystr), xeo_string); + if (q) { + r = strstr(q += strlen(xeo_string), xee_string); + if (r && (size_t)(r - q) < size) { + strncpy(value, q, r-q); + value[r-q] = 0; + return 0; + } + } + } + return -1; +} + +static int detect_model( + const ucs2char_t* path_to_device, + const ipod_descriptor_t* md, + pmp_device_information_t* ptr_info + ) +{ + int ret = 0; + ipodprop_t ip; + char *path = ucs2dupmbs(path_to_device); + + ipodprop_init(&ip); + + if (ipodprop_get(path, &ip) == 0) { + if (ip.vendor && strncmp(ip.vendor, "Apple", 5) == 0 && + ip.product && strncmp(ip.product, "iPod", 4) == 0) { + /* This is iPod. */ + ret = 1; + + /* Obtain the version number from the XML. */ + if (ip.info) { + get_string_value(ip.info, "VisibleBuildID", (char*)ptr_info->decl.version, PMP_DECLSIZE); + get_string_value(ip.info, "Language", (char*)ptr_info->decl.language, PMP_DECLSIZE); + } + } + } + + ipodprop_finish(&ip); + ucs2free(path); + return ret; +} + +const ipod_descriptor_t* ipod_detect( + const ucs2char_t* path_to_device, + const char *id, + pmp_device_information_t* ptr_info + ) +{ const ipod_descriptor_t* md = NULL; // Find a suitable model for the device. @@ -70,8 +129,15 @@ if (id && *id) { // Match the device identifier. if (strcmp(md->id, id) == 0) { + // This will fill some members in decl. + detect_model(path_to_device, md, ptr_info); break; } + } else { + // Detect the model automatically. + if (detect_model(path_to_device, md, ptr_info)) { + break; + } } } return md->id ? md : NULL; @@ -123,6 +189,7 @@ result_t ipod_write(ipod_t* ipod, const ucs2char_t* itunesdb) { + result_t ret = 0; FILE *fp = NULL; serializer_t sio; @@ -130,11 +197,15 @@ itunesdb_write(ipod->itunesdb, &sio); fp = ucs2fopen(itunesdb, "wb"); - fwrite(sio.base, 1, sio.offset, fp); - fclose(fp); + if (fp) { + fwrite(sio.base, 1, sio.offset, fp); + fclose(fp); + } else { + ret = PMPERR_OPENFORWRITE; + } serialize_finish(&sio); - return 0; + return ret; } result_t ipod_dump(ipod_t* ipod, FILE *fpo) Modified: trunk/pmplib/lib/pmp_ipod/ipod.h =================================================================== --- trunk/pmplib/lib/pmp_ipod/ipod.h 2007-02-27 09:45:39 UTC (rev 397) +++ trunk/pmplib/lib/pmp_ipod/ipod.h 2007-02-27 14:15:54 UTC (rev 398) @@ -48,7 +48,7 @@ itunesdb_chunk_t* itunesdb; } ipod_t; -const ipod_descriptor_t* ipod_detect(const ucs2char_t* path_to_device, const char *id); +const ipod_descriptor_t* ipod_detect(const ucs2char_t* path_to_device, const char *id, pmp_device_information_t* ptr_info); const ipod_descriptor_t* ipod_next_descriptor(const ipod_descriptor_t* md); void ipod_init(ipod_t* ipod); Added: trunk/pmplib/lib/pmp_ipod/ipodprop.h =================================================================== --- trunk/pmplib/lib/pmp_ipod/ipodprop.h (rev 0) +++ trunk/pmplib/lib/pmp_ipod/ipodprop.h 2007-02-27 14:15:54 UTC (rev 398) @@ -0,0 +1,45 @@ +/* + * iPod property retrieval. + * + * Copyright (c) 2005-2007 Naoaki Okazaki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit + * http://www.gnu.org/copyleft/gpl.html . + * + */ + +/* $Id:$ */ + +#ifndef __IPODPROP_H__ +#define __IPODPROP_H__ + +#ifdef _WIN32 +#define IPODPROPAPI __cdecl +#else +#define IPODPROPAPI +#endif/*_WIN32*/ + +typedef struct { + char* vendor; + char* product; + char* revision; + char* info; +} ipodprop_t; + +void IPODPROPAPI ipodprop_init(ipodprop_t *prop); +void IPODPROPAPI ipodprop_finish(ipodprop_t *prop); +int IPODPROPAPI ipodprop_get(const char *path_to_root, ipodprop_t *prop); + +#endif/*__IPODPROP_H__*/ Property changes on: trunk/pmplib/lib/pmp_ipod/ipodprop.h ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Modified: trunk/pmplib/lib/pmp_ipod/pmp_ipod.c =================================================================== --- trunk/pmplib/lib/pmp_ipod/pmp_ipod.c 2007-02-27 09:45:39 UTC (rev 397) +++ trunk/pmplib/lib/pmp_ipod/pmp_ipod.c 2007-02-27 14:15:54 UTC (rev 398) @@ -185,7 +185,7 @@ *ptr_pmp = 0; // Find a suitable model for the device. - md = ipod_detect(path_to_device, id); + md = ipod_detect(path_to_device, id, &info); if (!md) { return PMPERR_DEVICENOTFOUND; } Modified: trunk/pmplib/lib/pmp_ipod/pmp_ipod.vcproj =================================================================== --- trunk/pmplib/lib/pmp_ipod/pmp_ipod.vcproj 2007-02-27 09:45:39 UTC (rev 397) +++ trunk/pmplib/lib/pmp_ipod/pmp_ipod.vcproj 2007-02-27 14:15:54 UTC (rev 398) @@ -61,6 +61,7 @@ /> <Tool Name="VCLinkerTool" + AdditionalDependencies=".\win32spti\ipodprop_win32spti.lib shlwapi.lib" LinkIncremental="2" GenerateDebugInformation="true" SubSystem="2" @@ -193,10 +194,6 @@ > </File> <File - RelativePath=".\settledb.c" - > - </File> - <File RelativePath=".\util.c" > </File> @@ -211,15 +208,15 @@ > </File> <File - RelativePath=".\itunesdb.h" + RelativePath=".\ipodprop.h" > </File> <File - RelativePath=".\serialize.h" + RelativePath=".\itunesdb.h" > </File> <File - RelativePath=".\settledb.h" + RelativePath=".\serialize.h" > </File> <File Added: trunk/pmplib/lib/pmp_ipod/win32spti/README.txt =================================================================== --- trunk/pmplib/lib/pmp_ipod/win32spti/README.txt (rev 0) +++ trunk/pmplib/lib/pmp_ipod/win32spti/README.txt 2007-02-27 14:15:54 UTC (rev 398) @@ -0,0 +1 @@ +This source code requires Microsoft Windows DDK to be compiled. Property changes on: trunk/pmplib/lib/pmp_ipod/win32spti/README.txt ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Added: trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.c =================================================================== --- trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.c (rev 0) +++ trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.c 2007-02-27 14:15:54 UTC (rev 398) @@ -0,0 +1,286 @@ +/* + * iPod property retrieval through Win32 SPTI (for 2000/XP/Vista). + * + * Copyright (c) 2005-2007 Naoaki Okazaki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit + * http://www.gnu.org/copyleft/gpl.html . + * + */ + +/* I used the following information to access to the property of + * iPod players: + * http://www.ipodlinux.org/Device_Information + * + * This source code is based on the sample program found in Windows + * DDK, Enumdisk.c written by Raju Ramanathan. + */ + +/* $Id:$ */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <windows.h> +#include <shlwapi.h> +#include <devioctl.h> +#include <ntdddisk.h> +#include <ntddscsi.h> + +#include "../ipodprop.h" + + + +#define CDB6GENERIC_LENGTH 6 +#define CDB10GENERIC_LENGTH 10 + +#define SCSIOP_INQUIRY 0x12 + +typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS { + SCSI_PASS_THROUGH Spt; + ULONG Filler; + UCHAR SenseBuf[32]; + UCHAR DataBuf[512]; +} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; + + + +void __cdecl ipodprop_init(ipodprop_t *prop) +{ + memset(prop, 0, sizeof(*prop)); +} + +void __cdecl ipodprop_finish(ipodprop_t *prop) +{ + free(prop->vendor); + free(prop->product); + free(prop->revision); + free(prop->info); + memset(prop, 0, sizeof(*prop)); +} + +int __cdecl ipodprop_get(const char *path_to_root, ipodprop_t *prop) +{ + int ret = 0; + DWORD i; + int j, k, n; + BOOL status; + UCHAR *p, outBuf[512]; + STORAGE_PROPERTY_QUERY query; + PSTORAGE_DEVICE_DESCRIPTOR devDesc; + SCSI_PASS_THROUGH_WITH_BUFFERS sptwb; + HANDLE hDevice = INVALID_HANDLE_VALUE; + ULONG length = 0, returned = 0; + int num_pages = 0; + UCHAR pages[256]; + size_t info_size = 0; + CHAR drive[7]; + + memset(pages, 0, sizeof(pages)); + + /* Obtain the drive letter. */ + drive[0] = '\\'; + drive[1] = '\\'; + drive[2] = '.'; + drive[3] = '\\'; + drive[4] = 'A' + PathGetDriveNumber(path_to_root); + drive[5] = ':'; + drive[6] = 0; + + /* Open the device. */ + hDevice = CreateFile( + drive, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (hDevice == INVALID_HANDLE_VALUE) { + ret = -1; + goto error_exit; + } + + /* Query the property of the device. */ + query.PropertyId = StorageDeviceProperty; + query.QueryType = PropertyStandardQuery; + status = DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &query, + sizeof(STORAGE_PROPERTY_QUERY), + &outBuf, + 512, + &returned, + NULL + ); + if (!status) { + ret = -1; + goto error_exit; + } + + /* Obtain vendor, product and revision of the device. */ + devDesc = (PSTORAGE_DEVICE_DESCRIPTOR)outBuf; + p = (PUCHAR)outBuf; + if (devDesc->VendorIdOffset && p[devDesc->VendorIdOffset]) { + for (n = 0, i = devDesc->VendorIdOffset;p[i] && i < returned;i++) { + n++; + } + prop->vendor = (char*)calloc(n+1, sizeof(char)); + strncpy(prop->vendor, &p[devDesc->VendorIdOffset], n); + } + if (devDesc->ProductIdOffset && p[devDesc->ProductIdOffset]) { + for (n = 0, i = devDesc->ProductIdOffset;p[i] && i < returned;i++) { + n++; + } + prop->product = (char*)calloc(n+1, sizeof(char)); + strncpy(prop->product, &p[devDesc->ProductIdOffset], n); + } + + if ( devDesc->ProductRevisionOffset && p[devDesc->ProductRevisionOffset] ) { + for (n = 0, i = devDesc->ProductRevisionOffset;p[i] && i < returned;i++) { + n++; + } + prop->revision = (char*)calloc(n+1, sizeof(char)); + strncpy(prop->revision, &p[devDesc->ProductRevisionOffset], n); + } + + /* Access to SCSI INQUIRY page 0xC0. */ + ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); + sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH); + sptwb.Spt.PathId = 0; + sptwb.Spt.TargetId = 1; + sptwb.Spt.Lun = 0; + sptwb.Spt.CdbLength = CDB6GENERIC_LENGTH; + sptwb.Spt.SenseInfoLength = 24; + sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN; + sptwb.Spt.DataTransferLength = 255; + sptwb.Spt.TimeOutValue = 2; + sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf); + sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,SenseBuf); + sptwb.Spt.Cdb[0] = SCSIOP_INQUIRY; + sptwb.Spt.Cdb[1] = 0x01; + sptwb.Spt.Cdb[2] = 0xC0; + sptwb.Spt.Cdb[4] = 255; + length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf) + sptwb.Spt.DataTransferLength; + + status = DeviceIoControl(hDevice, + IOCTL_SCSI_PASS_THROUGH, + &sptwb, + sizeof(SCSI_PASS_THROUGH), + &sptwb, + length, + &returned, + FALSE + ); + + if (!status) { + ret = -1; + goto error_exit; + } + + /* Obtain the number of pages and list of pages. */ + num_pages = (int)sptwb.DataBuf[3]; + for (j = 0;j < num_pages;++j) { + pages[j] = sptwb.DataBuf[j+4]; + } + + /* Access to all pages available. */ + for (j = 0;j < num_pages;++j) { + ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS)); + sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH); + sptwb.Spt.PathId = 0; + sptwb.Spt.TargetId = 1; + sptwb.Spt.Lun = 0; + sptwb.Spt.CdbLength = CDB6GENERIC_LENGTH; + sptwb.Spt.SenseInfoLength = 24; + sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN; + sptwb.Spt.DataTransferLength = 255; + sptwb.Spt.TimeOutValue = 2; + sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf); + sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,SenseBuf); + sptwb.Spt.Cdb[0] = SCSIOP_INQUIRY; + sptwb.Spt.Cdb[1] = 0x01; + sptwb.Spt.Cdb[2] = pages[j]; + sptwb.Spt.Cdb[4] = 255; + length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,DataBuf) + + sptwb.Spt.DataTransferLength; + + status = DeviceIoControl(hDevice, + IOCTL_SCSI_PASS_THROUGH, + &sptwb, + sizeof(SCSI_PASS_THROUGH), + &sptwb, + length, + &returned, + FALSE + ); + + if (!status) { + ret = -1; + goto error_exit; + } + + /* Obtain the number of characters in this page. */ + n = (int)sptwb.DataBuf[3]; + /* Expand the buffer storing the information. */ + prop->info = realloc(prop->info, sizeof(char) * (info_size + n + 1)); + /* Storing the information in the current page. */ + for (k = 0;k < n;++k) { + prop->info[info_size+k] = sptwb.DataBuf[k+4]; + } + info_size += n; + prop->info[info_size] = 0; + } + + if (!CloseHandle(hDevice)) { + ret = -1; + goto error_exit; + } + return 0; + +error_exit: + free(prop->vendor); + free(prop->product); + free(prop->revision); + free(prop->info); + memset(prop, 0, sizeof(*prop)); + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + return ret; +} + +#if 0 +int __cdecl main(int argc, char *argv[]) +{ + ipodprop_t prop; + + ipodprop_init(&prop); + + if (ipodprop_get("D:\\", &prop) == 0) { + if (prop.vendor) printf("Vendor: %s\n", prop.vendor); + if (prop.product) printf("Product: %s\n", prop.product); + if (prop.revision) printf("Revision: %s\n", prop.revision); + if (prop.info) printf("Info:\n%s\n", prop.info); + } + + ipodprop_finish(&prop); + + return 0; +} +#endif Property changes on: trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.c ___________________________________________________________________ Name: svn:keywords + Id Added: trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.lib =================================================================== (Binary files differ) Property changes on: trunk/pmplib/lib/pmp_ipod/win32spti/ipodprop_win32spti.lib ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/pmplib/lib/pmp_ipod/win32spti/makefile =================================================================== --- trunk/pmplib/lib/pmp_ipod/win32spti/makefile (rev 0) +++ trunk/pmplib/lib/pmp_ipod/win32spti/makefile 2007-02-27 14:15:54 UTC (rev 398) @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def + Added: trunk/pmplib/lib/pmp_ipod/win32spti/sources =================================================================== --- trunk/pmplib/lib/pmp_ipod/win32spti/sources (rev 0) +++ trunk/pmplib/lib/pmp_ipod/win32spti/sources 2007-02-27 14:15:54 UTC (rev 398) @@ -0,0 +1,8 @@ +TARGETNAME=ipodprop_win32spti +TARGETTYPE=LIBRARY + +TARGETPATH=obj + +TARGETLIBS=$(DDK_LIB_PATH)\user32.lib $(DDK_LIB_PATH)\shlwapi.lib + +SOURCES=ipodprop_win32spti.c This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |