/*	
 *	clipptp.c
 *
 *	USB PTP Responder (Picture Transfer Protocol), USB MTP Responder (Media Transfer Protocol)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2014 Naoyuki Sawa
 *
 *	* Fri Sep 05 21:36:08 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Sep 06 23:41:20 JST 2014 Naoyuki Sawa
 *	- ストールでエラーを通知した後の、復旧ができるようになりました。
 *	  詳細は、「エラー発生後の復旧方法について」の「2014/09/06追記」を参照してください。
 *	* Sun Sep 14 02:44:46 JST 2014 Naoyuki Sawa
 *	- デハイス情報データセット(DeviceInfo Dataset)のImageFormatsに、Undefinedを追加しました。
 *	  この変更により、Windows7⇒P/ECEへ書き込むとき、警告が表示されていた問題が解決しました。
 *	- オブジェクト情報データセットのObjectFormatを、VendorDefined⇒Undefinedに変更しました。
 *	  任意の拡張子を扱う場合は、VendorDefinedよりもUndefinedの方が適切のようです。
 *	  オブジェクト情報データセットのObjectFormatはどちらでも影響無いようですが、確実のためにVendorDefined⇒Undefinedに変更しておくことにしました。
 *	- PTP_Start()に引数bMTPを追加し、MTPデバイスとして動作できるようにしました。
 *	 まだ、WindowsがMTPデバイスとして認識するようにしただけで、MTP特有の動作は何も作っていません。
 *	- MTP Extension format codesを追加しました。
 *	  デハイス情報データセット(DeviceInfo Dataset)のImageFormatsに、MTP Extension format codesも追加しました。
 *	  この変更により、*.xlsや*.docを書き込むときにも、警告が表示されなくなりました。(まだ*.exeは警告が出ます。)
 *	  MTP Extension format codesは、MTPだけでなくPTPとして動作している時も有効です。
 *	* Mon Sep 15 02:07:06 JST 2014 Naoyuki Sawa
 *	- MTP Extension operation codes,MTP Extension response codes,MTP Extension event codes,MTP Extension device properties,MTP Extension protection statusesを追加しました。
 *	- ObjectPropertyを追加しました。
 *	* Mon Sep 15 19:28:40 JST 2014 Naoyuki Sawa
 *	- Get/Set,FormFlag,MTP Extension form flagsを追加しました。
 *	* Mon Sep 15 21:24:52 JST 2014 Naoyuki Sawa
 *	- MTPのオペレーション(GetObjectPropsSupported,GetObjectPropDesc,GetObjectPropValue)を実装しました。
 *	  シンボルUSE_MTP_OPERATIONを定義すると、動作モード(PTP/MTP)に関係無く、これらのオペレーションが有効になります。
 *	  シンボルUSE_MTP_OPERATIONを定義しなければ、動作モード(PTP/MTP)に関係無く、これらのオペレーションが無効になります。
 *	  '動作モード(PTP/MTP)に関係無く'とは、Windows7は、PTPとして認識したデバイスであっても、MTPのオペレーションが対応されていれば、MTPのオペレーションを使用して動作するようだからです。
 *	  '動作モード(PTP/MTP)に関係無く'とは、Windows7は、MTPとして認識したデバイスであっても、MTPのオペレーションが対応されていなければ、PTPのオペレーションのみで動作するようだからです。
 *	* Sat Sep 20 08:44:17 JST 2014 Naoyuki Sawa
 *	- FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
 *	  詳細は、clippce.cの「ファイル書き込み系関数の排他制御」のコメントと「FRAM4領域の退避復元」を参照してください。
 */
#include "clip.h"

/* * Mon Sep 15 21:24:52 JST 2014 Naoyuki Sawa
 * - MTPのオペレーション(GetObjectPropsSupported,GetObjectPropDesc,GetObjectPropValue)を実装しました。
 *   シンボルUSE_MTP_OPERATIONを定義すると、    動作モード(PTP/MTP)に関係無く、これらのオペレーションが有効になります。
 *   シンボルUSE_MTP_OPERATIONを定義しなければ、動作モード(PTP/MTP)に関係無く、これらのオペレーションが無効になります。
 *   '動作モード(PTP/MTP)に関係無く'とは、Windows7は、PTPとして認識したデバイスであっても、MTPのオペレーションが対応されていれば、MTPのオペレーションを使用して動作するようだからです。
 *   '動作モード(PTP/MTP)に関係無く'とは、Windows7は、MTPとして認識したデバイスであっても、MTPのオペレーションが対応されていなければ、PTPのオペレーションのみで動作するようだからです。 */
#define USE_MTP_OPERATION

/****************************************************************************
 *	参考資料
 ****************************************************************************/
//■エラー発生後の復旧方法について
//「PTP Error Recovery」(http://msdn.microsoft.com/en-us/library/windows/hardware/ff546442(v=vs.85).aspx)より引用:
//│During initialization of the Microsoft PTP class minidriver (that is, on initial retrieval of the DeviceInfo and ObjectInfo datasets, and the property descriptions),
//│any error is treated as a catastrophic failure, and the WIA minidriver fails to initialize.
//│During later processing (for example, while retrieving an image), when an unrecognized error occurs,
//│the Microsoft PTP minidriver first attempts to send the Get Device Status USB class-specific request (described in the USB Still Image Capture Device Definition).
//│If that request succeeds, the driver clears any stalled endpoints and continues.
//│If the Get Device Status request fails, the PTP minidriver attempts to reset the device using the Device Reset class-specific request (described in the USB Still Image Capture Device Definition).
//│If the Device Reset class-specific request succeeds, it returns S_FALSE instead of S_OK. If resetting the device fails, the Device Reset class-specific request returns an error code.
//と書いてあるが、実際に試すと、エラー発生後の復旧が出来ない。
//具体的には、Get Device StatusやDevice Resetは呼ばれるが、その後にClear Featureが呼ばれない。
//問題の原因は、Get Device Statusの戻り値の構造が、正しくないのだと思う。
//本来、Get Device Statusの戻り値には、ストールしているパイプを追加して返すことになっているのだが、
//仕様書(Universal Serial Bus Still Image Capture Device Definition)の説明が曖昧で、具体的な構造がわからない。
//推測で、1バイト配列でバルクエンドポイントの番号(0x02と0x82)を格納してみたが、Clear Featureが呼ばれなかった。
//解決の目処が立たず、現在の所、ストールでエラーを通知した後は、P/ECEを抜き差しするしか復旧の方法が無い。
//できるだけストールせずに、レスポンスフェーズでエラーを返すように工夫するしか無いと思う。
//↓↓↓↓↓2014/09/06追記↓↓↓↓↓
//○○○解決しました○○○。これまで正しく動作していなかったのは、以下の二つの原因でした。
//1. clipusb.cのdevice_request_endpoint()にバグが有り、clear_feature()が正しく動作していませんでした。
//2. Get Device Status Requestの戻り値のParameterをUINT8配列にしていました。正しくはUINT32配列でした。
//上記二つを修正したところ、ストールでエラーを通知した後に、復旧して次の処理を行えるようになりました。
/*--------------------------------------------------------------------------*/
//「MTP Compliance Test - Requirements - Media Players」(http://msdn.microsoft.com/en-us/library/windows/hardware/jj124296.aspx)より引用:
//│The test validates that the following Object Properties are supported for each supported format:
//│1. StorageID
//│2. ObjectFormat
//│3. ProtectionStatus
//│4. ObjectSize
//│5. ObjectFileName
//│6. ParentObject
//│7. PersistentUniqueObjectIdentifier
//│8. Name
//│9. Non-Consumable
//サポートすべきオブジェクトプロパティは、上記の通りです。
//特に重要なのは、ParentObjectとPersistentUniqueObjectIdentifierです。詳細は、以下を読んでください。
/*--------------------------------------------------------------------------*/
//「Media Transfer Protocol Revision 1.1 April 6th, 2011」(MTPforUSB-IFv1.1.pdf)より引用:
//■5.3.2.6 Required Object Properties
//│Devices which implement Object Properties must implement as Object Properties the properties which map to the required fields of the ObjectInfo dataset, as well as certain properties which are required for effective functioning of the protocol.
//│Required properties for all object formats include:
//│・StorageID
//│・ObjectFormat
//│・ObjectCompressedSize
//│・Persistent Unique Object Identifier
//│・Name
//│Devices which support file systems through the use of associations must support the following object properties:
//│・ParentObject
//GetObjectPropsSupported,GetObjectPropDesc,GetObjectPropValueを実装する場合は、上記のプロパティに対応することが必須です。
// - ParentObjectに対応しないと、PC⇒P/ECEへファイルを書き込んだ後に、そのセション内で、そのファイルを削除できなくなります。(Windows7にて確認)		←←←←←←←←←←【重要】
// - Persistent Unique Object Identifierに対応しないと、ファイルの一覧表示はできるが、ファイルの読み書きができなくなります。(Windows7にて確認)		←←←←←←←←←←【重要】
// - ObjectCompressedSizeは、ObjectSizeのことだと思います。
// - Nameは、ObjectFileNameのことかNameのことか判らなかったので、両方対応しておくことにしました。
/*--------------------------------------------------------------------------*/
//「Media Transfer Protocol Revision 1.1 April 6th, 2011」(MTPforUSB-IFv1.1.pdf)より引用:
//■5.3.2.7 Optimizing Object Properties
//│The development of object properties allows considerable improvements in functionality over the static descriptive set of metadata exposed in the ObjectInfo dataset, however, it comes at the cost of a dramatically increased number of queries to the device.
//│This has been mitigated in the Basic MTP specification by defining object-property retrieval groups.
//□5.3.2.7.1 Object Property Groups
//│Many devices currently maintain an accelerator file or database containing a subset of available metadata used by the device for its own UI.
//│These metadata items, when defined as object properties, are much more easily and efficiently retrieved than metadata stored within the content on the device.
//│Devices are encouraged to identify the relative retrieval qualities of different properties by assigning them a group value in the ObjectPropDesc dataset, and allowing them to be retrieved based on that group value.
//│Group codes shall be assigned in ascending order, based upon the relative retrieval speed of the property.
//│The expected behavior of an initiator that is taking advantage of object property groups is that it will retrieve properties in ascending order.
//□5.3.2.7.2 Special Values for Object Property Groups
//│Properties of essentially unbounded size shall be marked with a group code of 0xFFFFFFFF.
//│This includes any property defined by a LongString or ByteArray form.
//│It is the responsibility of the device to accurately identify these groups.
//ObjectPropDescDataset.GroupCodeについての説明です。
//どうやら、イニシエータがレスポンダへGetObjectPropValueを発行する際、プロパティをどの順番で要求するかに関する指定のようです。
//複雑なデバイスでは、プロパティを特定の順番で取り出すと効率が良いようですが、P/ECEでは関係無いので0固定にすることにしました。
/****************************************************************************
 *	グローバル変数
 ****************************************************************************/
ST_PTP stPTP;
/****************************************************************************
 *	ローカル関数宣言
 ****************************************************************************/
static void get_descriptor(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void set_configuration(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void set_interface(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void class_request(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void vendor_request(const DEVICE_REQUEST* req, const unsigned char* dat, int len);
static void ep2_rxdone();
static void ep2_txdone();
static int ep2_txsub();
static void put_string(void* _dst, const char* src);
static void get_string(char* dst, const void* _src);
static int is_protected_filename(const char* name);
static int process_command();
static int process_dataout(const void* buf, int len);
static int process_datain(void* buf, int len);
/****************************************************************************
 *	USBフック情報
 ****************************************************************************/
static const USBINF usb_inf = {
	/* USBC mode */
	mode:			D12_ENDP_NONISO,
	/* USBC raw event */
	ep2_rxdone:		ep2_rxdone,
	ep2_txdone:		ep2_txdone,
	/* Device request */
	get_descriptor:		get_descriptor,
	set_configuration:	set_configuration,
	set_interface:		set_interface,
	/* Class request */
	class_request:		class_request,
	vendor_request:		vendor_request,
};
/****************************************************************************
 *	ディスクリプタ
 ****************************************************************************/
/* D.6.1.1 Device Descriptor */
static const DEVICE_DESCRIPTOR device_desc_PTP = {
	bLength:		sizeof(DEVICE_DESCRIPTOR),		//The length of this descriptor
	bDescriptorType:	DEVICE_DESCRIPTOR_TYPE,			//Device Descriptor Type
	bcdUSB:			0x0110,					//USB Specification Release Number
//不要	bDeviceClass:		0x00,					//Class information may be found at the interface level
//不要	bDeviceSubClass:	0x00,					//bDeviceSubClass is zero
//不要	bDeviceProtocol:	0x00,					//bDeviceProtocol is zero
	bMaxPacketSize0:	EP0_PACKET_SIZE,			//mplementation specific, may be set to 8, 16, 32 or 64
	idVendor:		PCE_VENDOR_ID,				//Vendor ID assigned to IHV by USB-IF
	idProduct:		PTP_PRODUCT_ID,				//Product ID assigned by IHV
	bcdDevice:		0x0001,					//Device release number in BCD assigned by IHV to this release of model
	iManufacture:		1,					//Index of string descriptor describing IHV. If set to zero (0), there is no manufacturer string.
	iProduct:		2,					//Index of string describing this product. If set to zero (0), there is no product string.
//不要	iSerialNumber:		0,					//Index of string descriptor with this specific device’s serial number. If set to zero (0), this device does not have a serial number.
	bNumConfigurations:	1,					//Device has this number of configurations.
};
static const DEVICE_DESCRIPTOR device_desc_MTP = {
	bLength:		sizeof(DEVICE_DESCRIPTOR),		//The length of this descriptor
	bDescriptorType:	DEVICE_DESCRIPTOR_TYPE,			//Device Descriptor Type
	bcdUSB:			0x0200,					//USB Specification Release Number	//【重要】Version 2.0+ required for microsoft os descriptors to work.
//不要	bDeviceClass:		0x00,					//Class information may be found at the interface level
//不要	bDeviceSubClass:	0x00,					//bDeviceSubClass is zero
//不要	bDeviceProtocol:	0x00,					//bDeviceProtocol is zero
	bMaxPacketSize0:	EP0_PACKET_SIZE,			//mplementation specific, may be set to 8, 16, 32 or 64
	idVendor:		PCE_VENDOR_ID,				//Vendor ID assigned to IHV by USB-IF
	idProduct:		MTP_PRODUCT_ID,				//Product ID assigned by IHV		//【重要】PTPとMTPのIDを同じにしてはいけない。詳細はclipptp.hの「プロダクトID」のコメントを参照してください。
	bcdDevice:		0x0001,					//Device release number in BCD assigned by IHV to this release of model
	iManufacture:		1,					//Index of string descriptor describing IHV. If set to zero (0), there is no manufacturer string.
	iProduct:		2,					//Index of string describing this product. If set to zero (0), there is no product string.
//不要	iSerialNumber:		0,					//Index of string descriptor with this specific device’s serial number. If set to zero (0), this device does not have a serial number.
	bNumConfigurations:	1,					//Device has this number of configurations.
};
/*--------------------------------------------------------------------------*/
/* D.6.1.2 Configuration Descriptor */
static const CONFIGURATION_DESCRIPTOR config_desc = {
	bLength:		sizeof(CONFIGURATION_DESCRIPTOR),	//The length of this descriptor
	bDescriptorType:	CONFIGURATION_DESCRIPTOR_TYPE,		//Configuration Descriptor Type
	wTotalLength:		sizeof(CONFIGURATION_DESCRIPTOR) +	//Total length of data returned for this configuration. Includes this descriptor and all of the descriptors that follow (interface, endpoint and vendor specific, if present).
				sizeof(INTERFACE_DESCRIPTOR) +
				sizeof(ENDPOINT_DESCRIPTOR) * 3,
	bNumInterfaces:		1,					//This configuration has <#> interfaces
	bConfigurationValue:	1,					//Implementation specific value used as an argument to Set Configuration to select this configuration
//不要	iConfiguration:		0,					//Index of string describing this configu ration. If set to zero (0), there is no configuration string.
	bmAttributes:		0x80,		/* Bus-powered */	//Configuration characteristics as defined by USB Specification
	MaxPower:		100 / 2,	/* 100[mA](仮) */	//Maximum power draw from the bus by this device when this configuration is selected.
};
/* D.6.1.3 Still Image Interface Descriptor */
static const INTERFACE_DESCRIPTOR interface_desc = {
	bLength:		sizeof(INTERFACE_DESCRIPTOR),		//The length of this descriptor
	bDescriptorType:	INTERFACE_DESCRIPTOR_TYPE,		//Interface Descriptor Type
//不要	bInterfaceNumber:	0,					//Number of interface in configuration
//不要	bAlternateSetting:	0x00,					//Default setting for this interface
	bNumEndpoints:		3,					//Number of endpoints in this interface, not including the default endpoint.
	bInterfaceClass:	0x06,					//Image interface
	bInterfaceSubClass:	0x01,					//Still Image Capture Device
	bInterfaceProtocol:	0x01,					//This field indicates the protocol sup ported by this device. PIMA 15740 compliant devices use Bulk-only protocol
//不要	iInterface:		0,					//Index of string describing this inter face. If set to zero (0), there is no inter face string.
};
/* D.6.1.4 Data-In Endpoint Descriptor */
static const ENDPOINT_DESCRIPTOR endpoint_desc_ep2in = {
	bLength:		sizeof(ENDPOINT_DESCRIPTOR),		//The length of this descriptor
	bDescriptorType:	ENDPOINT_DESCRIPTOR_TYPE,		//Endpoint Descriptor Type
	bEndpointAddress:	0x82,		/* EP2IN */		//Any endpoint number not used by another endpoint. The direction shall be set to IN.
	bmAttributes:		2,		/* Bulk */		//The endpoint uses bulk transfers
	wMaxPacketSize:		EP2_NONISO_PACKET_SIZE,			//Maximum packet size used by this endpoint. This must be less than or equal to 64 bytes.
//不要	bInterval:		0,					//Ignored
};
/* D.6.1.5 Data-Out Endpoint Descriptor */
static const ENDPOINT_DESCRIPTOR endpoint_desc_ep2out = {
	bLength:		sizeof(ENDPOINT_DESCRIPTOR),		//The length of this descriptor
	bDescriptorType:	ENDPOINT_DESCRIPTOR_TYPE,		//Endpoint Descriptor Type
	bEndpointAddress:	0x02,		/* EP2OUT */		//Any endpoint number not used by another endpoint. The direction shall be set to OUT.
	bmAttributes:		2,		/* Bulk */		//The endpoint uses bulk transfers
	wMaxPacketSize:		EP2_NONISO_PACKET_SIZE,			//Maximum packet size used by this endpoint. This must be less than or equal to 64 bytes.
//不要	bInterval:		0,					//Ignored
};
/* D.6.1.6 Interrupt Endpoint Descriptor */
static const ENDPOINT_DESCRIPTOR endpoint_desc_ep1in = {
	bLength:		sizeof(ENDPOINT_DESCRIPTOR),		//The length of this descriptor
	bDescriptorType:	ENDPOINT_DESCRIPTOR_TYPE,		//Endpoint Descriptor Type
	bEndpointAddress:	0x81,		/* EP1IN */		//Any endpoint number not used by another endpoint. The direction shall be set to IN.
	bmAttributes:		3,		/* Interrupt */		//The endpoint uses interrupt transfers
	wMaxPacketSize:		EP1_PACKET_SIZE,			//Maximum packet size used by this endpoint. This must be less than or equal to 64 bytes.
	bInterval:		100,		/* 100[ms] */		//Interval for polling endpoint for data transfers
};
/*--------------------------------------------------------------------------*/
/* D.6.1.7 String Descriptors */
static const char* const string_desc[] = {
//	   ++-- 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 20 22 24 26 28 2a 2c 2e 30
//	   ||
//	"\x??\3_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0_\0"
	"\x04\3\x09\x04",						// 0: wLANGID = 0x0409 English (United States)
	"\x16\3P\0i\0e\0c\0e\0 \0L\0a\0b\0.\0",				// 1: iManufacture   = "Piece Lab."
	"\x22\3P\0/\0E\0C\0E\0 \0U\0S\0B\0 \0d\0e\0v\0i\0c\0e\0",	// 2: iProduct       = "P/ECE USB device"
};
/****************************************************************************
 *	その他のローカルデータ
 ****************************************************************************/
/* コマンドフェーズの次に行うべきフェーズ */
static const uint16_t TBL_DataDirection[][2/*OperationCode,Phase*/] = {
	{PTP_OperationCode_GetDeviceInfo		,PTP_Phase_DataIn	},
	{PTP_OperationCode_OpenSession			,PTP_Phase_Response	},
	{PTP_OperationCode_CloseSession			,PTP_Phase_Response	},
	{PTP_OperationCode_GetStorageIDs		,PTP_Phase_DataIn	},
	{PTP_OperationCode_GetStorageInfo		,PTP_Phase_DataIn	},
	{PTP_OperationCode_GetNumObjects		,PTP_Phase_Response	},
	{PTP_OperationCode_GetObjectHandles		,PTP_Phase_DataIn	},
	{PTP_OperationCode_GetObjectInfo		,PTP_Phase_DataIn	},
	{PTP_OperationCode_GetObject			,PTP_Phase_DataIn	},
	{PTP_OperationCode_GetThumb			,PTP_Phase_DataIn	},
	{PTP_OperationCode_DeleteObject			,PTP_Phase_Response	},
	{PTP_OperationCode_SendObjectInfo		,PTP_Phase_DataOut	},
	{PTP_OperationCode_SendObject			,PTP_Phase_DataOut	},
	{PTP_OperationCode_InitiateCapture		,PTP_Phase_Response	},
	{PTP_OperationCode_FormatStore			,PTP_Phase_Response	},
	{PTP_OperationCode_ResetDevice			,PTP_Phase_Response	},
	{PTP_OperationCode_SelfTest			,PTP_Phase_Response	},
	{PTP_OperationCode_SetObjectProtection		,PTP_Phase_Response	},
	{PTP_OperationCode_PowerDown			,PTP_Phase_Response	},
	{PTP_OperationCode_GetDevicePropDesc		,PTP_Phase_DataIn	},
	{PTP_OperationCode_GetDevicePropValue		,PTP_Phase_DataIn	},
	{PTP_OperationCode_SetDevicePropValue		,PTP_Phase_DataOut	},
	{PTP_OperationCode_ResetDevicePropValue		,PTP_Phase_Response	},
	{PTP_OperationCode_TerminateOpenCapture		,PTP_Phase_Response	},
	{PTP_OperationCode_MoveObject			,PTP_Phase_Response	},
	{PTP_OperationCode_CopyObject			,PTP_Phase_Response	},
	{PTP_OperationCode_GetPartialObject		,PTP_Phase_DataIn	},
	{PTP_OperationCode_InitiateOpenCapture		,PTP_Phase_Response	},
#ifdef  USE_MTP_OPERATION
	/*--- MTP Extension operation codes ---*/
	{MTP_OperationCode_GetObjectPropsSupported	,PTP_Phase_DataIn	},
	{MTP_OperationCode_GetObjectPropDesc		,PTP_Phase_DataIn	},
	{MTP_OperationCode_GetObjectPropValue		,PTP_Phase_DataIn	},
	{MTP_OperationCode_SetObjectPropValue		,PTP_Phase_DataOut	},
	{MTP_OperationCode_GetObjectPropList		,PTP_Phase_DataIn	},
	{MTP_OperationCode_SetObjectPropList		,PTP_Phase_DataOut	},
	{MTP_OperationCode_GetInterdependentPropDesc	,PTP_Phase_DataIn	},
	{MTP_OperationCode_SendObjectPropList		,PTP_Phase_DataOut	},
	{MTP_OperationCode_GetObjectReferences		,PTP_Phase_DataIn	},
	{MTP_OperationCode_SetObjectReferences		,PTP_Phase_DataOut	},
	{MTP_OperationCode_Skip				,PTP_Phase_Response	},
#endif//USE_MTP_OPERATION
};
/*--------------------------------------------------------------------------*/
/* DeviceInfo Dataset */
static const uint8_t DeviceInfoDataset[] = {
	USB_UINT16(100),						// 1 StandardVersion		2 UINT16	「0x0100」ではなく「100」で正しい。
#ifdef  USE_MTP_OPERATION
	USB_UINT32(6),							// 2 VendorExtensionID		4 UINT32	「MTP Device Extensions for Metadata Transfer」(http://msdn.microsoft.com/en-us/library/windows/desktop/dd563898(v=vs.85).aspx)より引用:
	USB_UINT16(100),						// 3 VendorExtensionVersion	2 UINT16	│Media Transfer Protocol (MTP) is a protocol designed for portable media devices.
	26,								// 4 VendorExtensionDesc	? String	│The primary purpose of this protocol is to provide a common protocol for exchanging data between a computer and a portable media device.
	 USB_UINT16('m'),// 1						//						│This includes receiving and sending media objects and enumerating the contents and capabilities of the device.
	 USB_UINT16('i'),// 2						//						│MTP uses persistent unique object identifiers (PUOIDs) to uniquely identify digital media items (and other objects) stored on a device.
	 USB_UINT16('c'),// 3						//						│When exchanging information about changes that have occurred on a device that supports MTP, the device and Windows Media Player use PUOIDs to identify which objects have changed.
	 USB_UINT16('r'),// 4						//						│The header file named wmpdevices.h, which is installed as part of the Windows Media Player SDK, defines the structures and constants needed to support Windows Media Player device extensions
	 USB_UINT16('o'),// 5						//						│For a device to be recognized as supporting metadata transfer through the Windows Media Player MTP device extension set, it must include the following information in the DeviceInfo dataset. (For more information about this dataset, see section 4.6.1 of the MTP specification.)
	 USB_UINT16('s'),// 6						//						│ Dataset field           Field order  Data type  Value
	 USB_UINT16('o'),// 7						//						│ VendorExtensionID       2            UINT32     0x00000006
	 USB_UINT16('f'),// 8						//						│ VendorExtensionVersion  3            UINT16     0x0064 (100)
	 USB_UINT16('t'),// 9						//						│ VendorExtensionDesc     4            String     "microsoft.com/WMPPD: 10.0"
	 USB_UINT16('.'),//10						//						│The following table provides details about the MTP operation for accelerated metadata transfer.
	 USB_UINT16('c'),//11						//						│ Item                   Description
	 USB_UINT16('o'),//12						//						│ Operation Code         0x9201
	 USB_UINT16('m'),//13						//						│ Operation Parameter 1  The transaction ID supplied by the device during the previous session. This value is zero for the first session.
	 USB_UINT16('/'),//14						//						│ Operation Parameter 2  Starting index. This value is always zero on the first call of a session. On subsequent calls within the same synchronization session, this value increases by the sum of the count of the modified and the deleted items from the previous response data.
	 USB_UINT16('W'),//15						//						│ Operation Parameter 3  0x10000. This constant, defined in wmpdevices.h, is the maximum number of PUOIDs that can be returned in the response. Note that the value of this constant may be revised in future releases of this header file.
	 USB_UINT16('M'),//16						//						│ Operation Parameter 4  0
	 USB_UINT16('P'),//17						//						│ Operation Parameter 5  0
	 USB_UINT16('P'),//18						//						│ Data                   The device returns two contiguous MTP arrays containing PUOIDs. Each MTP array begins with a DWORD value indicating the count of items in the array, followed by the array of elements. The first MTP array contains the list of PUOIDs that have been added or changed. The second MTP array contains the list of PUOIDs that have been deleted from the portable device. Note that the sum of PUOID count in the two arrays must not exceed the value passed in Operation Parameter 3.
	 USB_UINT16('D'),//19						//						│ Data Direction         R->I
	 USB_UINT16(':'),//20						//						│ Response Code          Options MTP_RESPONSE_OK (0x2001) or valid error response code.
	 USB_UINT16(' '),//21						//						│ Response Parameter 1   The device's current transaction ID.
	 USB_UINT16('1'),//22						//						│ Response Parameter 2   The number of PUOIDs that remain to be retrieved by future requests.
	 USB_UINT16('0'),//23						//						│ Response Parameter 3   DWORD containing status information. Status is indicated in a bitwise fashion. See Remarks for information about flags to use.
	 USB_UINT16('.'),//24						//						│ Response Parameter 4   0
	 USB_UINT16('0'),//25						//						│ Response Parameter 5   0
	 USB_UINT16( 0 ),//26						//
#else //USE_MTP_OPERATION
	USB_UINT32(0),							// 2 VendorExtensionID		4 UINT32
	USB_UINT16(0),							// 3 VendorExtensionVersion	2 UINT16
	0,								// 4 VendorExtensionDesc	? String
#endif//USE_MTP_OPERATION
	USB_UINT16(0),							// 5 FunctionalMode		2 UINT16
#ifdef  USE_MTP_OPERATION
	USB_UINT32(15),							// 6 OperationsSupported	? OperationCode Array
	 USB_UINT16(PTP_OperationCode_GetDeviceInfo),				// 1
	 USB_UINT16(PTP_OperationCode_OpenSession),				// 2
	 USB_UINT16(PTP_OperationCode_CloseSession),				// 3
	 USB_UINT16(PTP_OperationCode_GetStorageIDs),				// 4
	 USB_UINT16(PTP_OperationCode_GetStorageInfo),				// 5
	 USB_UINT16(PTP_OperationCode_GetNumObjects),				// 6
	 USB_UINT16(PTP_OperationCode_GetObjectHandles),			// 7
	 USB_UINT16(PTP_OperationCode_GetObjectInfo),				// 8
	 USB_UINT16(PTP_OperationCode_GetObject),				// 9
//	 USB_UINT16(PTP_OperationCode_GetThumb),				//
	 USB_UINT16(PTP_OperationCode_DeleteObject),				//10
	 USB_UINT16(PTP_OperationCode_SendObjectInfo),				//11
	 USB_UINT16(PTP_OperationCode_SendObject),				//12
//	 USB_UINT16(PTP_OperationCode_InitiateCapture),				//
//	 USB_UINT16(PTP_OperationCode_FormatStore),				//
//	 USB_UINT16(PTP_OperationCode_ResetDevice),				//
//	 USB_UINT16(PTP_OperationCode_SelfTest),				//
//	 USB_UINT16(PTP_OperationCode_SetObjectProtection),			//
//	 USB_UINT16(PTP_OperationCode_PowerDown),				//
//	 USB_UINT16(PTP_OperationCode_GetDevicePropDesc),			//
//	 USB_UINT16(PTP_OperationCode_GetDevicePropValue),			//
//	 USB_UINT16(PTP_OperationCode_SetDevicePropValue),			//
//	 USB_UINT16(PTP_OperationCode_ResetDevicePropValue),			//
//	 USB_UINT16(PTP_OperationCode_TerminateOpenCapture),			//
//	 USB_UINT16(PTP_OperationCode_MoveObject),				//
//	 USB_UINT16(PTP_OperationCode_CopyObject),				//
//	 USB_UINT16(PTP_OperationCode_GetPartialObject),			//
//	 USB_UINT16(PTP_OperationCode_InitiateOpenCapture),			//
	 /*--- MTP Extension operation codes ---*/
	 USB_UINT16(MTP_OperationCode_GetObjectPropsSupported),			//13	┐
	 USB_UINT16(MTP_OperationCode_GetObjectPropDesc),			//14	├5.3.2.1 Requirements for Object Property Support
	 USB_UINT16(MTP_OperationCode_GetObjectPropValue),			//15	┘
//	 USB_UINT16(MTP_OperationCode_SetObjectPropValue),			//
//	 USB_UINT16(MTP_OperationCode_GetObjectPropList),			//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_SetObjectPropList),			//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_GetInterdependentPropDesc),		//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_SendObjectPropList),			//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_GetObjectReferences),			//
//	 USB_UINT16(MTP_OperationCode_SetObjectReferences),			//
//	 USB_UINT16(MTP_OperationCode_Skip),					//
#else //USE_MTP_OPERATION
	USB_UINT32(12),							// 6 OperationsSupported	? OperationCode Array
	 USB_UINT16(PTP_OperationCode_GetDeviceInfo),				// 1
	 USB_UINT16(PTP_OperationCode_OpenSession),				// 2
	 USB_UINT16(PTP_OperationCode_CloseSession),				// 3
	 USB_UINT16(PTP_OperationCode_GetStorageIDs),				// 4
	 USB_UINT16(PTP_OperationCode_GetStorageInfo),				// 5
	 USB_UINT16(PTP_OperationCode_GetNumObjects),				// 6
	 USB_UINT16(PTP_OperationCode_GetObjectHandles),			// 7
	 USB_UINT16(PTP_OperationCode_GetObjectInfo),				// 8
	 USB_UINT16(PTP_OperationCode_GetObject),				// 9
//	 USB_UINT16(PTP_OperationCode_GetThumb),				//
	 USB_UINT16(PTP_OperationCode_DeleteObject),				//10
	 USB_UINT16(PTP_OperationCode_SendObjectInfo),				//11
	 USB_UINT16(PTP_OperationCode_SendObject),				//12
//	 USB_UINT16(PTP_OperationCode_InitiateCapture),				//
//	 USB_UINT16(PTP_OperationCode_FormatStore),				//
//	 USB_UINT16(PTP_OperationCode_ResetDevice),				//
//	 USB_UINT16(PTP_OperationCode_SelfTest),				//
//	 USB_UINT16(PTP_OperationCode_SetObjectProtection),			//
//	 USB_UINT16(PTP_OperationCode_PowerDown),				//
//	 USB_UINT16(PTP_OperationCode_GetDevicePropDesc),			//
//	 USB_UINT16(PTP_OperationCode_GetDevicePropValue),			//
//	 USB_UINT16(PTP_OperationCode_SetDevicePropValue),			//
//	 USB_UINT16(PTP_OperationCode_ResetDevicePropValue),			//
//	 USB_UINT16(PTP_OperationCode_TerminateOpenCapture),			//
//	 USB_UINT16(PTP_OperationCode_MoveObject),				//
//	 USB_UINT16(PTP_OperationCode_CopyObject),				//
//	 USB_UINT16(PTP_OperationCode_GetPartialObject),			//
//	 USB_UINT16(PTP_OperationCode_InitiateOpenCapture),			//
	 /*--- MTP Extension operation codes ---*/
//	 USB_UINT16(MTP_OperationCode_GetObjectPropsSupported),			//	┐
//	 USB_UINT16(MTP_OperationCode_GetObjectPropDesc),			//	├5.3.2.1 Requirements for Object Property Support
//	 USB_UINT16(MTP_OperationCode_GetObjectPropValue),			//	┘
//	 USB_UINT16(MTP_OperationCode_SetObjectPropValue),			//
//	 USB_UINT16(MTP_OperationCode_GetObjectPropList),			//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_SetObjectPropList),			//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_GetInterdependentPropDesc),		//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_SendObjectPropList),			//	//Enhanced Operation
//	 USB_UINT16(MTP_OperationCode_GetObjectReferences),			//
//	 USB_UINT16(MTP_OperationCode_SetObjectReferences),			//
//	 USB_UINT16(MTP_OperationCode_Skip),					//
#endif//USE_MTP_OPERATION
	USB_UINT32(0),							// 7 EventsSupported		? EventCode Array
	USB_UINT32(0),							// 8 DevicePropertiesSupported	? DevicePropCode Array
	USB_UINT32(0),							// 9 CaptureFormats		? ObjectFormatCode Array
	USB_UINT32(96),							//10 ImageFormats		? ObjectFormatCode Array
	 USB_UINT16(PTP_ObjectFormat_Undefined),				// 1	0x3000		//Undefined non-image object						┐←Windows7⇒P/ECEへ書き込むとき、OSが既知の拡張子(*.jpg,*.png等)以外は、全て「Undefined」形式として扱われる。「Undefined」形式を含めておかないと、毎回、
	 USB_UINT16(PTP_ObjectFormat_Association),				// 2	0x3001		//Association (e.g. folder)						│　「～をデバイスにコピーしてよろしいですか? ご使用のデバイスでは、このファイルを再生または表示できない可能性があります。」という警告が表示されてしまう。
	 USB_UINT16(PTP_ObjectFormat_Script),					// 3	0x3002		//Device-model-specific script						│
	 USB_UINT16(PTP_ObjectFormat_Executable),				// 4	0x3003		//Device-model-specific binary executable				│
	 USB_UINT16(PTP_ObjectFormat_Text),					// 5	0x3004		//Text file								│
	 USB_UINT16(PTP_ObjectFormat_HTML),					// 6	0x3005		//HyperText Markup Language file (text)					│
	 USB_UINT16(PTP_ObjectFormat_DPOF),					// 7	0x3006		//Digital Print Order Format file (text)				│
	 USB_UINT16(PTP_ObjectFormat_AIFF),					// 8	0x3007		//Audio clip								│
	 USB_UINT16(PTP_ObjectFormat_WAV),					// 9	0x3008		//Audio clip								│
	 USB_UINT16(PTP_ObjectFormat_MP3),					//10	0x3009		//Audio clip								│
	 USB_UINT16(PTP_ObjectFormat_AVI),					//11	0x300A		//Video clip								│
	 USB_UINT16(PTP_ObjectFormat_MPEG),					//12	0x300B		//Video clip								│
	 USB_UINT16(PTP_ObjectFormat_ASF),					//13	0x300C		//Microsoft Advanced Streaming Format (video)				│
	 USB_UINT16(PTP_ObjectFormat_UnknownImageObject),			//14	0x3800		//Unknown image object							│
	 USB_UINT16(PTP_ObjectFormat_EXIF_JPEG),				//15	0x3801		//Exchangeable File Format, JEIDA standard				│
	 USB_UINT16(PTP_ObjectFormat_TIFF_EP),					//16	0x3802		//Tag Image File Format for Electronic Photography			│
	 USB_UINT16(PTP_ObjectFormat_FlashPix),					//17	0x3803		//Structured Storage Image Format					│
	 USB_UINT16(PTP_ObjectFormat_BMP),					//18	0x3804		//Microsoft Windows Bitmap file						├─定義されているオブジェクトフォーマットを、全て列挙しておくことにする。ここに列挙されていない形式は、OS側で判断して、コピー不可,又は,警告が表示される。
	 USB_UINT16(PTP_ObjectFormat_CIFF),					//19	0x3805		//Canon Camera Image File Format					│
	 USB_UINT16(PTP_ObjectFormat_Reserved_0x3806),				//20	0x3806		//Reserved								│
	 USB_UINT16(PTP_ObjectFormat_GIF),					//21	0x3807		//Graphics Interchange Format						│
	 USB_UINT16(PTP_ObjectFormat_JFIF),					//22	0x3808		//JPEG File Interchange Format						│
	 USB_UINT16(PTP_ObjectFormat_PCD),					//23	0x3809		//PhotoCD Image Pac							│
	 USB_UINT16(PTP_ObjectFormat_PICT),					//24	0x380A		//Quickdraw Image Format						│
	 USB_UINT16(PTP_ObjectFormat_PNG),					//25	0x380B		//Portable Network Graphics						│
	 USB_UINT16(PTP_ObjectFormat_Reserved_0x380C),				//26	0x380C		//Reserved								│
	 USB_UINT16(PTP_ObjectFormat_TIFF),					//27	0x380D		//Tag Image File Format							│
	 USB_UINT16(PTP_ObjectFormat_TIFF_IT),					//28	0x380E		//Tag Image File Format for Information Technology (graphic arts)	│
	 USB_UINT16(PTP_ObjectFormat_JP2),					//29	0x380F		//JPEG2000 Baseline File Format						│
	 USB_UINT16(PTP_ObjectFormat_JPX),					//30	0x3810		//JPEG2000 Extended File Format						│
//	 USB_UINT16(PTP_ObjectFormat_Reserved),					//	0x3000/*+?*/	//Reserved for future use	All other codes with MSN of 0011	│
//	 USB_UINT16(PTP_ObjectFormat_VendorDefined),				//	0xB000/*+?*/	//Vendor-Defined		All other codes with MSN of 1011	│
	 /*--- MTP Extension format codes ---*/					//												│
	 USB_UINT16(MTP_ObjectFormat_UndefinedFirmware),			//31	0xB802											│
	 USB_UINT16(MTP_ObjectFormat_WBMP ),					//32	0xB803		//Wireless Application Protocol Bitmap Format (.wbmp). image/vnd.wap.wbmp http://www.wapforum.org/what/technical/SPEC-WAESpec-19990524.pdf
	 USB_UINT16(MTP_ObjectFormat_JPEG_XR ),					//33	0xB804		//JPEG XR, also known as HD Photo (.hdp,.jxr,.wpd). image/vnd.ms-photo. ISO/IEC 29199-2:2009 http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=51609
	 USB_UINT16(MTP_ObjectFormat_WindowsImageFormat),			//34	0xB881											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedAudio),				//35	0xB900		//Undefined audio object						│
	 USB_UINT16(MTP_ObjectFormat_WMA),					//36	0xB901		//Windows Media Audio							│
	 USB_UINT16(MTP_ObjectFormat_OGG),					//37	0xB902											│
	 USB_UINT16(MTP_ObjectFormat_AAC),					//38	0xB903		//Advanced Audio Coding (.aac). audio/aac. MPEG-4 AAC.			│
	 USB_UINT16(MTP_ObjectFormat_Audible),					//39	0xB904											│
	 USB_UINT16(MTP_ObjectFormat_FLAC),					//40	0xB906		//Free Lossless Audio Codec						│
	 USB_UINT16(MTP_ObjectFormat_QCELP),					//41	0xB907		//Qualcomm Code Excited Linear Prediction (.qcp). audio/qcelp		│
	 USB_UINT16(MTP_ObjectFormat_AMR),					//42	0xB908		//Adaptive Multi-Rate audio codec (.amr). audio/amr			│
	 USB_UINT16(MTP_ObjectFormat_UndefinedVideo),				//43	0xB980		//Undefined video object						│
	 USB_UINT16(MTP_ObjectFormat_WMV),					//44	0xB981		//Windows Media Video							│
	 USB_UINT16(MTP_ObjectFormat_MP4Container),				//45	0xB982		//ISO 14496-1								│
	 USB_UINT16(MTP_ObjectFormat_MP2),					//46	0xB983		//MPEG-1 Layer II audio (ISO/IEC 13818-3)				│
	 USB_UINT16(MTP_ObjectFormat_3GPContainer),				//47	0xB984		//3GPP file format. Details: http://www.3gpp.org/ftp/Specs/html-info/26244.htm (page title - "Transparent end-to-end packet switched streaming service, 3GPP file format").
	 USB_UINT16(MTP_ObjectFormat_3G2),					//48	0xB985		//3GPP2 format (.3g2). video/3gpp2, audio/3gpp2 http://www.3gpp2.org/Public_html/specs/C.S0050-B_v1.0_070521.pdf
	 USB_UINT16(MTP_ObjectFormat_AVCHD),					//49	0xB986		//MPEG-4 AVC video and Dolby Digital audio within an MPEG-2 Transport Stream as constrained by the AVCHD format specification http://www.avchd-info.org/
	 USB_UINT16(MTP_ObjectFormat_ATSC_TS),					//50	0xB987		//MPEG-2 video and AC-3 audio within an ATSC-compliant MPEG-2 Transport Stream
	 USB_UINT16(MTP_ObjectFormat_DVB_TS),					//51	0xB988		//MPEG-2 video and MPEG-1 Layer II or AC-3 audio within a DVB-compliant MPEG-2 Transport Stream
	 USB_UINT16(MTP_ObjectFormat_UndefinedCollection),			//52	0xBA00											│
	 USB_UINT16(MTP_ObjectFormat_AbstractMultimediaAlbum),			//53	0xBA01											│
	 USB_UINT16(MTP_ObjectFormat_AbstractImageAlbum),			//54	0xBA02											│
	 USB_UINT16(MTP_ObjectFormat_AbstractAudioAlbum),			//55	0xBA03											│
	 USB_UINT16(MTP_ObjectFormat_AbstractVideoAlbum),			//56	0xBA04											│
	 USB_UINT16(MTP_ObjectFormat_AbstractAudioVideoPlaylist),		//57	0xBA05											│
	 USB_UINT16(MTP_ObjectFormat_AbstractContactGroup),			//58	0xBA06											│
	 USB_UINT16(MTP_ObjectFormat_AbstractMessageFolder),			//59	0xBA07											│
	 USB_UINT16(MTP_ObjectFormat_AbstractChapteredProduction),		//60	0xBA08											│
	 USB_UINT16(MTP_ObjectFormat_AbstractAudioPlaylist),			//61	0xBA09											│
	 USB_UINT16(MTP_ObjectFormat_AbstractVideoPlaylist),			//62	0xBA0A											│
	 USB_UINT16(MTP_ObjectFormat_AbstractMediacast),			//63	0xBA0B		//For use with mediacasts; references multimedia enclosures of RSS feeds or episodic content
	 USB_UINT16(MTP_ObjectFormat_WPLPlaylist),				//64	0xBA10											│
	 USB_UINT16(MTP_ObjectFormat_M3UPlaylist),				//65	0xBA11											│
	 USB_UINT16(MTP_ObjectFormat_MPLPlaylist),				//66	0xBA12											│
	 USB_UINT16(MTP_ObjectFormat_ASXPlaylist),				//67	0xBA13											│
	 USB_UINT16(MTP_ObjectFormat_PLSPlaylist),				//68	0xBA14											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedDocument),			//69	0xBA80											│
	 USB_UINT16(MTP_ObjectFormat_AbstractDocument),				//70	0xBA81											│
	 USB_UINT16(MTP_ObjectFormat_XMLDocument),				//71	0xBA82											│
	 USB_UINT16(MTP_ObjectFormat_MicrosoftWordDocument),			//72	0xBA83											│
	 USB_UINT16(MTP_ObjectFormat_MHTCompiledHTMLDocument),			//73	0xBA84											│
	 USB_UINT16(MTP_ObjectFormat_MicrosoftExcelSpreadsheet),		//74	0xBA85											│
	 USB_UINT16(MTP_ObjectFormat_MicrosoftPowerpointDocument),		//75	0xBA86											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedMessage),				//76	0xBB00											│
	 USB_UINT16(MTP_ObjectFormat_AbstractMessage),				//77	0xBB01											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedBookmark),			//78	0xBB10											│
	 USB_UINT16(MTP_ObjectFormat_AbstractBookmark),				//79	0xBB11											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedAppointment),			//80	0xBB20											│
	 USB_UINT16(MTP_ObjectFormat_AbstractAppointment),			//81	0xBB21											│
	 USB_UINT16(MTP_ObjectFormat_vCalendar1_0),				//82	0xBE22		//(※要確認:0xBE22と0xBE02のどちらが正しいのか不明)			│
	 USB_UINT16(MTP_ObjectFormat_UndefinedTask),				//83	0xBB40											│
	 USB_UINT16(MTP_ObjectFormat_AbstractTask),				//84	0xBB41											│
	 USB_UINT16(MTP_ObjectFormat_iCalendar),				//85	0xBB42											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedNote),				//86	0xBB60											│
	 USB_UINT16(MTP_ObjectFormat_AbstractNote),				//87	0xBB61											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedContact),				//88	0xBB80											│
	 USB_UINT16(MTP_ObjectFormat_AbstractContact),				//89	0xBB81											│
	 USB_UINT16(MTP_ObjectFormat_vCard2),					//90	0xBB82											│
	 USB_UINT16(MTP_ObjectFormat_vCard3),					//91	0xBB83											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedCalendarItem),			//92	0xBE00											│
	 USB_UINT16(MTP_ObjectFormat_AbstractCalendarItem),			//93	0xBE01											│
	 USB_UINT16(MTP_ObjectFormat_vCalendar1),				//94	0xBE02		//(※要確認:0xBE22と0xBE02のどちらが正しいのか不明)			│
	 USB_UINT16(MTP_ObjectFormat_vCalendar2),				//95	0xBE03											│
	 USB_UINT16(MTP_ObjectFormat_UndefinedWindowsExecutable),		//96	0xBE80											┘
	11,								//11 Manufacturer		? String
	 USB_UINT16('P'),// 1
	 USB_UINT16('i'),// 2
	 USB_UINT16('e'),// 3
	 USB_UINT16('c'),// 4
	 USB_UINT16('e'),// 5
	 USB_UINT16(' '),// 6
	 USB_UINT16('L'),// 7
	 USB_UINT16('a'),// 8
	 USB_UINT16('b'),// 9
	 USB_UINT16('.'),//10
	 USB_UINT16( 0 ),//11
	17,								//12 Model			? String
	 USB_UINT16('P'),// 1
	 USB_UINT16('/'),// 2
	 USB_UINT16('E'),// 3
	 USB_UINT16('C'),// 4
	 USB_UINT16('E'),// 5
	 USB_UINT16(' '),// 6
	 USB_UINT16('U'),// 7
	 USB_UINT16('S'),// 8
	 USB_UINT16('B'),// 9
	 USB_UINT16(' '),//10
	 USB_UINT16('d'),//11
	 USB_UINT16('e'),//12
	 USB_UINT16('v'),//13
	 USB_UINT16('i'),//14
	 USB_UINT16('c'),//15
	 USB_UINT16('e'),//16
	 USB_UINT16( 0 ),//17
	0,								//13 DeviceVersion		? String
	0,								//14 SerialNumber		? String
};
/*--------------------------------------------------------------------------*/
//If a physical store does not contain any logical stores, the LogicalStorageID should be set to 0x0000, and it shall be assumed that the store does not contain any data, nor can it receive any data.
//StorageIDs of 0x00000000 and 0xFFFFFFFF are not used to refer to real stores, but have context-specific meanings, such as “all-stores,” or “the default store.”
#define StorageID	(1|1<<16)	//PhysicalStorageID=1,LogicalStorageID=1
/*--------------------------------------------------------------------------*/
/* StorageID Array */
static const uint8_t StorageIDArray[] = {
	USB_UINT32(1),
	 USB_UINT32(StorageID),// 0
};
/*--------------------------------------------------------------------------*/
/* StorageInfo Dataset */
static const uint8_t StorageInfoDataset[] = {
	USB_UINT16(PTP_StorageType_FixedRAM),				// 1 StorageType		2 UINT16
	USB_UINT16(PTP_FilesystemType_GenericFlat),			// 2 FilesystemType		2 UINT16
	USB_UINT16(PTP_AccessCapability_ReadWrite),			// 3 AccessCapability		2 UINT16
	USB_UINT64(-1,-1),						// 4 MaxCapacity		8 UINT64	If this field is unused, it should report 0xFFFFFFFF.
	USB_UINT64(-1,-1),						// 5 FreeSpaceInBytes		8 UINT64	If this value is not useful for the device, it may set this field to 0xFFFFFFFF and rely upon the FreeSpaceInImages field instead.
	USB_UINT32(-1),							// 6 FreeSpaceInImages		4 UINT32	If the device does not implement this capability, this field should be set to 0xFFFFFFFF. This field may be used for devices that do not report FreeSpaceInBytes, or the two fields may be used in combination.
	0,								// 7 StorageDescription		? String
	0,								// 8 VolumeLabel		? String
};
/*--------------------------------------------------------------------------*/
#ifdef  USE_MTP_OPERATION
/* ObjectPropCode Array */
static const uint8_t ObjectPropCodeArray[] = {
	USB_UINT32(9),
	 USB_UINT16(MTP_ObjectProperty_StorageID),				// 1
	 USB_UINT16(MTP_ObjectProperty_ObjectFormat),				// 2
	 USB_UINT16(MTP_ObjectProperty_ProtectionStatus),			// 3
	 USB_UINT16(MTP_ObjectProperty_ObjectSize),				// 4
//	 USB_UINT16(MTP_ObjectProperty_AssociationType),			//
//	 USB_UINT16(MTP_ObjectProperty_AssociationDesc),			//
	 USB_UINT16(MTP_ObjectProperty_ObjectFileName),				// 5
//	 USB_UINT16(MTP_ObjectProperty_DateCreated),				//
//	 USB_UINT16(MTP_ObjectProperty_DateModified),				//
//	 USB_UINT16(MTP_ObjectProperty_Keywords),				//
	 USB_UINT16(MTP_ObjectProperty_ParentObject),				// 6
//	 USB_UINT16(MTP_ObjectProperty_AllowedFolderContents),			//
//	 USB_UINT16(MTP_ObjectProperty_Hidden),					//
//	 USB_UINT16(MTP_ObjectProperty_SystemObject),				//
	 USB_UINT16(MTP_ObjectProperty_PersistentUniqueObjectIdentifier),	// 7
//	 USB_UINT16(MTP_ObjectProperty_SyncID),					//
//	 USB_UINT16(MTP_ObjectProperty_PropertyBag),				//
	 USB_UINT16(MTP_ObjectProperty_Name),					// 8
//	 USB_UINT16(MTP_ObjectProperty_CreatedBy),				//
//	 USB_UINT16(MTP_ObjectProperty_Artist),					//
//	 USB_UINT16(MTP_ObjectProperty_DateAuthored),				//
//	 USB_UINT16(MTP_ObjectProperty_Description),				//
//	 USB_UINT16(MTP_ObjectProperty_URLReference),				//
//	 USB_UINT16(MTP_ObjectProperty_LanguageLocale),				//
//	 USB_UINT16(MTP_ObjectProperty_CopyrightInformation),			//
//	 USB_UINT16(MTP_ObjectProperty_Source),					//
//	 USB_UINT16(MTP_ObjectProperty_OriginLocation),				//
//	 USB_UINT16(MTP_ObjectProperty_DateAdded),				//
	 USB_UINT16(MTP_ObjectProperty_NonConsumable),				// 9
//	 USB_UINT16(MTP_ObjectProperty_CorruptUnplayable),			//
//	 USB_UINT16(MTP_ObjectProperty_ProducerSerialNumber),			//
//	 USB_UINT16(MTP_ObjectProperty_RepresentativeSampleFormat),		//
//	 USB_UINT16(MTP_ObjectProperty_RepresentativeSampleSize),		//
//	 USB_UINT16(MTP_ObjectProperty_RepresentativeSampleHeight),		//
//	 USB_UINT16(MTP_ObjectProperty_RepresentativeSampleWidth),		//
//	 USB_UINT16(MTP_ObjectProperty_RepresentativeSampleDuration),		//
//	 USB_UINT16(MTP_ObjectProperty_RepresentativeSampleData),		//
//	 USB_UINT16(MTP_ObjectProperty_Width),					//
//	 USB_UINT16(MTP_ObjectProperty_Height),					//
//	 USB_UINT16(MTP_ObjectProperty_Duration),				//
//	 USB_UINT16(MTP_ObjectProperty_Rating),					//
//	 USB_UINT16(MTP_ObjectProperty_Track),					//
//	 USB_UINT16(MTP_ObjectProperty_Genre),					//
//	 USB_UINT16(MTP_ObjectProperty_Credits),				//
//	 USB_UINT16(MTP_ObjectProperty_Lyrics),					//
//	 USB_UINT16(MTP_ObjectProperty_SubscriptionContentID),			//
//	 USB_UINT16(MTP_ObjectProperty_ProducedBy),				//
//	 USB_UINT16(MTP_ObjectProperty_UseCount),				//
//	 USB_UINT16(MTP_ObjectProperty_SkipCount),				//
//	 USB_UINT16(MTP_ObjectProperty_LastAccessed),				//
//	 USB_UINT16(MTP_ObjectProperty_ParentalRating),				//
//	 USB_UINT16(MTP_ObjectProperty_MetaGenre),				//
//	 USB_UINT16(MTP_ObjectProperty_Composer),				//
//	 USB_UINT16(MTP_ObjectProperty_EffectiveRating),			//
//	 USB_UINT16(MTP_ObjectProperty_Subtitle),				//
//	 USB_UINT16(MTP_ObjectProperty_OriginalReleaseDate),			//
//	 USB_UINT16(MTP_ObjectProperty_AlbumName),				//
//	 USB_UINT16(MTP_ObjectProperty_AlbumArtist),				//
//	 USB_UINT16(MTP_ObjectProperty_Mood),					//
//	 USB_UINT16(MTP_ObjectProperty_DRMStatus),				//
//	 USB_UINT16(MTP_ObjectProperty_SubDescription),				//
//	 USB_UINT16(MTP_ObjectProperty_IsCropped),				//
//	 USB_UINT16(MTP_ObjectProperty_IsColourCorrected),			//
//	 USB_UINT16(MTP_ObjectProperty_ImageBitDepth),				//
//	 USB_UINT16(MTP_ObjectProperty_Fnumber),				//
//	 USB_UINT16(MTP_ObjectProperty_ExposureTime),				//
//	 USB_UINT16(MTP_ObjectProperty_ExposureIndex),				//
//	 USB_UINT16(MTP_ObjectProperty_TotalBitRate),				//
//	 USB_UINT16(MTP_ObjectProperty_BitrateType),				//
//	 USB_UINT16(MTP_ObjectProperty_SampleRate),				//
//	 USB_UINT16(MTP_ObjectProperty_NumberOfChannels),			//
//	 USB_UINT16(MTP_ObjectProperty_AudioBitDepth),				//
//	 USB_UINT16(MTP_ObjectProperty_ScanType),				//
//	 USB_UINT16(MTP_ObjectProperty_AudioWAVECodec),				//
//	 USB_UINT16(MTP_ObjectProperty_AudioBitRate),				//
//	 USB_UINT16(MTP_ObjectProperty_VideoFourCCCodec),			//
//	 USB_UINT16(MTP_ObjectProperty_VideoBitRate),				//
//	 USB_UINT16(MTP_ObjectProperty_FramesPerThousandSeconds),		//
//	 USB_UINT16(MTP_ObjectProperty_KeyFrameDistance),			//
//	 USB_UINT16(MTP_ObjectProperty_BufferSize),				//
//	 USB_UINT16(MTP_ObjectProperty_EncodingQuality),			//
//	 USB_UINT16(MTP_ObjectProperty_EncodingProfile),			//
//	 USB_UINT16(MTP_ObjectProperty_DisplayName),				//
//	 USB_UINT16(MTP_ObjectProperty_BodyText),				//
//	 USB_UINT16(MTP_ObjectProperty_Subject),				//
//	 USB_UINT16(MTP_ObjectProperty_Priority),				//
//	 USB_UINT16(MTP_ObjectProperty_GivenName),				//
//	 USB_UINT16(MTP_ObjectProperty_MiddleNames),				//
//	 USB_UINT16(MTP_ObjectProperty_FamilyName),				//
//	 USB_UINT16(MTP_ObjectProperty_Prefix),					//
//	 USB_UINT16(MTP_ObjectProperty_Suffix),					//
//	 USB_UINT16(MTP_ObjectProperty_PhoneticGivenName),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneticFamilyName),			//
//	 USB_UINT16(MTP_ObjectProperty_EmailPrimary),				//
//	 USB_UINT16(MTP_ObjectProperty_EmailPersonal1),				//
//	 USB_UINT16(MTP_ObjectProperty_EmailPersonal2),				//
//	 USB_UINT16(MTP_ObjectProperty_EmailBusiness1),				//
//	 USB_UINT16(MTP_ObjectProperty_EmailBusiness2),				//
//	 USB_UINT16(MTP_ObjectProperty_EmailOthers),				//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberPrimary),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberPersonal),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberPersonal2),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberBusiness),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberBusiness2),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberMobile),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberMobile2),			//
//	 USB_UINT16(MTP_ObjectProperty_FaxNumberPrimary),			//
//	 USB_UINT16(MTP_ObjectProperty_FaxNumberPersonal),			//
//	 USB_UINT16(MTP_ObjectProperty_FaxNumberBusiness),			//
//	 USB_UINT16(MTP_ObjectProperty_PagerNumber),				//
//	 USB_UINT16(MTP_ObjectProperty_PhoneNumberOthers),			//
//	 USB_UINT16(MTP_ObjectProperty_PrimaryWebAddress),			//
//	 USB_UINT16(MTP_ObjectProperty_PersonalWebAddress),			//
//	 USB_UINT16(MTP_ObjectProperty_BusinessWebAddress),			//
//	 USB_UINT16(MTP_ObjectProperty_InstantMessengerAddress),		//
//	 USB_UINT16(MTP_ObjectProperty_InstantMessengerAddress2),		//
//	 USB_UINT16(MTP_ObjectProperty_InstantMessengerAddress3),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalFull),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalLine1),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalLine2),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalCity),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalRegion),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalPostalCode),	//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressPersonalCountry),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessFull),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessLine1),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessLine2),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessCity),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessRegion),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessPostalCode),	//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressBusinessCountry),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherFull),			//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherLine1),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherLine2),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherCity),			//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherRegion),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherPostalCode),		//
//	 USB_UINT16(MTP_ObjectProperty_PostalAddressOtherCountry),		//
//	 USB_UINT16(MTP_ObjectProperty_OrganizationName),			//
//	 USB_UINT16(MTP_ObjectProperty_PhoneticOrganizationName),		//
//	 USB_UINT16(MTP_ObjectProperty_Role),					//
//	 USB_UINT16(MTP_ObjectProperty_Birthdate),				//
//	 USB_UINT16(MTP_ObjectProperty_MessageTo),				//
//	 USB_UINT16(MTP_ObjectProperty_MessageCC),				//
//	 USB_UINT16(MTP_ObjectProperty_MessageBCC),				//
//	 USB_UINT16(MTP_ObjectProperty_MessageRead),				//
//	 USB_UINT16(MTP_ObjectProperty_MessageReceivedTime),			//
//	 USB_UINT16(MTP_ObjectProperty_MessageSender),				//
//	 USB_UINT16(MTP_ObjectProperty_ActivityBeginTime),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityEndTime),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityLocation),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityRequiredAttendees),		//
//	 USB_UINT16(MTP_ObjectProperty_ActivityOptionalAttendees),		//
//	 USB_UINT16(MTP_ObjectProperty_ActivityResources),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityAccepted),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityTentative),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityDeclined),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityReminderTime),			//
//	 USB_UINT16(MTP_ObjectProperty_ActivityOwner),				//
//	 USB_UINT16(MTP_ObjectProperty_ActivityStatus),				//
//	 USB_UINT16(MTP_ObjectProperty_Owner),					//
//	 USB_UINT16(MTP_ObjectProperty_Editor),					//
//	 USB_UINT16(MTP_ObjectProperty_Webmaster),				//
//	 USB_UINT16(MTP_ObjectProperty_URLSource),				//
//	 USB_UINT16(MTP_ObjectProperty_URLDestination),				//
//	 USB_UINT16(MTP_ObjectProperty_TimeBookmark),				//
//	 USB_UINT16(MTP_ObjectProperty_ObjectBookmark),				//
//	 USB_UINT16(MTP_ObjectProperty_ByteBookmark),				//
//	 USB_UINT16(MTP_ObjectProperty_LastBuildDate),				//
//	 USB_UINT16(MTP_ObjectProperty_TimetoLive),				//
//	 USB_UINT16(MTP_ObjectProperty_MediaGUID),				//
};
/*--------------------------------------------------------------------------*/
/* ObjectPropDesc dataset */
static const uint8_t ObjectPropDescDataset_StorageID[] = {
	USB_UINT16(MTP_ObjectProperty_StorageID),				// 1 PropertyCode	2 UINT16	0xDC01			//※要確認:「Media Transfer Protocol Revision 1.1 April 6th, 2011」(MTPforUSB-IFv1.1.pdf)ではこのフィールドの型が'UINT32'となっているが、'UINT16'の間違いだと判断して'UINT16'にした。他のプロパティの説明ではこのフィールドの型が'UINT16'となっており、B.2.1 StorageIDの説明だけ'UINT32'となっており不自然だから。5.1.2.1 Device Property Describing Datasetの説明でも'UINT16'となっており、'UINT16'が正しいだろう。
	USB_UINT16(PTP_DataType_UINT32),					// 2 Datatype		2 UINT16	0x0006 (UINT32)		//※要確認:「Media Transfer Protocol Revision 1.1 April 6th, 2011」(MTPforUSB-IFv1.1.pdf)ではこのフィールドの型が'UINT32'となっているが、'UINT16'の間違いだと判断して'UINT16'にした。他のプロパティの説明ではこのフィールドの型が'UINT16'となっており、B.2.1 StorageIDの説明だけ'UINT32'となっており不自然だから。5.1.2.1 Device Property Describing Datasetの説明でも'UINT16'となっており、'UINT16'が正しいだろう。
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	USB_UINT32(0),								// 4 DefaultValue			0x00000000
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None
};
static const uint8_t ObjectPropDescDataset_ObjectFormat[] = {
	USB_UINT16(MTP_ObjectProperty_ObjectFormat),				// 1 PropertyCode	2 UINT16	0xDC02
	USB_UINT16(PTP_DataType_UINT16),					// 2 Datatype		2 UINT16	0x0004 (UINT16)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	USB_UINT16(0),								// 4 DefaultValue			0x0000			←仕様書「Media Transfer Protocol Revision 1.1 April 6th, 2011」(MTPforUSB-IFv1.1.pdf)では0x0000となっていますが、Android 4.4.2のスマホは0x3000を返すようです。どちらにしても動作に影響は無いようだったので、仕様書に従って0x0000にすることにしました。
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None
};
static const uint8_t ObjectPropDescDataset_ProtectionStatus[] = {
	USB_UINT16(MTP_ObjectProperty_ProtectionStatus),			// 1 PropertyCode	2 UINT16	0xDC03
	USB_UINT16(PTP_DataType_UINT16),					// 2 Datatype		2 UINT16	0x0004 (UINT16)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	USB_UINT16(0),								// 4 DefaultValue			0x0000
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_EnumerationForm,						// 6 FormFlag		1 UINT8		0x02 Enumeration form
	USB_UINT16(4),								// 7 NumberOfValues	2 UINT16
	 USB_UINT16(PTP_ProtectionStatus_NoProtection),				// 8 SupportedValue1			0x0000 No Protection
	 USB_UINT16(PTP_ProtectionStatus_ReadOnly),				// 9 SupportedValue2			0x0001 Read-only
	 USB_UINT16(MTP_ProtectionStatus_ReadOnlyData),				//10 SupportedValue3			0x8002 Read-only data
	 USB_UINT16(MTP_ProtectionStatus_NonTransferableData),			//11 SupportedValue4			0x8003 Non-transferrable data
};
static const uint8_t ObjectPropDescDataset_ObjectSize[] = {
	USB_UINT16(MTP_ObjectProperty_ObjectSize),				// 1 PropertyCode	2 UINT16	0xDC04
	USB_UINT16(PTP_DataType_UINT64),					// 2 Datatype		2 UINT16	0x0008 (UINT64)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	USB_UINT64(0,0),							// 4 DefaultValue			0x0000000000000000
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None
};
static const uint8_t ObjectPropDescDataset_ObjectFileName[] = {
	USB_UINT16(MTP_ObjectProperty_ObjectFileName),				// 1 PropertyCode	2 UINT16	0xDC07
	USB_UINT16(PTP_DataType_STR),						// 2 Datatype		2 UINT16	0xFFFF (STRING)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		Device-defined
	0,									// 4 DefaultValue			0x00 (Null String)
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None 0x05 RegularExpression form
};
static const uint8_t ObjectPropDescDataset_ParentObject[] = {
	USB_UINT16(MTP_ObjectProperty_ParentObject),				// 1 PropertyCode	2 UINT16	0xDC0B
	USB_UINT16(PTP_DataType_UINT32),					// 2 Datatype		2 UINT16	0x0006 (UINT32)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	USB_UINT32(0),								// 4 DefaultValue			0x00000000
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None
};
static const uint8_t ObjectPropDescDataset_PersistentUniqueObjectIdentifier[] = {
	USB_UINT16(MTP_ObjectProperty_PersistentUniqueObjectIdentifier),	// 1 PropertyCode	2 UINT16	0xDC41
	USB_UINT16(PTP_DataType_UINT128),					// 2 Datatype		2 UINT16	0x000A (UINT128)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	USB_UINT128(0,0,0,0),							// 4 DefaultValue			0x0…0
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None
};
static const uint8_t ObjectPropDescDataset_Name[] = {
	USB_UINT16(MTP_ObjectProperty_Name),					// 1 PropertyCode	2 UINT16	0xDC44
	USB_UINT16(PTP_DataType_STR),						// 2 Datatype		2 UINT16	0xFFFF (STRING)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		Device-defined
	0,									// 4 DefaultValue			0x00 (Null String)
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_None,							// 6 FormFlag		1 UINT8		0x00 None
};
static const uint8_t ObjectPropDescDataset_NonConsumable[] = {
	USB_UINT16(MTP_ObjectProperty_NonConsumable),				// 1 PropertyCode	2 UINT16	0xDC4F
	USB_UINT16(PTP_DataType_UINT8),						// 2 Datatype		2 UINT16	0x0002 (UINT8)
	PTP_GetSet_Get,								// 3 Get/Set		1 UINT8		0x00 (GET)
	0x00,									// 4 DefaultValue			0x00
	USB_UINT32(0),								// 5 GroupCode		4 UINT32	Device-defined
	PTP_FormFlag_EnumerationForm,						// 6 FormFlag		1 UINT8		0x02 Enumeration form
	USB_UINT16(2),								// 7 NumberOfValues	2 UINT16
	 0x00,									// 8 SupportedValue1			A value of 0x00 indicates that the object is intended for consumption,
	 0x01,									// 9 SupportedValue2			and a value of 0x01 indicates that it shall simply be stored.
};
#endif//USE_MTP_OPERATION
/****************************************************************************
 *	
 ****************************************************************************/
void PTP_Start(const char* pProtectedFilenames, int bMTP) {
	/* 確実に終了しておく。 */
	PTP_Stop();
	/* プロテクトするファイル名のリストを格納する。 */
	stPTP.pProtectedFilenames = pProtectedFilenames ? /*GCC拡張機能*/ : "";
	/* 動作モードを格納する。 */
	stPTP.bMTP = bMTP;
	/* USBのフックを開始する。 */
	usb_start(&usb_inf);
}
/*--------------------------------------------------------------------------*/
void PTP_Stop() {
	/* USBのフックを終了する。 */
	usb_stop();
	/* 構造体メモリをクリアする。 */
	memset(&stPTP, 0, sizeof stPTP);
}
/****************************************************************************
 *	
 ****************************************************************************/
static void get_descriptor(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	int type  = HIBYTE(req->wValue);
	int index = LOBYTE(req->wValue);
	switch(type) {
	case DEVICE_DESCRIPTOR_TYPE:
		if(!stPTP.bMTP) {
			usb_ep0_tx(&device_desc_PTP, sizeof(DEVICE_DESCRIPTOR));
		} else {
			usb_ep0_tx(&device_desc_MTP, sizeof(DEVICE_DESCRIPTOR));
		}
		return;
	case CONFIGURATION_DESCRIPTOR_TYPE:
		if(index == 0) {
			static uint8_t buf[sizeof(CONFIGURATION_DESCRIPTOR) +	/* config_desc */
					   sizeof(INTERFACE_DESCRIPTOR) +	/* interface_desc */
					   sizeof(ENDPOINT_DESCRIPTOR) * 3];	/* endpoint_desc_ep2in,endpoint_desc_ep2out,endpoint_desc_ep1in */
			uint8_t* ptr =  memcpy(buf, &config_desc,          sizeof(CONFIGURATION_DESCRIPTOR))  + sizeof(CONFIGURATION_DESCRIPTOR);
			         ptr =  memcpy(ptr, &interface_desc,       sizeof(INTERFACE_DESCRIPTOR)    )  + sizeof(INTERFACE_DESCRIPTOR);
			         ptr =  memcpy(ptr, &endpoint_desc_ep2in,  sizeof(ENDPOINT_DESCRIPTOR)     )  + sizeof(ENDPOINT_DESCRIPTOR);
			         ptr =  memcpy(ptr, &endpoint_desc_ep2out, sizeof(ENDPOINT_DESCRIPTOR)     )  + sizeof(ENDPOINT_DESCRIPTOR);
			       /*ptr =*/memcpy(ptr, &endpoint_desc_ep1in,  sizeof(ENDPOINT_DESCRIPTOR)     )/*+ sizeof(ENDPOINT_DESCRIPTOR)*/;
			usb_ep0_tx(buf, sizeof buf);
			return;
		}
		break;
	case STRING_DESCRIPTOR_TYPE:
		if(stPTP.bMTP) {
			if(index == 0xEE) {
				//MS OS String Descriptor
				static const uint8_t MS_OS_String_Descriptor[]={
					0x12,									//bLength		Must be 0x12
					0x03,									//bDescriptorType	Must be 0x03
					0x4D,0x00,0x53,0x00,0x46,0x00,0x54,0x00,0x31,0x00,0x30,0x00,0x30,0x00,	//rgbSignature[14]	must be L"MSFT100"
					0xFE,									//bMSVendorCode		any
					0x00};									//bPad			Must be 0x00
				usb_ep0_tx(MS_OS_String_Descriptor, sizeof MS_OS_String_Descriptor);
				return;
			}
		}
		if(index < ARRAY_SIZE(string_desc)) {
			usb_ep0_tx(string_desc[index], string_desc[index][0]);
			return;
		}
		break;
	}
	usb_ep0_stall(); /* 未対応 */
}
/*--------------------------------------------------------------------------*/
static void set_configuration(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	D12_SetEndpointEnable(req->wValue == 1);
	usb_ep0_tx(NULL, 0); /* ACK */
}
/*--------------------------------------------------------------------------*/
static void set_interface(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	usb_ep0_tx(NULL, 0); /* ACK */
}
/*--------------------------------------------------------------------------*/
static void class_request(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	switch(req->bRequest) {
	/*--------------------------------------------------------------------------*/
//	case 0x64://Cancel Request
//	case 0x65://Get Extended Event Data
//	case 0x66://Device Reset Request
	/*--------------------------------------------------------------------------*/
	case 0x67://Get Device Status Request
		if((D12_ReadEndpointStatus(EP2OUT) | D12_ReadEndpointStatus(EP2IN)) & D12_ENDPOINTSTALLED) {
			static const uint8_t DeviceStatusData[]={
				USB_UINT16(2+2+4+4),					//wLength	This field specifies the total length of the status data
				USB_UINT16(PTP_ResponseCode_TransactionCancelled),	//Code		The PIMA15740 Response Code or Vendor Code: 0x2001 Status OK 0x2019 Device Busy 0x201F Transaction Cancelled
				USB_UINT32(0x02),	/* EP2OUT */			//Parameter 1	The format and meaning of the parameter depends on the Status Code. For device initiated cancels this parameter contains an endpoint number.	★仕様書(「PHOTOGRAPHIC AND IMAGING MANUFACTURERS ASSOCIATION, INC. PIMA 15740:2000」pima15740-2000.pdf)には明記されていない事ですが、
				USB_UINT32(0x82),	/* EP2IN */			//Parameter N	The format and meaning of the parameter depends on the Status Code. For device initiated cancels this parameter contains an endpoint number.	┃ParameterはUINT32配列です。エンドポイント番号の配列なのでUINT8配列かと思いそうですが、UINT32配列が正解です。(Windows7の挙動より推測)
			};
			usb_ep0_tx(DeviceStatusData, sizeof DeviceStatusData);
		} else {
			static const uint8_t DeviceStatusData[]={
				USB_UINT16(2+2),					//wLength	This field specifies the total length of the status data
				USB_UINT16(PTP_ResponseCode_OK),			//Code		The PIMA15740 Response Code or Vendor Code: 0x2001 Status OK 0x2019 Device Busy 0x201F Transaction Cancelled
			};
			usb_ep0_tx(DeviceStatusData, sizeof DeviceStatusData);
		}
		return;
	/*--------------------------------------------------------------------------*/
	}
	/* The Device may support class-specific requests.
	 * The device shall return STALL if an unrecognized or unsupported device-specific request is received. */
	usb_ep0_stall(); /* 未対応 */
}
/*--------------------------------------------------------------------------*/
static void vendor_request(const DEVICE_REQUEST* req, const unsigned char* dat, int len) {
	if(stPTP.bMTP) {
		if(req->bRequest == 0xFE) {
			//MTP USB Extended Configuration Descriptor
			static const uint8_t MTP_USB_Extended_Configuration_Descriptor[]={
				//MSOS_EXT_CONFIG_DESCRIPTOR_HEADER
				0x28,0x00,0x00,0x00,				//dwLength			Length of the entire Extended Configuration Descriptor
				0x00,0x01,					//bcdVersion			Version info in BCD: 0x0100 ~ 1.00
				0x04,0x00,					//wIndex			must be MSOS_FEATURE_INDEX_EXTENDED_CONFIG_DESC, or 0x0004
				0x01,						//bCount			total number of Function Sections that follow the header section
				0x00,0x00,0x00,0x00,0x00,0x00,0x00,		//bReserved[7]			RESERVED, should be 0x00
				//MSOS_EXT_CONFIG_DESCRIPTOR_FUNCTION
				0x00,						//bFirstInterfaceNumber		Starting Interface Number for this function
				0x01,						//bInterfaceCount		Total number of interfaces 
				0x4D,0x54,0x50,0x00,0x00,0x00,0x00,0x00,	//compatibleID[8]		Compatible ID as defined by Microsoft
				0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	//subCompatibleID[8]		The Sub Compatible ID as defined by Microsoft
				0x00,0x00,0x00,0x00,0x00,0x00};			//bReserved[6]			RESERVED, should be 0x00
			usb_ep0_tx(MTP_USB_Extended_Configuration_Descriptor, sizeof MTP_USB_Extended_Configuration_Descriptor);
			return;
		}
	}
	usb_ep0_stall(); /* 未対応 */
}
/*--------------------------------------------------------------------------*/
static void ep2_rxdone() {
	union { uint8_t buf[EP2_NONISO_PACKET_SIZE]; PTP_GenericContainerStructure Container; } u;
	int len;
	for(;;) {
		/* 受信データを読み出す。受信データが無ければ帰る。受信データを読み出したら、読み出した受信データをクリアする。
		 * - D12_ReadBuffer()が(-1)を場合は、D12_ClearBuffer()を呼んではいけない。
		 *   D12_ReadBuffer()～D12_ClearBuffer()の間に新しいデータが到着した場合、読み出す前にクリアするバグになる。 */
		memset(&u, 0, sizeof u);
		if((len = D12_ReadBuffer(EP2OUT, &u, sizeof u)) == -1) { return; } /* ここまで */
		         D12_ClearBuffer(EP2OUT);
		/* コマンドフェーズならば… */
		if(stPTP.Phase == PTP_Phase_Command) {
			/* 以下の検査に不合格ならば、エラーと見なしてストールする。
			 * - コマンドフェーズの受信データは、ペイロードサイズ(64Byte)未満であるはず。
			 *   (コンテナヘッダ(12Byte)+パラメータ×0～5(0～20Byte)=12～32Byte＜64Byte) */
			if((len == EP2_NONISO_PACKET_SIZE) ||					//ペイロードサイズ未満でない
			   (u.Container.ContainerLength != len) ||				//コンテナ長と一致していない
			   (u.Container.ContainerType != PTP_ContainerType_CommandBlock)) {	//コマンドブロックでない
				break; } /* stall */
			/* オペレーションリクエストデータセットを構築する。 */
			memset(&stPTP.OperationRequestDataset, 0, sizeof stPTP.OperationRequestDataset);
			stPTP.OperationRequestDataset.OperationCode = u.Container.Code;
			stPTP.TransactionID                         = u.Container.TransactionID;
			if((len -= offsetof(PTP_GenericContainerStructure, Payload)) < 0) { len = 0; }
			if(len > sizeof stPTP.OperationRequestDataset.Parameter) { len = sizeof stPTP.OperationRequestDataset.Parameter; }
			memcpy(stPTP.OperationRequestDataset.Parameter, u.Container.Payload, len);
			/* コマンドを処理する。エラーならば、ストールする。 */
			if(process_command()) { break; } /* stall */
			/* データインフェーズ,又は,レスポンスフェーズを開始する。データアウトフェーズならば、ep2_txsub()が無視する。 */
			if(ep2_txsub()) { break; } /* stall */
		/* データアウトフェーズならば… */
		} else if(stPTP.Phase == PTP_Phase_DataOut) {
			/* 最後のパケットであるかを判定しておく。
			 * - データアウトフェーズの受信データは、ペイロードサイズ未満のパケットで終端される。
			 *   コンテナ長でも判断できるが、明示的にペイロードサイズ未満のパケットで終端されるのが、PTPの仕様である。
			 *   │The Data phase ends when the number of bytes transferred equals the number of bytes specified in the first four bytes of the Data Block that coincide with a short or a NULL packet.
			 *   │A short packet or a NULL packet indicates the end of the end of a Data phase.
			 *   │If the number of bytes specified in the first four bytes of the Data Block are an integral multiple of the wMaxPacketSize field of the Endpoint Descriptor the Data phase will end in a NULL packet. */
			int end = (len != EP2_NONISO_PACKET_SIZE);
			/* 最初のパケットならば… */
			if(!stPTP.DataPos) {
				/* データブロックでなければ、エラーと見なしてストールする。 */
				if(u.Container.ContainerType != PTP_ContainerType_DataBlock) { break; } /* stall */
				/* データ長を取得する。データ長が0未満ならば、エラーと見なしてストールする。 */
				stPTP.DataLen = u.Container.ContainerLength - offsetof(PTP_GenericContainerStructure, Payload);
				if(stPTP.DataLen < 0) { break; } /* stall */
				/* 受信サイズから、コンテナヘッダのサイズを差し引く。 */
				if((len -= offsetof(PTP_GenericContainerStructure, Payload)) < 0) { len = 0; }
				/* データをバッファの先頭へずらす。 */
				memmove(&u, u.Container.Payload, len);
			}
			/* 最後のパケットを受信しデータ長が不一致か,又は,データ位置がデータ長を超過したら、エラーと見なす。 */
			if((end && ((stPTP.DataPos + len) != stPTP.DataLen)) ||
			           ((stPTP.DataPos + len) >  stPTP.DataLen)) { break; } /* stall */
			/* データを処理する。 */
			if(len && process_dataout(u.buf, len)) { break; } /* stall */
			/* データ位置を加算する。 */
			stPTP.DataPos += len;
			/* 最後のパケットならば… */
			if(end) {
				/* レスポンスフェーズへ移行する。 */
				stPTP.Phase = PTP_Phase_Response;
				/* レスポンスフェーズを開始する。 */
				if(ep2_txsub()) { break; } /* stall */
			}
		/* それ以外のフェーズならば… */
		} else {
			/* それ以外のフェーズでは受信しないはずである。受信した場合は、エラーと見なしてストールする。 */
			break; /* stall */
		}
		/* 受信処理を継続する。
		 * ダブルバッファのもう一面に受信データが残っているか,又は,上の処理中に新しいデータが到着した可能性が有るから。 */
	}
	/* STALL Bulk-in & Bulk-out Endpoints */
	D12_SetEndpointStatus(EP2OUT, 1);
	D12_SetEndpointStatus(EP2IN , 1);
	/* コマンドフェーズへ戻す。 */
	stPTP.Phase = PTP_Phase_Command;
}
/*--------------------------------------------------------------------------*/
static void ep2_txdone() {
	if(ep2_txsub()) {
		/* STALL Bulk-in & Bulk-out Endpoints */
		D12_SetEndpointStatus(EP2OUT, 1);
		D12_SetEndpointStatus(EP2IN , 1);
		/* コマンドフェーズへ戻す。 */
		stPTP.Phase = PTP_Phase_Command;
	}
}
/*--------------------------------------------------------------------------*/
static int ep2_txsub() {
	union { uint8_t buf[EP2_NONISO_PACKET_SIZE]; PTP_GenericContainerStructure Container; } u;
	int len;
	for(;;) {
		/* データインフェーズならば… */
		if(stPTP.Phase == PTP_Phase_DataIn) {
			int end;
			/* 最初のパケットならば… */
			if(!stPTP.DataPos) {
				/* コンテナを構築する。 */
				memset(&u, 0, sizeof u);
				u.Container.ContainerLength = offsetof(PTP_GenericContainerStructure, Payload) + stPTP.DataLen;
				u.Container.ContainerType   = PTP_ContainerType_DataBlock;
				u.Container.Code            = stPTP.OperationRequestDataset.OperationCode;	//The Data Block will use the OperationCode from the Command Block
				u.Container.TransactionID   = stPTP.TransactionID;
				/* 最初のパケットに入る分の、データを取得する。 */
				len = (stPTP.DataLen - stPTP.DataPos);
				if(len > (EP2_NONISO_PACKET_SIZE - offsetof(PTP_GenericContainerStructure, Payload))) {
				   len = (EP2_NONISO_PACKET_SIZE - offsetof(PTP_GenericContainerStructure, Payload)); }
				if(len && process_datain(u.Container.Payload, len)) { return -1; }
			/* 最初のパケットでなければ… */
			} else {
				/* データを取得する。 */
				len = (stPTP.DataLen - stPTP.DataPos);
				if(len > EP2_NONISO_PACKET_SIZE) { len = EP2_NONISO_PACKET_SIZE; }
				if(len && process_datain(u.buf, len)) { return -1; }
			}
			/* 最初のパケットならば、コンテナヘッダのサイズを加算し、送信サイズとする。 */
			if(!stPTP.DataPos) { len += offsetof(PTP_GenericContainerStructure, Payload); }
			/* パケットを書き込む。パケットを書き込んだら、パケット送出を開始する。
			 * - パケットを書き込めなければ、パケットを送出せずに、成功(0)を返す。
			 *   この後で送信バッファが空いたら、ep2_txdone()が発生するはずである。
			 *   ep2_txdone()が発生したら、再度、同じ処理を行う。 */
			if((len = D12_WriteBuffer(EP2IN, &u, len)) == -1) { return 0; }
			       D12_ValidateBuffer(EP2IN);
			/* 最後のパケットであるかを判定しておく。
			 * - データインフェーズの送信データは、ペイロードサイズ未満のパケットで終端する。
			 *   コンテナ長でも判断できるが、明示的にペイロードサイズ未満のパケットで終端するのが、PTPの仕様である。
			 *   │The Data phase ends when the number of bytes transferred equals the number of bytes specified in the first four bytes of the Data Block that coincide with a short or a NULL packet.
			 *   │A short packet or a NULL packet indicates the end of the end of a Data phase.
			 *   │If the number of bytes specified in the first four bytes of the Data Block are an integral multiple of the wMaxPacketSize field of the Endpoint Descriptor the Data phase will end in a NULL packet. */
			end = (len != EP2_NONISO_PACKET_SIZE);
			/* 最初のパケットならば、送信サイズから、コンテナヘッダのサイズを差し引く。 */
			if(!stPTP.DataPos) { if((len -= offsetof(PTP_GenericContainerStructure, Payload)) < 0) { len = 0; } }
			/* データ位置を加算する。 */
			stPTP.DataPos += len;
			/* 最後のパケットならば、レスポンスフェーズへ移行する。 */
			if(end) { stPTP.Phase = PTP_Phase_Response; }
		/* レスポンスフェーズならば… */
		} else if(stPTP.Phase == PTP_Phase_Response) {
			/* コンテナを構築する。
			 * - レスポンスフェーズの送信データは、ペイロードサイズ(64Byte)未満である。
			 *   (コンテナヘッダ(12Byte)+パラメータ×5(20Byte)=32Byte＜64Byte) */
			memset(&u, 0, sizeof u);
			u.Container.ContainerLength = offsetof(PTP_GenericContainerStructure, Payload) + sizeof stPTP.ResponseDataset.Parameter;
			u.Container.ContainerType   = PTP_ContainerType_ResponseBlock;
			u.Container.Code            = stPTP.ResponseDataset.ResponseCode;
			u.Container.TransactionID   = stPTP.TransactionID;
			memcpy(u.Container.Payload, stPTP.ResponseDataset.Parameter, sizeof stPTP.ResponseDataset.Parameter);
			/* パケットを書き込む。パケットを書き込んだら、パケット送出を開始する。
			 * - パケットを書き込めなければ、パケットを送出せずに、成功(0)を返す。
			 *   この後で送信バッファが空いたら、ep2_txdone()が発生するはずである。
			 *   ep2_txdone()が発生したら、再度、同じ処理を行う。 */
			if((len = D12_WriteBuffer(EP2IN, &u, u.Container.ContainerLength)) == -1) { return 0; }
			       D12_ValidateBuffer(EP2IN);
			/* コマンドフェーズへ戻す。 */
			stPTP.Phase = PTP_Phase_Command;
		/* それ以外のフェーズならば… */
		} else {
			/* それ以外のフェーズでは送信しない。送信せずに、成功(0)を返す。 */
			return 0;
		}
		/* 送信処理を継続する。
		 * ダブルバッファのもう一面が空いているか,又は,上の処理中にデータが送出完了しバッファが空いた可能性が有るから。 */
	}
}
/*--------------------------------------------------------------------------*/
static void put_string(void* _dst, const char* src) {
	char* len = _dst;	//NumChars
	char* dst = _dst + 1;	//StringChars
	*len = 0;
	if(*src) {		//(NumChars=0)の場合、終端のヌルを格納しない。
		int c;
		do {
			*dst++ = c = *src++;
			*dst++ = 0;
			(*len)++;
		} while(c);
	}
}
/*--------------------------------------------------------------------------*/
static void get_string(char* dst, const void* _src) {
	const uint8_t* src = _src;
	int len = *src++;	//NumChars
	while(len--) {
		*dst++ = *src;
		          src += 2;
	}
	*dst = 0;		//(NumChars=0)の場合も、終端のヌルを付加する。
}
/*--------------------------------------------------------------------------*/
static int is_protected_filename(const char* name) {
	const char* ptr = stPTP.pProtectedFilenames;
	/* プロテクトするファイル名のリストの終端に達するまで… */
	while(*ptr) {
		/* プロテクトするファイル名に一致したら、1を返す。 */
		if(!strcasecmp(ptr, name)) { return 1; }
		/* プロテクトするファイル名を、次へ進める。 */
		ptr += (strlen(ptr) + 1);
	}
	/* プロテクトするファイル名に一致しなければ、0を返す。 */
	return 0;
}
/*--------------------------------------------------------------------------*/
static int process_command() {
	int i;
	/* コマンドフェーズの次に行うべきフェーズを取得する。 */
	for(i = 0; i < ARRAY_SIZE(TBL_DataDirection); i++) { if(TBL_DataDirection[i][0/*OperationCode*/] == stPTP.OperationRequestDataset.OperationCode) { break; } }
	if((unsigned)i >= ARRAY_SIZE(TBL_DataDirection)) { return -1; }
	stPTP.Phase = TBL_DataDirection[i][1/*Phase*/];
	/* 以降のコード量を削減するために、一般的な値を設定しておく。 */
	memset(&stPTP.ResponseDataset, 0, sizeof stPTP.ResponseDataset);
	stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_OK;
	stPTP.DataLen = stPTP.DataPos = 0, stPTP.DataPtr = NULL;
	/* オペレーションコードによって… */
	switch(stPTP.OperationRequestDataset.OperationCode) {
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetDeviceInfo:
		stPTP.DataLen = sizeof DeviceInfoDataset;
		stPTP.DataPtr = (void*)DeviceInfoDataset;
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_OpenSession:
		stPTP.SessionID = stPTP.OperationRequestDataset.Parameter[0];
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_CloseSession:
		stPTP.SessionID = 0;
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetStorageIDs:
		stPTP.DataLen = sizeof StorageIDArray;
		stPTP.DataPtr = (void*)StorageIDArray;
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetStorageInfo:
		{
			/* ファイルシステムの統計を取得する。 */
			struct statvfs st;
			if(statvfs("/", &st)) { return -1; }
			/* ストレージ情報データセットをコピーし、MaxCapacity,FreeSpaceInBytesを格納する。 */
			// 1 StorageType		+ 0,2 UINT16
			// 2 FilesystemType		+ 2,2 UINT16
			// 3 AccessCapability		+ 4,2 UINT16
			// 4 MaxCapacity		+ 6,8 UINT64
			// 5 FreeSpaceInBytes		+14,8 UINT64
			// 6 FreeSpaceInImages		+22,4 UINT32
			// 7 StorageDescription		+26,? String
			// 8 VolumeLabel		+ ?,? String
			memcpy(stPTP.WorkBuf, StorageInfoDataset, sizeof StorageInfoDataset);
			PUT_LEWORD(stPTP.WorkBuf +  6, st.f_frsize * st.f_blocks);	//┬MaxCapacity
			PUT_LEWORD(stPTP.WorkBuf + 10, 0);				//┘
			PUT_LEWORD(stPTP.WorkBuf + 14, st.f_frsize * st.f_bfree);	//┬FreeSpaceInBytes
			PUT_LEWORD(stPTP.WorkBuf + 18, 0);				//┘
			/* ストレージ情報データセットを、データインフェーズの送信データとする。 */
			stPTP.DataLen = sizeof StorageInfoDataset;
			stPTP.DataPtr = stPTP.WorkBuf;
		}
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetNumObjects:
	case PTP_OperationCode_GetObjectHandles:
		{
			/* オブジェクトハンドル配列を作成する。
			 * readdir()を使わずに、ディレクトリエントリを直接走査する。オブジェクトハンドルを得るためです。 */
			const pffsMASTERBLOCK* msb = (pffsMASTERBLOCK*)pceSystemGetInfo()->pffs_top;
			const DIRECTORY *pdir = msb->dir, *pdir_end = msb->dir + MAXDIR;
			uint32_t* ObjectHandleArray = (uint32_t*)stPTP.WorkBuf;
			ObjectHandleArray[0/*NumElements*/] = 0;
			do {
				/* 使用中のディレクトリエントリならば…(\usr\PIECE\sysdev\pcekn\file.c Search() 参照) */
				if((pdir->name[0] == 0) || (pdir->name[0] == -1)) { continue; }	//空き
				/* 配列の要素数を増やし、オブジェクトハンドルを格納する。
				 * ディレクトリエントリへのポインタを、オブジェクトハンドルとして格納することにした。 */
				ObjectHandleArray[++ObjectHandleArray[0/*NumElements*/]] = (uint32_t)pdir;
			} while(++pdir < pdir_end);
			switch(stPTP.OperationRequestDataset.OperationCode) {
			/*--------------------------------------------------------------------------*/
			case PTP_OperationCode_GetNumObjects:
				/* オブジェクト数を、レスポンスのパラメータに格納する。 */
				stPTP.ResponseDataset.Parameter[0] = ObjectHandleArray[0/*NumElements*/];
				break;
			/*--------------------------------------------------------------------------*/
			case PTP_OperationCode_GetObjectHandles:
				/* オブジェクトハンドル配列を、データインフェーズの送信データとする。 */
				stPTP.DataLen = sizeof(uint32_t) * (1 + ObjectHandleArray[0/*NumElements*/]);
				stPTP.DataPtr = ObjectHandleArray;
				break;
			/*--------------------------------------------------------------------------*/
			default: DIE();
			}
		}
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetObjectInfo:
		{
			const DIRECTORY* pdir = (DIRECTORY*)stPTP.OperationRequestDataset.Parameter[0];
			struct stat st;
			if(stat(pdir->name, &st)) {	//オブジェクトハンドルが不正
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_InvalidObjectHandle;
				return 0;
			}
			/* オブジェクト情報データセットを構築する。 */
			// 1 StorageID			+ 0,4 StorageID
			// 2 ObjectFormat		+ 4,2 ObjectFormatCode		WindowsXpで試したところ、①VendorDefined*以外*にすると、エクスプローラが勝手に拡張子を変えてしまう。②VendorDefinedにすると、エクスプローラでダブルクリックしてプレビューしようとするとエクスプローラが不正終了する。①の方が②よりも重大なので、VendorDefinedにすることにした。
			// 3 ProtectionStatus		+ 6,2 UINT16			└→Windows7でも試したところ、①の問題は発生しなかった。ただし、ダブルクリックした時にどのビューアが起動するかには影響するようだ。②の問題も発生しなかった。結論としては、Windows7でも、VendorDefinedにして問題ない。
			// 4 ObjectCompressedSize	+ 8,4 UINT32			└→WindowsXpで、別の問題が見つかった。拡張子だけが異なる二つのファイルが有ると、WindowsXpのエクスプローラ上では、片方のファイルが二回表示されてしまう。WindowsXpは、拡張子を除くファイル名とObjectFormatの組合せで、見ているのではないかと思う。回避方法が無い。
			// 5 ThumbFormat		+12,2 ObjectFormatCode		　　さらに悪いことに、WindowsXpのエクスプローラ経由で、これらのファイルを両方削除しようとすると、P/ECEがハングアップする。どのようなリクエストが原因で、P/ECEがハングアップしているのか、まだ原因を調査できていない。
			// 6 ThumbCompressedSize	+14,4 UINT32			└→2014/09/14追記:任意の拡張子を扱う場合は、VendorDefinedよりもUndefinedの方が適切です。オブジェクト情報データセットのObjectFormatはどちらでも影響無いようですが、確実のためにVendorDefined⇒Undefinedに変更しておくことにしました。
			// 7 ThumbPixWidth		+18,4 UINT32
			// 8 ThumbPixHeight		+22,4 UINT32
			// 9 ImagePixWidth		+26,4 UINT32
			//10 ImagePixHeight		+30,4 UINT32
			//11 ImageBitDepth		+34,4 UINT32
			//12 ParentObject		+38,4 ObjectHandle
			//13 AssociationType		+42,2 AssociationCode
			//14 AssociationDesc		+44,4 AssociationDesc
			//15 SequenceNumber		+48,4 UINT32
			//16 Filename			+52,? String		1+((8+1+3)+1)*2=27Byte(Max)
			//17 CaptureDate		+ ?,? DateTime String	1
			//18 ModificationDate		+ ?,? DateTime String	1
			//19 Keywords			+ ?,? String		1
			memset(stPTP.WorkBuf, 0, sizeof stPTP.WorkBuf);
			PUT_LEWORD(stPTP.WorkBuf +  0, StorageID);				//StorageID
		    //{{2014/09/14変更:任意の拡張子を扱う場合は、VendorDefinedよりもUndefinedの方が適切のようです。オブジェクト情報データセットのObjectFormatはどちらでも影響無いようですが、確実のためにVendorDefined⇒Undefinedに変更しておくことにしました。
		    //	PUT_LEHALF(stPTP.WorkBuf +  4, PTP_ObjectFormat_VendorDefined);		//ObjectFormat		上記コメント参照
		    //↓2014/09/14変更:任意の拡張子を扱う場合は、VendorDefinedよりもUndefinedの方が適切のようです。オブジェクト情報データセットのObjectFormatはどちらでも影響無いようですが、確実のためにVendorDefined⇒Undefinedに変更しておくことにしました。
			PUT_LEHALF(stPTP.WorkBuf +  4, PTP_ObjectFormat_Undefined);		//ObjectFormat		上記コメント参照
		    //}}2014/09/14変更:任意の拡張子を扱う場合は、VendorDefinedよりもUndefinedの方が適切のようです。オブジェクト情報データセットのObjectFormatはどちらでも影響無いようですが、確実のためにVendorDefined⇒Undefinedに変更しておくことにしました。
		//不要	PUT_LEHALF(stPTP.WorkBuf +  6, PTP_ProtectionStatus_NoProtection);	//ProtectionStatus	(PTP_ProtectionStatus_NoProtection=0)なので不要
			PUT_LEWORD(stPTP.WorkBuf +  8, st.st_size);				//ObjectCompressedSize
			put_string(stPTP.WorkBuf + 52, pdir->name);				//Filename
			if(is_protected_filename(pdir->name)) {//プロテクトするファイル名か?
				PUT_LEHALF(stPTP.WorkBuf +  6, PTP_ProtectionStatus_ReadOnly);	//ProtectionStatus
			}
			/* オブジェクト情報データセットを、データインフェーズの送信データとする。 */
			stPTP.DataLen = 52 + (1 + stPTP.WorkBuf[52] * 2) + 3;
			stPTP.DataPtr = stPTP.WorkBuf;
		}
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetObject:
		{
			const DIRECTORY* pdir = (DIRECTORY*)stPTP.OperationRequestDataset.Parameter[0];
			struct stat st;
			if(stat(pdir->name, &st)) {	//オブジェクトハンドルが不正
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_InvalidObjectHandle;
				return 0;
			}
			/* データインフェーズの、送信データ長を設定する。 */
			stPTP.DataLen = st.st_size;
		}
		return 0;
	/*--------------------------------------------------------------------------*/
//	case PTP_OperationCode_GetThumb:
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_DeleteObject:
		{
			int retval;
			const DIRECTORY* pdir = (DIRECTORY*)stPTP.OperationRequestDataset.Parameter[0];
			if(is_protected_filename(pdir->name)) {//プロテクトするファイル名か?
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_ObjectWriteProtected;
				return 0;
			}
			/* ファイルを削除する。 */
		    //{{2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
		    //	memcpy(stPTP.save_FRAM4, FRAM4_START, FRAM4_SIZE);	//FRAM4を退避する
		    //}}2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
			retval = pceFileDelete(pdir->name);			//FRAM4が破壊される
		    //{{2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
		    //	memcpy(FRAM4_START, stPTP.save_FRAM4, FRAM4_SIZE);	//FRAM4を復元する
		    //}}2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
			if(retval) {	//オブジェクトハンドルが不正
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_InvalidObjectHandle;
				return 0;
			}
		}
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_SendObjectInfo:
	case PTP_OperationCode_SendObject:
		/** no job **/
		return 0;
	/*--------------------------------------------------------------------------*/
//	case PTP_OperationCode_InitiateCapture:
//	case PTP_OperationCode_FormatStore:
//	case PTP_OperationCode_ResetDevice:
//	case PTP_OperationCode_SelfTest:
//	case PTP_OperationCode_SetObjectProtection:
//	case PTP_OperationCode_PowerDown:
//	case PTP_OperationCode_GetDevicePropDesc:
//	case PTP_OperationCode_GetDevicePropValue:
//	case PTP_OperationCode_SetDevicePropValue:
//	case PTP_OperationCode_ResetDevicePropValue:
//	case PTP_OperationCode_TerminateOpenCapture:
//	case PTP_OperationCode_MoveObject:
//	case PTP_OperationCode_CopyObject:
//	case PTP_OperationCode_GetPartialObject:
//	case PTP_OperationCode_InitiateOpenCapture:
	/*--------------------------------------------------------------------------*/
#ifdef  USE_MTP_OPERATION
	case MTP_OperationCode_GetObjectPropsSupported:
		stPTP.DataLen = sizeof ObjectPropCodeArray;
		stPTP.DataPtr = (void*)ObjectPropCodeArray;
		return 0;
	/*--------------------------------------------------------------------------*/
	case MTP_OperationCode_GetObjectPropDesc:
		{
			switch(stPTP.OperationRequestDataset.Parameter[0]) {
			case MTP_ObjectProperty_StorageID:
				stPTP.DataLen = sizeof ObjectPropDescDataset_StorageID;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_StorageID;
				break;
			case MTP_ObjectProperty_ObjectFormat:
				stPTP.DataLen = sizeof ObjectPropDescDataset_ObjectFormat;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_ObjectFormat;
				break;
			case MTP_ObjectProperty_ProtectionStatus:
				stPTP.DataLen = sizeof ObjectPropDescDataset_ProtectionStatus;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_ProtectionStatus;
				break;
			case MTP_ObjectProperty_ObjectSize:
				stPTP.DataLen = sizeof ObjectPropDescDataset_ObjectSize;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_ObjectSize;
				break;
			case MTP_ObjectProperty_ObjectFileName:
				stPTP.DataLen = sizeof ObjectPropDescDataset_ObjectFileName;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_ObjectFileName;
				break;
			case MTP_ObjectProperty_ParentObject:
				stPTP.DataLen = sizeof ObjectPropDescDataset_ParentObject;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_ParentObject;
				break;
			case MTP_ObjectProperty_PersistentUniqueObjectIdentifier:
				stPTP.DataLen = sizeof ObjectPropDescDataset_PersistentUniqueObjectIdentifier;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_PersistentUniqueObjectIdentifier;
				break;
			case MTP_ObjectProperty_Name:
				stPTP.DataLen = sizeof ObjectPropDescDataset_Name;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_Name;
				break;
			case MTP_ObjectProperty_NonConsumable:
				stPTP.DataLen = sizeof ObjectPropDescDataset_NonConsumable;
				stPTP.DataPtr = (void*)ObjectPropDescDataset_NonConsumable;
				break;
			default:	//オブジェクトプロパティコードが不正
				stPTP.ResponseDataset.ResponseCode = MTP_ResponseCode_InvalidObjectPropCode;
				return 0;
			}
		}
		return 0;
	/*--------------------------------------------------------------------------*/
	case MTP_OperationCode_GetObjectPropValue:
		{
			const DIRECTORY* pdir = (DIRECTORY*)stPTP.OperationRequestDataset.Parameter[0];
			struct stat st;
			if(stat(pdir->name, &st)) {	//オブジェクトハンドルが不正
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_InvalidObjectHandle;
				return 0;
			}
			/* 以降の処理で、UINT64,UINT128の32ビット以上の格納を省略できるよう、あらかじめバッファ全体をクリアしておく。 */
			memset(stPTP.WorkBuf, 0, sizeof stPTP.WorkBuf);
			switch(stPTP.OperationRequestDataset.Parameter[1]) {
			case MTP_ObjectProperty_StorageID:
				PUT_LEWORD(stPTP.WorkBuf, StorageID);
				stPTP.DataLen = sizeof(uint32_t);
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_ObjectFormat:
				PUT_LEHALF(stPTP.WorkBuf, PTP_ObjectFormat_Undefined);
				stPTP.DataLen = sizeof(uint16_t);
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_ProtectionStatus:
			//不要	PUT_LEHALF(stPTP.WorkBuf, PTP_ProtectionStatus_NoProtection);	//⇒(PTP_ProtectionStatus_NoProtection=0)なので不要
				if(is_protected_filename(pdir->name)) {//プロテクトするファイル名か?
					PUT_LEHALF(stPTP.WorkBuf, PTP_ProtectionStatus_ReadOnly);
				}
				stPTP.DataLen = sizeof(uint16_t);
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_ObjectSize:
				PUT_LEWORD(stPTP.WorkBuf + 0, st.st_size);	//┬UINT64
			//不要	PUT_LEWORD(stPTP.WorkBuf + 4, 0);		//┘
				stPTP.DataLen = sizeof(uint64_t);
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_ObjectFileName:
			case MTP_ObjectProperty_Name:
				put_string(stPTP.WorkBuf, pdir->name);
				stPTP.DataLen = 1 + stPTP.WorkBuf[0] * 2;
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_ParentObject:
				//B.2.11 Parent Object
				//If this object exists in a hierarchy, this property will contain the object handle of the parent of this object.
				//Only objects of type Association may be identified in this field.
				//If this object is in the root or the device does not support associations, this field shall be set to 0x00000000.
				//Devices cannot be moved by updating this property.
				//They must be moved using the MoveObject operation.
				//The value of this property must be identical to the value of field 12 of the ObjectInfo dataset.
			//不要	PUT_LEWORD(stPTP.WorkBuf, 0x00000000);
				stPTP.DataLen = sizeof(uint32_t);
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_PersistentUniqueObjectIdentifier:
				PUT_LEWORD(stPTP.WorkBuf +  0, (int)pdir);	//┬UINT128
			//不要	PUT_LEWORD(stPTP.WorkBuf +  4, 0);		//│
			//不要	PUT_LEWORD(stPTP.WorkBuf +  8, 0);		//│
			//不要	PUT_LEWORD(stPTP.WorkBuf + 12, 0);		//┘
				stPTP.DataLen = 16/*sizeof(uint128_t)*/;
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			case MTP_ObjectProperty_NonConsumable:
				//B.2.29 Non-Consumable
				//This property determines whether or not this object is intended to be consumed by the device, or whether it has been placed on the device just for storage.
				//If this property is not present, all data is assumed to be intended for consumption.
				//If this property is supported, it must be supported for all objects on the device.
				//The allowed values for this property are identified in the FORM fields of the Object Property Description dataset, and must contain the values 0x00 and 0x01.
				//A value of 0x00 indicates that the object is intended for consumption, and a value of 0x01 indicates that it shall simply be stored.
				//If a vendor-specific extension is defined which extends the allowed values of this property, it shall use only values with a most significant bit of 1.
				PUT_LEHALF(stPTP.WorkBuf, 0x01);	//a value of 0x01 indicates that it shall simply be stored.
				stPTP.DataLen = sizeof(uint8_t);
				stPTP.DataPtr = stPTP.WorkBuf;
				break;
			default:	//オブジェクトプロパティコードが不正
				stPTP.ResponseDataset.ResponseCode = MTP_ResponseCode_InvalidObjectPropCode;
				return 0;
			}
		}
		return 0;
	/*--------------------------------------------------------------------------*/
//	case MTP_OperationCode_GetObjectPropList:
//	case MTP_OperationCode_GetInterdependentPropDesc:
//	case MTP_OperationCode_GetObjectReferences:
#endif//USE_MTP_OPERATION
	/*--------------------------------------------------------------------------*/
	}
	/* 処理が無ければ、エラーとする。 */
	return -1;
}
/*--------------------------------------------------------------------------*/
static int process_dataout(const void* buf, int len) {
	/* データポインタが設定されていたら、データを格納する。 */
	if(stPTP.DataPtr) { memcpy(stPTP.DataPtr + stPTP.DataPos, buf, len); }
	/* オペレーションコードによって… */
	switch(stPTP.OperationRequestDataset.OperationCode) {
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_SendObjectInfo:
		/* 最初のパケットならば… */
		if(!stPTP.DataPos) {
			/* オブジェクト情報データセットが、ワークバッファに格納できることを確認する。 */
			if(stPTP.DataLen > sizeof stPTP.WorkBuf) { return -1; }	//メモリ不足
			stPTP.DataPtr = stPTP.WorkBuf;
			/* 最初のパケットを格納する。次回からは、当関数の先頭の共通処理で格納される。 */
			memcpy(stPTP.DataPtr + stPTP.DataPos, buf, len);
		}
		/* 最後のパケットならば… */
		if(stPTP.DataPos + len == stPTP.DataLen) {
			char name[(8+1+3)+1];
			{
				int retval;
				// 1 StorageID			+ 0,4 StorageID
				// 2 ObjectFormat		+ 4,2 ObjectFormatCode
				// 3 ProtectionStatus		+ 6,2 UINT16
				// 4 ObjectCompressedSize	+ 8,4 UINT32
				// 5 ThumbFormat		+12,2 ObjectFormatCode
				// 6 ThumbCompressedSize	+14,4 UINT32
				// 7 ThumbPixWidth		+18,4 UINT32
				// 8 ThumbPixHeight		+22,4 UINT32
				// 9 ImagePixWidth		+26,4 UINT32
				//10 ImagePixHeight		+30,4 UINT32
				//11 ImageBitDepth		+34,4 UINT32
				//12 ParentObject		+38,4 ObjectHandle
				//13 AssociationType		+42,2 AssociationCode
				//14 AssociationDesc		+44,4 AssociationDesc
				//15 SequenceNumber		+48,4 UINT32
				//16 Filename			+52,? String
				//17 CaptureDate		+ ?,? DateTime String
				//18 ModificationDate		+ ?,? DateTime String
				//19 Keywords			+ ?,? String
				uint32_t size = LEWORD(stPTP.WorkBuf +  8);	//ObjectCompressedSize
				uint8_t* pstr =        stPTP.WorkBuf + 52 ;	//Filename
				if(pstr[0]/*終端ヌル込み*/ > sizeof name) {	//ファイル名が不正
					stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_GeneralError;
					return 0;
				}
				get_string(name, pstr);
				strlwr(name);//P/ECEは小文字ファイル名しか使えないので、自動的に小文字化することにした。必須ではないが、こうしないと、大文字のファイル名を転送しようとした時にエラーになり面倒であるから。
				if(is_protected_filename(name)) {//プロテクトするファイル名か?
					stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_ObjectWriteProtected;
					return 0;
				}
				/* ファイルを作成する。 */
			    //{{2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
			    //	memcpy(stPTP.save_FRAM4, FRAM4_START, FRAM4_SIZE);	//FRAM4を退避する
			    //}}2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
				retval = pceFileCreate(name, size);			//FRAM4が破壊される
			    //{{2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
			    //	memcpy(FRAM4_START, stPTP.save_FRAM4, FRAM4_SIZE);	//FRAM4を復元する
			    //}}2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
				if(retval) {	//ファイル作成失敗
					stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_StoreFull;
					return 0;
				}
			}
			{
				const pffsMASTERBLOCK* msb = (pffsMASTERBLOCK*)pceSystemGetInfo()->pffs_top;
				const DIRECTORY *pdir = msb->dir, *pdir_end = msb->dir + MAXDIR;
				do {
				//	/* 使用中のディレクトリエントリならば…(\usr\PIECE\sysdev\pcekn\file.c Search() 参照) */	//┐ファイル名の比較で
				//	if((pdir->name[0] == 0) || (pdir->name[0] == -1)) { continue; }	//空き				//┘判断できるので不要
					/* いま作成したファイル名に一致したら… */
					if(!strcmp(pdir->name, name)) {
						/* ディレクトリエントリへのポインタをオブジェクトハンドルとして、レスポンスのパラメータに格納する。 */
						stPTP.ObjectHandle = (int)pdir;	//SendObjectInfo⇒SendObjectへの引渡し用
						stPTP.ResponseDataset.Parameter[0] = StorageID;			//Responder StorageID in which the object will be stored
					//	stPTP.ResponseDataset.Parameter[1] = -1;			//Responder Parent ObjectHandle in which the object will be stored
						stPTP.ResponseDataset.Parameter[2] = stPTP.ObjectHandle;	//Responder’s reserved ObjectHandle for the incoming object
						return 0;
					}
				} while(++pdir < pdir_end);
				/* いま作成したファイルのディレクトリエントリが見つからない(?)。実際には起こり得ないはず。 */
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_GeneralError;
			}
		}
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_SendObject:
		{
			int sct = stPTP.DataPos / BLOCKSIZE;			//現在のデータ位置に対応するセクタ番号
			int pos = stPTP.DataPos % BLOCKSIZE;			//ワークバッファの書き込み位置
			do {
				int cnt = BLOCKSIZE - pos;			//┬ワークバッファに書き込むバイト数を求める
				if(cnt > len) { cnt = len; }			//┘
				memcpy(&stPTP.WorkBuf[pos], buf, cnt);		//ワークバッファに書き込む
				if(((          pos + cnt) ==     BLOCKSIZE) ||	//ワークバッファが一杯になったか,又は,
				   ((stPTP.DataPos + len) == stPTP.DataLen)) {	//最後のパケットを受信したら…
					const DIRECTORY* pdir = (DIRECTORY*)stPTP.ObjectHandle;	//SendObjectInfo⇒SendObjectへの引渡し用
					FILEACC fa;
					if(pceFileOpen(&fa, pdir->name, FOMD_WR)) {	//オブジェクトハンドルが不正
						stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_InvalidObjectHandle;
						return 0;
					}
					/* ワークバッファをセクタへ書き込む */
				    //{{2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
				    //	memcpy(stPTP.save_FRAM4, FRAM4_START, FRAM4_SIZE);	//FRAM4を退避する
				    //}}2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
					pceFileWriteSct(&fa, stPTP.WorkBuf, sct, pos + cnt);	//FRAM4が破壊される
				    //{{2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
				    //	memcpy(FRAM4_START, stPTP.save_FRAM4, FRAM4_SIZE);	//FRAM4を復元する
				    //}}2014/09/20削除:FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
					pceFileClose(&fa);
					sct++;					//セクタ番号を次へ進める
					pos = 0;				//ワークバッファの書き込み位置を先頭へ戻す
				}
				buf += cnt;					//ワークバッファに書き込んだ分、受信データを進める
				len -= cnt;					//受信データの残りバイト数を減らす
			} while(len);						//受信データの残りバイト数が有る間、繰り返す
		}
		return 0;
	/*--------------------------------------------------------------------------*/
//	case PTP_OperationCode_SetDevicePropValue:
	/*--------------------------------------------------------------------------*/
#ifdef  USE_MTP_OPERATION
//	case MTP_OperationCode_SetObjectPropValue:
//	case MTP_OperationCode_SetObjectPropList:
//	case MTP_OperationCode_SendObjectPropList:
//	case MTP_OperationCode_SetObjectReferences:
#endif//USE_MTP_OPERATION
	/*--------------------------------------------------------------------------*/
	}
	/* 処理が無ければ、エラーとする。 */
	return -1;
}
/*--------------------------------------------------------------------------*/
static int process_datain(void* buf, int len) {
	/* データポインタが設定されていたら、データを取得する。 */
	if(stPTP.DataPtr) { memcpy(buf, stPTP.DataPtr + stPTP.DataPos, len); }
	/* オペレーションコードによって… */
	switch(stPTP.OperationRequestDataset.OperationCode) {
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetDeviceInfo:
	case PTP_OperationCode_GetStorageIDs:
	case PTP_OperationCode_GetStorageInfo:
	case PTP_OperationCode_GetObjectHandles:
	case PTP_OperationCode_GetObjectInfo:
		/** no job **/
		return 0;
	/*--------------------------------------------------------------------------*/
	case PTP_OperationCode_GetObject:
		{
			/* 1パケット取得する度にファイルを開く実装とした。効率は悪いが処理が単純である。
			 * 実際に試したところ、この方法でも読出速度は充分早くて、問題無いと判断した。 */
			const DIRECTORY* pdir = (DIRECTORY*)stPTP.OperationRequestDataset.Parameter[0];
			FILE* fp = fopen(pdir->name, "rb");	//■■■■■■■■■■【重要】fopen()は排他制御されていない。割り込み外で同時にfopen()を使うと、clipio.c内のファイルI/O構造体バッファが壊れる恐れが有る。当モジュールを利用するアプリケーションは、割り込み外でfopen(),fclose()を使う場合、明示的に割り込み禁止にせよ。■■■■■■■■■■
			if(!fp) {	//オブジェクトハンドルが不正
				stPTP.ResponseDataset.ResponseCode = PTP_ResponseCode_InvalidObjectHandle;
				return 0;
			}
			fseek(fp, stPTP.DataPos, SEEK_SET);	//厳密にはエラーチェックすべきだが、成功すると仮定して処理を省略した。
			fread(buf, 1, len, fp);			//厳密にはエラーチェックすべきだが、成功すると仮定して処理を省略した。
			fclose(fp);
		}
		return 0;
	/*--------------------------------------------------------------------------*/
//	case PTP_OperationCode_GetThumb:
//	case PTP_OperationCode_GetDevicePropDesc:
//	case PTP_OperationCode_GetDevicePropValue:
//	case PTP_OperationCode_GetPartialObject:
	/*--------------------------------------------------------------------------*/
#ifdef  USE_MTP_OPERATION
	case MTP_OperationCode_GetObjectPropsSupported:
	case MTP_OperationCode_GetObjectPropDesc:
	case MTP_OperationCode_GetObjectPropValue:
		/** no job **/
		return 0;
	/*--------------------------------------------------------------------------*/
//	case MTP_OperationCode_GetObjectPropList:
//	case MTP_OperationCode_GetInterdependentPropDesc:
//	case MTP_OperationCode_GetObjectReferences:
#endif//USE_MTP_OPERATION
	/*--------------------------------------------------------------------------*/
	}
	/* 処理が無ければ、エラーとする。 */
	return -1;
}
